Browse code

- experimental sctp support (one to many)

Andrei Pelinescu-Onciul authored on 08/08/2008 20:47:23
Showing 7 changed files
... ...
@@ -75,6 +75,7 @@
75 75
  * 2007-06-07  added support for locking pages in mem. and using real time
76 76
  *              scheduling policies (andrei)
77 77
  * 2007-07-30  dst blacklist and DNS cache measurements added (Gergo)
78
+ * 2008-08-08  sctp support (andrei)
78 79
  */
79 80
 
80 81
 
... ...
@@ -145,6 +146,10 @@
145 145
 #include "tls_hooks_init.h"
146 146
 #endif /* CORE_TLS */
147 147
 #endif /* USE_TCP */
148
+#ifdef USE_SCTP
149
+#include "sctp_options.h"
150
+#include "sctp_server.h"
151
+#endif
148 152
 #include "usr_avp.h"
149 153
 #include "core_cmd.h"
150 154
 #include "flags.h"
... ...
@@ -211,6 +216,10 @@ Options:\n\
211 211
     -N           Number of tcp child processes (default: equal to `-n')\n\
212 212
     -W           poll method\n"
213 213
 #endif
214
+#ifdef USE_SCTP
215
+"    -S           Disable sctp\n\
216
+    -O            Number of sctp child processes (default: equal to `-n')\n"
217
+#endif /* USE_SCTP */
214 218
 "    -V           Version number\n\
215 219
     -h           This help message\n\
216 220
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
... ...
@@ -288,6 +297,10 @@ int tls_disable = 0;  /* tls enabled by default */
288 288
 int tls_disable = 1;  /* tls disabled by default */
289 289
 #endif /* CORE_TLS */
290 290
 #endif /* USE_TLS */
291
+#ifdef USE_SCTP
292
+int sctp_children_no = 0;
293
+int sctp_disable = 0; /* 1 if sctp is disabled */
294
+#endif /* USE_SCTP */
291 295
 
292 296
 struct process_table *pt=0;		/*array with children pids, 0= main proc,
293 297
 									alloc'ed in shared mem if possible*/
... ...
@@ -392,6 +405,9 @@ struct socket_info* tcp_listen=0;
392 392
 #ifdef USE_TLS
393 393
 struct socket_info* tls_listen=0;
394 394
 #endif
395
+#ifdef USE_SCTP
396
+struct socket_info* sctp_listen=0;
397
+#endif
395 398
 struct socket_info* bind_address=0; /* pointer to the crt. proc.
396 399
 									 listening address*/
397 400
 struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/
... ...
@@ -404,6 +420,10 @@ struct socket_info* sendipv6_tcp;
404 404
 struct socket_info* sendipv4_tls;
405 405
 struct socket_info* sendipv6_tls;
406 406
 #endif
407
+#ifdef USE_SCTP
408
+struct socket_info* sendipv4_sctp;
409
+struct socket_info* sendipv6_sctp;
410
+#endif
407 411
 
408 412
 unsigned short port_no=0; /* default port*/
409 413
 #ifdef USE_TLS
... ...
@@ -486,6 +506,9 @@ void cleanup(show_status)
486 486
 	destroy_tls();
487 487
 #endif /* USE_TLS */
488 488
 #endif /* USE_TCP */
489
+#ifdef USE_SCTP
490
+	destroy_sctp();
491
+#endif
489 492
 	destroy_timer();
490 493
 	destroy_script_cb();
491 494
 	destroy_nonsip_hooks();
... ...
@@ -777,29 +800,46 @@ error:
777 777
  * sets proto */
778 778
 static int parse_proto(unsigned char* s, long len, int* proto)
779 779
 {
780
-#define PROTO2UINT(a, b, c) ((	(((unsigned int)(a))<<16)+ \
780
+#define PROTO2UINT3(a, b, c) ((	(((unsigned int)(a))<<16)+ \
781 781
 								(((unsigned int)(b))<<8)+  \
782 782
 								((unsigned int)(c)) ) | 0x20202020)
783
+#define PROTO2UINT4(a, b ,c ,d) ((	(((unsigned int)(a))<<24)+ \
784
+									(((unsigned int)(b))<<16)+ \
785
+									(((unsigned int)(c))<< 8)+ \
786
+									(((unsigned int)(d))) \
787
+								  )| 0x20202020 )
783 788
 	unsigned int i;
784
-	if (len!=3) return -1;
785
-	i=PROTO2UINT(s[0], s[1], s[2]);
786
-	switch(i){
787
-		case PROTO2UINT('u', 'd', 'p'):
788
-			*proto=PROTO_UDP;
789
-			break;
789
+	if (likely(len==3)){
790
+		i=PROTO2UINT3(s[0], s[1], s[2]);
791
+		switch(i){
792
+			case PROTO2UINT3('u', 'd', 'p'):
793
+				*proto=PROTO_UDP;
794
+				break;
790 795
 #ifdef USE_TCP
791
-		case PROTO2UINT('t', 'c', 'p'):
792
-			*proto=PROTO_TCP;
793
-			break;
796
+			case PROTO2UINT3('t', 'c', 'p'):
797
+				*proto=PROTO_TCP;
798
+				break;
794 799
 #ifdef USE_TLS
795
-		case PROTO2UINT('t', 'l', 's'):
796
-			*proto=PROTO_TLS;
797
-			break;
800
+			case PROTO2UINT3('t', 'l', 's'):
801
+				*proto=PROTO_TLS;
802
+				break;
798 803
 #endif
799 804
 #endif
800
-		default:
805
+			default:
806
+				return -1;
807
+		}
808
+	}
809
+#ifdef USE_SCTP
810
+	else if (likely(len==4)){
811
+		i=PROTO2UINT4(s[0], s[1], s[2], s[3]);
812
+		if (i==PROTO2UINT4('s', 'c', 't', 'p'))
813
+			*proto=PROTO_SCTP;
814
+		else
801 815
 			return -1;
802 816
 	}
817
+#endif /* USE_SCTP */
818
+	else
819
+		return -1;
803 820
 	return 0;
804 821
 }
805 822
 
... ...
@@ -1032,12 +1072,13 @@ int main_loop()
1032 1032
 			"stand-alone receiver @ %s:%s",
1033 1033
 			 bind_address->name.s, bind_address->port_no_str.s );
1034 1034
 
1035
-	/* call it also w/ PROC_MAIN to make sure modules that init things only
1036
-	 * in PROC_MAIN get a chance to run */
1037
-	if (init_child(PROC_MAIN) < 0) {
1038
-		LOG(L_ERR, "ERROR: main_dontfork: init_child(PROC_MAIN) -- exiting\n");
1039
-		goto error;
1040
-	}
1035
+		/* call it also w/ PROC_MAIN to make sure modules that init things 
1036
+		 * only in PROC_MAIN get a chance to run */
1037
+		if (init_child(PROC_MAIN) < 0) {
1038
+			LOG(L_ERR, "ERROR: main_dontfork: init_child(PROC_MAIN) "
1039
+						"-- exiting\n");
1040
+			goto error;
1041
+		}
1041 1042
 
1042 1043
 		/* We will call child_init even if we
1043 1044
 		 * do not fork - and it will be called with rank 1 because
... ...
@@ -1064,6 +1105,22 @@ int main_loop()
1064 1064
 				sendipv6=si;
1065 1065
 	#endif
1066 1066
 		}
1067
+#ifdef USE_SCTP
1068
+		if (!sctp_disable){
1069
+			for(si=sctp_listen; si; si=si->next){
1070
+				if (sctp_init_sock(si)==-1)  goto error;
1071
+				/* get first ipv4/ipv6 socket*/
1072
+				if ((si->address.af==AF_INET)&&
1073
+						((sendipv4_sctp==0)||
1074
+						 	(sendipv4_sctp->flags&(SI_IS_LO|SI_IS_MCAST))))
1075
+					sendipv4_sctp=si;
1076
+		#ifdef USE_IPV6
1077
+				if((sendipv6_sctp==0)&&(si->address.af==AF_INET6))
1078
+					sendipv6_sctp=si;
1079
+		#endif
1080
+			}
1081
+		}
1082
+#endif /* USE_SCTP */
1067 1083
 #ifdef USE_TCP
1068 1084
 		if (!tcp_disable){
1069 1085
 			for(si=tcp_listen; si; si=si->next){
... ...
@@ -1099,8 +1156,8 @@ int main_loop()
1099 1099
 #endif /* USE_TLS */
1100 1100
 #endif /* USE_TCP */
1101 1101
 
1102
-			/* all processes should have access to all the sockets (for sending)
1103
-			 * so we open all first*/
1102
+			/* all processes should have access to all the sockets (for 
1103
+			 * sending) so we open all first*/
1104 1104
 		if (do_suid()==-1) goto error; /* try to drop privileges */
1105 1105
 
1106 1106
 		/* init childs with rank==PROC_INIT before forking any process,
... ...
@@ -1139,12 +1196,37 @@ int main_loop()
1139 1139
 			/*parent*/
1140 1140
 			/*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/
1141 1141
 		}
1142
-	}
1142
+#ifdef USE_SCTP
1143
+		/* sctp processes */
1144
+		if (!sctp_disable){
1145
+			for(si=sctp_listen; si; si=si->next){
1146
+				for(i=0;i<sctp_children_no;i++){
1147
+					snprintf(si_desc, MAX_PT_DESC, "sctp receiver child=%d "
1148
+								"sock=%s:%s",
1149
+								i, si->name.s, si->port_no_str.s);
1150
+					child_rank++;
1151
+					pid = fork_process(child_rank, si_desc, 1);
1152
+					if (pid<0){
1153
+						LOG(L_CRIT,  "main_loop: Cannot fork\n");
1154
+						goto error;
1155
+					}else if (pid==0){
1156
+						/* child */
1157
+						bind_address=si; /* shortcut */
1158
+#ifdef STATS
1159
+						setstats( i+r*children_no );
1160
+#endif
1161
+						return sctp_rcv_loop();
1162
+					}
1163
+				}
1164
+			/*parent*/
1165
+			/*close(sctp_sock)*/; /*if closed=>sendto invalid fd errors?*/
1166
+			}
1167
+		}
1168
+#endif /* USE_SCTP */
1143 1169
 
1144
-	/*this is the main process*/
1145
-	bind_address=0;				/* main proc -> it shouldn't send anything, */
1170
+		/*this is the main process*/
1171
+		bind_address=0;	/* main proc -> it shouldn't send anything, */
1146 1172
 
1147
-	{
1148 1173
 #ifdef USE_SLOW_TIMER
1149 1174
 		/* fork again for the "slow" timer process*/
1150 1175
 		pid = fork_process(PROC_TIMER, "slow timer", 1);
... ...
@@ -1173,17 +1255,15 @@ int main_loop()
1173 1173
 				set_rt_prio(rt_timer1_prio, rt_timer1_policy);
1174 1174
 			if (arm_timer()<0) goto error;
1175 1175
 			timer_main();
1176
-		}else{
1177 1176
 		}
1178
-	}
1179 1177
 
1180
-/* init childs with rank==MAIN before starting tcp main (in case they want to
1181
- *  fork  a tcp capable process, the corresponding tcp. comm. fds in pt[] must
1182
- *  be set before calling tcp_main_loop()) */
1183
-	if (init_child(PROC_MAIN) < 0) {
1184
-		LOG(L_ERR, "ERROR: main: error in init_child\n");
1185
-		goto error;
1186
-	}
1178
+	/* init childs with rank==MAIN before starting tcp main (in case they want
1179
+	 * to fork  a tcp capable process, the corresponding tcp. comm. fds in
1180
+	 * pt[] must be set before calling tcp_main_loop()) */
1181
+		if (init_child(PROC_MAIN) < 0) {
1182
+			LOG(L_ERR, "ERROR: main: error in init_child\n");
1183
+			goto error;
1184
+		}
1187 1185
 
1188 1186
 #ifdef USE_TCP
1189 1187
 		if (!tcp_disable){
... ...
@@ -1204,32 +1284,32 @@ int main_loop()
1204 1204
 			}
1205 1205
 		}
