# HG changeset patch # User Sebastien Decugis # Date 1256118165 -32400 # Node ID bd83ce9328edc75e0c59d8ebdac23e9b3eceec1e # Parent db6c40b8b307c70e7bb7e69fbca665bf517d6c35 Cleanups and completed sctp code (not finished) diff -r db6c40b8b307 -r bd83ce9328ed doc/freediameter.conf.sample --- a/doc/freediameter.conf.sample Tue Oct 20 17:30:20 2009 +0900 +++ b/doc/freediameter.conf.sample Wed Oct 21 18:42:45 2009 +0900 @@ -204,8 +204,8 @@ SCTP_streams = 50; TcTimer = 60; TwTimer = 6; -ListenOn = "133.243.146.201"; -ListenOn = "fe80::21d:9ff:fe89:7d68%eth0"; +#ListenOn = "133.243.146.201"; +#ListenOn = "fe80::21d:9ff:fe89:7d68%eth0"; NoRelay; LoadExtension = "extensions/dbg_monitor.fdx"; LoadExtension = "extensions/dict_nasreq.fdx"; diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/CMakeLists.txt --- a/freeDiameter/CMakeLists.txt Tue Oct 20 17:30:20 2009 +0900 +++ b/freeDiameter/CMakeLists.txt Wed Oct 21 18:42:45 2009 +0900 @@ -12,6 +12,7 @@ config.c cnxctx.c dispatch.c + endpoints.c extensions.c dict_base_proto.c messages.c diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/cnxctx.c --- a/freeDiameter/cnxctx.c Tue Oct 20 17:30:20 2009 +0900 +++ b/freeDiameter/cnxctx.c Wed Oct 21 18:42:45 2009 +0900 @@ -173,9 +173,15 @@ fd_cnx_destroy(cnx); return NULL; } -#ifndef DISABLE_SCTP + +/* Same function for SCTP, with a list of local endpoints to bind to */ struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list) { +#ifdef DISABLE_SCTP + TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled..."); + ASSERT(0); + CHECK_FCT_DO( ENOTSUP, return NULL); +#else /* DISABLE_SCTP */ struct cnxctx * cnx = NULL; sSS dummy; sSA * sa = (sSA *) &dummy; @@ -200,8 +206,8 @@ error: fd_cnx_destroy(cnx); return NULL; +#endif /* DISABLE_SCTP */ } -#endif /* DISABLE_SCTP */ /* Allow clients to connect on the server socket */ int fd_cnx_serv_listen(struct cnxctx * conn) @@ -238,12 +244,13 @@ TRACE_ENTRY("%p", serv); CHECK_PARAMS_DO(serv, return NULL); + /* Accept the new connection -- this is blocking until new client enters or cancellation */ CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL ); if (TRACE_BOOL(INFO)) { - fd_log_debug("%s - new client [", fd_cnx_getid(serv)); - sSA_DUMP_NODE( &ss, AI_NUMERICHOST ); - fd_log_debug("] connected.\n"); + fd_log_debug("%s : accepted new client [", fd_cnx_getid(serv)); + sSA_DUMP_NODE( &ss, NI_NUMERICHOST ); + fd_log_debug("].\n"); } CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); return NULL; } ); @@ -258,25 +265,27 @@ /* Numeric values for debug */ rc = getnameinfo((sSA *)&ss, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); - if (rc) + if (rc) { snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); + portbuf[0] = '\0'; + } - snprintf(cli->cc_id, sizeof(cli->cc_id), "Client %s [%s]:%s (%d) / serv (%d)", + snprintf(cli->cc_id, sizeof(cli->cc_id), "Incoming %s [%s]:%s (%d) @ serv (%d)", IPPROTO_NAME(cli->cc_proto), addrbuf, portbuf, cli->cc_socket, serv->cc_socket); - /* Textual value for log messages */ - rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, NI_NUMERICHOST); + /* Name for log messages */ + rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0); if (rc) snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc)); } +#ifndef DISABLE_SCTP /* SCTP-specific handlings */ -#ifndef DISABLE_SCTP if (cli->cc_proto == IPPROTO_SCTP) { /* Retrieve the number of streams */ - CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out ), goto error ); + CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out, NULL ), goto error ); if (cli->cc_sctp_para.str_out > cli->cc_sctp_para.str_in) cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out; else @@ -290,12 +299,121 @@ return NULL; } -/* Client side: connect to a remote server */ -struct cnxctx * fd_cnx_cli_connect(int proto, const sSA * sa, socklen_t addrlen) +/* Client side: connect to a remote server -- cancelable */ +struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa /* contains the port already */, socklen_t addrlen) +{ + int sock; + struct cnxctx * cnx = NULL; + + TRACE_ENTRY("%p %d", sa, addrlen); + CHECK_PARAMS_DO( sa && addrlen, return NULL ); + + /* Create the socket and connect, which can take some time and/or fail */ + CHECK_FCT_DO( fd_tcp_client( &sock, sa, addrlen ), return NULL ); + + if (TRACE_BOOL(INFO)) { + fd_log_debug("Connection established to server '"); + sSA_DUMP_NODE_SERV( sa, NI_NUMERICSERV); + fd_log_debug("' (TCP:%d).\n", sock); + } + + /* Once the socket is created successfuly, prepare the remaining of the cnx */ + CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } ); + + cnx->cc_socket = sock; + cnx->cc_proto = IPPROTO_TCP; + + /* Generate the names for the object */ + { + char addrbuf[INET6_ADDRSTRLEN]; + char portbuf[10]; + int rc; + + /* Numeric values for debug */ + rc = getnameinfo(sa, addrlen, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); + if (rc) { + snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); + portbuf[0] = '\0'; + } + + snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of TCP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket); + + /* Name for log messages */ + rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); + if (rc) + snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); + } + + return cnx; + +error: + fd_cnx_destroy(cnx); + return NULL; +} + +/* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx) */ +struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list) { +#ifdef DISABLE_SCTP + TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled..."); + ASSERT(0); + CHECK_FCT_DO( ENOTSUP, return NULL); +#else /* DISABLE_SCTP */ + int sock; + struct cnxctx * cnx = NULL; + sSS primary; + + TRACE_ENTRY("%p", list); + CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL ); + + CHECK_FCT_DO( fd_sctp_client( &sock, no_ip6, port, list ), return NULL ); + + /* Once the socket is created successfuly, prepare the remaining of the cnx */ + CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } ); + + cnx->cc_socket = sock; + cnx->cc_proto = IPPROTO_SCTP; + + /* Retrieve the number of streams and primary address */ + CHECK_FCT_DO( fd_sctp_get_str_info( sock, &cnx->cc_sctp_para.str_in, &cnx->cc_sctp_para.str_out, &primary ), goto error ); + if (cnx->cc_sctp_para.str_out > cnx->cc_sctp_para.str_in) + cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_out; + else + cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in; + + /* Generate the names for the object */ + { + char addrbuf[INET6_ADDRSTRLEN]; + char portbuf[10]; + int rc; + + /* Numeric values for debug */ + rc = getnameinfo((sSA *)&primary, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); + if (rc) { + snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); + portbuf[0] = '\0'; + } + + snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of SCTP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket); + + /* Name for log messages */ + rc = getnameinfo((sSA *)&primary, sizeof(sSS), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); + if (rc) + snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); + } + + if (TRACE_BOOL(INFO)) { + fd_log_debug("Connection established to server '"); + sSA_DUMP_NODE_SERV( &primary, NI_NUMERICSERV); + fd_log_debug("' (SCTP:%d).\n", sock); + } + + return cnx; - TODO("..."); +error: + fd_cnx_destroy(cnx); return NULL; +#endif /* DISABLE_SCTP */ } /* Return a string describing the connection, for debug */ @@ -414,7 +532,7 @@ 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 )); + CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY)); } break; @@ -440,7 +558,7 @@ 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 )); + CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY )); } break; @@ -527,7 +645,3 @@ /* Done! */ return; } - - - - diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/config.c --- a/freeDiameter/config.c Tue Oct 20 17:30:20 2009 +0900 +++ b/freeDiameter/config.c Wed Oct 21 18:42:45 2009 +0900 @@ -271,43 +271,3 @@ 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; -} - diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/endpoints.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/endpoints.c Wed Oct 21 18:42:45 2009 +0900 @@ -0,0 +1,110 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + + +/* Add an endpoint information in a list */ +int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags ) +{ + struct fd_endpoint * ep; + struct fd_list * li; + int cmp = -1; + + TRACE_ENTRY("%p %p %u %x", list, sa, sl, flags); + CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) ); + + /* 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->flags |= flags; + + return 0; +} + +/* Delete endpoints that do not have a matching flag from a list (0: delete all endpoints) */ +int fd_ep_filter( struct fd_list * list, uint32_t flags ) +{ + struct fd_list * li; + + TRACE_ENTRY("%p %x", list, flags); + CHECK_PARAMS(list); + + for (li = list->next; li != list; li = li->next) { + struct fd_endpoint * ep = (struct fd_endpoint *)li; + + if (! (ep->flags & flags)) { + li = li->prev; + fd_list_unlink(&ep->chain); + free(ep); + } + } + + return 0; +} + +/* Reset the given flag(s) from all items in the list */ +int fd_ep_clearflags( struct fd_list * list, uint32_t flags ) +{ + struct fd_list * li; + + TRACE_ENTRY("%p %x", list, flags); + CHECK_PARAMS(list); + + for (li = list->next; li != list; li = li->next) { + struct fd_endpoint * ep = (struct fd_endpoint *)li; + ep->flags &= ~flags; + } + + return 0; +} diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/fD.h --- a/freeDiameter/fD.h Tue Oct 20 17:30:20 2009 +0900 +++ b/freeDiameter/fD.h Wed Oct 21 18:42:45 2009 +0900 @@ -206,7 +206,8 @@ struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list); int fd_cnx_serv_listen(struct cnxctx * conn); struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv); -struct cnxctx * fd_cnx_cli_connect(int proto, const sSA * sa, socklen_t addrlen); +struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen); +struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list); char * fd_cnx_getid(struct cnxctx * conn); int fd_cnx_start_clear(struct cnxctx * conn); int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority); @@ -221,6 +222,7 @@ /* TCP */ int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen ); int fd_tcp_listen( int sock ); +int fd_tcp_client( int *sock, sSA * sa, socklen_t salen ); 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); @@ -228,9 +230,10 @@ #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_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list ); 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 ); +int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary ); #endif /* DISABLE_SCTP */ diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/fdd.y --- a/freeDiameter/fdd.y Tue Oct 20 17:30:20 2009 +0900 +++ b/freeDiameter/fdd.y Wed Oct 21 18:42:45 2009 +0900 @@ -218,7 +218,7 @@ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; ret = getaddrinfo($3, NULL, &hints, &ai); 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 ); + CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF ), YYERROR ); freeaddrinfo(ai); free($3); } @@ -429,13 +429,13 @@ ret = getaddrinfo($4, NULL, &hints, &ai); if (ret == EAI_NONAME) { /* The name was maybe not numeric, try again */ - disc = 1; + disc = EP_FL_DISC; hints.ai_flags &= ~ AI_NUMERICHOST; ret = getaddrinfo($4, NULL, &hints, &ai); } if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; } - CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, 1, disc, 0, 0 ), YYERROR ); + CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF | disc ), YYERROR ); free($4); freeaddrinfo(ai); } diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/sctp.c --- a/freeDiameter/sctp.c Tue Oct 20 17:30:20 2009 +0900 +++ b/freeDiameter/sctp.c Wed Oct 21 18:42:45 2009 +0900 @@ -75,15 +75,15 @@ 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); + TRACE_DEBUG(FULL, "SCTP_EVENTS : sctp_data_io_event : %hhu", event.sctp_data_io_event); + TRACE_DEBUG(FULL, " sctp_association_event : %hhu", event.sctp_association_event); + TRACE_DEBUG(FULL, " sctp_address_event : %hhu", event.sctp_address_event); + TRACE_DEBUG(FULL, " sctp_send_failure_event : %hhu", event.sctp_send_failure_event); + TRACE_DEBUG(FULL, " sctp_peer_error_event : %hhu", event.sctp_peer_error_event); + TRACE_DEBUG(FULL, " sctp_shutdown_event : %hhu", event.sctp_shutdown_event); + TRACE_DEBUG(FULL, " sctp_partial_delivery_event : %hhu", event.sctp_partial_delivery_event); + TRACE_DEBUG(FULL, " sctp_adaptation_layer_event : %hhu", event.sctp_adaptation_layer_event); + // TRACE_DEBUG(FULL, " sctp_authentication_event : %hhu", event.sctp_authentication_event); #endif /* DEBUG_SCTP */ } @@ -103,10 +103,10 @@ 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); + TRACE_DEBUG(FULL, "Def SCTP_INITMSG : sinit_num_ostreams : %hu", init.sinit_num_ostreams); + TRACE_DEBUG(FULL, " sinit_max_instreams : %hu", init.sinit_max_instreams); + TRACE_DEBUG(FULL, " sinit_max_attempts : %hu", init.sinit_max_attempts); + TRACE_DEBUG(FULL, " 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 */ @@ -119,10 +119,10 @@ #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); + TRACE_DEBUG(FULL, "New SCTP_INITMSG : sinit_num_ostreams : %hu", init.sinit_num_ostreams); + TRACE_DEBUG(FULL, " sinit_max_instreams : %hu", init.sinit_max_instreams); + TRACE_DEBUG(FULL, " sinit_max_attempts : %hu", init.sinit_max_attempts); + TRACE_DEBUG(FULL, " sinit_max_init_timeo : %hu", init.sinit_max_init_timeo); #endif /* DEBUG_SCTP */ } @@ -174,9 +174,9 @@ 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); + TRACE_DEBUG(FULL, "Def SCTP_RTOINFO : srto_initial : %u", rtoinfo.srto_initial); + TRACE_DEBUG(FULL, " srto_max : %u", rtoinfo.srto_max); + TRACE_DEBUG(FULL, " 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) */ @@ -187,9 +187,9 @@ #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); + TRACE_DEBUG(FULL, "New SCTP_RTOINFO : srto_initial : %u", rtoinfo.srto_initial); + TRACE_DEBUG(FULL, " srto_max : %u", rtoinfo.srto_max); + TRACE_DEBUG(FULL, " srto_min : %u", rtoinfo.srto_min); #endif /* DEBUG_SCTP */ } #else /* SCTP_RTOINFO */ @@ -213,11 +213,11 @@ 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); + TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu", assoc.sasoc_asocmaxrxt); + TRACE_DEBUG(FULL, " sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations); + TRACE_DEBUG(FULL, " sasoc_peer_rwnd : %u" , assoc.sasoc_peer_rwnd); + TRACE_DEBUG(FULL, " sasoc_local_rwnd : %u" , assoc.sasoc_local_rwnd); + TRACE_DEBUG(FULL, " sasoc_cookie_life : %u" , assoc.sasoc_cookie_life); #endif /* DEBUG_SCTP */ assoc.sasoc_asocmaxrxt = 5; /* Maximum retransmission attempts: we want fast detection of errors */ @@ -228,11 +228,11 @@ #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); + TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu", assoc.sasoc_asocmaxrxt); + TRACE_DEBUG(FULL, " sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations); + TRACE_DEBUG(FULL, " sasoc_peer_rwnd : %u" , assoc.sasoc_peer_rwnd); + TRACE_DEBUG(FULL, " sasoc_local_rwnd : %u" , assoc.sasoc_local_rwnd); + TRACE_DEBUG(FULL, " sasoc_cookie_life : %u" , assoc.sasoc_cookie_life); #endif /* DEBUG_SCTP */ } #else /* SCTP_ASSOCINFO */ @@ -257,8 +257,8 @@ 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); + TRACE_DEBUG(FULL, "Def SO_LINGER : l_onoff : %d", linger.l_onoff); + TRACE_DEBUG(FULL, " l_linger : %d", linger.l_linger); #endif /* DEBUG_SCTP */ linger.l_onoff = 0; /* Do not activate the linger */ @@ -270,8 +270,8 @@ #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); + TRACE_DEBUG(FULL, "New SO_LINGER : l_onoff : %d", linger.l_onoff); + TRACE_DEBUG(FULL, " l_linger : %d", linger.l_linger); #endif /* DEBUG_SCTP */ } #else /* SO_LINGER */ @@ -369,8 +369,11 @@ TRACE_DEBUG(FULL, "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s", v4mapped ? "true" : "false"); #endif /* DEBUG_SCTP */ +#ifndef SCTP_USE_MAPPED_ADDRESSES 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?) */ +#else /* SCTP_USE_MAPPED_ADDRESSES */ + v4mapped = 1; /* but we may have to, otherwise the bind fails in some environments */ +#endif /* SCTP_USE_MAPPED_ADDRESSES */ /* Set the option to the socket */ CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped)) ); @@ -421,7 +424,7 @@ SCTP_GET_ASSOC_ID_LIST list of these associations */ - /* In case of no_ip4, force the v6only option */ + /* In case of no_ip4, force the v6only option -- is it a valid option for SCTP ? */ #ifdef IPV6_V6ONLY if (fd_g_config->cnf_flags.no_ip4) { int opt = 1; @@ -525,40 +528,61 @@ } else { /* Explicit endpoints to bind to from config */ + union { - sSA *sa; - sSA4 *sin; - sSA6 *sin6; - } sar; /* build the list of endpoints to bind to */ + sSA * sa; + sSA4 *sin; + sSA6 *sin6; + uint8_t *buf; + } ptr; + union { + sSA * sa; + uint8_t * buf; + } sar; int count = 0; /* number of sock addr in sar array */ + size_t offset = 0; struct fd_list * li; - sar.sa = NULL; + sar.buf = 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; + size_t sz = 0; - if ( ! ep->meta.conf ) + if (! (ep->flags & EP_FL_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); + + /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */ +#ifndef SCTP_USE_MAPPED_ADDRESSES + if (ep->sa.sa_family == AF_INET6) +#else /* SCTP_USE_MAPPED_ADDRESSES */ + if (family == AF_INET6) +#endif /* SCTP_USE_MAPPED_ADDRESSES */ + sz = sizeof(sSA6); + else + sz = sizeof(sSA4); + + /* augment sar to contain the additional info */ + CHECK_MALLOC( sar.buf = realloc(sar.buf, offset + sz) ); + + ptr.buf = sar.buf + offset; /* place of the new SA */ + offset += sz; /* update to end of sar */ + + if (sz == sizeof(sSA4)) { + memcpy(ptr.buf, &ep->sin, sz); + ptr.sin->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 ); + if (ep->sa.sa_family == AF_INET) { /* We must map the address */ + memset(ptr.buf, 0, sz); + ptr.sin6->sin6_family = AF_INET6; + IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr ); } else { - memcpy(&sar.sin6[count - 1], &ep->sin6, sizeof(sSA6)); + memcpy(ptr.sin6, &ep->sin6, sz); } - sar.sin6[count - 1].sin6_port = htons(port); + ptr.sin6->sin6_port = htons(port); } } @@ -571,17 +595,20 @@ # ifdef DEBUG_SCTP if (TRACE_BOOL(FULL)) { int i; - fd_log_debug("Calling sctp_bindx with the following array:\n"); + ptr.buf = sar.buf; + fd_log_debug("Calling sctp_bindx with the following address 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"); + TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" ); + ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ; } } #endif /* DEBUG_SCTP */ + /* Bind to this array */ CHECK_SYS( sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR) ); + /* We don't need sar anymore */ + free(sar.buf); } /* Now, the server is bound, set remaining sockopt */ @@ -590,16 +617,18 @@ #ifdef DEBUG_SCTP /* Debug: show all local listening addresses */ if (TRACE_BOOL(FULL)) { - sSA *sa, *sar; + sSA *sar; + union { + sSA *sa; + uint8_t *buf; + } ptr; 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"); + for (ptr.sa = sar; sz-- > 0; ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6)) { + TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" ); } sctp_freeladdrs(sar); } @@ -616,12 +645,143 @@ return 0; } -/* Retrieve streams information from a connected association */ -int fd_sctp_get_str_info( int socket, int *in, int *out ) +/* Create a client socket and connect to remote server */ +int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list ) { - TODO("Retrieve streams info from the socket"); + int family; + int count = 0; + size_t offset = 0, sz; + union { + uint8_t *buf; + sSA *sa; + } sar; + union { + uint8_t *buf; + sSA *sa; + sSA4 *sin; + sSA6 *sin6; + } ptr; + struct fd_list * li; + int ret; + + sar.buf = NULL; + + TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list); + CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) ); + + if (no_ip6) { + family = AF_INET; + } else { + family = AF_INET6; + } + + /* Create the socket */ + CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) ); + + /* Cleanup if we are cancelled */ + pthread_cleanup_push(fd_cleanup_socket, sock); + + /* Set the socket options */ + CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail ); - return ENOTSUP; + /* Create the array of addresses for sctp_connectx */ + for (li = list->next; li != list; li = li->next) { + struct fd_endpoint * ep = (struct fd_endpoint *) li; + + count++; + + /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */ +#ifndef SCTP_USE_MAPPED_ADDRESSES + if (ep->sa.sa_family == AF_INET6) +#else /* SCTP_USE_MAPPED_ADDRESSES */ + if (family == AF_INET6) +#endif /* SCTP_USE_MAPPED_ADDRESSES */ + sz = sizeof(sSA6); + else + sz = sizeof(sSA4); + + /* augment sar to contain the additional info */ + CHECK_MALLOC_DO( sar.buf = realloc(sar.buf, offset + sz), { ret = ENOMEM; goto fail; } ); + + ptr.buf = sar.buf + offset; /* place of the new SA */ + offset += sz; /* update to end of sar */ + + if (sz == sizeof(sSA4)) { + memcpy(ptr.buf, &ep->sin, sz); + ptr.sin->sin_port = htons(port); + } else { + if (ep->sa.sa_family == AF_INET) { /* We must map the address */ + memset(ptr.buf, 0, sz); + ptr.sin6->sin6_family = AF_INET6; + IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr ); + } else { + memcpy(ptr.sin6, &ep->sin6, sz); + } + ptr.sin6->sin6_port = htons(port); + } + } + + /* Try connecting */ + TRACE_DEBUG(FULL, "Attempting SCTP connection (%d addresses attempted)...", count); + CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count), { ret = errno; goto fail; } ); + free(sar.buf); sar.buf = NULL; + + /* Set the remaining sockopts */ + CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, 1), goto fail ); + + /* Done! */ + pthread_cleanup_pop(0); + return 0; + +fail: + if (*sock > 0) { + shutdown(*sock, SHUT_RDWR); + *sock = -1; + } + free(sar.buf); + return ret; +} + +/* Retrieve streams information from a connected association -- optionaly provide the primary address */ +int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary ) +{ + struct sctp_status status; + socklen_t sz = sizeof(status); + + TRACE_ENTRY("%d %p %p %p", sock, in, out, primary); + CHECK_PARAMS( (sock > 0) && in && out ); + + /* Read the association parameters */ + memset(&status, 0, sizeof(status)); + CHECK_SYS( getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz) ); + if (sz != sizeof(status)) + { + TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %g", sz, sizeof(status)); + return ENOTSUP; + } + #ifdef DEBUG_SCTP + TRACE_DEBUG(FULL, "SCTP_STATUS : sstat_state : %i" , status.sstat_state); + TRACE_DEBUG(FULL, " sstat_rwnd : %u" , status.sstat_rwnd); + TRACE_DEBUG(FULL, " sstat_unackdata : %hu", status.sstat_unackdata); + TRACE_DEBUG(FULL, " sstat_penddata : %hu", status.sstat_penddata); + TRACE_DEBUG(FULL, " sstat_instrms : %hu", status.sstat_instrms); + TRACE_DEBUG(FULL, " sstat_outstrms : %hu", status.sstat_outstrms); + TRACE_DEBUG(FULL, " sstat_fragmentation_point : %u" , status.sstat_fragmentation_point); + TRACE_DEBUG_sSA(FULL, " sstat_primary.spinfo_address : ", &status.sstat_primary.spinfo_address, NI_NUMERICHOST | NI_NUMERICSERV, "" ); + TRACE_DEBUG(FULL, " sstat_primary.spinfo_state : %d" , status.sstat_primary.spinfo_state); + TRACE_DEBUG(FULL, " sstat_primary.spinfo_cwnd : %u" , status.sstat_primary.spinfo_cwnd); + TRACE_DEBUG(FULL, " sstat_primary.spinfo_srtt : %u" , status.sstat_primary.spinfo_srtt); + TRACE_DEBUG(FULL, " sstat_primary.spinfo_rto : %u" , status.sstat_primary.spinfo_rto); + TRACE_DEBUG(FULL, " sstat_primary.spinfo_mtu : %u" , status.sstat_primary.spinfo_mtu); + #endif /* DEBUG_SCTP */ + + *in = (int)status.sstat_instrms; + *out = (int)status.sstat_outstrms; + + if (primary) + memcpy(primary, &status.sstat_primary.spinfo_address, sizeof(sSS)); + + return 0; } /* Get the list of local endpoints of the socket */ @@ -629,8 +789,6 @@ { union { sSA *sa; - sSA4 *sin; - sSA6 *sin6; uint8_t *buf; } ptr; @@ -645,24 +803,92 @@ ptr.sa = data; while (count) { - TODO("get the data from ptr"); - TODO("Increment ptr to the next sa in data"); - + socklen_t sl; + switch (ptr.sa->sa_family) { + case AF_INET: sl = sizeof(sSA4); break; + case AF_INET6: sl = sizeof(sSA6); break; + default: + TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family); + } + + CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) ); + ptr.buf += sl; count --; } - /* And now, free the list and return */ + /* Free the list */ sctp_freeladdrs(data); - return ENOTSUP; + /* Now get the primary address, the add function will take care of merging with existing entry */ + { + + struct sctp_status status; + socklen_t sz = sizeof(status); + int ret; + + memset(&status, 0, sizeof(status)); + /* Attempt to use SCTP_STATUS message to retrieve the primary address */ + ret = getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz); + if (sz != sizeof(status)) + ret = -1; + sz = sizeof(sSS); + if (ret < 0) + { + /* Fallback to getsockname -- not recommended by draft-ietf-tsvwg-sctpsocket-19#section-7.4 */ + CHECK_SYS(getsockname(sock, (sSA *)&status.sstat_primary.spinfo_address, &sz)); + } + + CHECK_FCT( fd_ep_add_merge( list, (sSA *)&status.sstat_primary.spinfo_address, sz, EP_FL_PRIMARY ) ); + } + + return 0; } /* 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"); - + union { + sSA *sa; + 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_getpaddrs(sock, 0, &data) ); + ptr.sa = data; - return ENOTSUP; + while (count) { + socklen_t sl; + switch (ptr.sa->sa_family) { + case AF_INET: sl = sizeof(sSA4); break; + case AF_INET6: sl = sizeof(sSA6); break; + default: + TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getpaddrs: %d", ptr.sa->sa_family); + } + + CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) ); + ptr.buf += sl; + count --; + } + + /* Free the list */ + sctp_freepaddrs(data); + + /* Now get the primary address, the add function will take care of merging with existing entry */ + { + sSS ss; + socklen_t sl = sizeof(sSS); + + CHECK_SYS(getpeername(sock, (sSA *)&ss, &sl)); + CHECK_FCT( fd_ep_add_merge( list, (sSA *)&ss, sl, EP_FL_PRIMARY ) ); + } + + /* Done! */ + return 0; } diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/server.c --- a/freeDiameter/server.c Tue Oct 20 17:30:20 2009 +0900 +++ b/freeDiameter/server.c Wed Oct 21 18:42:45 2009 +0900 @@ -290,7 +290,7 @@ 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; sSA * sa = (sSA *) &ep->ss; - if (! ep->meta.conf) + if (! (ep->flags & EP_FL_CONF)) continue; if (fd_g_config->cnf_flags.no_ip4 && (sa->sa_family == AF_INET)) continue; diff -r db6c40b8b307 -r bd83ce9328ed freeDiameter/tcp.c --- a/freeDiameter/tcp.c Tue Oct 20 17:30:20 2009 +0900 +++ b/freeDiameter/tcp.c Wed Oct 21 18:42:45 2009 +0900 @@ -112,6 +112,32 @@ return 0; } +/* Create a client socket and connect to remote server */ +int fd_tcp_client( int *sock, sSA * sa, socklen_t salen ) +{ + TRACE_ENTRY("%p %p %d", sock, sa, salen); + CHECK_PARAMS( sock && sa && salen ); + + /* Create the socket */ + CHECK_SYS( *sock = socket(sa->sa_family, SOCK_STREAM, IPPROTO_TCP) ); + + /* Cleanup if we are cancelled */ + pthread_cleanup_push(fd_cleanup_socket, sock); + + /* Set the socket options */ + CHECK_FCT( fd_tcp_setsockopt(sa->sa_family, *sock) ); + + TRACE_DEBUG_sSA(FULL, "Attempting TCP connection with peer: ", sa, NI_NUMERICHOST | NI_NUMERICSERV, "..." ); + + /* Try connecting to the remote address */ + CHECK_SYS( connect(*sock, sa, salen) ); + + /* Done! */ + pthread_cleanup_pop(0); + 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) { diff -r db6c40b8b307 -r bd83ce9328ed include/freeDiameter/CMakeLists.txt --- a/include/freeDiameter/CMakeLists.txt Tue Oct 20 17:30:20 2009 +0900 +++ b/include/freeDiameter/CMakeLists.txt Wed Oct 21 18:42:45 2009 +0900 @@ -12,6 +12,7 @@ OPTION(DISABLE_SCTP "Disable SCTP support?" OFF) IF (NOT DISABLE_SCTP) OPTION(DEBUG_SCTP "Verbose SCTP (for debug)?" OFF) + OPTION(SCTP_USE_MAPPED_ADDRESSES "Use v6-mapped v4 addresses in SCTP (workaround some SCTP limitations)?" OFF) ENDIF (NOT DISABLE_SCTP) # Find TODO items in the code easily ? diff -r db6c40b8b307 -r bd83ce9328ed include/freeDiameter/freeDiameter-host.h.in --- a/include/freeDiameter/freeDiameter-host.h.in Tue Oct 20 17:30:20 2009 +0900 +++ b/include/freeDiameter/freeDiameter-host.h.in Wed Oct 21 18:42:45 2009 +0900 @@ -45,6 +45,7 @@ #cmakedefine DISABLE_SCTP #cmakedefine DEBUG_SCTP +#cmakedefine SCTP_USE_MAPPED_ADDRESSES #cmakedefine ERRORS_ON_TODO #cmakedefine DEBUG diff -r db6c40b8b307 -r bd83ce9328ed include/freeDiameter/freeDiameter.h --- a/include/freeDiameter/freeDiameter.h Tue Oct 20 17:30:20 2009 +0900 +++ b/include/freeDiameter/freeDiameter.h Wed Oct 21 18:42:45 2009 +0900 @@ -117,26 +117,24 @@ /* Endpoints */ struct fd_endpoint { struct fd_list chain; /* link in cnf_endpoints list */ + union { - sSS ss; /* the socket information. List is always ordered by ss value (memcmp) */ + sSS ss; /* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */ 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 */ - unsigned adv : 1; /* This endpoint was advertized in Diameter CER/CEA exchange */ - unsigned ll : 1; /* Lower layer mechanism provided this endpoint */ + +#define EP_FL_CONF (1 << 0) /* This endpoint is statically configured in a configuration file */ +#define EP_FL_DISC (1 << 1) /* This endpoint was resolved from the Diameter Identity or other DNS query */ +#define EP_FL_ADV (1 << 2) /* This endpoint was advertized in Diameter CER/CEA exchange */ +#define EP_FL_LL (1 << 3) /* Lower layer mechanism provided this endpoint */ +#define EP_FL_PRIMARY (1 << 4) /* This endpoint is primary in a multihomed SCTP association */ + uint32_t flags; /* Additional information about the endpoint */ - /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */ - - } meta; /* Additional information about the endpoint */ + /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */ }; -/* 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. */ @@ -467,4 +465,14 @@ /* Note: if we want to support capabilities updates, we'll have to add possibility to remove an app as well... */ +/***************************************/ +/* Endpoints lists helpers */ +/***************************************/ + +int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags ); +int fd_ep_filter( struct fd_list * list, uint32_t flags ); +int fd_ep_clearflags( struct fd_list * list, uint32_t flags ); + + + #endif /* _FREEDIAMETER_H */ diff -r db6c40b8b307 -r bd83ce9328ed include/freeDiameter/libfreeDiameter.h --- a/include/freeDiameter/libfreeDiameter.h Tue Oct 20 17:30:20 2009 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Wed Oct 21 18:42:45 2009 +0900 @@ -335,27 +335,7 @@ fd_log_debug("(NULL / ANY)"); \ } \ } -/* 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 */ +/* Same but with the port (service) also */ #define sSA_DUMP_NODE_SERV( sa, flag ) { \ sSA * __sa = (sSA *)(sa); \ char __addrbuf[INET6_ADDRSTRLEN]; \ @@ -376,6 +356,19 @@ fd_log_debug("(NULL / ANY)"); \ } \ } +/* Inside a debug trace */ +#define TRACE_DEBUG_sSA(level, prefix, sa, flags, suffix ) { \ + if ( TRACE_BOOL(level) ) { \ + char __buf[25]; \ + char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"); \ + fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n" \ + "\t%s|%*s" prefix , \ + __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\ + (level < FULL)?"@":" ",level, ""); \ + sSA_DUMP_NODE_SERV( sa, flags ); \ + fd_log_debug(suffix "\n"); \ + } \ +} /* A l4 protocol name (TCP / SCTP) */ @@ -480,6 +473,14 @@ { free(buffer); } +static __inline__ void fd_cleanup_socket(void * sockptr) +{ + if (sockptr) { + shutdown(*(int *)sockptr, SHUT_RDWR); + *(int *)sockptr = 0; + } +} + /*============================================================*/ /* LISTS */