Make the http sender use the generic sender code.
[paraslash.git] / dccp_send.c
1 /*
2  * Copyright (C) 2006-2008 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file dccp_send.c paraslash's dccp sender */
8
9 /*
10  * based on server.c of dccp-cs-0.01.tar.bz2,
11  * (C) 2005 Ian McDonald <imcdnzl@gmail.com>
12  */
13
14 #include <sys/types.h>
15 #include <dirent.h>
16
17 #include "para.h"
18 #include "error.h"
19 #include "string.h"
20 #include "afh.h"
21 #include "afs.h"
22 #include "server.h"
23 #include "net.h"
24 #include "list.h"
25 #include "vss.h"
26 #include "send.h"
27 #include "fd.h"
28 #include "close_on_fork.h"
29 #include "chunk_queue.h"
30 #include "server.cmdline.h"
31
32 /** the list of connected clients **/
33 static struct list_head clients;
34 static int listen_fd = -1;
35
36 /** Maximal number of bytes in a chunk queue. */
37 #define DCCP_MAX_PENDING_BYTES 40000
38
39 /** Do not write more than that many bytes at once. */
40 #define DCCP_MAX_BYTES_PER_WRITE 1024
41
42 static void dccp_pre_select(int *max_fileno, fd_set *rfds,
43                 __a_unused fd_set *wfds)
44 {
45         if (listen_fd >= 0)
46                 para_fd_set(listen_fd, rfds, max_fileno);
47 }
48
49 static void dccp_post_select(fd_set *rfds, __a_unused fd_set *wfds)
50 {
51         struct sender_client *sc;
52         int ret, fd;
53
54         if (listen_fd < 0 || !FD_ISSET(listen_fd, rfds))
55                 return;
56         ret = para_accept(listen_fd, NULL, 0);
57         if (ret < 0) {
58                 PARA_ERROR_LOG("%s\n", para_strerror(-ret));
59                 return;
60         }
61         fd = ret;
62         /*
63          * Bypass unused CCID paths: the sender does not receive application data
64          * from the client; by shutting down this unused communication path we can
65          * reduce processing costs a bit. See analogous comment in dccp_recv.c.
66          */
67         if (shutdown(fd, SHUT_RD) < 0) {
68                 ret = -ERRNO_TO_PARA_ERROR(errno);
69                 goto err;
70         }
71         ret = mark_fd_nonblocking(fd);
72         if (ret < 0)
73                 goto err;
74         sc = para_calloc(sizeof(*sc));
75         sc->fd = fd;
76         sc->name = make_message("%s", remote_name(sc->fd));
77         PARA_NOTICE_LOG("connection from %s\n", sc->name);
78         para_list_add(&sc->node, &clients);
79         add_close_on_fork_list(sc->fd);
80         sc->cq = cq_new(DCCP_MAX_PENDING_BYTES);
81         return;
82 err:
83         PARA_ERROR_LOG("%s\n", para_strerror(-ret));
84         close(fd);
85 }
86
87 static void dccp_send(long unsigned current_chunk,
88                 __a_unused long unsigned chunks_sent, const char *buf, size_t len)
89 {
90         struct sender_client *sc, *tmp;
91
92         list_for_each_entry_safe(sc, tmp, &clients, node)
93                 send_chunk(sc, DCCP_MAX_BYTES_PER_WRITE, current_chunk, buf,
94                         len);
95 }
96
97 static void dccp_shutdown_clients(void)
98 {
99         struct sender_client *sc, *tmp;
100
101         list_for_each_entry_safe(sc, tmp, &clients, node)
102                 shutdown_client(sc);
103 }
104
105 static char *dccp_info(void)
106 {
107         static char *buf;
108         int num_clients = 0;
109         struct sender_client *sc, *tmp;
110
111         free(buf);
112         list_for_each_entry_safe(sc, tmp, &clients, node)
113                 num_clients++;
114         buf = make_message("dccp connected clients: %d\n", num_clients);
115         return buf;
116 }
117
118 static char *dccp_help(void)
119 {
120         return make_message("no help available\n");
121 }
122
123 /**
124  * The init function of the dccp sender.
125  *
126  * \param s pointer to the dccp sender struct.
127  *
128  * It initializes all function pointers of \a s and starts
129  * listening on the given port.
130  */
131 void dccp_send_init(struct sender *s)
132 {
133         int ret;
134
135         INIT_LIST_HEAD(&clients);
136         s->info = dccp_info;
137         s->send = dccp_send;
138         s->pre_select = dccp_pre_select;
139         s->post_select = dccp_post_select;
140         s->shutdown_clients = dccp_shutdown_clients;
141         s->help = dccp_help;
142         s->client_cmds[SENDER_ON] = NULL;
143         s->client_cmds[SENDER_OFF] = NULL;
144         s->client_cmds[SENDER_DENY] = NULL;
145         s->client_cmds[SENDER_ALLOW] = NULL;
146         s->client_cmds[SENDER_ADD] = NULL;
147         s->client_cmds[SENDER_DELETE] = NULL;
148         ret = open_sender(IPPROTO_DCCP, conf.dccp_port_arg);
149         if (ret < 0)
150                 PARA_ERROR_LOG("%s\n", para_strerror(-ret));
151         else
152                 listen_fd = ret;
153 }