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 146
 #include "tls_hooks_init.h"
146 147
 #endif /* CORE_TLS */
147 148
 #endif /* USE_TCP */
149
+#ifdef USE_SCTP
150
+#include "sctp_options.h"
151
+#include "sctp_server.h"
152
+#endif
148 153
 #include "usr_avp.h"
149 154
 #include "core_cmd.h"
150 155
 #include "flags.h"
... ...
@@ -211,6 +216,10 @@ Options:\n\
211 216
     -N           Number of tcp child processes (default: equal to `-n')\n\
212 217
     -W           poll method\n"
213 218
 #endif
219
+#ifdef USE_SCTP
220
+"    -S           Disable sctp\n\
221
+    -O            Number of sctp child processes (default: equal to `-n')\n"
222
+#endif /* USE_SCTP */
214 223
 "    -V           Version number\n\
215 224
     -h           This help message\n\
216 225
     -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 297
 int tls_disable = 1;  /* tls disabled by default */
289 298
 #endif /* CORE_TLS */
290 299
 #endif /* USE_TLS */
300
+#ifdef USE_SCTP
301
+int sctp_children_no = 0;
302
+int sctp_disable = 0; /* 1 if sctp is disabled */
303
+#endif /* USE_SCTP */
291 304
 
292 305
 struct process_table *pt=0;		/*array with children pids, 0= main proc,
293 306
 									alloc'ed in shared mem if possible*/
... ...
@@ -392,6 +405,9 @@ struct socket_info* tcp_listen=0;
392 405
 #ifdef USE_TLS
393 406
 struct socket_info* tls_listen=0;
394 407
 #endif
408
+#ifdef USE_SCTP
409
+struct socket_info* sctp_listen=0;
410
+#endif
395 411
 struct socket_info* bind_address=0; /* pointer to the crt. proc.
396 412
 									 listening address*/
397 413
 struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/
... ...
@@ -404,6 +420,10 @@ struct socket_info* sendipv6_tcp;
404 420
 struct socket_info* sendipv4_tls;
405 421
 struct socket_info* sendipv6_tls;
406 422
 #endif
423
+#ifdef USE_SCTP
424
+struct socket_info* sendipv4_sctp;
425
+struct socket_info* sendipv6_sctp;
426
+#endif
407 427
 
408 428
 unsigned short port_no=0; /* default port*/
409 429
 #ifdef USE_TLS
... ...
@@ -486,6 +506,9 @@ void cleanup(show_status)
486 506
 	destroy_tls();
487 507
 #endif /* USE_TLS */
488 508
 #endif /* USE_TCP */
509
+#ifdef USE_SCTP
510
+	destroy_sctp();
511
+#endif
489 512
 	destroy_timer();
490 513
 	destroy_script_cb();
491 514
 	destroy_nonsip_hooks();
... ...
@@ -777,29 +800,46 @@ error:
777 800
  * sets proto */
778 801
 static int parse_proto(unsigned char* s, long len, int* proto)
779 802
 {
780
-#define PROTO2UINT(a, b, c) ((	(((unsigned int)(a))<<16)+ \
803
+#define PROTO2UINT3(a, b, c) ((	(((unsigned int)(a))<<16)+ \
781 804
 								(((unsigned int)(b))<<8)+  \
782 805
 								((unsigned int)(c)) ) | 0x20202020)
806
+#define PROTO2UINT4(a, b ,c ,d) ((	(((unsigned int)(a))<<24)+ \
807
+									(((unsigned int)(b))<<16)+ \
808
+									(((unsigned int)(c))<< 8)+ \
809
+									(((unsigned int)(d))) \
810
+								  )| 0x20202020 )
783 811
 	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;
812
+	if (likely(len==3)){
813
+		i=PROTO2UINT3(s[0], s[1], s[2]);
814
+		switch(i){
815
+			case PROTO2UINT3('u', 'd', 'p'):
816
+				*proto=PROTO_UDP;
817
+				break;
790 818
 #ifdef USE_TCP
791
-		case PROTO2UINT('t', 'c', 'p'):
792
-			*proto=PROTO_TCP;
793
-			break;
819
+			case PROTO2UINT3('t', 'c', 'p'):
820
+				*proto=PROTO_TCP;
821
+				break;
794 822
 #ifdef USE_TLS
795
-		case PROTO2UINT('t', 'l', 's'):
796
-			*proto=PROTO_TLS;
797
-			break;
823
+			case PROTO2UINT3('t', 'l', 's'):
824
+				*proto=PROTO_TLS;
825
+				break;
798 826
 #endif
799 827
 #endif
800
-		default:
828
+			default:
829
+				return -1;
830
+		}
831
+	}
832
+#ifdef USE_SCTP
833
+	else if (likely(len==4)){
834
+		i=PROTO2UINT4(s[0], s[1], s[2], s[3]);
835
+		if (i==PROTO2UINT4('s', 'c', 't', 'p'))
836
+			*proto=PROTO_SCTP;
837
+		else
801 838
 			return -1;
802 839
 	}
840
+#endif /* USE_SCTP */
841
+	else
842
+		return -1;
803 843
 	return 0;
804 844
 }
805 845
 
