ace92dee9f13ae2037e34279751494bf4245a00e
[paraslash.git] / dccp_send.c
1 #include "server.h"
2 #include "net.h"
3 #include "list.h"
4 #include "afs.h"
5 #include "send.h"
6 #include "dccp.h"
7 #include "error.h"
8 #include "string.h"
9 #include "server.cmdline.h"
10 extern struct gengetopt_args_info conf;
11 /** the list of connected clients **/
12 static struct list_head clients;
13 static int listen_fd = -1;
14 static struct sender *self;
15
16 /** describes one connected client */
17 struct dccp_client {
18 /** the dccp socket */
19 int fd;
20 /** address information about the client */
21 struct sockaddr_in addr;
22 /** the position of this client in the client list */
23 struct list_head node;
24 int header_sent; /* non-zero if audio file header has been sent */
25 };
26
27 static void dccp_pre_select(__unused struct audio_format *af, int *max_fileno, fd_set *rfds,
28 __unused fd_set *wfds)
29 {
30 if (listen_fd < 0)
31 return;
32 FD_SET(listen_fd, rfds);
33 *max_fileno = MAX(*max_fileno, listen_fd);
34 }
35
36 static void dccp_post_select(__unused struct audio_format *af, fd_set *rfds,
37 __unused fd_set *wfds)
38 {
39 struct dccp_client *dc;
40 int ret;
41
42 if (!FD_ISSET(listen_fd, rfds))
43 return;
44 PARA_NOTICE_LOG("%s", "accepting...\n");
45 dc = para_calloc(sizeof(struct dccp_client));
46 ret = para_accept(listen_fd, &dc->addr, sizeof(struct sockaddr_in));
47 if (ret < 0) {
48 PARA_ERROR_LOG("%s", PARA_STRERROR(-ret));
49 return;
50 }
51 PARA_NOTICE_LOG("%s", "connection\n");
52 dc->fd = ret;
53 list_add(&dc->node, &clients);
54 }
55
56 static int dccp_open(void)
57 {
58 struct sockaddr_in servaddr;
59 int ret;
60
61 ret = dccp_get_socket();
62 if (ret < 0)
63 return ret;
64 listen_fd = ret;
65
66 bzero(&servaddr, sizeof(servaddr));
67 servaddr.sin_family = AF_INET;
68 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
69 servaddr.sin_port = htons(conf.dccp_port_arg);
70 ret = bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
71 if (ret < 0)
72 return -E_DCCP_BIND;
73 ret = dccp_set_socket(listen_fd);
74 if (ret < 0)
75 return ret;
76 ret = listen(listen_fd, 0);
77 if (ret < 0)
78 return -E_DCCP_LISTEN;
79 PARA_DEBUG_LOG("listening on fd %d\n", listen_fd);
80 return 1;
81 }
82
83 static void dccp_shutdown_client(struct dccp_client *dc)
84 {
85 close(dc->fd);
86 list_del(&dc->node);
87 free(dc);
88 }
89
90 static void dccp_send(__unused struct audio_format *af,
91 long unsigned current_chunk,
92 __unused long unsigned chunks_sent, const char *buf, size_t len)
93 {
94 struct dccp_client *dc, *tmp;
95 int ret, header_len;
96 char *header_buf;
97
98 if (listen_fd < 0 || !len)
99 return;
100
101 list_for_each_entry_safe(dc, tmp, &clients, node) {
102 if (!_write_ok(dc->fd))
103 continue;
104 if (!dc->header_sent && af->get_header_info && current_chunk) {
105 header_buf = af->get_header_info(&header_len);
106 if (!header_buf || header_len <= 0)
107 continue; /* header not yet available */
108 ret = write(dc->fd, header_buf, header_len);
109 if (ret != header_len) {
110 dccp_shutdown_client(dc);
111 continue;
112 }
113 if (!_write_ok(dc->fd))
114 continue;
115 }
116 PARA_DEBUG_LOG("writing %d bytes to fd %d\n", len, dc->fd);
117 ret = write(dc->fd, buf, len);
118 if (ret != len)
119 dccp_shutdown_client(dc);
120 }
121 }
122
123 static void dccp_shutdown_clients(void)
124 {
125 struct dccp_client *dc, *tmp;
126
127 list_for_each_entry_safe(dc, tmp, &clients, node)
128 dccp_shutdown_client(dc);
129 }
130
131 static char *dccp_info(void)
132 {
133 static char *buf;
134 int num_clients = 0;
135 struct dccp_client *dc, *tmp;
136
137 free(buf);
138 list_for_each_entry_safe(dc, tmp, &clients, node)
139 num_clients++;
140 buf = make_message("%d connected clients\n", num_clients);
141 return buf;
142 }
143
144 static char *dccp_help(void)
145 {
146 return make_message("no help available\n");
147 }
148
149 void dccp_send_init(struct sender *s)
150 {
151 int ret;
152
153 INIT_LIST_HEAD(&clients);
154 s->info = dccp_info;
155 s->send = dccp_send;
156 s->pre_select = dccp_pre_select;
157 s->post_select = dccp_post_select;
158 s->shutdown_clients = dccp_shutdown_clients;
159 s->help = dccp_help;
160 s->client_cmds[SENDER_ON] = NULL;
161 s->client_cmds[SENDER_OFF] = NULL;
162 s->client_cmds[SENDER_DENY] = NULL;
163 s->client_cmds[SENDER_ALLOW] = NULL;
164 s->client_cmds[SENDER_ADD] = NULL;
165 s->client_cmds[SENDER_DELETE] = NULL;
166 self = s;
167 ret = dccp_open();
168 if (ret < 0)
169 PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
170 else
171 s->status = SENDER_ON;
172 }