test-server-libuv.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. * libwebsockets-test-server for libev - libwebsockets test implementation
  3. *
  4. * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation:
  9. * version 2.1 of the License.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301 USA
  20. */
  21. #include "test-server.h"
  22. #include <uv.h>
  23. int close_testing;
  24. int max_poll_elements;
  25. int debug_level = 7;
  26. struct lws_context *context;
  27. struct lws_plat_file_ops fops_plat;
  28. /* http server gets files from this path */
  29. #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
  30. char *resource_path = LOCAL_RESOURCE_PATH;
  31. #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param)
  32. char crl_path[1024] = "";
  33. #endif
  34. /* singlethreaded version --> no locks */
  35. void test_server_lock(int care)
  36. {
  37. }
  38. void test_server_unlock(int care)
  39. {
  40. }
  41. /*
  42. * This demo server shows how to use libwebsockets for one or more
  43. * websocket protocols in the same server
  44. *
  45. * It defines the following websocket protocols:
  46. *
  47. * dumb-increment-protocol: once the socket is opened, an incrementing
  48. * ascii string is sent down it every 50ms.
  49. * If you send "reset\n" on the websocket, then
  50. * the incrementing number is reset to 0.
  51. *
  52. * lws-mirror-protocol: copies any received packet to every connection also
  53. * using this protocol, including the sender
  54. */
  55. enum demo_protocols {
  56. /* always first */
  57. PROTOCOL_HTTP = 0,
  58. PROTOCOL_DUMB_INCREMENT,
  59. PROTOCOL_LWS_MIRROR,
  60. /* always last */
  61. DEMO_PROTOCOL_COUNT
  62. };
  63. /* list of supported protocols and callbacks */
  64. static struct lws_protocols protocols[] = {
  65. /* first protocol must always be HTTP handler */
  66. {
  67. "http-only", /* name */
  68. callback_http, /* callback */
  69. sizeof (struct per_session_data__http), /* per_session_data_size */
  70. 0, /* max frame size / rx buffer */
  71. },
  72. {
  73. "dumb-increment-protocol",
  74. callback_dumb_increment,
  75. sizeof(struct per_session_data__dumb_increment),
  76. 10,
  77. },
  78. {
  79. "lws-mirror-protocol",
  80. callback_lws_mirror,
  81. sizeof(struct per_session_data__lws_mirror),
  82. 128,
  83. },
  84. {
  85. "lws-status",
  86. callback_lws_status,
  87. sizeof(struct per_session_data__lws_status),
  88. 128,
  89. },
  90. { NULL, NULL, 0, 0 } /* terminator */
  91. };
  92. static const struct lws_extension exts[] = {
  93. {
  94. "permessage-deflate",
  95. lws_extension_callback_pm_deflate,
  96. "permessage-deflate; client_no_context_takeover; client_max_window_bits"
  97. },
  98. {
  99. "deflate-frame",
  100. lws_extension_callback_pm_deflate,
  101. "deflate_frame"
  102. },
  103. { NULL, NULL, NULL /* terminator */ }
  104. };
  105. void signal_cb(uv_signal_t *watcher, int signum)
  106. {
  107. lwsl_err("Signal %d caught, exiting...\n", watcher->signum);
  108. switch (watcher->signum) {
  109. case SIGTERM:
  110. case SIGINT:
  111. break;
  112. default:
  113. signal(SIGABRT, SIG_DFL);
  114. abort();
  115. break;
  116. }
  117. lws_libuv_stop(context);
  118. }
  119. static void
  120. uv_timeout_cb_dumb_increment(uv_timer_t *w
  121. #if UV_VERSION_MAJOR == 0
  122. , int status
  123. #endif
  124. )
  125. {
  126. lws_callback_on_writable_all_protocol(context,
  127. &protocols[PROTOCOL_DUMB_INCREMENT]);
  128. }
  129. static struct option options[] = {
  130. { "help", no_argument, NULL, 'h' },
  131. { "debug", required_argument, NULL, 'd' },
  132. { "port", required_argument, NULL, 'p' },
  133. { "ssl", no_argument, NULL, 's' },
  134. { "allow-non-ssl", no_argument, NULL, 'a' },
  135. { "interface", required_argument, NULL, 'i' },
  136. { "closetest", no_argument, NULL, 'c' },
  137. { "libev", no_argument, NULL, 'e' },
  138. { "foreign", no_argument, NULL, 'f' },
  139. #ifndef LWS_NO_DAEMONIZE
  140. { "daemonize", no_argument, NULL, 'D' },
  141. #endif
  142. { "resource_path", required_argument, NULL, 'r' },
  143. { NULL, 0, 0, 0 }
  144. };
  145. #if UV_VERSION_MAJOR > 0
  146. /* ----- this code is only needed for foreign / external libuv tests -----*/
  147. struct counter
  148. {
  149. int cur, lim;
  150. int stop_loop;
  151. };
  152. static void timer_cb(uv_timer_t *t)
  153. {
  154. struct counter *c = t->data;
  155. lwsl_notice(" timer %p cb, count %d, loop has %d handles\n",
  156. t, c->cur, t->loop->active_handles);
  157. if (c->cur++ == c->lim) {
  158. lwsl_debug("stop loop from timer\n");
  159. uv_timer_stop(t);
  160. if (c->stop_loop)
  161. uv_stop(t->loop);
  162. }
  163. }
  164. static void timer_close_cb(uv_handle_t *h)
  165. {
  166. lwsl_notice("timer close cb %p, loop has %d handles\n",
  167. h, h->loop->active_handles);
  168. }
  169. void outer_signal_cb(uv_signal_t *s, int signum)
  170. {
  171. lwsl_notice("Foreign loop got signal %d\n", signum);
  172. uv_signal_stop(s);
  173. uv_stop(s->loop);
  174. }
  175. static void lws_uv_close_cb(uv_handle_t *handle)
  176. {
  177. //lwsl_err("%s\n", __func__);
  178. }
  179. static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
  180. {
  181. uv_close(handle, lws_uv_close_cb);
  182. }
  183. /* --- end of foreign test code ---- */
  184. #endif
  185. int main(int argc, char **argv)
  186. {
  187. struct lws_context_creation_info info;
  188. char interface_name[128] = "";
  189. #if UV_VERSION_MAJOR > 0
  190. /* --- only needed for foreign loop test ---> */
  191. uv_loop_t loop;
  192. uv_signal_t signal_outer;
  193. uv_timer_t timer_outer;
  194. struct counter ctr;
  195. int foreign_libuv_loop = 0;
  196. /* <--- only needed for foreign loop test --- */
  197. #endif
  198. uv_timer_t timeout_watcher;
  199. const char *iface = NULL;
  200. char cert_path[1024];
  201. char key_path[1024];
  202. int use_ssl = 0;
  203. int opts = 0;
  204. int n = 0;
  205. #ifndef _WIN32
  206. int syslog_options = LOG_PID | LOG_PERROR;
  207. #endif
  208. #ifndef LWS_NO_DAEMONIZE
  209. int daemonize = 0;
  210. #endif
  211. /*
  212. * take care to zero down the info struct, he contains random garbaage
  213. * from the stack otherwise
  214. */
  215. memset(&info, 0, sizeof info);
  216. info.port = 7681;
  217. while (n >= 0) {
  218. n = getopt_long(argc, argv, "feci:hsap:d:Dr:", options, NULL);
  219. if (n < 0)
  220. continue;
  221. switch (n) {
  222. case 'f':
  223. #if UV_VERSION_MAJOR > 0
  224. foreign_libuv_loop = 1;
  225. #endif
  226. break;
  227. case 'e':
  228. opts |= LWS_SERVER_OPTION_LIBEV;
  229. break;
  230. #ifndef LWS_NO_DAEMONIZE
  231. case 'D':
  232. daemonize = 1;
  233. #ifndef _WIN32
  234. syslog_options &= ~LOG_PERROR;
  235. #endif
  236. break;
  237. #endif
  238. case 'd':
  239. debug_level = atoi(optarg);
  240. break;
  241. case 's':
  242. use_ssl = 1;
  243. break;
  244. case 'a':
  245. opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
  246. break;
  247. case 'p':
  248. info.port = atoi(optarg);
  249. break;
  250. case 'i':
  251. strncpy(interface_name, optarg, sizeof interface_name);
  252. interface_name[(sizeof interface_name) - 1] = '\0';
  253. iface = interface_name;
  254. break;
  255. case 'c':
  256. close_testing = 1;
  257. fprintf(stderr, " Close testing mode -- closes on "
  258. "client after 50 dumb increments"
  259. "and suppresses lws_mirror spam\n");
  260. break;
  261. case 'r':
  262. resource_path = optarg;
  263. printf("Setting resource path to \"%s\"\n", resource_path);
  264. break;
  265. case 'h':
  266. fprintf(stderr, "Usage: test-server "
  267. "[--port=<p>] [--ssl] "
  268. "[-d <log bitfield>] "
  269. "[--resource_path <path>]\n");
  270. exit(1);
  271. }
  272. }
  273. #if !defined(WIN32)
  274. #if !defined(LWS_NO_DAEMONIZE)
  275. /*
  276. * normally lock path would be /var/lock/lwsts or similar, to
  277. * simplify getting started without having to take care about
  278. * permissions or running as root, set to /tmp/.lwsts-lock
  279. */
  280. if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
  281. fprintf(stderr, "Failed to daemonize\n");
  282. return 1;
  283. }
  284. #endif
  285. /* we will only try to log things according to our debug_level */
  286. setlogmask(LOG_UPTO (LOG_DEBUG));
  287. openlog("lwsts", syslog_options, LOG_DAEMON);
  288. #endif
  289. /* tell the library what debug level to emit and to send it to syslog */
  290. lws_set_log_level(debug_level, lwsl_emit_syslog);
  291. lwsl_notice("libwebsockets test server libuv - license LGPL2.1+SLE\n");
  292. lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
  293. lwsl_info("Using resource path \"%s\"\n", resource_path);
  294. info.iface = iface;
  295. info.protocols = protocols;
  296. info.extensions = exts;
  297. info.ssl_cert_filepath = NULL;
  298. info.ssl_private_key_filepath = NULL;
  299. if (use_ssl) {
  300. if (strlen(resource_path) > sizeof(cert_path) - 32) {
  301. lwsl_err("resource path too long\n");
  302. return -1;
  303. }
  304. sprintf(cert_path, "%s/libwebsockets-test-server.pem",
  305. resource_path);
  306. if (strlen(resource_path) > sizeof(key_path) - 32) {
  307. lwsl_err("resource path too long\n");
  308. return -1;
  309. }
  310. sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
  311. resource_path);
  312. info.ssl_cert_filepath = cert_path;
  313. info.ssl_private_key_filepath = key_path;
  314. opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
  315. }
  316. info.gid = -1;
  317. info.uid = -1;
  318. info.max_http_header_pool = 1;
  319. info.timeout_secs = 5;
  320. info.options = opts | LWS_SERVER_OPTION_LIBUV;
  321. #if UV_VERSION_MAJOR > 0
  322. if (foreign_libuv_loop) {
  323. /* create the foreign loop */
  324. uv_loop_init(&loop);
  325. /* run some timer on that loop just so loop is not 'clean' */
  326. uv_signal_init(&loop, &signal_outer);
  327. uv_signal_start(&signal_outer, outer_signal_cb, SIGINT);
  328. uv_timer_init(&loop, &timer_outer);
  329. timer_outer.data = &ctr;
  330. ctr.cur = 0;
  331. ctr.lim = ctr.cur + 5;
  332. ctr.stop_loop = 1;
  333. uv_timer_start(&timer_outer, timer_cb, 0, 1000);
  334. lwsl_notice("running loop without libwebsockets for %d s\n", ctr.lim);
  335. uv_run(&loop, UV_RUN_DEFAULT);
  336. /* timer will stop loop and we will get here */
  337. }
  338. #endif
  339. context = lws_create_context(&info);
  340. if (context == NULL) {
  341. lwsl_err("libwebsocket init failed\n");
  342. return -1;
  343. }
  344. lws_uv_sigint_cfg(context, 1, signal_cb);
  345. #if UV_VERSION_MAJOR > 0
  346. if (foreign_libuv_loop)
  347. /* we have our own uv loop outside of lws */
  348. lws_uv_initloop(context, &loop, 0);
  349. else
  350. #endif
  351. {
  352. /*
  353. * lws will create his own libuv loop in the context
  354. */
  355. if (lws_uv_initloop(context, NULL, 0)) {
  356. lwsl_err("lws_uv_initloop failed\n");
  357. goto bail;
  358. }
  359. }
  360. uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher);
  361. uv_timer_start(&timeout_watcher, uv_timeout_cb_dumb_increment, 50, 50);
  362. #if UV_VERSION_MAJOR > 0
  363. if (foreign_libuv_loop) {
  364. /*
  365. * prepare inner timer on loop, to run along with lws.
  366. * Will exit after 5s while lws keeps running
  367. */
  368. struct counter ctr_inner = { 0, 3, 0 };
  369. int e;
  370. uv_timer_t timer_inner;
  371. uv_timer_init(&loop, &timer_inner);
  372. timer_inner.data = &ctr_inner;
  373. uv_timer_start(&timer_inner, timer_cb, 200, 1000);
  374. /* make this timer long-lived, should keep
  375. * firing after lws exits */
  376. ctr.cur = 0;
  377. ctr.lim = ctr.cur + 1000;
  378. uv_timer_start(&timer_outer, timer_cb, 0, 1000);
  379. uv_run(&loop, UV_RUN_DEFAULT);
  380. /* we are here either because signal stopped us,
  381. * or outer timer expired */
  382. /* close short timer */
  383. uv_timer_stop(&timer_inner);
  384. uv_close((uv_handle_t*)&timer_inner, timer_close_cb);
  385. /* stop the dumb increment timer */
  386. uv_timer_stop(&timeout_watcher);
  387. lwsl_notice("Destroying lws context\n");
  388. /* detach lws */
  389. lws_context_destroy(context);
  390. lwsl_notice("Please wait while the outer libuv test continues for 10s\n");
  391. ctr.lim = ctr.cur + 10;
  392. /* try and run outer timer for 10 more seconds,
  393. * (or sigint outer handler) after lws has left the loop */
  394. uv_run(&loop, UV_RUN_DEFAULT);
  395. /* Clean up the foreign loop now */
  396. /* PHASE 1: stop and close things we created
  397. * outside of lws */
  398. uv_timer_stop(&timer_outer);
  399. uv_close((uv_handle_t*)&timer_outer, timer_close_cb);
  400. uv_signal_stop(&signal_outer);
  401. e = 100;
  402. while (e--)
  403. uv_run(&loop, UV_RUN_NOWAIT);
  404. /* PHASE 2: close anything remaining */
  405. uv_walk(&loop, lws_uv_walk_cb, NULL);
  406. e = 100;
  407. while (e--)
  408. uv_run(&loop, UV_RUN_NOWAIT);
  409. /* PHASE 3: close the UV loop itself */
  410. e = uv_loop_close(&loop);
  411. lwsl_notice("uv loop close rc %s\n",
  412. e ? uv_strerror(e) : "ok");
  413. } else
  414. #endif
  415. {
  416. lws_libuv_run(context, 0);
  417. bail:
  418. lws_context_destroy(context);
  419. }
  420. lwsl_notice("libwebsockets-test-server exited cleanly\n");
  421. return 0;
  422. }