... ...
@@ -1032,12 +1072,13 @@ int main_loop()
1032 1072
 			"stand-alone receiver @ %s:%s",
1033 1073
 			 bind_address->name.s, bind_address->port_no_str.s );
1034 1074
 
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
-	}
1075
+		/* call it also w/ PROC_MAIN to make sure modules that init things 
1076
+		 * only in PROC_MAIN get a chance to run */
1077
+		if (init_child(PROC_MAIN) < 0) {
1078
+			LOG(L_ERR, "ERROR: main_dontfork: init_child(PROC_MAIN) "
1079
+						"-- exiting\n");
1080
+			goto error;
1081
+		}
1041 1082
 
1042 1083
 		/* We will call child_init even if we
1043 1084
 		 * do not fork - and it will be called with rank 1 because
... ...
@@ -1064,6 +1105,22 @@ int main_loop()
1064 1105
 				sendipv6=si;
1065 1106
 	#endif
1066 1107
 		}
1108
+#ifdef USE_SCTP
1109
+		if (!sctp_disable){
1110
+			for(si=sctp_listen; si; si=si->next){
1111
+				if (sctp_init_sock(si)==-1)  goto error;
1112
+				/* get first ipv4/ipv6 socket*/
1113
+				if ((si->address.af==AF_INET)&&
1114
+						((sendipv4_sctp==0)||
1115
+						 	(sendipv4_sctp->flags&(SI_IS_LO|SI_IS_MCAST))))
1116
+					sendipv4_sctp=si;
1117
+		#ifdef USE_IPV6
1118
+				if((sendipv6_sctp==0)&&(si->address.af==AF_INET6))
1119
+					sendipv6_sctp=si;
1120
+		#endif
1121
+			}
1122
+		}
1123
+#endif /* USE_SCTP */
1067 1124
 #ifdef USE_TCP
1068 1125
 		if (!tcp_disable){
1069 1126
 			for(si=tcp_listen; si; si=si->next){
... ...
@@ -1099,8 +1156,8 @@ int main_loop()
1099 1156
 #endif /* USE_TLS */
1100 1157
 #endif /* USE_TCP */
1101 1158
 
1102
-			/* all processes should have access to all the sockets (for sending)
1103
-			 * so we open all first*/
1159
+			/* all processes should have access to all the sockets (for 
1160
+			 * sending) so we open all first*/
1104 1161
 		if (do_suid()==-1) goto error; /* try to drop privileges */
1105 1162
 
1106 1163
 		/* init childs with rank==PROC_INIT before forking any process,
... ...
@@ -1139,12 +1196,37 @@ int main_loop()
1139 1196
 			/*parent*/
1140 1197
 			/*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/
1141 1198
 		}
1142
-	}
1199
+#ifdef USE_SCTP
1200
+		/* sctp processes */
1201
+		if (!sctp_disable){
1202
+			for(si=sctp_listen; si; si=si->next){
1203
+				for(i=0;i<sctp_children_no;i++){
1204
+					snprintf(si_desc, MAX_PT_DESC, "sctp receiver child=%d "
1205
+								"sock=%s:%s",
1206
+								i, si->name.s, si->port_no_str.s);
1207
+					child_rank++;
1208
+					pid = fork_process(child_rank, si_desc, 1);
1209
+					if (pid<0){
1210
+						LOG(L_CRIT,  "main_loop: Cannot fork\n");
1211
+						goto error;
1212
+					}else if (pid==0){
1213
+						/* child */
1214
+						bind_address=si; /* shortcut */
1215
+#ifdef STATS
1216
+						setstats( i+r*children_no );
1217
+#endif
1218
+						return sctp_rcv_loop();
1219
+					}
1220
+				}
1221
+			/*parent*/
1222
+			/*close(sctp_sock)*/; /*if closed=>sendto invalid fd errors?*/
1223
+			}
1224
+		}
1225
+#endif /* USE_SCTP */
1143 1226
 
1144
-	/*this is the main process*/
1145
-	bind_address=0;				/* main proc -> it shouldn't send anything, */
1227
+		/*this is the main process*/
1228
+		bind_address=0;	/* main proc -> it shouldn't send anything, */
1146 1229
 
1147
-	{
1148 1230
 #ifdef USE_SLOW_TIMER
1149 1231
 		/* fork again for the "slow" timer process*/
1150 1232
 		pid = fork_process(PROC_TIMER, "slow timer", 1);
... ...
@@ -1173,17 +1255,15 @@ int main_loop()
1173 1255
 				set_rt_prio(rt_timer1_prio, rt_timer1_policy);
1174 1256
 			if (arm_timer()<0) goto error;
1175 1257
 			timer_main();
1176
-		}else{
1177 1258
 		}
1178
-	}
1179 1259
 
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
-	}
1260
+	/* init childs with rank==MAIN before starting tcp main (in case they want
1261
+	 * to fork  a tcp capable process, the corresponding tcp. comm. fds in
1262
+	 * pt[] must be set before calling tcp_main_loop()) */
1263
+		if (init_child(PROC_MAIN) < 0) {
1264
+			LOG(L_ERR, "ERROR: main: error in init_child\n");
1265
+			goto error;
1266
+		}
1187 1267
 
1188 1268
 #ifdef USE_TCP
