Commit 6083b9c5 authored by Sergey Lyubka's avatar Sergey Lyubka

Updated to the recent skeleton. SSL address format changed

parent 83237a02
......@@ -474,6 +474,7 @@ static void set_options(char *argv[]) {
// scripts can use relative paths.
chdir(mg_get_option(server, "document_root"));
#if 0
// Add an ability to pass listening socket to mongoose
{
const char *env = getenv("MONGOOSE_LISTENING_SOCKET");
......@@ -481,6 +482,7 @@ static void set_options(char *argv[]) {
mg_set_listening_socket(server, atoi(env));
}
}
#endif
// Setup signal handler: quit on Ctrl-C
signal(SIGTERM, signal_handler);
......
......@@ -396,9 +396,9 @@ static const char *test_server(void) {
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0)) != NULL);
ASSERT((conn = mg_connect(server, "127.0.0.1:" HTTP_PORT)) != NULL);
conn->connection_param = buf1;
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0)) != NULL);
ASSERT((conn = mg_connect(server, "127.0.0.1:" HTTP_PORT)) != NULL);
conn->connection_param = buf2;
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
......@@ -483,7 +483,7 @@ static const char *test_mg_set_option(void) {
}
static const char *test_rewrites(void) {
char buf1[100] = "xx";
char buf1[100] = "xx", addr[50];
struct mg_server *server = mg_create_server(NULL, evh2);
struct mg_connection *conn;
const char *port;
......@@ -492,7 +492,8 @@ static const char *test_rewrites(void) {
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
ASSERT(mg_set_option(server, "url_rewrites", "/xx=unit_test.c") == NULL);
ASSERT((port = mg_get_option(server, "listening_port")) != NULL);
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(port), 0)) != NULL);
snprintf(addr, sizeof(addr), "127.0.0.1:%s", port);
ASSERT((conn = mg_connect(server, addr)) != NULL);
conn->connection_param = buf1;
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
......
// Copyright (c) 2013-2014 Cesanta Software Limited
// $Date: 2014-09-08 22:30:52 UTC $
// $Date: 2014-09-09 17:07:55 UTC $
#include <string.h>
#include <time.h>
......
// Copyright (c) 2013-2014 Cesanta Software Limited
// $Date: 2014-09-09 08:27:35 UTC $
// $Date: 2014-09-09 17:07:55 UTC $
#include <string.h>
#include <time.h>
......
# Copyright (c) 2014 Cesanta Software
# All rights reserved
CFLAGS = -W -Wall -I../.. -g -O0 $(CFLAGS_EXTRA)
NS = ../../../net_skeleton
SW = ../../../ssl_wrapper
CFLAGS = -W -Wall -I../.. -I. -g -O0 $(CFLAGS_EXTRA)
SOURCES = ws_ssl.c ../../mongoose.c $(NS)/net_skeleton.c $(SW)/ssl_wrapper.c
SOURCES = ws_ssl.c ../../mongoose.c net_skeleton.c ssl_wrapper.c
PROG = ws_ssl
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) -o $(PROG) $(SOURCES) \
-I$(NS) -DNS_ENABLE_SSL -DNOEMBED_NET_SKELETON \
-I$(SW) -DSSL_WRAPPER_USE_AS_LIBRARY -lssl $(CFLAGS)
-DNS_ENABLE_SSL -DNOEMBED_NET_SKELETON \
-DSSL_WRAPPER_USE_AS_LIBRARY -lssl $(CFLAGS)
clean:
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
......@@ -14,7 +14,7 @@
// Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-09 16:03:50 UTC $
// $Date: 2014-09-09 17:07:55 UTC $
#include "net_skeleton.h"
......
......@@ -14,7 +14,7 @@
// Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-09 16:03:50 UTC $
// $Date: 2014-09-09 17:07:55 UTC $
#ifndef NS_SKELETON_HEADER_INCLUDED
#define NS_SKELETON_HEADER_INCLUDED
......
......@@ -14,7 +14,7 @@
// Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/products.html>.
//
// $Date: 2014-09-09 16:03:50 UTC $
// $Date: 2014-09-09 17:07:55 UTC $
#include "net_skeleton.h"
#include "ssl_wrapper.h"
......
......@@ -14,7 +14,7 @@
// Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/products.html>.
//
// $Date: 2014-09-09 16:03:50 UTC $
// $Date: 2014-09-09 17:07:55 UTC $
#ifndef SSL_WRAPPER_HEADER_INCLUDED
#define SSL_WRAPPER_HEADER_INCLUDED
......
......@@ -15,7 +15,7 @@
// Alternatively, you can license this library under a commercial
// license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-01 19:53:26 UTC $
// $Date: 2014-09-09 17:07:55 UTC $
#ifdef NOEMBED_NET_SKELETON
#include "net_skeleton.h"
......@@ -36,11 +36,13 @@
//
// Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-09 17:07:55 UTC $
#ifndef NS_SKELETON_HEADER_INCLUDED
#define NS_SKELETON_HEADER_INCLUDED
#define NS_SKELETON_VERSION "1.1"
#define NS_SKELETON_VERSION "2.0.0"
#undef UNICODE // Use ANSI WinAPI functions
#undef _UNICODE // Use multibyte encoding on Windows
......@@ -133,7 +135,9 @@ typedef int sock_t;
#define DBG(x)
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#endif
#ifdef NS_ENABLE_SSL
#ifdef __APPLE__
......@@ -174,7 +178,7 @@ void iobuf_remove(struct iobuf *, size_t data_size);
// Net skeleton interface
// Events. Meaning of event parameter (evp) is given in the comment.
enum ns_event {
NS_POLL, // Sent to each connection on each call to ns_server_poll()
NS_POLL, // Sent to each connection on each call to ns_mgr_poll()
NS_ACCEPT, // New connection accept()-ed. union socket_address *remote_addr
NS_CONNECT, // connect() succeeded or failed. int *success_status
NS_RECV, // Data has benn received. int *num_bytes
......@@ -187,36 +191,37 @@ enum ns_event {
struct ns_connection;
typedef void (*ns_callback_t)(struct ns_connection *, enum ns_event, void *evp);
struct ns_server {
void *server_data;
sock_t listening_sock;
struct ns_mgr {
struct ns_connection *active_connections;
ns_callback_t callback;
SSL_CTX *ssl_ctx;
SSL_CTX *client_ssl_ctx;
const char *hexdump_file;
sock_t ctl[2];
ns_callback_t callback; // Event handler function
const char *hexdump_file; // Debug hexdump file path
sock_t ctl[2]; // Socketpair for mg_wakeup()
void *user_data; // User data
};
struct ns_connection {
struct ns_connection *prev, *next;
struct ns_server *server;
struct ns_connection *next, *prev; // ns_mgr::active_connections linkage
struct ns_connection *listener; // Set only for accept()-ed connections
struct ns_mgr *mgr;
sock_t sock;
union socket_address sa;
struct iobuf recv_iobuf;
struct iobuf send_iobuf;
SSL *ssl;
SSL_CTX *ssl_ctx;
void *connection_data;
time_t last_io_time;
unsigned int flags;
#define NSF_FINISHED_SENDING_DATA (1 << 0)
#define NSF_BUFFER_BUT_DONT_SEND (1 << 1)
#define NSF_SSL_HANDSHAKE_DONE (1 << 2)
#define NSF_CONNECTING (1 << 3)
#define NSF_CLOSE_IMMEDIATELY (1 << 4)
#define NSF_ACCEPTED (1 << 5)
#define NSF_WANT_READ (1 << 6)
#define NSF_WANT_WRITE (1 << 7)
#define NSF_WANT_READ (1 << 5)
#define NSF_WANT_WRITE (1 << 6)
#define NSF_LISTENING (1 << 7)
#define NSF_UDP (1 << 8)
#define NSF_USER_1 (1 << 26)
#define NSF_USER_2 (1 << 27)
......@@ -226,20 +231,15 @@ struct ns_connection {
#define NSF_USER_6 (1 << 31)
};
void ns_server_init(struct ns_server *, void *server_data, ns_callback_t);
void ns_server_free(struct ns_server *);
int ns_server_poll(struct ns_server *, int milli);
void ns_server_wakeup(struct ns_server *);
void ns_server_wakeup_ex(struct ns_server *, ns_callback_t, void *, size_t);
void ns_iterate(struct ns_server *, ns_callback_t cb, void *param);
struct ns_connection *ns_next(struct ns_server *, struct ns_connection *);
struct ns_connection *ns_add_sock(struct ns_server *, sock_t sock, void *p);
int ns_bind(struct ns_server *, const char *addr);
int ns_set_ssl_cert(struct ns_server *, const char *ssl_cert);
int ns_set_ssl_ca_cert(struct ns_server *, const char *ssl_ca_cert);
struct ns_connection *ns_connect(struct ns_server *, const char *host,
int port, int ssl, void *connection_param);
void ns_mgr_init(struct ns_mgr *, void *data, ns_callback_t);
void ns_mgr_free(struct ns_mgr *);
int ns_mgr_poll(struct ns_mgr *, int milli);
void ns_broadcast(struct ns_mgr *, ns_callback_t, void *, size_t);
struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *);
struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t sock, void *p);
struct ns_connection *ns_bind(struct ns_mgr *, const char *addr, void *p);
struct ns_connection *ns_connect(struct ns_mgr *, const char *addr, void *p);
int ns_send(struct ns_connection *, const void *buf, int len);
int ns_printf(struct ns_connection *, const char *fmt, ...);
......@@ -253,6 +253,7 @@ void ns_set_close_on_exec(sock_t);
void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags);
int ns_hexdump(const void *buf, int len, char *dst, int dst_len);
int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
#ifdef __cplusplus
}
......@@ -274,6 +275,8 @@ int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
//
// Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-09 17:07:55 UTC $
#ifndef NS_MALLOC
......@@ -288,6 +291,9 @@ int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
#define NS_FREE free
#endif
#define NS_UDP_RECEIVE_BUFFER_SIZE 2000
#define NS_VPRINTF_BUFFER_SIZE 500
struct ctl_msg {
ns_callback_t callback;
char message[1024 * 8];
......@@ -338,6 +344,16 @@ void iobuf_remove(struct iobuf *io, size_t n) {
}
}
static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) {
if (nc->flags & NSF_UDP) {
long n = send(nc->sock, buf, len, 0);
DBG(("%p %d send %ld (%d)", nc, nc->sock, n, errno));
return n < 0 ? 0 : n;
} else {
return iobuf_append(&nc->send_iobuf, buf, len);
}
}
#ifndef NS_DISABLE_THREADS
void *ns_start_thread(void *(*f)(void *), void *p) {
#ifdef _WIN32
......@@ -361,15 +377,15 @@ void *ns_start_thread(void *(*f)(void *), void *p) {
}
#endif // NS_DISABLE_THREADS
static void ns_add_conn(struct ns_server *server, struct ns_connection *c) {
c->next = server->active_connections;
server->active_connections = c;
static void ns_add_conn(struct ns_mgr *mgr, struct ns_connection *c) {
c->next = mgr->active_connections;
mgr->active_connections = c;
c->prev = NULL;
if (c->next != NULL) c->next->prev = c;
}
static void ns_remove_conn(struct ns_connection *conn) {
if (conn->prev == NULL) conn->server->active_connections = conn->next;
if (conn->prev == NULL) conn->mgr->active_connections = conn->next;
if (conn->prev) conn->prev->next = conn->next;
if (conn->next) conn->next->prev = conn->prev;
}
......@@ -412,12 +428,12 @@ int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
return len;
}
int ns_vprintf(struct ns_connection *conn, const char *fmt, va_list ap) {
char mem[2000], *buf = mem;
int ns_vprintf(struct ns_connection *nc, const char *fmt, va_list ap) {
char mem[NS_VPRINTF_BUFFER_SIZE], *buf = mem;
int len;
if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
iobuf_append(&conn->send_iobuf, buf, len);
ns_out(nc, buf, len);
}
if (buf != mem && buf != NULL) {
free(buf);
......@@ -450,7 +466,7 @@ static void hexdump(struct ns_connection *nc, const char *path,
ev == NS_RECV ? "<-" : ev == NS_SEND ? "->" :
ev == NS_ACCEPT ? "<A" : ev == NS_CONNECT ? "C>" : "XX",
dst, num_bytes);
if (num_bytes > 0 && (buf = (char *) malloc(buf_size)) != NULL) {
if (num_bytes > 0 && (buf = (char *) NS_MALLOC(buf_size)) != NULL) {
ns_hexdump(io->buf + (ev == NS_SEND ? 0 : io->len) -
(ev == NS_SEND ? 0 : num_bytes), num_bytes, buf, buf_size);
fprintf(fp, "%s", buf);
......@@ -461,17 +477,14 @@ static void hexdump(struct ns_connection *nc, const char *path,
}
static void ns_call(struct ns_connection *conn, enum ns_event ev, void *p) {
if (conn->server->hexdump_file != NULL && ev != NS_POLL) {
if (conn->mgr->hexdump_file != NULL && ev != NS_POLL) {
int len = (ev == NS_RECV || ev == NS_SEND) ? * (int *) p : 0;
hexdump(conn, conn->server->hexdump_file, len, ev);
hexdump(conn, conn->mgr->hexdump_file, len, ev);
}
if (conn->server->callback) conn->server->callback(conn, ev, p);
if (conn->mgr->callback) conn->mgr->callback(conn, ev, p);
}
static void ns_close_conn(struct ns_connection *conn) {
DBG(("%p %d", conn, conn->flags));
ns_call(conn, NS_CLOSE, NULL);
ns_remove_conn(conn);
static void ns_destroy_conn(struct ns_connection *conn) {
closesocket(conn->sock);
iobuf_free(&conn->recv_iobuf);
iobuf_free(&conn->send_iobuf);
......@@ -479,10 +492,20 @@ static void ns_close_conn(struct ns_connection *conn) {
if (conn->ssl != NULL) {
SSL_free(conn->ssl);
}
if (conn->ssl_ctx != NULL) {
SSL_CTX_free(conn->ssl_ctx);
}
#endif
NS_FREE(conn);
}
static void ns_close_conn(struct ns_connection *conn) {
DBG(("%p %d", conn, conn->flags));
ns_call(conn, NS_CLOSE, NULL);
ns_remove_conn(conn);
ns_destroy_conn(conn);
}
void ns_set_close_on_exec(sock_t sock) {
#ifdef _WIN32
(void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
......@@ -543,10 +566,31 @@ int ns_socketpair(sock_t sp[2]) {
}
#endif // NS_DISABLE_SOCKETPAIR
// Valid listening port spec is: [ip_address:]port, e.g. "80", "127.0.0.1:3128"
static int ns_parse_port_string(const char *str, union socket_address *sa) {
// TODO(lsm): use non-blocking resolver
static int ns_resolve2(const char *host, struct in_addr *ina) {
struct hostent *he;
if ((he = gethostbyname(host)) == NULL) {
DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
} else {
memcpy(ina, he->h_addr_list[0], sizeof(*ina));
return 1;
}
return 0;
}
// Resolve FDQN "host", store IP address in the "ip".
// Return > 0 (IP address length) on success.
int ns_resolve(const char *host, char *buf, size_t n) {
struct in_addr ad;
return ns_resolve2(host, &ad) ? snprintf(buf, n, "%s", inet_ntoa(ad)) : 0;
}
// Address format: [PROTO://][IP_ADDRESS:]PORT[:CERT][:CA_CERT]
static int ns_parse_address(const char *str, union socket_address *sa,
int *proto, int *use_ssl, char *cert, char *ca) {
unsigned int a, b, c, d, port;
int len = 0;
int n = 0, len = 0;
char host[200];
#ifdef NS_ENABLE_IPV6
char buf[100];
#endif
......@@ -557,36 +601,57 @@ static int ns_parse_port_string(const char *str, union socket_address *sa) {
memset(sa, 0, sizeof(*sa));
sa->sin.sin_family = AF_INET;
*proto = SOCK_STREAM;
*use_ssl = 0;
cert[0] = ca[0] = '\0';
if (memcmp(str, "ssl://", 6) == 0) {
str += 6;
*use_ssl = 1;
} else if (memcmp(str, "udp://", 6) == 0) {
str += 6;
*proto = SOCK_DGRAM;
} else if (memcmp(str, "tcp://", 6) == 0) {
str += 6;
}
if (sscanf(str, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
// Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
sa->sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
sa->sin.sin_port = htons((uint16_t) port);
#ifdef NS_ENABLE_IPV6
} else if (sscanf(str, "[%49[^]]]:%u%n", buf, &port, &len) == 2 &&
} else if (sscanf(str, "[%99[^]]]:%u%n", buf, &port, &len) == 2 &&
inet_pton(AF_INET6, buf, &sa->sin6.sin6_addr)) {
// IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080
sa->sin6.sin6_family = AF_INET6;
sa->sin6.sin6_port = htons((uint16_t) port);
#endif
} else if (sscanf(str, "%199[^ :]:%u%n", host, &port, &len) == 2) {
sa->sin.sin_port = htons((uint16_t) port);
ns_resolve2(host, &sa->sin.sin_addr);
} else if (sscanf(str, "%u%n", &port, &len) == 1) {
// If only port is specified, bind to IPv4, INADDR_ANY
sa->sin.sin_port = htons((uint16_t) port);
} else {
port = 0; // Parsing failure. Make port invalid.
}
return port <= 0xffff && str[len] == '\0';
if (*use_ssl && (sscanf(str + len, ":%99[^:]:%99[^:]%n", cert, ca, &n) == 2 ||
sscanf(str + len, ":%99[^:]%n", cert, &n) == 1)) {
len += n;
}
return port < 0xffff && str[len] == '\0' ? len : 0;
}
// 'sa' must be an initialized address to bind to
static sock_t ns_open_listening_socket(union socket_address *sa) {
socklen_t len = sizeof(*sa);
static sock_t ns_open_listening_socket(union socket_address *sa, int proto) {
socklen_t sa_len = (sa->sa.sa_family == AF_INET) ?
sizeof(sa->sin) : sizeof(sa->sin6);
sock_t sock = INVALID_SOCKET;
#ifndef _WIN32
int on = 1;
#endif
if ((sock = socket(sa->sa.sa_family, SOCK_STREAM, 6)) != INVALID_SOCKET &&
if ((sock = socket(sa->sa.sa_family, proto, 0)) != INVALID_SOCKET &&
#ifndef _WIN32
// SO_RESUSEADDR is not enabled on Windows because the semantics of
// SO_REUSEADDR on UNIX and Windows is different. On Windows,
......@@ -596,12 +661,11 @@ static sock_t ns_open_listening_socket(union socket_address *sa) {
// scenarios. Therefore, SO_REUSEADDR was disabled on Windows.
!setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on)) &&
#endif
!bind(sock, &sa->sa, sa->sa.sa_family == AF_INET ?
sizeof(sa->sin) : sizeof(sa->sin6)) &&
!listen(sock, SOMAXCONN)) {
!bind(sock, &sa->sa, sa_len) &&
(proto == SOCK_DGRAM || listen(sock, SOMAXCONN) == 0)) {
ns_set_non_blocking_mode(sock);
// In case port was set to 0, get the real port number
(void) getsockname(sock, &sa->sa, &len);
(void) getsockname(sock, &sa->sa, &sa_len);
} else if (sock != INVALID_SOCKET) {
closesocket(sock);
sock = INVALID_SOCKET;
......@@ -610,80 +674,97 @@ static sock_t ns_open_listening_socket(union socket_address *sa) {
return sock;
}
// Certificate generation script is at
// https://github.com/cesanta/net_skeleton/blob/master/examples/gen_certs.sh
int ns_set_ssl_ca_cert(struct ns_server *server, const char *cert) {
#ifdef NS_ENABLE_SSL
STACK_OF(X509_NAME) *list = SSL_load_client_CA_file(cert);
if (cert != NULL && server->ssl_ctx != NULL && list != NULL) {
SSL_CTX_set_client_CA_list(server->ssl_ctx, list);
SSL_CTX_set_verify(server->ssl_ctx, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
// Certificate generation script is at
// https://github.com/cesanta/net_skeleton/blob/master/scripts/gen_certs.sh
static int ns_use_ca_cert(SSL_CTX *ctx, const char *cert) {
if (ctx == NULL) {
return -1;
} else if (cert == NULL || cert[0] == '\0') {
return 0;
}
#endif
return server != NULL && cert == NULL ? 0 : -1;
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? 0 : -2;
}
int ns_set_ssl_cert(struct ns_server *server, const char *cert) {
#ifdef NS_ENABLE_SSL
if (cert != NULL &&
(server->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
static int ns_use_cert(SSL_CTX *ctx, const char *pem_file) {
if (ctx == NULL) {
return -1;
} else if (SSL_CTX_use_certificate_file(server->ssl_ctx, cert, 1) == 0 ||
SSL_CTX_use_PrivateKey_file(server->ssl_ctx, cert, 1) == 0) {
} else if (pem_file == NULL || pem_file[0] == '\0') {
return 0;
} else if (SSL_CTX_use_certificate_file(ctx, pem_file, 1) == 0 ||
SSL_CTX_use_PrivateKey_file(ctx, pem_file, 1) == 0) {
return -2;
} else {
SSL_CTX_set_mode(server->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_CTX_use_certificate_chain_file(server->ssl_ctx, cert);
SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_CTX_use_certificate_chain_file(ctx, pem_file);
return 0;
}
#endif
return server != NULL && cert == NULL ? 0 : -3;
}
#endif // NS_ENABLE_SSL
int ns_bind(struct ns_server *server, const char *str) {
struct ns_connection *ns_bind(struct ns_mgr *srv, const char *str, void *data) {
union socket_address sa;
ns_parse_port_string(str, &sa);
if (server->listening_sock != INVALID_SOCKET) {
closesocket(server->listening_sock);
struct ns_connection *nc = NULL;
int use_ssl, proto;
char cert[100], ca_cert[100];
sock_t sock;
ns_parse_address(str, &sa, &proto, &use_ssl, cert, ca_cert);
if (use_ssl && cert[0] == '\0') return NULL;
if ((sock = ns_open_listening_socket(&sa, proto)) == INVALID_SOCKET) {
} else if ((nc = ns_add_sock(srv, sock, NULL)) == NULL) {
closesocket(sock);
} else {
nc->sa = sa;
nc->flags |= NSF_LISTENING;
nc->connection_data = data;
if (proto == SOCK_DGRAM) {
nc->flags |= NSF_UDP;
}
server->listening_sock = ns_open_listening_socket(&sa);
return server->listening_sock == INVALID_SOCKET ? -1 :
(int) ntohs(sa.sin.sin_port);
}
#ifdef NS_ENABLE_SSL
if (use_ssl) {
nc->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (ns_use_cert(nc->ssl_ctx, cert) != 0 ||
ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0) {
ns_close_conn(nc);
nc = NULL;
}
}
#endif
static struct ns_connection *accept_conn(struct ns_server *server) {
DBG(("%p sock %d/%d ssl %p %p", nc, sock, proto, nc->ssl_ctx, nc->ssl));
}
return nc;
}
static struct ns_connection *accept_conn(struct ns_connection *ls) {
struct ns_connection *c = NULL;
union socket_address sa;
socklen_t len = sizeof(sa);
sock_t sock = INVALID_SOCKET;
// NOTE(lsm): on Windows, sock is always > FD_SETSIZE
if ((sock = accept(server->listening_sock, &sa.sa, &len)) == INVALID_SOCKET) {
} else if ((c = (struct ns_connection *) NS_MALLOC(sizeof(*c))) == NULL ||
memset(c, 0, sizeof(*c)) == NULL) {
if ((sock = accept(ls->sock, &sa.sa, &len)) == INVALID_SOCKET) {
} else if ((c = ns_add_sock(ls->mgr, sock, NULL)) == NULL) {
closesocket(sock);
#ifdef NS_ENABLE_SSL
} else if (server->ssl_ctx != NULL &&
((c->ssl = SSL_new(server->ssl_ctx)) == NULL ||
} else if (ls->ssl_ctx != NULL &&
((c->ssl = SSL_new(ls->ssl_ctx)) == NULL ||
SSL_set_fd(c->ssl, sock) != 1)) {
DBG(("SSL error"));
closesocket(sock);
free(c);
ns_close_conn(c);
c = NULL;
#endif
} else {
ns_set_close_on_exec(sock);
ns_set_non_blocking_mode(sock);
c->server = server;
c->sock = sock;
c->flags |= NSF_ACCEPTED;
ns_add_conn(server, c);
c->listener = ls;
ns_call(c, NS_ACCEPT, &sa);
DBG(("%p %d %p %p", c, c->sock, c->ssl, server->ssl_ctx));
DBG(("%p %d %p %p", c, c->sock, c->ssl_ctx, c->ssl));
}
return c;
......@@ -720,7 +801,7 @@ void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags) {
// Only Windoze Vista (and newer) have inet_ntop()
strncpy(buf, inet_ntoa(sa.sin.sin_addr), len);
#else
inet_ntop(sa.sa.sa_family, (void *) &sa.sin.sin_addr, buf, len);
inet_ntop(sa.sa.sa_family, (void *) &sa.sin.sin_addr, buf,(socklen_t)len);
#endif
}
if (flags & 2) {
......@@ -822,7 +903,7 @@ static void ns_read_from_socket(struct ns_connection *conn) {
} else
#endif
{
while ((n = recv(conn->sock, buf, sizeof(buf), 0)) > 0) {
while ((n = (int) recv(conn->sock, buf, sizeof(buf), 0)) > 0) {
DBG(("%p %d <- %d bytes (PLAIN)", conn, conn->flags, n));
iobuf_append(&conn->recv_iobuf, buf, n);
ns_call(conn, NS_RECV, &n);
......@@ -851,7 +932,7 @@ static void ns_write_to_socket(struct ns_connection *conn) {
}
} else
#endif
{ n = send(conn->sock, io->buf, io->len, 0); }
{ n = (int) send(conn->sock, io->buf, io->len, 0); }
DBG(("%p %d -> %d bytes", conn, conn->flags, n));
......@@ -864,7 +945,27 @@ static void ns_write_to_socket(struct ns_connection *conn) {
}
int ns_send(struct ns_connection *conn, const void *buf, int len) {
return iobuf_append(&conn->send_iobuf, buf, len);
return (int) ns_out(conn, buf, len);
}
static void ns_handle_udp(struct ns_connection *ls) {
struct ns_connection nc;
char buf[NS_UDP_RECEIVE_BUFFER_SIZE];
int n;
socklen_t s_len = sizeof(nc.sa);
memset(&nc, 0, sizeof(nc));
n = recvfrom(ls->sock, buf, sizeof(buf), 0, &nc.sa.sa, &s_len);
if (n <= 0) {
DBG(("%p recvfrom: %s", ls, strerror(errno)));
} else {
nc.recv_iobuf.buf = buf;
nc.recv_iobuf.len = nc.recv_iobuf.size = n;
nc.sock = ls->sock;
nc.mgr = ls->mgr;
DBG(("%p %d bytes received", ls, n));
ns_call(&nc, NS_RECV, &n);
}
}
static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
......@@ -876,7 +977,7 @@ static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
}
}
int ns_server_poll(struct ns_server *server, int milli) {
int ns_mgr_poll(struct ns_mgr *mgr, int milli) {
struct ns_connection *conn, *tmp_conn;
struct timeval tv;
fd_set read_set, write_set;
......@@ -884,15 +985,11 @@ int ns_server_poll(struct ns_server *server, int milli) {
sock_t max_fd = INVALID_SOCKET;
time_t current_time = time(NULL);
if (server->listening_sock == INVALID_SOCKET &&
server->active_connections == NULL) return 0;
FD_ZERO(&read_set);
FD_ZERO(&write_set);
ns_add_to_set(server->listening_sock, &read_set, &max_fd);
ns_add_to_set(server->ctl[1], &read_set, &max_fd);
ns_add_to_set(mgr->ctl[1], &read_set, &max_fd);
for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
tmp_conn = conn->next;
ns_call(conn, NS_POLL, &current_time);
if (!(conn->flags & NSF_WANT_WRITE)) {
......@@ -918,34 +1015,38 @@ int ns_server_poll(struct ns_server *server, int milli) {
// now to prevent last_io_time being set to the past.
current_time = time(NULL);
// Accept new connections
if (server->listening_sock != INVALID_SOCKET &&
FD_ISSET(server->listening_sock, &read_set)) {
// We're not looping here, and accepting just one connection at
// a time. The reason is that eCos does not respect non-blocking
// flag on a listening socket and hangs in a loop.
if ((conn = accept_conn(server)) != NULL) {
conn->last_io_time = current_time;
}
}
// Read wakeup messages
if (server->ctl[1] != INVALID_SOCKET &&
FD_ISSET(server->ctl[1], &read_set)) {
if (mgr->ctl[1] != INVALID_SOCKET &&
FD_ISSET(mgr->ctl[1], &read_set)) {
struct ctl_msg ctl_msg;
int len = recv(server->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
send(server->ctl[1], ctl_msg.message, 1, 0);
int len = (int) recv(mgr->ctl[1], (char *) &ctl_msg, sizeof(ctl_msg), 0);
send(mgr->ctl[1], ctl_msg.message, 1, 0);
if (len >= (int) sizeof(ctl_msg.callback) && ctl_msg.callback != NULL) {
ns_iterate(server, ctl_msg.callback, ctl_msg.message);
struct ns_connection *c;
for (c = ns_next(mgr, NULL); c != NULL; c = ns_next(mgr, c)) {
ctl_msg.callback(c, NS_POLL, ctl_msg.message);
}
}
}
for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
tmp_conn = conn->next;
if (FD_ISSET(conn->sock, &read_set)) {
if (conn->flags & NSF_LISTENING) {
if (conn->flags & NSF_UDP) {
ns_handle_udp(conn);
} else {
// We're not looping here, and accepting just one connection at
// a time. The reason is that eCos does not respect non-blocking
// flag on a listening socket and hangs in a loop.
accept_conn(conn);
}
} else {
conn->last_io_time = current_time;
ns_read_from_socket(conn);
}
}
if (FD_ISSET(conn->sock, &write_set)) {
if (conn->flags & NSF_CONNECTING) {
ns_read_from_socket(conn);
......@@ -957,7 +1058,7 @@ int ns_server_poll(struct ns_server *server, int milli) {
}
}
for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
for (conn = mgr->active_connections; conn != NULL; conn = tmp_conn) {
tmp_conn = conn->next;
num_active_connections++;
if ((conn->flags & NSF_CLOSE_IMMEDIATELY) ||
......@@ -971,65 +1072,62 @@ int ns_server_poll(struct ns_server *server, int milli) {
return num_active_connections;
}
struct ns_connection *ns_connect(struct ns_server *server, const char *host,
int port, int use_ssl, void *param) {
struct ns_connection *ns_connect(struct ns_mgr *mgr,
const char *address, void *param) {
sock_t sock = INVALID_SOCKET;
struct sockaddr_in sin;
struct hostent *he = NULL;
struct ns_connection *conn = NULL;
int connect_ret_val;
(void) use_ssl;
struct ns_connection *nc = NULL;
union socket_address sa;
char cert[100], ca_cert[100];
int connect_ret_val, use_ssl, proto;
if (host == NULL || (he = gethostbyname(host)) == NULL ||
(sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
ns_parse_address(address, &sa, &proto, &use_ssl, cert, ca_cert);
if ((sock = socket(AF_INET, proto, 0)) == INVALID_SOCKET) {
return NULL;
}
sin.sin_family = AF_INET;
sin.sin_port = htons((uint16_t) port);
sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
ns_set_non_blocking_mode(sock);
connect_ret_val = connect(sock, &sa.sa, sizeof(sa.sin));
connect_ret_val = connect(sock, (struct sockaddr *) &sin, sizeof(sin));
if (ns_is_error(connect_ret_val)) {
if (connect_ret_val != 0 && ns_is_error(connect_ret_val)) {
closesocket(sock);
return NULL;
} else if ((conn = (struct ns_connection *)
NS_MALLOC(sizeof(*conn))) == NULL) {
} else if ((nc = ns_add_sock(mgr, sock, param)) == NULL) {
closesocket(sock);
return NULL;
}
memset(conn, 0, sizeof(*conn));
conn->server = server;
conn->sock = sock;
conn->connection_data = param;
conn->flags = NSF_CONNECTING;
conn->last_io_time = time(NULL);
nc->sa = sa; // Essential, cause UDP conns will use sendto()
if (proto == SOCK_DGRAM) {
nc->flags = NSF_UDP;
} else {
nc->flags = NSF_CONNECTING;
}
#ifdef NS_ENABLE_SSL
if (use_ssl &&
(conn->ssl = SSL_new(server->client_ssl_ctx)) != NULL) {
SSL_set_fd(conn->ssl, sock);
if (use_ssl) {
if ((nc->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL ||
ns_use_cert(nc->ssl_ctx, cert) != 0 ||
ns_use_ca_cert(nc->ssl_ctx, ca_cert) != 0 ||
(nc->ssl = SSL_new(nc->ssl_ctx)) == NULL) {
ns_close_conn(nc);
return NULL;
} else {
SSL_set_fd(nc->ssl, sock);
}
}
#endif
ns_add_conn(server, conn);
DBG(("%p %s:%d %d %p", conn, host, port, conn->sock, conn->ssl));
return conn;
return nc;
}
struct ns_connection *ns_add_sock(struct ns_server *s, sock_t sock, void *p) {
struct ns_connection *ns_add_sock(struct ns_mgr *s, sock_t sock, void *p) {
struct ns_connection *conn;
if ((conn = (struct ns_connection *) NS_MALLOC(sizeof(*conn))) != NULL) {
memset(conn, 0, sizeof(*conn));
ns_set_non_blocking_mode(sock);
ns_set_close_on_exec(sock);
conn->sock = sock;
conn->connection_data = p;
conn->server = s;
conn->mgr = s;
conn->last_io_time = time(NULL);
ns_add_conn(s, conn);
DBG(("%p %d", conn, sock));
......@@ -1037,40 +1135,26 @@ struct ns_connection *ns_add_sock(struct ns_server *s, sock_t sock, void *p) {
return conn;
}
struct ns_connection *ns_next(struct ns_server *s, struct ns_connection *conn) {
struct ns_connection *ns_next(struct ns_mgr *s, struct ns_connection *conn) {
return conn == NULL ? s->active_connections : conn->next;
}
void ns_iterate(struct ns_server *server, ns_callback_t cb, void *param) {
struct ns_connection *conn, *tmp_conn;
for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
tmp_conn = conn->next;
cb(conn, NS_POLL, param);
}
}
void ns_server_wakeup_ex(struct ns_server *server, ns_callback_t cb,
void *data, size_t len) {
void ns_broadcast(struct ns_mgr *mgr, ns_callback_t cb,void *data, size_t len) {
struct ctl_msg ctl_msg;
if (server->ctl[0] != INVALID_SOCKET && data != NULL &&
if (mgr->ctl[0] != INVALID_SOCKET && data != NULL &&
len < sizeof(ctl_msg.message)) {
ctl_msg.callback = cb;
memcpy(ctl_msg.message, data, len);
send(server->ctl[0], (char *) &ctl_msg,
send(mgr->ctl[0], (char *) &ctl_msg,
offsetof(struct ctl_msg, message) + len, 0);
recv(server->ctl[0], (char *) &len, 1, 0);
recv(mgr->ctl[0], (char *) &len, 1, 0);
}
}
void ns_server_wakeup(struct ns_server *server) {
ns_server_wakeup_ex(server, NULL, (void *) "", 0);
}
void ns_server_init(struct ns_server *s, void *server_data, ns_callback_t cb) {
void ns_mgr_init(struct ns_mgr *s, void *user_data, ns_callback_t cb) {
memset(s, 0, sizeof(*s));
s->listening_sock = s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
s->server_data = server_data;
s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
s->user_data = user_data;
s->callback = cb;
#ifdef _WIN32
......@@ -1089,33 +1173,25 @@ void ns_server_init(struct ns_server *s, void *server_data, ns_callback_t cb) {
#ifdef NS_ENABLE_SSL
{static int init_done; if (!init_done) { SSL_library_init(); init_done++; }}
s->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method());
#endif
}
void ns_server_free(struct ns_server *s) {
void ns_mgr_free(struct ns_mgr *s) {
struct ns_connection *conn, *tmp_conn;
DBG(("%p", s));
if (s == NULL) return;
// Do one last poll, see https://github.com/cesanta/mongoose/issues/286
ns_server_poll(s, 0);
ns_mgr_poll(s, 0);
if (s->listening_sock != INVALID_SOCKET) closesocket(s->listening_sock);
if (s->ctl[0] != INVALID_SOCKET) closesocket(s->ctl[0]);
if (s->ctl[1] != INVALID_SOCKET) closesocket(s->ctl[1]);
s->listening_sock = s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
s->ctl[0] = s->ctl[1] = INVALID_SOCKET;
for (conn = s->active_connections; conn != NULL; conn = tmp_conn) {
tmp_conn = conn->next;
ns_close_conn(conn);
}
#ifdef NS_ENABLE_SSL
if (s->ssl_ctx != NULL) SSL_CTX_free(s->ssl_ctx);
if (s->client_ssl_ctx != NULL) SSL_CTX_free(s->client_ssl_ctx);
s->ssl_ctx = s->client_ssl_ctx = NULL;
#endif
}
// net_skeleton end
#endif // NOEMBED_NET_SKELETON
......@@ -1264,11 +1340,6 @@ enum {
#endif
#ifndef MONGOOSE_NO_SSI
SSI_PATTERN,
#endif
#ifdef NS_ENABLE_SSL
SSL_CERTIFICATE,
SSL_CA_CERTIFICATE,
SSL_MITM_CERTS,
#endif
URL_REWRITES,
NUM_OPTIONS
......@@ -1299,7 +1370,7 @@ static const char *static_config_options[] = {
#ifndef MONGOOSE_NO_FILESYSTEM
"hide_files_patterns", NULL,
"hexdump_file", NULL,
"index_files","index.html,index.htm,index.shtml,index.cgi,index.php,index.lp",
"index_files","index.html,index.htm,index.shtml,index.cgi,index.php",
#endif
"listening_port", NULL,
#ifndef _WIN32
......@@ -1307,18 +1378,13 @@ static const char *static_config_options[] = {
#endif
#ifndef MONGOOSE_NO_SSI
"ssi_pattern", "**.shtml$|**.shtm$",
#endif
#ifdef NS_ENABLE_SSL
"ssl_certificate", NULL,
"ssl_ca_certificate", NULL,
"ssl_mitm_certs", NULL,
#endif
"url_rewrites", NULL,
NULL
};
struct mg_server {
struct ns_server ns_server;
struct ns_mgr ns_mgr;
union socket_address lsa; // Listening socket address
mg_handler_t event_handler;
char *config_options[NUM_OPTIONS];
......@@ -1420,6 +1486,32 @@ void *mg_start_thread(void *(*f)(void *), void *p) {
}
#endif // MONGOOSE_NO_THREADS
#ifdef _WIN32
static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
int offset) {
HANDLE fh = (HANDLE) _get_osfhandle(fd);
HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len);
CloseHandle(mh);
return p;
}
#define munmap(x, y) UnmapViewOfFile(x)
#define MAP_FAILED NULL
#define MAP_PRIVATE 0
#define PROT_READ 0
#else
#include <sys/mman.h>
#endif
void *mg_mmap(FILE *fp, size_t size) {
void *p = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
return p == MAP_FAILED ? NULL : p;
}
void mg_munmap(void *p, size_t size) {
munmap(p, size);
}
#if defined(_WIN32) && !defined(MONGOOSE_NO_FILESYSTEM)
// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
// wbuf and wbuf_len is a target buffer and its length.
......@@ -2093,7 +2185,7 @@ static void open_cgi_endpoint(struct connection *conn, const char *prog) {
if (start_process(conn->server->config_options[CGI_INTERPRETER],
prog, blk.buf, blk.vars, dir, fds[1]) != 0) {
conn->endpoint_type = EP_CGI;
conn->endpoint.nc = ns_add_sock(&conn->server->ns_server, fds[0], conn);
conn->endpoint.nc = ns_add_sock(&conn->server->ns_mgr, fds[0], conn);
conn->endpoint.nc->flags |= MG_CGI_CONN;
ns_send(conn->ns_conn, cgi_status, sizeof(cgi_status) - 1);
conn->mg_conn.status_code = 200;
......@@ -4160,7 +4252,6 @@ int mg_terminate_ssl(struct mg_connection *c, const char *cert) {
SSL_CTX *ctx;
DBG(("%p MITM", conn));
SSL_library_init();
if ((ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) return 0;
SSL_CTX_use_certificate_file(ctx, cert, 1);
......@@ -4170,7 +4261,7 @@ int mg_terminate_ssl(struct mg_connection *c, const char *cert) {
// When clear-text reply is pushed to client, switch to SSL mode.
// TODO(lsm): check for send() failure
send(conn->ns_conn->sock, ok, sizeof(ok) - 1, 0);
DBG(("%p %lu %d SEND", c, (unsigned long)sizeof(ok) - 1, n));
//DBG(("%p %lu %d SEND", c, (unsigned long) sizeof(ok) - 1, n));
conn->ns_conn->send_iobuf.len = 0;
conn->endpoint_type = EP_USER; // To keep-alive in close_local_endpoint()
close_local_endpoint(conn); // Clean up current CONNECT request
......@@ -4182,12 +4273,12 @@ int mg_terminate_ssl(struct mg_connection *c, const char *cert) {
}
#endif
int mg_forward(struct mg_connection *c, const char *host, int port, int ssl) {
int mg_forward(struct mg_connection *c, const char *addr) {
static const char ok[] = "HTTP/1.1 200 OK\r\n\r\n";
struct connection *conn = MG_CONN_2_CONN(c);
struct ns_server *server = &conn->server->ns_server;
struct ns_connection *pc;
if ((pc = ns_connect(server, host, port, ssl, conn)) == NULL) {
if ((pc = ns_connect(&conn->server->ns_mgr, addr, conn)) == NULL) {
conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
return 0;
}
......@@ -4196,12 +4287,12 @@ int mg_forward(struct mg_connection *c, const char *host, int port, int ssl) {
pc->flags |= MG_PROXY_CONN;
conn->endpoint_type = EP_PROXY;
conn->endpoint.nc = pc;
DBG(("%p [%s] [%s:%d] -> %p %p",
conn, c->uri, host, port, pc, conn->ns_conn->ssl));
DBG(("%p [%s] [%s] -> %p %p", conn, c->uri, addr, pc, conn->ns_conn->ssl));
if (strcmp(c->request_method, "CONNECT") == 0) {
// For CONNECT request, reply with 200 OK. Tunnel is established.
mg_printf(c, "%s", "HTTP/1.1 200 OK\r\n\r\n");
// TODO(lsm): check for send() failure
(void) send(conn->ns_conn->sock, ok, sizeof(ok) - 1, 0);
} else {
// Strip "http://host:port" part from the URI
if (memcmp(c->uri, "http://", 7) == 0) c->uri += 7;
......@@ -4212,7 +4303,7 @@ int mg_forward(struct mg_connection *c, const char *host, int port, int ssl) {
}
static void proxify_connection(struct connection *conn) {
char proto[10], host[500], cert[500];
char proto[10], host[500], cert[500], addr[1000];
unsigned short port = 80;
struct mg_connection *c = &conn->mg_conn;
int n = 0;
......@@ -4225,25 +4316,9 @@ static void proxify_connection(struct connection *conn) {
n = 0;
}
#ifdef NS_ENABLE_SSL
// Find out whether we should be in the MITM mode
{
const char *certs = conn->server->config_options[SSL_MITM_CERTS];
int host_len = strlen(host);
struct vec a, b;
while (conn->ns_conn->ssl == NULL && port != 80 &&
(certs = next_option(certs, &a, &b)) != NULL) {
if (a.len != host_len || mg_strncasecmp(a.ptr, host, a.len)) continue;
snprintf(cert, sizeof(cert), "%.*s", b.len, b.ptr);
mg_terminate_ssl(&conn->mg_conn, cert);
return;
}
}
#endif
if (n > 0 && mg_forward(c, host, port, conn->ns_conn->ssl != NULL)) {
} else {
snprintf(addr, sizeof(addr), "%s://%s:%hu",
conn->ns_conn->ssl != NULL ? "ssl" : "tcp", host, port);
if (n <= 0 || !mg_forward(c, addr)) {
conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
}
}
......@@ -4535,12 +4610,11 @@ static void process_response(struct connection *conn) {
}
}
struct mg_connection *mg_connect(struct mg_server *server, const char *host,
int port, int use_ssl) {
struct mg_connection *mg_connect(struct mg_server *server, const char *addr) {
struct ns_connection *nsconn;
struct connection *conn;
nsconn = ns_connect(&server->ns_server, host, port, use_ssl, NULL);
nsconn = ns_connect(&server->ns_mgr, addr, NULL);
if (nsconn == NULL) return 0;
if ((conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) {
......@@ -4555,7 +4629,7 @@ struct mg_connection *mg_connect(struct mg_server *server, const char *host,
conn->server = server;
conn->endpoint_type = EP_CLIENT;
//conn->handler = handler;
conn->mg_conn.server_param = server->ns_server.server_data;
conn->mg_conn.server_param = server->ns_mgr.user_data;
conn->ns_conn->flags = NSF_CONNECTING;
return &conn->mg_conn;
......@@ -4684,7 +4758,7 @@ static void transfer_file_data(struct connection *conn) {
}
int mg_poll_server(struct mg_server *server, int milliseconds) {
return ns_server_poll(&server->ns_server, milliseconds);
return ns_mgr_poll(&server->ns_mgr, milliseconds);
}
void mg_destroy_server(struct mg_server **server) {
......@@ -4692,7 +4766,7 @@ void mg_destroy_server(struct mg_server **server) {
struct mg_server *s = *server;
int i;
ns_server_free(&s->ns_server);
ns_mgr_free(&s->ns_mgr);
for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
free(s->config_options[i]); // It is OK to free(NULL)
}
......@@ -4701,34 +4775,15 @@ void mg_destroy_server(struct mg_server **server) {
}
}
struct mg_iterator {
mg_handler_t cb;
void *param;
};
static void iter(struct ns_connection *nsconn, enum ns_event ev, void *param) {
if (ev == NS_POLL) {
struct mg_iterator *it = (struct mg_iterator *) param;
struct connection *c = (struct connection *) nsconn->connection_data;
if (c != NULL) c->mg_conn.callback_param = it->param;
it->cb(&c->mg_conn, MG_POLL);
}
}
struct mg_connection *mg_next(struct mg_server *s, struct mg_connection *c) {
struct connection *conn = MG_CONN_2_CONN(c);
struct ns_connection *nc = ns_next(&s->ns_server,
struct ns_connection *nc = ns_next(&s->ns_mgr,
c == NULL ? NULL : conn->ns_conn);
return nc == NULL ? NULL :
& ((struct connection *) nc->connection_data)->mg_conn;
}
// Apply function to all active connections.
void mg_iterate_over_connections(struct mg_server *server, mg_handler_t cb,
void *param) {
struct mg_iterator it = { cb, param };
ns_iterate(&server->ns_server, iter, &it);
if (nc != NULL && nc->connection_data != NULL) {
return & ((struct connection *) nc->connection_data)->mg_conn;
} else {
return NULL;
}
}
static int get_var(const char *data, size_t data_len, const char *name,
......@@ -4886,18 +4941,18 @@ const char *mg_set_option(struct mg_server *server, const char *name,
DBG(("%s [%s]", name, *v));
if (ind == LISTENING_PORT) {
int port = ns_bind(&server->ns_server, value);
if (port < 0) {
struct ns_connection *c = ns_bind(&server->ns_mgr, value, NULL);
if (c == NULL) {
error_msg = "Cannot bind to port";
} else {
char buf[100];
ns_sock_to_str(server->ns_server.listening_sock, buf, sizeof(buf), 2);
ns_sock_to_str(c->sock, buf, sizeof(buf), 2);
free(*v);
*v = mg_strdup(buf);
}
#ifndef MONGOOSE_NO_FILESYSTEM
} else if (ind == HEXDUMP_FILE) {
server->ns_server.hexdump_file = *v;
server->ns_mgr.hexdump_file = *v;
#endif
#ifndef _WIN32
} else if (ind == RUN_AS_USER) {
......@@ -4909,21 +4964,6 @@ const char *mg_set_option(struct mg_server *server, const char *name,
} else if (setuid(pw->pw_uid) != 0) {
error_msg = "setuid() failed";
}
#endif
#ifdef NS_ENABLE_SSL
} else if (ind == SSL_CERTIFICATE) {
int res = ns_set_ssl_cert(&server->ns_server, value);
if (res == -2) {
error_msg = "Cannot load PEM";
} else if (res == -3) {
error_msg = "SSL not enabled";
} else if (res == -1) {
error_msg = "SSL_CTX_new() failed";
}
} else if (ind == SSL_CA_CERTIFICATE) {
if (ns_set_ssl_ca_cert(&server->ns_server, value) != 0) {
error_msg = "Error setting CA cert";
}
#endif
}
......@@ -4943,7 +4983,7 @@ static void set_ips(struct ns_connection *nc, int is_rem) {
}
static void on_accept(struct ns_connection *nc, union socket_address *sa) {
struct mg_server *server = (struct mg_server *) nc->server;
struct mg_server *server = (struct mg_server *) nc->mgr;
struct connection *conn;
if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
......@@ -4957,7 +4997,7 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) {
// Initialize the rest of connection attributes
conn->server = server;
conn->mg_conn.server_param = nc->server->server_data;
conn->mg_conn.server_param = nc->mgr->user_data;
set_ips(nc, 1);
set_ips(nc, 0);
}
......@@ -5007,7 +5047,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
if (conn != NULL) {
conn->num_bytes_recv += * (int *) p;
}
if (nc->flags & NSF_ACCEPTED) {
if (nc->listener != NULL) {
on_recv_data(conn);
#ifndef MONGOOSE_NO_CGI
} else if (nc->flags & MG_CGI_CONN) {
......@@ -5110,23 +5150,25 @@ void mg_wakeup_server_ex(struct mg_server *server, mg_handler_t cb,
va_end(ap);
// "len + 1" is to include terminating \0 in the message
ns_server_wakeup_ex(&server->ns_server, iter2, buf, len + 1);
ns_broadcast(&server->ns_mgr, iter2, buf, len + 1);
}
void mg_wakeup_server(struct mg_server *server) {
ns_server_wakeup_ex(&server->ns_server, NULL, (void *) "", 0);
ns_broadcast(&server->ns_mgr, NULL, (void *) "", 0);
}
#if 0
void mg_set_listening_socket(struct mg_server *server, int sock) {
if (server->ns_server.listening_sock != INVALID_SOCKET) {
closesocket(server->ns_server.listening_sock);
if (server->ns_mgr.listening_sock != INVALID_SOCKET) {
closesocket(server->ns_mgr.listening_sock);
}
server->ns_server.listening_sock = (sock_t) sock;
server->ns_mgr.listening_sock = (sock_t) sock;
}
int mg_get_listening_socket(struct mg_server *server) {
return server->ns_server.listening_sock;
return server->ns_mgr.listening_sock;
}
#endif
const char *mg_get_option(const struct mg_server *server, const char *name) {
const char **opts = (const char **) server->config_options;
......@@ -5136,33 +5178,8 @@ const char *mg_get_option(const struct mg_server *server, const char *name) {
struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server));
ns_server_init(&server->ns_server, server_data, mg_ev_handler);
ns_mgr_init(&server->ns_mgr, server_data, mg_ev_handler);
set_default_option_values(server->config_options);
server->event_handler = handler;
return server;
}
#ifdef _WIN32
static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
int offset) {
HANDLE fh = (HANDLE) _get_osfhandle(fd);
HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len);
CloseHandle(mh);
return p;
}
#define munmap(x, y) UnmapViewOfFile(x)
#define MAP_FAILED NULL
#define MAP_PRIVATE 0
#define PROT_READ 0
#else
#include <sys/mman.h>
#endif
void *mg_mmap(FILE *fp, size_t size) {
return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
}
void mg_munmap(void *p, size_t size) {
munmap(p, size);
}
......@@ -15,7 +15,7 @@
// Alternatively, you can license this library under a commercial
// license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-01 19:53:26 UTC $
// $Date: 2014-09-09 17:07:55 UTC $
#ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED
......@@ -55,7 +55,7 @@ struct mg_connection {
int wsbits; // First byte of the websocket frame
void *server_param; // Parameter passed to mg_add_uri_handler()
void *connection_param; // Placeholder for connection-specific data
void *callback_param; // Needed by mg_iterate_over_connections()
void *callback_param;
};
struct mg_server; // Opaque structure describing server instance
......@@ -95,11 +95,10 @@ const char **mg_get_valid_option_names(void);
const char *mg_get_option(const struct mg_server *server, const char *name);
void mg_set_listening_socket(struct mg_server *, int sock);
int mg_get_listening_socket(struct mg_server *);
void mg_iterate_over_connections(struct mg_server *, mg_handler_t, void *);
struct mg_connection *mg_next(struct mg_server *, struct mg_connection *);
void mg_wakeup_server(struct mg_server *);
void mg_wakeup_server_ex(struct mg_server *, mg_handler_t, const char *, ...);
struct mg_connection *mg_connect(struct mg_server *, const char *, int, int);
struct mg_connection *mg_connect(struct mg_server *, const char *);
// Connection management functions
void mg_send_status(struct mg_connection *, int status_code);
......@@ -127,6 +126,7 @@ int mg_parse_multipart(const char *buf, int buf_len,
char *file_name, int file_name_len,
const char **data, int *data_len);
// Utility functions
void *mg_start_thread(void *(*func)(void *), void *param);
char *mg_md5(char buf[33], ...);
......@@ -134,7 +134,7 @@ int mg_authorize_digest(struct mg_connection *c, FILE *fp);
int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int);
int mg_terminate_ssl(struct mg_connection *c, const char *cert);
int mg_forward(struct mg_connection *, const char *host, int port, int use_ssl);
int mg_forward(struct mg_connection *c, const char *addr);
void *mg_mmap(FILE *fp, size_t size);
void mg_munmap(void *p, size_t size);
......@@ -147,7 +147,6 @@ struct mg_expansion {
void mg_template(struct mg_connection *, const char *text,
struct mg_expansion *expansions);
#ifdef __cplusplus
}
#endif // __cplusplus
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment