Trouble with web sockets

Discussion to talk about software related topics only.
Post Reply
sulliwk06
Posts: 118
Joined: Tue Sep 17, 2013 7:14 am

Trouble with web sockets

Post by sulliwk06 »

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

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);
    }
}
index.htm

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>
Attachments
SimpleWebSocketTest.zip
(23.92 KiB) Downloaded 242 times
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: Trouble with web sockets

Post by dciliske »

More like, give me a week... There's been some major rework on the back end to shake out some corruption bugs. You probably are running into those...

We'll be doing a release soon that should address the issue...

-Dan
Dan Ciliske
Project Engineer
Netburner, Inc
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: Trouble with web sockets

Post by dciliske »

Here's the .s19 from my tools with the updates. Seems to work for me... So, yea, I think your code is 100% working, it's just the code I wrote that you're using isn't :twisted:

-Dan
Attachments
SimpleWebsocketTest_APP.s19
(510.71 KiB) Downloaded 235 times
Dan Ciliske
Project Engineer
Netburner, Inc
sulliwk06
Posts: 118
Joined: Tue Sep 17, 2013 7:14 am

Re: Trouble with web sockets

Post by sulliwk06 »

dciliske wrote: We'll be doing a release soon that should address the issue...

-Dan
Any idea on when the next release will be? Just trying to get a time frame to see when I can add in this websocket file transfer feature.
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: Trouble with web sockets

Post by dciliske »

We're aiming for Tuesday. I literally just finished with the last of the major issues with the TLS beta.
Dan Ciliske
Project Engineer
Netburner, Inc
Post Reply