Module: sip-router Branch: ser_core_cvs Commit: e5064a814654a71dc2aa28c5fe2bd6fbba76e62c URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=e5064a81...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Thu May 21 15:41:16 2009 +0000
sctp: compatibility with older linux kernels
- try hard to workaround compatibility problems between lksctp userspace (sctp.h) and kernel side: older kernelsi (<2.6.26) expect a certain size for the sctp_event_subscribe structure (SCTP_EVENTS sock. opt), leading to problems when using newer lksctp userspace (>=1.0.9) which adds an additional member to the structure => if the SCTP_EVENTS setsockopt() fails, try with different sizes (since we don't care about authentication events anyway). - failure to enable SCTP_EVENTS upgraded to critical: ser will not start.
---
sctp_server.c | 62 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 49 insertions(+), 13 deletions(-)
diff --git a/sctp_server.c b/sctp_server.c index 424def8..d559ce3 100644 --- a/sctp_server.c +++ b/sctp_server.c @@ -193,14 +193,27 @@ error: WARNING: please keep it sync'ed w/ sctp_check_compiled_sockopts() */ static int sctp_init_sock_opt_common(int s) { - struct sctp_event_subscribe es; int optval; int pd_point; int saved_errno; socklen_t optlen; int sctp_err; +#ifdef __OS_linux + union { + struct sctp_event_subscribe s; + char padding[sizeof(struct sctp_event_subscribe)+sizeof(__u8)]; + } es; +#else + struct sctp_event_subscribe es; +#endif + struct sctp_event_subscribe* ev_s; sctp_err=0; +#ifdef __OS_linux + ev_s=&es.s; +#else + ev_s=&es; +#endif /* set tos */ optval = tos; if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,sizeof(optval)) ==-1){ @@ -349,27 +362,50 @@ static int sctp_init_sock_opt_common(int s) memset(&es, 0, sizeof(es)); /* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message * information in sctp_sndrcvinfo */ - es.sctp_data_io_event=1; + ev_s->sctp_data_io_event=1; /* enable association event notifications */ - es.sctp_association_event=1; /* SCTP_ASSOC_CHANGE */ - es.sctp_address_event=1; /* enable address events notifications */ - es.sctp_send_failure_event=1; /* SCTP_SEND_FAILED */ - es.sctp_peer_error_event=1; /* SCTP_REMOTE_ERROR */ - es.sctp_shutdown_event=1; /* SCTP_SHUTDOWN_EVENT */ - es.sctp_partial_delivery_event=1; /* SCTP_PARTIAL_DELIVERY_EVENT */ - /* es.sctp_adaptation_layer_event=1; - not supported by lksctp<=1.0.6*/ - /* es.sctp_authentication_event=1; -- not supported on linux 2.6.25 */ + ev_s->sctp_association_event=1; /* SCTP_ASSOC_CHANGE */ + ev_s->sctp_address_event=1; /* enable address events notifications */ + ev_s->sctp_send_failure_event=1; /* SCTP_SEND_FAILED */ + ev_s->sctp_peer_error_event=1; /* SCTP_REMOTE_ERROR */ + ev_s->sctp_shutdown_event=1; /* SCTP_SHUTDOWN_EVENT */ + ev_s->sctp_partial_delivery_event=1; /* SCTP_PARTIAL_DELIVERY_EVENT */ + /* ev_s->sctp_adaptation_layer_event=1; - not supported by lksctp<=1.0.6*/ + /* ev_s->sctp_authentication_event=1; -- not supported on linux 2.6.25 */ /* enable the SCTP_EVENTS */ #ifdef SCTP_EVENTS - if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, &es, sizeof(es))==-1){ + if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s))==-1){ + /* on linux the checks for the struct sctp_event_subscribe size + are too strict, making certain lksctp/kernel combination + unworkable => since we don't use the extra information + (sctp_authentication_event) added in newer version, we can + try with different sizes) */ +#ifdef __OS_linux + /* 1. lksctp 1.0.9 with kernel < 2.6.26 -> kernel expects + the structure without the authentication event member */ + if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(*ev_s)-1)==0) + goto ev_success; + /* 2. lksctp < 1.0.9? with kernel >= 2.6.26: the sctp.h structure + does not have the authentication member, but the newer kernels + check only for optlen > sizeof(...) => we should never reach + this point. */ + /* 3. just to be foolproof if we reached this point, try + with a bigger size before giving up (out of desperation) */ + if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, ev_s, sizeof(es))==0) + goto ev_success; + +#endif LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: " "SCTP_EVENTS: %s\n", strerror(errno)); sctp_err++; - /* non critical, try to continue */ + goto error; /* critical */ } +#ifdef __OS_linux +ev_success: +#endif #else -#warning no sctp lib support for SCTP_EVENTS, consider upgrading +#error no sctp lib support for SCTP_EVENTS, consider upgrading #endif /* SCTP_EVENTS */ if (sctp_err){