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