1206 1206
 #endif
1207
-	/* main */
1208
-	strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
1207
+		/* main */
1208
+		strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
1209 1209
 #ifdef USE_TCP
1210
-	close_extra_socks(PROC_ATTENDANT, get_proc_no());
1211
-	if(!tcp_disable){
1212
-		/* main's tcp sockets are disabled by default from init_pt() */
1213
-		unix_tcp_sock=-1;
1214
-	}
1210
+		close_extra_socks(PROC_ATTENDANT, get_proc_no());
1211
+		if(!tcp_disable){
1212
+			/* main's tcp sockets are disabled by default from init_pt() */
1213
+			unix_tcp_sock=-1;
1214
+		}
1215 1215
 #endif
1216 1216
 
1217
-	/*DEBUG- remove it*/
1218 1217
 #ifdef EXTRA_DEBUG
1219
-	for (r=0; r<*process_count; r++){
1220
-		fprintf(stderr, "% 3d   % 5d - %s\n", r, pt[r].pid, pt[r].desc);
1221
-	}
1218
+		for (r=0; r<*process_count; r++){
1219
+			fprintf(stderr, "% 3d   % 5d - %s\n", r, pt[r].pid, pt[r].desc);
1220
+		}
1222 1221
 #endif
1223
-	DBG("Expect maximum %d  open fds\n", get_max_open_fds());
1222
+		DBG("Expect maximum %d  open fds\n", get_max_open_fds());
1224 1223
 
1225
-	for(;;){
1224
+		for(;;){
1226 1225
 			handle_sigs();
1227 1226
 			pause();
1227
+		}
1228
+	
1228 1229
 	}
1229 1230
 
1230
-
1231 1231
 	/*return 0; */
1232
- error:
1232
+error:
1233 1233
 				 /* if we are here, we are the "main process",
1234 1234
 				  any forked children should exit with exit(-1) and not
1235 1235
 				  ever use return */
... ...
@@ -1245,8 +1325,14 @@ static int calc_proc_no(void)
1245 1245
 {
1246 1246
 	int udp_listeners;
1247 1247
 	struct socket_info* si;
1248
+#ifdef USE_SCTP
1249
+	int sctp_listeners;
1250
+#endif
1248 1251
 
1249 1252
 	for (si=udp_listen, udp_listeners=0; si; si=si->next, udp_listeners++);
1253
+#ifdef USE_SCTP
1254
+	for (si=sctp_listen, sctp_listeners=0; si; si=si->next, sctp_listeners++);
1255
+#endif
1250 1256
 	return
1251 1257
 		     /* receivers and attendant */
1252 1258
 		(dont_fork ? 1 : children_no * udp_listeners + 1)
... ...
@@ -1259,6 +1345,9 @@ static int calc_proc_no(void)
1259 1259
 #ifdef USE_TCP
1260 1260
 		+((!tcp_disable)?( 1/* tcp main */ + tcp_children_no ):0)
1261 1261
 #endif
1262
+#ifdef USE_SCTP
1263
+		+((!sctp_disable)?sctp_children_no*sctp_listeners:0)
1264
+#endif
1262 1265
 		;
1263 1266
 }
1264 1267
 
... ...
@@ -1295,7 +1384,7 @@ int main(int argc, char** argv)
1295 1295
 		"DBG_MSG_QA enabled, ser may exit abruptly\n");
1296 1296
 #endif
1297 1297
 
1298
-	options=  ":f:cm:dVhEb:l:L:n:vrRDTN:W:w:t:u:g:P:G:"
1298
+	options=  ":f:cm:dVhEb:l:L:n:vrRDTN:W:w:t:u:g:P:G:SO:"
1299 1299
 #ifdef STATS
1300 1300
 		"s:"
1301 1301
 #endif
... ...
@@ -1304,6 +1393,9 @@ int main(int argc, char** argv)
1304 1304
 #ifdef USE_TCP
1305 1305
 	init_tcp_options(); /* set the defaults before the config */
1306 1306
 #endif
1307
+#ifdef USE_SCTP
1308
+	init_sctp_options(); /* set defaults before the config */
1309
+#endif
1307 1310
 	/* look if there is a -h, e.g. -f -h construction won't catch it later */
1308 1311
 	opterr = 0;
1309 1312
 	while((c=getopt(argc,argv,options))!=-1) {
... ...
@@ -1535,6 +1627,25 @@ try_again:
1535 1535
 					fprintf(stderr,"WARNING: tcp support not compiled in\n");
1536 1536
 				#endif
1537 1537
 					break;
1538
+			case 'S':
1539
+				#ifdef USE_SCTP
1540
+					sctp_disable=1;
1541
+				#else
1542
+					fprintf(stderr,"WARNING: sctp support not compiled in\n");
1543
+				#endif
1544
+					break;
1545
+			case 'O':
1546
+				#ifdef USE_SCTP
1547
+					sctp_children_no=strtol(optarg, &tmp, 10);
1548
+					if ((tmp==0) ||(*tmp)){
1549
+						fprintf(stderr, "bad process number: -O %s\n",
1550
+									optarg);
1551
+						goto error;
1552
+					}
1553
+				#else
1554
+					fprintf(stderr,"WARNING: sctp support not compiled in\n");
1555
+				#endif
1556
+					break;
1538 1557
 			case 'w':
1539 1558
 					working_dir=optarg;
1540 1559
 					break;
... ...
@@ -1573,6 +1684,14 @@ try_again:
1573 1573
 	/* init locks first */
1574 1574
 	if (init_lock_ops()!=0)
1575 1575
 		goto error;
1576
+#ifdef USE_TCP
1577
+#ifdef USE_TLS
1578
+	if (tcp_disable)
1579
+		tls_disable=1; /* if no tcp => no tls */
1580
+#endif /* USE_TLS */
1581
+#endif /* USE_TCP */
1582
+	/* initialize the configured proto list */
1583
+	init_proto_order();
1576 1584
 	/* init the resolver, before fixing the config */
1577 1585
 	resolv_init();
1578 1586
 	/* fix parameters */
... ...
@@ -1588,6 +1707,11 @@ try_again:
1588 1588
 		if (tcp_children_no<=0) tcp_children_no=children_no;
1589 1589
 	}
1590 1590
 #endif
1591
+#ifdef USE_SCTP
1592
+	if (!sctp_disable){
1593
+		if (sctp_children_no<=0) sctp_children_no=children_no;
1594
+	}
1595
+#endif
1591 1596
 
1592 1597
 	if (working_dir==0) working_dir="/";
1593 1598
 
