websocket_client.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. * Copyright (c) 2014-2016 the Civetweb developers
  3. * Copyright (c) 2014 Jordan Shelley
  4. * https://github.com/jshelley
  5. * License http://opensource.org/licenses/mit-license.php MIT License
  6. */
  7. /* This example is superseeded by other examples, and no longer
  8. * actively maintained.
  9. * See examples/embedded_c for an up to date example.
  10. */
  11. // Simple example program on how to use websocket client embedded C interface.
  12. #ifdef _WIN32
  13. #include <windows.h>
  14. #define sleep(x) Sleep(1000 * (x))
  15. #else
  16. #include <unistd.h>
  17. #endif
  18. #include <assert.h>
  19. #include <string.h>
  20. #include "civetweb.h"
  21. #define DOCUMENT_ROOT "."
  22. #define PORT "8888"
  23. #define SSL_CERT "./ssl/server.pem"
  24. const char *websocket_welcome_msg = "websocket welcome\n";
  25. const size_t websocket_welcome_msg_len = 18 /* strlen(websocket_welcome_msg) */;
  26. const char *websocket_acknowledge_msg = "websocket msg ok\n";
  27. const size_t websocket_acknowledge_msg_len =
  28. 17 /* strlen(websocket_acknowledge_msg) */;
  29. const char *websocket_goodbye_msg = "websocket bye\n";
  30. const size_t websocket_goodbye_msg_len = 14 /* strlen(websocket_goodbye_msg) */;
  31. /*************************************************************************************/
  32. /* WEBSOCKET SERVER */
  33. /*************************************************************************************/
  34. #if defined(MG_LEGACY_INTERFACE)
  35. int
  36. websock_server_connect(const struct mg_connection *conn)
  37. #else
  38. int
  39. websocket_server_connect(const struct mg_connection *conn, void *_ignored)
  40. #endif
  41. {
  42. printf("Server: Websocket connected\n");
  43. return 0; /* return 0 to accept every connection */
  44. }
  45. #if defined(MG_LEGACY_INTERFACE)
  46. void
  47. websocket_server_ready(struct mg_connection *conn)
  48. #else
  49. void
  50. websocket_server_ready(struct mg_connection *conn, void *_ignored)
  51. #endif
  52. {
  53. printf("Server: Websocket ready\n");
  54. /* Send websocket welcome message */
  55. mg_lock_connection(conn);
  56. mg_websocket_write(conn,
  57. WEBSOCKET_OPCODE_TEXT,
  58. websocket_welcome_msg,
  59. websocket_welcome_msg_len);
  60. mg_unlock_connection(conn);
  61. }
  62. #if defined(MG_LEGACY_INTERFACE)
  63. int
  64. websocket_server_data(struct mg_connection *conn,
  65. int bits,
  66. char *data,
  67. size_t data_len)
  68. #else
  69. int
  70. websocket_server_data(struct mg_connection *conn,
  71. int bits,
  72. char *data,
  73. size_t data_len,
  74. void *_ignored)
  75. #endif
  76. {
  77. printf("Server: Got %lu bytes from the client\n", (unsigned long)data_len);
  78. printf("Server received data from client: ");
  79. fwrite(data, 1, data_len, stdout);
  80. printf("\n");
  81. if (data_len < 3 || 0 != memcmp(data, "bye", 3)) {
  82. /* Send websocket acknowledge message */
  83. mg_lock_connection(conn);
  84. mg_websocket_write(conn,
  85. WEBSOCKET_OPCODE_TEXT,
  86. websocket_acknowledge_msg,
  87. websocket_acknowledge_msg_len);
  88. mg_unlock_connection(conn);
  89. } else {
  90. /* Send websocket acknowledge message */
  91. mg_lock_connection(conn);
  92. mg_websocket_write(conn,
  93. WEBSOCKET_OPCODE_TEXT,
  94. websocket_goodbye_msg,
  95. websocket_goodbye_msg_len);
  96. mg_unlock_connection(conn);
  97. }
  98. return 1; /* return 1 to keep the connetion open */
  99. }
  100. #if defined(MG_LEGACY_INTERFACE)
  101. void
  102. websocket_server_connection_close(const struct mg_connection *conn)
  103. #else
  104. void
  105. websocket_server_connection_close(const struct mg_connection *conn,
  106. void *_ignored)
  107. #endif
  108. {
  109. printf("Server: Close connection\n");
  110. /* Can not send a websocket goodbye message here - the connection is already
  111. * closed */
  112. }
  113. struct mg_context *
  114. start_websocket_server()
  115. {
  116. const char *options[] = {"document_root",
  117. DOCUMENT_ROOT,
  118. "ssl_certificate",
  119. SSL_CERT,
  120. "listening_ports",
  121. PORT,
  122. "request_timeout_ms",
  123. "5000",
  124. 0};
  125. struct mg_callbacks callbacks;
  126. struct mg_context *ctx;
  127. memset(&callbacks, 0, sizeof(callbacks));
  128. #if defined(MG_LEGACY_INTERFACE)
  129. /* Obsolete: */
  130. callbacks.websocket_connect = websock_server_connect;
  131. callbacks.websocket_ready = websocket_server_ready;
  132. callbacks.websocket_data = websocket_server_data;
  133. callbacks.connection_close = websocket_server_connection_close;
  134. ctx = mg_start(&callbacks, 0, options);
  135. #else
  136. /* New interface: */
  137. ctx = mg_start(&callbacks, 0, options);
  138. mg_set_websocket_handler(ctx,
  139. "/websocket",
  140. websocket_server_connect,
  141. websocket_server_ready,
  142. websocket_server_data,
  143. websocket_server_connection_close,
  144. NULL);
  145. #endif
  146. return ctx;
  147. }
  148. /*************************************************************************************/
  149. /* WEBSOCKET CLIENT */
  150. /*************************************************************************************/
  151. struct tclient_data {
  152. void *data;
  153. size_t len;
  154. int closed;
  155. };
  156. static int
  157. websocket_client_data_handler(struct mg_connection *conn,
  158. int flags,
  159. char *data,
  160. size_t data_len,
  161. void *user_data)
  162. {
  163. struct mg_context *ctx = mg_get_context(conn);
  164. struct tclient_data *pclient_data =
  165. (struct tclient_data *)mg_get_user_data(ctx);
  166. printf("Client received data from server: ");
  167. fwrite(data, 1, data_len, stdout);
  168. printf("\n");
  169. pclient_data->data = malloc(data_len);
  170. assert(pclient_data->data != NULL);
  171. memcpy(pclient_data->data, data, data_len);
  172. pclient_data->len = data_len;
  173. return 1;
  174. }
  175. static void
  176. websocket_client_close_handler(const struct mg_connection *conn,
  177. void *user_data)
  178. {
  179. struct mg_context *ctx = mg_get_context(conn);
  180. struct tclient_data *pclient_data =
  181. (struct tclient_data *)mg_get_user_data(ctx);
  182. printf("Client: Close handler\n");
  183. pclient_data->closed++;
  184. }
  185. int
  186. main(int argc, char *argv[])
  187. {
  188. struct mg_context *ctx = NULL;
  189. struct tclient_data client1_data = {NULL, 0, 0};
  190. struct tclient_data client2_data = {NULL, 0, 0};
  191. struct tclient_data client3_data = {NULL, 0, 0};
  192. struct mg_connection *newconn1 = NULL;
  193. struct mg_connection *newconn2 = NULL;
  194. struct mg_connection *newconn3 = NULL;
  195. char ebuf[100] = {0};
  196. assert(websocket_welcome_msg_len == strlen(websocket_welcome_msg));
  197. /* First set up a websocket server */
  198. ctx = start_websocket_server();
  199. assert(ctx != NULL);
  200. printf("Server init\n\n");
  201. /* Then connect a first client */
  202. newconn1 = mg_connect_websocket_client("localhost",
  203. atoi(PORT),
  204. 0,
  205. ebuf,
  206. sizeof(ebuf),
  207. "/websocket",
  208. NULL,
  209. websocket_client_data_handler,
  210. websocket_client_close_handler,
  211. &client1_data);
  212. if (newconn1 == NULL) {
  213. printf("Error: %s", ebuf);
  214. return 1;
  215. }
  216. sleep(1); /* Should get the websocket welcome message */
  217. assert(client1_data.closed == 0);
  218. assert(client2_data.closed == 0);
  219. assert(client2_data.data == NULL);
  220. assert(client2_data.len == 0);
  221. assert(client1_data.data != NULL);
  222. assert(client1_data.len == websocket_welcome_msg_len);
  223. assert(!memcmp(client1_data.data,
  224. websocket_welcome_msg,
  225. websocket_welcome_msg_len));
  226. free(client1_data.data);
  227. client1_data.data = NULL;
  228. client1_data.len = 0;
  229. mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data1", 5);
  230. sleep(1); /* Should get the acknowledge message */
  231. assert(client1_data.closed == 0);
  232. assert(client2_data.closed == 0);
  233. assert(client2_data.data == NULL);
  234. assert(client2_data.len == 0);
  235. assert(client1_data.data != NULL);
  236. assert(client1_data.len == websocket_acknowledge_msg_len);
  237. assert(!memcmp(client1_data.data,
  238. websocket_acknowledge_msg,
  239. websocket_acknowledge_msg_len));
  240. free(client1_data.data);
  241. client1_data.data = NULL;
  242. client1_data.len = 0;
  243. /* Now connect a second client */
  244. newconn2 = mg_connect_websocket_client("localhost",
  245. atoi(PORT),
  246. 0,
  247. ebuf,
  248. sizeof(ebuf),
  249. "/websocket",
  250. NULL,
  251. websocket_client_data_handler,
  252. websocket_client_close_handler,
  253. &client2_data);
  254. if (newconn2 == NULL) {
  255. printf("Error: %s", ebuf);
  256. return 1;
  257. }
  258. sleep(1); /* Client 2 should get the websocket welcome message */
  259. assert(client1_data.closed == 0);
  260. assert(client2_data.closed == 0);
  261. assert(client1_data.data == NULL);
  262. assert(client1_data.len == 0);
  263. assert(client2_data.data != NULL);
  264. assert(client2_data.len == websocket_welcome_msg_len);
  265. assert(!memcmp(client2_data.data,
  266. websocket_welcome_msg,
  267. websocket_welcome_msg_len));
  268. free(client2_data.data);
  269. client2_data.data = NULL;
  270. client2_data.len = 0;
  271. mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data2", 5);
  272. sleep(1); /* Should get the acknowledge message */
  273. assert(client1_data.closed == 0);
  274. assert(client2_data.closed == 0);
  275. assert(client2_data.data == NULL);
  276. assert(client2_data.len == 0);
  277. assert(client1_data.data != NULL);
  278. assert(client1_data.len == websocket_acknowledge_msg_len);
  279. assert(!memcmp(client1_data.data,
  280. websocket_acknowledge_msg,
  281. websocket_acknowledge_msg_len));
  282. free(client1_data.data);
  283. client1_data.data = NULL;
  284. client1_data.len = 0;
  285. mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "bye", 3);
  286. sleep(1); /* Should get the goodbye message */
  287. assert(client1_data.closed == 0);
  288. assert(client2_data.closed == 0);
  289. assert(client2_data.data == NULL);
  290. assert(client2_data.len == 0);
  291. assert(client1_data.data != NULL);
  292. assert(client1_data.len == websocket_goodbye_msg_len);
  293. assert(!memcmp(client1_data.data,
  294. websocket_goodbye_msg,
  295. websocket_goodbye_msg_len));
  296. free(client1_data.data);
  297. client1_data.data = NULL;
  298. client1_data.len = 0;
  299. mg_close_connection(newconn1);
  300. sleep(1); /* Won't get any message */
  301. assert(client1_data.closed == 1);
  302. assert(client2_data.closed == 0);
  303. assert(client1_data.data == NULL);
  304. assert(client1_data.len == 0);
  305. assert(client2_data.data == NULL);
  306. assert(client2_data.len == 0);
  307. mg_websocket_client_write(newconn2, WEBSOCKET_OPCODE_TEXT, "bye", 3);
  308. sleep(1); /* Should get the goodbye message */
  309. assert(client1_data.closed == 1);
  310. assert(client2_data.closed == 0);
  311. assert(client1_data.data == NULL);
  312. assert(client1_data.len == 0);
  313. assert(client2_data.data != NULL);
  314. assert(client2_data.len == websocket_goodbye_msg_len);
  315. assert(!memcmp(client2_data.data,
  316. websocket_goodbye_msg,
  317. websocket_goodbye_msg_len));
  318. free(client2_data.data);
  319. client2_data.data = NULL;
  320. client2_data.len = 0;
  321. mg_close_connection(newconn2);
  322. sleep(1); /* Won't get any message */
  323. assert(client1_data.closed == 1);
  324. assert(client2_data.closed == 1);
  325. assert(client1_data.data == NULL);
  326. assert(client1_data.len == 0);
  327. assert(client2_data.data == NULL);
  328. assert(client2_data.len == 0);
  329. /* Connect client 3 */
  330. newconn3 = mg_connect_websocket_client("localhost",
  331. atoi(PORT),
  332. 0,
  333. ebuf,
  334. sizeof(ebuf),
  335. "/websocket",
  336. NULL,
  337. websocket_client_data_handler,
  338. websocket_client_close_handler,
  339. &client3_data);
  340. sleep(1); /* Client 3 should get the websocket welcome message */
  341. assert(client1_data.closed == 1);
  342. assert(client2_data.closed == 1);
  343. assert(client3_data.closed == 0);
  344. assert(client1_data.data == NULL);
  345. assert(client1_data.len == 0);
  346. assert(client2_data.data == NULL);
  347. assert(client2_data.len == 0);
  348. assert(client3_data.data != NULL);
  349. assert(client3_data.len == websocket_welcome_msg_len);
  350. assert(!memcmp(client3_data.data,
  351. websocket_welcome_msg,
  352. websocket_welcome_msg_len));
  353. free(client3_data.data);
  354. client3_data.data = NULL;
  355. client3_data.len = 0;
  356. mg_stop(ctx);
  357. printf("Server shutdown\n");
  358. sleep(10);
  359. assert(client3_data.closed == 1);
  360. return 0;
  361. }