1189 1269
 		if (!tcp_disable){
... ...
@@ -1204,32 +1284,32 @@ int main_loop()
1204 1284
 			}
1205 1285
 		}
1206 1286
 #endif
1207
-	/* main */
1208
-	strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
1287
+		/* main */
1288
+		strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
1209 1289
 #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
-	}
1290
+		close_extra_socks(PROC_ATTENDANT, get_proc_no());
1291
+		if(!tcp_disable){
1292
+			/* main's tcp sockets are disabled by default from init_pt() */
1293
+			unix_tcp_sock=-1;
1294
+		}
1215 1295
 #endif
1216 1296
 
1217
-	/*DEBUG- remove it*/
1218 1297
 #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
-	}
1298
+		for (r=0; r<*process_count; r++){
1299
+			fprintf(stderr, "% 3d   % 5d - %s\n", r, pt[r].pid, pt[r].desc);
1300
+		}
1222 1301
 #endif
1223
-	DBG("Expect maximum %d  open fds\n", get_max_open_fds());
1302
+		DBG("Expect maximum %d  open fds\n", get_max_open_fds());
1224 1303
 
1225
-	for(;;){
1304
+		for(;;){
1226 1305
 			handle_sigs();
1227 1306
 			pause();
1307
+		}
1308
+	
1228 1309
 	}
1229 1310
 
1230
-
1231 1311
 	/*return 0; */
1232
- error:
1312
+error:
1233 1313
 				 /* if we are here, we are the "main process",
1234 1314
 				  any forked children should exit with exit(-1) and not
1235 1315
 				  ever use return */
... ...
@@ -1245,8 +1325,14 @@ static int calc_proc_no(void)
1245 1325
 {
1246 1326
 	int udp_listeners;
1247 1327
 	struct socket_info* si;
1328
+#ifdef USE_SCTP
1329
+	int sctp_listeners;
1330
+#endif
1248 1331
 
1249 1332
 	for (si=udp_listen, udp_listeners=0; si; si=si->next, udp_listeners++);
1333
+#ifdef USE_SCTP
1334
+	for (si=sctp_listen, sctp_listeners=0; si; si=si->next, sctp_listeners++);
1335
+#endif
1250 1336
 	return
1251 1337
 		     /* receivers and attendant */
1252 1338
 		(dont_fork ? 1 : children_no * udp_listeners + 1)
... ...
@@ -1258,6 +1344,9 @@ static int calc_proc_no(void)
1258 1344
 #endif
1259 1345
 #ifdef USE_TCP
1260 1346
 		+((!tcp_disable)?( 1/* tcp main */ + tcp_children_no ):0)
1347
+#endif
1348
+#ifdef USE_SCTP
1349
+		+((!sctp_disable)?sctp_children_no*sctp_listeners:0)
1261 1350
 #endif
1262 1351
 		;
1263 1352
 }
... ...
@@ -1295,7 +1384,7 @@ int main(int argc, char** argv)
1295 1384
 		"DBG_MSG_QA enabled, ser may exit abruptly\n");
1296 1385
 #endif
1297 1386
 
1298
-	options=  ":f:cm:dVhEb:l:L:n:vrRDTN:W:w:t:u:g:P:G:"
1387
+	options=  ":f:cm:dVhEb:l:L:n:vrRDTN:W:w:t:u:g:P:G:SO:"
1299 1388
 #ifdef STATS
1300 1389
 		"s:"
1301 1390
 #endif
... ...
@@ -1303,6 +1392,9 @@ int main(int argc, char** argv)
1303 1392
 	
1304 1393
 #ifdef USE_TCP
1305 1394
 	init_tcp_options(); /* set the defaults before the config */
1395
+#endif
1396
+#ifdef USE_SCTP
1397
+	init_sctp_options(); /* set defaults before the config */
1306 1398
 #endif
1307 1399
 	/* look if there is a -h, e.g. -f -h construction won't catch it later */
1308 1400
 	opterr = 0;
... ...
@@ -1535,6 +1627,25 @@ try_again:
1535 1627
 					fprintf(stderr,"WARNING: tcp support not compiled in\n");
1536 1628
 				#endif
1537 1629
 					break;
1630
+			case 'S':
1631
+				#ifdef USE_SCTP
1632
+					sctp_disable=1;
1633
+				#else
1634
+					fprintf(stderr,"WARNING: sctp support not compiled in\n");
1635
+				#endif
1636
+					break;
1637
+			case 'O':
1638
+				#ifdef USE_SCTP
1639
+					sctp_children_no=strtol(optarg, &tmp, 10);
1640
+					if ((tmp==0) ||(*tmp)){
1641
+						fprintf(stderr, "bad process number: -O %s\n",
1642
+									optarg);
1643
+						goto error;
1644
+					}
1645
+				#else
1646
+					fprintf(stderr,"WARNING: sctp support not compiled in\n");
1647
+				#endif
1648
+					break;
1538 1649
 			case 'w':
1539 1650
 					working_dir=optarg;
1540 1651
 					break;
... ...
@@ -1573,6 +1684,14 @@ try_again:
1573 1684
 	/* init locks first */
1574 1685
 	if (init_lock_ops()!=0)
1575 1686
 		goto error;