1594 1599
new file mode 100644
... ...
@@ -0,0 +1,66 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2008 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/* 
18
+ * sctp options
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2008-08-07  initial version (andrei)
24
+ */
25
+
26
+
27
+#include "sctp_options.h"
28
+#include "dprint.h"
29
+
30
+
31
+struct sctp_cfg_options sctp_options;
32
+
33
+void init_sctp_options()
34
+{
35
+#ifdef USE_SCTP
36
+	sctp_options.sctp_autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
37
+	sctp_options.sctp_send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
38
+#endif
39
+}
40
+
41
+
42
+
43
+#define W_OPT_NSCTP(option) \
44
+	if (sctp_options.option){\
45
+		WARN("sctp_options: " #option \
46
+			" cannot be enabled (sctp support not compiled-in)\n"); \
47
+			sctp_options.option=0; \
48
+	}
49
+
50
+
51
+
52
+void sctp_options_check()
53
+{
54
+#ifndef USE_SCTP
55
+	W_OPT_NSCTP(sctp_autoclose);
56
+	W_OPT_NSCTP(sctp_send_ttl);
57
+#endif
58
+}
59
+
60
+
61
+
62
+void sctp_options_get(struct sctp_cfg_options *s)
63
+{
64
+	*s=sctp_options;
65
+}
0 66
new file mode 100644
... ...
@@ -0,0 +1,47 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2008 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/* 
18
+ * sctp options
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2008-08-07  initial version (andrei)
24
+ */
25
+
26
+#ifndef _sctp_options_h
27
+#define _sctp_options_h
28
+
29
+#define DEFAULT_SCTP_AUTOCLOSE 180 /* seconds */
30
+#define DEFAULT_SCTP_SEND_TTL  32000 /* in ms (32s)  */
31
+
32
+
33
+struct sctp_cfg_options{
34
+	int sctp_so_rcvbuf;
35
+	int sctp_so_sndbuf;
36
+	unsigned int sctp_autoclose; /* in seconds */
37
+	unsigned int sctp_send_ttl; /* in milliseconds */
38
+};
39
+
40
+extern struct sctp_cfg_options sctp_options;
41
+
42
+void init_sctp_options();
43
+void sctp_options_check();
44
+void sctp_options_get(struct sctp_cfg_options *s);
45
+
46
+#endif /* _sctp_options_h */
0 47
new file mode 100644
... ...
@@ -0,0 +1,351 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2008 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/* 
18
+ * sctp one to many 
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2008-08-07  initial version (andrei)
24
+ */
25
+
26
+#ifdef USE_SCTP
27
+
28
+#include <stdlib.h>
29
+#include <string.h>
30
+#include <sys/types.h>
31
+#include <sys/socket.h>
32
+#include <netinet/in.h>
33
+#include <netinet/in_systm.h>
34
+#include <netinet/ip.h>
35
+#include <netinet/sctp.h>
36
+#include <errno.h>
37
+#include <arpa/inet.h>
38
+#include <unistd.h>
39
+#include <fcntl.h>
40
+
41
+
42
+#include "sctp_server.h"
43
+#include "sctp_options.h"
44
+#include "globals.h"
45
+#include "config.h"
46
+#include "dprint.h"
47
+#include "receive.h"
48
+#include "mem/mem.h"
49
+#include "ip_addr.h"
50
+#include "cfg/cfg_struct.h"
51
+
52
+
53
+
54
+int sctp_init_sock(struct socket_info* sock_info)
55
+{
56
+	union sockaddr_union* addr;
57
+	int optval;
58
+	socklen_t optlen;
59
+	
60
+	addr=&sock_info->su;
61
+	sock_info->proto=PROTO_SCTP;
62
+	if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
63
+		LOG(L_ERR, "ERROR: sctp_init_sock: could not init sockaddr_union\n");
64
+		goto error;
65
+	}
66
+	sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_SEQPACKET, 
67
+								IPPROTO_SCTP);
68
+	if (sock_info->socket==-1){
69
+		LOG(L_ERR, "ERROR: sctp_init_sock: socket: %s\n", strerror(errno));
70
+		goto error;
71
+	}
72
+	INFO("sctp: socket %d initialized (%p)\n", sock_info->socket, sock_info);
73
+	/* make socket non-blocking */
74
+#if 0
75
+	/* MSG_WAITALL doesn't work for recvmsg, so use blocking sockets
76
+	 * and send with MSG_DONTWAIT */
77
+	optval=fcntl(sock_info->socket, F_GETFL);
78
+	if (optval==-1){
79
+		LOG(L_ERR, "ERROR: init_sctp: fnctl failed: (%d) %s\n",
80
+				errno, strerror(errno));
81
+		goto error;
82
+	}
83
+	if (fcntl(sock_info->socket, F_SETFL, optval|O_NONBLOCK)==-1){
84
+		LOG(L_ERR, "ERROR: init_sctp: fcntl: set non-blocking failed:"
85
+				" (%d) %s\n", errno, strerror(errno));
86
+		goto error;
87
+	}
88
+#endif
89
+
90
+	/* set sock opts */
91
+	/* set receive buffer: SO_RCVBUF*/
92
+	if (sctp_options.sctp_so_rcvbuf){
93
+		optval=sctp_options.sctp_so_rcvbuf;
94
+		if (setsockopt(sock_info->socket, SOL_SCTP, SO_RCVBUF,
95
+					(void*)&optval, sizeof(optval)) ==-1){
96
+			LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: SO_RCVBUF (%d):"
97
+						" %s\n", optval, strerror(errno));
98
+			/* continue, non-critical */
99
+		}
100
+	}
101
+	
102
+	/* set send buffer: SO_SNDBUF */
103
+	if (sctp_options.sctp_so_sndbuf){
104
+		optval=sctp_options.sctp_so_sndbuf;
105
+		if (setsockopt(sock_info->socket, SOL_SCTP, SO_SNDBUF,
106
+					(void*)&optval, sizeof(optval)) ==-1){
107
+			LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: SO_SNDBUF (%d):"
108
+						" %s\n", optval, strerror(errno));
109
+			/* continue, non-critical */
110
+		}
111
+	}
112
+	
113
+	/* disable fragments interleave (SCTP_FRAGMENT_INTERLEAVE) --
114
+	 * we don't want partial delivery, so fragment interleave must be off too
115
+	 */
116
+	optval=0;
117
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_FRAGMENT_INTERLEAVE ,
118
+					(void*)&optval, sizeof(optval)) ==-1){
119
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
120
+						strerror(errno));
121
+		goto error;
122
+	}
123
+	
124
+	/* turn off partial delivery: on linux setting SCTP_PARTIAL_DELIVERY_POINT
125
+	 * to 0 or a very large number seems to be enough, however the portable
126
+	 * way to do it is to set it to the socket receive buffer size
127
+	 * (this is the maximum value allowed in the sctp api draft) */
128
+	optlen=sizeof(optval);
129
+	if (getsockopt(sock_info->socket, SOL_SCTP, SO_RCVBUF,
130
+					(void*)&optval, &optlen) ==-1){
131
+		LOG(L_ERR, "ERROR: sctp_init_sock: getsockopt: %s\n",
132
+						strerror(errno));
133
+		goto error;
134
+	}
135
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
136
+					(void*)&optval, sizeof(optval)) ==-1){
137
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
138
+						strerror(errno));
139
+		goto error;
140
+	}
141
+	
142
+	/* nagle / no delay */
143
+	optval=1;
144
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_NODELAY,
145
+					(void*)&optval, sizeof(optval)) ==-1){
146
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
147
+						strerror(errno));
148
+		/* non critical, try to continue */
149
+	}
150
+	
151
+	/* enable message fragmentation (SCTP_DISABLE_FRAGMENTS)  (on send) */
152
+	optval=0;
153
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_DISABLE_FRAGMENTS,
154
+					(void*)&optval, sizeof(optval)) ==-1){
155
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
156
+						strerror(errno));
157
+		/* non critical, try to continue */
158
+	}
159
+	
160
+	/* set autoclose */
161
+	optval=sctp_options.sctp_autoclose;
162
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_DISABLE_FRAGMENTS,
163
+					(void*)&optval, sizeof(optval)) ==-1){
164
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
165
+						strerror(errno));
166
+		/* non critical, try to continue */
167
+	}
168
+	
169
+	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
170
+	 *  information in sctp_sndrcvinfo */
171
+	
172
+	/* SCTP_EVENTS for send dried out -> present in the draft not yet
173
+	 * present in linux (might help to detect when we could send again to
174
+	 * some peer, kind of poor's man poll on write, based on received
175
+	 * SCTP_SENDER_DRY_EVENTs */
176
+	
177
+	
178
+	/* bind the addresses  (TODO multiple addresses support)*/
179
+	if (bind(sock_info->socket,  &addr->s, sockaddru_len(*addr))==-1){
180
+		LOG(L_ERR, "ERROR: sctp_init_sock: bind(%x, %p, %d) on %s: %s\n",
181
+				sock_info->socket, &addr->s, 
182
+				(unsigned)sockaddru_len(*addr),
183
+				sock_info->address_str.s,
184
+				strerror(errno));
185
+	#ifdef USE_IPV6
186
+		if (addr->s.sa_family==AF_INET6)
187
+			LOG(L_ERR, "ERROR: sctp_init_sock: might be caused by using a "
188
+							"link local address, try site local or global\n");
189
+	#endif
190
+		goto error;
191
+	}
192
+	if (listen(sock_info->socket, 1)<0){
193
+		LOG(L_ERR, "ERROR: sctp_init_sock: listen(%x, 1) on %s: %s\n",
194
+					sock_info->socket, sock_info->address_str.s,
195
+					strerror(errno));
196
+		goto error;
197
+	}
198
+	return 0;
199
+error:
200
+	return -1;
201
+}
202
+
203
+
204
+
205
+int sctp_rcv_loop()
206
+{
207
+	unsigned len;
208
+	static char buf [BUF_SIZE+1];
209
+	char *tmp;
210
+	struct receive_info ri;
211
+	struct sctp_sndrcvinfo* sinfo;
212
+	struct msghdr msg;
213
+	struct iovec iov[1];
214
+	/*struct cmsghdr* cmsg; */
215
+	char cbuf[CMSG_SPACE(sizeof(*sinfo))];
216
+
217
+	
218
+	ri.bind_address=bind_address; /* this will not change */
219
+	ri.dst_port=bind_address->port_no;
220
+	ri.dst_ip=bind_address->address;
221
+	ri.proto=PROTO_SCTP;
222
+	ri.proto_reserved1=ri.proto_reserved2=0;
223
+	
224
+	iov[0].iov_base=buf;
225
+	iov[0].iov_len=BUF_SIZE;
226
+	msg.msg_iov=iov;
227
+	msg.msg_iovlen=1;
228
+	msg.msg_control=cbuf;
229
+	msg.msg_controllen=sizeof(cbuf);
230
+	msg.msg_flags=0;
231
+	
232
+
233
+	/* initialize the config framework */
234
+	if (cfg_child_init()) goto error;
235
+	
236
+	for(;;){
237
+		/* recv
238
+		 * recvmsg must be used because the socket is non-blocking
239
+		 * and we want MSG_WAITALL */
240
+		msg.msg_name=&ri.src_su.s;
241
+		msg.msg_namelen=sockaddru_len(bind_address->su);
242
+
243
+		len=recvmsg(bind_address->socket, &msg, MSG_WAITALL);
244
+		/* len=sctp_recvmsg(bind_address->socket, buf, BUF_SIZE, &ri.src_su.s,
245
+							&msg.msg_namelen, &sinfo, &msg.msg_flags); */
246
+		if (len==-1){
247
+			if (errno==EAGAIN){
248
+				DBG("sctp_rcv_loop: EAGAIN on sctp socket\n");
249
+				continue;
250
+			}
251
+			LOG(L_ERR, "ERROR: sctp_rcv_loop: sctp_recvmsg on %d (%p):"
252
+						"[%d] %s\n", bind_address->socket, bind_address,
253
+						errno, strerror(errno));
254
+			if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
255
+				continue; /* goto skip;*/
256
+			else goto error;
257
+		}
258
+		if (unlikely(msg.msg_flags & MSG_NOTIFICATION)){
259
+			/* intercept usefull notifications: TODO */
260
+			DBG("sctp_rcv_loop: MSG_NOTIFICATION\n");
261
+			/* notification in CMSG data */
262
+			continue;
263
+		}else if (unlikely(!(msg.msg_flags & MSG_EOR))){
264
+			LOG(L_ERR, "ERROR: sctp_rcv_loop: partial delivery not"
265
+						"supported\n");
266
+			continue;
267
+		}
268
+		/* we  0-term the messages for debugging */
269
+		buf[len]=0; /* no need to save the previous char */
270
+		su2ip_addr(&ri.src_ip, &ri.src_su);
271
+		ri.src_port=su_getport(&ri.src_su);
272
+
273
+		/* sanity checks */
274
+		if (len<MIN_SCTP_PACKET) {
275
+			tmp=ip_addr2a(&ri.src_ip);
276
+			DBG("sctp_rcv_loop: probing packet received from %s %d\n",
277
+					tmp, htons(ri.src_port));
278
+			continue;
279
+		}
280
+		if (ri.src_port==0){
281
+			tmp=ip_addr2a(&ri.src_ip);
282
+			LOG(L_INFO, "sctp_rcv_loop: dropping 0 port packet from %s\n",
283
+						tmp);
284
+			continue;
285
+		}
286
+	
287
+		/* update the local config */
288
+		cfg_update();
289
+		receive_msg(buf, len, &ri);
290
+	}
291
+error:
292
+	return -1;
293
+}
294
+
295
+
296
+/* send buf:len over udp to dst (uses only the to and send_sock dst members)
297
+ * returns the numbers of bytes sent on success (>=0) and -1 on error
298
+ */
299
+int sctp_msg_send(struct dest_info* dst, char* buf, unsigned len)
300
+{
301
+	int n;
302
+	int tolen;
303
+	struct ip_addr ip; /* used only on error, for debugging */
304
+	struct msghdr msg;
305
+	struct iovec iov[1];
306
+	
307
+	tolen=sockaddru_len(dst->to);
308
+	iov[0].iov_base=buf;
309
+	iov[0].iov_len=len;
310
+	msg.msg_iov=iov;
311
+	msg.msg_iovlen=1;
312
+	msg.msg_name=&dst->to.s;
313
+	msg.msg_namelen=tolen;
314
+	msg.msg_control=0;
315
+	msg.msg_controllen=0;
316
+	msg.msg_flags=SCTP_UNORDERED;
317
+again:
318
+	n=sendmsg(dst->send_sock->socket, &msg, MSG_DONTWAIT);
319
+#if 0
320
+	n=sctp_sendmsg(dst->send_sock->socket, buf, len, &dst->to.s, tolen,
321
+					0 /* ppid */, SCTP_UNORDERED /* | SCTP_EOR */ /* flags */,
322
+					0 /* stream */, sctp_options.sctp_send_ttl /* ttl */,
323
+					0 /* context */);
324
+#endif
325
+	if (n==-1){
326
+		su2ip_addr(&ip, &dst->to);
327
+		LOG(L_ERR, "ERROR: sctp_msg_send: sendmsg(sock,%p,%d,0,%s:%d,%d):"
328
+				" %s(%d)\n", buf, len, ip_addr2a(&ip), su_getport(&dst->to),
329
+				tolen, strerror(errno),errno);
330
+		if (errno==EINTR) goto again;
331
+		if (errno==EINVAL) {
332
+			LOG(L_CRIT,"CRITICAL: invalid sendmsg parameters\n"
333
+			"one possible reason is the server is bound to localhost and\n"
334
+			"attempts to send to the net\n");
335
+		}else if (errno==EAGAIN || errno==EWOULDBLOCK){
336
+			LOG(L_ERR, "ERROR: sctp_msg_send: failed to send, send buffers"
337
+						" full\n");
338
+			/* TODO: fix blocking writes */
339
+		}
340
+	}
341
+	return n;
342
+}
343
+
344
+
345
+
346
+void destroy_sctp()
347
+{
348
+}
349
+
350
+#endif /* USE_SCTP */
0 351
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2008 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/* 
18
+ * sctp one to many 
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2008-08-07  initial version (andrei)
24
+ */
25
+
26
+#ifndef _sctp_server_h
27
+#define _sctp_server_h
28
+
29
+#include "ip_addr.h"
30
+
31
+int sctp_init_sock(struct socket_info* sock_info);
32
+int sctp_rcv_loop();
33
+int sctp_msg_send(struct dest_info* dst, char* buf, unsigned len);
34
+
35
+void destroy_sctp();
36
+
37
+#endif /* _sctp_server_h */
... ...
@@ -35,6 +35,7 @@
35 35
  *  2004-10-10  added grep_sock_info (andrei)
