Newer
Older
Sergey Lyubka
committed
static int get_option_index(const char *name) {
for (i = 0; static_config_options[i * 2] != NULL; i++) {
if (strcmp(static_config_options[i * 2], name) == 0) {
return i;
}
return -1;
}
static void set_default_option_values(char **opts) {
const char *value, **all_opts = mg_get_valid_option_names();
int i;
for (i = 0; all_opts[i * 2] != NULL; i++) {
value = all_opts[i * 2 + 1];
if (opts[i] == NULL && value != NULL) {
opts[i] = mg_strdup(value);
const char *mg_set_option(struct mg_server *server, const char *name,
const char *value) {
int ind = get_option_index(name);
const char *error_msg = NULL;
Sergey Lyubka
committed
char **v = NULL;
Sergey Lyubka
committed
if (ind < 0) return "No such option";
v = &server->config_options[ind];
Sergey Lyubka
committed
// Return success immediately if setting to the same value
if ((*v == NULL && value == NULL) ||
(value != NULL && *v != NULL && !strcmp(value, *v))) {
return NULL;
}
if (*v != NULL) {
Sergey Lyubka
committed
*v = NULL;
}
if (value == NULL || value[0] == '\0') return NULL;
Sergey Lyubka
committed
*v = mg_strdup(value);
DBG(("%s [%s]", name, *v));
if (ind == LISTENING_PORT) {
while ((value = next_option(value, &vec, NULL)) != NULL) {
struct ns_connection *c = ns_bind(&server->ns_mgr, vec.ptr,
mg_ev_handler, NULL);
if (c== NULL) {
error_msg = "Cannot bind to port";
break;
} else {
char buf[100];
ns_sock_to_str(c->sock, buf, sizeof(buf), 2);
Sergey Lyubka
committed
}
server->ns_mgr.hexdump_file = *v;
#if !defined(_WIN32) && !defined(MONGOOSE_NO_USER)
Sergey Lyubka
committed
} else if (ind == RUN_AS_USER) {
struct passwd *pw;
if ((pw = getpwnam(value)) == NULL) {
error_msg = "Unknown user";
} else if (setgid(pw->pw_gid) != 0) {
error_msg = "setgid() failed";
} else if (setuid(pw->pw_uid) != 0) {
error_msg = "setuid() failed";
}
#endif
static void set_ips(struct ns_connection *nc, int is_rem) {
struct connection *conn = (struct connection *) nc->user_data;
struct mg_connection *c = &conn->mg_conn;
char buf[100];
ns_sock_to_str(nc->sock, buf, sizeof(buf), is_rem ? 7 : 3);
sscanf(buf, "%47[^:]:%hu",
is_rem ? c->remote_ip : c->local_ip,
is_rem ? &c->remote_port : &c->local_port);
//DBG(("%p %s %s", conn, is_rem ? "rem" : "loc", buf));
static void on_accept(struct ns_connection *nc, union socket_address *sa) {
struct mg_server *server = (struct mg_server *) nc->mgr;
struct connection *conn;
if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
ntohl(* (uint32_t *) &sa->sin.sin_addr)) ||
(conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
nc->flags |= NSF_CLOSE_IMMEDIATELY;
} else {
// Circularly link two connection structures
// Initialize the rest of connection attributes
conn->server = server;
conn->mg_conn.server_param = nc->mgr->user_data;
static void process_udp(struct ns_connection *nc) {
struct iobuf *io = &nc->recv_iobuf;
struct connection conn;
memset(&conn, 0, sizeof(conn));
conn.ns_conn = nc;
conn.server = (struct mg_server *) nc->mgr;
conn.request_len = parse_http_message(io->buf, io->len, &conn.mg_conn);
on_recv_data(&conn);
//ns_printf(nc, "%s", "HTTP/1.0 200 OK\r\n\r\n");
}
static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) {
struct connection *conn = (struct connection *) nc->user_data;
Sergey Lyubka
committed
// Send NS event to the handler. Note that call_user won't send an event
// if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well.
#ifdef MONGOOSE_SEND_NS_EVENTS
{
struct connection *conn = (struct connection *) nc->user_data;
void *param[2] = { nc, p };
if (conn != NULL) conn->mg_conn.callback_param = param;
Sergey Lyubka
committed
call_user(conn, (enum mg_event) ev);
}
#endif
switch (ev) {
case NS_ACCEPT:
on_accept(nc, (union socket_address *) p);
Sergey Lyubka
committed
#ifdef MONGOOSE_SEND_NS_EVENTS
{
struct connection *conn = (struct connection *) nc->user_data;
void *param[2] = { nc, p };
if (conn != NULL) conn->mg_conn.callback_param = param;
Sergey Lyubka
committed
call_user(conn, (enum mg_event) ev);
}
#endif
conn->mg_conn.status_code = * (int *) p;
if (conn->mg_conn.status_code != 0 ||
(!(nc->flags & MG_PROXY_CONN) &&
call_user(conn, MG_CONNECT) == MG_FALSE)) {
if (conn != NULL) {
conn->num_bytes_recv += * (int *) p;
}
if (nc->flags & NSF_UDP) {
process_udp(nc);
} else if (nc->listener != NULL) {
#ifndef MONGOOSE_NO_CGI
} else if (nc->flags & MG_CGI_CONN) {
on_cgi_data(nc);
} else if (nc->flags & MG_PROXY_CONN) {
if (conn != NULL) {
ns_forward(nc, conn->ns_conn);
}
} else {
process_response(conn);
}
break;
case NS_SEND:
break;
case NS_CLOSE:
if (nc->flags & (MG_CGI_CONN | MG_PROXY_CONN)) {
DBG(("%p %p closing cgi/proxy conn", conn, nc));
if (conn && conn->ns_conn) {
conn->ns_conn->flags &= ~NSF_BUFFER_BUT_DONT_SEND;
conn->ns_conn->flags |= conn->ns_conn->send_iobuf.len > 0 ?
NSF_FINISHED_SENDING_DATA : NSF_CLOSE_IMMEDIATELY;
conn->endpoint.nc = NULL;
}
DBG(("%p %p %d closing", conn, nc, conn->endpoint_type));
if (conn->endpoint_type == EP_CLIENT && nc->recv_iobuf.len > 0) {
call_user(conn, MG_CLOSE);
if (conn != NULL) {
if (call_user(conn, MG_POLL) == MG_TRUE) {
if (conn->ns_conn->flags & MG_HEADERS_SENT) {
write_terminating_chunk(conn);
}
close_local_endpoint(conn);
if (conn->endpoint_type == EP_FILE) {
transfer_file_data(conn);
}
}
// Expire idle connections
{
time_t current_time = * (time_t *) p;
if (conn != NULL && conn->mg_conn.is_websocket) {
ping_idle_websocket_connection(conn, current_time);
}
nc->last_io_time + MONGOOSE_IDLE_TIMEOUT_SECONDS < current_time) {
mg_ev_handler(nc, NS_CLOSE, NULL);
nc->flags |= NSF_CLOSE_IMMEDIATELY;
}
}
break;
default:
break;
}
}
static void iter2(struct ns_connection *nc, int ev, void *param) {
struct connection *conn = (struct connection *) nc->user_data;
const char *msg = (const char *) param;
int n;
(void) ev;
if (sscanf(msg, "%p %n", &func, &n) && func != NULL && conn != NULL) {
conn->mg_conn.callback_param = (void *) (msg + n);
func(&conn->mg_conn, MG_POLL);
}
}
void mg_wakeup_server_ex(struct mg_server *server, mg_handler_t cb,
const char *fmt, ...) {
va_list ap;
char buf[8 * 1024];
int len;
// Encode callback (cb) into a buffer
len = snprintf(buf, sizeof(buf), "%p ", cb);
va_start(ap, fmt);
len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
va_end(ap);
// "len + 1" is to include terminating \0 in the message
ns_broadcast(&server->ns_mgr, iter2, buf, len + 1);
void mg_wakeup_server(struct mg_server *server) {
ns_broadcast(&server->ns_mgr, NULL, (void *) "", 0);
const char *mg_get_option(const struct mg_server *server, const char *name) {
const char **opts = (const char **) server->config_options;
int i = get_option_index(name);
return i == -1 ? NULL : opts[i] == NULL ? "" : opts[i];
}
struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
struct mg_server *server = (struct mg_server *) NS_CALLOC(1, sizeof(*server));
ns_mgr_init(&server->ns_mgr, server_data);
set_default_option_values(server->config_options);
server->event_handler = handler;