1687
+#ifdef USE_TCP
1688
+#ifdef USE_TLS
1689
+	if (tcp_disable)
1690
+		tls_disable=1; /* if no tcp => no tls */
1691
+#endif /* USE_TLS */
1692
+#endif /* USE_TCP */
1693
+	/* initialize the configured proto list */
1694
+	init_proto_order();
1576 1695
 	/* init the resolver, before fixing the config */
1577 1696
 	resolv_init();
1578 1697
 	/* fix parameters */
... ...
@@ -1588,6 +1707,11 @@ try_again:
1588 1707
 		if (tcp_children_no<=0) tcp_children_no=children_no;
1589 1708
 	}
1590 1709
 #endif
1710
+#ifdef USE_SCTP
1711
+	if (!sctp_disable){
1712
+		if (sctp_children_no<=0) sctp_children_no=children_no;
1713
+	}
1714
+#endif
1591 1715
 
1592 1716
 	if (working_dir==0) working_dir="/";
1593 1717
 
1594 1718
new file mode 100644
... ...
@@ -0,0 +1,66 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/* 
19
+ * sctp options
20
+ */
21
+/*
22
+ * History:
23
+ * --------
24
+ *  2008-08-07  initial version (andrei)
25
+ */
26
+
27
+
28
+#include "sctp_options.h"
29
+#include "dprint.h"
30
+
31
+
32
+struct sctp_cfg_options sctp_options;
33
+
34
+void init_sctp_options()
35
+{
36
+#ifdef USE_SCTP
37
+	sctp_options.sctp_autoclose=DEFAULT_SCTP_AUTOCLOSE; /* in seconds */
38
+	sctp_options.sctp_send_ttl=DEFAULT_SCTP_SEND_TTL;   /* in milliseconds */
39
+#endif
40
+}
41
+
42
+
43
+
44
+#define W_OPT_NSCTP(option) \
45
+	if (sctp_options.option){\
46
+		WARN("sctp_options: " #option \
47
+			" cannot be enabled (sctp support not compiled-in)\n"); \
48
+			sctp_options.option=0; \
49
+	}
50
+
51
+
52
+
53
+void sctp_options_check()
54
+{
55
+#ifndef USE_SCTP
56
+	W_OPT_NSCTP(sctp_autoclose);
57
+	W_OPT_NSCTP(sctp_send_ttl);
58
+#endif
59
+}
60
+
61
+
62
+
63
+void sctp_options_get(struct sctp_cfg_options *s)
64
+{
65
+	*s=sctp_options;
66
+}
0 67
new file mode 100644
... ...
@@ -0,0 +1,47 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/* 
19
+ * sctp options
20
+ */
21
+/*
22
+ * History:
23
+ * --------
24
+ *  2008-08-07  initial version (andrei)
25
+ */
26
+
27
+#ifndef _sctp_options_h
28
+#define _sctp_options_h
29
+
30
+#define DEFAULT_SCTP_AUTOCLOSE 180 /* seconds */
31
+#define DEFAULT_SCTP_SEND_TTL  32000 /* in ms (32s)  */
32
+
33
+
34
+struct sctp_cfg_options{
35
+	int sctp_so_rcvbuf;
36
+	int sctp_so_sndbuf;
37
+	unsigned int sctp_autoclose; /* in seconds */
38
+	unsigned int sctp_send_ttl; /* in milliseconds */
39
+};
40
+
41
+extern struct sctp_cfg_options sctp_options;
42
+
43
+void init_sctp_options();
44
+void sctp_options_check();
45
+void sctp_options_get(struct sctp_cfg_options *s);
46
+
47
+#endif /* _sctp_options_h */
0 48
new file mode 100644
... ...
@@ -0,0 +1,351 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/* 
19
+ * sctp one to many 
20
+ */
21
+/*
22
+ * History:
23
+ * --------
24
+ *  2008-08-07  initial version (andrei)
25
+ */
26
+
27
+#ifdef USE_SCTP
28
+
29
+#include <stdlib.h>
30
+#include <string.h>
31
+#include <sys/types.h>
32
+#include <sys/socket.h>
33
+#include <netinet/in.h>
34
+#include <netinet/in_systm.h>
35
+#include <netinet/ip.h>
36
+#include <netinet/sctp.h>
37
+#include <errno.h>
38
+#include <arpa/inet.h>
39
+#include <unistd.h>
40
+#include <fcntl.h>
41
+
42
+
43
+#include "sctp_server.h"
44
+#include "sctp_options.h"
45
+#include "globals.h"
46
+#include "config.h"
47
+#include "dprint.h"
48
+#include "receive.h"
49
+#include "mem/mem.h"
50
+#include "ip_addr.h"
51
+#include "cfg/cfg_struct.h"
52
+
53
+
54
+
55
+int sctp_init_sock(struct socket_info* sock_info)
56
+{
57
+	union sockaddr_union* addr;
58
+	int optval;
59
+	socklen_t optlen;
60
+	
61
+	addr=&sock_info->su;
62
+	sock_info->proto=PROTO_SCTP;
63
+	if (init_su(addr, &sock_info->address, sock_info->port_no)<0){
64
+		LOG(L_ERR, "ERROR: sctp_init_sock: could not init sockaddr_union\n");
65
+		goto error;
66
+	}
67
+	sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_SEQPACKET, 
68
+								IPPROTO_SCTP);
69
+	if (sock_info->socket==-1){
70
+		LOG(L_ERR, "ERROR: sctp_init_sock: socket: %s\n", strerror(errno));
71
+		goto error;
72
+	}
73
+	INFO("sctp: socket %d initialized (%p)\n", sock_info->socket, sock_info);
74
+	/* make socket non-blocking */
75
+#if 0
76
+	/* MSG_WAITALL doesn't work for recvmsg, so use blocking sockets
77
+	 * and send with MSG_DONTWAIT */
78
+	optval=fcntl(sock_info->socket, F_GETFL);
79
+	if (optval==-1){
80
+		LOG(L_ERR, "ERROR: init_sctp: fnctl failed: (%d) %s\n",
81
+				errno, strerror(errno));
82
+		goto error;
83
+	}
84
+	if (fcntl(sock_info->socket, F_SETFL, optval|O_NONBLOCK)==-1){
85
+		LOG(L_ERR, "ERROR: init_sctp: fcntl: set non-blocking failed:"
86
+				" (%d) %s\n", errno, strerror(errno));
87
+		goto error;
88
+	}
89
+#endif
90
+
91
+	/* set sock opts */
92
+	/* set receive buffer: SO_RCVBUF*/
93
+	if (sctp_options.sctp_so_rcvbuf){
94
+		optval=sctp_options.sctp_so_rcvbuf;
95
+		if (setsockopt(sock_info->socket, SOL_SCTP, SO_RCVBUF,
96
+					(void*)&optval, sizeof(optval)) ==-1){
97
+			LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: SO_RCVBUF (%d):"
98
+						" %s\n", optval, strerror(errno));
99
+			/* continue, non-critical */
100
+		}
101
+	}
102
+	
103
+	/* set send buffer: SO_SNDBUF */
104
+	if (sctp_options.sctp_so_sndbuf){
105
+		optval=sctp_options.sctp_so_sndbuf;
106
+		if (setsockopt(sock_info->socket, SOL_SCTP, SO_SNDBUF,
107
+					(void*)&optval, sizeof(optval)) ==-1){
108
+			LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: SO_SNDBUF (%d):"
109
+						" %s\n", optval, strerror(errno));
110
+			/* continue, non-critical */
111
+		}
112
+	}
113
+	
114
+	/* disable fragments interleave (SCTP_FRAGMENT_INTERLEAVE) --
115
+	 * we don't want partial delivery, so fragment interleave must be off too
116
+	 */
117
+	optval=0;
118
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_FRAGMENT_INTERLEAVE ,
119
+					(void*)&optval, sizeof(optval)) ==-1){
120
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
121
+						strerror(errno));
122
+		goto error;
123
+	}
124
+	
125
+	/* turn off partial delivery: on linux setting SCTP_PARTIAL_DELIVERY_POINT
126
+	 * to 0 or a very large number seems to be enough, however the portable
127
+	 * way to do it is to set it to the socket receive buffer size
128
+	 * (this is the maximum value allowed in the sctp api draft) */
129
+	optlen=sizeof(optval);
130
+	if (getsockopt(sock_info->socket, SOL_SCTP, SO_RCVBUF,
131
+					(void*)&optval, &optlen) ==-1){
132
+		LOG(L_ERR, "ERROR: sctp_init_sock: getsockopt: %s\n",
133
+						strerror(errno));
134
+		goto error;
135
+	}
136
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
137
+					(void*)&optval, sizeof(optval)) ==-1){
138
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
139
+						strerror(errno));
140
+		goto error;
141
+	}
142
+	
143
+	/* nagle / no delay */
144
+	optval=1;
145
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_NODELAY,
146
+					(void*)&optval, sizeof(optval)) ==-1){
147
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
148
+						strerror(errno));
149
+		/* non critical, try to continue */
150
+	}
151
+	
152
+	/* enable message fragmentation (SCTP_DISABLE_FRAGMENTS)  (on send) */
153
+	optval=0;
154
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_DISABLE_FRAGMENTS,
155
+					(void*)&optval, sizeof(optval)) ==-1){
156
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
157
+						strerror(errno));
158
+		/* non critical, try to continue */
159
+	}
160
+	
161
+	/* set autoclose */
162
+	optval=sctp_options.sctp_autoclose;
163
+	if (setsockopt(sock_info->socket, SOL_SCTP, SCTP_DISABLE_FRAGMENTS,
164
+					(void*)&optval, sizeof(optval)) ==-1){
165
+		LOG(L_ERR, "ERROR: sctp_init_sock: setsockopt: %s\n",
166
+						strerror(errno));
167
+		/* non critical, try to continue */
168
+	}
169
+	
170
+	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
171
+	 *  information in sctp_sndrcvinfo */
172
+	
173
+	/* SCTP_EVENTS for send dried out -> present in the draft not yet
174
+	 * present in linux (might help to detect when we could send again to
175
+	 * some peer, kind of poor's man poll on write, based on received
176
+	 * SCTP_SENDER_DRY_EVENTs */
177
+	
178
+	
179
+	/* bind the addresses  (TODO multiple addresses support)*/
180
+	if (bind(sock_info->socket,  &addr->s, sockaddru_len(*addr))==-1){
181
+		LOG(L_ERR, "ERROR: sctp_init_sock: bind(%x, %p, %d) on %s: %s\n",
182
+				sock_info->socket, &addr->s, 
183
+				(unsigned)sockaddru_len(*addr),
184
+				sock_info->address_str.s,
185
+				strerror(errno));
186
+	#ifdef USE_IPV6
187
+		if (addr->s.sa_family==AF_INET6)
188
+			LOG(L_ERR, "ERROR: sctp_init_sock: might be caused by using a "
189
+							"link local address, try site local or global\n");
190
+	#endif
191
+		goto error;
192
+	}
193
+	if (listen(sock_info->socket, 1)<0){
194
+		LOG(L_ERR, "ERROR: sctp_init_sock: listen(%x, 1) on %s: %s\n",
195
+					sock_info->socket, sock_info->address_str.s,
196
+					strerror(errno));
197
+		goto error;
198
+	}
199
+	return 0;
200
+error:
201
+	return -1;
202
+}
203
+
204
+
205
+
206
+int sctp_rcv_loop()
207
+{
208
+	unsigned len;
209
+	static char buf [BUF_SIZE+1];
210
+	char *tmp;
211
+	struct receive_info ri;
212
+	struct sctp_sndrcvinfo* sinfo;
213
+	struct msghdr msg;
214
+	struct iovec iov[1];
215
+	/*struct cmsghdr* cmsg; */
216
+	char cbuf[CMSG_SPACE(sizeof(*sinfo))];
217
+
218
+	
219
+	ri.bind_address=bind_address; /* this will not change */
220
+	ri.dst_port=bind_address->port_no;
221
+	ri.dst_ip=bind_address->address;
222
+	ri.proto=PROTO_SCTP;
223
+	ri.proto_reserved1=ri.proto_reserved2=0;
224
+	
225
+	iov[0].iov_base=buf;
226
+	iov[0].iov_len=BUF_SIZE;
227
+	msg.msg_iov=iov;
228
+	msg.msg_iovlen=1;
229
+	msg.msg_control=cbuf;
230
+	msg.msg_controllen=sizeof(cbuf);
231
+	msg.msg_flags=0;
232
+	
233
+
234
+	/* initialize the config framework */
235
+	if (cfg_child_init()) goto error;
236
+	
237
+	for(;;){
238
+		/* recv
239
+		 * recvmsg must be used because the socket is non-blocking
240
+		 * and we want MSG_WAITALL */
241
+		msg.msg_name=&ri.src_su.s;
242
+		msg.msg_namelen=sockaddru_len(bind_address->su);
243
+
244
+		len=recvmsg(bind_address->socket, &msg, MSG_WAITALL);
245
+		/* len=sctp_recvmsg(bind_address->socket, buf, BUF_SIZE, &ri.src_su.s,
246
+							&msg.msg_namelen, &sinfo, &msg.msg_flags); */
247
+		if (len==-1){
248
+			if (errno==EAGAIN){
249
+				DBG("sctp_rcv_loop: EAGAIN on sctp socket\n");
250
+				continue;
251
+			}
252
+			LOG(L_ERR, "ERROR: sctp_rcv_loop: sctp_recvmsg on %d (%p):"
253
+						"[%d] %s\n", bind_address->socket, bind_address,
254
+						errno, strerror(errno));
255
+			if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
256
+				continue; /* goto skip;*/
257
+			else goto error;
258
+		}
259
+		if (unlikely(msg.msg_flags & MSG_NOTIFICATION)){
260
+			/* intercept usefull notifications: TODO */
261
+			DBG("sctp_rcv_loop: MSG_NOTIFICATION\n");
262
+			/* notification in CMSG data */
263
+			continue;
264
+		}else if (unlikely(!(msg.msg_flags & MSG_EOR))){
265
+			LOG(L_ERR, "ERROR: sctp_rcv_loop: partial delivery not"
266
+						"supported\n");
267
+			continue;
268
+		}
269
+		/* we  0-term the messages for debugging */
270
+		buf[len]=0; /* no need to save the previous char */
271
+		su2ip_addr(&ri.src_ip, &ri.src_su);
272
+		ri.src_port=su_getport(&ri.src_su);
273
+
274
+		/* sanity checks */
275
+		if (len<MIN_SCTP_PACKET) {
276
+			tmp=ip_addr2a(&ri.src_ip);
277
+			DBG("sctp_rcv_loop: probing packet received from %s %d\n",
278
+					tmp, htons(ri.src_port));
279
+			continue;
280
+		}
281
+		if (ri.src_port==0){
282
+			tmp=ip_addr2a(&ri.src_ip);
283
+			LOG(L_INFO, "sctp_rcv_loop: dropping 0 port packet from %s\n",
284
+						tmp);
285
+			continue;
286
+		}
287
+	
288
+		/* update the local config */
289
+		cfg_update();
290
+		receive_msg(buf, len, &ri);
291
+	}
292
+error:
293
+	return -1;
294
+}
295
+
296
+
297
+/* send buf:len over udp to dst (uses only the to and send_sock dst members)
298
+ * returns the numbers of bytes sent on success (>=0) and -1 on error
299
+ */
300
+int sctp_msg_send(struct dest_info* dst, char* buf, unsigned len)
301
+{
302
+	int n;
303
+	int tolen;
304
+	struct ip_addr ip; /* used only on error, for debugging */
305
+	struct msghdr msg;
306
+	struct iovec iov[1];
307
+	
308
+	tolen=sockaddru_len(dst->to);
309
+	iov[0].iov_base=buf;
310
+	iov[0].iov_len=len;
311
+	msg.msg_iov=iov;
312
+	msg.msg_iovlen=1;
313
+	msg.msg_name=&dst->to.s;
314
+	msg.msg_namelen=tolen;
315
+	msg.msg_control=0;
316
+	msg.msg_controllen=0;
317
+	msg.msg_flags=SCTP_UNORDERED;
318
+again:
319
+	n=sendmsg(dst->send_sock->socket, &msg, MSG_DONTWAIT);
320
+#if 0
321
+	n=sctp_sendmsg(dst->send_sock->socket, buf, len, &dst->to.s, tolen,
322
+					0 /* ppid */, SCTP_UNORDERED /* | SCTP_EOR */ /* flags */,
323
+					0 /* stream */, sctp_options.sctp_send_ttl /* ttl */,
324
+					0 /* context */);
325
+#endif
326
+	if (n==-1){
327
+		su2ip_addr(&ip, &dst->to);
328
+		LOG(L_ERR, "ERROR: sctp_msg_send: sendmsg(sock,%p,%d,0,%s:%d,%d):"
329
+				" %s(%d)\n", buf, len, ip_addr2a(&ip), su_getport(&dst->to),
330
+				tolen, strerror(errno),errno);
331
+		if (errno==EINTR) goto again;
332
+		if (errno==EINVAL) {
333
+			LOG(L_CRIT,"CRITICAL: invalid sendmsg parameters\n"
334
+			"one possible reason is the server is bound to localhost and\n"
335
+			"attempts to send to the net\n");
336
+		}else if (errno==EAGAIN || errno==EWOULDBLOCK){
337
+			LOG(L_ERR, "ERROR: sctp_msg_send: failed to send, send buffers"
338
+						" full\n");
339
+			/* TODO: fix blocking writes */
340
+		}
341
+	}
342
+	return n;
343
+}
344
+
345
+
346
+
347
+void destroy_sctp()
348
+{
349
+}
350
+
351
+#endif /* USE_SCTP */
0 352
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/* 
19
+ * sctp one to many 
20
+ */
21
+/*
22
+ * History:
23
+ * --------
24
+ *  2008-08-07  initial version (andrei)
25
+ */
26
+
27
+#ifndef _sctp_server_h
28
+#define _sctp_server_h
29
+
30
+#include "ip_addr.h"
31
+
32
+int sctp_init_sock(struct socket_info* sock_info);
33
+int sctp_rcv_loop();
34
+int sctp_msg_send(struct dest_info* dst, char* buf, unsigned len);
35
+
36
+void destroy_sctp();
37
+
38
+#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 104
 
