ws_server.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h> /* for sleep() */
  6. #include "civetweb.h"
  7. /* Global options for this example. */
  8. static const char WS_URL[] = "/wsURL";
  9. static const char *SERVER_OPTIONS[] =
  10. {"listening_ports", "8081", "num_threads", "10", NULL, NULL};
  11. /* Define websocket sub-protocols. */
  12. /* This must be static data, available between mg_start and mg_stop. */
  13. static const char subprotocol_bin[] = "Company.ProtoName.bin";
  14. static const char subprotocol_json[] = "Company.ProtoName.json";
  15. static const char *subprotocols[] = {subprotocol_bin, subprotocol_json, NULL};
  16. static struct mg_websocket_subprotocols wsprot = {2, subprotocols};
  17. /* Exit flag for the server */
  18. volatile int g_exit = 0;
  19. /* User defined data structure for websocket client context. */
  20. struct tClientContext {
  21. uint32_t connectionNumber;
  22. uint32_t demo_var;
  23. };
  24. /* Handler for new websocket connections. */
  25. static int
  26. ws_connect_handler(const struct mg_connection *conn, void *user_data)
  27. {
  28. (void)user_data; /* unused */
  29. /* Allocate data for websocket client context, and initialize context. */
  30. struct tClientContext *wsCliCtx =
  31. (struct tClientContext *)calloc(1, sizeof(struct tClientContext));
  32. if (!wsCliCtx) {
  33. /* reject client */
  34. return 1;
  35. }
  36. static uint32_t connectionCounter = 0; /* Example data: client number */
  37. wsCliCtx->connectionNumber = __sync_add_and_fetch(&connectionCounter, 1);
  38. mg_set_user_connection_data(
  39. conn, wsCliCtx); /* client context assigned to connection */
  40. /* DEBUG: New client connected (but not ready to receive data yet). */
  41. const struct mg_request_info *ri = mg_get_request_info(conn);
  42. printf("Client %u connected with subprotocol: %s\n",
  43. wsCliCtx->connectionNumber,
  44. ri->acceptedWebSocketSubprotocol);
  45. return 0;
  46. }
  47. /* Handler indicating the client is ready to receive data. */
  48. static void
  49. ws_ready_handler(struct mg_connection *conn, void *user_data)
  50. {
  51. (void)user_data; /* unused */
  52. /* Get websocket client context information. */
  53. struct tClientContext *wsCliCtx =
  54. (struct tClientContext *)mg_get_user_connection_data(conn);
  55. const struct mg_request_info *ri = mg_get_request_info(conn);
  56. (void)ri; /* in this example, we do not need the request_info */
  57. /* Send "hello" message. */
  58. const char *hello = "{}";
  59. size_t hello_len = strlen(hello);
  60. mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_TEXT, hello, hello_len);
  61. /* DEBUG: New client ready to receive data. */
  62. printf("Client %u ready to receive data\n", wsCliCtx->connectionNumber);
  63. }
  64. /* Handler indicating the client sent data to the server. */
  65. static int
  66. ws_data_handler(struct mg_connection *conn,
  67. int opcode,
  68. char *data,
  69. size_t datasize,
  70. void *user_data)
  71. {
  72. (void)user_data; /* unused */
  73. /* Get websocket client context information. */
  74. struct tClientContext *wsCliCtx =
  75. (struct tClientContext *)mg_get_user_connection_data(conn);
  76. const struct mg_request_info *ri = mg_get_request_info(conn);
  77. (void)ri; /* in this example, we do not need the request_info */
  78. /* DEBUG: Print data received from client. */
  79. const char *messageType = "";
  80. switch (opcode & 0xf) {
  81. case MG_WEBSOCKET_OPCODE_TEXT:
  82. messageType = "text";
  83. break;
  84. case MG_WEBSOCKET_OPCODE_BINARY:
  85. messageType = "binary";
  86. break;
  87. case MG_WEBSOCKET_OPCODE_PING:
  88. messageType = "ping";
  89. break;
  90. case MG_WEBSOCKET_OPCODE_PONG:
  91. messageType = "pong";
  92. break;
  93. }
  94. printf("Websocket received %lu bytes of %s data from client %u\n",
  95. (unsigned long)datasize,
  96. messageType,
  97. wsCliCtx->connectionNumber);
  98. return 1;
  99. }
  100. /* Handler indicating the connection to the client is closing. */
  101. static void
  102. ws_close_handler(const struct mg_connection *conn, void *user_data)
  103. {
  104. (void)user_data; /* unused */
  105. /* Get websocket client context information. */
  106. struct tClientContext *wsCliCtx =
  107. (struct tClientContext *)mg_get_user_connection_data(conn);
  108. /* DEBUG: Client has left. */
  109. printf("Client %u closing connection\n", wsCliCtx->connectionNumber);
  110. /* Free memory allocated for client context in ws_connect_handler() call. */
  111. free(wsCliCtx);
  112. }
  113. int
  114. main(int argc, char *argv[])
  115. {
  116. /* Initialize CivetWeb library without OpenSSL/TLS support. */
  117. mg_init_library(0);
  118. /* Start the server using the advanced API. */
  119. struct mg_callbacks callbacks = {0};
  120. void *user_data = NULL;
  121. struct mg_init_data mg_start_init_data = {0};
  122. mg_start_init_data.callbacks = &callbacks;
  123. mg_start_init_data.user_data = user_data;
  124. mg_start_init_data.configuration_options = SERVER_OPTIONS;
  125. struct mg_error_data mg_start_error_data = {0};
  126. char errtxtbuf[256] = {0};
  127. mg_start_error_data.text = errtxtbuf;
  128. mg_start_error_data.text_buffer_size = sizeof(errtxtbuf);
  129. struct mg_context *ctx =
  130. mg_start2(&mg_start_init_data, &mg_start_error_data);
  131. if (!ctx) {
  132. fprintf(stderr, "Cannot start server: %s\n", errtxtbuf);
  133. mg_exit_library();
  134. return 1;
  135. }
  136. /* Register the websocket callback functions. */
  137. mg_set_websocket_handler_with_subprotocols(ctx,
  138. WS_URL,
  139. &wsprot,
  140. ws_connect_handler,
  141. ws_ready_handler,
  142. ws_data_handler,
  143. ws_close_handler,
  144. user_data);
  145. /* Let the server run. */
  146. printf("Websocket server running\n");
  147. while (!g_exit) {
  148. sleep(1);
  149. }
  150. printf("Websocket server stopping\n");
  151. /* Stop server, disconnect all clients. Then deinitialize CivetWeb library.
  152. */
  153. mg_stop(ctx);
  154. mg_exit_library();
  155. }