title: Multiple Sub-protocol Websocket Javascript Client and Libwebsockets Server not working
body: <p>I am trying to create a simple two protocol client and server for a demo. But when I specify two sub-protocols in the client initialization of the websocket I always get this message on the server side:</p>
  
  <pre><code>[1363089953:1535] ERR: Req protocol SIGN_IN_OUT_REQUEST_PROTOCOL, GET_REQUEST_PROTOCOL not supported
  </code></pre>
  
  <p>Client Javascript Code:</p>
  
  <pre><code>    var host = 'ws://10.0.96.32:9000';
  var webSocket = {};
  var websocketStatus = {};
  
  $(function() {
  
          function webSocketSupported() {
              if(window.MozWebSocket) {
                  window.WebSocket = window.MozWebSocket;
              }
              return (window.webSocket != null);
          }
  
          if(!webSocketSupported) { 
             $(document).simpledialog2({
                 mode: 'blank',
                 headerClose: true,
                 blankContent :
                         "&lt;p&gt;Websockets not supported by this browser. How about &lt;a href='http://www.google.com/chrome'&gt;Google Chrome&lt;/a&gt;?&lt;/p&gt;"+
                         "&lt;a rel='close' data-role='button' href='#'&gt;Close&lt;/a&gt;"         
             }); 
          } else {
  
              $("#login_form").validate({
                 rules:{
                     username: {required: true, minlength: 2},
                     password: {required: true, minlength: 4}
                 },
                 messages:{
                     username: {required: "Username is required",
                                minlength: "Username must be atleast 2 characters"},
                     password: {required: "Password is required",
                                minlength: "Password must be atleast 4 characters"}
                 } 
              });
  
              /** Setting up WebSocket **/
              webSocket = new WebSocket(host, 'SIGN_IN_OUT_REQUEST_PROTOCOL', 'GET_REQUEST_PROTOCOL');
              webSocket.binaryType = "arraybuffer";
              webSocket.onopen = onopen;
              webSocket.onmessage = onmessage;
              webSocket.onclose = onclose;
              webSocket.onerror = onerror;           
          }
  });
  
  function onopen() {
      $('#connectionStatus').text("Connected");
      $('#connectionStatus').buttonMarkup({theme: 'b'});
      $("#connectionStatus").data('icon', 'check'); 
      $("#connectionStatus .ui-icon").addClass("ui-icon-check").removeClass("ui-icon-alert");
      $('#login_info').append("Sub-protocol: "+webSocket.protocol+"\n");
  }
  
  function onmessage(event) {
      var data = new DataView(event.data);
      if(data.getUint8(data.byteLength - 1) == 1) {
          $('#login_info').append("Login Attempt Successful");
          $.mobile.loadPage("mobileApp.html");
          $.mobile.changePage("mobileApp.html")
      }
      else {
          $('#login_info').append("Login Attempt Unsuccessful");
          $('#username').val("");
          $('#password').val("");
      }
  }
  
  function onclose() {
      $('#connectionStatus').text("Connection Closed");
      $('#connectionStatus').buttonMarkup({theme: 'a'});
      $("#connectionStatus").data('icon', 'alert'); 
      $("#connectionStatus .ui-icon").addClass("ui-icon-alert").removeClass("ui-icon-alert");
  }
  
  function onerror() {
      $('#connectionStatus').text("Connection Error");
      $('#connectionStatus').buttonMarkup({theme: 'a'});
      $("#connectionStatus").data('icon', 'alert'); 
      $("#connectionStatus .ui-icon").addClass("ui-icon-alert").removeClass("ui-icon-alert");
  }
  
  function initialize() {
      $('#login_info').val("");
      $('#username').val("");
      $('#password').val("");
      $('#connectionStatus').text("Connection Closed");
      $('#connectionStatus').buttonMarkup({theme: 'a'});
      $("#connectionStatus").data('icon', 'alert'); 
      $("#connectionStatus .ui-icon").addClass("ui-icon-alert").removeClass("ui-icon-alert");
  }
  
  function sendLoginRequest(event) {
      var i = 0;
      event.preventDefault();
      if($("#login_form").valid()) {
          var username = $("#username").val();
          var password = $("#password").val();
          var loginRequest = new Uint8Array(calculateBufferLength());
          loginRequest[i++] = 0x13; //User Accounts IP
          loginRequest[i++] = 0x13; //Sign In/Sign Out Request
          loginRequest[i++] = 0x07; //Sign In
          loginRequest[i++] = username.length;
          loginRequest[i++] = password.length;
  
          //Pushing username
          for(var j=0; j &lt; username.length; j++) {
              loginRequest[i++] = username.charCodeAt(j);
          }
  
          //Pushing password
          for(var j=0; j &lt; password.length; j++) {
              loginRequest[i++] = password.charCodeAt(j);
          }
  
          webSocket.send(loginRequest.buffer);
          $("#login_info").append("Login request sent with\nUsername: "+username+"\nPassword: "+password+"\n");
      }
  }
  
  function calculateBufferLength() {
      var opIPLength = 1;
      var modeLength = 1;
      var subModeLength = 1;
      var UserNamePasswordlengths = 2;
      var userNameLength = $("#username").val().length;
      var passwordLength = $("#password").val().length;
      return (opIPLength + modeLength + subModeLength + UserNamePasswordlengths + userNameLength + passwordLength);
  }
  </code></pre>
  
  <p>Server C/C++ code (Libwebsockets)</p>
  
  <pre><code>    #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;string&gt;
  #include &lt;vector&gt;
  #include &lt;libwebsockets.h&gt;
  
  using namespace std;
  
  typedef enum {
      USER_ACCOUNTS_IP_REQUEST,
      MODE,
      SUB_MODE,
      USER_NAME_LENGTH,
      PASSWORD_LENGTH
  }user_accounts_ip_request_t;
  
  typedef enum {
      USER_ACCOUNTS_IP_RESPONSE,
      RESPONSE_IP
  }user_accounts_ip_response_t;
  
  int Hex_to_Dec(unsigned char *array, int size);
  void sendLoginResponse(struct libwebsocket *wsi, void *in_buffer, size_t bufferlen, struct per_session_data__binary *out_buffer);
  void printSocketInfo(struct libwebsocket *wsi, struct libwebsocket_context *currentContext);
  
  struct per_session_data__binary
  {
      unsigned int len;
      unsigned char buf[sizeof(LWS_SEND_BUFFER_PRE_PADDING) + 1024 + sizeof(LWS_SEND_BUFFER_POST_PADDING)];
  };
  
  static int callback_http(struct libwebsocket_context *currentContext,
                           struct libwebsocket *wsi,
                           enum libwebsocket_callback_reasons reason, void *user,
                           void *in, size_t len)
  {
      return 0;
  }
  
  static int callback_sign_in_out_request(struct libwebsocket_context *currentContext,
                                     struct libwebsocket *wsi,
                                     enum libwebsocket_callback_reasons reason,
                                     void *user, void *in, size_t len)
  {
      struct per_session_data__binary *psb = (per_session_data__binary *)user;   ////////
  
      switch (reason) {
          case LWS_CALLBACK_ESTABLISHED: // just log message that someone is connecting
              printf("connection established\n");
              break;
          case LWS_CALLBACK_PROTOCOL_INIT:
              printf("LWS_CALLBACK_PROTOCOL_INIT\n");
              break;
          case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
              printf("LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n");
              break;
          case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH:
              printf("LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH\n");
              break;
          case LWS_CALLBACK_RECEIVE: {
              printf("Binary frame received decoding packet...\n");
              sendLoginResponse(wsi, in, len, psb);
          }
              break;
          default:
                      break;
      }
          return 0;
  }
  
  static int callback_get_request(struct libwebsocket_context *currentContext,
          struct libwebsocket *wsi,
          enum libwebsocket_callback_reasons reason,
          void *user, void *in, size_t len)
  {
      return 0;
  }
  
  static struct libwebsocket_protocols protocols[] = {
      /* first protocol must always be HTTP handler */
      {
          "http-only",   // name
          callback_http, // callback
          0              // per_session_data_size
      },
      {
          "SIGN_IN_OUT_REQUEST_PROTOCOL", // protocol name - very important!
          callback_sign_in_out_request,   // callback
          sizeof(struct per_session_data__binary)              // we don't use any per session data
      },
      {
          "GET_REQUEST_PROTOCOL",
          callback_get_request,
          sizeof(struct per_session_data__binary)
      },
      {
          NULL, NULL, 0   /* End of list */
      }
  };
  
  int main(void) {
          // server url will be http://localhost:9000
          int port = 9000;
          const char *interface = NULL;
          struct libwebsocket_context *context;
          struct lws_context_creation_info info;
          // we're not using ssl
          const char *cert_path = NULL;
          const char *key_path = NULL;
          // no special options
          int opts = 0;
  
      info.port = port;
      info.iface = interface;
      info.protocols = protocols;
      info.extensions = libwebsocket_get_internal_extensions();
      info.ssl_cert_filepath = cert_path;
      info.ssl_private_key_filepath = key_path;
      info.ssl_ca_filepath = NULL;
      info.gid = -1;
      info.uid = -1;
      info.options = opts;
      info.user = NULL;
      //info.ka_time = 0;
      //info.ka_probes = 100;
      //info.ka_interval= 60;
  
      context = libwebsocket_create_context(&amp;info);
  
          if (context == NULL) {
              fprintf(stderr, "libwebsocket init failed\n");
              return -1;
      }
  
          printf("starting server...\n");
  
      // infinite loop, to end this server send SIGTERM. (CTRL+C)
      while (1) {
              libwebsocket_service(context, 50);
          //printf("after service\n");
              // libwebsocket_service will process all waiting events with their
              // callback functions and then wait 50 ms.
              // (this is a single threaded webserver and this will keep our server
              // from generating load while there are not requests to process)
      }
          libwebsocket_context_destroy(context);
  
          return 0;
  }
  
  void sendLoginResponse(struct libwebsocket *wsi, void *in_buffer, size_t bufferlen, struct per_session_data__binary *out_buffer)
  {
      vector&lt;string&gt; userNames, passwords;
      string userName, password;
      bool loginValid = false;
      int usernameLength, passwordLength;
      int usernamePos, passwordPos;
  
  
      userNames.push_back("Nautel");
      passwords.push_back("password");
  
      //Print Login Request Data
      char* loginRequest = (char*) in_buffer;
      usernameLength = loginRequest[USER_NAME_LENGTH];
      passwordLength = loginRequest[PASSWORD_LENGTH];
      usernamePos = PASSWORD_LENGTH + 1;
      passwordPos = usernamePos + usernameLength;
  
      //Get Username
      for(int i=usernamePos; i &lt; (usernamePos+usernameLength); i++) {
          userName.push_back(loginRequest[i]);
      }
  
      //Get Password
      for(int i=passwordPos; i &lt; (passwordPos + passwordLength); i++) {
          password.push_back(loginRequest[i]);
      }
  
      printf("Username: %s Password: %s\n", userName.c_str(), password.c_str());
  
      for(int i=0; i &lt; userNames.size(); i++) {
          loginValid = (!userName.compare(userNames[i]) &amp;&amp; !password.compare(passwords[i]));
          if(loginValid) break;
      }
  
      out_buffer-&gt;buf[USER_ACCOUNTS_IP_RESPONSE] = 0x13;
      out_buffer-&gt;buf[RESPONSE_IP] = (loginValid) ? 0x01 : 0x00;
      out_buffer-&gt;len = 2;
      libwebsocket_write(wsi, out_buffer-&gt;buf,  out_buffer-&gt;len, LWS_WRITE_BINARY);
  }
  
  void printSocketInfo(struct libwebsocket *wsi, struct libwebsocket_context *currentContext){
      char name[128];
      int name_len=sizeof(name);
      char rip[16];
      int rip_len= sizeof(rip);
      int fd;
  
      fd = libwebsocket_get_socket_fd(wsi);
      libwebsockets_get_peer_addresses (currentContext, wsi, fd, name, name_len, rip, rip_len);
  
      printf("Name: %s, IP: %s\n", name, rip);
  }
  </code></pre>
  
  <p>Is it possible to have a client with multiple subprotocols supported by a single server or vice-versa. Or would I need multiple websocket connections from the client to the server for different protocols.</p>
  
  <p>Regards,
  Shreyas</p>