... | ... |
@@ -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 |