Trouble with web sockets
Posted: Wed Jan 28, 2015 1:46 pm
I'm trying to use a web socket to transfer a file from a webpage to my device. When I look at the stream of bytes I'm getting on the receiving side I'm seeing some corrupted bytes at consistent locations. I'll see 2 corrupted bytes at offset 0x5A8 (1448) and 2 bytes at 0xB5A (2904) and some more places further down. I tried doing a packet capture to try and see the transfer but it seems the web socket doesn't transfer the data in it's raw format because I couldn't see it. I don't know much about web sockets so I'm wondering if there is some kind of protocol limitations of web sockets that is messing with the transfer or if I'm just doing something wrong.
I've attached a zipped up minimal example at the bottom. Any ideas?
edit: I'm running this on a MOD54417 with NNDK 2.7.0
main.cpp
index.htm
I've attached a zipped up minimal example at the bottom. Any ideas?
edit: I'm running this on a MOD54417 with NNDK 2.7.0
main.cpp
Code: Select all
#include "predef.h"
#include <stdio.h>
#include <ctype.h>
#include <startnet.h>
#include <autoupdate.h>
#include <dhcpclient.h>
#include "netinterface.h"
#include "websockets.h"
#include "ftpd.h"
#include <effs_fat/fat.h>
#include "FileSystemUtils.h"
#if ( defined(USE_MMC) && defined(MOD5441X) )
#define MULTI_MMC TRUE // For modules with onboard flash sockets, even if you are using external flash cards
#include <effs_fat/multi_drive_mmc_mcf.h>
#elif ( defined(USE_MMC) )
#include <effs_fat/mmc_mcf.h>
#elif ( defined(USE_CFC) )
#include <effs_fat/cfc_mcf.h>
#endif
extern "C" {
void UserMain(void * pd);
}
const char * AppName="SimpleWebSocketTest";
extern http_wshandler *TheWSHandler;
int GlobalWebSocket = 0;
OS_SEM UploadSocketReady;
int MyDoWSUpgrade( HTTP_Request *req, int sock, PSTR url, PSTR rxb )
{
if(httpstricmp(url, "WEBSOCKETUPLOAD"))
{
int webSocket = WSUpgrade( req, sock );
if (webSocket >= 0)
{
iprintf("\r\nSocket connection received");
GlobalWebSocket = webSocket;
OSSemPost(&UploadSocketReady);
//handler now has ownership of socket
return 2;
}
else
{
iprintf("\r\nUnable to open web socket.\r\n");
return 0;
}
}
iprintf("\r\nWebSocket URL '%s' not found.\r\n", url);
NotFoundResponse( sock, url );
return 0;
}
void UploadTask(void *ptr)
{
//create buffer to read raw data into before writing to file
int myBufferSize = 250;
char myBuffer[myBufferSize];
//to signal the end of the file transfer i just use a timeout
int uploadTimeout = TICKS_PER_SECOND * 5;
F_FILE *uploadFile;
while(1)
{
iprintf("\r\nWaiting for upload socket...");
OSSemPend(&UploadSocketReady,0);
//grab the global websocket and store it for local use
int thisWebSocket = GlobalWebSocket;
f_chdrive(EXT_FLASH_DRV_NUM);
f_chdir( "/" );
uploadFile = f_open( "upload.txt", "w" ); // Open it for write
if(!uploadFile)
{
iprintf("\r\nFailed to open file for writing");
close(thisWebSocket);
thisWebSocket = 0;
continue;
}
iprintf("\r\n...Upload socket acquired.\r\nBegin transmission: \r\n");
fd_set read_fds;
fd_set error_fds;
while(thisWebSocket)
{
FD_ZERO( &read_fds );
FD_ZERO( &error_fds );
FD_SET(thisWebSocket, &read_fds);
FD_SET(thisWebSocket, &error_fds);
//wait for data on the web socket
if(select(FD_SETSIZE, &read_fds, NULL, &error_fds, uploadTimeout))
{
if(FD_ISSET(thisWebSocket, &read_fds))
{
int n;
//read data from the fd until none is left
do
{
//read as much as will fit into our buffer
n = read( thisWebSocket, myBuffer, myBufferSize );
if(n > 0)
{
int bytesWritten = 0;
int RetryAttempts = 0;
//try 3 times to write the data to the file
while(bytesWritten < n && ( RetryAttempts++ < 3 ))
{
if(RetryAttempts > 1)
OSTimeDly(TICKS_PER_SECOND / 4);//pause a moment if we weren't able to write everything
//DEBUG: display out the serial port so we can see the raw data we received
//write(0, (char *) (myBuffer + bytesWritten), n-bytesWritten);
//write the bytes to the file
bytesWritten += f_write( myBuffer + bytesWritten, 1, n-bytesWritten, uploadFile );
}
if(RetryAttempts >= 3)
{
iprintf("\r\nFailed to write bytes to file");
}
}
}while(n > 0);//keep reading until no data is left on the socket
}
if(FD_ISSET(thisWebSocket, &error_fds))
{
//socket error
iprintf("\r\nError on socket.\r\n");
close(thisWebSocket);
f_close(uploadFile);
thisWebSocket = 0;
}
}
else
{
//timed out
iprintf("\r\nUpload complete");
close(thisWebSocket);
f_close(uploadFile);
thisWebSocket = 0;
}
}
}
}
#define FTP_PRIO 58
#define UPLOAD_PRIO 59
#define MY_MAIN_PRIO 60
void UserMain(void * pd)
{
InitializeStack();
if (EthernetIP == 0) GetDHCPAddress();
OSChangePrio(MAIN_PRIO);
EnableAutoUpdate();
StartHTTP();
OSSemInit(&UploadSocketReady, 0);
//display links for the web page and ftp
iprintf("\r\nGo to:\r\nhttp://");
ShowIP(EthernetIP);
iprintf("\r\n");
iprintf("\r\nYou can download the file 'Upload.txt' from:\r\nftp://");
ShowIP(EthernetIP);
iprintf("\r\n\r\n");
// We have to enter the file system for each task
OSChangePrio( FTP_PRIO );
f_enterFS();
OSChangePrio( UPLOAD_PRIO );
f_enterFS();
OSChangePrio( MY_MAIN_PRIO );
f_enterFS();
InitExtFlash(); // Initialize the CFC or SD/MMC external flash drive
FTPDStart( 21, FTP_PRIO);
TheWSHandler = MyDoWSUpgrade;
OSSimpleTaskCreatewName(UploadTask,UPLOAD_PRIO,"UploadTask");
iprintf("\r\nApplication started");
while (1) {
OSTimeDly(20);
}
}
Code: Select all
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
//create a web socket variable
var ws;
function uploadFile()
{
//get the file
var file = document.getElementById('filename').files[0];
//make a reader for the file
var reader = new FileReader();
//create an array buffer view to use on the file
var rawData = new ArrayBuffer();
reader.loadend = function()
{
}
reader.onload = function(e)
{
//once the file has been read, set the array buffer view on it
rawData = e.target.result;
//send the data
ws.send(rawData);
console.log("File sent");
alert("the File has been transferred.");
}
//trigger the reading of the file
reader.readAsArrayBuffer(file);
}
function sendFile()
{
connectChatServer();
}
function connectChatServer()
{
//create web socket
var webSocketAddress = "ws://" + window.location.hostname + "/WEBSOCKETUPLOAD";
ws = new WebSocket(webSocketAddress);
//we will send the file as an array buffer
ws.binaryType = "arraybuffer";
ws.onopen = function()
{
//once we connect, send the file
console.log("Connected.");
uploadFile();
};
ws.onmessage = function(evt)
{
console.log(evt.msg);
};
ws.onclose = function()
{
console.log("Connection is closed...");
};
ws.onerror = function(e)
{
console.log(e.msg);
}
}
</script>
Select file and click upload. It will be stored on the SD card root directory under the name Upload.txt
<br>
<input type="file" id="filename" />
<br>
<input type="button" value="Upload" onclick="sendFile()" />
</body>
</html>