test-server.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. * libwebsockets-test-server - libwebsockets test implementation
  3. *
  4. * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
  5. *
  6. * This file is made available under the Creative Commons CC0 1.0
  7. * Universal Public Domain Dedication.
  8. *
  9. * The person who associated a work with this deed has dedicated
  10. * the work to the public domain by waiving all of his or her rights
  11. * to the work worldwide under copyright law, including all related
  12. * and neighboring rights, to the extent allowed by law. You can copy,
  13. * modify, distribute and perform the work, even for commercial purposes,
  14. * all without asking permission.
  15. *
  16. * The test apps are intended to be adapted for use in your code, which
  17. * may be proprietary. So unlike the library itself, they are licensed
  18. * Public Domain.
  19. */
  20. #include "test-server.h"
  21. int close_testing;
  22. int max_poll_elements;
  23. int debug_level = 7;
  24. #ifdef EXTERNAL_POLL
  25. struct lws_pollfd *pollfds;
  26. int *fd_lookup;
  27. int count_pollfds;
  28. #endif
  29. volatile int force_exit = 0;
  30. struct lws_context *context;
  31. struct lws_plat_file_ops fops_plat;
  32. /* http server gets files from this path */
  33. #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
  34. char *resource_path = LOCAL_RESOURCE_PATH;
  35. #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param)
  36. char crl_path[1024] = "";
  37. #endif
  38. /* singlethreaded version --> no locks */
  39. void test_server_lock(int care)
  40. {
  41. }
  42. void test_server_unlock(int care)
  43. {
  44. }
  45. /*
  46. * This demo server shows how to use libwebsockets for one or more
  47. * websocket protocols in the same server
  48. *
  49. * It defines the following websocket protocols:
  50. *
  51. * dumb-increment-protocol: once the socket is opened, an incrementing
  52. * ascii string is sent down it every 50ms.
  53. * If you send "reset\n" on the websocket, then
  54. * the incrementing number is reset to 0.
  55. *
  56. * lws-mirror-protocol: copies any received packet to every connection also
  57. * using this protocol, including the sender
  58. */
  59. enum demo_protocols {
  60. /* always first */
  61. PROTOCOL_HTTP = 0,
  62. PROTOCOL_DUMB_INCREMENT,
  63. PROTOCOL_LWS_MIRROR,
  64. PROTOCOL_LWS_ECHOGEN,
  65. PROTOCOL_LWS_STATUS,
  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, /* rx buf size must be >= permessage-deflate rx size */
  83. },
  84. {
  85. "lws-mirror-protocol",
  86. callback_lws_mirror,
  87. sizeof(struct per_session_data__lws_mirror),
  88. 128, /* rx buf size must be >= permessage-deflate rx size */
  89. },
  90. {
  91. "lws-echogen",
  92. callback_lws_echogen,
  93. sizeof(struct per_session_data__echogen),
  94. 128, /* rx buf size must be >= permessage-deflate rx size */
  95. },
  96. {
  97. "lws-status",
  98. callback_lws_status,
  99. sizeof(struct per_session_data__lws_status),
  100. 128, /* rx buf size must be >= permessage-deflate rx size */
  101. },
  102. { NULL, NULL, 0, 0 } /* terminator */
  103. };
  104. /* this shows how to override the lws file operations. You don't need
  105. * to do any of this unless you have a reason (eg, want to serve
  106. * compressed files without decompressing the whole archive)
  107. */
  108. static lws_fop_fd_t
  109. test_server_fops_open(const struct lws_plat_file_ops *fops,
  110. const char *vfs_path, const char *vpath,
  111. lws_fop_flags_t *flags)
  112. {
  113. lws_fop_fd_t fop_fd;
  114. /* call through to original platform implementation */
  115. fop_fd = fops_plat.open(fops, vfs_path, vpath, flags);
  116. if (fop_fd)
  117. lwsl_info("%s: opening %s, ret %p, len %lu\n", __func__,
  118. vfs_path, fop_fd,
  119. (long)lws_vfs_get_length(fop_fd));
  120. else
  121. lwsl_info("%s: open %s failed\n", __func__, vfs_path);
  122. return fop_fd;
  123. }
  124. void sighandler(int sig)
  125. {
  126. force_exit = 1;
  127. lws_cancel_service(context);
  128. }
  129. static const struct lws_extension exts[] = {
  130. {
  131. "permessage-deflate",
  132. lws_extension_callback_pm_deflate,
  133. "permessage-deflate"
  134. },
  135. {
  136. "deflate-frame",
  137. lws_extension_callback_pm_deflate,
  138. "deflate_frame"
  139. },
  140. { NULL, NULL, NULL /* terminator */ }
  141. };
  142. static struct option options[] = {
  143. { "help", no_argument, NULL, 'h' },
  144. { "debug", required_argument, NULL, 'd' },
  145. { "port", required_argument, NULL, 'p' },
  146. { "ssl", no_argument, NULL, 's' },
  147. { "allow-non-ssl", no_argument, NULL, 'a' },
  148. { "interface", required_argument, NULL, 'i' },
  149. { "closetest", no_argument, NULL, 'c' },
  150. { "ssl-cert", required_argument, NULL, 'C' },
  151. { "ssl-key", required_argument, NULL, 'K' },
  152. { "ssl-ca", required_argument, NULL, 'A' },
  153. #if defined(LWS_OPENSSL_SUPPORT)
  154. { "ssl-verify-client", no_argument, NULL, 'v' },
  155. #if defined(LWS_HAVE_SSL_CTX_set1_param)
  156. { "ssl-crl", required_argument, NULL, 'R' },
  157. #endif
  158. #endif
  159. { "libev", no_argument, NULL, 'e' },
  160. #ifndef LWS_NO_DAEMONIZE
  161. { "daemonize", no_argument, NULL, 'D' },
  162. #endif
  163. { "resource_path", required_argument, NULL, 'r' },
  164. { "pingpong-secs", required_argument, NULL, 'P' },
  165. { NULL, 0, 0, 0 }
  166. };
  167. int main(int argc, char **argv)
  168. {
  169. struct lws_context_creation_info info;
  170. char interface_name[128] = "";
  171. unsigned int ms, oldms = 0;
  172. const char *iface = NULL;
  173. char cert_path[1024] = "";
  174. char key_path[1024] = "";
  175. char ca_path[1024] = "";
  176. int uid = -1, gid = -1;
  177. int use_ssl = 0;
  178. int pp_secs = 0;
  179. int opts = 0;
  180. int n = 0;
  181. #ifndef _WIN32
  182. /* LOG_PERROR is not POSIX standard, and may not be portable */
  183. #ifdef __sun
  184. int syslog_options = LOG_PID;
  185. #else
  186. int syslog_options = LOG_PID | LOG_PERROR;
  187. #endif
  188. #endif
  189. #ifndef LWS_NO_DAEMONIZE
  190. int daemonize = 0;
  191. #endif
  192. /*
  193. * take care to zero down the info struct, he contains random garbaage
  194. * from the stack otherwise
  195. */
  196. memset(&info, 0, sizeof info);
  197. info.port = 7681;
  198. while (n >= 0) {
  199. n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:", options, NULL);
  200. if (n < 0)
  201. continue;
  202. switch (n) {
  203. case 'e':
  204. opts |= LWS_SERVER_OPTION_LIBEV;
  205. break;
  206. #ifndef LWS_NO_DAEMONIZE
  207. case 'D':
  208. daemonize = 1;
  209. #if !defined(_WIN32) && !defined(__sun)
  210. syslog_options &= ~LOG_PERROR;
  211. #endif
  212. break;
  213. #endif
  214. case 'u':
  215. uid = atoi(optarg);
  216. break;
  217. case 'g':
  218. gid = atoi(optarg);
  219. break;
  220. case 'd':
  221. debug_level = atoi(optarg);
  222. break;
  223. case 's':
  224. use_ssl = 1;
  225. break;
  226. case 'a':
  227. opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
  228. break;
  229. case 'p':
  230. info.port = atoi(optarg);
  231. break;
  232. case 'i':
  233. strncpy(interface_name, optarg, sizeof interface_name);
  234. interface_name[(sizeof interface_name) - 1] = '\0';
  235. iface = interface_name;
  236. break;
  237. case 'c':
  238. close_testing = 1;
  239. fprintf(stderr, " Close testing mode -- closes on "
  240. "client after 50 dumb increments"
  241. "and suppresses lws_mirror spam\n");
  242. break;
  243. case 'r':
  244. resource_path = optarg;
  245. printf("Setting resource path to \"%s\"\n", resource_path);
  246. break;
  247. case 'C':
  248. strncpy(cert_path, optarg, sizeof(cert_path) - 1);
  249. cert_path[sizeof(cert_path) - 1] = '\0';
  250. break;
  251. case 'K':
  252. strncpy(key_path, optarg, sizeof(key_path) - 1);
  253. key_path[sizeof(key_path) - 1] = '\0';
  254. break;
  255. case 'A':
  256. strncpy(ca_path, optarg, sizeof(ca_path) - 1);
  257. ca_path[sizeof(ca_path) - 1] = '\0';
  258. break;
  259. case 'P':
  260. pp_secs = atoi(optarg);
  261. lwsl_notice("Setting pingpong interval to %d\n", pp_secs);
  262. break;
  263. #if defined(LWS_OPENSSL_SUPPORT)
  264. case 'v':
  265. use_ssl = 1;
  266. opts |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
  267. break;
  268. #if defined(LWS_HAVE_SSL_CTX_set1_param)
  269. case 'R':
  270. strncpy(crl_path, optarg, sizeof(crl_path) - 1);
  271. crl_path[sizeof(crl_path) - 1] = '\0';
  272. break;
  273. #endif
  274. #endif
  275. case 'h':
  276. fprintf(stderr, "Usage: test-server "
  277. "[--port=<p>] [--ssl] "
  278. "[-d <log bitfield>] "
  279. "[--resource_path <path>]\n");
  280. exit(1);
  281. }
  282. }
  283. #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
  284. /*
  285. * normally lock path would be /var/lock/lwsts or similar, to
  286. * simplify getting started without having to take care about
  287. * permissions or running as root, set to /tmp/.lwsts-lock
  288. */
  289. if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
  290. fprintf(stderr, "Failed to daemonize\n");
  291. return 10;
  292. }
  293. #endif
  294. signal(SIGINT, sighandler);
  295. #ifndef _WIN32
  296. /* we will only try to log things according to our debug_level */
  297. setlogmask(LOG_UPTO (LOG_DEBUG));
  298. openlog("lwsts", syslog_options, LOG_DAEMON);
  299. #endif
  300. /* tell the library what debug level to emit and to send it to syslog */
  301. lws_set_log_level(debug_level, lwsl_emit_syslog);
  302. lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n");
  303. lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
  304. printf("Using resource path \"%s\"\n", resource_path);
  305. #ifdef EXTERNAL_POLL
  306. max_poll_elements = getdtablesize();
  307. pollfds = malloc(max_poll_elements * sizeof (struct lws_pollfd));
  308. fd_lookup = malloc(max_poll_elements * sizeof (int));
  309. if (pollfds == NULL || fd_lookup == NULL) {
  310. lwsl_err("Out of memory pollfds=%d\n", max_poll_elements);
  311. return -1;
  312. }
  313. #endif
  314. info.iface = iface;
  315. info.protocols = protocols;
  316. info.ssl_cert_filepath = NULL;
  317. info.ssl_private_key_filepath = NULL;
  318. info.ws_ping_pong_interval = pp_secs;
  319. if (use_ssl) {
  320. if (strlen(resource_path) > sizeof(cert_path) - 32) {
  321. lwsl_err("resource path too long\n");
  322. return -1;
  323. }
  324. if (!cert_path[0])
  325. sprintf(cert_path, "%s/libwebsockets-test-server.pem",
  326. resource_path);
  327. if (strlen(resource_path) > sizeof(key_path) - 32) {
  328. lwsl_err("resource path too long\n");
  329. return -1;
  330. }
  331. if (!key_path[0])
  332. sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
  333. resource_path);
  334. info.ssl_cert_filepath = cert_path;
  335. info.ssl_private_key_filepath = key_path;
  336. if (ca_path[0])
  337. info.ssl_ca_filepath = ca_path;
  338. }
  339. info.gid = gid;
  340. info.uid = uid;
  341. info.max_http_header_pool = 16;
  342. info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8;
  343. info.extensions = exts;
  344. info.timeout_secs = 5;
  345. info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
  346. "ECDHE-RSA-AES256-GCM-SHA384:"
  347. "DHE-RSA-AES256-GCM-SHA384:"
  348. "ECDHE-RSA-AES256-SHA384:"
  349. "HIGH:!aNULL:!eNULL:!EXPORT:"
  350. "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
  351. "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
  352. "!DHE-RSA-AES128-SHA256:"
  353. "!AES128-GCM-SHA256:"
  354. "!AES128-SHA256:"
  355. "!DHE-RSA-AES256-SHA256:"
  356. "!AES256-GCM-SHA384:"
  357. "!AES256-SHA256";
  358. if (use_ssl)
  359. /* redirect guys coming on http */
  360. info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS;
  361. context = lws_create_context(&info);
  362. if (context == NULL) {
  363. lwsl_err("libwebsocket init failed\n");
  364. return -1;
  365. }
  366. /* this shows how to override the lws file operations. You don't need
  367. * to do any of this unless you have a reason (eg, want to serve
  368. * compressed files without decompressing the whole archive)
  369. */
  370. /* stash original platform fops */
  371. fops_plat = *(lws_get_fops(context));
  372. /* override the active fops */
  373. lws_get_fops(context)->open = test_server_fops_open;
  374. n = 0;
  375. #ifdef EXTERNAL_POLL
  376. int ms_1sec = 0;
  377. #endif
  378. while (n >= 0 && !force_exit) {
  379. struct timeval tv;
  380. gettimeofday(&tv, NULL);
  381. /*
  382. * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every
  383. * live websocket connection using the DUMB_INCREMENT protocol,
  384. * as soon as it can take more packets (usually immediately)
  385. */
  386. ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
  387. if ((ms - oldms) > 50) {
  388. lws_callback_on_writable_all_protocol(context,
  389. &protocols[PROTOCOL_DUMB_INCREMENT]);
  390. oldms = ms;
  391. }
  392. #ifdef EXTERNAL_POLL
  393. /*
  394. * this represents an existing server's single poll action
  395. * which also includes libwebsocket sockets
  396. */
  397. n = poll(pollfds, count_pollfds, 50);
  398. if (n < 0)
  399. continue;
  400. if (n) {
  401. for (n = 0; n < count_pollfds; n++)
  402. if (pollfds[n].revents)
  403. /*
  404. * returns immediately if the fd does not
  405. * match anything under libwebsockets
  406. * control
  407. */
  408. if (lws_service_fd(context,
  409. &pollfds[n]) < 0)
  410. goto done;
  411. /* if needed, force-service wsis that may not have read all input */
  412. while (!lws_service_adjust_timeout(context, 1, 0)) {
  413. lwsl_notice("extpoll doing forced service!\n");
  414. lws_service_tsi(context, -1, 0);
  415. }
  416. } else {
  417. /* no revents, but before polling again, make lws check for any timeouts */
  418. if (ms - ms_1sec > 1000) {
  419. lwsl_notice("1 per sec\n");
  420. lws_service_fd(context, NULL);
  421. ms_1sec = ms;
  422. }
  423. }
  424. #else
  425. /*
  426. * If libwebsockets sockets are all we care about,
  427. * you can use this api which takes care of the poll()
  428. * and looping through finding who needed service.
  429. *
  430. * If no socket needs service, it'll return anyway after
  431. * the number of ms in the second argument.
  432. */
  433. n = lws_service(context, 50);
  434. #endif
  435. }
  436. #ifdef EXTERNAL_POLL
  437. done:
  438. #endif
  439. lws_context_destroy(context);
  440. lwsl_notice("libwebsockets-test-server exited cleanly\n");
  441. #ifndef _WIN32
  442. closelog();
  443. #endif
  444. return 0;
  445. }