From 8a65611a8cd35e8148ac63a977460c7c6a511f3d Mon Sep 17 00:00:00 2001 From: Sergey Lyubka <valenok@gmail.com> Date: Mon, 2 Dec 2013 22:22:22 +0000 Subject: [PATCH] Using core.h and modified API --- build/src/core.c | 281 ++++++++++++++++++++++++++++++++--------------- build/src/core.h | 89 +++++++++++++++ 2 files changed, 279 insertions(+), 91 deletions(-) create mode 100644 build/src/core.h diff --git a/build/src/core.c b/build/src/core.c index dd929c18a..2dc75333a 100644 --- a/build/src/core.c +++ b/build/src/core.c @@ -69,6 +69,7 @@ typedef CRITICAL_SECTION mutex_t; #define mutex_lock(x) EnterCriticalSection(x) #define mutex_unlock(x) LeaveCriticalSection(x) #define S_ISDIR(x) ((x) & _S_IFDIR) +#define sleep(x) Sleep((x) * 1000) #ifndef va_copy #define va_copy(x,y) x = y #endif // MINGW #defines va_copy @@ -93,7 +94,8 @@ typedef pthread_mutex_t mutex_t; #define INT64_FMT PRId64 #endif -#include "mongoose.h" +//#include "mongoose.h" +#include "core.h" struct linked_list_link { struct linked_list_link *prev, *next; }; #define LINKED_LIST_INIT(N) ((N)->next = (N)->prev = (N)) @@ -139,6 +141,12 @@ struct vec { int len; }; +struct uri_handler { + struct linked_list_link link; + char *uri; + mg_uri_handler_t handler; +}; + // NOTE(lsm): this enum shoulds be in sync with the config_options. enum { ACCESS_CONTROL_LIST, ACCESS_LOG_FILE, AUTH_DOMAIN, CGI_INTERPRETER, @@ -152,9 +160,9 @@ struct mg_server { sock_t listening_sock; union socket_address lsa; // Listening socket address struct linked_list_link active_connections; + struct linked_list_link uri_handlers; char *config_options[NUM_OPTIONS]; - mg_event_handler_t event_handler; - void *user_data; + void *server_data; sock_t ctl[2]; // Control socketpair. Used to wake up from select() call }; @@ -170,13 +178,13 @@ union endpoint { void *ssl; // SSL descriptor }; -enum endpoint_type { EP_NONE, EP_FILE, EP_DIR, EP_CGI, EP_SSL }; +enum endpoint_type { EP_NONE, EP_FILE, EP_DIR, EP_CGI, EP_SSL, EP_USER }; enum connection_flags { CONN_CLOSE = 1, CONN_SPOOL_DONE = 2 }; -struct mg_connection { +struct connection { + struct mg_connection mg_conn; // XXX: Must be first struct linked_list_link link; // Linkage to server->active_connections struct mg_server *server; - struct mg_event event; // NOTE(lsm): this has conn_data attribute sock_t client_sock; // Connected client union socket_address csa; // Client's socket address struct iobuf local_iobuf; @@ -184,7 +192,6 @@ struct mg_connection { union endpoint endpoint; enum endpoint_type endpoint_type; time_t expire_time; - struct mg_request_info request_info; char *path_info; int request_len; int flags; @@ -206,7 +213,7 @@ static const char *static_config_options[] = { "hide_files_patterns", NULL, "idle_timeout_ms", "30000", "index_files","index.html,index.htm,index.cgi,index.shtml,index.php,index.lp", - "listening_port", "8080", + "listening_port", NULL, "num_threads", "50", "put_delete_auth_file", NULL, "run_as_user", NULL, @@ -287,13 +294,13 @@ static int get_option_index(const char *name) { return -1; } -const char *mg_get_option2(const struct mg_server *srv, const char *name) { +const char *mg_get_option(const struct mg_server *srv, const char *name) { int i = get_option_index(name); return i == -1 ? NULL : srv->config_options[i] == NULL ? "" : srv->config_options[i]; } -int mg_start_thread(mg_thread_func_t f, void *p) { +int mg_start_thread(void *(*f)(void *), void *p) { #ifdef _WIN32 return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0; #else @@ -316,6 +323,7 @@ int mg_start_thread(mg_thread_func_t f, void *p) { #endif } +#if 0 static int call_user(int event_type, struct mg_connection *conn, void *p) { if (conn != NULL && conn->server != NULL) { conn->event.user_data = conn->server->user_data; @@ -327,6 +335,7 @@ static int call_user(int event_type, struct mg_connection *conn, void *p) { return !conn || !conn->server || !conn->server->event_handler ? 0 : conn->server->event_handler(&conn->event); } +#endif static void set_close_on_exec(int fd) { #ifdef _WIN32 @@ -547,11 +556,11 @@ static int check_acl(const char *acl, uint32_t remote_ip) { return allowed == '+'; } -static struct mg_connection *accept_new_connection(struct mg_server *server) { +static struct connection *accept_new_connection(struct mg_server *server) { union socket_address sa; socklen_t len = sizeof(sa); sock_t sock = INVALID_SOCKET; - struct mg_connection *conn = NULL; + struct connection *conn = NULL; if ((sock = accept(server->listening_sock, &sa.sa, &len)) == INVALID_SOCKET) { #if 0 @@ -562,7 +571,7 @@ static struct mg_connection *accept_new_connection(struct mg_server *server) { } else if (!check_acl(server->config_options[ACCESS_CONTROL_LIST], ntohl(* (uint32_t *) &sa.sin.sin_addr))) { closesocket(sock); - } else if ((conn = (struct mg_connection *) + } else if ((conn = (struct connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) { closesocket(sock); } else { @@ -584,7 +593,7 @@ static struct mg_connection *accept_new_connection(struct mg_server *server) { return conn; } -static void close_conn(struct mg_connection *conn) { +static void close_conn(struct connection *conn) { DBG(("closing %p", conn)); LINKED_LIST_REMOVE(&conn->link); closesocket(conn->client_sock); @@ -638,7 +647,7 @@ static char *skip(char **buf, const char *delimiters) { // Parse HTTP headers from the given buffer, advance buffer to the point // where parsing stopped. -static void parse_http_headers(char **buf, struct mg_request_info *ri) { +static void parse_http_headers(char **buf, struct mg_connection *ri) { size_t i; for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) { @@ -658,16 +667,15 @@ static int is_valid_http_method(const char *method) { || !strcmp(method, "MKCOL"); } -// Parse HTTP request, fill in mg_request_info structure. +// Parse HTTP request, fill in mg_request structure. // This function modifies the buffer by NUL-terminating // HTTP request components, header names and header values. -static int parse_http_message(char *buf, int len, struct mg_request_info *ri) { +static int parse_http_message(char *buf, int len, struct mg_connection *ri) { int is_request, request_len = get_request_len((unsigned char *) buf, len); if (request_len > 0) { // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port - ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL; + ri->request_method = ri->uri = ri->http_version = NULL; ri->num_headers = 0; - buf[request_len - 1] = '\0'; // RFC says that all initial whitespaces should be ingored @@ -804,7 +812,7 @@ int mg_url_decode(const char *src, int src_len, char *dst, } // Return HTTP header value, or NULL if not found. -static const char *get_header(const struct mg_request_info *ri, const char *s) { +const char *mg_get_header(const struct mg_connection *ri, const char *s) { int i; for (i = 0; i < ri->num_headers; i++) @@ -814,18 +822,14 @@ static const char *get_header(const struct mg_request_info *ri, const char *s) { return NULL; } -const char *mg_get_header(const struct mg_connection *conn, const char *name) { - return get_header(&conn->request_info, name); -} - // Return 1 if real file has been found, 0 otherwise -static int convert_uri_to_file_name(struct mg_connection *conn, char *buf, +static int convert_uri_to_file_name(struct connection *conn, char *buf, size_t buf_len, struct stat *st) { struct vec a, b; const char *rewrites = conn->server->config_options[URL_REWRITES], *root = conn->server->config_options[DOCUMENT_ROOT], *cgi_pat = conn->server->config_options[CGI_PATTERN], - *uri = conn->request_info.uri; + *uri = conn->mg_conn.uri; char *p; int match_len; @@ -896,7 +900,8 @@ static int vspool(struct iobuf *io, const char *fmt, va_list ap) { return len; } -int mg_printf(struct mg_connection *conn, const char *fmt, ...) { +int mg_printf(struct mg_connection *c, const char *fmt, ...) { + struct connection *conn = (struct connection *) c; va_list ap; int ret; va_start(ap, fmt); @@ -908,7 +913,8 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...) { return ret; } -int mg_write(struct mg_connection *conn, const void *buf, int len) { +int mg_write(struct mg_connection *c, const void *buf, int len) { + struct connection *conn = (struct connection *) c; int ret; mutex_lock(&conn->mutex); ret = spool(&conn->remote_iobuf, buf, len); @@ -921,7 +927,7 @@ static int is_error(int n) { return n == 0 || (n < 0 && errno != EINTR && errno != EAGAIN); } -static void write_to_client(struct mg_connection *conn) { +static void write_to_client(struct connection *conn) { struct iobuf *io = &conn->remote_iobuf; int n = send(conn->client_sock, io->buf, io->len, 0); @@ -938,7 +944,7 @@ static void write_to_client(struct mg_connection *conn) { } } -const char *mg_get_builtin_mime_type(const char *path) { +const char *mg_get_mime_type(const char *path) { const char *ext; size_t i, path_len; @@ -977,7 +983,7 @@ static void get_mime_type(const struct mg_server *server, const char *path, } } - vec->ptr = mg_get_builtin_mime_type(path); + vec->ptr = mg_get_mime_type(path); vec->len = strlen(vec->ptr); } @@ -994,7 +1000,7 @@ static void construct_etag(char *buf, size_t buf_len, const struct stat *st) { (unsigned long) st->st_mtime, (int64_t) st->st_size); } -static void open_file_endpoint(struct mg_connection *conn, const char *path, +static void open_file_endpoint(struct connection *conn, const char *path, struct stat *st) { char date[64], lm[64], etag[64], range[64]; const char *msg = "OK", *hdr; @@ -1013,7 +1019,7 @@ static void open_file_endpoint(struct mg_connection *conn, const char *path, // If Range: header specified, act accordingly r1 = r2 = 0; - hdr = mg_get_header(conn, "Range"); + hdr = mg_get_header(&conn->mg_conn, "Range"); if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && r1 >= 0 && r2 >= 0) { conn->status_code = 206; @@ -1031,7 +1037,7 @@ static void open_file_endpoint(struct mg_connection *conn, const char *path, gmt_time_string(lm, sizeof(lm), &st->st_mtime); construct_etag(etag, sizeof(etag), st); - mg_printf(conn, + mg_printf(&conn->mg_conn, "HTTP/1.1 %d %s\r\n" "Date: %s\r\n" "Last-Modified: %s\r\n" @@ -1044,46 +1050,67 @@ static void open_file_endpoint(struct mg_connection *conn, const char *path, conn->status_code, msg, date, lm, etag, (int) mime_vec.len, mime_vec.ptr, cl, "keep-alive", range, EXTRA_HTTP_HEADERS); - if (!strcmp(conn->request_info.request_method, "HEAD")) { + if (!strcmp(conn->mg_conn.request_method, "HEAD")) { lseek(conn->endpoint.fd, 0, SEEK_END); } } -static void open_local_endpoint(struct mg_connection *conn) { - struct mg_request_info *ri = &conn->request_info; +static struct uri_handler *find_uri_handler(struct mg_server *server, + const char *uri) { + struct linked_list_link *lp, *tmp; + struct uri_handler *uh; + + LINKED_LIST_FOREACH(&server->uri_handlers, lp, tmp) { + uh = LINKED_LIST_ENTRY(lp, struct uri_handler, link); + if (!strcmp(uh->uri, uri)) return uh; + } + + return NULL; +} + +static void open_local_endpoint(struct connection *conn) { char path[MAX_PATH_SIZE] = {'\0'}; struct stat st; int uri_len, exists = 0, is_directory = 0; + struct uri_handler *uh; - if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) { - * ((char *) conn->request_info.query_string++) = '\0'; + if ((conn->mg_conn.query_string = strchr(conn->mg_conn.uri, '?')) != NULL) { + * ((char *) conn->mg_conn.query_string++) = '\0'; } - uri_len = (int) strlen(ri->uri); - mg_url_decode(ri->uri, uri_len, (char *) ri->uri, uri_len + 1, 0); - remove_double_dots_and_double_slashes((char *) ri->uri); + uri_len = (int) strlen(conn->mg_conn.uri); + mg_url_decode(conn->mg_conn.uri, uri_len, (char *) conn->mg_conn.uri, + uri_len + 1, 0); + remove_double_dots_and_double_slashes((char *) conn->mg_conn.uri); +#if 0 if (call_user(MG_REQUEST_BEGIN, conn, NULL) != 0) { conn->flags |= CONN_SPOOL_DONE; return; } +#endif + + if ((uh = find_uri_handler(conn->server, conn->mg_conn.uri)) != NULL) { + conn->endpoint_type = EP_USER; + } exists = convert_uri_to_file_name(conn, path, sizeof(path), &st); is_directory = S_ISDIR(st.st_mode); if (!exists) { - mg_printf(conn, "%s", "HTTP/1.0 404 Not Found\r\n\r\n"); + mg_printf(&conn->mg_conn, "%s", "HTTP/1.0 404 Not Found\r\n\r\n"); conn->flags |= CONN_SPOOL_DONE; - } else if (is_directory && ri->uri[uri_len - 1] != '/') { - mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n" - "Location: %s/\r\n\r\n", ri->uri); + } else if (is_directory && conn->mg_conn.uri[uri_len - 1] != '/') { + mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n" + "Location: %s/\r\n\r\n", conn->mg_conn.uri); conn->flags |= CONN_SPOOL_DONE; } else if (is_directory) { - mg_printf(conn, "%s", "HTTP/1.0 403 Directory Listing Denied\r\n\r\n"); + mg_printf(&conn->mg_conn, "%s", + "HTTP/1.0 403 Directory Listing Denied\r\n\r\n"); conn->flags |= CONN_SPOOL_DONE; } else if ((conn->endpoint.fd = open(path, O_RDONLY)) != -1) { open_file_endpoint(conn, path, &st); } else { - mg_printf(conn, "%s", "HTTP/1.0 404 Not Found\r\n\r\n"); + mg_printf(&conn->mg_conn, "%s", "HTTP/1.0 404 Not Found\r\n\r\n"); conn->flags |= CONN_SPOOL_DONE; } } @@ -1092,13 +1119,12 @@ static int io_space(const struct iobuf *io) { return io->size - io->len; } -static void process_request(struct mg_connection *conn) { +static void process_request(struct connection *conn) { struct iobuf *io = &conn->local_iobuf; //DBG(("parse_http_message(%d [%.*s])", io->len, io->len, io->buf)); if (conn->request_len == 0) { - conn->request_len = parse_http_message(io->buf, io->len, - &conn->request_info); + conn->request_len = parse_http_message(io->buf, io->len, &conn->mg_conn); } DBG(("parse_http_message() -> %d", conn->request_len)); @@ -1111,7 +1137,7 @@ static void process_request(struct mg_connection *conn) { } } -static void read_from_client(struct mg_connection *conn) { +static void read_from_client(struct connection *conn) { struct iobuf *io = &conn->local_iobuf; int n = recv(conn->client_sock, io->buf + io->len, io->size - io->len, 0); @@ -1127,21 +1153,19 @@ static void read_from_client(struct mg_connection *conn) { } } -static int should_keep_alive(const struct mg_connection *conn) { - const char *method = conn->request_info.request_method; - const char *http_version = conn->request_info.http_version; - const char *header = mg_get_header(conn, "Connection"); +static int should_keep_alive(const struct connection *conn) { + const char *method = conn->mg_conn.request_method; + const char *http_version = conn->mg_conn.http_version; + const char *header = mg_get_header(&conn->mg_conn, "Connection"); return method != NULL && !strcmp(method, "GET") && ((header != NULL && !strcmp(header, "keep-alive")) || (header == NULL && http_version && !strcmp(http_version, "1.1"))); } -static void close_local_endpoint(struct mg_connection *conn) { +static void close_local_endpoint(struct connection *conn) { struct iobuf *io = &conn->local_iobuf; int keep_alive = should_keep_alive(conn); // Must be done before memmove - call_user(MG_REQUEST_END, conn, (void *) (long) conn->status_code); - // Close file descriptor switch (conn->endpoint_type) { case EP_FILE: close(conn->endpoint.fd); break; @@ -1162,7 +1186,7 @@ static void close_local_endpoint(struct mg_connection *conn) { } } -static void transfer_file_data(struct mg_connection *conn) { +static void transfer_file_data(struct connection *conn) { struct iobuf *io = &conn->remote_iobuf; int n, rem_space = io_space(io); @@ -1183,22 +1207,24 @@ void add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) { } } -void mg_poll_server(struct mg_server *server, unsigned int milliseconds) { +void mg_poll_server(struct mg_server *server, int milliseconds) { struct linked_list_link *lp, *tmp; - struct mg_connection *conn; + struct connection *conn; struct timeval tv; fd_set read_set, write_set; sock_t max_fd = -1; time_t current_time = time(NULL), expire_time = current_time + atoi(server->config_options[IDLE_TIMEOUT_MS]) / 1000; + if (server->listening_sock == INVALID_SOCKET) return; + FD_ZERO(&read_set); FD_ZERO(&write_set); add_to_set(server->listening_sock, &read_set, &max_fd); add_to_set(server->ctl[0], &read_set, &max_fd); LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) { - conn = LINKED_LIST_ENTRY(lp, struct mg_connection, link); + conn = LINKED_LIST_ENTRY(lp, struct connection, link); add_to_set(conn->client_sock, &read_set, &max_fd); if (conn->endpoint_type == EP_FILE) { transfer_file_data(conn); @@ -1230,7 +1256,7 @@ void mg_poll_server(struct mg_server *server, unsigned int milliseconds) { // Read/write from clients LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) { - conn = LINKED_LIST_ENTRY(lp, struct mg_connection, link); + conn = LINKED_LIST_ENTRY(lp, struct connection, link); if (FD_ISSET(conn->client_sock, &read_set)) { conn->expire_time = expire_time; read_from_client(conn); @@ -1244,7 +1270,7 @@ void mg_poll_server(struct mg_server *server, unsigned int milliseconds) { // Close expired connections and those that need to be closed LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) { - conn = LINKED_LIST_ENTRY(lp, struct mg_connection, link); + conn = LINKED_LIST_ENTRY(lp, struct connection, link); if (conn->flags & CONN_CLOSE || current_time > conn->expire_time) { close_conn(conn); } @@ -1253,27 +1279,85 @@ void mg_poll_server(struct mg_server *server, unsigned int milliseconds) { void mg_destroy_server(struct mg_server **server) { struct linked_list_link *lp, *tmp; - struct mg_connection *conn; if (server != NULL && *server != NULL) { closesocket((*server)->listening_sock); closesocket((*server)->ctl[0]); closesocket((*server)->ctl[1]); LINKED_LIST_FOREACH(&(*server)->active_connections, lp, tmp) { - conn = LINKED_LIST_ENTRY(lp, struct mg_connection, link); - LINKED_LIST_REMOVE(&conn->link); - free(conn); + free(LINKED_LIST_ENTRY(lp, struct connection, link)); + } + LINKED_LIST_FOREACH(&(*server)->uri_handlers, lp, tmp) { + free(LINKED_LIST_ENTRY(lp, struct uri_handler, link)); } free(*server); *server = NULL; } } -struct mg_server *mg_create_server(const char *opts[], mg_event_handler_t func, - void *user_data) { +// Apply function to all active connections. Return number of active +// connections. Function could be NULL. +static int mg_iterate_over_connections(struct mg_server *server, + void (*func)(struct mg_connection *, void *), + void *param) { + struct linked_list_link *lp, *tmp; + struct connection *conn; + int num_connections = 0; + + LINKED_LIST_FOREACH(&server->active_connections, lp, tmp) { + num_connections++; + conn = LINKED_LIST_ENTRY(lp, struct connection, link); + if (conn->endpoint_type == EP_USER && func != NULL) { + func((struct mg_connection *) conn, param); + } + } + + return num_connections; +} + +void mg_add_uri_handler(struct mg_server *server, const char *uri, + mg_uri_handler_t handler) { + struct uri_handler *p = (struct uri_handler *) malloc(sizeof(*p)); + if (p != NULL) { + LINKED_LIST_ADD_TO_FRONT(&server->uri_handlers, &p->link); + p->uri = mg_strdup(uri); + p->handler = handler; + } +} + +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; + + if (ind < 0) { + error_msg = "No such option"; + } else { + if (server->config_options[ind] != NULL) { + free(server->config_options[ind]); + } + server->config_options[ind] = mg_strdup(value); + + if (ind == LISTENING_PORT) { + if (server->listening_sock != INVALID_SOCKET) { + closesocket(server->listening_sock); + } + parse_port_string(server->config_options[LISTENING_PORT], &server->lsa); + server->listening_sock = open_listening_socket(&server->lsa); + if (server->listening_sock == INVALID_SOCKET) { + error_msg = "Cannot bind to port"; + } else { + set_non_blocking_mode(server->listening_sock); + } + } + } + + return error_msg; +} + +struct mg_server *mg_create_server(void *server_data) { struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server)); - const char *name, *value; - char error_msg[100] = {'\0'}; + const char *value; int i; #ifdef _WIN32 @@ -1281,11 +1365,13 @@ struct mg_server *mg_create_server(const char *opts[], mg_event_handler_t func, WSAStartup(MAKEWORD(2, 2), &data); #endif - server->event_handler = func; - server->user_data = user_data; LINKED_LIST_INIT(&server->active_connections); + LINKED_LIST_INIT(&server->uri_handlers); mg_socketpair(server->ctl); + server->server_data = server_data; + server->listening_sock = INVALID_SOCKET; +#if 0 while (opts != NULL && (name = *opts++) != NULL) { if ((i = get_option_index(name)) == -1) { snprintf(error_msg, sizeof(error_msg), "Invalid option: [%s]", name); @@ -1299,43 +1385,56 @@ struct mg_server *mg_create_server(const char *opts[], mg_event_handler_t func, DBG(("[%s] -> [%s]", name, value)); } } +#endif - // Set default values + // Set default options values for (i = 0; static_config_options[i * 2] != NULL; i++) { value = static_config_options[i * 2 + 1]; if (server->config_options[i] == NULL && value != NULL) { server->config_options[i] = mg_strdup(value); } } - parse_port_string(server->config_options[LISTENING_PORT], &server->lsa); - server->listening_sock = open_listening_socket(&server->lsa); - set_non_blocking_mode(server->listening_sock); - - if (error_msg[0] != '\0') { - mg_destroy_server(&server); - } return server; } // End of library, start of the application code -static int event_handler(struct mg_event *ev) { - if (ev->type == MG_REQUEST_BEGIN && - !strcmp(ev->request_info->uri, "/x")) { - mg_printf(ev->conn, "%s", "HTTP/1.0 200 OK\r\n\r\n:-)\n"); - return 1; +static void iterate_callback(struct mg_connection *c, void *param) { + mg_write(c, "%d", * (int *) param); +} + +static void *timer_thread(void *param) { + struct mg_server *server = (struct mg_server *) param; + int i; + + for (i = 0; i < 1000; i++) { + sleep(1); + mg_iterate_over_connections(server, iterate_callback, &i); } - return 0; + + return NULL; +} + +static int websocket_handler(struct mg_connection *conn) { + mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n:-)\n"); + return 1; } + int main(void) { - const char *options[] = {"document_root", ".", "listening_port", "8080", 0}; - struct mg_server *server = mg_create_server(options, event_handler, NULL); + struct mg_server *server = mg_create_server(NULL); + + mg_set_option(server, "listening_port", "8080"); + mg_set_option(server, "document_root", "."); + mg_add_uri_handler(server, "/ws", websocket_handler); + mg_start_thread(timer_thread, server); + printf("Started on port %s\n", mg_get_option(server, "listening_port")); for (;;) { mg_poll_server(server, 1000); } + mg_destroy_server(&server); return 0; } diff --git a/build/src/core.h b/build/src/core.h new file mode 100644 index 000000000..621bd30c0 --- /dev/null +++ b/build/src/core.h @@ -0,0 +1,89 @@ +// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com> +// Copyright (c) 2013 Cesanta Software Limited +// All rights reserved +// +// This library is dual-licensed: you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. For the terms of this +// license, see <http://www.gnu.org/licenses/>. +// +// You are free to use this library under the terms of the GNU General +// Public License, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// Alternatively, you can license this library under a commercial +// license, as set out in <http://cesanta.com/products.html>. +// +// NOTE: Detailed API documentation is at http://cesanta.com/docs.html + +#ifndef MONGOOSE_HEADER_INCLUDED +#define MONGOOSE_HEADER_INCLUDED + +#include <stdio.h> // required for FILE +#include <stddef.h> // required for size_t + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// This structure contains information about HTTP request. +struct mg_connection { + const char *request_method; // "GET", "POST", etc + const char *uri; // URL-decoded URI + const char *http_version; // E.g. "1.0", "1.1" + const char *query_string; // URL part after '?', not including '?', or NULL + long remote_ip; // Client's IP address + int remote_port; // Client's port + int is_ssl; // 1 if SSL-ed, 0 if not + int num_headers; // Number of HTTP headers + struct mg_header { + const char *name; // HTTP header name + const char *value; // HTTP header value + } http_headers[64]; // Maximum 64 headers + + void *server_param; // Parameter passed to mg_add_uri_handler() + void *connection_param; // Placeholder for connection-specific data +}; + +struct mg_server; // Opaque structure describing server instance +typedef int (*mg_uri_handler_t)(struct mg_connection *); +typedef int (*mg_error_handler_t)(struct mg_connection *, int http_error_code); + +// Server management functions +struct mg_server *mg_create_server(void *server_param); +void mg_destroy_server(struct mg_server **); +const char *mg_set_option(struct mg_server *, const char *opt, const char *val); +void mg_poll_server(struct mg_server *, int milliseconds); +void mg_add_uri_handler(struct mg_server *, const char *uri, mg_uri_handler_t); +void mg_set_error_handler(struct mg_server *, mg_error_handler_t); +void mg_set_log_handler(struct mg_server*, int (*)(struct mg_connection*, int)); +const char **mg_get_valid_option_names(void); +const char *mg_get_option(const struct mg_server *server, const char *name); + +// Websocket functions +void mg_websocket_handshake(struct mg_connection *); +int mg_websocket_read(struct mg_connection *, int *bits, char **data); +int mg_websocket_write(struct mg_connection* conn, int opcode, + const char *data, size_t data_len); + +// Connection management functions +int mg_write(struct mg_connection *, const void *buf, int len); +int mg_printf(struct mg_connection *, const char *fmt, ...); +void mg_send_file(struct mg_connection *, const char *path); +int mg_read(struct mg_connection *, void *buf, int len); +const char *mg_get_header(const struct mg_connection *, const char *name); +int mg_get_var(const char *data, size_t data_len, + const char *var_name, char *dst, size_t dst_len); +int mg_get_cookie(const char *cookie, const char *var_name, + char *buf, size_t buf_len); +const char *mg_get_mime_type(const char *file_name); + +// Utility functions +int mg_start_thread(void *(*func)(void *), void *param); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // MONGOOSE_HEADER_INCLUDED -- GitLab