Browse code

sctp event notification and ancillary info

- debugging: print stream number, ppid, flags, tsn, cumtsn and assoc_id
for each received packet (DBG())
- handle notifications (for now only print info about them)

Andrei Pelinescu-Onciul authored on 27/08/2008 08:35:19
Showing 1 changed files
... ...
@@ -58,6 +58,7 @@ int sctp_init_sock(struct socket_info* sock_info)
58 58
 	int optval;
59 59
 	socklen_t optlen;
60 60
 	struct addr_info* ai;
61
+	struct sctp_event_subscribe es;
61 62
 	
62 63
 	addr=&sock_info->su;
63 64
 	sock_info->proto=PROTO_SCTP;
... ...
@@ -85,7 +86,7 @@ int sctp_init_sock(struct socket_info* sock_info)
85 85
 	INFO("sctp: socket %d initialized (%p)\n", sock_info->socket, sock_info);
86 86
 	/* make socket non-blocking */
87 87
 #if 0
88
-	/* MSG_WAITALL doesn't work for recvmsg, so use blocking sockets
88
+	/* recvmsg must block so use blocking sockets
89 89
 	 * and send with MSG_DONTWAIT */
90 90
 	optval=fcntl(sock_info->socket, F_GETFL);
91 91
 	if (optval==-1){
... ...
@@ -179,8 +180,27 @@ int sctp_init_sock(struct socket_info* sock_info)
179 179
 		/* non critical, try to continue */
180 180
 	}
181 181
 	
182
+	memset(&es, 0, sizeof(es));
182 183
 	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
183 184
 	 *  information in sctp_sndrcvinfo */
185
+	es.sctp_data_io_event=1;
186
+	/* enable association event notifications */
187
+	es.sctp_association_event=1; /* SCTP_ASSOC_CHANGE */
188
+	es.sctp_address_event=1;  /* enable address events notifications */
189
+	es.sctp_send_failure_event=1; /* SCTP_SEND_FAILED */
190
+	es.sctp_peer_error_event=1;
191
+	es.sctp_shutdown_event=1;
192
+	es.sctp_partial_delivery_event=1;
193
+	es.sctp_adaptation_layer_event=1;
194
+	/* es.sctp_authentication_event=1; -- not supported on linux 2.6.25 */
195
+	
196
+	/* enable the SCTP_EVENTS */
197
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_EVENTS,
198
+						&es, sizeof(es))==-1){
199
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: SCTP_EVENTS: %s\n",
200
+						strerror(errno));
201
+		/* non critical, try to continue */
202
+	}
184 203
 	
185 204
 	/* SCTP_EVENTS for send dried out -> present in the draft not yet
186 205
 	 * present in linux (might help to detect when we could send again to
... ...
@@ -233,6 +253,65 @@ error:
233 233
 
234 234
 
235 235
 
236
+static int sctp_handle_notification(struct socket_info* si,
237
+									union sockaddr_union* su,
238
+									char* buf, unsigned len)
239
+{
240
+	union sctp_notification* snp;
241
+	DBG("sctp_rcv_loop: MSG_NOTIFICATION\n");
242
+
243
+	if (len < sizeof(snp->sn_header)){
244
+		LOG(L_ERR, "ERROR: sctp_handle_notification: invalid length %d "
245
+					"on %.*s:%d, from %s\n",
246
+					len, si->name.len, si->name.s, si->port_no,
247
+					su2a(su, sizeof(*su)));
248
+		goto err;
249
+	}
250
+	snp=(union sctp_notification*) buf;
251
+	switch(snp->sn_header.sn_type){
252
+		case SCTP_REMOTE_ERROR:
253
+			if (likely(len>=(sizeof(struct sctp_remote_error)))){
254
+				INFO("sctp notification from %s on %.*s:%d:"
255
+						" SCTP_REMOTE_ERROR: %d, len %d\n",
256
+						su2a(su, sizeof(*su)), si->name.len, si->name.s,
257
+						si->port_no,
258
+						ntohs(snp->sn_remote_error.sre_error),
259
+						ntohs(snp->sn_remote_error.sre_length)
260
+						);
261
+			}else{
262
+				LOG(L_ERR, "ERROR: sctp notification from %s on %.*s:%d:"
263
+						" SCTP_REMOTE_ERROR: too short\n",
264
+						su2a(su, sizeof(*su)), si->name.len, si->name.s,
265
+						si->port_no);
266
+				goto err;
267
+			}
268
+			break;
269
+		case SCTP_SEND_FAILED:
270
+			if (likely(len>=(sizeof(struct sctp_send_failed)))){
271
+				INFO("sctp notification from %s on %.*s:%d:"
272
+						" SCTP_SEND_FAILED: error %d\n",
273
+						su2a(su, sizeof(*su)), si->name.len, si->name.s,
274
+						si->port_no, snp->sn_send_failed.ssf_error);
275
+			}else{
276
+				LOG(L_ERR, "ERROR: sctp notification from %s on %.*s:%d:"
277
+						" SCTP_SEND_FAILED: too short\n",
278
+						su2a(su, sizeof(*su)), si->name.len, si->name.s,
279
+						si->port_no);
280
+				goto err;
281
+			}
282
+			break;
283
+		default:
284
+			INFO("sctp notification from %s on %.*s:%d: UNKNOWN (%d)\n",
285
+					su2a(su, sizeof(*su)), si->name.len, si->name.s,
286
+					si->port_no, snp->sn_header.sn_type);
287
+	}
288
+	return 0;
289
+err:
290
+	return -1;
291
+}
292
+
293
+
294
+
236 295
 int sctp_rcv_loop()
237 296
 {
238 297
 	unsigned len;
... ...
@@ -242,8 +321,10 @@ int sctp_rcv_loop()
242 242
 	struct sctp_sndrcvinfo* sinfo;
243 243
 	struct msghdr msg;
244 244
 	struct iovec iov[1];
245
-	/*struct cmsghdr* cmsg; */
246
-	char cbuf[CMSG_SPACE(sizeof(*sinfo))];
245
+	struct cmsghdr* cmsg;
246
+	/* use a larger buffer then needed in case some other ancillary info
247
+	 * is enabled */
248
+	char cbuf[CMSG_SPACE(sizeof(*sinfo))+CMSG_SPACE(1024)];
247 249
 
