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.
Diff: WsEchoClient.cpp
- Revision:
- 0:3a00a9689a7e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WsEchoClient.cpp Wed Apr 06 16:43:26 2016 +0000 @@ -0,0 +1,264 @@ +/** + * ____ _________ __ _ + * / __ \___ ____ _/ /_ __(_)___ ___ ___ / / ____ ____ _(_)____ + * / /_/ / _ \/ __ `/ / / / / / __ `__ \/ _ \/ / / __ \/ __ `/ / ___/ + * / _, _/ __/ /_/ / / / / / / / / / / / __/ /___/ /_/ / /_/ / / /__ + * /_/ |_|\___/\__,_/_/ /_/ /_/_/ /_/ /_/\___/_____/\____/\__, /_/\___/ + * /____/ + * + * 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!")); +} +