Merge branch 'master' into my-osx
[paraslash.git] / dccp_send.c
1 /*
2 * Copyright (C) 2006 Andre Noll <maan@systemlinux.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
17 */
18
19 /** \file dccp_send.c paraslash's dccp sender */
20
21 /*
22 * based on server.c of dccp-cs-0.01.tar.bz2,
23 * (C) 2005 Ian McDonald <imcdnzl@gmail.com>
24 */
25
26 #include "server.h"
27 #include "net.h"
28 #include "list.h"
29 #include "afs.h"
30 #include "send.h"
31 #include "dccp.h"
32 #include "error.h"
33 #include "string.h"
34 #include "fd.h"
35 #include "close_on_fork.h"
36 #include "server.cmdline.h"
37
38 /** the list of connected clients **/
39 static struct list_head clients;
40 static int listen_fd = -1;
41 static struct sender *self;
42
43 /** describes one connected client */
44 struct dccp_client {
45 /** the dccp socket */
46 int fd;
47 /** address information about the client */
48 struct sockaddr_in addr;
49 /** the position of this client in the client list */
50 struct list_head node;
51 /** non-zero if audio file header has been sent */
52 int header_sent;
53 };
54
55 static void dccp_pre_select( int *max_fileno, fd_set *rfds,
56 __a_unused fd_set *wfds)
57 {
58 if (listen_fd < 0)
59 return;
60 FD_SET(listen_fd, rfds);
61 *max_fileno = PARA_MAX(*max_fileno, listen_fd);
62 }
63
64 static void dccp_post_select(fd_set *rfds, __a_unused fd_set *wfds)
65 {
66 struct dccp_client *dc;
67 int ret;
68
69 if (!FD_ISSET(listen_fd, rfds))
70 return;
71 dc = para_calloc(sizeof(struct dccp_client));
72 ret = para_accept(listen_fd, &dc->addr, sizeof(struct sockaddr_in));
73 if (ret < 0) {
74 PARA_ERROR_LOG("%s", PARA_STRERROR(-ret));
75 return;
76 }
77 PARA_NOTICE_LOG("connection from %s\n", inet_ntoa(dc->addr.sin_addr));
78 dc->fd = ret;
79 list_add(&dc->node, &clients);
80 add_close_on_fork_list(dc->fd);
81 mark_fd_nonblock(dc->fd);
82 }
83
84 static int dccp_open(void)
85 {
86 struct sockaddr_in servaddr;
87 int ret;
88
89 ret = dccp_get_socket();
90 if (ret < 0)
91 return ret;
92 listen_fd = ret;
93
94 bzero(&servaddr, sizeof(servaddr));
95 servaddr.sin_family = AF_INET;
96 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
97 servaddr.sin_port = htons(conf.dccp_port_arg);
98 ret = bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
99 if (ret < 0)
100 return -E_DCCP_BIND;
101 ret = dccp_set_socket(listen_fd);
102 if (ret < 0)
103 return ret;
104 ret = listen(listen_fd, 0);
105 if (ret < 0)
106 return -E_DCCP_LISTEN;
107 PARA_DEBUG_LOG("listening on fd %d\n", listen_fd);
108 add_close_on_fork_list(listen_fd);
109 mark_fd_nonblock(listen_fd);
110 return 1;
111 }
112
113 static void dccp_shutdown_client(struct dccp_client *dc)
114 {
115 PARA_DEBUG_LOG("shutting down %s (fd %d)\n", inet_ntoa(dc->addr.sin_addr),
116 dc->fd);
117 close(dc->fd);
118 del_close_on_fork_list(dc->fd);
119 list_del(&dc->node);
120 free(dc);
121 }
122
123 #define DCCP_RETRIES 100
124
125 static int dccp_write(int fd, const char *buf, size_t len)
126 {
127 size_t size, written = 0;
128 int ret, retries = 0;
129 again:
130 size = PARA_MIN(1024, len - written);
131 ret = write(fd, buf + written, size);
132 if (ret < 0) {
133 if (errno != EAGAIN || !retries++ > DCCP_RETRIES)
134 goto err_out;
135 PARA_DEBUG_LOG("EAGAIN #%d@%d/%d\n", retries, written, len);
136 goto again;
137 }
138 retries = 0;
139 written += ret;
140 if (written >= len)
141 return written;
142 ret = write_ok(fd);
143 if (ret > 0)
144 goto again;
145 err_out:
146 return -E_DCCP_WRITE;
147 }
148
149 static void dccp_send(long unsigned current_chunk,
150 __a_unused long unsigned chunks_sent, const char *buf, size_t len)
151 {
152 struct dccp_client *dc, *tmp;
153 int ret, header_len;
154 char *header_buf;
155
156 if (listen_fd < 0 || !len)
157 return;
158
159 list_for_each_entry_safe(dc, tmp, &clients, node) {
160 ret = write_ok(dc->fd);
161 if (ret < 0) {
162 dccp_shutdown_client(dc);
163 continue;
164 }
165 if (!ret)
166 continue;
167 if (!dc->header_sent && current_chunk) {
168 header_buf = afs_get_header(&header_len);
169 if (header_buf && header_len > 0) {
170 ret = dccp_write(dc->fd, header_buf, header_len);
171 if (ret != header_len) {
172 int err = errno;
173 PARA_ERROR_LOG("header write: %d/%d (%s)\n",
174 ret, header_len, ret < 0?
175 strerror(err) : "");
176 dccp_shutdown_client(dc);
177 continue;
178 }
179 dc->header_sent = 1;
180 ret = write_ok(dc->fd);
181 if (ret < 0) {
182 dccp_shutdown_client(dc);
183 continue;
184 }
185 if (!ret)
186 continue;
187 }
188 }
189 // PARA_DEBUG_LOG("writing %d bytes to fd %d\n", len, dc->fd);
190 ret = dccp_write(dc->fd, buf, len);
191 if (ret != len)
192 dccp_shutdown_client(dc);
193 }
194 }
195
196 static void dccp_shutdown_clients(void)
197 {
198 struct dccp_client *dc, *tmp;
199
200 list_for_each_entry_safe(dc, tmp, &clients, node)
201 dccp_shutdown_client(dc);
202 }
203
204 static char *dccp_info(void)
205 {
206 static char *buf;
207 int num_clients = 0;
208 struct dccp_client *dc, *tmp;
209
210 free(buf);
211 list_for_each_entry_safe(dc, tmp, &clients, node)
212 num_clients++;
213 buf = make_message("dccp connected clients: %d\n", num_clients);
214 return buf;
215 }
216
217 static char *dccp_help(void)
218 {
219 return make_message("no help available\n");
220 }
221
222 /**
223 * the init function of the dccp sender
224 *
225 * \param s pointer to the dccp sender struct
226 *
227 * It initializes all function pointers of \a s and starts
228 * listening on the given port.
229 */
230 void dccp_send_init(struct sender *s)
231 {
232 int ret;
233
234 INIT_LIST_HEAD(&clients);
235 s->info = dccp_info;
236 s->send = dccp_send;
237 s->pre_select = dccp_pre_select;
238 s->post_select = dccp_post_select;
239 s->shutdown_clients = dccp_shutdown_clients;
240 s->help = dccp_help;
241 s->client_cmds[SENDER_ON] = NULL;
242 s->client_cmds[SENDER_OFF] = NULL;
243 s->client_cmds[SENDER_DENY] = NULL;
244 s->client_cmds[SENDER_ALLOW] = NULL;
245 s->client_cmds[SENDER_ADD] = NULL;
246 s->client_cmds[SENDER_DELETE] = NULL;
247 self = s;
248 ret = dccp_open();
249 if (ret < 0) {
250 PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
251 s->status = SENDER_OFF;
252 } else
253 s->status = SENDER_ON;
254 }