36 36
  *  2004-11-08  added find_si (andrei)
37 37
  *  2007-08-23  added detection for INADDR_ANY types of sockets (andrei)
38
+ *  2008-08-08  sctp support (andrei)
38 39
  */
39 40
 
40 41
 
... ...
@@ -103,6 +104,12 @@
103 103
 
104 104
 
105 105
 
106
+/* protocol order, filled by init_proto_order() */
107
+enum sip_protos nxt_proto[PROTO_LAST+1]=
108
+{ PROTO_UDP, PROTO_TCP, PROTO_TLS, PROTO_SCTP, 0 };
109
+
110
+
111
+
106 112
 /* another helper function, it just creates a socket_info struct */
107 113
 static inline struct socket_info* new_sock_info(	char* name,
108 114
 								unsigned short port, unsigned short proto,
... ...
@@ -158,6 +165,10 @@ static char* get_proto_name(unsigned short proto)
158 158
 		case PROTO_TLS:
159 159
 			return "tls";
160 160
 #endif
161
+#ifdef USE_SCTP
162
+		case PROTO_SCTP:
163
+			return "sctp";
164
+#endif
161 165
 		default:
162 166
 			return "unknown";
163 167
 	}
... ...
@@ -181,6 +192,11 @@ static struct socket_info** get_sock_info_list(unsigned short proto)
181 181
 			return &tls_listen;
