Port of TI's CC3100 Websock camera demo. Using FreeRTOS, mbedTLS, also parts of Arducam for cams ov5642 and 0v2640. Can also use MT9D111. Work in progress. Be warned some parts maybe a bit flacky. This is for Seeed Arch max only, for an M3, see the demo for CM3 using the 0v5642 aducam mini.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WebSockHandler.cpp Source File

WebSockHandler.cpp

00001 //*****************************************************************************
00002 // Copyright (C) 2014 Texas Instruments Incorporated
00003 //
00004 // All rights reserved. Property of Texas Instruments Incorporated.
00005 // Restricted rights to use, duplicate or disclose this code are
00006 // granted through contract.
00007 // The program may not be used without the written permission of
00008 // Texas Instruments Incorporated or against the terms and conditions
00009 // stipulated in the agreement under which this program has been supplied,
00010 // and under no circumstances can it be used with non-TI connectivity device.
00011 //
00012 //*****************************************************************************
00013 
00014 
00015 /**
00016  * @addtogroup WebSockHandler
00017  *
00018  * @{
00019  */
00020 
00021 //#include "HttpHeaders.h"
00022 #include "HttpCore.h"
00023 #include "HttpResponse.h"
00024 #include "HttpRequest.h"
00025 #include "HttpAuth.h"
00026 #include "HttpDebug.h"
00027 #include <string.h>
00028 #include <stdlib.h>
00029 #include "HttpConfig.h"
00030 #include "HttpString.h"
00031 #include "osi.h"
00032 #include "WebSockHandler.h"
00033 #include "httpserverapp.h"
00034 
00035 // Include CC3200 SimpleLink headers
00036 #include "cc3100_simplelink.h"
00037 
00038 
00039 char *GlobRecvBuf;
00040 int64_t GlobPayloadLen;
00041 int64_t GlobRecvLen;
00042 UINT8 RecvMore = 0;
00043 char MaskKey[4];
00044 UINT8 Mask;
00045 UINT8 Ping = 0;
00046 UINT8 Close = 0;
00047 
00048 // WebSocket response status line strings
00049 char    WS_STATUS_OK_STR[]                     =    "ok";
00050 char    WS_STATUS_GOING_AWAY_STR[]             =    "server down";
00051 char    WS_STATUS_ERROR_PROTOCOL_STR[]         =    "protocol error";
00052 char    WS_STATUS_ERROR_DATATYPE_STR[]         =    "datatype not supported";
00053 char    WS_STATUS_ERROR_ENCODING_STR[]         =    "data not interpreted";
00054 char    WS_STATUS_ERROR_OVERFLOW_STR[]         =    "data too large";
00055 char    WS_STATUS_ERROR_UNEXPECTED_STR[]       =    "unexpected event server";
00056 
00057 
00058 /* This function parses the incoming data packet
00059 * @return 1 if successful
00060         0 if failure
00061 */
00062 /*
00063 
00064         0               1                   2                   3
00065      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
00066     +-+-+-+-+-------+-+-------------+-------------------------------+
00067     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
00068     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
00069     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
00070     | |1|2|3|       |K|             |                               |
00071     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
00072     |     Extended payload length continued, if payload len == 127  |
00073     + - - - - - - - - - - - - - - - +-------------------------------+
00074     |                               |Masking-key, if MASK set to 1  |
00075     +-------------------------------+-------------------------------+
00076     | Masking-key (continued)       |          Payload Data         |
00077     +-------------------------------- - - - - - - - - - - - - - - - +
00078     :                     Payload Data continued ...                :
00079     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
00080     |                     Payload Data continued ...                |
00081     +---------------------------------------------------------------+
00082 
00083 
00084 */
00085 
00086 int Payloadlength(struct HttpBlob * pData, UINT8 iter)
00087 {
00088     int result = 0x0;
00089 
00090     while(iter != 0)
00091     {
00092         result = ((int) (*(pData->pData)) | result);
00093         if(iter != 1)
00094             result = result << 8;
00095         pData->pData += sizeof(UINT8);
00096         pData->uLength -= sizeof(UINT8);
00097         iter--;
00098     }
00099 
00100     return result;
00101 }
00102 
00103 
00104 int WSCore_DataRecv(UINT16 uConnection,struct HttpBlob * pData)
00105 {
00106     UINT8 NextBlock;
00107     int lengthLeft;
00108     UINT16 final,RSV,Opcode;
00109     int PayloadLength;
00110     UINT8 iter;
00111     char *PayloadData;
00112     int RecvLength = (int)pData->uLength;
00113 
00114 
00115     if(!RecvMore)
00116     {
00117         //Parse the first byte
00118         NextBlock= *(pData->pData);
00119         pData->pData += sizeof(UINT8);
00120         pData->uLength -= sizeof(UINT8);
00121 
00122         //Mask bits to get header fields
00123         final = (NextBlock&(0x80));
00124         RSV = (NextBlock&(0x70));
00125         Opcode = ((NextBlock&(0x0F)));
00126 
00127         //If Final bit is set, this is the last data byte from client - terminating condition
00128         if(final)
00129             HttpDebug("Final datablock received \n\r");
00130 
00131 
00132         //Inform user about the opcode
00133             HttpDebug("Opcode is %d\n\r",Opcode);
00134 
00135             switch(Opcode)
00136             {
00137                 case WS_TEXT:
00138                     HttpDebug("Text data\n\r");
00139                     break;
00140                 case WS_BINARY:
00141                     HttpDebug("Binary data\n\r");
00142                     break;
00143                 case WS_CLOSE:
00144                     HttpDebug("Client has requested connection to be closed\n\r");
00145                     Close = 1;
00146                     WSStatusString(WS_STATUS_OK,pData);
00147                     WSCore_DataSend(uConnection,*pData,Opcode);
00148                     return 1;
00149                 case WS_CONTINUATION:
00150                     break;
00151                 case WS_PING:
00152                     HttpDebug("Ping received\n\r");
00153                     Ping = 1;
00154                     break;
00155                 case WS_PONG:
00156                     HttpDebug("Pong received\n\r");
00157                     break;
00158                 default:
00159                     HttpDebug("This is unsupported\n\r");
00160                     break;
00161             }
00162 
00163 
00164         ///If header supports extension, send back error
00165         ///Send error frame : TODO
00166         if(RSV)
00167             HttpDebug("Unsupported extension\n\r");
00168 
00169         //Parse the second byte
00170         NextBlock= *(pData->pData);
00171         pData->pData += sizeof(UINT8);
00172         pData->uLength -= sizeof(UINT8);
00173 
00174         Mask = (UINT8)(NextBlock&(0x80));
00175         PayloadLength = (NextBlock&(0x7F));
00176 
00177         //Payload length cases
00178         // If the payload length is 0x7E, the next 2 bytes represent the length
00179         if(PayloadLength == 0x7E)
00180         {
00181             iter = 2;
00182             PayloadLength = Payloadlength(pData, iter);
00183         }
00184 
00185         // If the payload length is 0x7F, the next 8 bytes represent the length
00186         if(PayloadLength == 0x7F)
00187         {
00188             iter = 8;
00189             PayloadLength = Payloadlength(pData, iter);
00190         }
00191 
00192         PayloadData = (char *)malloc(PayloadLength);
00193         if(PayloadData == NULL)
00194         {
00195             return 0;
00196         }
00197         memset(PayloadData,'\0',PayloadLength);
00198         GlobRecvBuf = PayloadData;
00199         GlobPayloadLen = PayloadLength;
00200 
00201         // If mask bit is set, the 4 bytes after payload length represent the masking key
00202         if(Mask)
00203         {
00204             memcpy(MaskKey,pData->pData,4);
00205             pData->pData += sizeof(UINT32);
00206             pData->uLength -= sizeof(UINT32);
00207         }
00208 
00209         int RecvLength = (int)pData->uLength;
00210 
00211         //Now, extract payload data
00212         memcpy(GlobRecvBuf,(const char *)(pData->pData),RecvLength);
00213 
00214         // Go back and get more data.
00215         if(PayloadLength > RecvLength)
00216         {
00217             GlobRecvLen = RecvLength;   // Websocket header has 8 bytes that were also received.
00218             RecvMore = 1;
00219             return 1;
00220         }
00221     }
00222 
00223     else
00224     {
00225         memcpy(GlobRecvBuf+GlobRecvLen,(const char *)(pData->pData),RecvLength);
00226         GlobRecvLen += RecvLength;
00227 
00228         if(GlobRecvLen < GlobPayloadLen)
00229             return 1;
00230     }
00231 
00232     RecvMore = 0;
00233 
00234 
00235     if(Mask)
00236     {
00237         //UINT8 MaskBlock;
00238         char *pData = GlobRecvBuf;
00239         lengthLeft = GlobPayloadLen;
00240         UINT8 MaskIndex = 0;
00241         while(MaskIndex < 4)
00242         {
00243             NextBlock = (UINT8)(*pData);
00244             NextBlock ^= MaskKey[MaskIndex];
00245             MaskIndex++;
00246             *pData = NextBlock;
00247             pData += sizeof(UINT8);
00248             lengthLeft -= sizeof(UINT8);
00249             if(lengthLeft == 0)
00250                 break;
00251             if(MaskIndex == 4)
00252                 MaskIndex = 0;
00253         }
00254 
00255     }
00256 
00257     *(GlobRecvBuf+GlobPayloadLen) = '\0';
00258 
00259     struct HttpBlob PayLoad;
00260     PayLoad.pData = (UINT8 *)GlobRecvBuf;
00261     PayLoad.uLength = (UINT16)GlobPayloadLen;
00262 
00263     if(Ping)
00264     {
00265         HttpDebug("You were Pinged\n\r");
00266         //You must pong
00267         Opcode = 0x0A;
00268         WSCore_DataSend(uConnection,PayLoad,Opcode);
00269     }
00270 
00271     //free(pData->pData);
00272 
00273     //Send this data to main
00274     WebSocketRecvEventHandler(uConnection,GlobRecvBuf);
00275 
00276 
00277     return 1;
00278 
00279 }
00280 
00281 /*!
00282  *  \brief                       Sends data to a websocket client                               
00283  *
00284  *  \param[in] uConnection          Connection number on HTTP server. 
00285  *  \param[in] PayLoad          Structure holding the payload data and the size of the data
00286  *  \param[in] Opcode               User provides data type (text/binary/ping/pong/close).
00287  *
00288  *  \return                     1 - If packet was successfully received, parsed and sent to the user API
00289  *                              0 - Error
00290  */
00291 int WSCore_DataSend(UINT16 uConnection, struct HttpBlob PayLoad, UINT8 Opcode)
00292 {
00293     UINT16 usTotalLength;
00294     UINT8 usNextBlock;
00295     UINT16 usPayloadLen;    // The heap cannot support beyond 65kb
00296     char *pucPayLoadData = (char *)PayLoad.pData;
00297 
00298     usNextBlock = 0;
00299     
00300     if(Opcode != 0x02)
00301         usTotalLength = strlen(pucPayLoadData);
00302     else
00303         usTotalLength = PayLoad.uLength;
00304 
00305     do{
00306         wait_ms(10);
00307         ///Is this the final packet?
00308         if(usTotalLength < FRAGMENT_LENGTH)
00309         {
00310             //final = 0x1;
00311             usNextBlock |= 0x80;
00312         }
00313         ///Add opcode to the header
00314         usNextBlock |= Opcode;
00315 
00316         /// Add this byte to the sendpacket
00317         HttpResponse_AddCharToResponseHeaders(usNextBlock);
00318         
00319         ///Reset byte
00320         usNextBlock = 0x0;
00321         ///Mask bit is always set to 0 from server to client
00322 
00323         ///PayloadLen field
00324         if(usTotalLength <= 125)
00325             usPayloadLen = usTotalLength;
00326         else
00327             usPayloadLen = (126);
00328 
00329         usNextBlock |= (UINT8)usPayloadLen;
00330 
00331         /// Add this byte to the sendpacket
00332         HttpResponse_AddCharToResponseHeaders(usNextBlock);
00333     
00334         /// If payload length is more than 125 bytes, we need 16 bits to represent it.
00335         if(usPayloadLen == (126))
00336         {
00337 
00338             if(usTotalLength < FRAGMENT_LENGTH)
00339                 usPayloadLen = usTotalLength;
00340             else
00341                 usPayloadLen = FRAGMENT_LENGTH;
00342 
00343             if(usPayloadLen >= FRAGMENT_LENGTH - 4)
00344                 usPayloadLen = FRAGMENT_LENGTH - 4;
00345 
00346             usNextBlock = (char)(usPayloadLen>>8);
00347             HttpResponse_AddCharToResponseHeaders(usNextBlock);
00348             usNextBlock = (char)(usPayloadLen);
00349             HttpResponse_AddCharToResponseHeaders(usNextBlock);
00350         }
00351 
00352         HttpResponse_AddStringToResponseHeaders(pucPayLoadData,(usPayloadLen));
00353         wait_ms(2);
00354         if(!WS_SendPacket(uConnection)){
00355             Uart_Write((uint8_t*)"WS_SendPacket error \n\r");
00356             return 0;
00357         }
00358         if(Opcode == WS_CLOSE)
00359         {
00360             Uart_Write((uint8_t*)"WS_Close \n\r");
00361             sl_WebSocketCloseEvtHdlr();
00362             wait(1);
00363             (HttpCore_CloseConnection(uConnection));
00364             return 1;
00365         }
00366 
00367         usTotalLength -= (usPayloadLen);
00368         // Reset to continuation frame if packet is larger than max fragment size
00369         Opcode = WS_CONTINUATION;
00370 
00371         ///Reset byte
00372         usNextBlock = 0x0;
00373 
00374         //Update pointer
00375         pucPayLoadData += usPayloadLen;
00376 
00377     }while(usTotalLength > 0);
00378 
00379     return 1;
00380 }
00381 
00382 
00383 /**
00384  * Returns status string according to status code - CHANGE
00385  */
00386 void WSStatusString(UINT32 WS_Status, struct HttpBlob* status)
00387 {
00388     HttpString_utoa(WS_Status, status);
00389     struct HttpBlob blob = {0, NULL};
00390     switch (WS_Status)
00391     {
00392     case WS_STATUS_OK:
00393         HttpBlobSetConst(blob, WS_STATUS_OK_STR);
00394         break;
00395     case WS_STATUS_GOING_AWAY:
00396         HttpBlobSetConst(blob, WS_STATUS_GOING_AWAY_STR);
00397         break;
00398     case WS_STATUS_ERROR_DATATYPE:
00399         HttpBlobSetConst(blob, WS_STATUS_ERROR_DATATYPE_STR);
00400         break;
00401     case WS_STATUS_ERROR_ENCODING:
00402         HttpBlobSetConst(blob, WS_STATUS_ERROR_ENCODING_STR);
00403         break;
00404     case WS_STATUS_ERROR_OVERFLOW:
00405         HttpBlobSetConst(blob, WS_STATUS_ERROR_OVERFLOW_STR);
00406         break;
00407     case WS_STATUS_ERROR_PROTOCOL:
00408         HttpBlobSetConst(blob, WS_STATUS_ERROR_PROTOCOL_STR);
00409         break;
00410     case WS_STATUS_ERROR_UNEXPECTED:
00411         HttpBlobSetConst(blob, WS_STATUS_ERROR_UNEXPECTED_STR);
00412         break;
00413     default:
00414         HttpDebug("Unknown response status \n\r");
00415         HttpAssert(0);
00416         break;
00417     }
00418     memcpy(status->pData + status->uLength, blob.pData, blob.uLength);
00419     return;
00420 }
00421 
00422 /// @}
00423