Send WebSockets message to server












0















I am trying to work with an API of one device, but it is using a WS interface with enforced Origin header, which is giving me troubles.



In Chrome, I can open the Console while a page with the correct Origin is loaded, create the WS connection, and send/receive messages without difficulties:
WS connection created, messages sent and received
Note that sent messages (in green) are always acknowledged by the server.



For reference, this is what happens if I create the connection on a different page, which results in an Origin header mismatch, reported as 404:
WS connection created with wrong Origin header



To sidestep this problem, I turned to C, because the rest of my program is written in that anyway. This is the code I have right now, based mostly on this answer:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <libwebsockets.h>

#define KGRN "33[0;32;32m"
#define KCYN "33[0;36m"
#define KRED "33[0;32;31m"
#define KYEL "33[1;33m"
#define KBLU "33[0;32;34m"
#define KCYN_L "33[1;36m"
#define KBRN "33[0;33m"
#define RESET "33[0m"

static int destroy_flag = 0;
static int connection_flag = 0;
static int writeable_flag = 0;

static void INT_HANDLER(int signo) {
destroy_flag = 1;
}

struct session_data {
int fd;
};

struct pthread_routine_tool {
struct lws_context *context;
struct lws *wsi;
};

static int websocket_write_back(struct lws *wsi_in, char *str, int str_size_in)
{
if (str == NULL || wsi_in == NULL)
return -1;

int n;
int len;
char *out = NULL;

if (str_size_in < 1)
len = strlen(str);
else
len = str_size_in;

out = (char *)malloc(sizeof(char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING));
//* setup the buffer*/
memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, str, len );
//* write out*/
n = lws_write(wsi_in, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT);

printf(KBLU"[websocket_write_back] %sn"RESET, str);
//* free the buffer*/
free(out);

return n;
}


static int ws_service_callback(
struct lws *wsi,
enum lws_callback_reasons reason, void *user,
void *in, size_t len)
{

switch (reason) {

case LWS_CALLBACK_CLIENT_ESTABLISHED:
printf(KYEL"[Main Service] Connect with server success.n"RESET);
connection_flag = 1;
break;

case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
printf(KRED"[Main Service] Connect with server error.n"RESET);
destroy_flag = 1;
connection_flag = 0;
break;

case LWS_CALLBACK_CLOSED:
printf(KYEL"[Main Service] LWS_CALLBACK_CLOSEDn"RESET);
destroy_flag = 1;
connection_flag = 0;
break;

case LWS_CALLBACK_CLIENT_RECEIVE:
printf(KCYN_L"[Main Service] Client recvived:%sn"RESET, (char *)in);

if (writeable_flag)
destroy_flag = 1;

break;
case LWS_CALLBACK_CLIENT_WRITEABLE :
printf(KYEL"[Main Service] On writeable is called. send byebye messagen"RESET);
websocket_write_back(wsi, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"D0E91\"}"}", -1);
websocket_write_back(wsi, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"D0E91\"}","data":"{\"value\":100,\"action\":\"set_buzz\"}"}", -1);
writeable_flag = 1;
break;

default:
break;
}

return 0;
}

static void *pthread_routine(void *tool_in)
{
struct pthread_routine_tool *tool = tool_in;

printf(KBRN"[pthread_routine] Good day. This is pthread_routine.n"RESET);

//* waiting for connection with server done.*/
while(!connection_flag)
usleep(1000*20);

//*Send greeting to server*/
lws_callback_on_writable(tool->wsi);

}