248 250
 	
249 251
 	ri.bind_address=bind_address; /* this will not change */
... ...
@@ -265,13 +346,10 @@ int sctp_rcv_loop()
265 265
 	if (cfg_child_init()) goto error;
266 266
 	
267 267
 	for(;;){
268
-		/* recv
269
-		 * recvmsg must be used because the socket is non-blocking
270
-		 * and we want MSG_WAITALL */
271 268
 		msg.msg_name=&ri.src_su.s;
272 269
 		msg.msg_namelen=sockaddru_len(bind_address->su);
273 270
 
274
-		len=recvmsg(bind_address->socket, &msg, MSG_WAITALL);
271
+		len=recvmsg(bind_address->socket, &msg, 0);
275 272
 		/* len=sctp_recvmsg(bind_address->socket, buf, BUF_SIZE, &ri.src_su.s,
276 273
 							&msg.msg_namelen, &sinfo, &msg.msg_flags); */
277 274
 		if (len==-1){
... ...
@@ -287,19 +365,39 @@ int sctp_rcv_loop()
287 287
 			else goto error;
288 288
 		}
289 289
 		if (unlikely(msg.msg_flags & MSG_NOTIFICATION)){
290
-			/* intercept usefull notifications: TODO */
291
-			DBG("sctp_rcv_loop: MSG_NOTIFICATION\n");
292
-			/* notification in CMSG data */
290
+			/* intercept usefull notifications */
291
+			sctp_handle_notification(bind_address, &ri.src_su, buf, len);
293 292
 			continue;
294 293
 		}else if (unlikely(!(msg.msg_flags & MSG_EOR))){
295 294
 			LOG(L_ERR, "ERROR: sctp_rcv_loop: partial delivery not"
296 295
 						"supported\n");
297 296
 			continue;
298 297
 		}
299
-		/* we  0-term the messages for debugging */
300
-		buf[len]=0; /* no need to save the previous char */
298
+		
301 299
 		su2ip_addr(&ri.src_ip, &ri.src_su);
302 300
 		ri.src_port=su_getport(&ri.src_su);
301
+		
302
+		/* get ancillary data */
303
+		for (cmsg=CMSG_FIRSTHDR(&msg); cmsg; cmsg=CMSG_NXTHDR(&msg, cmsg)){
304
+			if (likely((cmsg->cmsg_level==IPPROTO_SCTP) &&
305
+						((cmsg->cmsg_type==SCTP_SNDRCV)
306
+#ifdef SCTP_EXT
307
+						 || (cmsg->cmsg_type==SCTP_EXTRCV)
308
+#endif
309
+						) && (cmsg->cmsg_len>=CMSG_LEN(sizeof(*sinfo)))) ){
310
+				sinfo=(struct sctp_sndrcvinfo*)CMSG_DATA(cmsg);
311
+				DBG("sctp recv: message from %s:%d stream %d  ppid %x"
312
+						" flags %x tsn %d" " cumtsn %d associd %d\n",
313
+						ip_addr2a(&ri.src_ip), htons(ri.src_port),
314
+						sinfo->sinfo_stream, sinfo->sinfo_ppid,
315
+						sinfo->sinfo_flags,
316
+						sinfo->sinfo_tsn, sinfo->sinfo_cumtsn, 
317
+						sinfo->sinfo_assoc_id);
318
+				break;
319
+			}
320
+		}
321
+		/* we  0-term the messages for debugging */
322
+		buf[len]=0; /* no need to save the previous char */
303 323
 
304 324
 		/* sanity checks */
305 325
 		if (len<MIN_SCTP_PACKET) {