paraslash 0.7.3
[paraslash.git] / http_send.c
index 210f85ac63c9dd718a3f00e6a6e9790ffeeb5d96..429b4662a70497d522fd68a0e3467941e7edc959 100644 (file)
 #include "server.h"
 #include "http.h"
 #include "list.h"
-#include "send.h"
 #include "sched.h"
+#include "send.h"
 #include "vss.h"
 #include "close_on_fork.h"
 #include "fd.h"
 #include "chunk_queue.h"
-#include "acl.h"
 
 /** Message sent to clients that do not send a valid get request. */
 #define HTTP_ERR_MSG "HTTP/1.0 400 Bad Request\n"
@@ -77,6 +76,13 @@ static void http_shutdown_clients(void)
        shutdown_clients(hss);
 }
 
+static void http_shutdown(void)
+{
+       http_shutdown_clients();
+       generic_acl_deplete(&hss->acl);
+       free_sender_status(hss);
+}
+
 static int queue_chunk_or_shutdown(struct sender_client *sc,
                struct sender_status *ss, const char *buf, size_t num_bytes)
 {
@@ -152,7 +158,7 @@ static void http_send(long unsigned current_chunk,
        }
 }
 
-static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds)
+static void http_post_monitor(__a_unused struct sched *s)
 {
        struct sender_client *sc, *tmp;
        struct private_http_sender_data *phsd;
@@ -164,7 +170,7 @@ static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds)
                case HTTP_STREAMING: /* nothing to do */
                        break;
                case HTTP_CONNECTED: /* need to recv get request */
-                       ret = read_pattern(sc->fd, HTTP_GET_MSG, MAXLINE, rfds);
+                       ret = read_and_compare(sc->fd, HTTP_GET_MSG);
                        if (ret < 0)
                                phsd->status = HTTP_INVALID_GET_REQUEST;
                        else if (ret > 0) {
@@ -182,28 +188,31 @@ static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds)
                        break;
                }
        }
-       sc = accept_sender_client(hss, rfds);
+       sc = accept_sender_client(hss);
        if (!sc)
                return;
-       phsd = para_malloc(sizeof(*phsd));
+       phsd = alloc(sizeof(*phsd));
        sc->private_data = phsd;
        phsd->status = HTTP_CONNECTED;
 }
 
-static void http_pre_select(int *max_fileno, fd_set *rfds, fd_set *wfds)
+static void http_pre_monitor(struct sched *s)
 {
        struct sender_client *sc, *tmp;
+       unsigned n;
 
-       if (hss->listen_fd < 0)
-               return;
-       para_fd_set(hss->listen_fd, rfds, max_fileno);
+       FOR_EACH_LISTEN_FD(n, hss) {
+               if (hss->listen_fds[n] < 0)
+                       continue;
+               sched_monitor_readfd(hss->listen_fds[n], s);
+       }
        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);
+                       sched_monitor_readfd(sc->fd, s);
                if (phsd->status == HTTP_GOT_GET_REQUEST ||
                                phsd->status == HTTP_INVALID_GET_REQUEST)
-                       para_fd_set(sc->fd, wfds, max_fileno);
+                       sched_monitor_writefd(sc->fd, s);
        }
 }
 
@@ -236,34 +245,45 @@ static char *http_status(void)
        return generic_sender_status(hss, "http");
 }
 
-/**
- * The init function of the http sender.
- *
- * \param s Pointer to the http sender struct.
- *
- * It initializes all function pointers of \a s, the client list and the access
- * control list. If the autostart option was given, the tcp port is opened.
+/*
+ * Initialize the client list and the access control list, and optionally
+ * listen on the tcp port.
  */
-void http_send_init(struct sender *s)
+static void http_send_init(void)
 {
-       s->status = http_status;
-       s->send = http_send;
-       s->pre_select = http_pre_select;
-       s->post_select = http_post_select;
-       s->shutdown_clients = http_shutdown_clients;
-       s->resolve_target = NULL;
-       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;
-
        init_sender_status(hss, OPT_RESULT(HTTP_ACCESS),
+               OPT_RESULT(HTTP_LISTEN_ADDRESS),
                OPT_UINT32_VAL(HTTP_PORT), OPT_UINT32_VAL(HTTP_MAX_CLIENTS),
                OPT_GIVEN(HTTP_DEFAULT_DENY));
        if (OPT_GIVEN(HTTP_NO_AUTOSTART))
                return;
        generic_com_on(hss, IPPROTO_TCP);
 }
+
+/**
+ * The HTTP sender.
+ *
+ * This is the only sender which does not FEC-encode the stream. This is not
+ * necessary because HTTP sits on top of TCP, a reliable transport which
+ * retransmits lost packets automatically. The sender employs per-client queues
+ * which queue chunks of audio data if they can not be sent immediately because
+ * the write operation would block. Most methods of the sender are implemented
+ * as wrappers for the generic functions defined in \ref send_common.c.
+ */
+const struct sender http_sender = {
+       .name = "http",
+       .init = http_send_init,
+       .shutdown = http_shutdown,
+       .pre_monitor = http_pre_monitor,
+       .post_monitor = http_post_monitor,
+       .send = http_send,
+       .shutdown_clients = http_shutdown_clients,
+       .client_cmds = {
+               [SENDER_on] = http_com_on,
+               [SENDER_off] = http_com_off,
+               [SENDER_deny] = http_com_deny,
+               [SENDER_allow] = http_com_allow,
+       },
+       .help = generic_sender_help,
+       .status = http_status,
+};