embedded_c.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /*
  2. * Copyright (c) 2013-2015 the CivetWeb developers
  3. * Copyright (c) 2013 No Face Press, LLC
  4. * License http://opensource.org/licenses/mit-license.php MIT License
  5. */
  6. /* Simple example program on how to use CivetWeb embedded into a C program. */
  7. #ifdef _WIN32
  8. #include <Windows.h>
  9. #else
  10. #include <unistd.h>
  11. #endif
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include "civetweb.h"
  15. #define DOCUMENT_ROOT "."
  16. #ifdef USE_IPV6
  17. #define PORT "[::]:8888"
  18. #else
  19. #define PORT "8888"
  20. #endif
  21. #define EXAMPLE_URI "/example"
  22. #define EXIT_URI "/exit"
  23. int exitNow = 0;
  24. int
  25. ExampleHandler(struct mg_connection *conn, void *cbdata)
  26. {
  27. mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
  28. mg_printf(conn, "<html><body>");
  29. mg_printf(conn, "<h2>This is an example text from a C handler</h2>");
  30. mg_printf(
  31. conn,
  32. "<p>To see a page from the A handler <a href=\"A\">click A</a></p>");
  33. mg_printf(conn,
  34. "<p>To see a page from the A handler <a href=\"A/A\">click "
  35. "A/A</a></p>");
  36. mg_printf(conn,
  37. "<p>To see a page from the A/B handler <a "
  38. "href=\"A/B\">click A/B</a></p>");
  39. mg_printf(conn,
  40. "<p>To see a page from the B handler (0) <a "
  41. "href=\"B\">click B</a></p>");
  42. mg_printf(conn,
  43. "<p>To see a page from the B handler (1) <a "
  44. "href=\"B/A\">click B/A</a></p>");
  45. mg_printf(conn,
  46. "<p>To see a page from the B handler (2) <a "
  47. "href=\"B/B\">click B/B</a></p>");
  48. mg_printf(conn,
  49. "<p>To see a page from the *.foo handler <a "
  50. "href=\"xy.foo\">click xy.foo</a></p>");
  51. #ifdef USE_WEBSOCKET
  52. mg_printf(conn,
  53. "<p>To test websocket handler <a href=\"/websocket\">click "
  54. "websocket</a></p>");
  55. #endif
  56. mg_printf(conn, "<p>To exit <a href=\"%s\">click exit</a></p>", EXIT_URI);
  57. mg_printf(conn, "</body></html>\n");
  58. return 1;
  59. }
  60. int
  61. ExitHandler(struct mg_connection *conn, void *cbdata)
  62. {
  63. mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n");
  64. mg_printf(conn, "Server will shut down.\n");
  65. mg_printf(conn, "Bye!\n");
  66. exitNow = 1;
  67. return 1;
  68. }
  69. int
  70. AHandler(struct mg_connection *conn, void *cbdata)
  71. {
  72. mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
  73. mg_printf(conn, "<html><body>");
  74. mg_printf(conn, "<h2>This is the A handler!!!</h2>");
  75. mg_printf(conn, "</body></html>\n");
  76. return 1;
  77. }
  78. int
  79. ABHandler(struct mg_connection *conn, void *cbdata)
  80. {
  81. mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
  82. mg_printf(conn, "<html><body>");
  83. mg_printf(conn, "<h2>This is the AB handler!!!</h2>");
  84. mg_printf(conn, "</body></html>\n");
  85. return 1;
  86. }
  87. int
  88. BXHandler(struct mg_connection *conn, void *cbdata)
  89. {
  90. /* Handler may access the request info using mg_get_request_info */
  91. const struct mg_request_info *req_info = mg_get_request_info(conn);
  92. mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
  93. mg_printf(conn, "<html><body>");
  94. mg_printf(conn, "<h2>This is the BX handler %p!!!</h2>", cbdata);
  95. mg_printf(conn, "<p>The actual uri is %s</p>", req_info->uri);
  96. mg_printf(conn, "</body></html>\n");
  97. return 1;
  98. }
  99. int
  100. FooHandler(struct mg_connection *conn, void *cbdata)
  101. {
  102. /* Handler may access the request info using mg_get_request_info */
  103. const struct mg_request_info *req_info = mg_get_request_info(conn);
  104. mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
  105. mg_printf(conn, "<html><body>");
  106. mg_printf(conn, "<h2>This is the Foo handler!!!</h2>");
  107. mg_printf(conn,
  108. "<p>The request was:<br><pre>%s %s HTTP/%s</pre></p>",
  109. req_info->request_method,
  110. req_info->uri,
  111. req_info->http_version);
  112. mg_printf(conn, "</body></html>\n");
  113. return 1;
  114. }
  115. int
  116. WebSocketStartHandler(struct mg_connection *conn, void *cbdata)
  117. {
  118. mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n");
  119. mg_printf(conn, "<!DOCTYPE html>\n");
  120. mg_printf(conn, "<html>\n<head>\n");
  121. mg_printf(conn, "<meta charset=\"UTF-8\">\n");
  122. mg_printf(conn, "<title>Embedded websocket example</title>\n");
  123. #ifdef USE_WEBSOCKET
  124. /* mg_printf(conn, "<script type=\"text/javascript\"><![CDATA[\n"); ...
  125. * xhtml style */
  126. mg_printf(conn, "<script>\n");
  127. mg_printf(
  128. conn,
  129. "function load() {\n"
  130. " var wsproto = (location.protocol === 'https:') ? 'wss:' : 'ws:';\n"
  131. " connection = new WebSocket(wsproto + '//' + window.location.host + "
  132. "'/websocket');\n"
  133. " websock_text_field = "
  134. "document.getElementById('websock_text_field');\n"
  135. " connection.onmessage = function (e) {\n"
  136. " websock_text_field.innerHTML=e.data;\n"
  137. " }\n"
  138. " connection.onerror = function (error) {\n"
  139. " alert('WebSocket error');\n"
  140. " connection.close();\n"
  141. " }\n"
  142. "}\n");
  143. /* mg_printf(conn, "]]></script>\n"); ... xhtml style */
  144. mg_printf(conn, "</script>\n");
  145. mg_printf(conn, "</head>\n<body onload=\"load()\">\n");
  146. mg_printf(
  147. conn,
  148. "<div id='websock_text_field'>No websocket connection yet</div>\n");
  149. #else
  150. mg_printf(conn, "</head>\n<body>\n");
  151. mg_printf(conn, "Example not compiled with USE_WEBSOCKET\n");
  152. #endif
  153. mg_printf(conn, "</body>\n</html>\n");
  154. return 1;
  155. }
  156. #ifdef USE_WEBSOCKET
  157. /* MAX_WS_CLIENTS defines how many clients can connect to a websocket at the
  158. * same time. The value 5 is very small and used here only for demonstration;
  159. * it can be easily tested to connect more than MAX_WS_CLIENTS clients.
  160. * A real server should use a much higher number, or better use a dynamic list
  161. * of currently connected websocket clients. */
  162. #define MAX_WS_CLIENTS (5)
  163. struct t_ws_client {
  164. struct mg_connection *conn;
  165. int state;
  166. } static ws_clients[MAX_WS_CLIENTS];
  167. #define ASSERT(x) \
  168. { \
  169. if (!(x)) { \
  170. fprintf(stderr, \
  171. "Assertion failed in line %u\n", \
  172. (unsigned)__LINE__); \
  173. } \
  174. }
  175. int
  176. WebSocketConnectHandler(const struct mg_connection *conn, void *cbdata)
  177. {
  178. struct mg_context *ctx = mg_get_context(conn);
  179. int reject = 1;
  180. int i;
  181. mg_lock_context(ctx);
  182. for (i = 0; i < MAX_WS_CLIENTS; i++) {
  183. if (ws_clients[i].conn == NULL) {
  184. ws_clients[i].conn = (struct mg_connection *)conn;
  185. ws_clients[i].state = 1;
  186. mg_set_user_connection_data(conn, (void *)(ws_clients + i));
  187. reject = 0;
  188. break;
  189. }
  190. }
  191. mg_unlock_context(ctx);
  192. fprintf(stdout,
  193. "Websocket client %s\r\n\r\n",
  194. (reject ? "rejected" : "accepted"));
  195. return reject;
  196. }
  197. void
  198. WebSocketReadyHandler(struct mg_connection *conn, void *cbdata)
  199. {
  200. const char *text = "Hello from the websocket ready handler";
  201. struct t_ws_client *client = mg_get_user_connection_data(conn);
  202. mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, text, strlen(text));
  203. fprintf(stdout, "Greeting message sent to websocket client\r\n\r\n");
  204. ASSERT(client->conn == conn);
  205. ASSERT(client->state == 1);
  206. client->state = 2;
  207. }
  208. int
  209. WebsocketDataHandler(struct mg_connection *conn,
  210. int bits,
  211. char *data,
  212. size_t len,
  213. void *cbdata)
  214. {
  215. struct t_ws_client *client = mg_get_user_connection_data(conn);
  216. ASSERT(client->conn == conn);
  217. ASSERT(client->state >= 1);
  218. fprintf(stdout, "Websocket got data:\r\n");
  219. fwrite(data, len, 1, stdout);
  220. fprintf(stdout, "\r\n\r\n");
  221. return 1;
  222. }
  223. void
  224. WebSocketCloseHandler(const struct mg_connection *conn, void *cbdata)
  225. {
  226. struct mg_context *ctx = mg_get_context(conn);
  227. struct t_ws_client *client = mg_get_user_connection_data(conn);
  228. ASSERT(client->conn == conn);
  229. ASSERT(client->state >= 1);
  230. mg_lock_context(ctx);
  231. client->state = 0;
  232. client->conn = NULL;
  233. mg_unlock_context(ctx);
  234. fprintf(stdout,
  235. "Client droped from the set of webserver connections\r\n\r\n");
  236. }
  237. void
  238. InformWebsockets(struct mg_context *ctx)
  239. {
  240. static unsigned long cnt = 0;
  241. char text[32];
  242. int i;
  243. sprintf(text, "%lu", ++cnt);
  244. mg_lock_context(ctx);
  245. for (i = 0; i < MAX_WS_CLIENTS; i++) {
  246. if (ws_clients[i].state == 2) {
  247. mg_websocket_write(ws_clients[i].conn,
  248. WEBSOCKET_OPCODE_TEXT,
  249. text,
  250. strlen(text));
  251. }
  252. }
  253. mg_unlock_context(ctx);
  254. }
  255. #endif
  256. int
  257. main(int argc, char *argv[])
  258. {
  259. const char *options[] = {"document_root",
  260. DOCUMENT_ROOT,
  261. "listening_ports",
  262. PORT,
  263. "request_timeout_ms",
  264. "10000",
  265. "error_log_file",
  266. "error.log",
  267. #ifdef USE_WEBSOCKET
  268. "websocket_timeout_ms",
  269. "3600000",
  270. #endif
  271. 0};
  272. struct mg_callbacks callbacks;
  273. struct mg_context *ctx;
  274. struct mg_server_ports ports[32];
  275. int port_cnt, n;
  276. int err = 0;
  277. /* Check if libcivetweb has been built with all required features. */
  278. #ifdef USE_IPV6
  279. if (!mg_check_feature(8)) {
  280. fprintf(stderr,
  281. "Error: Embedded example built with websocket support, "
  282. "but civetweb library build without.\n");
  283. err = 1;
  284. }
  285. #endif
  286. #ifdef USE_WEBSOCKET
  287. if (!mg_check_feature(16)) {
  288. fprintf(stderr,
  289. "Error: Embedded example built with websocket support, "
  290. "but civetweb library build without.\n");
  291. err = 1;
  292. }
  293. #endif
  294. if (err) {
  295. fprintf(stderr, "Cannot start CivetWeb - inconsistent build.\n");
  296. return EXIT_FAILURE;
  297. }
  298. /* Start CivetWeb web server */
  299. memset(&callbacks, 0, sizeof(callbacks));
  300. ctx = mg_start(&callbacks, 0, options);
  301. /* Add handler EXAMPLE_URI, to explain the example */
  302. mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0);
  303. mg_set_request_handler(ctx, EXIT_URI, ExitHandler, 0);
  304. /* Add handler for /A* and special handler for /A/B */
  305. mg_set_request_handler(ctx, "/A", AHandler, 0);
  306. mg_set_request_handler(ctx, "/A/B", ABHandler, 0);
  307. /* Add handler for /B, /B/A, /B/B but not for /B* */
  308. mg_set_request_handler(ctx, "/B$", BXHandler, (void *)0);
  309. mg_set_request_handler(ctx, "/B/A$", BXHandler, (void *)1);
  310. mg_set_request_handler(ctx, "/B/B$", BXHandler, (void *)2);
  311. /* Add handler for all files with .foo extention */
  312. mg_set_request_handler(ctx, "**.foo$", FooHandler, 0);
  313. /* Add HTTP site to open a websocket connection */
  314. mg_set_request_handler(ctx, "/websocket", WebSocketStartHandler, 0);
  315. #ifdef USE_WEBSOCKET
  316. /* WS site for the websocket connection */
  317. mg_set_websocket_handler(ctx,
  318. "/websocket",
  319. WebSocketConnectHandler,
  320. WebSocketReadyHandler,
  321. WebsocketDataHandler,
  322. WebSocketCloseHandler,
  323. 0);
  324. #endif
  325. /* List all listening ports */
  326. memset(ports, 0, sizeof(ports));
  327. port_cnt = mg_get_server_ports(ctx, 32, ports);
  328. printf("\n%i listening ports:\n\n", port_cnt);
  329. for (n = 0; n < port_cnt && n < 32; n++) {
  330. const char *proto = ports[n].is_ssl ? "https" : "http";
  331. const char *host;
  332. if ((ports[n].protocol & 1) == 1) {
  333. /* IPv4 */
  334. host = "127.0.0.1";
  335. printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);
  336. printf("Run example at %s://%s:%i%s\n",
  337. proto,
  338. host,
  339. ports[n].port,
  340. EXAMPLE_URI);
  341. printf(
  342. "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);
  343. printf("\n");
  344. }
  345. if ((ports[n].protocol & 2) == 2) {
  346. /* IPv6 */
  347. host = "[::1]";
  348. printf("Browse files at %s://%s:%i/\n", proto, host, ports[n].port);
  349. printf("Run example at %s://%s:%i%s\n",
  350. proto,
  351. host,
  352. ports[n].port,
  353. EXAMPLE_URI);
  354. printf(
  355. "Exit at %s://%s:%i%s\n", proto, host, ports[n].port, EXIT_URI);
  356. printf("\n");
  357. }
  358. }
  359. /* Wait until the server should be closed */
  360. while (!exitNow) {
  361. #ifdef _WIN32
  362. Sleep(1000);
  363. #else
  364. sleep(1);
  365. #endif
  366. #ifdef USE_WEBSOCKET
  367. InformWebsockets(ctx);
  368. #endif
  369. }
  370. /* Stop the server */
  371. mg_stop(ctx);
  372. printf("Server stopped.\n");
  373. printf("Bye!\n");
  374. return EXIT_SUCCESS;
  375. }