1
2 /*
3 * Code to support SCTP connections
4 */
5
6 #include "config.h"
7
8 #ifdef USE_SCTP
9
10 #include <errno.h>
11 #include <string.h>
12 #include <strings.h>
13 #include <stdio.h>
14 #include <netinet/sctp.h>
15
16 #include "hmalloc.h"
17 #include "hlog.h"
18 #include "worker.h"
19 #include "sctp.h"
20
sctp_set_client_sockopt(struct client_t * c)21 int sctp_set_client_sockopt(struct client_t *c)
22 {
23 struct sctp_sndrcvinfo sri;
24 socklen_t len;
25
26 /* default sendmsg() parameters */
27 len = sizeof(sri);
28 if (getsockopt(c->fd, IPPROTO_SCTP, SCTP_DEFAULT_SEND_PARAM, (char *)&sri, &len) == -1) {
29 hlog(LOG_ERR, "getsockopt(%s, SCTP_DEFAULT_SEND_PARAM): %s", c->addr_rem, strerror(errno));
30 return -1;
31 }
32
33 sri.sinfo_flags = SCTP_UNORDERED;
34
35 if (setsockopt(c->fd, IPPROTO_SCTP, SCTP_DEFAULT_SEND_PARAM, (char *)&sri, len) == -1) {
36 hlog(LOG_ERR, "setsockopt(%s, SCTP_DEFAULT_SEND_PARAM): %s", c->addr_rem, strerror(errno));
37 return -1;
38 }
39
40 /* which notifications do we want? */
41 struct sctp_event_subscribe subscribe;
42
43 memset(&subscribe, 0, sizeof(subscribe));
44
45 subscribe.sctp_shutdown_event = 1;
46 subscribe.sctp_association_event = 1;
47 subscribe.sctp_address_event = 1;
48 subscribe.sctp_send_failure_event = 1;
49 subscribe.sctp_peer_error_event = 1;
50 subscribe.sctp_partial_delivery_event = 1;
51
52 if (setsockopt(c->fd, IPPROTO_SCTP, SCTP_EVENTS, (char *)&subscribe, sizeof(subscribe)) == -1) {
53 hlog(LOG_ERR, "setsockopt(%s, SCTP_EVENTS): %s", c->addr_rem, strerror(errno));
54 return -1;
55 }
56
57 return 0;
58 }
59
60 /*
61 * Set parameters for a listener socket
62 */
63
sctp_set_listen_params(struct listen_t * l)64 int sctp_set_listen_params(struct listen_t *l)
65 {
66 struct sctp_event_subscribe subscribe;
67
68 memset(&subscribe, 0, sizeof(subscribe));
69
70 subscribe.sctp_data_io_event = 1;
71 subscribe.sctp_association_event = 1;
72
73 if (setsockopt(l->fd, IPPROTO_SCTP, SCTP_EVENTS, (char *)&subscribe, sizeof(subscribe)) == -1) {
74 hlog(LOG_ERR, "setsockopt(%s, SCTP_EVENTS): %s", l->addr_s, strerror(errno));
75 return -1;
76 }
77
78 return l->fd;
79 }
80
81 /*
82 * SCTP notification received
83 */
84
sctp_rx_assoc_change(struct client_t * c,union sctp_notification * sn)85 static int sctp_rx_assoc_change(struct client_t *c, union sctp_notification *sn)
86 {
87 switch (sn->sn_assoc_change.sac_state) {
88 case SCTP_COMM_UP:
89 hlog(LOG_DEBUG, "%s/%s: Received SCTP_COMM_UP", c->addr_rem, c->username);
90 break;
91 case SCTP_COMM_LOST:
92 hlog(LOG_DEBUG, "%s/%s: Received SCTP_COMM_LOST", c->addr_rem, c->username);
93 break;
94 case SCTP_RESTART:
95 hlog(LOG_DEBUG, "%s/%s: Received SCTP_RESTART", c->addr_rem, c->username);
96 break;
97 case SCTP_SHUTDOWN_COMP:
98 hlog(LOG_DEBUG, "%s/%s: Received SCTP_SHUTDOWN_COMP", c->addr_rem, c->username);
99 break;
100 case SCTP_CANT_STR_ASSOC:
101 hlog(LOG_DEBUG, "%s/%s: Received SCTP_CANT_STR_ASSOC", c->addr_rem, c->username);
102 break;
103 default:
104 hlog(LOG_DEBUG, "%s/%s: SCTP Received unexpected assoc_change %d", c->addr_rem, c->username, sn->sn_assoc_change.sac_state);
105 break;
106 }
107
108 if (sn->sn_assoc_change.sac_state == SCTP_COMM_UP)
109 return sn->sn_assoc_change.sac_assoc_id;
110
111 return 0;
112
113 }
114
sctp_rx_peer_addr_change(struct client_t * c,union sctp_notification * sn)115 static int sctp_rx_peer_addr_change(struct client_t *c, union sctp_notification *sn)
116 {
117 char *addr_s = strsockaddr((struct sockaddr *)&sn->sn_paddr_change.spc_aaddr, sizeof(sn->sn_paddr_change.spc_aaddr));
118
119 switch (sn->sn_paddr_change.spc_state) {
120 case SCTP_ADDR_AVAILABLE:
121 hlog(LOG_DEBUG, "%s/%s: Received SCTP_ADDR_AVAILABLE: %s", c->addr_rem, c->username, addr_s);
122 break;
123 case SCTP_ADDR_UNREACHABLE:
124 hlog(LOG_DEBUG, "%s/%s: Received SCTP_ADDR_UNREACHABLE: %s", c->addr_rem, c->username, addr_s);
125 break;
126 case SCTP_ADDR_REMOVED:
127 hlog(LOG_DEBUG, "%s/%s: Received SCTP_ADDR_REMOVED: %s", c->addr_rem, c->username, addr_s);
128 break;
129 case SCTP_ADDR_ADDED:
130 hlog(LOG_DEBUG, "%s/%s: Received SCTP_ADDR_ADDED: %s", c->addr_rem, c->username, addr_s);
131 break;
132 case SCTP_ADDR_MADE_PRIM:
133 hlog(LOG_DEBUG, "%s/%s: Received SCTP_ADDR_MADE_PRIM: %s", c->addr_rem, c->username, addr_s);
134 break;
135 case SCTP_ADDR_CONFIRMED:
136 hlog(LOG_DEBUG, "%s/%s: Received SCTP_ADDR_CONFIRMED: %s", c->addr_rem, c->username, addr_s);
137 break;
138 default:
139 hlog(LOG_DEBUG, "%s/%s: SCTP Received unexpected peer_addr_change %d: %s",
140 c->addr_rem, c->username, sn->sn_assoc_change.sac_state, addr_s);
141 break;
142 }
143
144 hfree(addr_s);
145
146 return 0;
147
148 }
149
sctp_rx_notification(struct client_t * c,struct msghdr * m)150 static int sctp_rx_notification(struct client_t *c, struct msghdr *m)
151 {
152 union sctp_notification *sn;
153
154 sn = (union sctp_notification *)m->msg_iov->iov_base;
155
156 switch(sn->sn_header.sn_type) {
157 case SCTP_SHUTDOWN_EVENT: {
158 struct sctp_shutdown_event *shut;
159 shut = (struct sctp_shutdown_event *)m->msg_iov->iov_base;
160 hlog(LOG_INFO, "SCTP shutdown on assoc id %d", shut->sse_assoc_id);
161 break;
162 }
163 case SCTP_ASSOC_CHANGE:
164 return sctp_rx_assoc_change(c, sn);
165 case SCTP_PEER_ADDR_CHANGE:
166 return sctp_rx_peer_addr_change(c, sn);
167 case SCTP_SEND_FAILED:
168 hlog(LOG_DEBUG, "%s/%s: SCTP send failed", c->addr_rem, c->username);
169 return 0;
170 case SCTP_REMOTE_ERROR:
171 hlog(LOG_DEBUG, "%s/%s: SCTP remote error", c->addr_rem, c->username);
172 return 0;
173 case SCTP_PARTIAL_DELIVERY_EVENT:
174 hlog(LOG_DEBUG, "%s/%s: SCTP partial delivery event", c->addr_rem, c->username);
175 return 0;
176 };
177
178 hlog(LOG_ERR, "%s/%s: sctp_rx_notification: Received unexpected notification: %d",
179 c->addr_rem, c->username, sn->sn_header.sn_type);
180
181 return -1;
182 }
183
184 typedef union {
185 struct sctp_initmsg init;
186 struct sctp_sndrcvinfo sndrcvinfo;
187 } _sctp_cmsg_data_t;
188
189 typedef union {
190 struct sockaddr_storage ss;
191 struct sockaddr_in v4;
192 struct sockaddr_in6 v6;
193 struct sockaddr sa;
194 } sockaddr_storage_t;
195
196 /*
197 * handle a readable event on SCTP socket
198 */
199
sctp_readable(struct worker_t * self,struct client_t * c)200 int sctp_readable(struct worker_t *self, struct client_t *c)
201 {
202 int e;
203 struct msghdr inmsg;
204 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
205 sockaddr_storage_t msgname;
206 struct iovec iov;
207
208 /* space to receive data */
209 c->ibuf_end = 0;
210 iov.iov_base = c->ibuf;
211 iov.iov_len = c->ibuf_size - 3;
212 inmsg.msg_flags = 0;
213 inmsg.msg_iov = &iov;
214 inmsg.msg_iovlen = 1;
215 /* or control messages */
216 inmsg.msg_control = incmsg;
217 inmsg.msg_controllen = sizeof(incmsg);
218 inmsg.msg_name = &msgname;
219 inmsg.msg_namelen = sizeof(msgname);
220
221 e = recvmsg(c->fd, &inmsg, MSG_WAITALL);
222 if (e < 0) {
223 if (errno == EAGAIN) {
224 hlog(LOG_DEBUG, "sctp_readable: EAGAIN");
225 return 0;
226 }
227
228 hlog(LOG_INFO, "sctp_readable: recvmsg returned %d: %s", e, strerror(errno));
229
230 client_close(self, c, errno);
231 return -1;
232 }
233
234 if (e == 0) {
235 hlog( LOG_DEBUG, "sctp_readable: EOF from socket fd %d (%s @ %s)",
236 c->fd, c->addr_rem, c->addr_loc );
237 client_close(self, c, CLIERR_EOF);
238 return -1;
239 }
240
241 if (inmsg.msg_flags & MSG_NOTIFICATION) {
242 hlog(LOG_DEBUG, "sctp_readable: got MSG_NOTIFICATION");
243 sctp_rx_notification(c, &inmsg);
244 return 0;
245 }
246
247 //hlog_packet(LOG_DEBUG, iov.iov_base, e, "sctp_readable: got data: ");
248 c->ibuf[e++] = '\r';
249 c->ibuf[e++] = '\n';
250
251 return client_postread(self, c, e);
252 }
253
254 /*
255 * SCTP socket is now writable, but we really don't do SCTP buffering yet...
256 */
257
sctp_writable(struct worker_t * self,struct client_t * c)258 int sctp_writable(struct worker_t *self, struct client_t *c)
259 {
260 hlog(LOG_INFO, "sctp_writable: SCTP tx buffering not implemented, closing socket");
261 client_close(self, c, errno);
262 return -1;
263 }
264
265 /*
266 * Write data to an SCTP client
267 */
268
sctp_client_write(struct worker_t * self,struct client_t * c,char * p,int len)269 int sctp_client_write(struct worker_t *self, struct client_t *c, char *p, int len)
270 {
271 //hlog_packet(LOG_DEBUG, p, len, "client_write_sctp %d bytes: ", len);
272
273 if (len == 0)
274 return 0;
275
276 clientaccount_add( c, IPPROTO_SCTP, 0, 0, len, 0, 0, 0);
277
278 int i = send(c->fd, p, len-2, 0);
279
280 if (i < 0) {
281 hlog(LOG_ERR, "SCTP transmit error to fd %d / %s: %s",
282 c->fd, c->addr_rem, strerror(errno));
283 } else if (i != len -2) {
284 hlog(LOG_ERR, "SCTP transmit incomplete to fd %d / %s: wrote %d of %d bytes, errno: %s",
285 c->fd, c->addr_rem, i, len-2, strerror(errno));
286 } else {
287 //hlog(LOG_DEBUG, "SCTP transmit ok to %s: %d bytes", c->addr_rem, i);
288 c->obuf_wtime = tick;
289 }
290
291 return i;
292 }
293
294
295 #if 0
296
297
298 /*
299 * SCTP notification received
300 */
301
302 static int sctp_rx_assoc_change(struct listen_t *l, union sctp_notification *sn)
303 {
304 switch (sn->sn_assoc_change.sac_state) {
305 case SCTP_COMM_UP:
306 hlog(LOG_DEBUG, "Received SCTP_COMM_UP");
307 break;
308 case SCTP_COMM_LOST:
309 hlog(LOG_DEBUG, "Received SCTP_COMM_LOST");
310 break;
311 case SCTP_RESTART:
312 hlog(LOG_DEBUG, "Received SCTP_RESTART");
313 break;
314 case SCTP_SHUTDOWN_COMP:
315 hlog(LOG_DEBUG, "Received SCTP_SHUTDOWN_COMP");
316 break;
317 case SCTP_CANT_STR_ASSOC:
318 hlog(LOG_DEBUG, "Received SCTP_CANT_STR_ASSOC");
319 break;
320 default:
321 hlog(LOG_DEBUG, "Received assoc_change %d", sn->sn_assoc_change.sac_state);
322 break;
323 }
324
325 if (sn->sn_assoc_change.sac_state == SCTP_COMM_UP)
326 return sn->sn_assoc_change.sac_assoc_id;
327
328 return 0;
329
330 }
331
332 static int sctp_rx_notification(struct listen_t *l, struct msghdr *m)
333 {
334 union sctp_notification *sn;
335
336 sn = (union sctp_notification *)m->msg_iov->iov_base;
337
338 switch(sn->sn_header.sn_type) {
339 case SCTP_SHUTDOWN_EVENT: {
340 struct sctp_shutdown_event *shut;
341 shut = (struct sctp_shutdown_event *)m->msg_iov->iov_base;
342 hlog(LOG_INFO, "SCTP shutdown on assoc id %d", shut->sse_assoc_id);
343 break;
344 }
345 case SCTP_ASSOC_CHANGE:
346 return sctp_rx_assoc_change(l, sn);
347 };
348
349 hlog(LOG_ERR, "sctp_rx_notification: Received unexpected notification: %d", sn->sn_header.sn_type);
350
351 return -1;
352 }
353
354 /*
355 * Receive something on an SCTP socket
356 */
357
358
359 typedef union {
360 struct sctp_initmsg init;
361 struct sctp_sndrcvinfo sndrcvinfo;
362 } _sctp_cmsg_data_t;
363
364 typedef union {
365 struct sockaddr_storage ss;
366 struct sockaddr_in v4;
367 struct sockaddr_in6 v6;
368 struct sockaddr sa;
369 } sockaddr_storage_t;
370
371 static void accept_sctp(struct listen_t *l)
372 {
373 int e;
374 struct msghdr inmsg;
375 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
376 sockaddr_storage_t msgname;
377 struct iovec iov;
378 char buf[2000];
379
380 /* space to receive data */
381 iov.iov_base = buf;
382 iov.iov_len = sizeof(buf);
383 inmsg.msg_flags = 0;
384 inmsg.msg_iov = &iov;
385 inmsg.msg_iovlen = 1;
386 /* or control messages */
387 inmsg.msg_control = incmsg;
388 inmsg.msg_controllen = sizeof(incmsg);
389 inmsg.msg_name = &msgname;
390 inmsg.msg_namelen = sizeof(msgname);
391
392 e = recvmsg(l->fd, &inmsg, MSG_WAITALL);
393 if (e < 0) {
394 if (errno == EAGAIN) {
395 hlog(LOG_DEBUG, "accept_sctp: EAGAIN");
396 return;
397 }
398
399 hlog(LOG_INFO, "accept_sctp: recvmsg returned %d: %s", e, strerror(errno));
400 }
401
402 if (inmsg.msg_flags & MSG_NOTIFICATION) {
403 hlog(LOG_DEBUG, "accept_sctp: got MSG_NOTIFICATION");
404 int associd = sctp_rx_notification(l, &inmsg);
405 } else {
406 hlog_packet(LOG_DEBUG, iov.iov_base, e, "accept_sctp: got data: ");
407 }
408
409 }
410 #endif
411
412
413 #endif
414