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.

/media/uploads/wini/websocket-example.png

Committer:
wini
Date:
Wed Apr 06 16:43:26 2016 +0000
Revision:
0:3a00a9689a7e
First release

Who changed what in which revision?

UserRevisionLine numberNew contents of line
wini 0:3a00a9689a7e 1 /**
wini 0:3a00a9689a7e 2 * ____ _________ __ _
wini 0:3a00a9689a7e 3 * / __ \___ ____ _/ /_ __(_)___ ___ ___ / / ____ ____ _(_)____
wini 0:3a00a9689a7e 4 * / /_/ / _ \/ __ `/ / / / / / __ `__ \/ _ \/ / / __ \/ __ `/ / ___/
wini 0:3a00a9689a7e 5 * / _, _/ __/ /_/ / / / / / / / / / / / __/ /___/ /_/ / /_/ / / /__
wini 0:3a00a9689a7e 6 * /_/ |_|\___/\__,_/_/ /_/ /_/_/ /_/ /_/\___/_____/\____/\__, /_/\___/
wini 0:3a00a9689a7e 7 * /____/
wini 0:3a00a9689a7e 8 *
wini 0:3a00a9689a7e 9 * SharkSSL Embedded SSL/TLS Stack
wini 0:3a00a9689a7e 10 ****************************************************************************
wini 0:3a00a9689a7e 11 * PROGRAM MODULE
wini 0:3a00a9689a7e 12 *
wini 0:3a00a9689a7e 13 * $Id: WsEchoClient.c 3616 2014-12-03 00:40:53Z wini $
wini 0:3a00a9689a7e 14 *
wini 0:3a00a9689a7e 15 * COPYRIGHT: Real Time Logic LLC, 2016
wini 0:3a00a9689a7e 16 *
wini 0:3a00a9689a7e 17 * This software is copyrighted by and is the sole property of Real
wini 0:3a00a9689a7e 18 * Time Logic LLC. All rights, title, ownership, or other interests in
wini 0:3a00a9689a7e 19 * the software remain the property of Real Time Logic LLC. This
wini 0:3a00a9689a7e 20 * software may only be used in accordance with the terms and
wini 0:3a00a9689a7e 21 * conditions stipulated in the corresponding license agreement under
wini 0:3a00a9689a7e 22 * which the software has been supplied. Any unauthorized use,
wini 0:3a00a9689a7e 23 * duplication, transmission, distribution, or disclosure of this
wini 0:3a00a9689a7e 24 * software is expressly forbidden.
wini 0:3a00a9689a7e 25 *
wini 0:3a00a9689a7e 26 * This Copyright notice may not be removed or modified without prior
wini 0:3a00a9689a7e 27 * written consent of Real Time Logic LLC.
wini 0:3a00a9689a7e 28 *
wini 0:3a00a9689a7e 29 * Real Time Logic LLC. reserves the right to modify this software
wini 0:3a00a9689a7e 30 * without notice.
wini 0:3a00a9689a7e 31 *
wini 0:3a00a9689a7e 32 * http://sharkssl.com
wini 0:3a00a9689a7e 33 ****************************************************************************
wini 0:3a00a9689a7e 34
wini 0:3a00a9689a7e 35
wini 0:3a00a9689a7e 36 Secure WebSocket Example
wini 0:3a00a9689a7e 37
wini 0:3a00a9689a7e 38 WebSocket (WS) is a new standard enabling full duplex asynchronous
wini 0:3a00a9689a7e 39 communication between a web server and a client and vice versa. WS can
wini 0:3a00a9689a7e 40 be used as a base for M2M communication. See the following page for an
wini 0:3a00a9689a7e 41 introduction to the protocol: http://en.wikipedia.org/wiki/WebSocket
wini 0:3a00a9689a7e 42
wini 0:3a00a9689a7e 43 The example is by default connecting to the WebSocket echo service at
wini 0:3a00a9689a7e 44 realtimelogic.info. Compiling the code with ECHO_EX makes the example
wini 0:3a00a9689a7e 45 connect to echo.websocket.org.
wini 0:3a00a9689a7e 46
wini 0:3a00a9689a7e 47 The WebSocket service at realtimelogic.info can respond to both RSA
wini 0:3a00a9689a7e 48 and ECC clients, but the echo service echo.websocket.org will only
wini 0:3a00a9689a7e 49 respond with an RSA certificate. For this reason, connecting to
wini 0:3a00a9689a7e 50 echo.websocket.org will fail if you have compiled SharkSSL with the
wini 0:3a00a9689a7e 51 option to exclude RSA and to only include support for ECC.
wini 0:3a00a9689a7e 52
wini 0:3a00a9689a7e 53 */
wini 0:3a00a9689a7e 54
wini 0:3a00a9689a7e 55 #include "WsClientLib.h"
wini 0:3a00a9689a7e 56 #include <mbed.h>
wini 0:3a00a9689a7e 57 #include <stdarg.h>
wini 0:3a00a9689a7e 58
wini 0:3a00a9689a7e 59 /*
wini 0:3a00a9689a7e 60 The #WSHOST and #WSURI macros must point to your WebSocket server.
wini 0:3a00a9689a7e 61 */
wini 0:3a00a9689a7e 62 #ifdef ECHO_EX
wini 0:3a00a9689a7e 63 #define WSHOST "echo.websocket.org"
wini 0:3a00a9689a7e 64 #define WSURI "/"
wini 0:3a00a9689a7e 65 #else
wini 0:3a00a9689a7e 66 #define WSHOST "realtimelogic.info"
wini 0:3a00a9689a7e 67 #define WSURI "/WS-ELIZA/"
wini 0:3a00a9689a7e 68 #endif
wini 0:3a00a9689a7e 69
wini 0:3a00a9689a7e 70
wini 0:3a00a9689a7e 71 /************************* Helper functions ******************************/
wini 0:3a00a9689a7e 72
wini 0:3a00a9689a7e 73 Serial pc(USBTX, USBRX); // tx, rx
wini 0:3a00a9689a7e 74
wini 0:3a00a9689a7e 75 /* Example code and selib.c use function xprintf.
wini 0:3a00a9689a7e 76 */
wini 0:3a00a9689a7e 77 void _xprintf(const char* fmt, ...)
wini 0:3a00a9689a7e 78 {
wini 0:3a00a9689a7e 79 va_list varg;
wini 0:3a00a9689a7e 80 va_start(varg, fmt);
wini 0:3a00a9689a7e 81 vprintf(fmt, varg);
wini 0:3a00a9689a7e 82 va_end(varg);
wini 0:3a00a9689a7e 83 }
wini 0:3a00a9689a7e 84
wini 0:3a00a9689a7e 85
wini 0:3a00a9689a7e 86 /**************************************************************************
wini 0:3a00a9689a7e 87 The following code is designed specifically for this example and
wini 0:3a00a9689a7e 88 enables non blocking read from the console. The example's main loop is
wini 0:3a00a9689a7e 89 single threaded and we most therefore use non blocking functions for
wini 0:3a00a9689a7e 90 reading from the console.
wini 0:3a00a9689a7e 91 ***************************************************************************/
wini 0:3a00a9689a7e 92
wini 0:3a00a9689a7e 93
wini 0:3a00a9689a7e 94 /* Function pollkb requires non blocking keyboard I/O.
wini 0:3a00a9689a7e 95 */
wini 0:3a00a9689a7e 96
wini 0:3a00a9689a7e 97 /* Platform specific function for non blocking keyboard read.
wini 0:3a00a9689a7e 98 */
wini 0:3a00a9689a7e 99 static int
wini 0:3a00a9689a7e 100 pollkb(void)
wini 0:3a00a9689a7e 101 {
wini 0:3a00a9689a7e 102 if(pc.readable())
wini 0:3a00a9689a7e 103 {
wini 0:3a00a9689a7e 104 int c = pc.getc();
wini 0:3a00a9689a7e 105 return c=='\r' ? '\n' : c;
wini 0:3a00a9689a7e 106 }
wini 0:3a00a9689a7e 107 return 0;
wini 0:3a00a9689a7e 108 }
wini 0:3a00a9689a7e 109
wini 0:3a00a9689a7e 110
wini 0:3a00a9689a7e 111
wini 0:3a00a9689a7e 112 /************ End non blocking console functions ***********************/
wini 0:3a00a9689a7e 113
wini 0:3a00a9689a7e 114
wini 0:3a00a9689a7e 115
wini 0:3a00a9689a7e 116 /*
wini 0:3a00a9689a7e 117 The main function connects to a WS echo server, by using the generic
wini 0:3a00a9689a7e 118 WS functions defined above.
wini 0:3a00a9689a7e 119
wini 0:3a00a9689a7e 120 The function connects to the server defined by the macro #WSHOST. See
wini 0:3a00a9689a7e 121 WsClientLib.h for details.
wini 0:3a00a9689a7e 122 */
wini 0:3a00a9689a7e 123 void
wini 0:3a00a9689a7e 124 mainTask(SeCtx* ctx)
wini 0:3a00a9689a7e 125 {
wini 0:3a00a9689a7e 126 /* Info printed to the console when the program starts
wini 0:3a00a9689a7e 127 */
wini 0:3a00a9689a7e 128 static const char info[] = {
wini 0:3a00a9689a7e 129 "SharkSSL Websocket client demo.\n"
wini 0:3a00a9689a7e 130 "Copyright (c) 2016 Real Time Logic. All rights reserved.\n"
wini 0:3a00a9689a7e 131 "Connecting to wss://" WSHOST
wini 0:3a00a9689a7e 132 };
wini 0:3a00a9689a7e 133
wini 0:3a00a9689a7e 134 SharkSsl sharkSsl;
wini 0:3a00a9689a7e 135 SharkSslCon* sharkSslCon;
wini 0:3a00a9689a7e 136 SOCKET sock;
wini 0:3a00a9689a7e 137 int rc,status;
wini 0:3a00a9689a7e 138
wini 0:3a00a9689a7e 139 WscReadState wss={0};
wini 0:3a00a9689a7e 140
wini 0:3a00a9689a7e 141 xprintf(("%s",info));
wini 0:3a00a9689a7e 142 xprintf(("y\n\n"));
wini 0:3a00a9689a7e 143 xprintf(("Connecting to " WSHOST "...\n"));
wini 0:3a00a9689a7e 144 /* Port 443 is the listen port for secure servers i.e. HTTPS */
wini 0:3a00a9689a7e 145 status=se_connect(&sock, WSHOST, 443);
wini 0:3a00a9689a7e 146 if(status)
wini 0:3a00a9689a7e 147 {
wini 0:3a00a9689a7e 148 const char* msg;
wini 0:3a00a9689a7e 149 switch(status)
wini 0:3a00a9689a7e 150 {
wini 0:3a00a9689a7e 151 case -1: msg="Socket error!";
wini 0:3a00a9689a7e 152 break;
wini 0:3a00a9689a7e 153 case -2: msg="Cannot resolve IP address for " WSHOST ".";
wini 0:3a00a9689a7e 154 break;
wini 0:3a00a9689a7e 155 default: msg="Cannot connect to " WSHOST ".";
wini 0:3a00a9689a7e 156 }
wini 0:3a00a9689a7e 157 xprintf((
wini 0:3a00a9689a7e 158 "%s\n%s",
wini 0:3a00a9689a7e 159 msg,
wini 0:3a00a9689a7e 160 status == -1 ? "" :
wini 0:3a00a9689a7e 161 "Note: this example is not designed to connect via a HTTP proxy.\n"));
wini 0:3a00a9689a7e 162 return;
wini 0:3a00a9689a7e 163 }
wini 0:3a00a9689a7e 164
wini 0:3a00a9689a7e 165 /* It is common to create one (or several) SharkSsl object(s) at
wini 0:3a00a9689a7e 166 system start and to keep these objects for the lifetime of the
wini 0:3a00a9689a7e 167 program/firmware.
wini 0:3a00a9689a7e 168 */
wini 0:3a00a9689a7e 169 SharkSsl_constructor(&sharkSsl,
wini 0:3a00a9689a7e 170 SharkSsl_Client, /* Two options: client or server */
wini 0:3a00a9689a7e 171 0, /* Not using SSL cache */
wini 0:3a00a9689a7e 172 4000, /* initial inBuf size: Can grow */
wini 0:3a00a9689a7e 173 4000); /* outBuf size: Fixed */
wini 0:3a00a9689a7e 174
wini 0:3a00a9689a7e 175 /* It is very important to seed the SharkSSL RNG generator (Ref-seed) */
wini 0:3a00a9689a7e 176 sharkssl_entropy(baGetUnixTime() ^ (U32)&sharkSsl);
wini 0:3a00a9689a7e 177
wini 0:3a00a9689a7e 178 if( (sharkSslCon = SharkSsl_createCon(&sharkSsl)) == 0)
wini 0:3a00a9689a7e 179 xprintf(("Cannot create SharkSslCon object.\n"));
wini 0:3a00a9689a7e 180 else /* We are now connected to the server. */
wini 0:3a00a9689a7e 181 {
wini 0:3a00a9689a7e 182 /* Keep seeding (Make it more secure: Ref-seed) */
wini 0:3a00a9689a7e 183 sharkssl_entropy(baGetUnixTime() ^ (U32)&sharkSsl);
wini 0:3a00a9689a7e 184 /* Establish a WS connection */
wini 0:3a00a9689a7e 185 if( ! wscProtocolHandshake(&wss, sharkSslCon, &sock,6000,WSHOST,WSURI,0))
wini 0:3a00a9689a7e 186 {
wini 0:3a00a9689a7e 187 U8 sbuf[255];
wini 0:3a00a9689a7e 188 int sbufIx=0; /* sbuf cursor */
wini 0:3a00a9689a7e 189 U8* rbuf; /* Receive buffer is managed by SharkSSL */
wini 0:3a00a9689a7e 190 int idleCounter=0;
wini 0:3a00a9689a7e 191 #ifdef ECHO_EX
wini 0:3a00a9689a7e 192 xprintf(("\n------\nConnected\nEnter data and press the ENTER key\n"));
wini 0:3a00a9689a7e 193 #endif
wini 0:3a00a9689a7e 194 while((rc = wscRead(&wss,sharkSslCon,&sock,&rbuf,50)) >= 0)
wini 0:3a00a9689a7e 195 {
wini 0:3a00a9689a7e 196 if(rc) /* incomming data from server */
wini 0:3a00a9689a7e 197 {
wini 0:3a00a9689a7e 198 idleCounter=0;
wini 0:3a00a9689a7e 199 #ifdef ECHO_EX
wini 0:3a00a9689a7e 200 xprintf(("Received %d bytes from server:\n",wss.frameLen));
wini 0:3a00a9689a7e 201 #endif
wini 0:3a00a9689a7e 202 do
wini 0:3a00a9689a7e 203 {
wini 0:3a00a9689a7e 204 int len=rc;
wini 0:3a00a9689a7e 205 while(len--)
wini 0:3a00a9689a7e 206 xprintf(("%c", *rbuf++));
wini 0:3a00a9689a7e 207 if(wss.bytesRead == wss.frameLen)
wini 0:3a00a9689a7e 208 break; /* We are done receiving the current frame */
wini 0:3a00a9689a7e 209 } while( (rc=wscRead(&wss,sharkSslCon,&sock,&rbuf,10000)) > 0 );
wini 0:3a00a9689a7e 210 #ifdef ECHO_EX
wini 0:3a00a9689a7e 211 xprintf(("\nEnd WS frame.\n"));
wini 0:3a00a9689a7e 212 #endif
wini 0:3a00a9689a7e 213 if(rc <= 0) break;
wini 0:3a00a9689a7e 214 }
wini 0:3a00a9689a7e 215 else /* 50 ms timeout */
wini 0:3a00a9689a7e 216 {
wini 0:3a00a9689a7e 217 int c;
wini 0:3a00a9689a7e 218 /* Check if we have console data i.e. if user
wini 0:3a00a9689a7e 219 * entered text into the console. */
wini 0:3a00a9689a7e 220 while((c=pollkb())!=0)
wini 0:3a00a9689a7e 221 {
wini 0:3a00a9689a7e 222 xprintf(("%c",c));
wini 0:3a00a9689a7e 223 sbuf[sbufIx++] = (U8)c;
wini 0:3a00a9689a7e 224 /* Flush on ENTER or if buffer is full */
wini 0:3a00a9689a7e 225 if(c == '\n' || sbufIx == sizeof(sbuf))
wini 0:3a00a9689a7e 226 {
wini 0:3a00a9689a7e 227 /* Send console data to server */
wini 0:3a00a9689a7e 228 rc = wscSendBin(sharkSslCon,&sock,sbuf,sbufIx);
wini 0:3a00a9689a7e 229 sbufIx=0;
wini 0:3a00a9689a7e 230 idleCounter=0;
wini 0:3a00a9689a7e 231 if(c != '\n')
wini 0:3a00a9689a7e 232 xprintf(("\n"));
wini 0:3a00a9689a7e 233 break;
wini 0:3a00a9689a7e 234 }
wini 0:3a00a9689a7e 235 }
wini 0:3a00a9689a7e 236 if(rc < 0) break;
wini 0:3a00a9689a7e 237 }
wini 0:3a00a9689a7e 238 if(rc == 0)
wini 0:3a00a9689a7e 239 {
wini 0:3a00a9689a7e 240 if(++idleCounter == 100) /* 50ms * 100: 5 sec */
wini 0:3a00a9689a7e 241 {
wini 0:3a00a9689a7e 242 static const U8 msg[]={"Are you still there?"};
wini 0:3a00a9689a7e 243 idleCounter=0;
wini 0:3a00a9689a7e 244 /* There are no WS requirements for sending
wini 0:3a00a9689a7e 245 * pings. This is just an example. (Ref-Ping). Note,
wini 0:3a00a9689a7e 246 * ping payload data is not required.
wini 0:3a00a9689a7e 247 */
wini 0:3a00a9689a7e 248 rc=wscSendCtrl(
wini 0:3a00a9689a7e 249 sharkSslCon,&sock,WSOP_Ping,msg,sizeof(msg)-1);
wini 0:3a00a9689a7e 250 if(rc < 0) break;
wini 0:3a00a9689a7e 251 }
wini 0:3a00a9689a7e 252 }
wini 0:3a00a9689a7e 253 }
wini 0:3a00a9689a7e 254 }
wini 0:3a00a9689a7e 255 /* Release resources used by sharkSslCon */
wini 0:3a00a9689a7e 256 SharkSsl_terminateCon(&sharkSsl, sharkSslCon);
wini 0:3a00a9689a7e 257 }
wini 0:3a00a9689a7e 258
wini 0:3a00a9689a7e 259 SharkSsl_destructor(&sharkSsl);
wini 0:3a00a9689a7e 260 se_close(&sock);
wini 0:3a00a9689a7e 261 /*! [inline doc] */
wini 0:3a00a9689a7e 262 xprintf(("\nServer connection closed!"));
wini 0:3a00a9689a7e 263 }
wini 0:3a00a9689a7e 264