David Fletcher / Mbed 2 deprecated cc3100_Test_websock_Camera_CM3

Dependencies:   mbed

Revision:
0:400d8e75a8d0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/http/server/WebSockHandler.cpp	Sun Sep 06 15:19:36 2015 +0000
@@ -0,0 +1,422 @@
+//*****************************************************************************
+// Copyright (C) 2014 Texas Instruments Incorporated
+//
+// All rights reserved. Property of Texas Instruments Incorporated.
+// Restricted rights to use, duplicate or disclose this code are
+// granted through contract.
+// The program may not be used without the written permission of
+// Texas Instruments Incorporated or against the terms and conditions
+// stipulated in the agreement under which this program has been supplied,
+// and under no circumstances can it be used with non-TI connectivity device.
+//
+//*****************************************************************************
+
+
+/**
+ * @addtogroup WebSockHandler
+ *
+ * @{
+ */
+
+//#include "HttpHeaders.h"
+#include "HttpCore.h"
+#include "HttpResponse.h"
+#include "HttpRequest.h"
+#include "HttpAuth.h"
+#include "HttpDebug.h"
+#include <string.h>
+#include <stdlib.h>
+#include "HttpConfig.h"
+#include "HttpString.h"
+#include "osi.h"
+#include "WebSockHandler.h"
+#include "httpserverapp.h"
+
+// Include CC3200 SimpleLink headers
+#include "cc3100_simplelink.h"
+
+
+char *GlobRecvBuf;
+int64_t GlobPayloadLen;
+int64_t GlobRecvLen;
+UINT8 RecvMore = 0;
+char MaskKey[4];
+UINT8 Mask;
+UINT8 Ping = 0;
+UINT8 Close = 0;
+
+// WebSocket response status line strings
+char    WS_STATUS_OK_STR[]                     =    "ok";
+char    WS_STATUS_GOING_AWAY_STR[]   		   =    "server down";
+char    WS_STATUS_ERROR_PROTOCOL_STR[]   	   =    "protocol error";
+char    WS_STATUS_ERROR_DATATYPE_STR[]   	   =    "datatype not supported";
+char    WS_STATUS_ERROR_ENCODING_STR[]         =    "data not interpreted";
+char    WS_STATUS_ERROR_OVERFLOW_STR[]   	   =    "data too large";
+char    WS_STATUS_ERROR_UNEXPECTED_STR[]       =    "unexpected event server";
+
+
+/* This function parses the incoming data packet
+* @return 1 if successful
+		0 if failure
+*/
+/*
+
+		0				1					2					3
+	 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+	+-+-+-+-+-------+-+-------------+-------------------------------+
+	|F|R|R|R| opcode|M| Payload len |	 Extended payload length	|
+	|I|S|S|S|  (4)	|A| 	(7) 	|			  (16/64)			|
+	|N|V|V|V|		|S| 			|	(if payload len==126/127)	|
+	| |1|2|3|		|K| 			|								|
+	+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
+	|	  Extended payload length continued, if payload len == 127	|
+	+ - - - - - - - - - - - - - - - +-------------------------------+
+	|								|Masking-key, if MASK set to 1	|
+	+-------------------------------+-------------------------------+
+	| Masking-key (continued)		|		   Payload Data 		|
+	+-------------------------------- - - - - - - - - - - - - - - - +
+	:					  Payload Data continued ...				:
+	+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+	|					  Payload Data continued ...				|
+	+---------------------------------------------------------------+
+
+
+*/
+
+int Payloadlength(struct HttpBlob * pData, UINT8 iter)
+{
+	int result = 0x0;
+
+	while(iter != 0)
+	{
+		result = ((int) (*(pData->pData)) | result);
+		if(iter != 1)
+			result = result << 8;
+		pData->pData += sizeof(UINT8);
+		pData->uLength -= sizeof(UINT8);
+		iter--;
+	}
+
+	return result;
+}
+
+
+int WSCore_DataRecv(UINT16 uConnection,struct HttpBlob * pData)
+{
+	UINT8 NextBlock;
+	int lengthLeft;
+	UINT16 final,RSV,Opcode;
+	int PayloadLength;
+	UINT8 iter;
+	char *PayloadData;
+	int RecvLength = (int)pData->uLength;
+
+
+	if(!RecvMore)
+	{
+		//Parse the first byte
+		NextBlock= *(pData->pData);
+		pData->pData += sizeof(UINT8);
+		pData->uLength -= sizeof(UINT8);
+
+		//Mask bits to get header fields
+		final = (NextBlock&(0x80));
+		RSV = (NextBlock&(0x70));
+		Opcode = ((NextBlock&(0x0F)));
+
+		//If Final bit is set, this is the last data byte from client - terminating condition
+		if(final)
+			HttpDebug("Final datablock received \n\r");
+
+
+		//Inform user about the opcode
+			HttpDebug("Opcode is %d\n\r",Opcode);
+
+			switch(Opcode)
+			{
+				case WS_TEXT:
+					HttpDebug("Text data\n\r");
+					break;
+				case WS_BINARY:
+					HttpDebug("Binary data\n\r");
+					break;
+				case WS_CLOSE:
+					HttpDebug("Client has requested connection to be closed\n\r");
+					Close = 1;
+					WSStatusString(WS_STATUS_OK,pData);
+					WSCore_DataSend(uConnection,*pData,Opcode);
+					return 1;
+				case WS_CONTINUATION:
+					break;
+				case WS_PING:
+					HttpDebug("Ping received\n\r");
+					Ping = 1;
+					break;
+				case WS_PONG:
+					HttpDebug("Pong received\n\r");
+					break;
+				default:
+					HttpDebug("This is unsupported\n\r");
+					break;
+			}
+
+
+		///If header supports extension, send back error
+		///Send error frame : TODO
+		if(RSV)
+			HttpDebug("Unsupported extension\n\r");
+
+		//Parse the second byte
+		NextBlock= *(pData->pData);
+		pData->pData += sizeof(UINT8);
+		pData->uLength -= sizeof(UINT8);
+
+		Mask = (UINT8)(NextBlock&(0x80));
+		PayloadLength = (NextBlock&(0x7F));
+
+		//Payload length cases
+		// If the payload length is 0x7E, the next 2 bytes represent the length
+		if(PayloadLength == 0x7E)
+		{
+			iter = 2;
+			PayloadLength = Payloadlength(pData, iter);
+		}
+
+		// If the payload length is 0x7F, the next 8 bytes represent the length
+		if(PayloadLength == 0x7F)
+		{
+			iter = 8;
+			PayloadLength = Payloadlength(pData, iter);
+		}
+
+		PayloadData = (char *)malloc(PayloadLength);
+		if(PayloadData == NULL)
+		{
+			return 0;
+		}
+		memset(PayloadData,'\0',PayloadLength);
+		GlobRecvBuf = PayloadData;
+		GlobPayloadLen = PayloadLength;
+
+		// If mask bit is set, the 4 bytes after payload length represent the masking key
+		if(Mask)
+		{
+			memcpy(MaskKey,pData->pData,4);
+			pData->pData += sizeof(UINT32);
+			pData->uLength -= sizeof(UINT32);
+		}
+
+		int RecvLength = (int)pData->uLength;
+
+		//Now, extract payload data
+		memcpy(GlobRecvBuf,(const char *)(pData->pData),RecvLength);
+
+		// Go back and get more data.
+		if(PayloadLength > RecvLength)
+		{
+			GlobRecvLen = RecvLength; 	// Websocket header has 8 bytes that were also received.
+			RecvMore = 1;
+			return 1;
+		}
+	}
+
+	else
+	{
+		memcpy(GlobRecvBuf+GlobRecvLen,(const char *)(pData->pData),RecvLength);
+		GlobRecvLen += RecvLength;
+
+		if(GlobRecvLen < GlobPayloadLen)
+			return 1;
+	}
+
+	RecvMore = 0;
+
+
+	if(Mask)
+	{
+		//UINT8 MaskBlock;
+		char *pData = GlobRecvBuf;
+		lengthLeft = GlobPayloadLen;
+		UINT8 MaskIndex = 0;
+		while(MaskIndex < 4)
+		{
+			NextBlock = (UINT8)(*pData);
+			NextBlock ^= MaskKey[MaskIndex];
+			MaskIndex++;
+			*pData = NextBlock;
+			pData += sizeof(UINT8);
+			lengthLeft -= sizeof(UINT8);
+			if(lengthLeft == 0)
+				break;
+			if(MaskIndex == 4)
+				MaskIndex = 0;
+		}
+
+	}
+
+	*(GlobRecvBuf+GlobPayloadLen) = '\0';
+
+	struct HttpBlob PayLoad;
+	PayLoad.pData = (UINT8 *)GlobRecvBuf;
+	PayLoad.uLength = (UINT16)GlobPayloadLen;
+
+	if(Ping)
+	{
+		HttpDebug("You were Pinged\n\r");
+		//You must pong
+		Opcode = 0x0A;
+		WSCore_DataSend(uConnection,PayLoad,Opcode);
+	}
+
+	//free(pData->pData);
+
+	//Send this data to main
+	WebSocketRecvEventHandler(uConnection,GlobRecvBuf);
+
+
+	return 1;
+
+}
+
+/*!
+ * 	\brief 						 Sends data to a websocket client								
+ *
+ * 	\param[in] uConnection			Connection number on HTTP server. 
+ * 	\param[in] PayLoad			Structure holding the payload data and the size of the data
+ * 	\param[in] Opcode				User provides data type (text/binary/ping/pong/close).
+ *
+ * 	\return						1 - If packet was successfully received, parsed and sent to the user API
+ *     							0 - Error
+ */
+int WSCore_DataSend(UINT16 uConnection, struct HttpBlob PayLoad, UINT8 Opcode)
+{
+	UINT16 usTotalLength;
+	UINT8 usNextBlock;
+	UINT16 usPayloadLen;	// The heap cannot support beyond 65kb
+	char *pucPayLoadData = (char *)PayLoad.pData;
+
+	usNextBlock = 0;
+    
+	if(Opcode != 0x02)
+		usTotalLength = strlen(pucPayLoadData);
+	else
+		usTotalLength = PayLoad.uLength;
+
+	do{
+
+		///Is this the final packet?
+		if(usTotalLength < FRAGMENT_LENGTH)
+		{
+			//final = 0x1;
+			usNextBlock |= 0x80;
+		}
+		///Add opcode to the header
+		usNextBlock |= Opcode;
+
+		/// Add this byte to the sendpacket
+		HttpResponse_AddCharToResponseHeaders(usNextBlock);
+
+		///Reset byte
+		usNextBlock = 0x0;
+		///Mask bit is always set to 0 from server to client
+
+		///PayloadLen field
+		if(usTotalLength <= 125)
+			usPayloadLen = usTotalLength;
+		else
+			usPayloadLen = (126);
+
+		usNextBlock |= (UINT8)usPayloadLen;
+
+		/// Add this byte to the sendpacket
+		HttpResponse_AddCharToResponseHeaders(usNextBlock);
+
+		/// If payload length is more than 125 bytes, we need 16 bits to represent it.
+		if(usPayloadLen == (126))
+		{
+
+			if(usTotalLength < FRAGMENT_LENGTH)
+				usPayloadLen = usTotalLength;
+			else
+				usPayloadLen = FRAGMENT_LENGTH;
+
+			if(usPayloadLen >= FRAGMENT_LENGTH - 4)
+				usPayloadLen = FRAGMENT_LENGTH - 4;
+
+			usNextBlock = (char)(usPayloadLen>>8);
+			HttpResponse_AddCharToResponseHeaders(usNextBlock);
+			usNextBlock = (char)(usPayloadLen);
+			HttpResponse_AddCharToResponseHeaders(usNextBlock);
+		}
+
+		HttpResponse_AddStringToResponseHeaders(pucPayLoadData,(usPayloadLen));
+
+		if(!WS_SendPacket(uConnection))
+			return 0;
+
+		if(Opcode == WS_CLOSE)
+		{
+			sl_WebSocketCloseEvtHdlr();
+			wait(1);
+			(HttpCore_CloseConnection(uConnection));
+			return 1;
+		}
+
+		usTotalLength -= (usPayloadLen);
+
+		// Reset to continuation frame if packet is larger than max fragment size
+		Opcode = WS_CONTINUATION;
+
+		///Reset byte
+		usNextBlock = 0x0;
+
+		//Update pointer
+		pucPayLoadData += usPayloadLen;
+
+	}while(usTotalLength > 0);
+
+	return 1;
+}
+
+
+/**
+ * Returns status string according to status code - CHANGE
+ */
+void WSStatusString(UINT32 WS_Status, struct HttpBlob* status)
+{
+	HttpString_utoa(WS_Status, status);
+	struct HttpBlob blob = {0, NULL};
+    switch (WS_Status)
+    {
+    case WS_STATUS_OK:
+        HttpBlobSetConst(blob, WS_STATUS_OK_STR);
+        break;
+    case WS_STATUS_GOING_AWAY:
+        HttpBlobSetConst(blob, WS_STATUS_GOING_AWAY_STR);
+        break;
+    case WS_STATUS_ERROR_DATATYPE:
+        HttpBlobSetConst(blob, WS_STATUS_ERROR_DATATYPE_STR);
+        break;
+    case WS_STATUS_ERROR_ENCODING:
+        HttpBlobSetConst(blob, WS_STATUS_ERROR_ENCODING_STR);
+        break;
+    case WS_STATUS_ERROR_OVERFLOW:
+        HttpBlobSetConst(blob, WS_STATUS_ERROR_OVERFLOW_STR);
+        break;
+    case WS_STATUS_ERROR_PROTOCOL:
+        HttpBlobSetConst(blob, WS_STATUS_ERROR_PROTOCOL_STR);
+        break;
+    case WS_STATUS_ERROR_UNEXPECTED:
+        HttpBlobSetConst(blob, WS_STATUS_ERROR_UNEXPECTED_STR);
+        break;
+    default:
+        HttpDebug("Unknown response status \n\r");
+        HttpAssert(0);
+        break;
+    }
+    memcpy(status->pData + status->uLength, blob.pData, blob.uLength);
+    return;
+}
+
+/// @}
+