104 105
 
105 106
 
107
+/* protocol order, filled by init_proto_order() */
108
+enum sip_protos nxt_proto[PROTO_LAST+1]=
109
+{ PROTO_UDP, PROTO_TCP, PROTO_TLS, PROTO_SCTP, 0 };
110
+
111
+
112
+
106 113
 /* another helper function, it just creates a socket_info struct */
107 114
 static inline struct socket_info* new_sock_info(	char* name,
108 115
 								unsigned short port, unsigned short proto,
... ...
@@ -157,6 +164,10 @@ static char* get_proto_name(unsigned short proto)
157 164
 #ifdef USE_TLS
158 165
 		case PROTO_TLS:
159 166
 			return "tls";
167
+#endif
168
+#ifdef USE_SCTP
169
+		case PROTO_SCTP:
170
+			return "sctp";
160 171
 #endif
161 172
 		default:
162 173
 			return "unknown";
... ...
@@ -180,6 +191,11 @@ static struct socket_info** get_sock_info_list(unsigned short proto)
180 191
 		case PROTO_TLS:
181 192
 			return &tls_listen;
182 193
 			break;
194
+#endif
195
+#ifdef USE_SCTP
196
+		case PROTO_SCTP:
197
+			return &sctp_listen;
198
+			break;
183 199
 #endif
184 200
 		default:
185 201
 			LOG(L_CRIT, "BUG: get_sock_info_list: invalid proto %d\n", proto);
... ...
@@ -775,6 +791,9 @@ int fix_all_socket_lists()
775 791
 #ifdef USE_TLS
776 792
 			&& (tls_listen==0)
777 793
 #endif
794
+#endif
795
+#ifdef USE_SCTP
796
+			&& (sctp_listen==0)
778 797
 #endif
779 798
 		){
780 799
 		/* get all listening ipv4 interfaces */
... ...
@@ -793,6 +812,13 @@ int fix_all_socket_lists()
793 812
 #endif
794 813
 			}
