int main(int argc, char **argv) { struct lws_context_creation_info info; struct lws_vhost *vhost; char interface_name[128] = ""; unsigned int ms, oldms = 0; const char *iface = NULL; char cert_path[1024] = ""; char key_path[1024] = ""; char ca_path[1024] = ""; int uid = -1, gid = -1; int use_ssl = 0; int pp_secs = 0; int opts = 0; int n = 0; #ifndef _WIN32 /* LOG_PERROR is not POSIX standard, and may not be portable */ #ifdef __sun int syslog_options = LOG_PID; #else int syslog_options = LOG_PID | LOG_PERROR; #endif #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; while (n >= 0) { n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:k", options, NULL); if (n < 0) continue; switch (n) { case 'e': opts |= LWS_SERVER_OPTION_LIBEV; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #if !defined(_WIN32) && !defined(__sun) syslog_options &= ~LOG_PERROR; #endif break; #endif case 'u': uid = atoi(optarg); break; case 'g': gid = atoi(optarg); break; case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; break; case 'a': opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; break; case 'p': info.port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'k': info.bind_iface = 1; #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) info.caps[0] = CAP_NET_RAW; info.count_caps = 1; #endif break; case 'c': close_testing = 1; fprintf(stderr, " Close testing mode -- closes on " "client after 50 dumb increments" "and suppresses lws_mirror spam\n"); break; case 'r': resource_path = optarg; printf("Setting resource path to \"%s\"\n", resource_path); break; case 'C': strncpy(cert_path, optarg, sizeof(cert_path) - 1); cert_path[sizeof(cert_path) - 1] = '\0'; break; case 'K': strncpy(key_path, optarg, sizeof(key_path) - 1); key_path[sizeof(key_path) - 1] = '\0'; break; case 'A': strncpy(ca_path, optarg, sizeof(ca_path) - 1); ca_path[sizeof(ca_path) - 1] = '\0'; break; case 'P': pp_secs = atoi(optarg); lwsl_notice("Setting pingpong interval to %d\n", pp_secs); break; #if defined(LWS_OPENSSL_SUPPORT) case 'v': use_ssl = 1; opts |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT; break; #if defined(LWS_HAVE_SSL_CTX_set1_param) case 'R': strncpy(crl_path, optarg, sizeof(crl_path) - 1); crl_path[sizeof(crl_path) - 1] = '\0'; break; #endif #endif case 'h': fprintf(stderr, "Usage: test-server " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--resource_path <path>]\n"); exit(1); } } #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 10; } #endif signal(SIGINT, sighandler); #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO(LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <*****@*****.**>\n"); printf("Using resource path \"%s\"\n", resource_path); #ifdef EXTERNAL_POLL max_poll_elements = getdtablesize(); pollfds = malloc(max_poll_elements * sizeof(struct lws_pollfd)); fd_lookup = malloc(max_poll_elements * sizeof(int)); if (pollfds == NULL || fd_lookup == NULL) { lwsl_err("Out of memory pollfds=%d\n", max_poll_elements); return -1; } #endif info.iface = iface; info.protocols = protocols; info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; info.ws_ping_pong_interval = pp_secs; if (use_ssl) { if (strlen(resource_path) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } if (!cert_path[0]) sprintf(cert_path, "%s/libwebsockets-test-server.pem", resource_path); if (strlen(resource_path) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } if (!key_path[0]) sprintf(key_path, "%s/libwebsockets-test-server.key.pem", resource_path); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; if (ca_path[0]) info.ssl_ca_filepath = ca_path; } info.gid = gid; info.uid = uid; info.max_http_header_pool = 16; info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_EXPLICIT_VHOSTS | LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.extensions = exts; info.timeout_secs = 5; info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-GCM-SHA384:" "DHE-RSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-SHA384:" "HIGH:!aNULL:!eNULL:!EXPORT:" "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:" "!SHA1:!DHE-RSA-AES128-GCM-SHA256:" "!DHE-RSA-AES128-SHA256:" "!AES128-GCM-SHA256:" "!AES128-SHA256:" "!DHE-RSA-AES256-SHA256:" "!AES256-GCM-SHA384:" "!AES256-SHA256"; if (use_ssl) /* redirect guys coming on http */ info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS; printf("options:%x\r\n", info.options); printf("before create\n"); context = lws_create_context(&info); printf("end create\n"); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } printf("111111\r\n"); vhost = lws_create_vhost(context, &info); if (!vhost) { lwsl_err("vhost creation failed\n"); return -1; } printf("222222\r\n"); #if !defined(LWS_NO_CLIENT) && defined(LWS_OPENSSL_SUPPORT) lws_init_vhost_client_ssl(&info, vhost); #endif /* this shows how to override the lws file operations. You don't need * to do any of this unless you have a reason (eg, want to serve * compressed files without decompressing the whole archive) */ /* stash original platform fops */ fops_plat = *(lws_get_fops(context)); /* override the active fops */ lws_get_fops(context)->open = test_server_fops_open; n = 0; #ifdef EXTERNAL_POLL int ms_1sec = 0; #endif while (n >= 0 && !force_exit) { struct timeval tv; gettimeofday(&tv, NULL); /* * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every * live websocket connection using the DUMB_INCREMENT protocol, * as soon as it can take more packets (usually immediately) */ ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); if ((ms - oldms) > 1) { lws_callback_on_writable_all_protocol(context, &protocols [PROTOCOL_DUMB_INCREMENT]); oldms = ms; } lws_callback_on_writable_all_protocol(context, &protocols [PROTOCOL_FILE_SERVER_SEND]); #ifdef EXTERNAL_POLL /* * this represents an existing server's single poll action * which also includes libwebsocket sockets */ n = poll(pollfds, count_pollfds, 50); if (n < 0) continue; if (n) { for (n = 0; n < count_pollfds; n++) if (pollfds[n].revents) /* * returns immediately if the fd does not * match anything under libwebsockets * control */ if (lws_service_fd(context, &pollfds[n]) < 0) goto done; /* if needed, force-service wsis that may not have read all input */ while (!lws_service_adjust_timeout(context, 1, 0)) { lwsl_notice("extpoll doing forced service!\n"); lws_service_tsi(context, -1, 0); } } else { /* no revents, but before polling again, make lws check for any timeouts */ if (ms - ms_1sec > 1000) { lwsl_notice("1 per sec\n"); lws_service_fd(context, NULL); ms_1sec = ms; } } #else /* * If libwebsockets sockets are all we care about, * you can use this api which takes care of the poll() * and looping through finding who needed service. * * If no socket needs service, it'll return anyway after * the number of ms in the second argument. */ n = lws_service(context, 5); #endif } #ifdef EXTERNAL_POLL done: #endif lws_context_destroy(context); lwsl_notice("libwebsockets-test-server exited cleanly\n"); #ifndef _WIN32 closelog(); #endif return 0; }
static char lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) { struct jpargs *a = (struct jpargs *)ctx->user; struct lws_protocol_vhost_options *pvo, *mp_cgienv; struct lws_http_mount *m; char *p, *p1; int n; #if 0 lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match); for (n = 0; n < ctx->wildcount; n++) lwsl_notice(" %d\n", ctx->wild[n]); #endif if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) { /* set the defaults for this vhost */ a->valid = 1; a->head = NULL; a->last = NULL; a->info->port = 0; a->info->iface = NULL; a->info->protocols = a->protocols; a->info->extensions = a->extensions; a->info->ssl_cert_filepath = NULL; a->info->ssl_private_key_filepath = NULL; a->info->ssl_ca_filepath = NULL; a->info->timeout_secs = 5; a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-GCM-SHA384:" "DHE-RSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-SHA384:" "HIGH:!aNULL:!eNULL:!EXPORT:" "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:" "!SHA1:!DHE-RSA-AES128-GCM-SHA256:" "!DHE-RSA-AES128-SHA256:" "!AES128-GCM-SHA256:" "!AES128-SHA256:" "!DHE-RSA-AES256-SHA256:" "!AES256-GCM-SHA384:" "!AES256-SHA256"; a->info->pvo = NULL; a->info->keepalive_timeout = 60; a->info->log_filepath = NULL; a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK | LWS_SERVER_OPTION_STS); a->enable_client_ssl = 0; } if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP_MOUNTS + 1) { a->fresh_mount = 1; memset(&a->m, 0, sizeof(a->m)); } /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */ if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) { a->pvo = lwsws_align(a); a->p += sizeof(*a->pvo); n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p); /* ie, enable this protocol, no options yet */ a->pvo->next = a->info->pvo; a->info->pvo = a->pvo; a->pvo->name = a->p; lwsl_notice(" adding protocol %s\n", a->p); a->p += n; a->pvo->value = a->p; a->pvo->options = NULL; goto dostring; } if (reason == LEJPCB_OBJECT_END && (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) && a->valid) { struct lws_vhost *vhost; //lwsl_notice("%s\n", ctx->path); if (!a->info->port) { lwsl_err("Port required (eg, 443)"); return 1; } a->valid = 0; a->info->mounts = a->head; vhost = lws_create_vhost(a->context, a->info); if (!vhost) { lwsl_err("Failed to create vhost %s\n", a->info->vhost_name); return 1; } a->any_vhosts = 1; if (a->enable_client_ssl) { memset(a->info, 0, sizeof(*a->info)); a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; lws_init_vhost_client_ssl(a->info, vhost); } return 0; } if (reason == LEJPCB_OBJECT_END && ctx->path_match == LEJPVP_MOUNTS + 1) { static const char * const mount_protocols[] = { "http://", "https://", "file://", "cgi://", ">http://", ">https://", "callback://" }; if (!a->fresh_mount) return 0; if (!a->m.mountpoint || !a->m.origin) { lwsl_err("mountpoint and origin required\n"); return 1; } lwsl_debug("adding mount %s\n", a->m.mountpoint); m = lwsws_align(a); memcpy(m, &a->m, sizeof(*m)); if (a->last) a->last->mount_next = m; for (n = 0; n < ARRAY_SIZE(mount_protocols); n++) if (!strncmp(a->m.origin, mount_protocols[n], strlen(mount_protocols[n]))) { lwsl_err("----%s\n", a->m.origin); m->origin_protocol = n; m->origin = a->m.origin + strlen(mount_protocols[n]); break; } if (n == ARRAY_SIZE(mount_protocols)) { lwsl_err("unsupported protocol:// %s\n", a->m.origin); return 1; } a->p += sizeof(*m); if (!a->head) a->head = m; a->last = m; a->fresh_mount = 0; } /* we only match on the prepared path strings */ if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match) return 0; switch (ctx->path_match - 1) { case LEJPVP_NAME: a->info->vhost_name = a->p; break; case LEJPVP_PORT: a->info->port = atoi(ctx->buf); return 0; case LEJPVP_INTERFACE: a->info->iface = a->p; break; case LEJPVP_UNIXSKT: if (arg_to_bool(ctx->buf)) a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK; else a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK); return 0; case LEJPVP_STS: if (arg_to_bool(ctx->buf)) a->info->options |= LWS_SERVER_OPTION_STS; else a->info->options &= ~(LWS_SERVER_OPTION_STS); return 0; case LEJPVP_HOST_SSL_KEY: a->info->ssl_private_key_filepath = a->p; break; case LEJPVP_HOST_SSL_CERT: a->info->ssl_cert_filepath = a->p; break; case LEJPVP_HOST_SSL_CA: a->info->ssl_ca_filepath = a->p; break; case LEJPVP_ACCESS_LOG: a->info->log_filepath = a->p; break; case LEJPVP_MOUNTPOINT: a->m.mountpoint = a->p; a->m.mountpoint_len = (unsigned char)strlen(ctx->buf); break; case LEJPVP_ORIGIN: if (!strncmp(ctx->buf, "callback://", 11)) a->m.protocol = a->p + 11; if (!a->m.origin) a->m.origin = a->p; break; case LEJPVP_DEFAULT: a->m.def = a->p; break; case LEJPVP_DEFAULT_AUTH_MASK: a->m.auth_mask = atoi(ctx->buf); return 0; case LEJPVP_MOUNT_CACHE_MAX_AGE: a->m.cache_max_age = atoi(ctx->buf); return 0; case LEJPVP_MOUNT_CACHE_REUSE: a->m.cache_reusable = arg_to_bool(ctx->buf); return 0; case LEJPVP_MOUNT_CACHE_REVALIDATE: a->m.cache_revalidate = arg_to_bool(ctx->buf); return 0; case LEJPVP_MOUNT_CACHE_INTERMEDIARIES: a->m.cache_intermediaries = arg_to_bool(ctx->buf);; return 0; case LEJPVP_CGI_TIMEOUT: a->m.cgi_timeout = atoi(ctx->buf); return 0; case LEJPVP_KEEPALIVE_TIMEOUT: a->info->keepalive_timeout = atoi(ctx->buf); return 0; case LEJPVP_CIPHERS: a->info->ssl_cipher_list = a->p; break; case LEJPVP_ECDH_CURVE: a->info->ecdh_curve = a->p; break; case LEJPVP_PMO: case LEJPVP_CGI_ENV: mp_cgienv = lwsws_align(a); a->p += sizeof(*a->m.cgienv); mp_cgienv->next = a->m.cgienv; a->m.cgienv = mp_cgienv; n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p); mp_cgienv->name = a->p; a->p += n; mp_cgienv->value = a->p; mp_cgienv->options = NULL; lwsl_notice(" adding pmo / cgi-env '%s' = '%s'\n", mp_cgienv->name, mp_cgienv->value); goto dostring; case LEJPVP_PROTOCOL_NAME_OPT: /* this catches, eg, * vhosts[].ws-protocols[].xxx-protocol.yyy-option * ie, these are options attached to a protocol with { } */ pvo = lwsws_align(a); a->p += sizeof(*a->pvo); n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p); /* ie, enable this protocol, no options yet */ pvo->next = a->pvo->options; a->pvo->options = pvo; pvo->name = a->p; a->p += n; pvo->value = a->p; pvo->options = NULL; break; case LEJPVP_MOUNT_EXTRA_MIMETYPES: a->pvo_em = lwsws_align(a); a->p += sizeof(*a->pvo_em); n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p); /* ie, enable this protocol, no options yet */ a->pvo_em->next = a->m.extra_mimetypes; a->m.extra_mimetypes = a->pvo_em; a->pvo_em->name = a->p; lwsl_notice(" adding extra-mimetypes %s -> %s\n", a->p, ctx->buf); a->p += n; a->pvo_em->value = a->p; a->pvo_em->options = NULL; break; case LEJPVP_MOUNT_INTERPRET: a->pvo_int = lwsws_align(a); a->p += sizeof(*a->pvo_int); n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p); /* ie, enable this protocol, no options yet */ a->pvo_int->next = a->m.interpret; a->m.interpret = a->pvo_int; a->pvo_int->name = a->p; lwsl_notice(" adding interpret %s -> %s\n", a->p, ctx->buf); a->p += n; a->pvo_int->value = a->p; a->pvo_int->options = NULL; break; case LEJPVP_ENABLE_CLIENT_SSL: a->enable_client_ssl = arg_to_bool(ctx->buf); return 0; case LEJPVP_NOIPV6: if (arg_to_bool(ctx->buf)) a->info->options |= LWS_SERVER_OPTION_DISABLE_IPV6; else a->info->options &= ~(LWS_SERVER_OPTION_DISABLE_IPV6); return 0; case LEJPVP_IPV6ONLY: a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY; if (arg_to_bool(ctx->buf)) a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE; else a->info->options &= ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE); return 0; case LEJPVP_SSL_OPTION_SET: a->info->ssl_options_set |= atol(ctx->buf); return 0; case LEJPVP_SSL_OPTION_CLEAR: a->info->ssl_options_clear |= atol(ctx->buf); return 0; default: return 0; } dostring: p = ctx->buf; p1 = strstr(p, ESC_INSTALL_DATADIR); if (p1) { n = p1 - p; if (n > a->end - a->p) n = a->end - a->p; strncpy(a->p, p, n); a->p += n; a->p += snprintf(a->p, a->end - a->p, "%s", LWS_INSTALL_DATADIR); p += n + strlen(ESC_INSTALL_DATADIR); } a->p += snprintf(a->p, a->end - a->p, "%s", p); *(a->p)++ = '\0'; return 0; }