Navigation


Changeset 38:68c1890f7049 in freeDiameter


Ignore:
Timestamp:
Nov 5, 2009, 5:29:12 PM (15 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Fixed a small bug in SCTP close

Files:
8 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/cnxctx.c

    r31 r38  
    11441144        if (conn->cc_socket > 0) {
    11451145                shutdown(conn->cc_socket, SHUT_RDWR);
     1146                close(conn->cc_socket);
     1147                conn->cc_socket = -1;
    11461148        }
    11471149       
  • freeDiameter/endpoints.c

    r33 r38  
    9494}
    9595
     96/* Keep only endpoints of the same family as af */
     97int fd_ep_filter_family( struct fd_list * list, int af )
     98{
     99        struct fd_list * li;
     100       
     101        TRACE_ENTRY("%p %d", list, af);
     102        CHECK_PARAMS(list);
     103       
     104        for (li = list->next; li != list; li = li->next) {
     105                struct fd_endpoint * ep = (struct fd_endpoint *)li;
     106               
     107                if (ep->sa.sa_family != af) {
     108                        li = li->prev;
     109                        fd_list_unlink(&ep->chain);
     110                        free(ep);
     111                }
     112        }
     113       
     114        return 0;
     115}
     116
    96117/* Reset the given flag(s) from all items in the list */
    97118int fd_ep_clearflags( struct fd_list * list, uint32_t flags )
  • freeDiameter/fD.h

    r37 r38  
    148148                struct cnxctx * p_receiver;     /* Only used in case of election */
    149149                pthread_t       p_ini_thr;
     150                struct fd_list  p_connparams;   /* The list of connection attempts, see p_cnx.c */
    150151        };
    151152               
     
    244245void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay);
    245246int fd_psm_change_state(struct fd_peer * peer, int new_state);
    246 void fd_psm_cleanup(struct fd_peer * peer);
     247void fd_psm_cleanup(struct fd_peer * peer, int terminate);
    247248
    248249/* Peer out */
     
    250251int fd_out_start(struct fd_peer * peer);
    251252int fd_out_stop(struct fd_peer * peer);
     253
     254/* Initiating connections */
     255int fd_p_cnx_init(struct fd_peer * peer);
     256void fd_p_cnx_abort(struct fd_peer * peer, int cleanup_all);
    252257
    253258/* Peer sent requests cache */
  • freeDiameter/p_cnx.c

    r37 r38  
    3838/* This file contains code used by a peer state machine to initiate a connection to remote peer */
    3939
     40struct next_conn {
     41        struct fd_list  chain;
     42        int             proto;  /* Protocol of the next attempt */
     43        sSS             ss;     /* The address, only for TCP */
     44        uint16_t        port;   /* The port, for SCTP (included in ss for TCP) */
     45        int             dotls;  /* Handshake TLS after connection ? */
     46};
     47
     48static int prepare_connection_list(struct fd_peer * peer)
     49{
     50        /* Resolve peer address(es) if needed */
     51        if (FD_IS_LIST_EMPTY(&peer->p_hdr.info.pi_endpoints)) {
     52                struct addrinfo hints, *ai, *aip;
     53                int ret;
     54
     55                memset(&hints, 0, sizeof(hints));
     56                hints.ai_flags = AI_ADDRCONFIG;
     57                ret = getaddrinfo(peer->p_hdr.info.pi_diamid, NULL, &hints, &ai);
     58                if (ret) {
     59                        fd_log_debug("Unable to resolve address for peer '%s' (%s), aborting this connection\n", peer->p_hdr.info.pi_diamid, gai_strerror(ret));
     60                        fd_psm_terminate( peer );
     61                        return 0;
     62                }
     63               
     64                for (aip = ai; aip != NULL; aip = aip->ai_next) {
     65                        CHECK_FCT( fd_ep_add_merge( &peer->p_hdr.info.pi_endpoints, aip->ai_addr, aip->ai_addrlen, EP_FL_DISC ) );
     66                }
     67                freeaddrinfo(ai);
     68        }
     69       
     70        /* Remove addresses from unwanted family */
     71        if (peer->p_hdr.info.config.pic_flags.pro3) {
     72                CHECK_FCT( fd_ep_filter_family(
     73                                        &peer->p_hdr.info.pi_endpoints,
     74                                        (peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ?
     75                                                AF_INET
     76                                                : AF_INET6));
     77        }
     78       
     79        TODO("Prepare the list in peer->p_connparams obeying the flags");
     80       
     81        TODO("Return an error if the list is empty in the end");
     82       
     83        return ENOTSUP;
     84}
     85
     86static __inline__ void failed_connection_attempt(struct fd_peer * peer)
     87{
     88        /* Simply remove the first item in the list */
     89        struct fd_list * li = peer->p_connparams.next;
     90        fd_list_unlink(li);
     91        free(li);
     92}
     93
     94static void empty_connection_list(struct fd_peer * peer)
     95{
     96        /* Remove all items */
     97        while (!FD_IS_LIST_EMPTY(&peer->p_connparams)) {
     98                failed_connection_attempt(peer);
     99        }
     100}
     101
    40102
    41103/* The thread that attempts the connection */
     
    44106        struct fd_peer * peer = arg;
    45107        struct cnxctx * cnx = NULL;
    46        
    47        
    48        
    49         /* Use the flags in the peer to select the protocol */
    50        
    51         TODO("loop on fd_cnx_cli_connect_tcp or fd_cnx_cli_connect_sctp");
    52        
     108        struct next_conn * nc = NULL;
     109       
     110        TRACE_ENTRY("%p", arg);
     111        CHECK_PARAMS_DO( CHECK_PEER(peer), return NULL );
     112
     113        do {
     114                /* Rebuild the list if needed, if it is empty */
     115                if (FD_IS_LIST_EMPTY(&peer->p_connparams)) {
     116                        CHECK_FCT_DO( prepare_connection_list(peer), goto fatal_error );
     117                        if (FD_IS_LIST_EMPTY(&peer->p_connparams))
     118                                /* Already logged and peer terminated */
     119                                return NULL;
     120                }
     121               
     122                /* Attempt connection to the first entry */
     123                nc = (struct next_conn *)(peer->p_connparams.next);
     124               
     125                switch (nc->proto) {
     126                        case IPPROTO_TCP:
     127                                cnx = fd_cnx_cli_connect_tcp((sSA *)&nc->ss, sSSlen(&nc->ss));
     128                                break;
     129#ifndef DISABLE_SCTP                   
     130                        case IPPROTO_SCTP:
     131                                cnx = fd_cnx_cli_connect_sctp((peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ?: fd_g_config->cnf_flags.no_ip6, nc->port, &peer->p_hdr.info.pi_endpoints);
     132                                break;
     133#endif /* DISABLE_SCTP */
     134                }
     135               
     136                if (cnx)
     137                        break;
     138               
     139                /* Pop these parameters and continue */
     140                failed_connection_attempt(peer);
     141               
     142                pthread_testcancel();
     143               
     144        } while (!cnx); /* and until cancellation */
    53145       
    54146        /* Now, we have an established connection in cnx */
     
    57149       
    58150        /* Handshake if needed (secure port) */
    59        
    60        
     151        if (nc->dotls) {
     152                CHECK_FCT_DO( fd_cnx_handshake(cnx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
     153                        {
     154                                /* Handshake failed ...  */
     155                                fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
     156                                fd_cnx_destroy(cnx);
     157                                empty_connection_list(peer);
     158                                fd_ep_filter(&peer->p_hdr.info.pi_endpoints, EP_FL_CONF);
     159                                return NULL;
     160                        } );
     161        }
    61162       
    62163        /* Upon success, generate FDEVP_CNX_ESTABLISHED */
    63164        CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ESTABLISHED, 0, cnx), goto fatal_error );
     165       
    64166        pthread_cleanup_pop(0);
    65167       
    66168        return NULL;
     169       
    67170fatal_error:
    68171        /* Cleanup the connection */
    69         fd_cnx_destroy(cnx);
     172        if (cnx)
     173                fd_cnx_destroy(cnx);
    70174
    71175        /* Generate a termination event */
     
    79183int fd_p_cnx_init(struct fd_peer * peer)
    80184{
     185        TRACE_ENTRY("%p", peer);
     186       
    81187        /* Start the connect thread */
    82188        CHECK_FCT( pthread_create(&peer->p_ini_thr, NULL, connect_thr, peer) );
    83189        return 0;
    84190}
     191
     192/* Cancel a connection attempt */
     193void fd_p_cnx_abort(struct fd_peer * peer, int cleanup_all)
     194{
     195        TRACE_ENTRY("%p %d", peer, cleanup_all);
     196        CHECK_PARAMS_DO( CHECK_PEER(peer), return );
     197       
     198        if (peer->p_ini_thr != (pthread_t)NULL) {
     199                CHECK_FCT_DO( fd_thr_term(&peer->p_ini_thr), /* continue */);
     200                failed_connection_attempt(peer);
     201        }
     202       
     203        if (cleanup_all) {
     204                empty_connection_list(peer);
     205        }
     206}
  • freeDiameter/p_psm.c

    r37 r38  
    243243
    244244/* Cleanup the peer */
    245 void fd_psm_cleanup(struct fd_peer * peer)
     245void fd_psm_cleanup(struct fd_peer * peer, int terminate)
    246246{
    247247        /* Move to CLOSED state: failover messages, stop OUT thread, unlink peer from active list */
    248248        CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ );
    249249       
    250         /* Destroy data */
    251         CHECK_FCT_DO( fd_thr_term(&peer->p_ini_thr), /* continue */);
     250
     251        fd_p_cnx_abort(peer, terminate);
     252       
    252253        if (peer->p_cnxctx) {
    253254                fd_cnx_destroy(peer->p_cnxctx);
    254255                peer->p_cnxctx = NULL;
    255256        }
     257       
    256258        if (peer->p_initiator) {
    257259                fd_cnx_destroy(peer->p_initiator);
    258260                peer->p_initiator = NULL;
    259261        }
     262       
    260263        if (peer->p_receiver) {
    261264                fd_cnx_destroy(peer->p_receiver);
    262265                peer->p_receiver = NULL;
     266        }
     267       
     268        if (terminate) {
     269                CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ );
    263270        }
    264271       
     
    527534                        case STATE_CLOSING:
    528535                                /* Cleanup the peer */
    529                                 fd_psm_cleanup(peer);
     536                                fd_psm_cleanup(peer, 0);
    530537
    531538                                /* Reset the timer */
     
    602609                        case STATE_WAITCEA:
    603610                                /* Destroy the connection, restart the timer to a new connection attempt */
    604                                 fd_psm_cleanup(peer);
     611                                fd_psm_cleanup(peer, 0);
    605612                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
    606613                                break;
     
    622629
    623630psm_end:
    624         fd_psm_cleanup(peer);
    625         CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ );
     631        fd_psm_cleanup(peer, 1);
    626632        pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
    627633        peer->p_psm = (pthread_t)NULL;
     
    675681       
    676682        /* Cleanup the data */
    677         fd_psm_cleanup(peer);
     683        fd_psm_cleanup(peer, 1);
    678684       
    679685        /* Destroy the event list */
  • freeDiameter/sctp.c

    r33 r38  
    641641}
    642642
    643 /* Create a client socket and connect to remote server */
    644 int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list )
     643/* Add addresses from the list that match the flags to the array */
     644static int add_addresses_from_list_mask(uint8_t ** array, int * count, size_t * offset, uint16_t port, struct fd_list * list, uint32_t mask, uint32_t val)
    645645{
    646         int family;
    647         int count = 0;
    648         size_t offset = 0, sz;
     646        size_t sz;
     647        struct fd_list * li;
    649648        union {
    650649                uint8_t *buf;
    651                 sSA     *sa;
    652         } sar;
    653         union {
    654                 uint8_t *buf;
    655                 sSA     *sa;
    656650                sSA4    *sin;
    657651                sSA6    *sin6;
    658652        } ptr;
    659         struct fd_list * li;
    660         int ret;
    661        
    662         sar.buf = NULL;
    663        
    664         TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list);
    665         CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) );
    666        
    667         if (no_ip6) {
    668                 family = AF_INET;
    669         } else {
    670                 family = AF_INET6;
    671         }
    672        
    673         /* Create the socket */
    674         CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );
    675        
    676         /* Cleanup if we are cancelled */
    677         pthread_cleanup_push(fd_cleanup_socket, sock);
    678        
    679         /* Set the socket options */
    680         CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail );
    681        
    682         /* Create the array of addresses for sctp_connectx */
     653       
    683654        for (li = list->next; li != list; li = li->next) {
    684655                struct fd_endpoint * ep = (struct fd_endpoint *) li;
    685656               
    686                 count++;
    687                
    688                 /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */
     657                /* Do the flag match ? */
     658                if ((val & mask) != (ep->flags & mask))
     659                        continue;
     660               
     661                /* We add this endpoint at the end of array */
     662                (*count)++;
     663               
     664                /* Size of the new SA we are adding (array may contain a mix of sockaddr_in and sockaddr_in6) */
    689665#ifndef SCTP_USE_MAPPED_ADDRESSES
    690666                if (ep->sa.sa_family == AF_INET6)
     
    696672                        sz = sizeof(sSA4);
    697673               
    698                 /* augment sar to contain the additional info */
    699                 CHECK_MALLOC_DO( sar.buf = realloc(sar.buf, offset + sz), { ret = ENOMEM; goto fail; } );
    700 
    701                 ptr.buf = sar.buf + offset; /* place of the new SA */
    702                 offset += sz; /* update to end of sar */
     674                /* augment array to contain the additional info */
     675                CHECK_MALLOC( *array = realloc(*array, (*offset) + sz) );
     676
     677                ptr.buf = *array + *offset; /* place of the new SA */
     678                (*offset) += sz; /* update to end of sar */
    703679                       
    704680                if (sz == sizeof(sSA4)) {
    705681                        memcpy(ptr.buf, &ep->sin, sz);
    706                         ptr.sin->sin_port = htons(port);
     682                        ptr.sin->sin_port = port;
    707683                } else {
    708684                        if (ep->sa.sa_family == AF_INET) { /* We must map the address */
     
    713689                                memcpy(ptr.sin6, &ep->sin6, sz);
    714690                        }
    715                         ptr.sin6->sin6_port = htons(port);
    716                 }
    717         }
     691                        ptr.sin6->sin6_port = port;
     692                }
     693        }
     694       
     695        return 0;
     696}
     697
     698/* Create a client socket and connect to remote server */
     699int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list )
     700{
     701        int family;
     702        int count = 0;
     703        size_t offset = 0;
     704        union {
     705                uint8_t *buf;
     706                sSA     *sa;
     707        } sar;
     708        int ret;
     709       
     710        sar.buf = NULL;
     711       
     712        TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list);
     713        CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) );
     714       
     715        if (no_ip6) {
     716                family = AF_INET;
     717        } else {
     718                family = AF_INET6;
     719        }
     720       
     721        /* Create the socket */
     722        CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );
     723       
     724        /* Cleanup if we are cancelled */
     725        pthread_cleanup_push(fd_cleanup_socket, sock);
     726       
     727        /* Set the socket options */
     728        CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail );
     729       
     730        /* Create the array of addresses, add first the configured addresses, then the discovered, then the other ones */
     731        CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &count, &offset, htons(port), list, EP_FL_CONF,              EP_FL_CONF      ), goto fail );
     732        CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &count, &offset, htons(port), list, EP_FL_CONF | EP_FL_DISC, EP_FL_DISC      ), goto fail );
     733        CHECK_FCT_DO( ret = add_addresses_from_list_mask(&sar.buf, &count, &offset, htons(port), list, EP_FL_CONF | EP_FL_DISC, 0               ), goto fail );
    718734       
    719735        /* Try connecting */
  • freeDiameter/tests/testcnx.c

    r32 r38  
    471471struct connect_flags {
    472472        int     proto;
     473        int     expect_failure; /* 0 or 1 */
    473474};
    474475
     
    486487                                struct fd_endpoint * ep = (struct fd_endpoint *)(eps.next);
    487488                                cnx = fd_cnx_cli_connect_tcp( &ep->sa, sSSlen(&ep->ss) );
    488                                 CHECK( 1, cnx ? 1 : 0 );
     489                                CHECK( 1, (cnx ? 1 : 0) ^ cf->expect_failure );
    489490                        }
    490491                        break;
     
    493494                        {
    494495                                cnx = fd_cnx_cli_connect_sctp(0, TEST_PORT, &eps);
    495                                 CHECK( 1, cnx ? 1 : 0 );
     496                                CHECK( 1, (cnx ? 1 : 0) ^ cf->expect_failure );
    496497                        }
    497498                        break;
     
    15101511        }
    15111512       
     1513        /* Check that connection attempt fails then */
     1514        {
     1515                struct connect_flags cf;
     1516               
     1517                memset(&cf, 0, sizeof(cf));
     1518                cf.proto = IPPROTO_TCP;
     1519                cf.expect_failure = 1;
     1520               
     1521                /* Start the client thread, that should fail */
     1522                CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
     1523                CHECK( 0, pthread_join( thr, (void *)&client_side ) );
     1524                CHECK( 0, client_side ? 1 : 0 );
     1525        }
     1526               
     1527#ifndef DISABLE_SCTP
     1528        {
     1529                struct connect_flags cf;
     1530               
     1531                memset(&cf, 0, sizeof(cf));
     1532                cf.proto = IPPROTO_SCTP;
     1533                cf.expect_failure = 1;
     1534               
     1535                /* Start the client thread, that should fail */
     1536                CHECK( 0, pthread_create(&thr, 0, connect_thr, &cf) );
     1537                CHECK( 0, pthread_join( thr, (void *)&client_side ) );
     1538                CHECK( 0, client_side ? 1 : 0 );
     1539        }
     1540#endif /* DISABLE_SCTP */
     1541       
     1542       
    15121543        /* That's all for the tests yet */
    15131544        PASSTEST();
  • include/freeDiameter/freeDiameter.h

    r37 r38  
    540540int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );
    541541int fd_ep_filter( struct fd_list * list, uint32_t flags );
     542int fd_ep_filter_family( struct fd_list * list, int af );
    542543int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
    543544void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep, char * suffix );
Note: See TracChangeset for help on using the changeset viewer.