795 814
 #endif
815
+#ifdef USE_SCTP
816
+			if (!sctp_disable){
817
+				if (add_interfaces(0, AF_INET, 0,  PROTO_SCTP,
818
+									&sctp_listen)!=0)
819
+					goto error;
820
+			}
821
+#endif /* USE_SCTP */
796 822
 		}else{
797 823
 			/* if error fall back to get hostname */
798 824
 			/* get our address, only the first one */
... ...
@@ -836,12 +862,25 @@ int fix_all_socket_lists()
836 862
 	}
837 863
 #endif
838 864
 #endif
865
+#ifdef USE_SCTP
866
+	if (!sctp_disable && (fix_socket_list(&sctp_listen, &flags)!=0)){
867
+		LOG(L_ERR, "ERROR: fix_all_socket_lists: fix_socket_list"
868
+				" sctp failed\n");
869
+		goto error;
870
+	}
871
+	if (flags){
872
+		socket_types|=flags|SOCKET_T_SCTP;
873
+	}
874
+#endif /* USE_SCTP */
839 875
 	if ((udp_listen==0)
840 876
 #ifdef USE_TCP
841 877
 			&& (tcp_listen==0)
842 878
 #ifdef USE_TLS
843 879
 			&& (tls_listen==0)
844 880
 #endif
881
+#endif
882
+#ifdef USE_SCTP
883
+			&& (sctp_listen==0)
845 884
 #endif
846 885
 		){
847 886
 		LOG(L_ERR, "ERROR: fix_all_socket_lists: no listening sockets\n");
... ...
@@ -885,3 +924,37 @@ void print_aliases()
885 924
 			printf("             %s: %.*s:*\n", get_proto_name(a->proto), 
886 925
 					a->alias.len, a->alias.s);
887 926
 }
