2
0
Fork 0

Recode the sockaddr handling, fixing some bugs

This commit is contained in:
Stefan Bühler 2009-04-03 14:29:55 +02:00
parent 293fabc963
commit 611d7dcac3
16 changed files with 150 additions and 61 deletions

View File

@ -29,6 +29,7 @@ struct connection {
guint idx; /** index in connection table */
server *srv;
worker *wrk;
server_socket *srv_sock;
connection_state_t state;
gboolean response_headers_sent, expect_100_cont;
@ -37,8 +38,8 @@ struct connection {
chunkqueue *in, *out; /* link to mainvr->in/out */
ev_io sock_watcher;
sock_addr remote_addr, local_addr;
GString *remote_addr_str, *local_addr_str;
sockaddr_t remote_addr;
GString *remote_addr_str;
gboolean is_ssl, keep_alive;
vrequest *mainvr;

View File

@ -11,12 +11,12 @@ typedef enum {
SERVER_STOPPING /** stopping: flush logs, don't accept new connections */
} server_state;
struct server_socket;
typedef struct server_socket server_socket;
struct server_socket {
guint refcount;
server *srv;
ev_io watcher;
sockaddr_t local_addr;
GString *local_addr_str;
};
struct server {
@ -36,7 +36,7 @@ struct server {
ev_prepare srv_prepare;
ev_check srv_check;
GArray *sockets; /** array of (server_socket*) */
GPtrArray *sockets; /** array of (server_socket*) */
struct modules *modules;
@ -99,4 +99,7 @@ LI_API void server_out_of_fds(server *srv);
LI_API guint server_ts_format_add(server *srv, GString* format);
LI_API void server_socket_release(server_socket* sock);
LI_API void server_socket_acquire(server_socket* sock);
#endif

View File

@ -77,9 +77,9 @@ typedef union {
struct sockaddr plain;
} sock_addr;
typedef struct {
typedef struct sockaddr_t {
socklen_t len;
sock_addr *addr;
} sockaddr;
} sockaddr_t;
#endif

View File

@ -162,6 +162,9 @@ typedef struct response response;
struct server;
typedef struct server server;
struct server_socket;
typedef struct server_socket server_socket;
/* utils.h */
struct waitqueue_elem;

View File

@ -52,10 +52,12 @@ LI_API guint hash_ipv6(gconstpointer key);
LI_API GString *mimetype_get(vrequest *vr, GString *filename);
/* converts a sock_addr to a human readable string. ipv4 and ipv6 supported. if dest is NULL, a new string will be allocated */
LI_API GString *sockaddr_to_string(sock_addr *saddr, GString *dest, gboolean showport);
LI_API GString *sockaddr_to_string(sockaddr_t addr, GString *dest, gboolean showport);
LI_API sockaddr sockaddr_from_string(GString *str, guint tcp_default_port);
LI_API void sockaddr_clear(sockaddr *saddr);
LI_API sockaddr_t sockaddr_from_string(GString *str, guint tcp_default_port);
LI_API sockaddr_t sockaddr_local_from_socket(gint fd);
LI_API sockaddr_t sockaddr_remote_from_socket(gint fd);
LI_API void sockaddr_clear(sockaddr_t *saddr);
LI_API void gstring_replace_char_with_str_len(GString *gstr, gchar c, gchar *str, guint len);

View File

@ -106,7 +106,7 @@ LI_API void worker_run(worker *wrk);
LI_API void worker_stop(worker *context, worker *wrk);
LI_API void worker_exit(worker *context, worker *wrk);
LI_API void worker_new_con(worker *ctx, worker *wrk, sock_addr *remote_addr, int s);
LI_API void worker_new_con(worker *ctx, worker *wrk, sockaddr_t remote_addr, int s, server_socket *srv_sock);
LI_API void worker_check_keepalive(worker *wrk);

View File

@ -306,7 +306,7 @@ static handler_t condition_check_eval_string(vrequest *vr, condition *cond, gboo
switch (cond->lvalue->type) {
case COMP_REQUEST_LOCALIP:
val = con->local_addr_str->str;
val = con->srv_sock->local_addr_str->str;
break;
case COMP_REQUEST_REMOTEIP:
val = con->remote_addr_str->str;
@ -506,11 +506,11 @@ static handler_t condition_check_eval_ip(vrequest *vr, condition *cond, gboolean
switch (cond->lvalue->type) {
case COMP_REQUEST_LOCALIP:
if (!condition_ip_from_socket(&ipval, &con->local_addr))
if (!condition_ip_from_socket(&ipval, con->srv_sock->local_addr.addr))
return HANDLER_GO_ON;
break;
case COMP_REQUEST_REMOTEIP:
if (!condition_ip_from_socket(&ipval, &con->remote_addr))
if (!condition_ip_from_socket(&ipval, con->remote_addr.addr))
return HANDLER_GO_ON;
break;
case COMP_REQUEST_PATH:

View File

@ -321,7 +321,6 @@ connection* connection_new(worker *wrk) {
ev_io_set(&con->sock_watcher, -1, 0);
con->sock_watcher.data = con;
con->remote_addr_str = g_string_sized_new(INET6_ADDRSTRLEN);
con->local_addr_str = g_string_sized_new(INET6_ADDRSTRLEN);
con->keep_alive = TRUE;
con->raw_in = chunkqueue_new();
@ -361,6 +360,9 @@ void connection_reset(connection *con) {
con->response_headers_sent = FALSE;
con->expect_100_cont = FALSE;
server_socket_release(con->srv_sock);
con->srv_sock = NULL;
ev_io_stop(con->wrk->loop, &con->sock_watcher);
if (con->sock_watcher.fd != -1) {
if (con->raw_in->is_closed) { /* read already shutdown */
@ -376,7 +378,7 @@ void connection_reset(connection *con) {
http_request_parser_reset(&con->req_parser_ctx);
g_string_truncate(con->remote_addr_str, 0);
g_string_truncate(con->local_addr_str, 0);
sockaddr_clear(&con->remote_addr);
con->keep_alive = TRUE;
chunkqueue_reset(con->raw_in);
@ -466,6 +468,9 @@ void connection_free(connection *con) {
con->response_headers_sent = FALSE;
con->expect_100_cont = FALSE;
server_socket_release(con->srv_sock);
con->srv_sock = NULL;
if (con->wrk)
ev_io_stop(con->wrk->loop, &con->sock_watcher);
if (con->sock_watcher.fd != -1) {
@ -475,7 +480,7 @@ void connection_free(connection *con) {
}
ev_io_set(&con->sock_watcher, -1, 0);
g_string_free(con->remote_addr_str, TRUE);
g_string_free(con->local_addr_str, TRUE);
sockaddr_clear(&con->remote_addr);
con->keep_alive = TRUE;
chunkqueue_free(con->raw_in);

View File

@ -240,7 +240,7 @@ static GString *al_format_log(connection *con, al_data *ald, GArray *format) {
g_string_append_len(str, GSTR_LEN(con->remote_addr_str));
break;
case AL_FORMAT_LOCAL_ADDR:
g_string_append_len(str, GSTR_LEN(con->local_addr_str));
g_string_append_len(str, GSTR_LEN(con->srv_sock->local_addr_str));
break;
case AL_FORMAT_BYTES_RESPONSE:
g_string_append_printf(str, "%jd", vr->out->bytes_out);

View File

@ -97,7 +97,7 @@ static gpointer debug_collect_func(worker *wrk, gpointer fdata) {
cd->is_ssl = c->is_ssl;
cd->keep_alive = c->keep_alive;
cd->remote_addr_str = g_string_new_len(GSTR_LEN(c->remote_addr_str));
cd->local_addr_str = g_string_new_len(GSTR_LEN(c->local_addr_str));
cd->local_addr_str = g_string_new_len(GSTR_LEN(c->srv_sock->local_addr_str));
cd->host = g_string_new_len(GSTR_LEN(c->mainvr->request.uri.host));
cd->path = g_string_new_len(GSTR_LEN(c->mainvr->request.uri.path));
cd->query = g_string_new_len(GSTR_LEN(c->mainvr->request.uri.query));

View File

@ -208,7 +208,7 @@ static handler_t dirlist(vrequest *vr, gpointer param, gpointer *context) {
}
/* redirect to scheme + host + path + / + querystring if directory without trailing slash */
/* TODO: local addr if HTTP 1.0 without host header, url encoding */
host = vr->request.uri.authority->len ? vr->request.uri.authority : vr->con->local_addr_str;
host = vr->request.uri.authority->len ? vr->request.uri.authority : vr->con->srv_sock->local_addr_str;
uri = g_string_sized_new(
8 /* https:// */ + host->len +
vr->request.uri.orig_path->len + 2 /* /? */ + vr->request.uri.query->len

View File

@ -87,7 +87,7 @@ struct fastcgi_connection {
struct fastcgi_context {
gint refcount;
sockaddr socket;
sockaddr_t socket;
guint timeout;
plugin *plugin;
};
@ -132,7 +132,7 @@ enum FCGI_ProtocolStatus {
/**********************************************************************************/
static fastcgi_context* fastcgi_context_new(server *srv, plugin *p, GString *dest_socket) {
sockaddr saddr;
sockaddr_t saddr;
fastcgi_context* ctx;
saddr = sockaddr_from_string(dest_socket, 0);
if (NULL == saddr.addr) {
@ -329,29 +329,29 @@ static void fastcgi_env_create(vrequest *vr, environment_dup *envdup, GString* b
fastcgi_env_add(buf, envdup, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
{
guint port = 0;
switch (con->local_addr.plain.sa_family) {
case AF_INET: port = con->local_addr.ipv4.sin_port; break;
switch (con->srv_sock->local_addr.addr->plain.sa_family) {
case AF_INET: port = con->srv_sock->local_addr.addr->ipv4.sin_port; break;
#ifdef HAVE_IPV6
case AF_INET6: port = con->local_addr.ipv6.sin6_port; break;
case AF_INET6: port = con->srv_sock->local_addr.addr->ipv6.sin6_port; break;
#endif
}
if (port) {
g_string_printf(tmp, "%u", port);
g_string_printf(tmp, "%u", htons(port));
fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_PORT"), GSTR_LEN(tmp));
}
}
fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_ADDR"), GSTR_LEN(con->local_addr_str));
fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_ADDR"), GSTR_LEN(con->srv_sock->local_addr_str));
{
guint port = 0;
switch (con->remote_addr.plain.sa_family) {
case AF_INET: port = con->remote_addr.ipv4.sin_port; break;
switch (con->remote_addr.addr->plain.sa_family) {
case AF_INET: port = con->remote_addr.addr->ipv4.sin_port; break;
#ifdef HAVE_IPV6
case AF_INET6: port = con->remote_addr.ipv6.sin6_port; break;
case AF_INET6: port = con->remote_addr.addr->ipv6.sin6_port; break;
#endif
}
if (port) {
g_string_printf(tmp, "%u", port);
g_string_printf(tmp, "%u", htons(port));
fastcgi_env_add(buf, envdup, CONST_STR_LEN("REMOTE_PORT"), GSTR_LEN(tmp));
}
}
@ -685,7 +685,7 @@ static handler_t fastcgi_statemachine(vrequest *vr, fastcgi_connection *fcon) {
return HANDLER_GO_ON;
default:
VR_ERROR(vr, "Couldn't connect to '%s': %s",
sockaddr_to_string(fcon->ctx->socket.addr, vr->con->wrk->tmp_str, TRUE)->str,
sockaddr_to_string(fcon->ctx->socket, vr->con->wrk->tmp_str, TRUE)->str,
g_strerror(errno));
fastcgi_close(vr, p);
vrequest_backend_dead(vr);

View File

@ -204,7 +204,7 @@ static gpointer status_collect_func(worker *wrk, gpointer fdata) {
cd->is_ssl = c->is_ssl;
cd->keep_alive = c->keep_alive;
cd->remote_addr_str = g_string_new_len(GSTR_LEN(c->remote_addr_str));
cd->local_addr_str = g_string_new_len(GSTR_LEN(c->local_addr_str));
cd->local_addr_str = g_string_new_len(GSTR_LEN(c->srv_sock->local_addr_str));
cd->host = g_string_new_len(GSTR_LEN(c->mainvr->request.uri.host));
cd->path = g_string_new_len(GSTR_LEN(c->mainvr->request.uri.path));
cd->query = g_string_new_len(GSTR_LEN(c->mainvr->request.uri.query));

View File

@ -2,6 +2,37 @@
#include <lighttpd/base.h>
#include <lighttpd/plugin_core.h>
static void server_listen_cb(struct ev_loop *loop, ev_io *w, int revents);
static server_socket* server_socket_new(int fd) {
server_socket *sock = g_slice_new0(server_socket);
sock->refcount = 1;
sock->watcher.data = sock;
sock->local_addr = sockaddr_local_from_socket(fd);
sock->local_addr_str = g_string_sized_new(0);
sockaddr_to_string(sock->local_addr, sock->local_addr_str, FALSE);
fd_init(fd);
ev_init(&sock->watcher, server_listen_cb);
ev_io_set(&sock->watcher, fd, EV_READ);
return sock;
}
void server_socket_release(server_socket* sock) {
if (!sock) return;
assert(g_atomic_int_get(&sock->refcount) > 0);
if (g_atomic_int_dec_and_test(&sock->refcount)) {
sockaddr_clear(&sock->local_addr);
g_string_free(sock->local_addr_str, TRUE);
g_slice_free(server_socket, sock);
}
}
void server_socket_acquire(server_socket* sock) {
assert(g_atomic_int_get(&sock->refcount) > 0);
g_atomic_int_inc(&sock->refcount);
}
static void server_value_free(gpointer _so) {
g_slice_free(server_option, _so);
}
@ -57,7 +88,7 @@ server* server_new(const gchar *module_dir) {
srv->workers = g_array_new(FALSE, TRUE, sizeof(worker*));
srv->sockets = g_array_new(FALSE, TRUE, sizeof(server_socket*));
srv->sockets = g_ptr_array_new();
srv->modules = modules_init(srv, module_dir);
@ -131,11 +162,11 @@ void server_free(server* srv) {
{
guint i; for (i = 0; i < srv->sockets->len; i++) {
server_socket *sock = g_array_index(srv->sockets, server_socket*, i);
server_socket *sock = g_ptr_array_index(srv->sockets, i);
close(sock->watcher.fd);
g_slice_free(server_socket, sock);
server_socket_release(sock);
}
g_array_free(srv->sockets, TRUE);
g_ptr_array_free(srv->sockets, TRUE);
}
{
@ -201,15 +232,25 @@ static void server_listen_cb(struct ev_loop *loop, ev_io *w, int revents) {
server_socket *sock = (server_socket*) w->data;
server *srv = sock->srv;
int s;
sock_addr remote_addr;
socklen_t l = sizeof(remote_addr);
sockaddr_t remote_addr;
struct sockaddr sa;
socklen_t l = sizeof(sa);
UNUSED(loop);
UNUSED(revents);
while (-1 != (s = accept(w->fd, (struct sockaddr*) &remote_addr, &l))) {
while (-1 != (s = accept(w->fd, &sa, &l))) {
worker *wrk = srv->main_worker;
guint i, min_load = g_atomic_int_get(&wrk->connection_load), sel = 0;
if (l <= sizeof(sa)) {
remote_addr.addr = g_slice_alloc(l);
remote_addr.len = l;
memcpy(remote_addr.addr, &sa, l);
} else {
remote_addr = sockaddr_remote_from_socket(s);
}
l = sizeof(sa); /* reset l */
fd_init(s);
for (i = 1; i < srv->worker_count; i++) {
@ -224,7 +265,8 @@ static void server_listen_cb(struct ev_loop *loop, ev_io *w, int revents) {
g_atomic_int_inc((gint*) &wrk->connection_load);
/* TRACE(srv, "selected worker %u with load %u", sel, min_load); */
worker_new_con(srv->main_worker, wrk, &remote_addr, s);
server_socket_acquire(sock);
worker_new_con(srv->main_worker, wrk, remote_addr, s, sock);
}
#ifdef _WIN32
@ -253,17 +295,12 @@ static void server_listen_cb(struct ev_loop *loop, ev_io *w, int revents) {
}
void server_listen(server *srv, int fd) {
server_socket *sock;
server_socket *sock = server_socket_new(fd);
sock = g_slice_new0(server_socket);
sock->srv = srv;
sock->watcher.data = sock;
fd_init(fd);
ev_init(&sock->watcher, server_listen_cb);
ev_io_set(&sock->watcher, fd, EV_READ);
if (g_atomic_int_get(&srv->state) == SERVER_RUNNING) ev_io_start(srv->main_worker->loop, &sock->watcher);
g_array_append_val(srv->sockets, sock);
g_ptr_array_add(srv->sockets, sock);
}
void server_start(server *srv) {
@ -283,7 +320,7 @@ void server_start(server *srv) {
plugins_prepare_callbacks(srv);
for (i = 0; i < srv->sockets->len; i++) {
server_socket *sock = g_array_index(srv->sockets, server_socket*, i);
server_socket *sock = g_ptr_array_index(srv->sockets, i);
ev_io_start(srv->main_worker->loop, &sock->watcher);
}
@ -307,7 +344,7 @@ void server_stop(server *srv) {
if (srv->main_worker) {
for (i = 0; i < srv->sockets->len; i++) {
server_socket *sock = g_array_index(srv->sockets, server_socket*, i);
server_socket *sock = g_ptr_array_index(srv->sockets, i);
ev_io_stop(srv->main_worker->loop, &sock->watcher);
}

View File

@ -432,12 +432,13 @@ GString *mimetype_get(vrequest *vr, GString *filename) {
}
GString *sockaddr_to_string(sock_addr *saddr, GString *dest, gboolean showport) {
GString *sockaddr_to_string(sockaddr_t addr, GString *dest, gboolean showport) {
gchar *p;
guint8 len = 0;
guint8 tmp;
guint8 tmplen;
guint8 oct;
sock_addr *saddr = addr.addr;
switch (saddr->plain.sa_family) {
case AF_INET:
@ -502,13 +503,13 @@ GString *sockaddr_to_string(sock_addr *saddr, GString *dest, gboolean showport)
return dest;
}
sockaddr sockaddr_from_string(GString *str, guint tcp_default_port) {
sockaddr_t sockaddr_from_string(GString *str, guint tcp_default_port) {
guint32 ipv4;
#ifdef HAVE_IPV6
guint8 ipv6[16];
#endif
guint16 port = tcp_default_port;
sockaddr saddr = { 0, NULL };
sockaddr_t saddr = { 0, NULL };
#ifdef HAVE_SYS_UN_H
if (0 == strncmp(str->str, "unix:/", 6)) {
@ -539,8 +540,42 @@ sockaddr sockaddr_from_string(GString *str, guint tcp_default_port) {
return saddr;
}
void sockaddr_clear(sockaddr *saddr) {
g_slice_free1(saddr->len, saddr->addr);
sockaddr_t sockaddr_local_from_socket(gint fd) {
socklen_t l = 0;
static struct sockaddr sa;
struct sockaddr_t saddr = { 0, NULL };
if (-1 == getsockname(fd, &sa, &l)) {
return saddr;
}
saddr.addr = (sock_addr*) g_slice_alloc0(l);
saddr.len = l;
getsockname(fd, (struct sockaddr*) saddr.addr, &l);
return saddr;
}
sockaddr_t sockaddr_remote_from_socket(gint fd) {
socklen_t l = 0;
static struct sockaddr sa;
struct sockaddr_t saddr = { 0, NULL };
if (-1 == getpeername(fd, &sa, &l)) {
return saddr;
}
saddr.addr = (sock_addr*) g_slice_alloc0(l);
saddr.len = l;
getpeername(fd, (struct sockaddr*) saddr.addr, &l);
return saddr;
}
void sockaddr_clear(sockaddr_t *saddr) {
if (saddr->addr) g_slice_free1(saddr->len, saddr->addr);
saddr->addr = NULL;
saddr->len = 0;
}
/* unused */

View File

@ -196,17 +196,19 @@ static void worker_exit_cb(struct ev_loop *loop, ev_async *w, int revents) {
struct worker_new_con_data;
typedef struct worker_new_con_data worker_new_con_data;
struct worker_new_con_data {
sock_addr remote_addr;
sockaddr_t remote_addr;
int s;
server_socket *srv_sock;
};
/* new con watcher */
void worker_new_con(worker *ctx, worker *wrk, sock_addr *remote_addr, int s) {
void worker_new_con(worker *ctx, worker *wrk, sockaddr_t remote_addr, int s, server_socket *srv_sock) {
if (ctx == wrk) {
connection *con = worker_con_get(wrk);
con->srv_sock = srv_sock;
con->state = CON_STATE_REQUEST_START;
con->remote_addr = *remote_addr;
con->remote_addr = remote_addr;
ev_io_set(&con->sock_watcher, s, EV_READ);
ev_io_start(wrk->loop, &con->sock_watcher);
con->ts = CUR_TS(con->wrk);
@ -214,8 +216,9 @@ void worker_new_con(worker *ctx, worker *wrk, sock_addr *remote_addr, int s) {
waitqueue_push(&wrk->io_timeout_queue, &con->io_timeout_elem);
} else {
worker_new_con_data *d = g_slice_new(worker_new_con_data);
d->remote_addr = *remote_addr;
d->remote_addr = remote_addr;
d->s = s;
d->srv_sock = srv_sock;
g_async_queue_push(wrk->new_con_queue, d);
ev_async_send(wrk->loop, &wrk->new_con_watcher);
}
@ -228,7 +231,7 @@ static void worker_new_con_cb(struct ev_loop *loop, ev_async *w, int revents) {
UNUSED(revents);
while (NULL != (d = g_async_queue_try_pop(wrk->new_con_queue))) {
worker_new_con(wrk, wrk, &d->remote_addr, d->s);
worker_new_con(wrk, wrk, d->remote_addr, d->s, d->srv_sock);
g_slice_free(worker_new_con_data, d);
}
}