Mercurial > hg > freeDiameter
changeset 23:db6c40b8b307
Added some code in cnxctx.c mainly
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Tue, 20 Oct 2009 17:30:20 +0900 |
parents | 0b3b46da2c12 |
children | bd83ce9328ed |
files | doc/freediameter.conf.sample freeDiameter/cnxctx.c freeDiameter/config.c freeDiameter/fD.h freeDiameter/fdd.y freeDiameter/main.c freeDiameter/sctp.c freeDiameter/tcp.c include/freeDiameter/CMakeLists.txt include/freeDiameter/freeDiameter-host.h.in include/freeDiameter/freeDiameter.h include/freeDiameter/libfreeDiameter.h |
diffstat | 12 files changed, 797 insertions(+), 46 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/freediameter.conf.sample Mon Oct 19 18:43:09 2009 +0900 +++ b/doc/freediameter.conf.sample Tue Oct 20 17:30:20 2009 +0900 @@ -67,6 +67,7 @@ # Default : listen on all addresses available. #ListenOn = "202.249.37.5"; #ListenOn = "2001:200:903:2::202:1"; +#ListenOn = "fe80::21c:5ff:fe98:7d62%eth0"; ############################################################## ## TLS Configuration @@ -200,13 +201,11 @@ Port = 3866; SecPort = 3867; TLS_old_method; -No_SCTP; -Prefer_TCP; SCTP_streams = 50; -#ListenOn = "202.249.37.5"; -#ListenOn = "2001:200:903:2::202:1"; TcTimer = 60; TwTimer = 6; +ListenOn = "133.243.146.201"; +ListenOn = "fe80::21d:9ff:fe89:7d68%eth0"; NoRelay; LoadExtension = "extensions/dbg_monitor.fdx"; LoadExtension = "extensions/dict_nasreq.fdx";
--- a/freeDiameter/cnxctx.c Mon Oct 19 18:43:09 2009 +0900 +++ b/freeDiameter/cnxctx.c Tue Oct 20 17:30:20 2009 +0900 @@ -213,9 +213,11 @@ CHECK_FCT(fd_tcp_listen(conn->cc_socket)); break; +#ifndef DISABLE_SCTP case IPPROTO_SCTP: CHECK_FCT(fd_sctp_listen(conn->cc_socket)); break; +#endif /* DISABLE_SCTP */ default: CHECK_PARAMS(0); @@ -399,7 +401,7 @@ return ENOTSUP; } -/* Get the list of endpoints (IP addresses) of the local and remote peers on this conenction */ +/* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */ int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote) { TRACE_ENTRY("%p %p %p", conn, local, remote); @@ -407,18 +409,54 @@ if (local) { /* Retrieve the local endpoint(s) of the connection */ - TODO("TCP : getsockname"); - TODO("SCTP: sctp_getladdrs / _sctp_getboundaddrs (waaad)"); + switch (conn->cc_proto) { + case IPPROTO_TCP: { + sSS ss; + socklen_t sl; + CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl)); + CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, 0, 0, 0, 1 )); + } + break; + + #ifndef DISABLE_SCTP + case IPPROTO_SCTP: { + CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local)); + } + break; + #endif /* DISABLE_SCTP */ + + default: + CHECK_PARAMS(0); + } } if (remote) { + /* Check we have a full connection object, not a listening socket (with no remote) */ + CHECK_PARAMS( conn->cc_events ); + /* Retrieve the peer endpoint(s) of the connection */ - TODO("TCP : getpeername"); - TODO("SCTP: sctp_getpaddrs"); - + switch (conn->cc_proto) { + case IPPROTO_TCP: { + sSS ss; + socklen_t sl; + CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl)); + CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, 0, 0, 0, 1 )); + } + break; + + #ifndef DISABLE_SCTP + case IPPROTO_SCTP: { + CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote)); + } + break; + #endif /* DISABLE_SCTP */ + + default: + CHECK_PARAMS(0); + } } - return ENOTSUP; + return 0; }
--- a/freeDiameter/config.c Mon Oct 19 18:43:09 2009 +0900 +++ b/freeDiameter/config.c Tue Oct 20 17:30:20 2009 +0900 @@ -99,7 +99,7 @@ while (li != &fd_g_config->cnf_endpoints) { struct fd_endpoint * ep = (struct fd_endpoint *)li; if (li != fd_g_config->cnf_endpoints.next) fd_log_debug(" "); - sSA_DUMP_NODE( &ep->ss, NI_NUMERICHOST ); + sSA_DUMP_NODE( &ep->sa, NI_NUMERICHOST ); fd_log_debug("\n"); li = li->next; } @@ -233,13 +233,13 @@ struct fd_list * li; for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) { struct fd_endpoint * ep = (struct fd_endpoint *)li; - if ( (fd_g_config->cnf_flags.no_ip4 && (ep->ss.ss_family == AF_INET)) - ||(fd_g_config->cnf_flags.no_ip6 && (ep->ss.ss_family == AF_INET6)) ) { + if ( (fd_g_config->cnf_flags.no_ip4 && (ep->sa.sa_family == AF_INET)) + ||(fd_g_config->cnf_flags.no_ip6 && (ep->sa.sa_family == AF_INET6)) ) { li = li->prev; fd_list_unlink(&ep->chain); if (TRACE_BOOL(INFO)) { fd_log_debug("Info: Removing local address conflicting with the flags no_IP / no_IP6 : "); - sSA_DUMP_NODE( &ep->ss, AI_NUMERICHOST ); + sSA_DUMP_NODE( &ep->sa, AI_NUMERICHOST ); fd_log_debug("\n"); } free(ep); @@ -271,3 +271,43 @@ return 0; } + +/* Add an endpoint information in a list */ +int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, int conf, int disc, int adv, int ll ) +{ + struct fd_endpoint * ep; + struct fd_list * li; + int cmp = -1; + + TRACE_ENTRY("%p %p %u %i %i %i %i", list, sa, sl, conf, disc, adv, ll); + CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) && (conf || disc || adv || ll) ); + + /* Search place in the list */ + for (li = list->next; li != list; li = li->next) { + ep = (struct fd_endpoint *)li; + + cmp = memcmp(&ep->ss, sa, sl); + if (cmp >= 0) + break; + } + + if (cmp) { + /* new item to be added */ + CHECK_MALLOC( ep = malloc(sizeof(struct fd_endpoint)) ); + memset(ep, 0, sizeof(struct fd_endpoint)); + fd_list_init(&ep->chain, NULL); + memcpy(&ep->ss, sa, sl); + + /* Insert in the list */ + fd_list_insert_before(li, &ep->chain); + } + + /* Merge the flags */ + ep->meta.conf = conf || ep->meta.conf; + ep->meta.disc = disc || ep->meta.disc; + ep->meta.adv = adv || ep->meta.adv; + ep->meta.ll = ll || ep->meta.ll; + + return 0; +} +
--- a/freeDiameter/fD.h Mon Oct 19 18:43:09 2009 +0900 +++ b/freeDiameter/fD.h Tue Oct 20 17:30:20 2009 +0900 @@ -221,12 +221,15 @@ /* TCP */ int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen ); int fd_tcp_listen( int sock ); +int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl); +int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl); /* SCTP */ #ifndef DISABLE_SCTP int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port ); int fd_sctp_listen( int sock ); - +int fd_sctp_get_local_ep(int sock, struct fd_list * list); +int fd_sctp_get_remote_ep(int sock, struct fd_list * list); int fd_sctp_get_str_info( int socket, int *in, int *out ); #endif /* DISABLE_SCTP */
--- a/freeDiameter/fdd.y Mon Oct 19 18:43:09 2009 +0900 +++ b/freeDiameter/fdd.y Tue Oct 20 17:30:20 2009 +0900 @@ -211,25 +211,16 @@ listenon: LISTENON '=' QSTRING ';' { - struct fd_endpoint * ep; struct addrinfo hints, *ai; int ret; - CHECK_MALLOC_DO( ep = malloc(sizeof(struct fd_endpoint)), - { yyerror (&yylloc, conf, "Out of memory"); YYERROR; } ); - memset(ep, 0, sizeof(struct fd_endpoint)); - fd_list_init(&ep->chain, NULL); - ep->meta.conf = 1; - memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; ret = getaddrinfo($3, NULL, &hints, &ai); - if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; } - ASSERT( ai->ai_addrlen <= sizeof(sSS) ); - memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen); + if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; } + CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, 1, 0, 0, 0 ), YYERROR ); + freeaddrinfo(ai); free($3); - freeaddrinfo(ai); - fd_list_insert_before(&conf->cnf_endpoints, &ep->chain); } ; @@ -429,30 +420,24 @@ } | peerparams CONNTO '=' QSTRING ';' { - struct fd_endpoint * ep; struct addrinfo hints, *ai; int ret; + int disc = 0; - CHECK_MALLOC_DO( ep = malloc(sizeof(struct fd_endpoint)), - { yyerror (&yylloc, conf, "Out of memory"); YYERROR; } ); - memset(ep, 0, sizeof(struct fd_endpoint)); - fd_list_init(&ep->chain, NULL); - ep->meta.conf = 1; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; ret = getaddrinfo($4, NULL, &hints, &ai); if (ret == EAI_NONAME) { /* The name was maybe not numeric, try again */ - ep->meta.disc = 1; + disc = 1; hints.ai_flags &= ~ AI_NUMERICHOST; ret = getaddrinfo($4, NULL, &hints, &ai); } - if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; } + if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; } - memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen); + CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, 1, disc, 0, 0 ), YYERROR ); free($4); freeaddrinfo(ai); - fd_list_insert_before(&fddpi.pi_endpoints, &ep->chain); } ;
--- a/freeDiameter/main.c Mon Oct 19 18:43:09 2009 +0900 +++ b/freeDiameter/main.c Tue Oct 20 17:30:20 2009 +0900 @@ -105,6 +105,8 @@ /* Load the dynamic extensions */ CHECK_FCT( fd_ext_load() ); + fd_conf_dump(); + /* Start the servers */ CHECK_FCT( fd_servers_start() ); @@ -113,7 +115,6 @@ /* Now, just wait for events */ TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); - fd_conf_dump(); while (1) { int code; CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, NULL), break );
--- a/freeDiameter/sctp.c Mon Oct 19 18:43:09 2009 +0900 +++ b/freeDiameter/sctp.c Tue Oct 20 17:30:20 2009 +0900 @@ -34,13 +34,578 @@ *********************************************************************************************************/ #include "fD.h" +#include <netinet/sctp.h> +#include <sys/uio.h> + +/* Pre-binding socket options -- # streams read in config */ +static int fd_setsockopt_prebind(int sk) +{ + #ifdef DEBUG_SCTP + socklen_t sz; + #endif /* DEBUG_SCTP */ + + TRACE_ENTRY( "%d", sk); + + CHECK_PARAMS( sk > 0 ); + + /* Subscribe to some notifications */ + { + struct sctp_event_subscribe event; + + memset(&event, 0, sizeof(event)); + event.sctp_data_io_event = 1; /* to receive the stream ID in SCTP_SNDRCV ancilliary data on message reception */ + event.sctp_association_event = 0; /* new or closed associations (mostly for one-to-many style sockets) */ + event.sctp_address_event = 1; /* address changes */ + event.sctp_send_failure_event = 1; /* delivery failures */ + event.sctp_peer_error_event = 1; /* remote peer sends an error */ + event.sctp_shutdown_event = 1; /* peer has sent a SHUTDOWN */ + event.sctp_partial_delivery_event = 1; /* a partial delivery is aborted, probably indicating the connection is being shutdown */ + // event.sctp_adaptation_layer_event = 0; /* adaptation layer notifications */ + // event.sctp_authentication_event = 0; /* when new key is made active */ + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) ); + + #ifdef DEBUG_SCTP + sz = sizeof(event); + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, &sz) ); + if (sz != sizeof(event)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(event)); + return ENOTSUP; + } + + TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_data_io_event : %hhu", event.sctp_data_io_event); + TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_association_event : %hhu", event.sctp_association_event); + TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_address_event : %hhu", event.sctp_address_event); + TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_send_failure_event : %hhu", event.sctp_send_failure_event); + TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_peer_error_event : %hhu", event.sctp_peer_error_event); + TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_shutdown_event : %hhu", event.sctp_shutdown_event); + TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_partial_delivery_event : %hhu", event.sctp_partial_delivery_event); + TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_adaptation_layer_event : %hhu", event.sctp_adaptation_layer_event); + // TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_authentication_event : %hhu", event.sctp_authentication_event); + #endif /* DEBUG_SCTP */ + + } + + /* Set the INIT parameters, such as number of streams */ + { + struct sctp_initmsg init; + memset(&init, 0, sizeof(init)); + + #ifdef DEBUG_SCTP + sz = sizeof(init); + + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); + if (sz != sizeof(init)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SCTP_INITMSG sinit_num_ostreams : %hu", init.sinit_num_ostreams); + TRACE_DEBUG(FULL, "Def SCTP_INITMSG sinit_max_instreams : %hu", init.sinit_max_instreams); + TRACE_DEBUG(FULL, "Def SCTP_INITMSG sinit_max_attempts : %hu", init.sinit_max_attempts); + TRACE_DEBUG(FULL, "Def SCTP_INITMSG sinit_max_init_timeo : %hu", init.sinit_max_init_timeo); + #endif /* DEBUG_SCTP */ + + /* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters */ + init.sinit_num_ostreams = fd_g_config->cnf_sctp_str; /* desired number of outgoing streams */ + init.sinit_max_init_timeo = CNX_TIMEOUT * 1000; + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); + TRACE_DEBUG(FULL, "New SCTP_INITMSG sinit_num_ostreams : %hu", init.sinit_num_ostreams); + TRACE_DEBUG(FULL, "New SCTP_INITMSG sinit_max_instreams : %hu", init.sinit_max_instreams); + TRACE_DEBUG(FULL, "New SCTP_INITMSG sinit_max_attempts : %hu", init.sinit_max_attempts); + TRACE_DEBUG(FULL, "New SCTP_INITMSG sinit_max_init_timeo : %hu", init.sinit_max_init_timeo); + #endif /* DEBUG_SCTP */ + } + + /* Set the SCTP_DISABLE_FRAGMENTS option, required for TLS */ + #ifdef SCTP_DISABLE_FRAGMENTS + { + int nofrag; + + #ifdef DEBUG_SCTP + sz = sizeof(nofrag); + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); + if (sz != sizeof(nofrag)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SCTP_DISABLE_FRAGMENTS value : %s", nofrag ? "true" : "false"); + #endif /* DEBUG_SCTP */ + + nofrag = 0; /* We turn ON the fragmentation */ + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, sizeof(nofrag)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); + TRACE_DEBUG(FULL, "New SCTP_DISABLE_FRAGMENTS value : %s", nofrag ? "true" : "false"); + #endif /* DEBUG_SCTP */ + } + #else /* SCTP_DISABLE_FRAGMENTS */ + # error "TLS requires support of SCTP_DISABLE_FRAGMENTS" + #endif /* SCTP_DISABLE_FRAGMENTS */ + + + /* Set the RETRANSMIT parameters */ + #ifdef SCTP_RTOINFO + { + struct sctp_rtoinfo rtoinfo; + memset(&rtoinfo, 0, sizeof(rtoinfo)); + + #ifdef DEBUG_SCTP + sz = sizeof(rtoinfo); + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); + if (sz != sizeof(rtoinfo)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SCTP_RTOINFO srto_initial : %u", rtoinfo.srto_initial); + TRACE_DEBUG(FULL, "Def SCTP_RTOINFO srto_max : %u", rtoinfo.srto_max); + TRACE_DEBUG(FULL, "Def SCTP_RTOINFO srto_min : %u", rtoinfo.srto_min); + #endif /* DEBUG_SCTP */ + + rtoinfo.srto_max = fd_g_config->cnf_timer_tw * 500 - 1000; /* Maximum retransmit timer (in ms) (set to Tw / 2 - 1) */ + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); + TRACE_DEBUG(FULL, "New SCTP_RTOINFO srto_initial : %u", rtoinfo.srto_initial); + TRACE_DEBUG(FULL, "New SCTP_RTOINFO srto_max : %u", rtoinfo.srto_max); + TRACE_DEBUG(FULL, "New SCTP_RTOINFO srto_min : %u", rtoinfo.srto_min); + #endif /* DEBUG_SCTP */ + } + #else /* SCTP_RTOINFO */ + # ifdef DEBUG_SCTP + TRACE_DEBUG(FULL, "Skipping SCTP_RTOINFO"); + # endif /* DEBUG_SCTP */ + #endif /* SCTP_RTOINFO */ + + /* Set the ASSOCIATION parameters */ + #ifdef SCTP_ASSOCINFO + { + struct sctp_assocparams assoc; + memset(&assoc, 0, sizeof(assoc)); + + #ifdef DEBUG_SCTP + sz = sizeof(assoc); + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); + if (sz != sizeof(assoc)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_asocmaxrxt : %hu", assoc.sasoc_asocmaxrxt); + TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations); + TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_peer_rwnd : %u" , assoc.sasoc_peer_rwnd); + TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_local_rwnd : %u" , assoc.sasoc_local_rwnd); + TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_cookie_life : %u" , assoc.sasoc_cookie_life); + #endif /* DEBUG_SCTP */ + + assoc.sasoc_asocmaxrxt = 5; /* Maximum retransmission attempts: we want fast detection of errors */ + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); + TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_asocmaxrxt : %hu", assoc.sasoc_asocmaxrxt); + TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations); + TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_peer_rwnd : %u" , assoc.sasoc_peer_rwnd); + TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_local_rwnd : %u" , assoc.sasoc_local_rwnd); + TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_cookie_life : %u" , assoc.sasoc_cookie_life); + #endif /* DEBUG_SCTP */ + } + #else /* SCTP_ASSOCINFO */ + # ifdef DEBUG_SCTP + TRACE_DEBUG(FULL, "Skipping SCTP_ASSOCINFO"); + # endif /* DEBUG_SCTP */ + #endif /* SCTP_ASSOCINFO */ + + + /* The SO_LINGER option will be re-set if we want to perform SCTP ABORT */ + #ifdef SO_LINGER + { + struct linger linger; + memset(&linger, 0, sizeof(linger)); + + #ifdef DEBUG_SCTP + sz = sizeof(linger); + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); + if (sz != sizeof(linger)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SO_LINGER l_onoff : %d", linger.l_onoff); + TRACE_DEBUG(FULL, "Def SO_LINGER l_linger : %d", linger.l_linger); + #endif /* DEBUG_SCTP */ + + linger.l_onoff = 0; /* Do not activate the linger */ + linger.l_linger = 0; /* Return immediately when closing (=> abort) */ + + /* Set the option */ + CHECK_SYS( setsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); + TRACE_DEBUG(FULL, "New SO_LINGER l_onoff : %d", linger.l_onoff); + TRACE_DEBUG(FULL, "New SO_LINGER l_linger : %d", linger.l_linger); + #endif /* DEBUG_SCTP */ + } + #else /* SO_LINGER */ + # ifdef DEBUG_SCTP + TRACE_DEBUG(FULL, "Skipping SO_LINGER"); + # endif /* DEBUG_SCTP */ + #endif /* SO_LINGER */ + + /* Set the NODELAY option (Nagle-like algorithm) */ + #ifdef SCTP_NODELAY + { + int nodelay; + + #ifdef DEBUG_SCTP + sz = sizeof(nodelay); + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); + if (sz != sizeof(nodelay)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SCTP_NODELAY value : %s", nodelay ? "true" : "false"); + #endif /* DEBUG_SCTP */ + + nodelay = 0; /* We turn ON the Nagle algorithm (probably the default already) */ + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); + TRACE_DEBUG(FULL, "New SCTP_NODELAY value : %s", nodelay ? "true" : "false"); + #endif /* DEBUG_SCTP */ + } + #else /* SCTP_NODELAY */ + # ifdef DEBUG_SCTP + TRACE_DEBUG(FULL, "Skipping SCTP_NODELAY"); + # endif /* DEBUG_SCTP */ + #endif /* SCTP_NODELAY */ + + /* Set the interleaving option */ + #ifdef SCTP_FRAGMENT_INTERLEAVE + { + int interleave; + + #ifdef DEBUG_SCTP + sz = sizeof(interleave); + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz) ); + if (sz != sizeof(interleave)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(interleave)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SCTP_FRAGMENT_INTERLEAVE value : %d", interleave); + #endif /* DEBUG_SCTP */ + + #if 0 + interleave = 2; /* Allow partial delivery on several streams at the same time, since we are stream-aware in our security modules */ + #else /* 0 */ + interleave = 1; /* hmmm actually, we are not yet capable of handling this, and we don t need it. */ + #endif /* 0 */ + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, sizeof(interleave)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz) ); + TRACE_DEBUG(FULL, "New SCTP_FRAGMENT_INTERLEAVE value : %d", interleave); + #endif /* DEBUG_SCTP */ + } + #else /* SCTP_FRAGMENT_INTERLEAVE */ + # ifdef DEBUG_SCTP + TRACE_DEBUG(FULL, "Skipping SCTP_FRAGMENT_INTERLEAVE"); + # endif /* DEBUG_SCTP */ + #endif /* SCTP_FRAGMENT_INTERLEAVE */ + + /* Set the v4 mapped addresses option */ + #ifdef SCTP_I_WANT_MAPPED_V4_ADDR + { + int v4mapped; + + #ifdef DEBUG_SCTP + sz = sizeof(v4mapped); + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); + if (sz != sizeof(v4mapped)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s", v4mapped ? "true" : "false"); + #endif /* DEBUG_SCTP */ + + v4mapped = 0; /* We don't want v4 mapped addresses */ + v4mapped = 1; /* but we have to, otherwise the bind fails in linux currently ... (Ok, It'd be better with a cmake test, any volunteer?) */ + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); + TRACE_DEBUG(FULL, "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s", v4mapped ? "true" : "false"); + #endif /* DEBUG_SCTP */ + } + #else /* SCTP_I_WANT_MAPPED_V4_ADDR */ + # ifdef DEBUG_SCTP + TRACE_DEBUG(FULL, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR"); + # endif /* DEBUG_SCTP */ + #endif /* SCTP_I_WANT_MAPPED_V4_ADDR */ + + + /* Other settable options (draft-ietf-tsvwg-sctpsocket-17): + SO_RCVBUF size of receiver window + SO_SNDBUF size of pending data to send + SCTP_AUTOCLOSE for one-to-many only + SCTP_SET_PEER_PRIMARY_ADDR ask remote peer to use this local address as primary + SCTP_PRIMARY_ADDR use this address as primary locally + SCTP_ADAPTATION_LAYER set adaptation layer indication + SCTP_PEER_ADDR_PARAMS control heartbeat per peer address + SCTP_DEFAULT_SEND_PARAM parameters for the sendto() call + SCTP_MAXSEG max size of fragmented segments -- bound to PMTU + SCTP_AUTH_CHUNK request authentication of some type of chunk + SCTP_HMAC_IDENT authentication algorithms + SCTP_AUTH_KEY set a shared key + SCTP_AUTH_ACTIVE_KEY set the active key + SCTP_AUTH_DELETE_KEY remove a key + SCTP_AUTH_DEACTIVATE_KEY will not use that key anymore + SCTP_DELAYED_SACK control delayed acks + SCTP_PARTIAL_DELIVERY_POINT control partial delivery size + SCTP_USE_EXT_RCVINFO use extended receive info structure (information about the next message if available) + SCTP_MAX_BURST number of packets that can be burst emitted + SCTP_CONTEXT save a context information along with the association. + SCTP_EXPLICIT_EOR enable sending one message across several send calls + SCTP_REUSE_PORT share one listening port with several sockets + + read-only options: + SCTP_STATUS retrieve info such as number of streams, pending packets, state, ... + SCTP_GET_PEER_ADDR_INFO get information about a specific peer address of the association. + SCTP_PEER_AUTH_CHUNKS list of chunks the remote peer wants authenticated + SCTP_LOCAL_AUTH_CHUNKS list of chunks the local peer wants authenticated + SCTP_GET_ASSOC_NUMBER number of associations in a one-to-many socket + SCTP_GET_ASSOC_ID_LIST list of these associations + */ + + /* In case of no_ip4, force the v6only option */ + #ifdef IPV6_V6ONLY + if (fd_g_config->cnf_flags.no_ip4) { + int opt = 1; + CHECK_SYS(setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))); + } + #endif /* IPV6_V6ONLY */ + + return 0; +} + + +/* Post-binding socket options */ +static int fd_setsockopt_postbind(int sk, int bound_to_default) +{ + TRACE_ENTRY( "%d %d", sk, bound_to_default); + + CHECK_PARAMS( (sk > 0) ); + + /* Set the ASCONF option */ + #ifdef SCTP_AUTO_ASCONF + { + int asconf; + + #ifdef DEBUG_SCTP + socklen_t sz; + + sz = sizeof(asconf); + /* Read socket defaults */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz) ); + if (sz != sizeof(asconf)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(asconf)); + return ENOTSUP; + } + TRACE_DEBUG(FULL, "Def SCTP_AUTO_ASCONF value : %s", asconf ? "true" : "false"); + #endif /* DEBUG_SCTP */ + + asconf = bound_to_default ? 1 : 0; /* allow automatic use of added or removed addresses in the association (for bound-all sockets) */ + + /* Set the option to the socket */ + CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, sizeof(asconf)) ); + + #ifdef DEBUG_SCTP + /* Check new values */ + CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz) ); + TRACE_DEBUG(FULL, "New SCTP_AUTO_ASCONF value : %s", asconf ? "true" : "false"); + #endif /* DEBUG_SCTP */ + } + #else /* SCTP_AUTO_ASCONF */ + # ifdef DEBUG_SCTP + TRACE_DEBUG(FULL, "Skipping SCTP_AUTO_ASCONF"); + # endif /* DEBUG_SCTP */ + #endif /* SCTP_AUTO_ASCONF */ + + return 0; +} /* Create a socket server and bind it according to daemon s configuration */ int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port ) { - TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str"); + int family; + int bind_default; + + TRACE_ENTRY("%p %p %hu", sock, list, port); + CHECK_PARAMS(sock); + + if (fd_g_config->cnf_flags.no_ip6) { + family = AF_INET; + } else { + family = AF_INET6; /* can create socket for both IP and IPv6 */ + } + + /* Create the socket */ + CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) ); + + /* Set pre-binding socket options, including number of streams etc... */ + CHECK_FCT( fd_setsockopt_prebind(*sock) ); - return ENOTSUP; + bind_default = (! list) || (FD_IS_LIST_EMPTY(list)) ; +redo: + if ( bind_default ) { + /* Implicit endpoints : bind to default addresses */ + union { + sSS ss; + sSA sa; + sSA4 sin; + sSA6 sin6; + } s; + + /* 0.0.0.0 and [::] are all zeros */ + memset(&s, 0, sizeof(s)); + + s.sa.sa_family = family; + + if (family == AF_INET) + s.sin.sin_port = htons(port); + else + s.sin6.sin6_port = htons(port); + + CHECK_SYS( bind(*sock, &s.sa, sizeof(s)) ); + + } else { + /* Explicit endpoints to bind to from config */ + union { + sSA *sa; + sSA4 *sin; + sSA6 *sin6; + } sar; /* build the list of endpoints to bind to */ + int count = 0; /* number of sock addr in sar array */ + struct fd_list * li; + + sar.sa = NULL; + + /* Create a flat array from the list of configured addresses */ + for (li = list->next; li != list; li = li->next) { + struct fd_endpoint * ep = (struct fd_endpoint *)li; + + if ( ! ep->meta.conf ) + continue; + + count++; + if (fd_g_config->cnf_flags.no_ip6) { + ASSERT(ep->sa.sa_family == AF_INET); + CHECK_MALLOC( sar.sa = realloc(sar.sa, count * sizeof(sSA4)) ); + memcpy(&sar.sin[count - 1], &ep->sin, sizeof(sSA4)); + sar.sin[count - 1].sin_port = htons(port); + } else { + /* Pass all addresses as IPv6, eventually mapped -- we already filtered out IPv4 addresses if no_ip4 flag is set */ + CHECK_MALLOC( sar.sa = realloc(sar.sa, count * sizeof(sSA6)) ); + if (ep->sa.sa_family == AF_INET) { + memset(&sar.sin6[count - 1], 0, sizeof(sSA6)); + sar.sin6[count - 1].sin6_family = AF_INET6; + IN6_ADDR_V4MAP( &sar.sin6[count - 1].sin6_addr.s6_addr, ep->sin.sin_addr.s_addr ); + } else { + memcpy(&sar.sin6[count - 1], &ep->sin6, sizeof(sSA6)); + } + sar.sin6[count - 1].sin6_port = htons(port); + } + } + + if (!count) { + /* None of the addresses in the list came from configuration, we bind to default */ + bind_default = 1; + goto redo; + } + + # ifdef DEBUG_SCTP + if (TRACE_BOOL(FULL)) { + int i; + fd_log_debug("Calling sctp_bindx with the following array:\n"); + for (i = 0; i < count; i++) { + fd_log_debug(" - "); + sSA_DUMP_NODE_SERV( (sar.sa[0].sa_family == AF_INET) ? (sSA *)(&sar.sin[i]) : (sSA *)(&sar.sin6[i]), NI_NUMERICHOST | NI_NUMERICSERV ); + fd_log_debug("\n"); + } + } + #endif /* DEBUG_SCTP */ + + CHECK_SYS( sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR) ); + + } + + /* Now, the server is bound, set remaining sockopt */ + CHECK_FCT( fd_setsockopt_postbind(*sock, bind_default) ); + + #ifdef DEBUG_SCTP + /* Debug: show all local listening addresses */ + if (TRACE_BOOL(FULL)) { + sSA *sa, *sar; + int sz; + + CHECK_SYS( sz = sctp_getladdrs(*sock, 0, &sar) ); + + fd_log_debug("SCTP server bound on :\n"); + for (sa = sar; sz-- > 0; sa = (sSA *)(((uint8_t *)sa) + ((sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6)))) { + fd_log_debug(" - "); + sSA_DUMP_NODE_SERV( sa, NI_NUMERICHOST | NI_NUMERICSERV ); + fd_log_debug("\n"); + } + sctp_freeladdrs(sar); + } + #endif /* DEBUG_SCTP */ + + return 0; } /* Allow clients connections on server sockets */ @@ -59,3 +624,45 @@ return ENOTSUP; } +/* Get the list of local endpoints of the socket */ +int fd_sctp_get_local_ep(int sock, struct fd_list * list) +{ + union { + sSA *sa; + sSA4 *sin; + sSA6 *sin6; + uint8_t *buf; + } ptr; + + sSA * data; + int count; + + TRACE_ENTRY("%d %p", sock, list); + CHECK_PARAMS(list); + + /* Read the list on the socket */ + CHECK_SYS( count = sctp_getladdrs(sock, 0, &data) ); + ptr.sa = data; + + while (count) { + TODO("get the data from ptr"); + TODO("Increment ptr to the next sa in data"); + + count --; + } + + /* And now, free the list and return */ + sctp_freeladdrs(data); + + return ENOTSUP; +} + +/* Get the list of remote endpoints of the socket */ +int fd_sctp_get_remote_ep(int sock, struct fd_list * list) +{ + TODO("SCTP: sctp_getpaddrs"); + + + return ENOTSUP; +} +
--- a/freeDiameter/tcp.c Mon Oct 19 18:43:09 2009 +0900 +++ b/freeDiameter/tcp.c Tue Oct 20 17:30:20 2009 +0900 @@ -36,6 +36,7 @@ #include "fD.h" #include <netinet/tcp.h> #include <netinet/ip6.h> +#include <sys/socket.h> /* Set the socket options for TCP sockets, before bind is called */ static int fd_tcp_setsockopt(int family, int sk) @@ -110,3 +111,27 @@ CHECK_SYS( listen(sock, 5) ); return 0; } + +/* Get the local name of a TCP socket -- would be nice if it did not return "0.0.0.0"... */ +int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl) +{ + TRACE_ENTRY("%d %p %p", sock, ss, sl); + CHECK_PARAMS( ss && sl ); + + *sl = sizeof(sSS); + CHECK_SYS(getsockname(sock, (sSA *)ss, sl)); + + return 0; +} + +/* Get the remote name of a TCP socket */ +int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl) +{ + TRACE_ENTRY("%d %p %p", sock, ss, sl); + CHECK_PARAMS( ss && sl ); + + *sl = sizeof(sSS); + CHECK_SYS(getpeername(sock, (sSA *)ss, sl)); + + return 0; +}
--- a/include/freeDiameter/CMakeLists.txt Mon Oct 19 18:43:09 2009 +0900 +++ b/include/freeDiameter/CMakeLists.txt Tue Oct 20 17:30:20 2009 +0900 @@ -9,7 +9,10 @@ OPTION(DEFAULT_CONF_FILE "Default path to configuration file?" OFF) # Disable SCTP support completly ? -OPTION(DISABLE_SCTP "Disable SCTP support?") +OPTION(DISABLE_SCTP "Disable SCTP support?" OFF) +IF (NOT DISABLE_SCTP) + OPTION(DEBUG_SCTP "Verbose SCTP (for debug)?" OFF) +ENDIF (NOT DISABLE_SCTP) # Find TODO items in the code easily ? OPTION(ERRORS_ON_TODO "(development) Generate compilation errors on TODO items ?" OFF)
--- a/include/freeDiameter/freeDiameter-host.h.in Mon Oct 19 18:43:09 2009 +0900 +++ b/include/freeDiameter/freeDiameter-host.h.in Tue Oct 20 17:30:20 2009 +0900 @@ -44,6 +44,7 @@ #cmakedefine HOST_BIG_ENDIAN @HOST_BIG_ENDIAN@ #cmakedefine DISABLE_SCTP +#cmakedefine DEBUG_SCTP #cmakedefine ERRORS_ON_TODO #cmakedefine DEBUG
--- a/include/freeDiameter/freeDiameter.h Mon Oct 19 18:43:09 2009 +0900 +++ b/include/freeDiameter/freeDiameter.h Tue Oct 20 17:30:20 2009 +0900 @@ -117,7 +117,12 @@ /* Endpoints */ struct fd_endpoint { struct fd_list chain; /* link in cnf_endpoints list */ - sSS ss; /* the socket information. List is always ordered by ss value (memcmp) */ + union { + sSS ss; /* the socket information. List is always ordered by ss value (memcmp) */ + sSA4 sin; + sSA6 sin6; + sSA sa; + }; struct { unsigned conf : 1; /* This endpoint is statically configured in a configuration file */ unsigned disc : 1; /* This endpoint was resolved from the Diameter Identity or other DNS query */ @@ -129,6 +134,9 @@ } meta; /* Additional information about the endpoint */ }; +/* Add a new entry in a list of endpoints -- merge if the sockaddr was already there */ +int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, int conf, int disc, int adv, int ll ); + /* Applications */ struct fd_app { struct fd_list chain; /* link in cnf_apps list. List ordered by appid. */
--- a/include/freeDiameter/libfreeDiameter.h Mon Oct 19 18:43:09 2009 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Tue Oct 20 17:30:20 2009 +0900 @@ -328,14 +328,55 @@ 0, \ flag); \ if (__rc) \ - fd_log_debug((char *)gai_strerror(__rc)); \ + fd_log_debug("%s", (char *)gai_strerror(__rc)); \ else \ - fd_log_debug(&__addrbuf[0]); \ + fd_log_debug("%s", &__addrbuf[0]); \ } else { \ fd_log_debug("(NULL / ANY)"); \ } \ } -/* if needed, add sSA_DUMP_SERVICE */ +/* Same, for a service */ +#define sSA_DUMP_SERV( sa, flag ) { \ + sSA * __sa = (sSA *)(sa); \ + char __servbuf[32]; \ + if (__sa) { \ + int __rc = getnameinfo(__sa, \ + sizeof(sSS), \ + NULL, \ + 0, \ + __servbuf, \ + sizeof(__servbuf), \ + flag); \ + if (__rc) \ + fd_log_debug("%s", (char *)gai_strerror(__rc)); \ + else \ + fd_log_debug("%s", &__servbuf[0]); \ + } else { \ + fd_log_debug("(unknown)"); \ + } \ +} +/* Combine both */ +#define sSA_DUMP_NODE_SERV( sa, flag ) { \ + sSA * __sa = (sSA *)(sa); \ + char __addrbuf[INET6_ADDRSTRLEN]; \ + char __servbuf[32]; \ + if (__sa) { \ + int __rc = getnameinfo(__sa, \ + sizeof(sSS), \ + __addrbuf, \ + sizeof(__addrbuf), \ + __servbuf, \ + sizeof(__servbuf), \ + flag); \ + if (__rc) \ + fd_log_debug("%s", (char *)gai_strerror(__rc)); \ + else \ + fd_log_debug("[%s]:%s", &__addrbuf[0],&__servbuf[0]); \ + } else { \ + fd_log_debug("(NULL / ANY)"); \ + } \ +} + /* A l4 protocol name (TCP / SCTP) */ #define IPPROTO_NAME( _proto ) \