927
+
928
+
929
+
930
+void init_proto_order()
931
+{
932
+	int r;
933
+	
934
+	/* fix proto list  (remove disabled protocols)*/
935
+#ifdef USE_TCP
936
+	if (tcp_disable)
937
+#endif
938
+		for(r=PROTO_NONE; r<=PROTO_LAST; r++){
939
+			if (nxt_proto[r]==PROTO_TCP)
940
+				nxt_proto[r]=nxt_proto[PROTO_TCP];
941
+		}
942
+#ifdef USE_TCP
943
+#ifdef USE_TLS
944
+	if (tls_disable || tcp_disable)
945
+#endif
946
+#endif
947
+		for(r=PROTO_NONE; r<=PROTO_LAST; r++){
948
+			if (nxt_proto[r]==PROTO_TLS)
949
+				nxt_proto[r]=nxt_proto[PROTO_TLS];
950
+		}
951
+#ifdef USE_SCTP
952
+	if (sctp_disable)
953
+		for(r=PROTO_NONE; r<=PROTO_LAST; r++){
954
+			if (nxt_proto[r]==PROTO_SCTP)
955
+				nxt_proto[r]=nxt_proto[PROTO_SCTP];
956
+		}
957
+#endif
958
+}
959
+
960
+
... ...
@@ -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 51
 #ifdef USE_TLS