182 182
 			break;
183 183
 #endif
184
+#ifdef USE_SCTP
185
+		case PROTO_SCTP:
186
+			return &sctp_listen;
187
+			break;
188
+#endif
184 189
 		default:
185 190
 			LOG(L_CRIT, "BUG: get_sock_info_list: invalid proto %d\n", proto);
186 191
 	}
... ...
@@ -776,6 +792,9 @@ int fix_all_socket_lists()
776 776
 			&& (tls_listen==0)
777 777
 #endif
778 778
 #endif
779
+#ifdef USE_SCTP
780
+			&& (sctp_listen==0)
781
+#endif
779 782
 		){
780 783
 		/* get all listening ipv4 interfaces */
781 784
 		if (add_interfaces(0, AF_INET, 0,  PROTO_UDP, &udp_listen)==0){
... ...
@@ -793,6 +812,13 @@ int fix_all_socket_lists()
793 793
 #endif
794 794
 			}
795 795
 #endif
796
+#ifdef USE_SCTP
797
+			if (!sctp_disable){
798
+				if (add_interfaces(0, AF_INET, 0,  PROTO_SCTP,
799
+									&sctp_listen)!=0)
800
+					goto error;
801
+			}
802
+#endif /* USE_SCTP */
796 803
 		}else{
797 804
 			/* if error fall back to get hostname */
798 805
 			/* get our address, only the first one */
... ...
@@ -836,6 +862,16 @@ int fix_all_socket_lists()
836 836
 	}
837 837
 #endif
838 838
 #endif
