Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
gwsocket(1)			  User Manuals			     gwsocket(1)

NAME
     gwsocket  is a standalone, simple, yet powerful rfc6455 compliant WebSocket
     Server.

SYNOPSIS
     gwsocket -p [--addr][--origin][gwsocket options ...]

DESCRIPTION
     gwsocket is a free (MIT Licensed), standalone, WebSocket  Server.	It  sits
     between  your  application and the client's browser, giving the ability for
     bidirectional communication between these two with ease and flexibility.

Start the Server
     You can run gwsocket without passing any options to the  command  line.  By
     default,  it  will  listen  on  port  7890  on  all  the  interfaces, e.g.,
     127.0.0.1, ::1, etc. For instance:

     # gwsocket --access-log=/tmp/access.log Note: See a basic client-side exam-
     ple at the bottom of the man page.

OPTIONS
     -p --port
	    Specifies the port to bind.

     -h --help
	    Command line help.

     -V --version
	    Display version information and exit.

     --access-log=<path/file>
	    Specifies the path/file for the access log.

     --addr=<addr>
	    Specifies the address to bind.

     --echo-mode
	    Set the server to echo all received messages.

     --max-frame-size=<bytes>
	    Maximum size of a websocket frame.	This  includes	received  frames
	    from the client and messages through the named pipe.

     --origin=<origin>
	    Ensure  clients  send the specified origin header upon the WebSocket
	    handshake.

     --pipein=<path/file>
	    Creates a named pipe (FIFO) that reads from on the given path/file.

     --pipeout=<path/file>
	    Creates a named pipe (FIFO) that writes to the given path/file.

     --strict
	    Parse messages using strict mode. See below for more details.

     --ssl-cert=<cert.crt>
	    Path to TLS/SSL certificate.

     --ssl-key=<priv.key>
	    Path to TLS/SSL private key.

CONFIGURATION
     --enable-debug
	    Compile with debugging symbols and turn off compiler optimizations.

     --with-openssl
	    Compile gwsocket with OpenSSL support for its WebSocket server.

