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

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!"));
+}
+