839
+#ifdef USE_SCTP
840
+	if (!sctp_disable && (fix_socket_list(&sctp_listen, &flags)!=0)){
841
+		LOG(L_ERR, "ERROR: fix_all_socket_lists: fix_socket_list"
842
+				" sctp failed\n");
843
+		goto error;
844
+	}
845
+	if (flags){
846
+		socket_types|=flags|SOCKET_T_SCTP;
847
+	}
848
+#endif /* USE_SCTP */
839 849
 	if ((udp_listen==0)
840 850
 #ifdef USE_TCP
841 851
 			&& (tcp_listen==0)
... ...
@@ -843,6 +879,9 @@ int fix_all_socket_lists()
843 843
 			&& (tls_listen==0)
844 844
 #endif
845 845
 #endif
846
+#ifdef USE_SCTP
847
+			&& (sctp_listen==0)
848
+#endif
846 849
 		){
847 850
 		LOG(L_ERR, "ERROR: fix_all_socket_lists: no listening sockets\n");
848 851
 		goto error;
... ...
@@ -885,3 +924,37 @@ void print_aliases()
885 885
 			printf("             %s: %.*s:*\n", get_proto_name(a->proto), 
886 886
 					a->alias.len, a->alias.s);
887 887
 }
888
+
889
+
890
+
891
+void init_proto_order()
892
+{
893
+	int r;
894
+	
895
+	/* fix proto list  (remove disabled protocols)*/
896
+#ifdef USE_TCP
897
+	if (tcp_disable)
898
+#endif
899
+		for(r=PROTO_NONE; r<=PROTO_LAST; r++){
900
+			if (nxt_proto[r]==PROTO_TCP)
901
+				nxt_proto[r]=nxt_proto[PROTO_TCP];
902
+		}
903
+#ifdef USE_TCP
904
+#ifdef USE_TLS
905
+	if (tls_disable || tcp_disable)
906
+#endif
907
+#endif
908
+		for(r=PROTO_NONE; r<=PROTO_LAST; r++){
909
+			if (nxt_proto[r]==PROTO_TLS)
910
+				nxt_proto[r]=nxt_proto[PROTO_TLS];
911
+		}
912
+#ifdef USE_SCTP
913
+	if (sctp_disable)
914
+		for(r=PROTO_NONE; r<=PROTO_LAST; r++){
915
+			if (nxt_proto[r]==PROTO_SCTP)
916
+				nxt_proto[r]=nxt_proto[PROTO_SCTP];
917
+		}
918
+#endif
919
+}
920
+
921
+
... ...
@@ -32,6 +32,7 @@
32 32
  * History:
33 33
  * --------
34 34
  *  2003-10-22  created by andrei
35
+ *  2008-08-08  sctp support (andrei)
35 36
  */
36 37
 
37 38
 
... ...
@@ -50,17 +51,26 @@ extern struct socket_info* tcp_listen;
50 50
 #ifdef USE_TLS
51 51
 extern struct socket_info* tls_listen;
52 52
 #endif
53
+#ifdef USE_SCTP
54
+extern struct socket_info* sctp_listen;
55
+#endif
56
+
57
+extern enum sip_protos nxt_proto[PROTO_LAST+1];
58
+
53 59
 
54 60
 
55 61
 /* flags for finding out the address types */
56
-#define SOCKET_T_IPV4 1
57
-#define SOCKET_T_IPV6 2
58
-#define SOCKET_T_UDP  4
59
-#define SOCKET_T_TCP  8
60
-#define SOCKET_T_TLS 16
62
+#define SOCKET_T_IPV4  1
63
+#define SOCKET_T_IPV6  2
64
+#define SOCKET_T_UDP   4
65
+#define SOCKET_T_TCP   8
66
+#define SOCKET_T_TLS  16
67
+#define SOCKET_T_SCTP 32
61 68
 
62 69
 extern int socket_types;
63 70
 
71
+void init_proto_order();
72
+
64 73
 int add_listen_iface(char* name, unsigned short port, unsigned short proto,
65 74
 							enum si_flags flags);
66 75
 int fix_all_socket_lists();
... ...
@@ -74,35 +84,18 @@ struct socket_info* grep_sock_info_by_port(unsigned short port,
74 74
 struct socket_info* find_si(struct ip_addr* ip, unsigned short port,
75 75
 												unsigned short proto);
76 76
 
77
+
78
+
77 79
 /* helper function:
78 80
  * returns next protocol, if the last one is reached return 0
79
- * useful for cycling on the supported protocols */
81
+ * useful for cycling on the supported protocols
82
+ * order: udp, tcp, tls, sctp */
80 83
 static inline int next_proto(unsigned short proto)
81 84
 {
82
-	switch(proto){
83
-		case PROTO_NONE:
84
-			return PROTO_UDP;
85
-		case PROTO_UDP:
86
-#ifdef	USE_TCP
87
-			return (tcp_disable)?0:PROTO_TCP;
88
-#else
89
-			return 0;
90
-#endif
91
-#ifdef USE_TCP
92
-		case PROTO_TCP:
93
-#ifdef USE_TLS
94
-			return (tls_disable)?0:PROTO_TLS;
95
-#else
96
-			return 0;
97
-#endif
98
-#endif
99
-#ifdef USE_TLS
100
-		case PROTO_TLS:
101
-			return 0;
102
-#endif
103
-		default:
85
+	if (proto>PROTO_LAST)
104 86
 			LOG(L_ERR, "ERROR: next_proto: unknown proto %d\n", proto);
105
-	}
87
+	else
88
+		return nxt_proto[proto];
106 89
 	return 0;
107 90
 }
108 91
 
... ...
@@ -116,6 +109,11 @@ inline static struct socket_info* get_first_socket()
116 116
 	if (udp_listen) return udp_listen;
117 117
 #ifdef USE_TCP
118 118
 	else if (tcp_listen) return tcp_listen;
119
+#endif
120
+#ifdef USE_SCTP
121
+	else if (sctp_listen) return sctp_listen;
122
+#endif
123
+#ifdef USE_TCP
119 124
 #ifdef USE_TLS
120 125
 	else if (tls_listen) return tls_listen;
121 126
 #endif