DATA MODES
     In order to establish a channel between your application and  the	client's
     browser,  gwsocket provides two methods that allow the user to send data in
     and out. The first one is through the use of  the	standard  input  (stdin)
     ,and  the standard output (stdout) followed by the payload. See options be-
     low for more details.

   1. stdin/stdout
     The standard input/output is the simplest	way  of  sending/receiving  data
     to/from  a  client.  However,  it's limited to broadcasting messages to all
     clients. To send messages to or receive from a  specific  client,	use  the
     strict mode in section 2.

   1.1 Sending Data to all Clients ^a stdout
     If  you  need  to	broadcast data from your application to all clients con-
     nected to gwsocket, then, the simplest way of doing it is	by  piping  your
     application  output  into	a  named pipe (also known as FIFO) that gwsocket
     makes use of. Once gwsocket receives the payload, then  it  will  automati-
     cally broadcast the message to all connected clients.

   1.1. Examples
       #include <fcntl.h>
       #include <sys/stat.h>
       #include <sys/types.h>
       #include <unistd.h>

       int main() {
	   int fd;
	   char *myfifo = "/tmp/wspipein.fifo";
	   const char *msg = "Message to broadcast";

	   fd = open(myfifo, O_WRONLY);
	   write(fd, msg, strlen(msg));
	   close(fd);

	   return 0;
       }

     Note: You can send as many bytes PIPE_BUF can hold. If a message is greater
     than  PIPE_BUF, it would send the rest on a second message or third, and so
     on. See strict mode below for more control over messages.

   1.2 Receiving Data from Clients ^a stdin
     When a client sends a message to the server, it is possible to capture that
     message in your application. To do this, your application simply  needs  to
     read  from  a  named  pipe.  By  default,	gwsocket  creates  a  FIFO under
     /tmp/wspipeout.fifo.

   1.2. Examples
     Receiving data can be as simple as doing a # cat /tmp/wspipeout.fifo or you
     can do it in the language of your choice. See examples below.

       #include <stdio.h>
       #include <stdlib.h>
       #include <fcntl.h>
       #include <limits.h>

       static void read_message (int fd, fd_set set) {
	 int bytes = 0;
	 char buf[PIPE_BUF] = { 0 };

	 FD_ZERO (&set);
	 FD_SET (fd, &set);

	 if ((select (fd + 1, &set, NULL, NULL, NULL)) < 1)
	   exit (1);
	 if (!FD_ISSET (fd, &set))
	   return;

	 if (read (fd, buf, PIPE_BUF) > 0)
	   printf ("%s0, buf);
       }

       int main (void) {
	 fd_set set;
	 char *fifo = "/tmp/wspipeout.fifo";
	 int fd = 0;

	 if ((fd = open (fifo, O_RDWR | O_NONBLOCK)) < 0)
	   exit (1);
	 while (1)
	   read_message(fd, set);

	 return 0;
       }

     Note: Make sure the reader in your application is set  as	non-blocking  to
     get a constant feed.

     Tip  If  you  need to know which client sent the message, for example, in a
     chat application, please see the strict mode below.

   2. Strict Mode
     gwsocket implements its own tiny protocol for  sending/receiving  data.  In
     contrast  to  the stdin/stdout mode, the strict mode allows you to send/re-
     ceive data to/from specific connected clients as well as to keep  track  of
     who  opened/closed a WebSocket connection. It also gives you the ability to
     pack and send as much data as you would like on a single message.

     2. Data Format

     The message header is a fixed-size header. The first  12  bytes  (uint32_t)
     are packed in network byte order and contain the "meta-data" of the message
     we are sending/receiving. The rest of it is the actual message.

       0	    1		    2		     3
       +---------------------------------------------+
       |	Client Socket Id (listener)	     |
       +---------------------------------------------+
       |    Message Type (binary: 0x2 / text: 0x1)   |
       +---------------------------------------------+
       |	     Payload length		     |
       +---------------------------------------------+
       |	      Payload Data		     |
       +---------------------------------------------+

   2.1 Sending Data ^a Strict Mode
     If  you  need to send a message to a specific client, then you can do so by
     specifying the client id in the message header. If set to	0,  the  message
     will  be broadcasted to all clients. The first 4 bytes are reserved for the
     client id or listener. The following 4 bytes are reserved for  the  message
     type.  0x01 for a text message, and 0x02 for a binary message. And the last
     4 bytes are reserved for the payload's length.

     Once the header has been written to the pipe, you may now	write  the  mes-
     sage.

   2.1. Examples
     First, start the server in strict-mode.

     # gwsocket --strict-mode
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <fcntl.h>

       size_t pack_uint32(void* buf, uint32_t val) {
	 uint32_t v32 = htonl(val);
	 memcpy(buf, &v32, sizeof(uint32_t));
	 return sizeof(uint32_t);
       }

       int main() {
	 char *p = calloc (sizeof(uint32_t) * 3, sizeof(char)), *ptr;
	 const char *msg = "Message to broadcast";
	 const char *fifo = "/tmp/wspipein.fifo";
	 int fd;

	 ptr = p;
	 ptr += pack_uint32(ptr, 0);
	 ptr += pack_uint32(ptr, 0x01);
	 ptr += pack_uint32(ptr, strlen(msg));

	 fd = open(fifo, O_WRONLY);
	 write(fd, p, sizeof(uint32_t) * 3);
	 write(fd, msg, strlen(msg));
	 close(fd);
	 free (p);

	 return 0;
       }

   2.2 Receiving Data from Clients ^a Strict Mode
     Now,  to  get  a  message	from  a  specific client and route it to another
     client, you just need to do the opposite of sending data. First you  unpack
     the  header  from	network  byte order to host byte order and then read the
     payload.

   2.2. Examples
     First, start the server in strict-mode.

     # gwsocket --strict-mode
       #include <stdio.h>
       #include <stdlib.h>
       #include <fcntl.h>
       #include <limits.h>
       #include <int.h>

       static size_t unpack_uint32 (const void *b, uint32_t * val) {
	 uint32_t v32 = 0;
	 memcpy (&v32, b, sizeof (uint32_t));
	 *val = ntohl (v32);
	 return sizeof (uint32_t);
       }

       static void read_message (int fd, fd_set set) {
	 int bytes = 0;
	 uint32_t size = 0, listener = 0, type = 0;
	 char hdr[PIPE_BUF] = { 0 }, buf[PIPE_BUF] = {0};
	 char *ptr = NULL;

	 FD_ZERO (&set);
	 FD_SET (fd, &set);

	 if ((select (fd + 1, &set, NULL, NULL, NULL)) < 1)
	   exit (1);
	 if (!FD_ISSET (fd, &set))
	   return;

	 if (hdr[0] == ' ') {
	   if (read (fd, hdr, sizeof (uint32_t) * 3) < 1)
	     return;
	 }

	 ptr = hdr;
	 ptr += unpack_uint32(ptr, &listener);
	 ptr += unpack_uint32(ptr, &type);
	 ptr += unpack_uint32(ptr, &size);

	 if (read (fd, buf, size) < 1)
	   return;

	 printf ("client: %d, msg: %s0, listener, buf);
       }

       int main (void) {
	 fd_set set;
	 char *fifo = "/tmp/wspipeout.fifo";
	 int fd = 0;

	 if ((fd = open (fifo, O_RDWR | O_NONBLOCK)) < 0)
	   exit (1);
	 while (1)
	   read_message(fd, set);

	 return 0;
       }

     Note: If you read/write to a stream, be aware that they do not  necessarily
     read/write  the  full  amount  of data you have requested. Your application
     will need to handle the case where only a single byte is read  or	written.
     Examples above do not handle this.

OBLIGATORY CLIENT EXAMPLE
     Here's  the  basic  example, client and server side. First start the server
     and set it in echo mode.

     # gwsocket --echo-mode

     Now, let's create the client side.

       <!DOCTYPE html>
       <html lang="en">
       <style>
       pre {
	   background: #EEE;
	   border: 1px solid #CCC;
	   padding: 10px;
       }
       #page-wrapper {
	   border-top: 5px solid #69c773;
	   margin: 1em auto;
	   width: 950px;
       }
       </style>
       <script>
       window.onload = function() {
	   function $(selector) {
	       return document.querySelector(selector);
	   }
	   var socket = new WebSocket('ws://localhost:7890');
	   socket.onopen = function(event) {
	       $('#messages').innerHTML = 'Connected<br>';
	   };
	   socket.onmessage = function(event) {
	       $('#messages').innerHTML  +=  'Received:<br>'  +   event.data   +
     '<br>';
	   };
	   socket.onclose = function(event) {
	       $('#messages').innerHTML = 'Disconnected ' + event.reason;
	   };
	   $('#submit').onclick = function(e) {
	       socket.send($('input').value);
	       $('#messages').innerHTML  +=  'Sent:<br>'  +  $('input').value  +
     '<br>';
	       $('input').value = '';
	   };
       };
       </script>

       <div id="page-wrapper">
	   <pre id="messages">Connecting...</pre>
	   <input id="message" required>
	   <button id="submit">Send Message</button>
       </div>

BUGS
     If you think you have found a bug, please send me an email to  hello  [@at]
     goaccess.io.

AUTHOR
     Gerardo  Orellana. For more details about it, or new releases, please visit
     http://gwsocket.io

Linux				   AUGUST 2018			     gwsocket(1)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=gwsocket&sektion=1&manpath=FreeBSD+Ports+15.1.quarterly>

home | help