X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=http_send.c;h=6ededb275ac225d8a38d6ccbead967d53877fad4;hp=ce2fd09c45ac71215dda23370b73faaf75fb8dc6;hb=5587494468627e20fe622b6055689717262d09ab;hpb=08d6590e06651c856015f785d89b43044081a224 diff --git a/http_send.c b/http_send.c index ce2fd09c..6ededb27 100644 --- a/http_send.c +++ b/http_send.c @@ -1,13 +1,15 @@ /* - * Copyright (C) 2005-2008 Andre Noll + * Copyright (C) 2005-2009 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ /** \file http_send.c paraslash's http sender */ +#include #include #include +#include #include "para.h" #include "error.h" @@ -29,9 +31,8 @@ /** Message sent to clients that do not send a valid get request. */ #define HTTP_ERR_MSG "HTTP/1.0 400 Bad Request\n" - /** The possible states of a client from the server's POV. */ -enum http_status { +enum http_client_status { /** We accepted the connection on the tcp socket. */ HTTP_CONNECTED, /** Successfully received the get request. */ @@ -42,25 +43,20 @@ enum http_status { HTTP_INVALID_GET_REQUEST }; -/** Clients will be kicked if there are more than that many bytes pending. */ -#define MAX_BACKLOG 400000 -/** The list of connected clients. */ -static struct list_head clients; -/** The whitelist/blacklist. */ -static struct list_head http_acl; - -static int listen_fd = -1, numclients; - +/** For each connected client, a structure of this type is maintained. */ struct private_http_sender_data { - enum http_status status; + /** The current state of this client. */ + enum http_client_status status; }; +static struct sender_status http_sender_status, *hss = &http_sender_status; + static int http_send_msg(struct sender_client *sc, const char *msg) { int ret = send_buffer(sc->fd, msg); if (ret < 0) - shutdown_client(sc); + shutdown_client(sc, hss); return ret; } @@ -78,33 +74,32 @@ static int http_send_err_msg(struct sender_client *sc) static void http_shutdown_clients(void) { - struct sender_client *sc, *tmp; - list_for_each_entry_safe(sc, tmp, &clients, node) - shutdown_client(sc); + shutdown_clients(hss); } static void http_send(long unsigned current_chunk, - __a_unused long unsigned chunks_sent, const char *buf, size_t len) + __a_unused long unsigned chunks_sent, const char *buf, size_t len, + const char *header_buf, size_t header_len) { struct sender_client *sc, *tmp; - list_for_each_entry_safe(sc, tmp, &clients, node) { + list_for_each_entry_safe(sc, tmp, &hss->client_list, node) { struct private_http_sender_data *phsd = sc->private_data; if (phsd->status != HTTP_STREAMING) continue; - send_chunk(sc, 0, current_chunk, buf, len); + send_chunk(sc, hss, 0, current_chunk, buf, len, header_buf, + header_len); } } static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds) { - int ret, match; struct sender_client *sc, *tmp; struct private_http_sender_data *phsd; - if (listen_fd < 0) + if (hss->listen_fd < 0) return; - list_for_each_entry_safe(sc, tmp, &clients, node) { + list_for_each_entry_safe(sc, tmp, &hss->client_list, node) { phsd = sc->private_data; switch (phsd->status) { case HTTP_STREAMING: /* nothing to do */ @@ -116,8 +111,7 @@ static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds) phsd->status = HTTP_INVALID_GET_REQUEST; } else { phsd->status = HTTP_GOT_GET_REQUEST; - PARA_INFO_LOG("%s", - "received get request\n"); + PARA_INFO_LOG("received get request\n"); } } break; @@ -127,141 +121,63 @@ static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds) break; case HTTP_INVALID_GET_REQUEST: /* need to send err msg */ if (http_send_err_msg(sc) >= 0) - shutdown_client(sc); + shutdown_client(sc, hss); break; } } - if (!FD_ISSET(listen_fd, rfds)) + if (!FD_ISSET(hss->listen_fd, rfds)) return; - ret = para_accept(listen_fd, NULL, 0); - if (ret < 0) { - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + sc = accept_sender_client(hss); + if (!sc) return; - } - sc = para_calloc(sizeof(*sc)); - sc->fd = ret; - sc->name = make_message("%s", remote_name(sc->fd)); - PARA_NOTICE_LOG("connection from %s (fd %d)\n", sc->name, sc->fd); - ret = -E_MAX_CLIENTS; - if (conf.http_max_clients_arg > 0 && numclients >= - conf.http_max_clients_arg) { - goto err_out; - } - match = acl_lookup(sc->fd, &http_acl); - PARA_DEBUG_LOG("acl lookup returned %d\n", match); - ret = -E_ACL_PERM; - if ((match && !conf.http_default_deny_given) || - (!match && conf.http_default_deny_given)) - goto err_out; - ret = mark_fd_nonblocking(sc->fd); - if (ret < 0) - goto err_out; phsd = para_malloc(sizeof(*phsd)); sc->private_data = phsd; phsd->status = HTTP_CONNECTED; - sc->cq = cq_new(MAX_BACKLOG); - numclients++; - PARA_INFO_LOG("accepted client #%d: %s (fd %d)\n", numclients, - sc->name, sc->fd); - para_list_add(&sc->node, &clients); - add_close_on_fork_list(sc->fd); - return; -err_out: - PARA_WARNING_LOG("%s\n", para_strerror(-ret)); - close(sc->fd); - free(sc); } -static void http_pre_select(int *max_fileno, fd_set *rfds, __a_unused fd_set *wfds) +static void http_pre_select(int *max_fileno, fd_set *rfds, fd_set *wfds) { struct sender_client *sc, *tmp; - if (listen_fd < 0) + if (hss->listen_fd < 0) return; - para_fd_set(listen_fd, rfds, max_fileno); - list_for_each_entry_safe(sc, tmp, &clients, node) { + para_fd_set(hss->listen_fd, rfds, max_fileno); + list_for_each_entry_safe(sc, tmp, &hss->client_list, node) { struct private_http_sender_data *phsd = sc->private_data; if (phsd->status == HTTP_CONNECTED) /* need to recv get request */ para_fd_set(sc->fd, rfds, max_fileno); + if (phsd->status == HTTP_GOT_GET_REQUEST || + phsd->status == HTTP_INVALID_GET_REQUEST) + para_fd_set(sc->fd, wfds, max_fileno); } } static int http_com_on(__a_unused struct sender_command_data *scd) { - if (listen_fd >= 0) - return 1; - return open_sender(IPPROTO_TCP, conf.http_port_arg); + return generic_com_on(hss, IPPROTO_TCP); } static int http_com_off(__a_unused struct sender_command_data *scd) { - if (listen_fd < 0) - return 1; - PARA_NOTICE_LOG("closing http port %d\n", conf.http_port_arg); - close(listen_fd); - del_close_on_fork_list(listen_fd); - http_shutdown_clients(); - listen_fd = -1; + generic_com_off(hss); return 1; } static int http_com_deny(struct sender_command_data *scd) { - if (conf.http_default_deny_given) - acl_del_entry(&http_acl, scd->addr, scd->netmask); - else - acl_add_entry(&http_acl, scd->addr, scd->netmask); + generic_com_deny(scd, hss); return 1; } static int http_com_allow(struct sender_command_data *scd) { - if (conf.http_default_deny_given) - acl_add_entry(&http_acl, scd->addr, scd->netmask); - else - acl_del_entry(&http_acl, scd->addr, scd->netmask); + generic_com_allow(scd, hss); return 1; } static char *http_info(void) { - char *clnts = NULL, *ret; - struct sender_client *sc, *tmp_sc; - - char *acl_contents = acl_get_contents(&http_acl); - list_for_each_entry_safe(sc, tmp_sc, &clients, node) { - char *tmp = make_message("%s%s ", clnts? clnts : "", sc->name); - free(clnts); - clnts = tmp; - } - ret = make_message( - "http status: %s\n" - "http tcp port: %d\n" - "http clients: %d\n" - "http maximal number of clients: %d%s\n" - "http connected clients: %s\n" - "http access %s list: %s\n", - (listen_fd >= 0)? "on" : "off", - conf.http_port_arg, - numclients, - conf.http_max_clients_arg, - conf.http_max_clients_arg > 0? "" : " (unlimited)", - clnts? clnts : "(none)", - conf.http_default_deny_given? "allow" : "deny", - acl_contents? acl_contents : "(none)" - ); - free(acl_contents); - free(clnts); - return ret; -} - -static char *http_help(void) -{ - return make_message( - "usage: {on|off}\n" - "usage: {allow|deny} IP mask\n" - "example: allow 127.0.0.1 32\n" - ); + return get_sender_info(hss, "http"); } /** @@ -275,25 +191,25 @@ static char *http_help(void) void http_send_init(struct sender *s) { int ret; - INIT_LIST_HEAD(&clients); s->info = http_info; s->send = http_send; s->pre_select = http_pre_select; s->post_select = http_post_select; s->shutdown_clients = http_shutdown_clients; - s->help = http_help; + s->help = generic_sender_help; s->client_cmds[SENDER_ON] = http_com_on; s->client_cmds[SENDER_OFF] = http_com_off; s->client_cmds[SENDER_DENY] = http_com_deny; s->client_cmds[SENDER_ALLOW] = http_com_allow; s->client_cmds[SENDER_ADD] = NULL; s->client_cmds[SENDER_DELETE] = NULL; - acl_init(&http_acl, conf.http_access_arg, conf.http_access_given); + + init_sender_status(hss, conf.http_access_arg, conf.http_access_given, + conf.http_port_arg, conf.http_max_clients_arg, + conf.http_default_deny_given); if (conf.http_no_autostart_given) return; - ret = open_sender(IPPROTO_TCP, conf.http_port_arg); + ret = generic_com_on(hss, IPPROTO_TCP); if (ret < 0) PARA_ERROR_LOG("%s\n", para_strerror(-ret)); - else - listen_fd = ret; }