A Secure WebSocket client example that shows how to use the WebSocket library in SharkSSL-Lite
Dependencies: EthernetInterface SharkSSL-Lite mbed-rtos mbed
The example connects to an online echo service and requires that you connect a terminal via the ''mbed Serial Port'. Windows users must install the Windows serial port driver.
The following screenshot shows Putty connected to the mbed serial terminal and after entering a few lines of text.
WsEchoClient.cpp
- Committer:
- wini
- Date:
- 2016-04-06
- Revision:
- 0:3a00a9689a7e
File content as of revision 0:3a00a9689a7e:
/** * ____ _________ __ _ * / __ \___ ____ _/ /_ __(_)___ ___ ___ / / ____ ____ _(_)____ * / /_/ / _ \/ __ `/ / / / / / __ `__ \/ _ \/ / / __ \/ __ `/ / ___/ * / _, _/ __/ /_/ / / / / / / / / / / / __/ /___/ /_/ / /_/ / / /__ * /_/ |_|\___/\__,_/_/ /_/ /_/_/ /_/ /_/\___/_____/\____/\__, /_/\___/ * /____/ * * SharkSSL Embedded SSL/TLS Stack **************************************************************************** * PROGRAM MODULE * * $Id: WsEchoClient.c 3616 2014-12-03 00:40:53Z wini $ * * COPYRIGHT: Real Time Logic LLC, 2016 * * This software is copyrighted by and is the sole property of Real * Time Logic LLC. All rights, title, ownership, or other interests in * the software remain the property of Real Time Logic LLC. This * software may only be used in accordance with the terms and * conditions stipulated in the corresponding license agreement under * which the software has been supplied. Any unauthorized use, * duplication, transmission, distribution, or disclosure of this * software is expressly forbidden. * * This Copyright notice may not be removed or modified without prior * written consent of Real Time Logic LLC. * * Real Time Logic LLC. reserves the right to modify this software * without notice. * * http://sharkssl.com **************************************************************************** Secure WebSocket Example WebSocket (WS) is a new standard enabling full duplex asynchronous communication between a web server and a client and vice versa. WS can be used as a base for M2M communication. See the following page for an introduction to the protocol: http://en.wikipedia.org/wiki/WebSocket The example is by default connecting to the WebSocket echo service at realtimelogic.info. Compiling the code with ECHO_EX makes the example connect to echo.websocket.org. The WebSocket service at realtimelogic.info can respond to both RSA and ECC clients, but the echo service echo.websocket.org will only respond with an RSA certificate. For this reason, connecting to echo.websocket.org will fail if you have compiled SharkSSL with the option to exclude RSA and to only include support for ECC. */ #include "WsClientLib.h" #include <mbed.h> #include <stdarg.h> /* The #WSHOST and #WSURI macros must point to your WebSocket server. */ #ifdef ECHO_EX #define WSHOST "echo.websocket.org" #define WSURI "/" #else #define WSHOST "realtimelogic.info" #define WSURI "/WS-ELIZA/" #endif /************************* Helper functions ******************************/ Serial pc(USBTX, USBRX); // tx, rx /* Example code and selib.c use function xprintf. */ void _xprintf(const char* fmt, ...) { va_list varg; va_start(varg, fmt); vprintf(fmt, varg); va_end(varg); } /************************************************************************** The following code is designed specifically for this example and enables non blocking read from the console. The example's main loop is single threaded and we most therefore use non blocking functions for reading from the console. ***************************************************************************/ /* Function pollkb requires non blocking keyboard I/O. */ /* Platform specific function for non blocking keyboard read. */ static int pollkb(void) { if(pc.readable()) { int c = pc.getc(); return c=='\r' ? '\n' : c; } return 0; } /************ End non blocking console functions ***********************/ /* The main function connects to a WS echo server, by using the generic WS functions defined above. The function connects to the server defined by the macro #WSHOST. See WsClientLib.h for details. */ void mainTask(SeCtx* ctx) { /* Info printed to the console when the program starts */ static const char info[] = { "SharkSSL Websocket client demo.\n" "Copyright (c) 2016 Real Time Logic. All rights reserved.\n" "Connecting to wss://" WSHOST }; SharkSsl sharkSsl; SharkSslCon* sharkSslCon; SOCKET sock; int rc,status; WscReadState wss={0}; xprintf(("%s",info)); xprintf(("y\n\n")); xprintf(("Connecting to " WSHOST "...\n")); /* Port 443 is the listen port for secure servers i.e. HTTPS */ status=se_connect(&sock, WSHOST, 443); if(status) { const char* msg; switch(status) { case -1: msg="Socket error!"; break; case -2: msg="Cannot resolve IP address for " WSHOST "."; break; default: msg="Cannot connect to " WSHOST "."; } xprintf(( "%s\n%s", msg, status == -1 ? "" : "Note: this example is not designed to connect via a HTTP proxy.\n")); return; } /* It is common to create one (or several) SharkSsl object(s) at system start and to keep these objects for the lifetime of the program/firmware. */ SharkSsl_constructor(&sharkSsl, SharkSsl_Client, /* Two options: client or server */ 0, /* Not using SSL cache */ 4000, /* initial inBuf size: Can grow */ 4000); /* outBuf size: Fixed */ /* It is very important to seed the SharkSSL RNG generator (Ref-seed) */ sharkssl_entropy(baGetUnixTime() ^ (U32)&sharkSsl); if( (sharkSslCon = SharkSsl_createCon(&sharkSsl)) == 0) xprintf(("Cannot create SharkSslCon object.\n")); else /* We are now connected to the server. */ { /* Keep seeding (Make it more secure: Ref-seed) */ sharkssl_entropy(baGetUnixTime() ^ (U32)&sharkSsl); /* Establish a WS connection */ if( ! wscProtocolHandshake(&wss, sharkSslCon, &sock,6000,WSHOST,WSURI,0)) { U8 sbuf[255]; int sbufIx=0; /* sbuf cursor */ U8* rbuf; /* Receive buffer is managed by SharkSSL */ int idleCounter=0; #ifdef ECHO_EX xprintf(("\n------\nConnected\nEnter data and press the ENTER key\n")); #endif while((rc = wscRead(&wss,sharkSslCon,&sock,&rbuf,50)) >= 0) { if(rc) /* incomming data from server */ { idleCounter=0; #ifdef ECHO_EX xprintf(("Received %d bytes from server:\n",wss.frameLen)); #endif do { int len=rc; while(len--) xprintf(("%c", *rbuf++)); if(wss.bytesRead == wss.frameLen) break; /* We are done receiving the current frame */ } while( (rc=wscRead(&wss,sharkSslCon,&sock,&rbuf,10000)) > 0 ); #ifdef ECHO_EX xprintf(("\nEnd WS frame.\n")); #endif if(rc <= 0) break; } else /* 50 ms timeout */ { int c; /* Check if we have console data i.e. if user * entered text into the console. */ while((c=pollkb())!=0) { xprintf(("%c",c)); sbuf[sbufIx++] = (U8)c; /* Flush on ENTER or if buffer is full */ if(c == '\n' || sbufIx == sizeof(sbuf)) { /* Send console data to server */ rc = wscSendBin(sharkSslCon,&sock,sbuf,sbufIx); sbufIx=0; idleCounter=0; if(c != '\n') xprintf(("\n")); break; } } if(rc < 0) break; } if(rc == 0) { if(++idleCounter == 100) /* 50ms * 100: 5 sec */ { static const U8 msg[]={"Are you still there?"}; idleCounter=0; /* There are no WS requirements for sending * pings. This is just an example. (Ref-Ping). Note, * ping payload data is not required. */ rc=wscSendCtrl( sharkSslCon,&sock,WSOP_Ping,msg,sizeof(msg)-1); if(rc < 0) break; } } } } /* Release resources used by sharkSslCon */ SharkSsl_terminateCon(&sharkSsl, sharkSslCon); } SharkSsl_destructor(&sharkSsl); se_close(&sock); /*! [inline doc] */ xprintf(("\nServer connection closed!")); }