int main(void)
{
//* register the signal SIGINT handler */
struct sigaction act;
act.sa_handler = INT_HANDLER;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction( SIGINT, &act, 0);


struct lws_context *context = NULL;
struct lws_context_creation_info info;
struct lws *wsi = NULL;
struct lws_protocols protocol;

memset(&info, 0, sizeof info);
info.port = CONTEXT_PORT_NO_LISTEN;
info.iface = NULL;
info.protocols = &protocol;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
info.extensions = lws_get_internal_extensions();
info.gid = -1;
info.uid = -1;
info.options = 0;

protocol.name = "websockets";
protocol.callback = &ws_service_callback;
protocol.per_session_data_size = sizeof(struct session_data);
protocol.rx_buffer_size = 0;
protocol.id = 0;
protocol.user = NULL;

context = lws_create_context(&info);
printf(KRED"[Main] context created.n"RESET);

if (context == NULL) {
printf(KRED"[Main] context is NULL.n"RESET);
return -1;
}


wsi = lws_client_connect(context, "mobu1.herokuapp.com", 443, 1,
"/cable", "mobu1.herokuapp.com", "link.motorbunny.com",
if (wsi == NULL) {
printf(KRED"[Main] wsi create error.n"RESET);
return -1;
}

printf(KGRN"[Main] wsi create success.n"RESET);

struct pthread_routine_tool tool;
tool.wsi = wsi;
tool.context = context;

pthread_t pid;
pthread_create(&pid, NULL, pthread_routine, &tool);
pthread_detach(pid);

while(!destroy_flag)
{
lws_service(context, 50);
}

lws_context_destroy(context);

return 0;
}


The result of running the above program is this:
WS messages from server



As you can see, the periodic pings from server to my client are being picked up, but the lws_callback_on_writable(wsi); seems to have no effect as the LWS_CALLBACK_CLIENT_WRITEABLE callback never gets called. Additionally, if I call websocket_write_back() directly anywhere else, it doesn't seem to be sending anything to the server, and no acknowledgement is present either.



Is there something obvious I am doing wrong?



EDIT 1:
I found this neat wscat, where I can replicate the results from Chrome:
wscat works
Now the question is, how can I interface this with my C program in a way that it can wait for the Welcome message from the server, and then send two messages?
And better yet, how to stay connected, so that my program can send multiple commands at different points of time without having to do the handshake all the time?










share|improve this question





























    0















    I am trying to work with an API of one device, but it is using a WS interface with enforced Origin header, which is giving me troubles.



    In Chrome, I can open the Console while a page with the correct Origin is loaded, create the WS connection, and send/receive messages without difficulties:
    WS connection created, messages sent and received
    Note that sent messages (in green) are always acknowledged by the server.



    For reference, this is what happens if I create the connection on a different page, which results in an Origin header mismatch, reported as 404:
    WS connection created with wrong Origin header



    To sidestep this problem, I turned to C, because the rest of my program is written in that anyway. This is the code I have right now, based mostly on this answer:



    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <signal.h>
    #include <libwebsockets.h>

    #define KGRN "33[0;32;32m"
    #define KCYN "33[0;36m"
    #define KRED "33[0;32;31m"
    #define KYEL "33[1;33m"
    #define KBLU "33[0;32;34m"
    #define KCYN_L "33[1;36m"
    #define KBRN "33[0;33m"
    #define RESET "33[0m"

    static int destroy_flag = 0;
    static int connection_flag = 0;
    static int writeable_flag = 0;

    static void INT_HANDLER(int signo) {
    destroy_flag = 1;
    }

    struct session_data {
    int fd;
    };

    struct pthread_routine_tool {
    struct lws_context *context;
    struct lws *wsi;
    };

    static int websocket_write_back(struct lws *wsi_in, char *str, int str_size_in)
    {
    if (str == NULL || wsi_in == NULL)
    return -1;

    int n;
    int len;
    char *out = NULL;

    if (str_size_in < 1)
    len = strlen(str);
    else
    len = str_size_in;

    out = (char *)malloc(sizeof(char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING));
    //* setup the buffer*/
    memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, str, len );
    //* write out*/
    n = lws_write(wsi_in, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT);

    printf(KBLU"[websocket_write_back] %sn"RESET, str);
    //* free the buffer*/
    free(out);

    return n;
    }


    static int ws_service_callback(
    struct lws *wsi,
    enum lws_callback_reasons reason, void *user,
    void *in, size_t len)
    {

    switch (reason) {

    case LWS_CALLBACK_CLIENT_ESTABLISHED:
    printf(KYEL"[Main Service] Connect with server success.n"RESET);
    connection_flag = 1;
    break;

    case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
    printf(KRED"[Main Service] Connect with server error.n"RESET);
    destroy_flag = 1;
    connection_flag = 0;
    break;

    case LWS_CALLBACK_CLOSED:
    printf(KYEL"[Main Service] LWS_CALLBACK_CLOSEDn"RESET);
    destroy_flag = 1;
    connection_flag = 0;
    break;

    case LWS_CALLBACK_CLIENT_RECEIVE:
    printf(KCYN_L"[Main Service] Client recvived:%sn"RESET, (char *)in);

    if (writeable_flag)
    destroy_flag = 1;

    break;
    case LWS_CALLBACK_CLIENT_WRITEABLE :
    printf(KYEL"[Main Service] On writeable is called. send byebye messagen"RESET);
    websocket_write_back(wsi, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"D0E91\"}"}", -1);
    websocket_write_back(wsi, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"D0E91\"}","data":"{\"value\":100,\"action\":\"set_buzz\"}"}", -1);
    writeable_flag = 1;
    break;

    default:
    break;
    }

    return 0;
    }

    static void *pthread_routine(void *tool_in)
    {
    struct pthread_routine_tool *tool = tool_in;

    printf(KBRN"[pthread_routine] Good day. This is pthread_routine.n"RESET);

    //* waiting for connection with server done.*/
    while(!connection_flag)
    usleep(1000*20);

    //*Send greeting to server*/
    lws_callback_on_writable(tool->wsi);

    }

    int main(void)
    {
    //* register the signal SIGINT handler */
    struct sigaction act;
    act.sa_handler = INT_HANDLER;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction( SIGINT, &act, 0);


    struct lws_context *context = NULL;
    struct lws_context_creation_info info;
    struct lws *wsi = NULL;
    struct lws_protocols protocol;

    memset(&info, 0, sizeof info);
    info.port = CONTEXT_PORT_NO_LISTEN;
    info.iface = NULL;
    info.protocols = &protocol;
    info.ssl_cert_filepath = NULL;
    info.ssl_private_key_filepath = NULL;
    info.extensions = lws_get_internal_extensions();
    info.gid = -1;
    info.uid = -1;
    info.options = 0;

    protocol.name = "websockets";
    protocol.callback = &ws_service_callback;
    protocol.per_session_data_size = sizeof(struct session_data);
    protocol.rx_buffer_size = 0;
    protocol.id = 0;
    protocol.user = NULL;

    context = lws_create_context(&info);
    printf(KRED"[Main] context created.n"RESET);

    if (context == NULL) {
    printf(KRED"[Main] context is NULL.n"RESET);
    return -1;
    }


    wsi = lws_client_connect(context, "mobu1.herokuapp.com", 443, 1,
    "/cable", "mobu1.herokuapp.com", "link.motorbunny.com",
    if (wsi == NULL) {
    printf(KRED"[Main] wsi create error.n"RESET);
    return -1;
    }

    printf(KGRN"[Main] wsi create success.n"RESET);

    struct pthread_routine_tool tool;
    tool.wsi = wsi;
    tool.context = context;

    pthread_t pid;
    pthread_create(&pid, NULL, pthread_routine, &tool);
    pthread_detach(pid);

    while(!destroy_flag)
    {
    lws_service(context, 50);
    }

    lws_context_destroy(context);

    return 0;
    }


    The result of running the above program is this:
    WS messages from server



    As you can see, the periodic pings from server to my client are being picked up, but the lws_callback_on_writable(wsi); seems to have no effect as the LWS_CALLBACK_CLIENT_WRITEABLE callback never gets called. Additionally, if I call websocket_write_back() directly anywhere else, it doesn't seem to be sending anything to the server, and no acknowledgement is present either.



    Is there something obvious I am doing wrong?



    EDIT 1:
    I found this neat wscat, where I can replicate the results from Chrome:
    wscat works
    Now the question is, how can I interface this with my C program in a way that it can wait for the Welcome message from the server, and then send two messages?
    And better yet, how to stay connected, so that my program can send multiple commands at different points of time without having to do the handshake all the time?










    share|improve this question



























      0












      0








      0








      I am trying to work with an API of one device, but it is using a WS interface with enforced Origin header, which is giving me troubles.



      In Chrome, I can open the Console while a page with the correct Origin is loaded, create the WS connection, and send/receive messages without difficulties:
      WS connection created, messages sent and received
      Note that sent messages (in green) are always acknowledged by the server.



      For reference, this is what happens if I create the connection on a different page, which results in an Origin header mismatch, reported as 404:
      WS connection created with wrong Origin header



      To sidestep this problem, I turned to C, because the rest of my program is written in that anyway. This is the code I have right now, based mostly on this answer:



      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <signal.h>
      #include <libwebsockets.h>

      #define KGRN "33[0;32;32m"
      #define KCYN "33[0;36m"
      #define KRED "33[0;32;31m"
      #define KYEL "33[1;33m"
      #define KBLU "33[0;32;34m"
      #define KCYN_L "33[1;36m"
      #define KBRN "33[0;33m"
      #define RESET "33[0m"

      static int destroy_flag = 0;
      static int connection_flag = 0;
      static int writeable_flag = 0;

      static void INT_HANDLER(int signo) {
      destroy_flag = 1;
      }

      struct session_data {
      int fd;
      };

      struct pthread_routine_tool {
      struct lws_context *context;
      struct lws *wsi;
      };

      static int websocket_write_back(struct lws *wsi_in, char *str, int str_size_in)
      {
      if (str == NULL || wsi_in == NULL)
      return -1;

      int n;
      int len;
      char *out = NULL;

      if (str_size_in < 1)
      len = strlen(str);
      else
      len = str_size_in;

      out = (char *)malloc(sizeof(char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING));
      //* setup the buffer*/
      memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, str, len );
      //* write out*/
      n = lws_write(wsi_in, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT);

      printf(KBLU"[websocket_write_back] %sn"RESET, str);
      //* free the buffer*/
      free(out);

      return n;
      }


      static int ws_service_callback(
      struct lws *wsi,
      enum lws_callback_reasons reason, void *user,
      void *in, size_t len)
      {

      switch (reason) {

      case LWS_CALLBACK_CLIENT_ESTABLISHED:
      printf(KYEL"[Main Service] Connect with server success.n"RESET);
      connection_flag = 1;
      break;

      case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
      printf(KRED"[Main Service] Connect with server error.n"RESET);
      destroy_flag = 1;
      connection_flag = 0;
      break;

      case LWS_CALLBACK_CLOSED:
      printf(KYEL"[Main Service] LWS_CALLBACK_CLOSEDn"RESET);
      destroy_flag = 1;
      connection_flag = 0;
      break;

      case LWS_CALLBACK_CLIENT_RECEIVE:
      printf(KCYN_L"[Main Service] Client recvived:%sn"RESET, (char *)in);

      if (writeable_flag)
      destroy_flag = 1;

      break;
      case LWS_CALLBACK_CLIENT_WRITEABLE :
      printf(KYEL"[Main Service] On writeable is called. send byebye messagen"RESET);
      websocket_write_back(wsi, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"D0E91\"}"}", -1);
      websocket_write_back(wsi, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"D0E91\"}","data":"{\"value\":100,\"action\":\"set_buzz\"}"}", -1);
      writeable_flag = 1;
      break;

      default:
      break;
      }

      return 0;
      }

      static void *pthread_routine(void *tool_in)
      {
      struct pthread_routine_tool *tool = tool_in;

      printf(KBRN"[pthread_routine] Good day. This is pthread_routine.n"RESET);

      //* waiting for connection with server done.*/
      while(!connection_flag)
      usleep(1000*20);

      //*Send greeting to server*/
      lws_callback_on_writable(tool->wsi);

      }

      int main(void)
      {
      //* register the signal SIGINT handler */
      struct sigaction act;
      act.sa_handler = INT_HANDLER;
      act.sa_flags = 0;
      sigemptyset(&act.sa_mask);
      sigaction( SIGINT, &act, 0);


      struct lws_context *context = NULL;
      struct lws_context_creation_info info;
      struct lws *wsi = NULL;
      struct lws_protocols protocol;

      memset(&info, 0, sizeof info);
      info.port = CONTEXT_PORT_NO_LISTEN;
      info.iface = NULL;
      info.protocols = &protocol;
      info.ssl_cert_filepath = NULL;
      info.ssl_private_key_filepath = NULL;
      info.extensions = lws_get_internal_extensions();
      info.gid = -1;
      info.uid = -1;
      info.options = 0;

      protocol.name = "websockets";
      protocol.callback = &ws_service_callback;
      protocol.per_session_data_size = sizeof(struct session_data);
      protocol.rx_buffer_size = 0;
      protocol.id = 0;
      protocol.user = NULL;

      context = lws_create_context(&info);
      printf(KRED"[Main] context created.n"RESET);

      if (context == NULL) {
      printf(KRED"[Main] context is NULL.n"RESET);
      return -1;
      }


      wsi = lws_client_connect(context, "mobu1.herokuapp.com", 443, 1,
      "/cable", "mobu1.herokuapp.com", "link.motorbunny.com",
      if (wsi == NULL) {
      printf(KRED"[Main] wsi create error.n"RESET);
      return -1;
      }

      printf(KGRN"[Main] wsi create success.n"RESET);

      struct pthread_routine_tool tool;
      tool.wsi = wsi;
      tool.context = context;

      pthread_t pid;
      pthread_create(&pid, NULL, pthread_routine, &tool);
      pthread_detach(pid);

      while(!destroy_flag)
      {
      lws_service(context, 50);
      }

      lws_context_destroy(context);

      return 0;
      }


      The result of running the above program is this:
      WS messages from server



      As you can see, the periodic pings from server to my client are being picked up, but the lws_callback_on_writable(wsi); seems to have no effect as the LWS_CALLBACK_CLIENT_WRITEABLE callback never gets called. Additionally, if I call websocket_write_back() directly anywhere else, it doesn't seem to be sending anything to the server, and no acknowledgement is present either.



      Is there something obvious I am doing wrong?



      EDIT 1:
      I found this neat wscat, where I can replicate the results from Chrome:
      wscat works
      Now the question is, how can I interface this with my C program in a way that it can wait for the Welcome message from the server, and then send two messages?
      And better yet, how to stay connected, so that my program can send multiple commands at different points of time without having to do the handshake all the time?










      share|improve this question
















      I am trying to work with an API of one device, but it is using a WS interface with enforced Origin header, which is giving me troubles.



      In Chrome, I can open the Console while a page with the correct Origin is loaded, create the WS connection, and send/receive messages without difficulties:
      WS connection created, messages sent and received
      Note that sent messages (in green) are always acknowledged by the server.



      For reference, this is what happens if I create the connection on a different page, which results in an Origin header mismatch, reported as 404:
      WS connection created with wrong Origin header



      To sidestep this problem, I turned to C, because the rest of my program is written in that anyway. This is the code I have right now, based mostly on this answer:



      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <unistd.h>
      #include <signal.h>
      #include <libwebsockets.h>

      #define KGRN "33[0;32;32m"
      #define KCYN "33[0;36m"
      #define KRED "33[0;32;31m"
      #define KYEL "33[1;33m"
      #define KBLU "33[0;32;34m"
      #define KCYN_L "33[1;36m"
      #define KBRN "33[0;33m"
      #define RESET "33[0m"

      static int destroy_flag = 0;
      static int connection_flag = 0;
      static int writeable_flag = 0;

      static void INT_HANDLER(int signo) {
      destroy_flag = 1;
      }

      struct session_data {
      int fd;
      };

      struct pthread_routine_tool {
      struct lws_context *context;
      struct lws *wsi;
      };

      static int websocket_write_back(struct lws *wsi_in, char *str, int str_size_in)
      {
      if (str == NULL || wsi_in == NULL)
      return -1;

      int n;
      int len;
      char *out = NULL;

      if (str_size_in < 1)
      len = strlen(str);
      else
      len = str_size_in;

      out = (char *)malloc(sizeof(char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING));
      //* setup the buffer*/
      memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, str, len );
      //* write out*/
      n = lws_write(wsi_in, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT);

      printf(KBLU"[websocket_write_back] %sn"RESET, str);
      //* free the buffer*/
      free(out);

      return n;
      }


      static int ws_service_callback(
      struct lws *wsi,
      enum lws_callback_reasons reason, void *user,
      void *in, size_t len)
      {

      switch (reason) {

      case LWS_CALLBACK_CLIENT_ESTABLISHED:
      printf(KYEL"[Main Service] Connect with server success.n"RESET);
      connection_flag = 1;
      break;

      case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
      printf(KRED"[Main Service] Connect with server error.n"RESET);
      destroy_flag = 1;
      connection_flag = 0;
      break;

      case LWS_CALLBACK_CLOSED:
      printf(KYEL"[Main Service] LWS_CALLBACK_CLOSEDn"RESET);
      destroy_flag = 1;
      connection_flag = 0;
      break;

      case LWS_CALLBACK_CLIENT_RECEIVE:
      printf(KCYN_L"[Main Service] Client recvived:%sn"RESET, (char *)in);

      if (writeable_flag)
      destroy_flag = 1;

      break;
      case LWS_CALLBACK_CLIENT_WRITEABLE :
      printf(KYEL"[Main Service] On writeable is called. send byebye messagen"RESET);
      websocket_write_back(wsi, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"D0E91\"}"}", -1);
      websocket_write_back(wsi, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"D0E91\"}","data":"{\"value\":100,\"action\":\"set_buzz\"}"}", -1);
      writeable_flag = 1;
      break;

      default:
      break;
      }

      return 0;
      }

      static void *pthread_routine(void *tool_in)
      {
      struct pthread_routine_tool *tool = tool_in;

      printf(KBRN"[pthread_routine] Good day. This is pthread_routine.n"RESET);

      //* waiting for connection with server done.*/
      while(!connection_flag)
      usleep(1000*20);

      //*Send greeting to server*/
      lws_callback_on_writable(tool->wsi);

      }

      int main(void)
      {
      //* register the signal SIGINT handler */
      struct sigaction act;
      act.sa_handler = INT_HANDLER;
      act.sa_flags = 0;
      sigemptyset(&act.sa_mask);
      sigaction( SIGINT, &act, 0);


      struct lws_context *context = NULL;
      struct lws_context_creation_info info;
      struct lws *wsi = NULL;
      struct lws_protocols protocol;

      memset(&info, 0, sizeof info);
      info.port = CONTEXT_PORT_NO_LISTEN;
      info.iface = NULL;
      info.protocols = &protocol;
      info.ssl_cert_filepath = NULL;
      info.ssl_private_key_filepath = NULL;
      info.extensions = lws_get_internal_extensions();
      info.gid = -1;
      info.uid = -1;
      info.options = 0;

      protocol.name = "websockets";
      protocol.callback = &ws_service_callback;
      protocol.per_session_data_size = sizeof(struct session_data);
      protocol.rx_buffer_size = 0;
      protocol.id = 0;
      protocol.user = NULL;

      context = lws_create_context(&info);
      printf(KRED"[Main] context created.n"RESET);

      if (context == NULL) {
      printf(KRED"[Main] context is NULL.n"RESET);
      return -1;
      }


      wsi = lws_client_connect(context, "mobu1.herokuapp.com", 443, 1,
      "/cable", "mobu1.herokuapp.com", "link.motorbunny.com",
      if (wsi == NULL) {
      printf(KRED"[Main] wsi create error.n"RESET);
      return -1;
      }

      printf(KGRN"[Main] wsi create success.n"RESET);

      struct pthread_routine_tool tool;
      tool.wsi = wsi;
      tool.context = context;

      pthread_t pid;
      pthread_create(&pid, NULL, pthread_routine, &tool);
      pthread_detach(pid);

      while(!destroy_flag)
      {
      lws_service(context, 50);
      }

      lws_context_destroy(context);

      return 0;
      }


      The result of running the above program is this:
      WS messages from server



      As you can see, the periodic pings from server to my client are being picked up, but the lws_callback_on_writable(wsi); seems to have no effect as the LWS_CALLBACK_CLIENT_WRITEABLE callback never gets called. Additionally, if I call websocket_write_back() directly anywhere else, it doesn't seem to be sending anything to the server, and no acknowledgement is present either.



      Is there something obvious I am doing wrong?



      EDIT 1:
      I found this neat wscat, where I can replicate the results from Chrome:
      wscat works
      Now the question is, how can I interface this with my C program in a way that it can wait for the Welcome message from the server, and then send two messages?
      And better yet, how to stay connected, so that my program can send multiple commands at different points of time without having to do the handshake all the time?







      c libwebsockets






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 4 at 9:53







      programagor

















      asked Jan 3 at 16:05









      programagorprogramagor

      10816




      10816
























          2 Answers
          2






          active

          oldest

          votes


















          0














          I found an ugly hack to make my C program send WebSocket messages to a server via the wsta program.



          It requires a text file, into which my program will append whenever it wants to send a message to the server. The new lines are then picked up in the background by tail -f, and are piped to wsta which maintains the connection. Output can be redirected to /dev/null so that the wsta output doesn't pollute the output of my program, or sent to a file if responses from the server need to be parsed.
          The whole script to make this work would look like this (or you could use FIFO pipe with cat instead of a file with tail):



          #!/bin/bash
          touch commands.txt
          tail commands.txt -f -n 0 | wsta --header "Origin: https://link.motorbunny.com" "wss://mobu1.herokuapp.com/cable" &> /dev/null &
          ./program


          In the C program, I just need to write to the commands.txt file:



          FILE* cmd;
          char sync_str[6];
          void mb_connect()
          {
          fprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}n",sync_str);
          fflush(cmd);
          }
          void mb_send(int power, char* type)
          {
          fprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}n",sync_str,power,type);
          fflush(cmd);
          }

          int main()
          {
          cmd = fopen ("commands.txt","w");
          ...
          mb_connect();
          ...
          mb_send(200,"buzz");
          ...
          mb_send(0,"buzz");
          }





          share|improve this answer

































            0














            The reason why the LWS_CALLBACK_CLIENT_WRITEABLE callback never got called was because this particular server uses non-standard handshake. So, to bypass this, I forked a fork of libwsclient and modified the handshake checking function to not fail on mismatch. I also added an optional Origin header.



            Now, all I need to do in my original program is



            wsclient *client;
            char sync_str[6];
            void mb_send(int power, char* type)
            {
            char cmd[2048];
            sprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}",sync_str,power,type);
            libwsclient_send(client,cmd);
            }
            void mb_connect()
            {
            char cmd[2048];
            sprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}",sync_str);
            libwsclient_send(client,cmd);
            mb_send(0,"buzz");
            }
            int nop()
            {
            return 0;
            }
            int main()
            {
            client = libwsclient_new_extra("wss://mobu1.herokuapp.com/cable","https://link.motorbunny.com");
            if(!client) {
            fprintf(stderr, "Unable to initialize new WS client.n");
            exit(1);
            }

            libwsclient_onopen(client, &nop);
            libwsclient_onmessage(client, &nop);
            libwsclient_onerror(client, &nop);
            libwsclient_onclose(client, &nop);

            libwsclient_run(client);

            ...
            mb_connect();
            ...
            mb_send(200,"buzz");
            mb_send(40,"twirl");
            ...
            mb_send(0,"buzz");
            mb_send(0,"twirl");
            }





            share|improve this answer
























              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54025881%2fsend-websockets-message-to-server%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              0














              I found an ugly hack to make my C program send WebSocket messages to a server via the wsta program.



              It requires a text file, into which my program will append whenever it wants to send a message to the server. The new lines are then picked up in the background by tail -f, and are piped to wsta which maintains the connection. Output can be redirected to /dev/null so that the wsta output doesn't pollute the output of my program, or sent to a file if responses from the server need to be parsed.
              The whole script to make this work would look like this (or you could use FIFO pipe with cat instead of a file with tail):



              #!/bin/bash
              touch commands.txt
              tail commands.txt -f -n 0 | wsta --header "Origin: https://link.motorbunny.com" "wss://mobu1.herokuapp.com/cable" &> /dev/null &
              ./program


              In the C program, I just need to write to the commands.txt file:



              FILE* cmd;
              char sync_str[6];
              void mb_connect()
              {
              fprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}n",sync_str);
              fflush(cmd);
              }
              void mb_send(int power, char* type)
              {
              fprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}n",sync_str,power,type);
              fflush(cmd);
              }

              int main()
              {
              cmd = fopen ("commands.txt","w");
              ...
              mb_connect();
              ...
              mb_send(200,"buzz");
              ...
              mb_send(0,"buzz");
              }





              share|improve this answer






























                0














                I found an ugly hack to make my C program send WebSocket messages to a server via the wsta program.



                It requires a text file, into which my program will append whenever it wants to send a message to the server. The new lines are then picked up in the background by tail -f, and are piped to wsta which maintains the connection. Output can be redirected to /dev/null so that the wsta output doesn't pollute the output of my program, or sent to a file if responses from the server need to be parsed.
                The whole script to make this work would look like this (or you could use FIFO pipe with cat instead of a file with tail):



                #!/bin/bash
                touch commands.txt
                tail commands.txt -f -n 0 | wsta --header "Origin: https://link.motorbunny.com" "wss://mobu1.herokuapp.com/cable" &> /dev/null &
                ./program


                In the C program, I just need to write to the commands.txt file:



                FILE* cmd;
                char sync_str[6];
                void mb_connect()
                {
                fprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}n",sync_str);
                fflush(cmd);
                }
                void mb_send(int power, char* type)
                {
                fprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}n",sync_str,power,type);
                fflush(cmd);
                }

                int main()
                {
                cmd = fopen ("commands.txt","w");
                ...
                mb_connect();
                ...
                mb_send(200,"buzz");
                ...
                mb_send(0,"buzz");
                }





                share|improve this answer




























                  0












                  0








                  0







                  I found an ugly hack to make my C program send WebSocket messages to a server via the wsta program.



                  It requires a text file, into which my program will append whenever it wants to send a message to the server. The new lines are then picked up in the background by tail -f, and are piped to wsta which maintains the connection. Output can be redirected to /dev/null so that the wsta output doesn't pollute the output of my program, or sent to a file if responses from the server need to be parsed.
                  The whole script to make this work would look like this (or you could use FIFO pipe with cat instead of a file with tail):



                  #!/bin/bash
                  touch commands.txt
                  tail commands.txt -f -n 0 | wsta --header "Origin: https://link.motorbunny.com" "wss://mobu1.herokuapp.com/cable" &> /dev/null &
                  ./program


                  In the C program, I just need to write to the commands.txt file:



                  FILE* cmd;
                  char sync_str[6];
                  void mb_connect()
                  {
                  fprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}n",sync_str);
                  fflush(cmd);
                  }
                  void mb_send(int power, char* type)
                  {
                  fprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}n",sync_str,power,type);
                  fflush(cmd);
                  }

                  int main()
                  {
                  cmd = fopen ("commands.txt","w");
                  ...
                  mb_connect();
                  ...
                  mb_send(200,"buzz");
                  ...
                  mb_send(0,"buzz");
                  }





                  share|improve this answer















                  I found an ugly hack to make my C program send WebSocket messages to a server via the wsta program.



                  It requires a text file, into which my program will append whenever it wants to send a message to the server. The new lines are then picked up in the background by tail -f, and are piped to wsta which maintains the connection. Output can be redirected to /dev/null so that the wsta output doesn't pollute the output of my program, or sent to a file if responses from the server need to be parsed.
                  The whole script to make this work would look like this (or you could use FIFO pipe with cat instead of a file with tail):



                  #!/bin/bash
                  touch commands.txt
                  tail commands.txt -f -n 0 | wsta --header "Origin: https://link.motorbunny.com" "wss://mobu1.herokuapp.com/cable" &> /dev/null &
                  ./program


                  In the C program, I just need to write to the commands.txt file:



                  FILE* cmd;
                  char sync_str[6];
                  void mb_connect()
                  {
                  fprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}n",sync_str);
                  fflush(cmd);
                  }
                  void mb_send(int power, char* type)
                  {
                  fprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}n",sync_str,power,type);
                  fflush(cmd);
                  }

                  int main()
                  {
                  cmd = fopen ("commands.txt","w");
                  ...
                  mb_connect();
                  ...
                  mb_send(200,"buzz");
                  ...
                  mb_send(0,"buzz");
                  }






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jan 4 at 10:45

























                  answered Jan 4 at 9:52









                  programagorprogramagor

                  10816




                  10816

























                      0














                      The reason why the LWS_CALLBACK_CLIENT_WRITEABLE callback never got called was because this particular server uses non-standard handshake. So, to bypass this, I forked a fork of libwsclient and modified the handshake checking function to not fail on mismatch. I also added an optional Origin header.



                      Now, all I need to do in my original program is



                      wsclient *client;
                      char sync_str[6];
                      void mb_send(int power, char* type)
                      {
                      char cmd[2048];
                      sprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}",sync_str,power,type);
                      libwsclient_send(client,cmd);
                      }
                      void mb_connect()
                      {
                      char cmd[2048];
                      sprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}",sync_str);
                      libwsclient_send(client,cmd);
                      mb_send(0,"buzz");
                      }
                      int nop()
                      {
                      return 0;
                      }
                      int main()
                      {
                      client = libwsclient_new_extra("wss://mobu1.herokuapp.com/cable","https://link.motorbunny.com");
                      if(!client) {
                      fprintf(stderr, "Unable to initialize new WS client.n");
                      exit(1);
                      }

                      libwsclient_onopen(client, &nop);
                      libwsclient_onmessage(client, &nop);
                      libwsclient_onerror(client, &nop);
                      libwsclient_onclose(client, &nop);

                      libwsclient_run(client);

                      ...
                      mb_connect();
                      ...
                      mb_send(200,"buzz");
                      mb_send(40,"twirl");
                      ...
                      mb_send(0,"buzz");
                      mb_send(0,"twirl");
                      }





                      share|improve this answer




























                        0














                        The reason why the LWS_CALLBACK_CLIENT_WRITEABLE callback never got called was because this particular server uses non-standard handshake. So, to bypass this, I forked a fork of libwsclient and modified the handshake checking function to not fail on mismatch. I also added an optional Origin header.



                        Now, all I need to do in my original program is



                        wsclient *client;
                        char sync_str[6];
                        void mb_send(int power, char* type)
                        {
                        char cmd[2048];
                        sprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}",sync_str,power,type);
                        libwsclient_send(client,cmd);
                        }
                        void mb_connect()
                        {
                        char cmd[2048];
                        sprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}",sync_str);
                        libwsclient_send(client,cmd);
                        mb_send(0,"buzz");
                        }
                        int nop()
                        {
                        return 0;
                        }
                        int main()
                        {
                        client = libwsclient_new_extra("wss://mobu1.herokuapp.com/cable","https://link.motorbunny.com");
                        if(!client) {
                        fprintf(stderr, "Unable to initialize new WS client.n");
                        exit(1);
                        }

                        libwsclient_onopen(client, &nop);
                        libwsclient_onmessage(client, &nop);
                        libwsclient_onerror(client, &nop);
                        libwsclient_onclose(client, &nop);

                        libwsclient_run(client);

                        ...
                        mb_connect();
                        ...
                        mb_send(200,"buzz");
                        mb_send(40,"twirl");
                        ...
                        mb_send(0,"buzz");
                        mb_send(0,"twirl");
                        }





                        share|improve this answer


























                          0












                          0








                          0







                          The reason why the LWS_CALLBACK_CLIENT_WRITEABLE callback never got called was because this particular server uses non-standard handshake. So, to bypass this, I forked a fork of libwsclient and modified the handshake checking function to not fail on mismatch. I also added an optional Origin header.



                          Now, all I need to do in my original program is



                          wsclient *client;
                          char sync_str[6];
                          void mb_send(int power, char* type)
                          {
                          char cmd[2048];
                          sprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}",sync_str,power,type);
                          libwsclient_send(client,cmd);
                          }
                          void mb_connect()
                          {
                          char cmd[2048];
                          sprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}",sync_str);
                          libwsclient_send(client,cmd);
                          mb_send(0,"buzz");
                          }
                          int nop()
                          {
                          return 0;
                          }
                          int main()
                          {
                          client = libwsclient_new_extra("wss://mobu1.herokuapp.com/cable","https://link.motorbunny.com");
                          if(!client) {
                          fprintf(stderr, "Unable to initialize new WS client.n");
                          exit(1);
                          }

                          libwsclient_onopen(client, &nop);
                          libwsclient_onmessage(client, &nop);
                          libwsclient_onerror(client, &nop);
                          libwsclient_onclose(client, &nop);

                          libwsclient_run(client);

                          ...
                          mb_connect();
                          ...
                          mb_send(200,"buzz");
                          mb_send(40,"twirl");
                          ...
                          mb_send(0,"buzz");
                          mb_send(0,"twirl");
                          }





                          share|improve this answer













                          The reason why the LWS_CALLBACK_CLIENT_WRITEABLE callback never got called was because this particular server uses non-standard handshake. So, to bypass this, I forked a fork of libwsclient and modified the handshake checking function to not fail on mismatch. I also added an optional Origin header.



                          Now, all I need to do in my original program is



                          wsclient *client;
                          char sync_str[6];
                          void mb_send(int power, char* type)
                          {
                          char cmd[2048];
                          sprintf (cmd, "{"command":"message","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}","data":"{\"value\":%d,\"action\":\"set_%s\"}"}",sync_str,power,type);
                          libwsclient_send(client,cmd);
                          }
                          void mb_connect()
                          {
                          char cmd[2048];
                          sprintf (cmd, "{"command":"subscribe","identifier":"{\"channel\":\"DevicesChannel\",\"share_token\":\"%s\"}"}",sync_str);
                          libwsclient_send(client,cmd);
                          mb_send(0,"buzz");
                          }
                          int nop()
                          {
                          return 0;
                          }
                          int main()
                          {
                          client = libwsclient_new_extra("wss://mobu1.herokuapp.com/cable","https://link.motorbunny.com");
                          if(!client) {
                          fprintf(stderr, "Unable to initialize new WS client.n");
                          exit(1);
                          }

                          libwsclient_onopen(client, &nop);
                          libwsclient_onmessage(client, &nop);
                          libwsclient_onerror(client, &nop);
                          libwsclient_onclose(client, &nop);

                          libwsclient_run(client);

                          ...
                          mb_connect();
                          ...
                          mb_send(200,"buzz");
                          mb_send(40,"twirl");
                          ...
                          mb_send(0,"buzz");
                          mb_send(0,"twirl");
                          }






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Jan 9 at 9:43









                          programagorprogramagor

                          10816




                          10816






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54025881%2fsend-websockets-message-to-server%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Monofisismo

                              Angular Downloading a file using contenturl with Basic Authentication

                              Olmecas