]> git.tuebingen.mpg.de Git - paraslash.git/blob - dccp_send.c
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 }