Mercurial > hg > freeDiameter
comparison freeDiameter/sctp.c @ 171:8ccbfdb49f1c
Adjustments on the SCTP parameters
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Tue, 02 Feb 2010 14:36:04 +0900 |
parents | 33d8bed6a9d7 |
children | 9c5dfc6399a4 |
comparison
equal
deleted
inserted
replaced
170:4b62e4a92828 | 171:8ccbfdb49f1c |
---|---|
49 #define SCTP_LEVEL FULL | 49 #define SCTP_LEVEL FULL |
50 #else /* DEBUG_SCTP */ | 50 #else /* DEBUG_SCTP */ |
51 #define SCTP_LEVEL (FCTS + 1) | 51 #define SCTP_LEVEL (FCTS + 1) |
52 #endif /* DEBUG_SCTP */ | 52 #endif /* DEBUG_SCTP */ |
53 | 53 |
54 /* Temper with the retransmission timers to try and improve disconnection detection response? Undef this to keep the defaults of SCTP stack */ | |
55 #ifndef USE_DEFAULT_SCTP_RTX_PARAMS /* make this a configuration option if useful */ | |
56 #define ADJUST_RTX_PARAMS | |
57 #endif /* USE_DEFAULT_SCTP_RTX_PARAMS */ | |
58 | |
54 /* Pre-binding socket options -- # streams read in config */ | 59 /* Pre-binding socket options -- # streams read in config */ |
60 /* The code of this file is based on draft-ietf-tsvwg-sctpsocket, versions 17 to 21 */ | |
55 static int fd_setsockopt_prebind(int sk) | 61 static int fd_setsockopt_prebind(int sk) |
56 { | 62 { |
57 socklen_t sz; | 63 socklen_t sz; |
58 | 64 |
59 TRACE_ENTRY( "%d", sk); | 65 TRACE_ENTRY( "%d", sk); |
60 | 66 |
61 CHECK_PARAMS( sk > 0 ); | 67 CHECK_PARAMS( sk > 0 ); |
62 | 68 |
69 #ifdef ADJUST_RTX_PARAMS | |
70 /* Set the retransmit parameters */ | |
71 #ifdef SCTP_RTOINFO | |
72 { | |
73 struct sctp_rtoinfo rtoinfo; | |
74 memset(&rtoinfo, 0, sizeof(rtoinfo)); | |
75 | |
76 if (TRACE_BOOL(SCTP_LEVEL)) { | |
77 sz = sizeof(rtoinfo); | |
78 /* Read socket defaults */ | |
79 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); | |
80 if (sz != sizeof(rtoinfo)) | |
81 { | |
82 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo)); | |
83 return ENOTSUP; | |
84 } | |
85 fd_log_debug( "Def SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial); | |
86 fd_log_debug( " srto_min : %u\n", rtoinfo.srto_min); | |
87 fd_log_debug( " srto_max : %u\n", rtoinfo.srto_max); | |
88 } | |
89 | |
90 /* rtoinfo.srto_initial: Estimate of the RTT before it can be measured; keep the default value */ | |
91 rtoinfo.srto_max = 5000; /* Maximum retransmit timer (in ms), we want fast retransmission time. */ | |
92 rtoinfo.srto_min = 1000; /* Value under which the RTO does not descend, we set this value to not conflict with srto_max */ | |
93 | |
94 /* Set the option to the socket */ | |
95 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo)) ); | |
96 | |
97 if (TRACE_BOOL(SCTP_LEVEL)) { | |
98 /* Check new values */ | |
99 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); | |
100 fd_log_debug( "New SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial); | |
101 fd_log_debug( " srto_max : %u\n", rtoinfo.srto_max); | |
102 fd_log_debug( " srto_min : %u\n", rtoinfo.srto_min); | |
103 } | |
104 } | |
105 #else /* SCTP_RTOINFO */ | |
106 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_RTOINFO"); | |
107 #endif /* SCTP_RTOINFO */ | |
108 | |
109 /* Set the association parameters: max number of retransmits, ... */ | |
110 #ifdef SCTP_ASSOCINFO | |
111 { | |
112 struct sctp_assocparams assoc; | |
113 memset(&assoc, 0, sizeof(assoc)); | |
114 | |
115 if (TRACE_BOOL(SCTP_LEVEL)) { | |
116 sz = sizeof(assoc); | |
117 /* Read socket defaults */ | |
118 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); | |
119 if (sz != sizeof(assoc)) | |
120 { | |
121 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc)); | |
122 return ENOTSUP; | |
123 } | |
124 fd_log_debug( "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu\n", assoc.sasoc_asocmaxrxt); | |
125 fd_log_debug( " sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations); | |
126 fd_log_debug( " sasoc_peer_rwnd : %u\n" , assoc.sasoc_peer_rwnd); | |
127 fd_log_debug( " sasoc_local_rwnd : %u\n" , assoc.sasoc_local_rwnd); | |
128 fd_log_debug( " sasoc_cookie_life : %u\n" , assoc.sasoc_cookie_life); | |
129 } | |
130 | |
131 assoc.sasoc_asocmaxrxt = 4; /* Maximum number of retransmission attempts: we want fast detection of errors */ | |
132 /* Note that this must remain less than the sum of retransmission parameters of the different paths. */ | |
133 | |
134 /* Set the option to the socket */ | |
135 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) ); | |
136 | |
137 if (TRACE_BOOL(SCTP_LEVEL)) { | |
138 /* Check new values */ | |
139 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); | |
140 fd_log_debug( "New SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu\n", assoc.sasoc_asocmaxrxt); | |
141 fd_log_debug( " sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations); | |
142 fd_log_debug( " sasoc_peer_rwnd : %u\n" , assoc.sasoc_peer_rwnd); | |
143 fd_log_debug( " sasoc_local_rwnd : %u\n" , assoc.sasoc_local_rwnd); | |
144 fd_log_debug( " sasoc_cookie_life : %u\n" , assoc.sasoc_cookie_life); | |
145 } | |
146 } | |
147 #else /* SCTP_ASSOCINFO */ | |
148 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_ASSOCINFO"); | |
149 #endif /* SCTP_ASSOCINFO */ | |
150 #endif /* ADJUST_RTX_PARAMS */ | |
151 | |
152 /* Set the INIT parameters, such as number of streams */ | |
153 #ifdef SCTP_INITMSG | |
154 { | |
155 struct sctp_initmsg init; | |
156 memset(&init, 0, sizeof(init)); | |
157 | |
158 if (TRACE_BOOL(SCTP_LEVEL)) { | |
159 sz = sizeof(init); | |
160 | |
161 /* Read socket defaults */ | |
162 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); | |
163 if (sz != sizeof(init)) | |
164 { | |
165 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init)); | |
166 return ENOTSUP; | |
167 } | |
168 fd_log_debug( "Def SCTP_INITMSG : sinit_num_ostreams : %hu\n", init.sinit_num_ostreams); | |
169 fd_log_debug( " sinit_max_instreams : %hu\n", init.sinit_max_instreams); | |
170 fd_log_debug( " sinit_max_attempts : %hu\n", init.sinit_max_attempts); | |
171 fd_log_debug( " sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo); | |
172 } | |
173 | |
174 /* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters, but we don't care (best effort) */ | |
175 init.sinit_num_ostreams = fd_g_config->cnf_sctp_str; /* desired number of outgoing streams */ | |
176 init.sinit_max_init_timeo = CNX_TIMEOUT * 1000; | |
177 | |
178 /* Set the option to the socket */ | |
179 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init)) ); | |
180 | |
181 if (TRACE_BOOL(SCTP_LEVEL)) { | |
182 /* Check new values */ | |
183 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); | |
184 fd_log_debug( "New SCTP_INITMSG : sinit_num_ostreams : %hu\n", init.sinit_num_ostreams); | |
185 fd_log_debug( " sinit_max_instreams : %hu\n", init.sinit_max_instreams); | |
186 fd_log_debug( " sinit_max_attempts : %hu\n", init.sinit_max_attempts); | |
187 fd_log_debug( " sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo); | |
188 } | |
189 } | |
190 #else /* SCTP_INITMSG */ | |
191 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_INITMSG"); | |
192 #endif /* SCTP_INITMSG */ | |
193 | |
194 /* The SO_LINGER option will be reset if we want to perform SCTP ABORT */ | |
195 #ifdef SO_LINGER | |
196 { | |
197 struct linger linger; | |
198 memset(&linger, 0, sizeof(linger)); | |
199 | |
200 if (TRACE_BOOL(SCTP_LEVEL)) { | |
201 sz = sizeof(linger); | |
202 /* Read socket defaults */ | |
203 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); | |
204 if (sz != sizeof(linger)) | |
205 { | |
206 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger)); | |
207 return ENOTSUP; | |
208 } | |
209 fd_log_debug( "Def SO_LINGER : l_onoff : %d\n", linger.l_onoff); | |
210 fd_log_debug( " l_linger : %d\n", linger.l_linger); | |
211 } | |
212 | |
213 linger.l_onoff = 0; /* Do not activate the linger */ | |
214 linger.l_linger = 0; /* Ignored, but it would mean : Return immediately when closing (=> abort) (graceful shutdown in background) */ | |
215 | |
216 /* Set the option */ | |
217 CHECK_SYS( setsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) ); | |
218 | |
219 if (TRACE_BOOL(SCTP_LEVEL)) { | |
220 /* Check new values */ | |
221 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); | |
222 fd_log_debug( "New SO_LINGER : l_onoff : %d\n", linger.l_onoff); | |
223 fd_log_debug( " l_linger : %d\n", linger.l_linger); | |
224 } | |
225 } | |
226 #else /* SO_LINGER */ | |
227 TRACE_DEBUG(SCTP_LEVEL, "Skipping SO_LINGER"); | |
228 #endif /* SO_LINGER */ | |
229 | |
230 /* Set the NODELAY option (Nagle-like algorithm) */ | |
231 #ifdef SCTP_NODELAY | |
232 { | |
233 int nodelay; | |
234 | |
235 if (TRACE_BOOL(SCTP_LEVEL)) { | |
236 sz = sizeof(nodelay); | |
237 /* Read socket defaults */ | |
238 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); | |
239 if (sz != sizeof(nodelay)) | |
240 { | |
241 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay)); | |
242 return ENOTSUP; | |
243 } | |
244 fd_log_debug( "Def SCTP_NODELAY value : %s\n", nodelay ? "true" : "false"); | |
245 } | |
246 | |
247 nodelay = 1; /* We turn ON the Nagle algorithm (probably the default already), since we might have several messages to send through the same proxy (not the same session). */ | |
248 | |
249 /* Set the option to the socket */ | |
250 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay)) ); | |
251 | |
252 if (TRACE_BOOL(SCTP_LEVEL)) { | |
253 /* Check new values */ | |
254 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); | |
255 fd_log_debug( "New SCTP_NODELAY value : %s\n", nodelay ? "true" : "false"); | |
256 } | |
257 } | |
258 #else /* SCTP_NODELAY */ | |
259 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_NODELAY"); | |
260 #endif /* SCTP_NODELAY */ | |
261 | |
262 /* | |
263 SO_RCVBUF size of receiver window | |
264 SO_SNDBUF size of pending data to send | |
265 SCTP_AUTOCLOSE for one-to-many only | |
266 SCTP_PRIMARY_ADDR use this address as primary locally | |
267 SCTP_ADAPTATION_LAYER set adaptation layer indication, we don't use this | |
268 */ | |
269 | |
270 /* Set the SCTP_DISABLE_FRAGMENTS option, required for TLS */ | |
271 #ifdef SCTP_DISABLE_FRAGMENTS | |
272 { | |
273 int nofrag; | |
274 | |
275 if (TRACE_BOOL(SCTP_LEVEL)) { | |
276 sz = sizeof(nofrag); | |
277 /* Read socket defaults */ | |
278 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); | |
279 if (sz != sizeof(nofrag)) | |
280 { | |
281 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag)); | |
282 return ENOTSUP; | |
283 } | |
284 fd_log_debug( "Def SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false"); | |
285 } | |
286 | |
287 nofrag = 0; /* We turn ON the fragmentation, since Diameter messages & TLS messages can be quite large. */ | |
288 | |
289 /* Set the option to the socket */ | |
290 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, sizeof(nofrag)) ); | |
291 | |
292 if (TRACE_BOOL(SCTP_LEVEL)) { | |
293 /* Check new values */ | |
294 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); | |
295 fd_log_debug( "New SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false"); | |
296 } | |
297 } | |
298 #else /* SCTP_DISABLE_FRAGMENTS */ | |
299 # error "TLS requires support of SCTP_DISABLE_FRAGMENTS" | |
300 #endif /* SCTP_DISABLE_FRAGMENTS */ | |
301 | |
302 /* SCTP_PEER_ADDR_PARAMS control heartbeat per peer address. We set it as a default for all addresses in the association; not sure if it works ... */ | |
303 #ifdef SCTP_PEER_ADDR_PARAMS | |
304 { | |
305 struct sctp_paddrparams parms; | |
306 memset(&parms, 0, sizeof(parms)); | |
307 | |
308 if (TRACE_BOOL(SCTP_LEVEL)) { | |
309 sz = sizeof(parms); | |
310 | |
311 /* Read socket defaults */ | |
312 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &parms, &sz) ); | |
313 if (sz != sizeof(parms)) | |
314 { | |
315 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(parms)); | |
316 return ENOTSUP; | |
317 } | |
318 fd_log_debug( "Def SCTP_PEER_ADDR_PARAMS : spp_hbinterval : %u\n", parms.spp_hbinterval); | |
319 fd_log_debug( " spp_pathmaxrxt : %hu\n", parms.spp_pathmaxrxt); | |
320 fd_log_debug( " spp_pathmtu : %u\n", parms.spp_pathmtu); | |
321 fd_log_debug( " spp_flags : %x\n", parms.spp_flags); | |
322 // fd_log_debug( " spp_ipv6_flowlabel: %u\n", parms.spp_ipv6_flowlabel); | |
323 // fd_log_debug( " spp_ipv4_tos : %hhu\n",parms.spp_ipv4_tos); | |
324 } | |
325 | |
326 parms.spp_flags = SPP_HB_ENABLE; /* Enable heartbeat for the associtation */ | |
327 #ifdef SPP_PMTUD_ENABLE | |
328 parms.spp_flags |= SPP_PMTUD_ENABLE; /* also enable path MTU discovery mechanism */ | |
329 #endif /* SPP_PMTUD_ENABLE */ | |
330 | |
331 #ifdef ADJUST_RTX_PARAMS | |
332 parms.spp_hbinterval = 6000; /* Send an heartbeat every 6 seconds to quickly start retransmissions */ | |
333 /* parms.spp_pathmaxrxt : max nbr of restransmissions on this address. There is a relationship with sasoc_asocmaxrxt, so we leave the default here */ | |
334 #endif /* ADJUST_RTX_PARAMS */ | |
335 | |
336 /* Set the option to the socket */ | |
337 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &parms, sizeof(parms)) ); | |
338 | |
339 if (TRACE_BOOL(SCTP_LEVEL)) { | |
340 /* Check new values */ | |
341 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &parms, &sz) ); | |
342 fd_log_debug( "New SCTP_PEER_ADDR_PARAMS : spp_hbinterval : %u\n", parms.spp_hbinterval); | |
343 fd_log_debug( " spp_pathmaxrxt : %hu\n", parms.spp_pathmaxrxt); | |
344 fd_log_debug( " spp_pathmtu : %u\n", parms.spp_pathmtu); | |
345 fd_log_debug( " spp_flags : %x\n", parms.spp_flags); | |
346 // fd_log_debug( " spp_ipv6_flowlabel: %u\n", parms.spp_ipv6_flowlabel); | |
347 // fd_log_debug( " spp_ipv4_tos : %hhu\n",parms.spp_ipv4_tos); | |
348 } | |
349 } | |
350 #else /* SCTP_PEER_ADDR_PARAMS */ | |
351 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_PEER_ADDR_PARAMS"); | |
352 #endif /* SCTP_PEER_ADDR_PARAMS */ | |
353 | |
354 /* | |
355 SCTP_DEFAULT_SEND_PARAM parameters for the sendto() call, we don't use it. | |
356 */ | |
357 | |
63 /* Subscribe to some notifications */ | 358 /* Subscribe to some notifications */ |
359 #ifdef SCTP_EVENTS | |
64 { | 360 { |
65 struct sctp_event_subscribe event; | 361 struct sctp_event_subscribe event; |
66 | 362 |
67 memset(&event, 0, sizeof(event)); | 363 memset(&event, 0, sizeof(event)); |
68 event.sctp_data_io_event = 1; /* to receive the stream ID in SCTP_SNDRCV ancilliary data on message reception */ | 364 event.sctp_data_io_event = 1; /* to receive the stream ID in SCTP_SNDRCV ancilliary data on message reception */ |
95 fd_log_debug( " sctp_shutdown_event : %hhu\n", event.sctp_shutdown_event); | 391 fd_log_debug( " sctp_shutdown_event : %hhu\n", event.sctp_shutdown_event); |
96 fd_log_debug( " sctp_partial_delivery_event : %hhu\n", event.sctp_partial_delivery_event); | 392 fd_log_debug( " sctp_partial_delivery_event : %hhu\n", event.sctp_partial_delivery_event); |
97 fd_log_debug( " sctp_adaptation_layer_event : %hhu\n", event.sctp_adaptation_layer_event); | 393 fd_log_debug( " sctp_adaptation_layer_event : %hhu\n", event.sctp_adaptation_layer_event); |
98 // fd_log_debug( " sctp_authentication_event : %hhu\n", event.sctp_authentication_event); | 394 // fd_log_debug( " sctp_authentication_event : %hhu\n", event.sctp_authentication_event); |
99 } | 395 } |
100 | 396 } |
101 } | 397 #else /* SCTP_EVENTS */ |
102 | 398 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_EVENTS"); |
103 /* Set the INIT parameters, such as number of streams */ | 399 #endif /* SCTP_EVENTS */ |
104 { | 400 |
105 struct sctp_initmsg init; | 401 /* Set the v4 mapped addresses option */ |
106 memset(&init, 0, sizeof(init)); | 402 #ifdef SCTP_I_WANT_MAPPED_V4_ADDR |
107 | 403 { |
108 if (TRACE_BOOL(SCTP_LEVEL)) { | 404 int v4mapped; |
109 sz = sizeof(init); | 405 |
110 | 406 if (TRACE_BOOL(SCTP_LEVEL)) { |
407 sz = sizeof(v4mapped); | |
111 /* Read socket defaults */ | 408 /* Read socket defaults */ |
112 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); | 409 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); |
113 if (sz != sizeof(init)) | 410 if (sz != sizeof(v4mapped)) |
114 { | 411 { |
115 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init)); | 412 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped)); |
116 return ENOTSUP; | 413 return ENOTSUP; |
117 } | 414 } |
118 fd_log_debug( "Def SCTP_INITMSG : sinit_num_ostreams : %hu\n", init.sinit_num_ostreams); | 415 fd_log_debug( "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false"); |
119 fd_log_debug( " sinit_max_instreams : %hu\n", init.sinit_max_instreams); | 416 } |
120 fd_log_debug( " sinit_max_attempts : %hu\n", init.sinit_max_attempts); | 417 |
121 fd_log_debug( " sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo); | 418 #ifndef SCTP_USE_MAPPED_ADDRESSES |
122 } | 419 v4mapped = 0; /* We don't want v4 mapped addresses */ |
123 | 420 #else /* SCTP_USE_MAPPED_ADDRESSES */ |
124 /* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters */ | 421 v4mapped = 1; /* but we may have to, otherwise the bind fails in some environments */ |
125 init.sinit_num_ostreams = fd_g_config->cnf_sctp_str; /* desired number of outgoing streams */ | 422 #endif /* SCTP_USE_MAPPED_ADDRESSES */ |
126 init.sinit_max_init_timeo = CNX_TIMEOUT * 1000; | 423 |
127 | |
128 /* Set the option to the socket */ | 424 /* Set the option to the socket */ |
129 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init)) ); | 425 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped)) ); |
130 | 426 |
131 if (TRACE_BOOL(SCTP_LEVEL)) { | 427 if (TRACE_BOOL(SCTP_LEVEL)) { |
132 /* Check new values */ | 428 /* Check new values */ |
133 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); | 429 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); |
134 fd_log_debug( "New SCTP_INITMSG : sinit_num_ostreams : %hu\n", init.sinit_num_ostreams); | 430 fd_log_debug( "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false"); |
135 fd_log_debug( " sinit_max_instreams : %hu\n", init.sinit_max_instreams); | 431 } |
136 fd_log_debug( " sinit_max_attempts : %hu\n", init.sinit_max_attempts); | 432 } |
137 fd_log_debug( " sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo); | 433 #else /* SCTP_I_WANT_MAPPED_V4_ADDR */ |
138 } | 434 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR"); |
139 } | 435 #endif /* SCTP_I_WANT_MAPPED_V4_ADDR */ |
140 | 436 |
141 /* Set the SCTP_DISABLE_FRAGMENTS option, required for TLS */ | 437 /* |
142 #ifdef SCTP_DISABLE_FRAGMENTS | 438 SCTP_MAXSEG max size of fragmented segments -- bound to PMTU |
143 { | 439 SCTP_HMAC_IDENT authentication algorithms |
144 int nofrag; | 440 SCTP_AUTH_ACTIVE_KEY set the active key |
145 | 441 SCTP_DELAYED_SACK control delayed acks |
146 if (TRACE_BOOL(SCTP_LEVEL)) { | 442 */ |
147 sz = sizeof(nofrag); | 443 |
148 /* Read socket defaults */ | |
149 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); | |
150 if (sz != sizeof(nofrag)) | |
151 { | |
152 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag)); | |
153 return ENOTSUP; | |
154 } | |
155 fd_log_debug( "Def SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false"); | |
156 } | |
157 | |
158 nofrag = 0; /* We turn ON the fragmentation */ | |
159 | |
160 /* Set the option to the socket */ | |
161 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, sizeof(nofrag)) ); | |
162 | |
163 if (TRACE_BOOL(SCTP_LEVEL)) { | |
164 /* Check new values */ | |
165 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); | |
166 fd_log_debug( "New SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false"); | |
167 } | |
168 } | |
169 #else /* SCTP_DISABLE_FRAGMENTS */ | |
170 # error "TLS requires support of SCTP_DISABLE_FRAGMENTS" | |
171 #endif /* SCTP_DISABLE_FRAGMENTS */ | |
172 | |
173 | |
174 /* Set the RETRANSMIT parameters */ | |
175 #ifdef SCTP_RTOINFO | |
176 { | |
177 struct sctp_rtoinfo rtoinfo; | |
178 memset(&rtoinfo, 0, sizeof(rtoinfo)); | |
179 | |
180 if (TRACE_BOOL(SCTP_LEVEL)) { | |
181 sz = sizeof(rtoinfo); | |
182 /* Read socket defaults */ | |
183 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); | |
184 if (sz != sizeof(rtoinfo)) | |
185 { | |
186 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo)); | |
187 return ENOTSUP; | |
188 } | |
189 fd_log_debug( "Def SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial); | |
190 fd_log_debug( " srto_max : %u\n", rtoinfo.srto_max); | |
191 fd_log_debug( " srto_min : %u\n", rtoinfo.srto_min); | |
192 } | |
193 | |
194 rtoinfo.srto_max = fd_g_config->cnf_timer_tw * 500 - 1000; /* Maximum retransmit timer (in ms) (set to Tw / 2 - 1) */ | |
195 | |
196 /* Set the option to the socket */ | |
197 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo)) ); | |
198 | |
199 if (TRACE_BOOL(SCTP_LEVEL)) { | |
200 /* Check new values */ | |
201 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); | |
202 fd_log_debug( "New SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial); | |
203 fd_log_debug( " srto_max : %u\n", rtoinfo.srto_max); | |
204 fd_log_debug( " srto_min : %u\n", rtoinfo.srto_min); | |
205 } | |
206 } | |
207 #else /* SCTP_RTOINFO */ | |
208 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_RTOINFO"); | |
209 #endif /* SCTP_RTOINFO */ | |
210 | |
211 /* Set the ASSOCIATION parameters */ | |
212 #ifdef SCTP_ASSOCINFO | |
213 { | |
214 struct sctp_assocparams assoc; | |
215 memset(&assoc, 0, sizeof(assoc)); | |
216 | |
217 if (TRACE_BOOL(SCTP_LEVEL)) { | |
218 sz = sizeof(assoc); | |
219 /* Read socket defaults */ | |
220 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); | |
221 if (sz != sizeof(assoc)) | |
222 { | |
223 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc)); | |
224 return ENOTSUP; | |
225 } | |
226 fd_log_debug( "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu\n", assoc.sasoc_asocmaxrxt); | |
227 fd_log_debug( " sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations); | |
228 fd_log_debug( " sasoc_peer_rwnd : %u\n" , assoc.sasoc_peer_rwnd); | |
229 fd_log_debug( " sasoc_local_rwnd : %u\n" , assoc.sasoc_local_rwnd); | |
230 fd_log_debug( " sasoc_cookie_life : %u\n" , assoc.sasoc_cookie_life); | |
231 } | |
232 | |
233 assoc.sasoc_asocmaxrxt = 8; /* Maximum retransmission attempts: we want fast detection of errors */ | |
234 | |
235 /* Set the option to the socket */ | |
236 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) ); | |
237 | |
238 if (TRACE_BOOL(SCTP_LEVEL)) { | |
239 /* Check new values */ | |
240 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); | |
241 fd_log_debug( "New SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu\n", assoc.sasoc_asocmaxrxt); | |
242 fd_log_debug( " sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations); | |
243 fd_log_debug( " sasoc_peer_rwnd : %u\n" , assoc.sasoc_peer_rwnd); | |
244 fd_log_debug( " sasoc_local_rwnd : %u\n" , assoc.sasoc_local_rwnd); | |
245 fd_log_debug( " sasoc_cookie_life : %u\n" , assoc.sasoc_cookie_life); | |
246 } | |
247 } | |
248 #else /* SCTP_ASSOCINFO */ | |
249 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_ASSOCINFO"); | |
250 #endif /* SCTP_ASSOCINFO */ | |
251 | |
252 | |
253 /* The SO_LINGER option will be re-set if we want to perform SCTP ABORT */ | |
254 #ifdef SO_LINGER | |
255 { | |
256 struct linger linger; | |
257 memset(&linger, 0, sizeof(linger)); | |
258 | |
259 if (TRACE_BOOL(SCTP_LEVEL)) { | |
260 sz = sizeof(linger); | |
261 /* Read socket defaults */ | |
262 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); | |
263 if (sz != sizeof(linger)) | |
264 { | |
265 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger)); | |
266 return ENOTSUP; | |
267 } | |
268 fd_log_debug( "Def SO_LINGER : l_onoff : %d\n", linger.l_onoff); | |
269 fd_log_debug( " l_linger : %d\n", linger.l_linger); | |
270 } | |
271 | |
272 linger.l_onoff = 0; /* Do not activate the linger */ | |
273 linger.l_linger = 0; /* Return immediately when closing (=> abort) */ | |
274 | |
275 /* Set the option */ | |
276 CHECK_SYS( setsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) ); | |
277 | |
278 if (TRACE_BOOL(SCTP_LEVEL)) { | |
279 /* Check new values */ | |
280 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); | |
281 fd_log_debug( "New SO_LINGER : l_onoff : %d\n", linger.l_onoff); | |
282 fd_log_debug( " l_linger : %d\n", linger.l_linger); | |
283 } | |
284 } | |
285 #else /* SO_LINGER */ | |
286 TRACE_DEBUG(SCTP_LEVEL, "Skipping SO_LINGER"); | |
287 #endif /* SO_LINGER */ | |
288 | |
289 /* Set the NODELAY option (Nagle-like algorithm) */ | |
290 #ifdef SCTP_NODELAY | |
291 { | |
292 int nodelay; | |
293 | |
294 if (TRACE_BOOL(SCTP_LEVEL)) { | |
295 sz = sizeof(nodelay); | |
296 /* Read socket defaults */ | |
297 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); | |
298 if (sz != sizeof(nodelay)) | |
299 { | |
300 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay)); | |
301 return ENOTSUP; | |
302 } | |
303 fd_log_debug( "Def SCTP_NODELAY value : %s\n", nodelay ? "true" : "false"); | |
304 } | |
305 | |
306 nodelay = 0; /* We turn ON the Nagle algorithm (probably the default already) */ | |
307 | |
308 /* Set the option to the socket */ | |
309 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay)) ); | |
310 | |
311 if (TRACE_BOOL(SCTP_LEVEL)) { | |
312 /* Check new values */ | |
313 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); | |
314 fd_log_debug( "New SCTP_NODELAY value : %s\n", nodelay ? "true" : "false"); | |
315 } | |
316 } | |
317 #else /* SCTP_NODELAY */ | |
318 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_NODELAY"); | |
319 #endif /* SCTP_NODELAY */ | |
320 | 444 |
321 /* Set the interleaving option */ | 445 /* Set the interleaving option */ |
322 #ifdef SCTP_FRAGMENT_INTERLEAVE | 446 #ifdef SCTP_FRAGMENT_INTERLEAVE |
323 { | 447 { |
324 int interleave; | 448 int interleave; |
352 } | 476 } |
353 #else /* SCTP_FRAGMENT_INTERLEAVE */ | 477 #else /* SCTP_FRAGMENT_INTERLEAVE */ |
354 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_FRAGMENT_INTERLEAVE"); | 478 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_FRAGMENT_INTERLEAVE"); |
355 #endif /* SCTP_FRAGMENT_INTERLEAVE */ | 479 #endif /* SCTP_FRAGMENT_INTERLEAVE */ |
356 | 480 |
357 /* Set the v4 mapped addresses option */ | 481 /* |
358 #ifdef SCTP_I_WANT_MAPPED_V4_ADDR | |
359 { | |
360 int v4mapped; | |
361 | |
362 if (TRACE_BOOL(SCTP_LEVEL)) { | |
363 sz = sizeof(v4mapped); | |
364 /* Read socket defaults */ | |
365 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); | |
366 if (sz != sizeof(v4mapped)) | |
367 { | |
368 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped)); | |
369 return ENOTSUP; | |
370 } | |
371 fd_log_debug( "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false"); | |
372 } | |
373 | |
374 #ifndef SCTP_USE_MAPPED_ADDRESSES | |
375 v4mapped = 0; /* We don't want v4 mapped addresses */ | |
376 #else /* SCTP_USE_MAPPED_ADDRESSES */ | |
377 v4mapped = 1; /* but we may have to, otherwise the bind fails in some environments */ | |
378 #endif /* SCTP_USE_MAPPED_ADDRESSES */ | |
379 | |
380 /* Set the option to the socket */ | |
381 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped)) ); | |
382 | |
383 if (TRACE_BOOL(SCTP_LEVEL)) { | |
384 /* Check new values */ | |
385 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); | |
386 fd_log_debug( "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false"); | |
387 } | |
388 } | |
389 #else /* SCTP_I_WANT_MAPPED_V4_ADDR */ | |
390 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR"); | |
391 #endif /* SCTP_I_WANT_MAPPED_V4_ADDR */ | |
392 | |
393 | |
394 /* Other settable options (draft-ietf-tsvwg-sctpsocket-17): | |
395 SO_RCVBUF size of receiver window | |
396 SO_SNDBUF size of pending data to send | |
397 SCTP_AUTOCLOSE for one-to-many only | |
398 SCTP_SET_PEER_PRIMARY_ADDR ask remote peer to use this local address as primary | |
399 SCTP_PRIMARY_ADDR use this address as primary locally | |
400 SCTP_ADAPTATION_LAYER set adaptation layer indication | |
401 SCTP_PEER_ADDR_PARAMS control heartbeat per peer address | |
402 SCTP_DEFAULT_SEND_PARAM parameters for the sendto() call | |
403 SCTP_MAXSEG max size of fragmented segments -- bound to PMTU | |
404 SCTP_AUTH_CHUNK request authentication of some type of chunk | |
405 SCTP_HMAC_IDENT authentication algorithms | |
406 SCTP_AUTH_KEY set a shared key | |
407 SCTP_AUTH_ACTIVE_KEY set the active key | |
408 SCTP_AUTH_DELETE_KEY remove a key | |
409 SCTP_AUTH_DEACTIVATE_KEY will not use that key anymore | |
410 SCTP_DELAYED_SACK control delayed acks | |
411 SCTP_PARTIAL_DELIVERY_POINT control partial delivery size | 482 SCTP_PARTIAL_DELIVERY_POINT control partial delivery size |
412 SCTP_USE_EXT_RCVINFO use extended receive info structure (information about the next message if available) | 483 SCTP_USE_EXT_RCVINFO use extended receive info structure (information about the next message if available) |
484 */ | |
485 /* SCTP_AUTO_ASCONF is set by the postbind function */ | |
486 /* | |
413 SCTP_MAX_BURST number of packets that can be burst emitted | 487 SCTP_MAX_BURST number of packets that can be burst emitted |
414 SCTP_CONTEXT save a context information along with the association. | 488 SCTP_CONTEXT save a context information along with the association. |
415 SCTP_EXPLICIT_EOR enable sending one message across several send calls | 489 */ |
490 | |
491 /* SCTP_EXPLICIT_EOR: we assume implicit EOR in freeDiameter, so let's ensure this is known by the stack */ | |
492 #ifdef SCTP_EXPLICIT_EOR | |
493 { | |
494 int bool; | |
495 | |
496 if (TRACE_BOOL(SCTP_LEVEL)) { | |
497 sz = sizeof(bool); | |
498 /* Read socket defaults */ | |
499 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_EXPLICIT_EOR, &bool, &sz) ); | |
500 if (sz != sizeof(bool)) | |
501 { | |
502 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(bool)); | |
503 return ENOTSUP; | |
504 } | |
505 fd_log_debug( "Def SCTP_EXPLICIT_EOR value : %s\n", bool ? "true" : "false"); | |
506 } | |
507 | |
508 bool = 0; | |
509 | |
510 /* Set the option to the socket */ | |
511 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_EXPLICIT_EOR, &bool, sizeof(bool)) ); | |
512 | |
513 if (TRACE_BOOL(SCTP_LEVEL)) { | |
514 /* Check new values */ | |
515 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_EXPLICIT_EOR, &bool, &sz) ); | |
516 fd_log_debug( "New SCTP_EXPLICIT_EOR value : %s\n", bool ? "true" : "false"); | |
517 } | |
518 } | |
519 #else /* SCTP_EXPLICIT_EOR */ | |
520 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_EXPLICIT_EOR"); | |
521 #endif /* SCTP_EXPLICIT_EOR */ | |
522 | |
523 /* | |
416 SCTP_REUSE_PORT share one listening port with several sockets | 524 SCTP_REUSE_PORT share one listening port with several sockets |
417 | 525 SCTP_EVENT same as EVENTS ? |
418 read-only options: | |
419 SCTP_STATUS retrieve info such as number of streams, pending packets, state, ... | |
420 SCTP_GET_PEER_ADDR_INFO get information about a specific peer address of the association. | |
421 SCTP_PEER_AUTH_CHUNKS list of chunks the remote peer wants authenticated | |
422 SCTP_LOCAL_AUTH_CHUNKS list of chunks the local peer wants authenticated | |
423 SCTP_GET_ASSOC_NUMBER number of associations in a one-to-many socket | |
424 SCTP_GET_ASSOC_ID_LIST list of these associations | |
425 */ | 526 */ |
426 | 527 |
427 /* In case of no_ip4, force the v6only option -- is it a valid option for SCTP ? */ | 528 /* In case of no_ip4, force the v6only option */ |
428 #ifdef IPV6_V6ONLY | 529 #ifdef IPV6_V6ONLY |
429 if (fd_g_config->cnf_flags.no_ip4) { | 530 if (fd_g_config->cnf_flags.no_ip4) { |
430 int opt = 1; | 531 int opt = 1; |
431 CHECK_SYS(setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))); | 532 CHECK_SYS(setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))); |
432 } | 533 } |