test-server-libuv.c 12 KB

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