server/server-main.c
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <syslog.h>
#include <unistd.h>
#include <libwebsockets.h>
#include "proto.h"
#include "proto-jittertrap.h"
#define xstr(s) str(s)
#define str(s) #s
char *resource_path = xstr(WEB_SERVER_DOCUMENT_ROOT);
static volatile int force_exit = 0;
static struct lws_context *context;
/* list of supported protocols and callbacks */
static struct lws_protocols protocols[] = {
/* first protocol must always be HTTP handler */
[PROTOCOL_HTTP] =
{
.name = "http-only",
.callback = lws_callback_http_dummy
},
[PROTOCOL_JITTERTRAP] =
{
.name = "jittertrap",
.callback = callback_jittertrap,
.per_session_data_size =
sizeof(struct per_session_data__jittertrap),
.rx_buffer_size = 0,
.tx_packet_size = 4000,
},
/* terminator */
[PROTOCOL_TERMINATOR] = {.name = NULL,
.callback = NULL,
.per_session_data_size = 0,
.rx_buffer_size = 0 }
};
void sighandler(int sig __attribute__((unused)))
{
force_exit = 1;
lws_cancel_service(context);
}
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "debug", required_argument, NULL, '1' },
{ "port", required_argument, NULL, 'p' },
{ "interface", required_argument, NULL, 'i' },
#ifndef LWS_NO_DAEMONIZE
{ "daemonize", no_argument, NULL, 'D' },
#endif
{ "resource_path", required_argument, NULL, 'r' },
{ NULL, 0, 0, 0 }
};
static struct lws_http_mount mount = {
.mount_next = NULL, /* linked-list "next" */
.mountpoint = "/", /* mountpoint URL */
.origin = "./mount-origin", /* serve from dir */
.def = "index.html", /* default filename */
.protocol = NULL,
.cgienv = NULL,
.extra_mimetypes = NULL,
.interpret = NULL,
.cgi_timeout = 0,
.cache_max_age = 0,
.auth_mask = 0,
.cache_reusable = 0,
.cache_revalidate = 0,
.cache_intermediaries = 0,
.origin_protocol = LWSMPRO_FILE, /* files in a dir */
.mountpoint_len = 1, /* char count */
.basic_auth_login_file = NULL
};
int main(int argc, char **argv)
{
int n = 0;
int opts = 0;
char interface_name[128] = "";
const char *iface = NULL;
int syslog_options = LOG_PID | LOG_PERROR;
struct lws_context_creation_info info;
int debug_level = LOG_WARNING;
#ifndef LWS_NO_DAEMONIZE
int daemonize = 0;
#endif
memset(&info, 0, sizeof info);
info.port = WEB_SERVER_PORT;
while (n >= 0) {
n = getopt_long(argc, argv, "ci:hsp:dDr:", options, NULL);
if (n < 0)
continue;
switch (n) {
#ifndef LWS_NO_DAEMONIZE
case 'D':
daemonize = 1;
syslog_options &= ~LOG_PERROR;
break;
#endif
/* opt that wont be a short opt either - for long --debug */
case '1':
debug_level = atoi(optarg);
debug_level =
(debug_level > LOG_DEBUG) ? LOG_DEBUG : debug_level;
debug_level =
(debug_level < LOG_EMERG) ? LOG_DEBUG : debug_level;
break;
case 'd':
debug_level = LOG_DEBUG;
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 'r':
resource_path = optarg;
mount.origin = resource_path;
break;
case 'h':
fprintf(stderr,
"Usage: " PROGNAME "[--port=<p>] "
"[-d <log level>]"
"[--resource_path <path>]\n");
exit(1);
}
}
#if !defined(LWS_NO_DAEMONIZE)
/*
* 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 1;
}
#endif
signal(SIGINT, sighandler);
/* we will only try to log things according to our debug_level */
setlogmask(LOG_UPTO(debug_level));
openlog("jt-server", syslog_options, LOG_DAEMON);
/* tell the library what debug level to emit and to send it to syslog */
lws_set_log_level(LOG_UPTO(debug_level), lwsl_emit_syslog);
syslog(LOG_NOTICE, "jittertrap server\n");
syslog(LOG_INFO, "Using resource path \"%s\"\n", resource_path);
info.iface = iface;
info.protocols = protocols;
info.mounts = &mount;
info.gid = -1;
info.uid = -1;
info.options = opts;
context = lws_create_context(&info);
if (context == NULL) {
syslog(LOG_ERR, "libwebsocket init failed\n");
return -1;
}
n = 0;
while (n >= 0 && !force_exit) {
lws_callback_on_writable_all_protocol(
context, &protocols[PROTOCOL_JITTERTRAP]);
/*
* FIXME:
* The lws_service() timeout doesn't seem to work as expected.
* This helps slow things down, but it's not a proper solution.
*/
const struct timespec rqtp = {.tv_sec = 0, .tv_nsec = 5E5 };
nanosleep(&rqtp, NULL);
n = lws_service(context, 1);
}
lws_context_destroy(context);
syslog(LOG_INFO, "jittertrap server exited cleanly\n");
closelog();
return 0;
}