51 52
 extern struct socket_info* tls_listen;
52 53
 #endif
54
+#ifdef USE_SCTP
55
+extern struct socket_info* sctp_listen;
56
+#endif
57
+
58
+extern enum sip_protos nxt_proto[PROTO_LAST+1];
59
+
53 60
 
54 61
 
55 62
 /* 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
63
+#define SOCKET_T_IPV4  1
64
+#define SOCKET_T_IPV6  2
65
+#define SOCKET_T_UDP   4
66
+#define SOCKET_T_TCP   8
67
+#define SOCKET_T_TLS  16
68
+#define SOCKET_T_SCTP 32
61 69
 
62 70
 extern int socket_types;
63 71
 
72
+void init_proto_order();
73
+
64 74
 int add_listen_iface(char* name, unsigned short port, unsigned short proto,
65 75
 							enum si_flags flags);
66 76
 int fix_all_socket_lists();
... ...
@@ -74,35 +84,18 @@ struct socket_info* grep_sock_info_by_port(unsigned short port,
74 84
 struct socket_info* find_si(struct ip_addr* ip, unsigned short port,
75 85
 												unsigned short proto);
76 86
 
87
+
88
+
77 89
 /* helper function:
78 90
  * returns next protocol, if the last one is reached return 0
79
- * useful for cycling on the supported protocols */
91
+ * useful for cycling on the supported protocols
92
+ * order: udp, tcp, tls, sctp */
80 93
 static inline int next_proto(unsigned short proto)
81 94
 {
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:
95
+	if (proto>PROTO_LAST)
104 96
 			LOG(L_ERR, "ERROR: next_proto: unknown proto %d\n", proto);
105
-	}
97
+	else
98
+		return nxt_proto[proto];
106 99
 	return 0;
107 100
 }
108 101
 
... ...
@@ -116,6 +109,11 @@ inline static struct socket_info* get_first_socket()
116 109
 	if (udp_listen) return udp_listen;
117 110
 #ifdef USE_TCP
118 111
 	else if (tcp_listen) return tcp_listen;
112
+#endif
113
+#ifdef USE_SCTP
114
+	else if (sctp_listen) return sctp_listen;
115
+#endif
116
+#ifdef USE_TCP
119 117
 #ifdef USE_TLS
120 118
 	else if (tls_listen) return tls_listen;
121 119
 #endif