Navigation


Changeset 706:4ffbc9f1e922 in freeDiameter for libfdcore


Ignore:
Timestamp:
Feb 9, 2011, 3:26:58 PM (13 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
Location:
libfdcore
Files:
21 edited

Legend:

Unmodified
Added
Removed
  • libfdcore/cnxctx.c

    r662 r706  
    5151 */
    5252
    53 /* Note: this file could be moved to libfreeDiameter instead, but since it uses gnuTLS we prefer to keep it in the daemon */
    54 
    5553/* Lifetime of a cnxctx object:
    5654 * 1) Creation
     
    158156        TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
    159157        ASSERT(0);
    160         CHECK_FCT_DO( ENOTSUP, );
    161         return NULL;
     158        CHECK_FCT_DO( ENOTSUP, return NULL);
    162159#else /* DISABLE_SCTP */
    163160        struct cnxctx * cnx = NULL;
     
    249246                int  rc;
    250247               
    251                 /* Numeric values for debug */
    252248                rc = getnameinfo((sSA *)&ss, sSAlen(&ss), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    253249                if (rc) {
     
    256252                }
    257253               
    258                 snprintf(cli->cc_id, sizeof(cli->cc_id), "{%s} (%d) <- [%s]:%s (%d)",
    259                                 IPPROTO_NAME(cli->cc_proto), serv->cc_socket,
    260                                 addrbuf, portbuf, cli->cc_socket);
    261                
    262                 /* Name for log messages */
     254                /* Numeric values for debug... */
     255                snprintf(cli->cc_id, sizeof(cli->cc_id), "%s from [%s]:%s (%d<-%d)",
     256                                IPPROTO_NAME(cli->cc_proto), addrbuf, portbuf, serv->cc_socket, cli->cc_socket);
     257               
     258               
     259                /* ...Name for log messages */
    263260                rc = getnameinfo((sSA *)&ss, sSAlen(&ss), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0);
    264261                if (rc)
     
    334331                int  rc;
    335332               
    336                 /* Numeric values for debug */
     333                /* Numeric values for debug... */
    337334                rc = getnameinfo(sa, addrlen, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    338335                if (rc) {
     
    341338                }
    342339               
    343                 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "{TCP} -> [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
    344                
    345                 /* Name for log messages */
     340                snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP to [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
     341               
     342                /* ...Name for log messages */
    346343                rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
    347344                if (rc)
     
    356353{
    357354#ifdef DISABLE_SCTP
    358         TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
     355        TRACE_DEBUG(INFO, "This function should never be called when SCTP is disabled...");
    359356        ASSERT(0);
    360         CHECK_FCT_DO( ENOTSUP, );
    361         return NULL;
     357        CHECK_FCT_DO( ENOTSUP, return NULL);
    362358#else /* DISABLE_SCTP */
    363359        int sock = 0;
     
    416412                int  rc;
    417413               
    418                 /* Numeric values for debug */
     414                /* Numeric values for debug... */
    419415                rc = getnameinfo((sSA *)&primary, sSAlen(&primary), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
    420416                if (rc) {
     
    423419                }
    424420               
    425                 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "{SCTP} -> [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
    426                
    427                 /* Name for log messages */
     421                snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP to [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
     422               
     423                /* ...Name for log messages */
    428424                rc = getnameinfo((sSA *)&primary, sSAlen(&primary), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
    429425                if (rc)
     
    454450
    455451/* Set the hostname to check during handshake */
    456 void fd_cnx_sethostname(struct cnxctx * conn, char * hn)
     452void fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn)
    457453{
    458454        CHECK_PARAMS_DO( conn, return );
     
    460456}
    461457
     458/* We share a lock with many threads but we hold it only very short time so it is OK */
     459static pthread_mutex_t state_lock = PTHREAD_MUTEX_INITIALIZER;
     460uint32_t fd_cnx_getstate(struct cnxctx * conn)
     461{
     462        uint32_t st;
     463        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     464        st = conn->cc_state;
     465        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     466        return st;
     467}
     468int  fd_cnx_teststate(struct cnxctx * conn, uint32_t flag)
     469{
     470        uint32_t st;
     471        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     472        st = conn->cc_state;
     473        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     474        return st & flag;
     475}
     476void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate)
     477{
     478        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     479        conn->cc_state |= orstate;
     480        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     481}
     482void fd_cnx_setstate(struct cnxctx * conn, uint32_t abstate)
     483{
     484        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     485        conn->cc_state = abstate;
     486        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     487}
     488
     489
    462490/* Return the TLS state of a connection */
    463491int fd_cnx_getTLS(struct cnxctx * conn)
    464492{
    465493        CHECK_PARAMS_DO( conn, return 0 );
    466         fd_cpu_flush_cache();
    467         return conn->cc_status & CC_STATUS_TLS;
    468 }
     494        return fd_cnx_teststate(conn, CC_STATUS_TLS);
     495}
     496
     497/* Return true if the connection supports unordered delivery of messages */
     498int fd_cnx_isMultichan(struct cnxctx * conn)
     499{
     500        CHECK_PARAMS_DO( conn, return 0 );
     501        #ifdef DISABLE_SCTP
     502        if (conn->cc_proto == IPPROTO_SCTP)
     503                return (conn->cc_sctp_para.str_in > 1) || (conn->cc_sctp_para.str_out > 1);
     504        #endif /* DISABLE_SCTP */
     505        return 0;
     506}
     507
    469508
    470509/* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
     
    508547}
    509548
    510 /* Retrieve a list of all IP addresses of the local system from the kernel, using */
     549/* Retrieve a list of all IP addresses of the local system from the kernel, using getifaddrs */
    511550int fd_cnx_get_local_eps(struct fd_list * list)
    512551{
    513552        struct ifaddrs *iflist, *cur;
     553       
    514554        CHECK_SYS(getifaddrs(&iflist));
    515555       
     
    543583        CHECK_PARAMS_DO( conn, goto fatal );
    544584       
    545         TRACE_DEBUG(FULL, "Error flag set for socket %d (%s / %s)", conn->cc_socket, conn->cc_remid, conn->cc_id);
     585        TRACE_DEBUG(FULL, "Error flag set for socket %d (%s, %s)", conn->cc_socket, conn->cc_id, conn->cc_remid);
    546586       
    547587        /* Mark the error */
    548         fd_cpu_flush_cache();
    549         conn->cc_status |= CC_STATUS_ERROR;
     588        fd_cnx_addstate(conn, CC_STATUS_ERROR);
    550589       
    551590        /* Report the error if not reported yet, and not closing */
    552         if ((!(conn->cc_status & CC_STATUS_CLOSING )) && (!(conn->cc_status & CC_STATUS_SIGNALED )))  {
     591        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING | CC_STATUS_SIGNALED ))  {
    553592                TRACE_DEBUG(FULL, "Sending FDEVP_CNX_ERROR event");
    554                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal);
    555                 conn->cc_status |= CC_STATUS_SIGNALED;
    556         }
    557         fd_cpu_flush_cache();
     593                CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal);
     594                fd_cnx_addstate(conn, CC_STATUS_SIGNALED);
     595        }
    558596        return;
    559597fatal:
    560598        /* An unrecoverable error occurred, stop the daemon */
     599        ASSERT(0);
    561600        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );       
    562601}
     
    583622        /* Handle special case of timeout */
    584623        if ((ret < 0) && (errno == EAGAIN)) {
    585                 fd_cpu_flush_cache();
    586                 if (! (conn->cc_status & CC_STATUS_CLOSING))
     624                if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
    587625                        goto again; /* don't care, just ignore */
    588626                if (!timedout) {
     
    592630        }
    593631       
    594         CHECK_SYS_DO(ret, /* continue */);
    595        
    596632        /* Mark the error */
    597         if (ret <= 0)
     633        if (ret <= 0) {
     634                CHECK_SYS_DO(ret, /* continue, this is only used to log the error here */);
    598635                fd_cnx_markerror(conn);
     636        }
    599637       
    600638        return ret;
     
    610648        /* Handle special case of timeout */
    611649        if ((ret < 0) && (errno == EAGAIN)) {
    612                 fd_cpu_flush_cache();
    613                 if (! (conn->cc_status & CC_STATUS_CLOSING))
     650                if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
    614651                        goto again; /* don't care, just ignore */
    615652                if (!timedout) {
     
    643680       
    644681        ASSERT( conn->cc_proto == IPPROTO_TCP );
    645         ASSERT( ! (conn->cc_status & CC_STATUS_TLS) );
    646         ASSERT( Target_Queue(conn) );
     682        ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) );
     683        ASSERT( fd_cnx_target_queue(conn) );
    647684       
    648685        /* Receive from a TCP connection: we have to rebuild the message boundaries */
     
    666703
    667704                /* Check the received word is a valid begining of a Diameter message */
    668                 if ((header[0] != DIAMETER_VERSION)     /* defined in <libfreeDiameter.h> */
     705                if ((header[0] != DIAMETER_VERSION)     /* defined in <libfdproto.h> */
    669706                   || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
    670707                        /* The message is suspect */
     
    691728               
    692729                /* We have received a complete message, pass it to the daemon */
    693                 fd_cpu_flush_cache();
    694                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
     730                CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
    695731               
    696732        } while (conn->cc_loop);
     
    726762       
    727763        ASSERT( conn->cc_proto == IPPROTO_SCTP );
    728         ASSERT( ! (conn->cc_status & CC_STATUS_TLS) );
    729         ASSERT( Target_Queue(conn) );
     764        ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) );
     765        ASSERT( fd_cnx_target_queue(conn) );
    730766       
    731767        do {
    732                 fd_cpu_flush_cache();
    733                 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event, &conn->cc_status), goto fatal );
     768                CHECK_FCT_DO( fd_sctp_recvmeta(conn, NULL, &buf, &bufsz, &event), goto fatal );
    734769                if (event == FDEVP_CNX_ERROR) {
    735770                        fd_cnx_markerror(conn);
     
    742777                }
    743778               
    744                 fd_cpu_flush_cache();
    745                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto fatal );
     779                CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, bufsz, buf), goto fatal );
    746780               
    747781        } while (conn->cc_loop || (event != FDEVP_CNX_MSG_RECV));
     
    763797        TRACE_ENTRY("%p %i", conn, loop);
    764798       
    765         CHECK_PARAMS( conn && Target_Queue(conn) && (!(conn->cc_status & CC_STATUS_TLS)) && (!conn->cc_loop));
     799        CHECK_PARAMS( conn && fd_cnx_target_queue(conn) && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && (!conn->cc_loop));
    766800       
    767801        /* Release resources in case of a previous call was already made */
     
    803837                        switch (ret) {
    804838                                case GNUTLS_E_REHANDSHAKE:
    805                                         fd_cpu_flush_cache();
    806                                         if (!(conn->cc_status & CC_STATUS_CLOSING))
     839                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
    807840                                                CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
    808841                                                        {
     
    815848                                case GNUTLS_E_AGAIN:
    816849                                case GNUTLS_E_INTERRUPTED:
    817                                         fd_cpu_flush_cache();
    818                                         if (!(conn->cc_status & CC_STATUS_CLOSING))
     850                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
    819851                                                goto again;
    820852                                        TRACE_DEBUG(FULL, "Connection is closing, so abord gnutls_record_recv now.");
     
    849881                        switch (ret) {
    850882                                case GNUTLS_E_REHANDSHAKE:
    851                                         fd_cpu_flush_cache();
    852                                         if (!(conn->cc_status & CC_STATUS_CLOSING))
     883                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
    853884                                                CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
    854885                                                        {
     
    861892                                case GNUTLS_E_AGAIN:
    862893                                case GNUTLS_E_INTERRUPTED:
    863                                         fd_cpu_flush_cache();
    864                                         if (!(conn->cc_status & CC_STATUS_CLOSING))
     894                                        if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING))
    865895                                                goto again;
    866896                                        TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now.");
     
    927957               
    928958                /* We have received a complete message, pass it to the daemon */
    929                 fd_cpu_flush_cache();
    930                 CHECK_FCT_DO( ret = fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg),
     959                CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg),
    931960                        {
    932961                                free(newmsg);
     
    956985        }
    957986       
    958         ASSERT( conn->cc_status & CC_STATUS_TLS );
    959         ASSERT( Target_Queue(conn) );
     987        ASSERT( fd_cnx_teststate(conn, CC_STATUS_TLS) );
     988        ASSERT( fd_cnx_target_queue(conn) );
    960989
    961990        /* The next function only returns when there is an error on the socket */       
     
    12151244{
    12161245        TRACE_ENTRY( "%p %d %p %p", conn, mode, priority, alt_creds);
    1217         CHECK_PARAMS( conn && (!(conn->cc_status & CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
     1246        CHECK_PARAMS( conn && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
    12181247
    12191248        /* Save the mode */
     
    12481277
    12491278        /* Mark the connection as protected from here, so that the gnutls credentials will be freed */
    1250         fd_cpu_flush_cache();
    1251         conn->cc_status |= CC_STATUS_TLS;
    1252 
     1279        fd_cnx_addstate(conn, CC_STATUS_TLS);
     1280       
    12531281        /* Handshake master session */
    12541282        {
     
    12991327{
    13001328        TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size);
    1301         CHECK_PARAMS( conn && (conn->cc_status & CC_STATUS_TLS) && cert_list && cert_list_size );
     1329        CHECK_PARAMS( conn && fd_cnx_teststate(conn, CC_STATUS_TLS) && cert_list && cert_list_size );
    13021330       
    13031331        /* This function only works for X.509 certificates. */
     
    13601388}
    13611389
     1390/* Where the events are sent */
     1391struct fifo * fd_cnx_target_queue(struct cnxctx * conn)
     1392{
     1393        struct fifo *q;
     1394        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     1395        q = conn->cc_alt ?: conn->cc_incoming;
     1396        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     1397        return q;
     1398}
     1399
    13621400/* Set an alternate FIFO list to send FDEVP_CNX_* events to */
    13631401int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)
    13641402{
     1403        int ret;
    13651404        TRACE_ENTRY( "%p %p", conn, alt_fifo );
    13661405        CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming );
    13671406       
    13681407        /* The magic function does it all */
    1369         CHECK_FCT( fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ) );
    1370        
    1371         return 0;
     1408        CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } );
     1409        CHECK_FCT_DO( ret = fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ), );
     1410        CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } );
     1411       
     1412        return ret;
    13721413}
    13731414
     
    13791420        TRACE_ENTRY("%p %p %zd", conn, buf, len);
    13801421        do {
    1381                 fd_cpu_flush_cache();
    1382                 if (conn->cc_status & CC_STATUS_TLS) {
     1422                if (fd_cnx_teststate(conn, CC_STATUS_TLS)) {
    13831423                        CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent),  );
    13841424                } else {
     
    13941434}
    13951435
    1396 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time, so we don't protect. */
     1436/* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time (on the same conn), so we don't protect. */
    13971437int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len, uint32_t flags)
    13981438{
    13991439        TRACE_ENTRY("%p %p %zd %x", conn, buf, len, flags);
    14001440       
    1401         CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! (conn->cc_status & CC_STATUS_ERROR)) && buf && len);
    1402 
    1403         TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, (conn->cc_status & CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id);
     1441        CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! fd_cnx_teststate(conn, CC_STATUS_ERROR)) && buf && len);
     1442
     1443        TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, fd_cnx_teststate(conn, CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id);
    14041444       
    14051445        switch (conn->cc_proto) {
     
    14101450#ifndef DISABLE_SCTP
    14111451                case IPPROTO_SCTP: {
    1412                         if (flags & FD_CNX_BROADCAST) {
    1413                                 /* Send the buffer over all other streams */
    1414                                 uint16_t str;
    1415                                 fd_cpu_flush_cache();
    1416                                 if (conn->cc_status & CC_STATUS_TLS) {
    1417                                         for ( str=1; str < conn->cc_sctp_para.pairs; str++) {
    1418                                                 ssize_t ret;
    1419                                                 size_t sent = 0;
    1420                                                 do {
    1421                                                         CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctps_data.array[str].session, buf + sent, len - sent), );
    1422                                                         if (ret <= 0)
    1423                                                                 return ENOTCONN;
    1424 
    1425                                                         sent += ret;
    1426                                                 } while ( sent < len );
    1427                                         }
    1428                                 } else {
    1429                                         for ( str=1; str < conn->cc_sctp_para.str_out; str++) {
    1430                                                 CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, str, buf, len, &conn->cc_status), { fd_cnx_markerror(conn); return ENOTCONN; } );
    1431                                         }
    1432                                 }
    1433                                
    1434                                 /* Set the ORDERED flag also so that it is sent over stream 0 as well */
    1435                                 flags &= FD_CNX_ORDERED;
    1436                         }
    1437                        
    14381452                        if (flags & FD_CNX_ORDERED) {
    14391453                                /* We send over stream #0 */
     
    14441458                                int another_str = 0; /* do we send over stream #0 ? */
    14451459                               
    1446                                 if ((conn->cc_sctp_para.str_out > 1) && ((! (conn->cc_status & CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1)))  {
     1460                                if ((conn->cc_sctp_para.str_out > 1) && ((!fd_cnx_teststate(conn, CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1)))  {
    14471461                                        /* Update the id of the stream we will send this message over */
    14481462                                        conn->cc_sctp_para.next += 1;
    1449                                         conn->cc_sctp_para.next %= ((conn->cc_status & CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
     1463                                        conn->cc_sctp_para.next %= (fd_cnx_teststate(conn, CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
    14501464                                        another_str = (conn->cc_sctp_para.next ? 1 : 0);
    14511465                                }
     
    14541468                                        CHECK_FCT( send_simple(conn, buf, len) );
    14551469                                } else {
    1456                                         if (!(conn->cc_status & CC_STATUS_TLS)) {
    1457                                                 CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len, &conn->cc_status), { fd_cnx_markerror(conn); return ENOTCONN; } );
     1470                                        if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) {
     1471                                                CHECK_FCT_DO( fd_sctp_sendstr(conn, conn->cc_sctp_para.next, buf, len), { fd_cnx_markerror(conn); return ENOTCONN; } );
    14581472                                        } else {
    14591473                                                /* push the record to the appropriate session */
     
    14961510        CHECK_PARAMS_DO(conn, return);
    14971511       
    1498         fd_cpu_flush_cache();
    1499         conn->cc_status |= CC_STATUS_CLOSING;
     1512        fd_cnx_addstate(conn, CC_STATUS_CLOSING);
    15001513       
    15011514        /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */
    1502         if (conn->cc_status & CC_STATUS_TLS) {
     1515        if (fd_cnx_teststate(conn, CC_STATUS_TLS)) {
    15031516#ifndef DISABLE_SCTP
    15041517                if (conn->cc_sctp_para.pairs > 1) {
    1505                         if (! (conn->cc_status & CC_STATUS_ERROR )) {
     1518                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR )) {
    15061519                                /* Bye on master session */
    15071520                                CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
    15081521                        }
    15091522
    1510                         if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
     1523                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
    15111524                                /* and other stream pairs */
    15121525                                fd_sctps_bye(conn);
    15131526                        }
    15141527
    1515                         if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
     1528                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
    15161529                                /* Now wait for all decipher threads to terminate */
    15171530                                fd_sctps_waitthreadsterm(conn);
     
    15331546                } else {
    15341547#endif /* DISABLE_SCTP */
    1535                 /* We are not using the sctps wrapper layer */
    1536                         if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
     1548                /* We are TLS, but not using the sctps wrapper layer */
     1549                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
    15371550                                /* Master session */
    15381551                                CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
    15391552                        }
    15401553
    1541                         if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
     1554                        if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) {
    15421555                                /* In this case, just wait for thread rcvthr_tls_single to terminate */
    15431556                                if (conn->cc_rcvthr != (pthread_t)NULL) {
     
    15551568                                conn->cc_tls_para.session = NULL;
    15561569                        }
    1557                
    15581570#ifndef DISABLE_SCTP
    15591571                }
  • libfdcore/cnxctx.h

    r662 r706  
    4848        int             cc_family;      /* AF_INET or AF_INET6 (mixed) */
    4949        int             cc_proto;       /* IPPROTO_TCP or IPPROTO_SCTP */
    50         uint32_t        cc_status;      /* True if the object is being destroyed: we don't send events anymore */
     50       
     51        uint32_t        cc_state;       /* True if the object is being destroyed: we don't send events anymore. access with fd_cnx_getstate() */
    5152        #define         CC_STATUS_CLOSING       1
    5253        #define         CC_STATUS_ERROR         2
     
    5960        struct fifo *   cc_incoming;    /* FIFO queue of events received on the connection, FDEVP_CNX_* */
    6061        struct fifo *   cc_alt;         /* alternate fifo to send FDEVP_CNX_* events to. */
    61         #define Target_Queue(cnx)       ((cnx)->cc_alt ?: (cnx)->cc_incoming)
    6262
    6363        /* If cc_tls == true */
    6464        struct {
    65                 char                            *cn;            /* If not NULL, remote certif will be checked to match this Common Name */
     65                DiamId_t                         cn;            /* If not NULL, remote certif will be checked to match this Common Name */
    6666                int                              mode;          /* GNUTLS_CLIENT / GNUTLS_SERVER */
    6767                gnutls_session_t                 session;       /* Session object (stream #0 in case of SCTP) */
     
    8484
    8585void fd_cnx_markerror(struct cnxctx * conn);
     86uint32_t fd_cnx_getstate(struct cnxctx * conn);
     87int  fd_cnx_teststate(struct cnxctx * conn, uint32_t flag);
     88void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate);
     89void fd_cnx_setstate(struct cnxctx * conn, uint32_t abstate);
     90struct fifo * fd_cnx_target_queue(struct cnxctx * conn);
     91
    8692
    8793/* Socket */
     
    109115int fd_sctp_get_remote_ep(int sock, struct fd_list * list);
    110116int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary );
    111 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len, uint32_t * cc_closing);
    112 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event, uint32_t * cc_closing);
     117int fd_sctp_sendstr(struct cnxctx * conn, uint16_t strid, uint8_t * buf, size_t len);
     118int fd_sctp_recvmeta(struct cnxctx * conn, uint16_t * strid, uint8_t ** buf, size_t * len, int *event);
    113119
    114120/* TLS over SCTP (multi-stream) */
  • libfdcore/config.c

    r686 r706  
    146146{
    147147        extern FILE * fddin;
     148        char * orig = NULL;
    148149       
    149150        /* Attempt to find the configuration file */
     
    154155        if ((fddin == NULL) && (*fd_g_config->cnf_file != '/')) {
    155156                /* We got a relative path, attempt to add the default directory prefix */
    156                 char * bkp = fd_g_config->cnf_file;
    157                 CHECK_MALLOC( fd_g_config->cnf_file = malloc(strlen(bkp) + strlen(DEFAULT_CONF_PATH) + 2) ); /* we will not free it, but not important */
    158                 sprintf( fd_g_config->cnf_file, DEFAULT_CONF_PATH "/%s", bkp );
     157                orig = fd_g_config->cnf_file;
     158                CHECK_MALLOC( fd_g_config->cnf_file = malloc(strlen(orig) + strlen(DEFAULT_CONF_PATH) + 2) ); /* we will not free it, but not important */
     159                sprintf( fd_g_config->cnf_file, DEFAULT_CONF_PATH "/%s", orig );
    159160                fddin = fopen(fd_g_config->cnf_file, "r");
    160161        }
    161162        if (fddin == NULL) {
    162163                int ret = errno;
    163                 fprintf(stderr, "Unable to open configuration file %s for reading: %s\n", fd_g_config->cnf_file, strerror(ret));
     164                if (orig) {
     165                        fprintf(stderr, "Unable to open configuration file for reading\n"
     166                                        "Tried the following locations:\n"
     167                                        " - %s\n"
     168                                        " - %s\n"
     169                                        "Error: %s\n", orig, fd_g_config->cnf_file, strerror(ret));
     170                } else {
     171                        fprintf(stderr, "Unable to open '%s' for reading: %s\n", fd_g_config->cnf_file, strerror(ret));
     172                }
    164173                return ret;
    165174        }
     
    178187        }
    179188       
     189        /* If the CA is not provided, let's use the same file (assuming self-signed certificate) */
     190        if (! fd_g_config->cnf_sec_data.ca_file) {
     191                CHECK_MALLOC( fd_g_config->cnf_sec_data.ca_file = strdup(fd_g_config->cnf_sec_data.cert_file) );
     192                CHECK_GNUTLS_DO( fd_g_config->cnf_sec_data.ca_file_nr += gnutls_certificate_set_x509_trust_file(
     193                                        fd_g_config->cnf_sec_data.credentials,
     194                                        fd_g_config->cnf_sec_data.ca_file,
     195                                        GNUTLS_X509_FMT_PEM),
     196                                {
     197                                        TRACE_DEBUG(INFO, "Unable to use the local certificate as trusted security anchor (CA), please provide a valid TLS_CA='...' directive.");
     198                                        return EINVAL;
     199                                } );
     200        }
     201       
     202       
    180203        /* Resolve hostname if not provided */
    181204        if (fd_g_config->cnf_diamid == NULL) {
    182 #ifndef HOST_NAME_MAX
    183 #define HOST_NAME_MAX 1024
    184 #endif /* HOST_NAME_MAX */
    185205                char buf[HOST_NAME_MAX + 1];
    186206                struct addrinfo hints, *info;
     
    202222                        return EINVAL;
    203223                }
    204                 CHECK_MALLOC( fd_g_config->cnf_diamid = strdup(info->ai_canonname) );
     224                fd_g_config->cnf_diamid = info->ai_canonname;
     225                CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 1) );
    205226                freeaddrinfo(info);
    206         }
    207        
    208         /* cache the length of the diameter id for the session module */
    209         fd_g_config->cnf_diamid_len = strlen(fd_g_config->cnf_diamid);
     227        } else {
     228                CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 0) );
     229        }
    210230       
    211231        /* Handle the realm part */
     
    220240                                        fd_g_config->cnf_diamid);
    221241                        return EINVAL;
    222                 }               
    223                
    224                 CHECK_MALLOC( fd_g_config->cnf_diamrlm = strdup( start + 1 )  );
    225         }
    226         fd_g_config->cnf_diamrlm_len = strlen(fd_g_config->cnf_diamrlm);
     242                }
     243               
     244                fd_g_config->cnf_diamrlm = start + 1;
     245                CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 1) );
     246        } else {
     247                CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 0) );
     248        }
    227249       
    228250        /* Validate some flags */
  • libfdcore/core.c

    r693 r706  
    4545GCRY_THREAD_OPTION_PTHREAD_IMPL;
    4646
    47 /* Signal extensions when the framework is completly initialized */
     47/* Signal extensions when the framework is completly initialized (they are waiting in fd_core_waitstartcomplete()) */
    4848static int             is_ready = 0;
    4949static pthread_mutex_t is_ready_mtx = PTHREAD_MUTEX_INITIALIZER;
     
    6262/* Thread that process incoming events on the main queue -- and terminates the framework when requested */
    6363static pthread_t core_runner = (pthread_t)NULL;
     64
     65/* How the thread is terminated */
    6466enum core_mode {
    6567        CORE_MODE_EVENTS,
  • libfdcore/extensions.c

    r695 r706  
    5757        struct fd_ext_info * new;
    5858       
    59         TRACE_ENTRY("%p(%s) %p(%s)", filename, filename?filename:"", conffile, conffile?conffile:"");
     59        TRACE_ENTRY("%p %p", filename, conffile);
    6060       
    6161        /* Check the filename is valid */
     
    106106                ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL);
    107107#else /* DEBUG */
    108                 /* We resolve immediatly so it's easier to find problems in ABI */
     108                /* We resolve symbols immediatly so it's easier to find problems in ABI */
    109109                ext->handler = dlopen(ext->filename, RTLD_NOW | RTLD_GLOBAL);
    110110#endif /* DEBUG */
  • libfdcore/fdcore-internal.h

    r662 r706  
    138138        char            *p_dbgorig;
    139139       
     140        /* State of the peer, and its lock */
     141        enum peer_state  p_state;
     142        pthread_mutex_t  p_state_mtx;
     143       
    140144        /* Chaining in peers sublists */
    141145        struct fd_list   p_actives;     /* list of peers in the STATE_OPEN state -- used by routing */
     
    147151                unsigned pf_responder   : 1;    /* The peer has been created to handle incoming connection */
    148152                unsigned pf_delete      : 1;    /* Destroy the peer when the connection is terminated */
     153                unsigned pf_localterm   : 1;    /* If the latest DPR/DPA was initiated from this side */
    149154               
    150155                unsigned pf_dw_pending  : 1;    /* A DWR message was sent and not answered yet */
     
    192197#define CHECK_PEER( _p ) \
    193198        (((_p) != NULL) && (((struct fd_peer *)(_p))->p_eyec == EYEC_PEER))
     199
     200#define fd_peer_getstate(peer)  fd_peer_get_state((struct peer_hdr *)(peer))
     201
    194202
    195203/* Events codespace for struct fd_peer->p_events */
     
    308316int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer);
    309317int fd_p_dp_initiate(struct fd_peer * peer, char * reason);
     318int fd_p_dp_newdelay(struct fd_peer * peer);
    310319
    311320/* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */
     
    327336struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
    328337int             fd_cnx_start_clear(struct cnxctx * conn, int loop);
    329 void            fd_cnx_sethostname(struct cnxctx * conn, char * hn);
     338void            fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn);
    330339int             fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds);
    331340char *          fd_cnx_getid(struct cnxctx * conn);
    332341int             fd_cnx_getproto(struct cnxctx * conn);
    333342int             fd_cnx_getTLS(struct cnxctx * conn);
     343int             fd_cnx_isMultichan(struct cnxctx * conn);
    334344int             fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
    335345int             fd_cnx_get_local_eps(struct fd_list * list);
     
    343353/* Flags for the fd_cnx_send function : */
    344354#define FD_CNX_ORDERED          (1 << 0)        /* All messages sent with this flag set will be delivered in the same order. No guarantee on other messages */
    345 #define FD_CNX_BROADCAST        (1 << 1)        /* The message is sent over all stream pairs, in case of SCTP. No effect on TCP */
    346355
    347356#endif /* _FDCORE_INTERNAL_H */
  • libfdcore/fdd.y

    r662 r706  
    236236appservthreads:         APPSERVTHREADS '=' INTEGER ';'
    237237                        {
    238                                 CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1024),
     238                                CHECK_PARAMS_DO( ($3 > 0) && ($3 < 256),
    239239                                        { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
    240240                                conf->cnf_dispthr = (uint16_t)$3;
  • libfdcore/messages.c

    r688 r706  
    3636#include "fdcore-internal.h"
    3737
     38static struct dict_object * dict_avp_SI  = NULL; /* Session-Id */
    3839static struct dict_object * dict_avp_OH  = NULL; /* Origin-Host */
    3940static struct dict_object * dict_avp_OR  = NULL; /* Origin-Realm */
     
    5455       
    5556        /* Initialize the dictionary objects that we may use frequently */
     57        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id",         &dict_avp_SI , ENOENT)  );
    5658        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host",        &dict_avp_OH  , ENOENT)  );
    5759        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm",       &dict_avp_OR  , ENOENT)  );
     
    8991        /* Set its value */
    9092        memset(&val, 0, sizeof(val));
    91         val.os.data = (unsigned char *)fd_g_config->cnf_diamid;
     93        val.os.data = (os0_t)fd_g_config->cnf_diamid;
    9294        val.os.len  = fd_g_config->cnf_diamid_len;
    9395        CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) );
     
    102104        /* Set its value */
    103105        memset(&val, 0, sizeof(val));
    104         val.os.data = (unsigned char *)fd_g_config->cnf_diamrlm;
     106        val.os.data = (os0_t)fd_g_config->cnf_diamrlm;
    105107        val.os.len  = fd_g_config->cnf_diamrlm_len;
    106108        CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) );
     
    124126        return 0;
    125127}
     128
     129/* Create a new Session-Id and add at the beginning of the message. */
     130int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen )
     131{
     132        union avp_value val;
     133        struct avp * avp  = NULL;
     134        struct session * sess = NULL;
     135        os0_t sid;
     136        size_t sidlen;
     137       
     138        TRACE_ENTRY("%p %p %zd", msg, opt, optlen);
     139        CHECK_PARAMS(  msg  );
     140       
     141        /* Check there is not already a session in the message */
     142        CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) );
     143        CHECK_PARAMS( sess == NULL );
     144       
     145        /* Ok, now create the session */
     146        CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) );
     147        CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) );
     148       
     149        /* Create an AVP to hold it */
     150        CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) );
     151       
     152        /* Set its value */
     153        memset(&val, 0, sizeof(val));
     154        val.os.data = sid;
     155        val.os.len  = sidlen;
     156        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
     157       
     158        /* Add it to the message */
     159        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) );
     160       
     161        /* Done! */
     162        return 0;
     163}
     164
    126165
    127166/* Add Result-Code and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */
     
    147186                memset(&req, 0, sizeof(struct dict_enumval_request));
    148187               
    149                 /* First, get the enumerated type of the Result-Code AVP */
     188                /* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */
    150189                CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT  )  );
    151190               
     
    184223                /* Set its value */
    185224                memset(&val, 0, sizeof(val));
    186                 val.os.data = (unsigned char *)fd_g_config->cnf_diamid;
     225                val.os.data = (uint8_t *)fd_g_config->cnf_diamid;
    187226                val.os.len  = fd_g_config->cnf_diamid_len;
    188227                CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) );
     
    246285               
    247286                if (errormsg) {
    248                         val.os.data = (unsigned char *)errormsg;
     287                        val.os.data = (uint8_t *)errormsg;
    249288                        val.os.len  = strlen(errormsg);
    250289                } else {
    251                         val.os.data = (unsigned char *)rescode;
     290                        val.os.data = (uint8_t *)rescode;
    252291                        val.os.len  = strlen(rescode);
    253292                }
     
    311350        if      ((ret != EBADMSG)       /* Parsing grouped AVP failed / Conflicting rule found */
    312351                && (ret != ENOTSUP))    /* Command is not supported / Mandatory AVP is not supported */
    313                 return ret;
     352                return ret; /* 0 or another error */
    314353       
    315354        TRACE_DEBUG(INFO, "A message does not comply to the dictionary and/or rules (%s)", pei.pei_errcode);
  • libfdcore/p_ce.c

    r688 r706  
    3838/* This file contains code to handle Capabilities Exchange messages (CER and CEA) and election process */
    3939
    40 /* Compilation option:
    41  USE_CEA_BROADCAST
    42         Define this to enable sending multiple copies of the CEA in case of SCTP connection.
    43         This avoids a race condition when sending an application message over a different stream
    44         than the CEA, it might be delivered first and thus ignored.
    45 */
    46 
    4740/* Save a connection as peer's principal */
    4841static int set_peer_cnx(struct fd_peer * peer, struct cnxctx **cnx)
     
    8881}
    8982
    90 /* Election: compare the Diameter Ids, return true if the election is won */
     83/* Election: compare the Diameter Ids by lexical order, return true if the election is won */
    9184static __inline__ int election_result(struct fd_peer * peer)
    9285{
     
    245238static void cleanup_remote_CE_info(struct fd_peer * peer)
    246239{
     240        /* free linked information */
    247241        free(peer->p_hdr.info.runtime.pir_realm);
    248         peer->p_hdr.info.runtime.pir_realm = NULL;
    249         peer->p_hdr.info.runtime.pir_vendorid = 0;
    250         peer->p_hdr.info.runtime.pir_orstate = 0;
    251242        free(peer->p_hdr.info.runtime.pir_prodname);
    252         peer->p_hdr.info.runtime.pir_prodname = NULL;
    253         peer->p_hdr.info.runtime.pir_firmrev = 0;
    254         peer->p_hdr.info.runtime.pir_relay = 0;
    255         peer->p_hdr.info.runtime.pir_isi = 0;
    256243        while (!FD_IS_LIST_EMPTY(&peer->p_hdr.info.runtime.pir_apps)) {
    257244                struct fd_list * li = peer->p_hdr.info.runtime.pir_apps.next;
     
    259246                free(li);
    260247        }
    261        
    262         fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_ADV /* Remove previously advertised endpoints */ );
     248        /* note: pir_cert_list needs not be freed (belongs to gnutls) */
     249       
     250        /* cleanup the area */
     251        memset(&peer->p_hdr.info.runtime, 0, sizeof(peer->p_hdr.info.runtime));
     252       
     253        /* reinit the list */
     254        fd_list_init(&peer->p_hdr.info.runtime.pir_apps, peer);
     255
     256        /* Remove previously advertised endpoints */
     257        fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_ADV );
    263258}
    264259
    265260/* Extract information sent by the remote peer and save it in our peer structure */
    266 static int save_remote_CE_info(struct msg * msg, struct fd_peer * peer, char ** error_code, uint32_t *rc)
     261static int save_remote_CE_info(struct msg * msg, struct fd_peer * peer, struct fd_pei * error, uint32_t *rc)
    267262{
    268263        struct avp * avp = NULL;
     
    309304                               
    310305                                /* We check that the value matches what we know, otherwise disconnect the peer */
    311                                 /* here also, using strcasecmp on (supposed) UTF8 data might be bad idea... to be improved */
    312                                 if (strncasecmp((char *)hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, hdr->avp_value->os.len)) {
     306                                if (fd_os_almostcasecmp(hdr->avp_value->os.data, hdr->avp_value->os.len,
     307                                                        peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen)) {
    313308                                        TRACE_DEBUG(INFO, "Received a message with Origin-Host set to '%.*s' while expecting '%s'\n",
    314309                                                        hdr->avp_value->os.len, hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid);
    315                                         *error_code = "DIAMETER_UNKNOWN_PEER";
     310                                        error->pei_errcode = "ER_DIAMETER_AVP_NOT_ALLOWED";
     311                                        error->pei_message = "Your Origin-Host value does not match my configuration.";
     312                                        error->pei_avp = avp;
    316313                                        return EINVAL;
    317314                                }
     
    330327                                /* In case of multiple AVPs */
    331328                                if (peer->p_hdr.info.runtime.pir_realm) {
    332                                         TRACE_DEBUG(INFO, "Ignored multiple instances of the Origin-Realm AVP");
    333                                         goto next;
    334                                 }
    335                                
    336                                 /* Save the value -- we don't change the case to avoid risking breaking UTF-8 with poor tolower() impls. */
    337                                 CHECK_MALLOC(  peer->p_hdr.info.runtime.pir_realm = calloc( hdr->avp_value->os.len + 1, 1 )  );
    338                                 memcpy(peer->p_hdr.info.runtime.pir_realm, hdr->avp_value->os.data, hdr->avp_value->os.len);
     329                                        TRACE_DEBUG(INFO, "Multiple instances of the Origin-Realm AVP");
     330                                        error->pei_errcode = "ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     331                                        error->pei_message = "I found several Origin-Realm AVPs";
     332                                        error->pei_avp = avp;
     333                                        return EINVAL;
     334                                }
     335                               
     336                                /* If the octet string contains a \0 */
     337                                if (!fd_os_is_valid_DiameterIdentity(hdr->avp_value->os.data, hdr->avp_value->os.len)) {
     338                                        error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE";
     339                                        error->pei_message = "Your Origin-Realm contains invalid characters.";
     340                                        error->pei_avp = avp;
     341                                        return EINVAL;
     342                                }
     343                               
     344                                /* Save the value */
     345                                CHECK_MALLOC(  peer->p_hdr.info.runtime.pir_realm = os0dup( hdr->avp_value->os.data, hdr->avp_value->os.len )  );
     346                                peer->p_hdr.info.runtime.pir_realmlen = hdr->avp_value->os.len;
    339347                                break;
    340348
     
    352360                                        /* Get the sockaddr value */
    353361                                        memset(&ss, 0, sizeof(ss));
    354                                         CHECK_FCT( fd_msg_avp_value_interpret( avp, &ss) );
     362                                        CHECK_FCT_DO( fd_msg_avp_value_interpret( avp, &ss),
     363                                                {
     364                                                        /* in case of error, assume the AVP value was wrong */
     365                                                        error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE";
     366                                                        error->pei_avp = avp;
     367                                                        return EINVAL;
     368                                                } );
    355369
    356370                                        /* Save this endpoint in the list as advertized */
     
    370384                                /* In case of multiple AVPs */
    371385                                if (peer->p_hdr.info.runtime.pir_vendorid) {
    372                                         TRACE_DEBUG(INFO, "Ignored multiple instances of the Vendor-Id AVP");
    373                                         goto next;
     386                                        TRACE_DEBUG(INFO, "Multiple instances of the Vendor-Id AVP");
     387                                        error->pei_errcode = "ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     388                                        error->pei_message = "I found several Vendor-Id AVPs";
     389                                        error->pei_avp = avp;
     390                                        return EINVAL;
    374391                                }
    375392                               
     
    388405                                /* In case of multiple AVPs */
    389406                                if (peer->p_hdr.info.runtime.pir_prodname) {
    390                                         TRACE_DEBUG(INFO, "Ignored multiple instances of the Product-Name AVP");
    391                                         goto next;
     407                                        TRACE_DEBUG(INFO, "Multiple instances of the Product-Name AVP");
     408                                        error->pei_errcode = "ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     409                                        error->pei_message = "I found several Product-Name AVPs";
     410                                        error->pei_avp = avp;
     411                                        return EINVAL;
    392412                                }
    393413
     
    407427                                /* In case of multiple AVPs */
    408428                                if (peer->p_hdr.info.runtime.pir_orstate) {
    409                                         TRACE_DEBUG(INFO, "Ignored multiple instances of the Origin-State-Id AVP");
    410                                         goto next;
     429                                        TRACE_DEBUG(INFO, "Multiple instances of the Origin-State-Id AVP");
     430                                        error->pei_errcode = "ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     431                                        error->pei_message = "I found several Origin-State-Id AVPs";
     432                                        error->pei_avp = avp;
     433                                        return EINVAL;
    411434                                }
    412435                               
     
    423446                                }
    424447                               
    425                                 TRACE_DEBUG(FULL, "'%s' supports a subset of vendor %d features.", peer->p_hdr.info.pi_diamid, hdr->avp_value->u32);
     448                                TRACE_DEBUG(FULL, "'%s' claims support for a subset of vendor %d features.", peer->p_hdr.info.pi_diamid, hdr->avp_value->u32);
     449                                /* not that it makes a difference for us...
     450                                 -- if an application actually needs this info, we could save it somewhere.
     451                                */
    426452                                break;
    427453
     
    477503                                                TRACE_DEBUG(FULL, "Invalid Vendor-Specific-Application-Id AVP received, ignored");
    478504                                                fd_msg_dump_one(FULL, avp);
     505                                                error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE";
     506                                                error->pei_avp = avp;
     507                                                return EINVAL;
    479508                                        } else {
    480509                                                /* Add an entry in the list */
     
    510539                               
    511540                                if (hdr->avp_value->u32 == AI_RELAY) {
     541                                        /* Not clear if the relay application can be inside this AVP... */
    512542                                        peer->p_hdr.info.runtime.pir_relay = 1;
    513543                                } else {
    514                                         /* Not clear if the relay application can be inside this AVP... */
    515544                                        CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, hdr->avp_value->u32, 0, 0, 1) );
    516545                                }
     
    537566                                        goto next;
    538567                                }
    539                                 ASSERT( hdr->avp_value->u32 < 32 ); /* if false, we have to change the code bellow */
     568                                if (hdr->avp_value->u32 >= 32 ) {
     569                                        error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE";
     570                                        error->pei_message = "I don't support this Inband-Security-Id value (yet).";
     571                                        error->pei_avp = avp;
     572                                        return EINVAL;
     573                                }
    540574                                peer->p_hdr.info.runtime.pir_isi |= (1 << hdr->avp_value->u32);
    541575                                break;
     
    559593        CHECK_FCT( fd_msg_new ( fd_dict_cmd_CER, MSGFL_ALLOC_ETEID, cer ) );
    560594       
    561         /* Do we need Inband-Security-Id AVPs ? */
     595        /* Do we need Inband-Security-Id AVPs ? If we're already using TLS, we don't... */
    562596        if (!fd_cnx_getTLS(cnx)) {
    563                 isi_none = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE; /* we add it event if the peer does not use the old mechanism */
     597                isi_none = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE; /* we add it even if the peer does not use the old mechanism, it is impossible to distinguish */
    564598                isi_tls  = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD;
    565599        }
     
    587621
    588622/* Reject an incoming connection attempt */
    589 static void receiver_reject(struct cnxctx * recv_cnx, struct msg ** cer, char * rescode, char * errormsg)
     623static void receiver_reject(struct cnxctx ** recv_cnx, struct msg ** cer, struct fd_pei * error)
    590624{
    591625        /* Create and send the CEA with appropriate error code */
    592626        CHECK_FCT_DO( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ), goto destroy );
    593         CHECK_FCT_DO( fd_msg_rescode_set(*cer, rescode, errormsg, NULL, 1 ), goto destroy );
    594         CHECK_FCT_DO( fd_out_send(cer, recv_cnx, NULL, FD_CNX_ORDERED), goto destroy );
     627        CHECK_FCT_DO( fd_msg_rescode_set(*cer, error->pei_errcode, error->pei_message, error->pei_avp, 1 ), goto destroy );
     628        CHECK_FCT_DO( fd_out_send(cer, *recv_cnx, NULL, FD_CNX_ORDERED), goto destroy );
    595629       
    596630        /* And now destroy this connection */
    597631destroy:
    598         fd_cnx_destroy(recv_cnx);
     632        fd_cnx_destroy(*recv_cnx);
     633        *recv_cnx = NULL;
    599634        if (*cer) {
    600635                fd_msg_log(FD_MSG_LOG_DROPPED, *cer, "An error occurred while rejecting a CER.");
     
    614649       
    615650        /* Are we doing an election ? */
    616         fd_cpu_flush_cache();
    617         if (peer->p_hdr.info.runtime.pir_state == STATE_WAITCNXACK_ELEC) {
     651        if (fd_peer_getstate(peer) == STATE_WAITCNXACK_ELEC) {
    618652                if (election_result(peer)) {
    619653                        /* Close initiator connection */
     
    624658
    625659                } else {
     660                        struct fd_pei pei;
     661                        memset(&pei, 0, sizeof(pei));
     662                        pei.pei_errcode = "ELECTION_LOST";
    626663
    627664                        /* Answer an ELECTION LOST to the receiver side */
    628                         receiver_reject(peer->p_receiver, &peer->p_cer, "ELECTION_LOST", NULL);
    629                         peer->p_receiver = NULL;
     665                        receiver_reject(&peer->p_receiver, &peer->p_cer, &pei);
    630666                        CHECK_FCT( to_waitcea(peer, initiator) );
    631667                }
     
    641677int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer)
    642678{
    643         char * ec;
    644679        uint32_t rc = 0;
     680        int st;
     681        struct fd_pei pei;
     682       
    645683        TRACE_ENTRY("%p %p", msg, peer);
    646684        CHECK_PARAMS( msg && *msg && CHECK_PEER(peer) );
     
    656694               
    657695                /* Set the error code */
    658                 CHECK_FCT( fd_msg_rescode_set(*msg, "DIAMETER_COMMAND_UNSUPPORTED", "No CER allowed in current state", NULL, 1 ) );
     696                CHECK_FCT( fd_msg_rescode_set(*msg, "ER_DIAMETER_UNABLE_TO_COMPLY", "No CER allowed in current state", NULL, 1 ) );
    659697
    660698                /* msg now contains an answer message to send back */
     
    663701       
    664702        /* If the state is not WAITCEA, just discard the message */
    665         fd_cpu_flush_cache();
    666         if (req || (peer->p_hdr.info.runtime.pir_state != STATE_WAITCEA)) {
     703        if (req || ((st = fd_peer_getstate(peer)) != STATE_WAITCEA)) {
    667704                if (*msg) {
    668                         fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Received CER/CEA while in '%s' state.\n", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     705                        fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Received CER/CEA while in '%s' state.\n", STATE_STR(st));
    669706                        CHECK_FCT_DO( fd_msg_free(*msg), /* continue */);
    670707                        *msg = NULL;
     
    674711        }
    675712       
     713        memset(&pei, 0, sizeof(pei));
     714       
    676715        /* Save info from the CEA into the peer */
    677         CHECK_FCT_DO( save_remote_CE_info(*msg, peer, &ec, &rc), goto cleanup );
     716        CHECK_FCT_DO( save_remote_CE_info(*msg, peer, &pei, &rc), goto cleanup );
    678717       
    679718        /* Dispose of the message, we don't need it anymore */
     
    701740                default:
    702741                        /* In any other case, we abort all attempts to connect to this peer */
    703                         TRACE_DEBUG(INFO, "Peer %s replied a CEA with Result-Code AVP %d, aborting connection attempts.", peer->p_hdr.info.pi_diamid, rc);
     742                        TRACE_DEBUG(INFO, "Peer %s replied a CEA with Result-Code %d, aborting connection attempts.", peer->p_hdr.info.pi_diamid, rc);
    704743                        return EINVAL;
    705744        }
     
    751790}
    752791
    753 /* Handle the receiver side to go to OPEN state (any election is resolved) */
     792/* Handle the receiver side to go to OPEN or OPEN_NEW state (any election is resolved) */
    754793int fd_p_ce_process_receiver(struct fd_peer * peer)
    755794{
    756         char * ec = NULL;
     795        struct fd_pei pei;
    757796        struct msg * msg = NULL;
    758797        int isi = 0;
    759798        int fatal = 0;
     799        int tls_sync=0;
    760800       
    761801        TRACE_ENTRY("%p", peer);
     
    765805        peer->p_cer = NULL;
    766806       
     807        memset(&pei, 0, sizeof(pei));
     808       
    767809        /* Parse the content of the received CER */
    768         CHECK_FCT_DO( save_remote_CE_info(msg, peer, &ec, NULL), goto error_abort );
     810        CHECK_FCT_DO( save_remote_CE_info(msg, peer, &pei, NULL), goto error_abort );
     811       
     812        /* Validate the realm if needed */
     813        if (peer->p_hdr.info.config.pic_realm) {
     814                size_t len = strlen(peer->p_hdr.info.config.pic_realm);
     815                if (fd_os_almostcasecmp(peer->p_hdr.info.config.pic_realm, len, peer->p_hdr.info.runtime.pir_realm, peer->p_hdr.info.runtime.pir_realmlen)) {
     816                        TRACE_DEBUG(INFO, "Rejected CER from peer '%s', realm mismatch with configured value (returning DIAMETER_UNKNOWN_PEER).\n", peer->p_hdr.info.pi_diamid);
     817                        pei.pei_errcode = "DIAMETER_UNKNOWN_PEER"; /* maybe AVP_NOT_ALLOWED would be better fit? */
     818                        goto error_abort;
     819                }
     820        }
    769821       
    770822        /* Validate the peer if needed */
     
    773825                if (res < 0) {
    774826                        TRACE_DEBUG(INFO, "Rejected CER from peer '%s', validation failed (returning DIAMETER_UNKNOWN_PEER).\n", peer->p_hdr.info.pi_diamid);
    775                         ec = "DIAMETER_UNKNOWN_PEER";
     827                        pei.pei_errcode = "DIAMETER_UNKNOWN_PEER";
    776828                        goto error_abort;
    777829                }
     
    785837                if (!got_common) {
    786838                        TRACE_DEBUG(INFO, "No common application with peer '%s', sending DIAMETER_NO_COMMON_APPLICATION", peer->p_hdr.info.pi_diamid);
    787                         ec = "DIAMETER_NO_COMMON_APPLICATION";
     839                        pei.pei_errcode = "DIAMETER_NO_COMMON_APPLICATION";
    788840                        fatal = 1;
    789841                        goto error_abort;
     
    835887                if (!isi) {
    836888                        TRACE_DEBUG(INFO, "No common security mechanism with '%s', sending DIAMETER_NO_COMMON_SECURITY", peer->p_hdr.info.pi_diamid);
    837                         ec = "DIAMETER_NO_COMMON_SECURITY";
     889                        pei.pei_errcode = "DIAMETER_NO_COMMON_SECURITY";
    838890                        fatal = 1;
    839891                        goto error_abort;
     
    849901        CHECK_FCT( fd_msg_rescode_set(msg, "DIAMETER_SUCCESS", NULL, NULL, 0 ) );
    850902        CHECK_FCT( add_CE_info(msg, peer->p_cnxctx, isi & PI_SEC_TLS_OLD, isi & PI_SEC_NONE) );
    851 #ifdef USE_CEA_BROADCAST
    852         CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer, (isi & PI_SEC_TLS_OLD) ? FD_CNX_ORDERED : FD_CNX_BROADCAST) ); /* Broadcast in order to avoid further messages sent over a different stream be delivered first... */
    853 #else /* USE_CEA_BROADCAST */
    854903        CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED ) );
    855 #endif /* USE_CEA_BROADCAST */
    856904       
    857905        /* Handshake if needed */
     
    878926                                }  );
    879927                }
    880                
     928                tls_sync = 1;
    881929        } else {
    882930                if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
     
    891939                CHECK_FCT( fd_p_dw_reopen(peer) );
    892940        } else {
    893                 fd_psm_change_state(peer, STATE_OPEN );
    894                 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
     941                if ((!tls_sync) && (fd_cnx_isMultichan(peer->p_cnxctx))) {
     942                        fd_psm_change_state(peer, STATE_OPEN_NEW );
     943                        /* send DWR */
     944                        CHECK_FCT( fd_p_dw_timeout(peer) );
     945                } else {
     946
     947                        fd_psm_change_state(peer, STATE_OPEN );
     948                        fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
     949                }
    895950        }
    896951       
     
    898953
    899954error_abort:
    900         if (ec) {
    901                 /* Create the error message */
    902                 CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, MSGFL_ANSW_ERROR ) );
    903 
    904                 /* Set the error code */
    905                 CHECK_FCT( fd_msg_rescode_set(msg, ec, NULL, NULL, 1 ) );
    906 
    907                 /* msg now contains an answer message to send back */
    908                 CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED), /* In case of error the message has already been dumped */ );
     955        if (pei.pei_errcode) {
     956                /* Send the error */
     957                receiver_reject(&peer->p_cnxctx, &msg, &pei);
    909958        }
    910959       
     
    925974int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid)
    926975{
    927         fd_cpu_flush_cache();
    928         switch (peer->p_hdr.info.runtime.pir_state) {
     976        struct fd_pei pei;
     977        int cur_state = fd_peer_getstate(peer);
     978        memset(&pei, 0, sizeof(pei));
     979       
     980        switch (cur_state) {
    929981                case STATE_CLOSED:
    930982                        peer->p_receiver = *cnx;
     
    9601012
    9611013                                /* Answer an ELECTION LOST to the receiver side and continue */
    962                                 receiver_reject(*cnx, msg, "ELECTION_LOST", "Please answer my CER instead, you won the election.");
    963                                 *cnx = NULL;
     1014                                pei.pei_errcode = "ELECTION_LOST";
     1015                                pei.pei_message = "Please answer my CER instead, you won the election.";
     1016                                receiver_reject(cnx, msg, &pei);
    9641017                        }
    9651018                        break;
    9661019
    9671020                default:
    968                         receiver_reject(*cnx, msg, "DIAMETER_UNABLE_TO_COMPLY", "Invalid state to receive a new connection attempt");
    969                         *cnx = NULL;
     1021                        pei.pei_errcode = "DIAMETER_UNABLE_TO_COMPLY"; /* INVALID COMMAND? in case of Capabilities-Updates? */
     1022                        pei.pei_message = "Invalid state to receive a new connection attempt.";
     1023                        receiver_reject(cnx, msg, &pei);
    9701024        }
    9711025                               
  • libfdcore/p_cnx.c

    r691 r706  
    3636#include "fdcore-internal.h"
    3737
     38
     39/* TODO: change the behavior to handle properly forced ordering at beginning & end of OPEN state */
     40
    3841/* This file contains code used by a peer state machine to initiate a connection to remote peer */
    3942
     
    8790                ret = getaddrinfo(peer->p_hdr.info.pi_diamid, NULL, &hints, &ai);
    8891                if (ret) {
    89                         fd_log_debug("Unable to resolve address for peer '%s' (%s), aborting\n", peer->p_hdr.info.pi_diamid, gai_strerror(ret));
     92                        TRACE_DEBUG(INFO, "Unable to resolve address for peer '%s' (%s), aborting\n", peer->p_hdr.info.pi_diamid, gai_strerror(ret));
    9093                        if (ret != EAI_AGAIN)
    9194                                fd_psm_terminate( peer, NULL );
     
    123126        /* Now check we have at least one address to attempt */
    124127        if (FD_IS_LIST_EMPTY(&peer->p_hdr.info.pi_endpoints)) {
    125                 fd_log_debug("No address %savailable to connect to peer '%s', aborting\n", peer->p_hdr.info.config.pic_flags.pro3 ? "in the configured family " : "", peer->p_hdr.info.pi_diamid);
     128                TRACE_DEBUG(INFO, "No address %savailable to connect to peer '%s', aborting\n",
     129                                        peer->p_hdr.info.config.pic_flags.pro3 ? "in the configured family " : "", peer->p_hdr.info.pi_diamid);
    126130                fd_psm_terminate( peer, NULL );
    127131                return 0;
     
    219223        {
    220224                char buf[48];
    221                 sprintf(buf, "ConnTo:%.*s", (int)(sizeof(buf)) - 8, peer->p_hdr.info.pi_diamid);
     225                snprintf(buf, sizeof(buf), "ConnTo:%s", peer->p_hdr.info.pi_diamid);
    222226                fd_log_threadname ( buf );
    223227        }
     
    247251#ifndef DISABLE_SCTP                   
    248252                        case IPPROTO_SCTP:
    249                                 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);
     253                                cnx = fd_cnx_cli_connect_sctp((peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ?: fd_g_config->cnf_flags.no_ip6,
     254                                                        nc->port, &peer->p_hdr.info.pi_endpoints);
    250255                                break;
    251256#endif /* DISABLE_SCTP */
     
    260265                pthread_testcancel();
    261266               
    262         } while (!cnx); /* and until cancellation */
     267        } while (!cnx); /* and until cancellation or all addresses attempted without success */
    263268       
    264269        /* Now, we have an established connection in cnx */
     
    274279                        {
    275280                                /* Handshake failed ...  */
    276                                 fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
     281                                TRACE_DEBUG(INFO, "TLS Handshake failed with peer '%s', resetting the connection\n", peer->p_hdr.info.pi_diamid);
    277282                                fd_cnx_destroy(cnx);
    278283                                empty_connection_list(peer);
  • libfdcore/p_dp.c

    r662 r706  
    3838/* This file contains code to handle Disconnect Peer messages (DPR and DPA) */
    3939
     40/* Delay to use before next reconnect attempt */
     41int fd_p_dp_newdelay(struct fd_peer * peer)
     42{
     43        int delay = peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc;
     44       
     45        switch (peer->p_hdr.info.runtime.pir_lastDC) {
     46                case ACV_DC_REBOOTING:
     47                default:
     48                        /* We use TcTimer to attempt reconnection */
     49                        break;
     50                case ACV_DC_BUSY:
     51                        /* No need to hammer the overloaded peer */
     52                        delay *= 10;
     53                        break;
     54                case ACV_DC_NOT_FRIEND:
     55                        /* He does not want to speak to us... let's retry a *lot* later maybe */
     56                        delay *= 200;
     57                        break;
     58        }
     59        return delay;
     60}
     61
    4062/* Handle a received message */
    4163int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer)
     
    4466       
    4567        if (req) {
    46                 /* We received a DPR, save the Disconnect-Cause and terminate the connection */
     68                /* We received a DPR, save the Disconnect-Cause and go to CLOSING_GRACE or terminate the connection */
    4769                struct avp * dc;
    48                 int delay = peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc;
    4970               
    5071                CHECK_FCT( fd_msg_search_avp ( *msg, fd_dict_avp_DC, &dc ));
    5172                if (dc) {
    52                         /* Check the value is consistent with the saved one */
    5373                        struct avp_hdr * hdr;
    5474                        CHECK_FCT(  fd_msg_avp_hdr( dc, &hdr )  );
     
    6080                        }
    6181
     82                        /* save the cause */
    6283                        peer->p_hdr.info.runtime.pir_lastDC = hdr->avp_value->u32;
    63                        
    64                         switch (hdr->avp_value->u32) {
    65                                 case ACV_DC_REBOOTING:
    66                                 default:
    67                                         /* We use TcTimer to attempt reconnection */
    68                                         break;
    69                                 case ACV_DC_BUSY:
    70                                         /* No need to hammer the overloaded peer */
    71                                         delay *= 10;
    72                                         break;
    73                                 case ACV_DC_NOT_FRIEND:
    74                                         /* He does not want to speak to us... let's retry a lot later maybe */
    75                                         delay *= 200;
    76                                         break;
    77                         }
    7884                }
    7985                if (TRACE_BOOL(INFO)) {
    8086                        if (dc) {
    81                                 struct dict_object * dictobj = NULL;
     87                                struct dict_object * dictobj;
    8288                                struct dict_enumval_request er;
    8389                                memset(&er, 0, sizeof(er));
     90                               
     91                                /* prepare the request */
    8492                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT )  );
    8593                                er.search.enum_value.u32 = peer->p_hdr.info.runtime.pir_lastDC;
     94                               
     95                                /* Search the enum value */
    8696                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, 0 )  );
    8797                                if (dictobj) {
     
    100110                CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_SUCCESS", NULL, NULL, 1 ) );
    101111               
    102                 /* Move to CLOSING state to failover outgoing messages (and avoid failing the DPA...) */
     112                /* Move to CLOSING state to failover outgoing messages (and avoid failing over the DPA...) */
    103113                CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) );
    104114               
     
    106116                CHECK_FCT( fd_out_send( msg, NULL, peer, FD_CNX_ORDERED) );
    107117               
    108                 /* Move to CLOSED state */
    109                 fd_psm_cleanup(peer, 0);
    110                
    111                 /* Reset the timer for next connection attempt -- we'll retry sooner or later depending on the disconnection cause */
    112                 fd_psm_next_timeout(peer, 1, delay);
    113                
     118                if (fd_cnx_isMultichan(peer->p_cnxctx)) {
     119                        /* There is a possibililty that messages are still in the pipe coming here, so let's grace for 1 second */
     120                        CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING_GRACE) );
     121                        fd_psm_next_timeout(peer, 0, 1);
     122                       
     123                } else {
     124                        /* Move to CLOSED state */
     125                        fd_psm_cleanup(peer, 0);
     126
     127                        /* Reset the timer for next connection attempt -- we'll retry sooner or later depending on the disconnection cause */
     128                        fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
     129                }
    114130        } else {
    115131                /* We received a DPA */
    116                 fd_cpu_flush_cache();
    117                 if (peer->p_hdr.info.runtime.pir_state != STATE_CLOSING) {
    118                         TRACE_DEBUG(INFO, "Ignoring DPA received in state %s", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     132                int curstate = fd_peer_getstate(peer);
     133                if (curstate != STATE_CLOSING) {
     134                        TRACE_DEBUG(INFO, "Ignoring DPA received in state %s", STATE_STR(curstate));
    119135                }
    120136                       
    121137                /* In theory, we should control the Result-Code AVP. But since we will not go back to OPEN state here anyway, let's skip it */
     138               
     139                /* TODO("Control Result-Code in the DPA") */
    122140                CHECK_FCT_DO( fd_msg_free( *msg ), /* continue */ );
    123141                *msg = NULL;
    124142               
    125                 /* The calling function handles cleaning the PSM and terminating the peer since we return in CLOSING state */
     143                if (fd_cnx_isMultichan(peer->p_cnxctx)) {
     144                        CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING_GRACE) );
     145                        fd_psm_next_timeout(peer, 0, 1);
     146                        peer->p_flags.pf_localterm = 1;
     147                }
     148                /* otherwise, return in CLOSING state, the psm will handle it */
    126149        }
    127150       
     
    153176        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT )  );
    154177        er.search.enum_name = reason ?: "REBOOTING";
    155         CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, ENOENT )  );
     178        CHECK_FCT_DO( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, ENOENT ), { ASSERT(0); /* internal error: unknown reason */ }  );
    156179        CHECK_FCT( fd_dict_getval( dictobj, &er.search ) );
    157180       
  • libfdcore/p_dw.c

    r662 r706  
    3838/* This file contains code to handle Device Watchdog messages (DWR and DWA) */
    3939
    40 /* Check the value of Origin-State-Id is consistent in a DWR or  DWA -- we just log if it is not the case */
    41 static void check_state_id(struct msg * msg, struct fd_peer * peer)
     40/* Check the value of Origin-State-Id is consistent in a DWR or DWA -- we return an error otherwise */
     41static int check_state_id(struct msg * msg, struct fd_peer * peer)
    4242{
    4343        struct avp * osi;
     44       
    4445        /* Check if the request contains the Origin-State-Id */
    45         CHECK_FCT_DO( fd_msg_search_avp ( msg, fd_dict_avp_OSI, &osi ), return );
     46        CHECK_FCT( fd_msg_search_avp ( msg, fd_dict_avp_OSI, &osi ) );
    4647        if (osi) {
    4748                /* Check the value is consistent with the saved one */
    4849                struct avp_hdr * hdr;
    49                 CHECK_FCT_DO(  fd_msg_avp_hdr( osi, &hdr ), return  );
     50                CHECK_FCT(  fd_msg_avp_hdr( osi, &hdr )  );
    5051                if (hdr->avp_value == NULL) {
    5152                        /* This is a sanity check */
     
    5657
    5758                if (peer->p_hdr.info.runtime.pir_orstate != hdr->avp_value->u32) {
    58                         fd_log_debug("Received a new Origin-State-Id from peer %s! (%x / %x)\n",
     59                        TRACE_DEBUG(INFO, "Received a new Origin-State-Id from peer '%s'! (%x -> %x); resetting the connection.\n",
    5960                                peer->p_hdr.info.pi_diamid,
    60                                 hdr->avp_value->u32,
    61                                 peer->p_hdr.info.runtime.pir_orstate );
     61                                peer->p_hdr.info.runtime.pir_orstate,
     62                                hdr->avp_value->u32 );
     63                        return EINVAL;
    6264                }
    6365        }
     66        return 0;
    6467}
    6568
     
    9295       
    9396        /* Check the value of OSI for information */
    94         check_state_id(*msg, peer);
     97        CHECK_FCT( check_state_id(*msg, peer) );
    9598       
    9699        if (req) {
     
    102105               
    103106        } else {
    104                 /* Just discard the DWA */
     107                /* Discard the DWA */
    105108                CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ );
    106109                *msg = NULL;
     
    123126       
    124127        /* If we are in REOPEN state, increment the counter */
    125         fd_cpu_flush_cache();
    126         if (peer->p_hdr.info.runtime.pir_state == STATE_REOPEN) {
     128        if (fd_peer_getstate(peer) == STATE_REOPEN) {
    127129                peer->p_flags.pf_reopen_cnt += 1;
    128130               
  • libfdcore/p_expiry.c

    r691 r706  
    5959               
    6060                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    61                         struct fd_peer * peer = (struct fd_peer *)li;
    62                        
    63                         fd_cpu_flush_cache();
    64                         if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE)
     61                        struct fd_peer * peer = (struct fd_peer *)li->o;
     62                       
     63                        if (fd_peer_getstate(peer) != STATE_ZOMBIE)
    6564                                continue;
    6665                       
     
    7877                /* Now delete peers that are in the purge list */
    7978                while (!FD_IS_LIST_EMPTY(&purge)) {
    80                         struct fd_peer * peer = (struct fd_peer *)(purge.next);
     79                        struct fd_peer * peer = (struct fd_peer *)(purge.next->o);
    8180                        fd_list_unlink(&peer->p_hdr.chain);
    8281                        TRACE_DEBUG(INFO, "Garbage Collect: delete zombie peer '%s'", peer->p_hdr.info.pi_diamid);
     
    105104                struct fd_peer * first;
    106105               
    107                 /* Check if there are expiring sessions available */
     106                /* Check if there are expiring peers available */
    108107                if (FD_IS_LIST_EMPTY(&exp_list)) {
    109108                        /* Just wait for a change or cancelation */
     
    183182               
    184183                /* update the p_exp_timer value */
    185                 CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &peer->p_exp_timer)  );
     184                CHECK_SYS_DO(  clock_gettime(CLOCK_REALTIME, &peer->p_exp_timer), { ASSERT(0); }  );
    186185                peer->p_exp_timer.tv_sec += peer->p_hdr.info.config.pic_lft;
    187186               
  • libfdcore/p_out.c

    r691 r706  
    109109        {
    110110                char buf[48];
    111                 sprintf(buf, "OUT/%.*s", (int)sizeof(buf) - 5, peer->p_hdr.info.pi_diamid);
     111                snprintf(buf, sizeof(buf), "OUT/%s", peer->p_hdr.info.pi_diamid);
    112112                fd_log_threadname ( buf );
    113113        }
     
    149149        CHECK_PARAMS( msg && *msg && (cnx || (peer && peer->p_cnxctx)));
    150150       
    151         fd_cpu_flush_cache();
    152         if (peer && (peer->p_hdr.info.runtime.pir_state == STATE_OPEN)) {
     151        if (fd_peer_getstate(peer) == STATE_OPEN) {
    153152                /* Normal case: just queue for the out thread to pick it up */
    154153                CHECK_FCT( fd_fifo_post(peer->p_tosend, msg) );
  • libfdcore/p_psm.c

    r691 r706  
    3636#include "fdcore-internal.h"
    3737
     38/*
     39This file implement a Peer State Machine which is a mix of:
     40 - the state machine described in rfc3588bis
     41 - the state machine described in rfc3539#section-3.4
     42 - the following observations.
     43 
     44The delivery of Diameter messages must not always be unordered: order is important at
     45begining and end of a connection lifetime. It means we need agility to
     46switch between "ordering enforced" and "ordering not enforced to counter
     47HotLB" modes of operation.
     48
     49The connection state machine represented in RFC3588 (and rfc3588bis) is
     50incomplete, because it lacks the SUSPECT state and the 3 DWR/DWA
     51exchanges (section 5.1) when the peer recovers from this state.
     52Personnally I don't see the rationale for exchanging 3 messages (why 3?)
     53but, if we require at least 1 DWR/DWA exchange to be always performed
     54after the CER/CEA exchange (and initiated by the peer that sent the
     55CEA), we have a simple way to deal with our ordering problem, as resumed
     56bellow. Peers are: [i]nitiator, [r]esponder.
     57 (1) [i] SCTP connection attempt.
     58 (2) [r] accept the connection.
     59 (3) [i,r] (if secure port) DTLS handshake, close on failure.
     60 (4) [i] Send CER
     61 (5) [r] Receive CER, send CEA using stream 0, flag "unordered" cleared.
     62       [r] Immediately send a DWR after the CEA, also using stream 0,
     63flag "unordered" cleared.
     64       [r] Move to STATE_OPEN_NEW state -- equivalent to OPEN except
     65that all messages are sent ordered at the moment.
     66 (6) [i] receive CEA, move to OPEN state. All messages can be sent
     67unordered in OPEN state.
     68       [i] As per normal operation, reply with DWA to the DWR.
     69 (7) [r] Upon reception of the DWA, move to OPEN state, messages can be
     70sent unordered from this point.
     71
     72Note about (5) and (6): if the Diameter Identity received in CER or CEA
     73does not match the credentials from the certificate presented during
     74DTLS handshake, we may need to specify a path of clean disconnection
     75(not blocking the remote peer waiting for something).
     76
     77This proposed mechanism removes the problem of application messages
     78received before the CEA by the initiator. Note that if the "old" inband
     79TLS handshake is used, this handshake plays the same synchronization
     80role than the new DWR/DWA, which becomes useless.
     81
     82
     83The other time where ordering is important is by the end of connection
     84lifetime, when one peer is shutting down the link for some reason
     85(reboot, overload, no activity, etc...). In case of unordered delivery,
     86we may have:
     87- peer A sends an application message followed by a DPR. Peer B receives
     88the DPR first and tears down the connection. Application message is lost.
     89- Peer B sends an application message, then receives a DPR and answers a
     90DPA. Peer A receives the DPA before the application message. The
     91application message is lost.
     92
     93This situation is actually quite possible because DPR/DPA messages are
     94very short, while application messages can be quite large. Therefore,
     95they require much more time to deliver.
     96
     97I really cannot see a way to counter this effect by using the ordering
     98of the messages, except by applying a timer (state STATE_CLOSING_GRACE).
     99
     100However, this problem must be balanced with the fact that the message
     101that is lost will be in many cases sent again as the failover mechanism
     102specifies.
     103*/
     104
    38105/* The actual declaration of peer_state_str */
    39106DECLARE_STATE_STR();
     
    101168                return 0;
    102169        }
     170       
    103171        /* Insert in the active peers list */
    104172        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) );
    105173        for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) {
    106174                struct fd_peer * next_p = (struct fd_peer *)li->o;
    107                 int cmp = strcmp(peer->p_hdr.info.pi_diamid, next_p->p_hdr.info.pi_diamid);
     175                int cmp = fd_os_cmp(peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen,
     176                                        next_p->p_hdr.info.pi_diamid, next_p->p_hdr.info.pi_diamidlen);
    108177                if (cmp < 0)
    109178                        break;
     
    115184        if (peer->p_cb) {
    116185                TRACE_DEBUG(FULL, "Calling add callback for peer %s", peer->p_hdr.info.pi_diamid);
    117                 (*peer->p_cb)(&peer->p_hdr.info, peer->p_cb_data);
     186                (*peer->p_cb)(&peer->p_hdr.info, peer->p_cb_data); /* TODO: do this in a separate detached thread? */
    118187                peer->p_cb = NULL;
    119188                peer->p_cb_data = NULL;
     
    178247}
    179248
     249/* Read state */
     250int fd_peer_get_state(struct peer_hdr *peer)
     251{
     252        int ret;
     253       
     254        struct fd_peer * p = (struct fd_peer *)peer;
     255       
     256        if (!CHECK_PEER(p))
     257                return -1;
     258       
     259        CHECK_POSIX_DO( pthread_mutex_lock(&p->p_state_mtx), return -1 );
     260        ret = p->p_state;
     261        CHECK_POSIX_DO( pthread_mutex_unlock(&p->p_state_mtx), return -1 );
     262       
     263        return ret;
     264}
     265
    180266
    181267/* Change state */
     
    186272        TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state));
    187273        CHECK_PARAMS( CHECK_PEER(peer) );
    188         fd_cpu_flush_cache();
    189         old = peer->p_hdr.info.runtime.pir_state;
     274       
     275        old = fd_peer_getstate(peer);
    190276        if (old == new_state)
    191277                return 0;
     
    196282                        peer->p_hdr.info.pi_diamid);
    197283       
    198         peer->p_hdr.info.runtime.pir_state = new_state;
    199         fd_cpu_flush_cache();
     284       
     285        CHECK_POSIX( pthread_mutex_lock(&peer->p_state_mtx) );
     286        peer->p_state = new_state;
     287        CHECK_POSIX( pthread_mutex_unlock(&peer->p_state_mtx) );
    200288       
    201289        if (old == STATE_OPEN) {
     
    255343{
    256344        /* Move to CLOSED state: failover messages, stop OUT thread, unlink peer from active list */
    257         fd_cpu_flush_cache();
    258         if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
     345        if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
    259346                CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ );
    260347        }
     
    285372        struct fd_peer * peer = (struct fd_peer *)arg;
    286373        CHECK_PARAMS_DO( CHECK_PEER(peer), return );
    287         peer->p_hdr.info.runtime.pir_state = STATE_ZOMBIE;
    288         fd_cpu_flush_cache();
     374        CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), );
     375        peer->p_state = STATE_ZOMBIE;
     376        CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), );
    289377        return;
    290378}
     
    298386        size_t ev_sz;
    299387        void * ev_data;
     388        int cur_state;
    300389       
    301390        CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) );
     
    306395        {
    307396                char buf[48];
    308                 sprintf(buf, "PSM/%.*s", (int)sizeof(buf) - 5, peer->p_hdr.info.pi_diamid);
     397                snprintf(buf, sizeof(buf), "PSM/%s", peer->p_hdr.info.pi_diamid);
    309398                fd_log_threadname ( buf );
    310399        }
    311400       
    312401        /* The state machine starts in CLOSED state */
    313         peer->p_hdr.info.runtime.pir_state = STATE_CLOSED;
     402        CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), goto psm_end );
     403        peer->p_state = STATE_CLOSED;
     404        CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), goto psm_end );
    314405
    315406        /* Wait that the PSM are authorized to start in the daemon */
     
    326417        /* Get next event */
    327418        TRACE_DEBUG(FULL, "'%s' in state '%s' waiting for next event.",
    328                         peer->p_hdr.info.pi_diamid, STATE_STR(peer->p_hdr.info.runtime.pir_state));
     419                        peer->p_hdr.info.pi_diamid, STATE_STR(fd_peer_getstate(peer)));
    329420        CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
     421       
     422        cur_state = fd_peer_getstate(peer);
     423        if (cur_state == -1)
     424                goto psm_end;
     425       
    330426        TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'",
    331                         STATE_STR(peer->p_hdr.info.runtime.pir_state),
     427                        STATE_STR(cur_state),
    332428                        fd_pev_str(event), ev_data, ev_sz,
    333429                        peer->p_hdr.info.pi_diamid);
     
    336432
    337433        /* The following states are impossible */
    338         ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_NEW );
    339         ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE );
    340         ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_OPEN_HANDSHAKE ); /* because it should exist only between two loops */
     434        ASSERT( cur_state != STATE_NEW );
     435        ASSERT( cur_state != STATE_ZOMBIE );
     436        ASSERT( cur_state != STATE_OPEN_HANDSHAKE ); /* because it should exist only between two loops */
    341437
    342438        /* Purge invalid events */
    343439        if (!CHECK_PEVENT(event)) {
    344440                TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event);
     441                ASSERT(0); /* we should investigate this situation */
    345442                goto psm_loop;
    346443        }
     
    354451        /* Requests to terminate the peer object */
    355452        if (event == FDEVP_TERMINATE) {
    356                 switch (peer->p_hdr.info.runtime.pir_state) {
     453                switch (cur_state) {
    357454                        case STATE_OPEN:
     455                        case STATE_OPEN_NEW:
    358456                        case STATE_REOPEN:
    359                                 /* We cannot just close the conenction, we have to send a DPR first */
     457                                /* We cannot just close the connection, we have to send a DPR first */
    360458                                CHECK_FCT_DO( fd_p_dp_initiate(peer, ev_data), goto psm_end );
    361459                                goto psm_loop;
     
    363461                        /*     
    364462                        case STATE_CLOSING:
     463                        case STATE_CLOSING_GRACE:
    365464                        case STATE_WAITCNXACK:
    366465                        case STATE_WAITCNXACK_ELEC:
     
    380479                struct msg_hdr * hdr;
    381480               
    382                 /* If the current state does not allow receiving messages, just drop it */
    383                 if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSED) {
    384                         TRACE_DEBUG(FULL, "Purging message in queue while in CLOSED state (%zdb)", ev_sz);
    385                         free(ev_data);
    386                         goto psm_loop;
    387                 }
    388                
    389481                /* Parse the received buffer */
    390482                CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg),
     
    396488                        } );
    397489               
     490                /* If the current state does not allow receiving messages, just drop it */
     491                if (cur_state == STATE_CLOSED) {
     492                        /* In such case, just discard the message */
     493                        fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Purged from peer '%s''s queue (CLOSED state).", peer->p_hdr.info.pi_diamid );
     494                        fd_msg_free(msg);
     495                        goto psm_loop;
     496                }
     497               
    398498                /* Log incoming message */
    399                 fd_msg_log( FD_MSG_LOG_RECEIVED, msg, "Received %zdb from '%s'", ev_sz, peer->p_hdr.info.pi_diamid );
     499                fd_msg_log( FD_MSG_LOG_RECEIVED, msg, "Received %zdb from '%s' (%s)", ev_sz, peer->p_hdr.info.pi_diamid, STATE_STR(cur_state) );
    400500       
    401501                /* Extract the header */
     
    417517                }
    418518               
     519                if (cur_state == STATE_OPEN_NEW) {
     520                        /* OK, we have received something, so the connection is supposedly now in OPEN state at the remote site */
     521                        fd_psm_change_state(peer, STATE_OPEN );
     522                }
     523               
    419524                /* Now handle non-link-local messages */
    420525                if (fd_msg_is_routable(msg)) {
    421                         switch (peer->p_hdr.info.runtime.pir_state) {
     526                        switch (cur_state) {
    422527                                /* To maximize compatibility -- should not be a security issue here */
    423528                                case STATE_REOPEN:
    424529                                case STATE_SUSPECT:
    425530                                case STATE_CLOSING:
     531                                case STATE_CLOSING_GRACE:
    426532                                        TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state... ");
    427533                                /* The standard situation : */
     534                                case STATE_OPEN_NEW:
    428535                                case STATE_OPEN:
    429536                                        /* We received a valid routable message, update the expiry timer */
     
    431538
    432539                                        /* Set the message source and add the Route-Record */
    433                                         CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), goto psm_end);
     540                                        CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen, 1, fd_g_config->cnf_dict ), goto psm_end);
    434541
    435542                                        /* Requeue to the global incoming queue */
     
    437544
    438545                                        /* Update the peer timer (only in OPEN state) */
    439                                         if ((peer->p_hdr.info.runtime.pir_state == STATE_OPEN) && (!peer->p_flags.pf_dw_pending)) {
     546                                        if ((cur_state == STATE_OPEN) && (!peer->p_flags.pf_dw_pending)) {
    440547                                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
    441548                                        }
     
    449556                                default:
    450557                                        /* In such case, just discard the message */
    451                                         fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received from peer '%s' while connection was not in OPEN state.", peer->p_hdr.info.pi_diamid );
     558                                        fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received from peer '%s' while connection was not in state %s.", peer->p_hdr.info.pi_diamid, STATE_STR(cur_state) );
    452559                                        fd_msg_free(msg);
    453560                        }
     
    485592                        case CC_DISCONNECT_PEER:
    486593                                CHECK_FCT_DO( fd_p_dp_handle(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_reset );
    487                                 if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSING)
     594                                if (fd_peer_getstate(peer) == STATE_CLOSING)
    488595                                        goto psm_end;
     596
    489597                                break;
    490598                       
     
    494602                       
    495603                        default:
    496                                 /* Unknown / unexpected / invalid message */
     604                                /* Unknown / unexpected / invalid message -- but validated by our dictionary */
    497605                                TRACE_DEBUG(INFO, "Invalid non-routable command received: %u.", hdr->msg_code);
    498606                                if (hdr->msg_flags & CMD_FLAG_REQUEST) {
     
    502610
    503611                                                /* Set the error code */
    504                                                 CHECK_FCT_DO( fd_msg_rescode_set(msg, "DIAMETER_INVALID_HDR_BITS", NULL, NULL, 1 ), break );
     612                                                CHECK_FCT_DO( fd_msg_rescode_set(msg, "DIAMETER_COMMAND_UNSUPPORTED", "Or maybe the P-bit or application Id are erroneous.", NULL, 1 ), break );
    505613
    506614                                                /* Send the answer */
     
    509617                                } else {
    510618                                        /* We did ASK for it ??? */
    511                                         fd_log_debug("Invalid PXY flag in answer header ?\n");
     619                                        TRACE_DEBUG(INFO, "Received answer with erroneous 'is_routable' result...");
    512620                                }
    513621                               
     
    531639        /* The connection object is broken */
    532640        if (event == FDEVP_CNX_ERROR) {
    533                 switch (peer->p_hdr.info.runtime.pir_state) {
     641                switch (cur_state) {
    534642                        case STATE_WAITCNXACK_ELEC:
    535643                                /* Abort the initiating side */
     
    541649                        case STATE_WAITCEA:
    542650                        case STATE_OPEN:
     651                        case STATE_OPEN_NEW:
    543652                        case STATE_REOPEN:
    544653                        case STATE_WAITCNXACK:
     
    558667                                goto psm_end;
    559668                               
     669                        case STATE_CLOSING_GRACE:
     670                                if (peer->p_flags.pf_localterm) /* initiated here */
     671                                        goto psm_end;
     672                               
     673                                fd_psm_cleanup(peer, 0);
     674                               
     675                                /* Reset the timer for next connection attempt */
     676                                fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
     677                                goto psm_loop;
    560678                }
    561679                goto psm_loop;
     
    616734                peer->p_ini_thr = (pthread_t)NULL;
    617735               
    618                 switch (peer->p_hdr.info.runtime.pir_state) {
     736                switch (cur_state) {
    619737                        case STATE_WAITCNXACK_ELEC:
    620738                        case STATE_WAITCNXACK:
     
    624742                        default:
    625743                                /* Just abort the attempt and continue */
    626                                 TRACE_DEBUG(FULL, "Connection attempt successful but current state is %s, closing...", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     744                                TRACE_DEBUG(FULL, "Connection attempt successful but current state is %s, closing... (too slow?)", STATE_STR(cur_state));
    627745                                fd_cnx_destroy(cnx);
    628746                }
     
    638756                peer->p_ini_thr = (pthread_t)NULL;
    639757               
    640                 switch (peer->p_hdr.info.runtime.pir_state) {
     758                switch (cur_state) {
    641759                        case STATE_WAITCNXACK_ELEC:
    642760                                /* Abort the initiating side */
     
    653771                        default:
    654772                                /* Just ignore */
    655                                 TRACE_DEBUG(FULL, "Connection attempt failed but current state is %s, ignoring...", STATE_STR(peer->p_hdr.info.runtime.pir_state));
     773                                TRACE_DEBUG(FULL, "Connection attempt failed but current state is %s, ignoring...", STATE_STR(cur_state));
    656774                }
    657775               
     
    661779        /* The timeout for the current state has been reached */
    662780        if (event == FDEVP_PSM_TIMEOUT) {
    663                 switch (peer->p_hdr.info.runtime.pir_state) {
     781                switch (cur_state) {
    664782                        case STATE_OPEN:
    665783                        case STATE_REOPEN:
     784                        case STATE_OPEN_NEW:
    666785                                CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end );
    667786                                goto psm_loop;
     
    676795                                /* Mark the connection problem */
    677796                                peer->p_flags.pf_cnx_pb = 1;
    678                                
    679797                        case STATE_CLOSING:
    680798                        case STATE_WAITCNXACK:
     
    683801                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
    684802                                goto psm_reset;
     803                               
     804                        case STATE_CLOSING_GRACE:
     805                                /* The grace period is completed, now close */
     806                                if (peer->p_flags.pf_localterm)
     807                                        goto psm_end;
     808                               
     809                                fd_psm_cleanup(peer, 0);
     810                                /* Reset the timer for next connection attempt */
     811                                fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
     812                                goto psm_loop;
    685813                               
    686814                        case STATE_WAITCNXACK_ELEC:
     
    697825       
    698826        /* Default action : the handling has not yet been implemented. [for debug only] */
    699         TRACE_DEBUG(INFO, "Missing handler in PSM for '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.runtime.pir_state), fd_pev_str(event));
     827        TRACE_DEBUG(INFO, "Missing handler in PSM for '%s'\t<-- '%s'", STATE_STR(cur_state), fd_pev_str(event));
    700828psm_reset:
    701829        if (peer->p_flags.pf_delete)
     
    707835        fd_psm_cleanup(peer, 1);
    708836        TRACE_DEBUG(INFO, "'%s'\t-> STATE_ZOMBIE (terminated)\t'%s'",
    709                         STATE_STR(peer->p_hdr.info.runtime.pir_state),
     837                        STATE_STR(fd_peer_getstate(peer)),
    710838                        peer->p_hdr.info.pi_diamid);
    711839        pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
    712         fd_cpu_flush_cache();
    713840        peer->p_psm = (pthread_t)NULL;
    714841        pthread_detach(pthread_self());
     
    726853       
    727854        /* Check the peer and state are OK */
    728         CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.runtime.pir_state == STATE_NEW) );
     855        CHECK_PARAMS( fd_peer_getstate(peer) == STATE_NEW );
    729856       
    730857        /* Create the FIFO for events */
     
    744871        CHECK_PARAMS( CHECK_PEER(peer) );
    745872       
    746         fd_cpu_flush_cache();
    747         if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
     873        if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
    748874                CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, reason) );
    749875        } else {
  • libfdcore/p_sr.c

    r691 r706  
    3636#include "fdcore-internal.h"
    3737
    38 #ifndef SR_DEBUG_LVL
    39 #define SR_DEBUG_LVL ANNOYING
    40 #endif /* SR_DEBUG_LVL */
    41 
    4238/* Structure to store a sent request */
    4339struct sentreq {
     
    6965        struct fd_list * li;
    7066        struct timespec now;
    71         if (!TRACE_BOOL(SR_DEBUG_LVL))
     67       
     68        if (!TRACE_BOOL(ANNOYING))
    7269                return;
     70       
     71        fd_log_debug("%sSentReq list @%p:\n", text, srlist);
     72       
    7373        CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), );
    74         fd_log_debug("%sSentReq list @%p:\n", text, srlist);
     74       
    7575        for (li = srlist->next; li != srlist; li = li->next) {
    7676                struct sentreq * sr = (struct sentreq *)li;
    7777                uint32_t * nexthbh = li->o;
    78                 fd_log_debug(" - Next req (%x): [since %ld.%06ld sec]\n", *nexthbh,
     78               
     79                fd_log_debug(" - Next req (hbh:%x): [since %ld.%06ld sec]\n", *nexthbh,
    7980                        (now.tv_nsec >= sr->added_on.tv_nsec) ? (now.tv_sec - sr->added_on.tv_sec) : (now.tv_sec - sr->added_on.tv_sec - 1),
    8081                        (now.tv_nsec >= sr->added_on.tv_nsec) ? (now.tv_nsec - sr->added_on.tv_nsec) / 1000 : (now.tv_nsec - sr->added_on.tv_nsec + 1000000000) / 1000);
    81                 fd_msg_dump_one(SR_DEBUG_LVL + 1, sr->req);
     82               
     83                fd_msg_dump_one(ANNOYING + 1, sr->req);
    8284        }
    8385}
     
    117119}
    118120
    119 /* thread that handles messages expiring. The thread is started / cancelled only when needed */
     121/* thread that handles messages expiring. The thread is started only when needed */
    120122static void * sr_expiry_th(void * arg) {
    121123        struct sr_list * srlist = arg;
     
    129131        {
    130132                char buf[48];
    131                 sprintf(buf, "ReqExp/%.*s", (int)sizeof(buf) - 8, ((struct fd_peer *)(srlist->exp.o))->p_hdr.info.pi_diamid);
     133                snprintf(buf, sizeof(buf), "ReqExp/%s", ((struct fd_peer *)(srlist->exp.o))->p_hdr.info.pi_diamid);
    132134                fd_log_threadname ( buf );
    133135        }
     
    313315                } else {
    314316                        /* Just free the request. */
    315                         fd_msg_log( FD_MSG_LOG_DROPPED, sr->req, "Local message discarded during failover" );
     317                        fd_msg_log( FD_MSG_LOG_DROPPED, sr->req, "Sent & unanswered local message discarded during failover." );
    316318                        CHECK_FCT_DO(fd_msg_free(sr->req), /* Ignore */);
    317319                }
  • libfdcore/peers.c

    r691 r706  
    7373       
    7474        p->p_eyec = EYEC_PEER;
     75        CHECK_POSIX( pthread_mutex_init(&p->p_state_mtx, NULL) );
     76       
    7577        fd_list_init(&p->p_actives, p);
    7678        fd_list_init(&p->p_expiry, p);
     
    9496        struct fd_list * li;
    9597        int ret = 0;
     98       
    9699        TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data);
    97100        CHECK_PARAMS(info && info->pi_diamid);
    98101       
     102        if (info->config.pic_realm) {
     103                if (!fd_os_is_valid_DiameterIdentity((os0_t)info->config.pic_realm, strlen(info->config.pic_realm))) {
     104                        TRACE_DEBUG(INFO, "'%s' is not a valid DiameterIdentity.", info->config.pic_realm);
     105                        return EINVAL;
     106                }
     107        }
     108       
    99109        /* Create a structure to contain the new peer information */
    100110        CHECK_FCT( fd_peer_alloc(&p) );
    101111       
    102112        /* Copy the informations from the parameters received */
    103         CHECK_MALLOC( p->p_hdr.info.pi_diamid = strdup(info->pi_diamid) );
     113        p->p_hdr.info.pi_diamid = info->pi_diamid;
     114        CHECK_FCT( fd_os_validate_DiameterIdentity(&p->p_hdr.info.pi_diamid, &p->p_hdr.info.pi_diamidlen, 1) );
    104115       
    105116        memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) );
     117       
    106118        /* Duplicate the strings if provided */
    107119        if (info->config.pic_realm) {
     
    109121        }
    110122        if (info->config.pic_priority) {
    111                 CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_priority) );
     123                CHECK_MALLOC( p->p_hdr.info.config.pic_priority = strdup(info->config.pic_priority) );
    112124        }
    113125       
     
    124136                CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) );
    125137        } else {
    126                 CHECK_MALLOC( p->p_dbgorig = strdup("unknown") );
     138                CHECK_MALLOC( p->p_dbgorig = strdup("unspecified") );
    127139        }
    128140        p->p_cb = cb;
     
    134146        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    135147                struct fd_peer * next = (struct fd_peer *)li;
    136                 int cmp = strcasecmp( p->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamid );
     148                int cmp = fd_os_almostcasecmp( p->p_hdr.info.pi_diamid, p->p_hdr.info.pi_diamidlen,
     149                                                next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
    137150                if (cmp > 0)
    138151                        continue;
     
    162175
    163176/* Search for a peer */
    164 int fd_peer_getbyid( char * diamid, struct peer_hdr ** peer )
     177int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer )
    165178{
    166179        struct fd_list * li;
    167        
    168         TRACE_ENTRY("%p %p", diamid, peer);
    169         CHECK_PARAMS( diamid && peer );
     180        TRACE_ENTRY("%p %zd %d %p", diamid, diamidlen, igncase, peer);
     181        CHECK_PARAMS( diamid && diamidlen && peer );
    170182       
    171183        *peer = NULL;
     
    175187        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    176188                struct fd_peer * next = (struct fd_peer *)li;
    177                 int cmp = strcasecmp( diamid, next->p_hdr.info.pi_diamid );
     189                int cmp;
     190                if (igncase)
     191                        cmp = fd_os_almostcasecmp( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
     192                else
     193                        cmp = fd_os_cmp( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
    178194                if (cmp > 0)
    179195                        continue;
     
    255271       
    256272        CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ );
     273        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_state_mtx), /* continue */);
    257274        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */);
    258275        CHECK_POSIX_DO( pthread_cond_destroy(&p->p_sr.cnd), /* continue */);
     
    283300        CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
    284301        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    285                 struct fd_peer * peer = (struct fd_peer *)li;
    286                
    287                 fd_cpu_flush_cache();
    288                 if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
     302                struct fd_peer * peer = (struct fd_peer *)li->o;
     303               
     304                if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
    289305                        CHECK_FCT_DO( fd_psm_terminate(peer, "REBOOTING"), /* continue */ );
    290306                } else {
     
    307323               
    308324                /* Allow the PSM(s) to execute */
    309                 sched_yield();
     325                usleep(100000);
    310326               
    311327                /* Remove zombie peers */
    312328                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
    313329                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    314                         struct fd_peer * peer = (struct fd_peer *)li;
    315                         fd_cpu_flush_cache();
    316                         if (peer->p_hdr.info.runtime.pir_state == STATE_ZOMBIE) {
     330                        struct fd_peer * peer = (struct fd_peer *)li->o;
     331                        if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
    317332                                li = li->prev; /* to avoid breaking the loop */
    318333                                fd_list_unlink(&peer->p_hdr.chain);
     
    329344                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
    330345                while (!FD_IS_LIST_EMPTY(&fd_g_peers)) {
    331                         struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next);
     346                        struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next->o);
    332347                        fd_psm_abord(peer);
    333348                        fd_list_unlink(&peer->p_hdr.chain);
     
    339354        /* Free memory objects of all peers */
    340355        while (!FD_IS_LIST_EMPTY(&purge)) {
    341                 struct fd_peer * peer = (struct fd_peer *)(purge.next);
     356                struct fd_peer * peer = (struct fd_peer *)(purge.next->o);
    342357                fd_list_unlink(&peer->p_hdr.chain);
    343358                fd_peer_free(&peer);
     
    364379        }
    365380
    366         fd_log_debug(">  %s\t%s", STATE_STR(peer->p_hdr.info.runtime.pir_state), peer->p_hdr.info.pi_diamid);
     381        fd_log_debug(">  %s\t%s", STATE_STR(fd_peer_getstate(peer)), peer->p_hdr.info.pi_diamid);
    367382        if (details > INFO) {
    368                 fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "(unknown)");
     383                fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>");
    369384                if (peer->p_hdr.info.runtime.pir_prodname)
    370385                        fd_log_debug("\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev);
     
    398413       
    399414        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    400                 struct fd_peer * np = (struct fd_peer *)li;
     415                struct fd_peer * np = (struct fd_peer *)li->o;
    401416                fd_peer_dump(np, details);
    402417        }
     
    404419        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
    405420}
     421
     422static struct dict_object *avp_oh_model = NULL;
     423static pthread_mutex_t cache_avp_lock = PTHREAD_MUTEX_INITIALIZER;
    406424
    407425/* Handle an incoming CER request on a new connection */
     
    409427{
    410428        struct msg * msg;
    411         struct dict_object *avp_oh_model;
    412         avp_code_t code = AC_ORIGIN_HOST;
    413429        struct avp *avp_oh;
    414430        struct avp_hdr * avp_hdr;
     
    424440        msg = *cer;
    425441       
     442        /* If needed, resolve the dictioanry model for Origin-Host */
     443        CHECK_POSIX( pthread_mutex_lock(&cache_avp_lock) );
     444        if (!avp_oh_model) {
     445                avp_code_t code = AC_ORIGIN_HOST;
     446                int ret;
     447                CHECK_FCT_DO( ret = fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT),
     448                        { CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) ); return ret; } );
     449        }
     450        CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) );
     451       
    426452        /* Find the Diameter Identity of the remote peer in the message */
    427         CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT) );
    428453        CHECK_FCT( fd_msg_search_avp ( msg, avp_oh_model, &avp_oh ) );
     454        ASSERT(avp_oh); /* otherwise it should not have passed rules validation, right? */
    429455        CHECK_FCT( fd_msg_avp_hdr ( avp_oh, &avp_hdr ) );
     456       
     457        /* First, check if the Origin-Host value  */
     458        if (!fd_os_is_valid_DiameterIdentity(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len)) {
     459                TRACE_DEBUG(INFO, "Received new CER with invalid \\0 in its Origin-Host");
     460                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ) );
     461                CHECK_FCT( fd_msg_rescode_set(*cer, "ER_DIAMETER_INVALID_AVP_VALUE",
     462                                                        "Your Origin-Host contains invalid characters.", avp_oh, 1 ) );
     463                CHECK_FCT( fd_out_send(cer, *cnx, NULL, FD_CNX_ORDERED) );
     464                return EINVAL;
     465        }
    430466       
    431467        /* Search if we already have this peer id in our list. We take directly the write lock so that we don't need to upgrade if it is a new peer.
     
    435471       
    436472        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    437                 peer = (struct fd_peer *)li;
    438                 /* It is probably unwise to use strcasecmp on UTF8 data... To be improved! */
    439                 int cmp = strncasecmp( (char *)avp_hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, avp_hdr->avp_value->os.len );
     473                int cmp;
     474                peer = (struct fd_peer *)li->o;
     475                cmp = fd_os_almostcasecmp( avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen );
    440476                if (cmp > 0)
    441477                        continue;
     
    451487               
    452488                /* Set the peer Diameter Id and the responder flag parameters */
    453                 CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = malloc(avp_hdr->avp_value->os.len + 1), { ret = ENOMEM; goto out; } );
    454                 memcpy(peer->p_hdr.info.pi_diamid, avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len);
    455                 peer->p_hdr.info.pi_diamid[avp_hdr->avp_value->os.len] = '\0';
     489                CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = os0dup(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len),
     490                        { ret = ENOMEM; goto out; } );
     491                peer->p_hdr.info.pi_diamidlen = avp_hdr->avp_value->os.len;
    456492                CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );
    457493                peer->p_flags.pf_responder = 1;
     
    470506        } else {
    471507                /* Check if the peer is in zombie state */
    472                 fd_cpu_flush_cache();
    473                 if (peer->p_hdr.info.runtime.pir_state == STATE_ZOMBIE) {
     508                if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
    474509                        /* Re-activate the peer */
    475510                        if (peer->p_hdr.info.config.pic_flags.exp)
    476511                                peer->p_flags.pf_responder = 1;
    477                         peer->p_hdr.info.runtime.pir_state = STATE_NEW;
     512                        CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), );
     513                        peer->p_state = STATE_NEW;
     514                        CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), );
     515                        peer->p_flags.pf_localterm = 0;
    478516                        CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
    479517                }
    480518        }
    481                
     519       
    482520        /* Send the new connection event to the PSM */
    483521        CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );
  • libfdcore/routing_dispatch.c

    r691 r706  
    208208                struct fd_peer * peer;
    209209                struct fd_app *found;
    210                 CHECK_FCT( fd_peer_getbyid( c->diamid, (void *)&peer ) );
    211                 if (peer && (peer->p_hdr.info.runtime.pir_relay == 0)) {
     210                CHECK_FCT( fd_peer_getbyid( c->diamid, c->diamidlen, 0, (void *)&peer ) );
     211                if (peer && !peer->p_hdr.info.runtime.pir_relay) {
    212212                        /* Check if the remote peer advertised the message's appli */
    213213                        CHECK_FCT( fd_app_check(&peer->p_hdr.info.runtime.pir_apps, hdr->msg_appl, &found) );
     
    264264        for (li = candidates->next; li != candidates; li = li->next) {
    265265                struct rtd_candidate *c = (struct rtd_candidate *) li;
     266               
     267            #if 0 /* this is actually useless since the sending process will also ensure that the peer is still available */
    266268                struct fd_peer * peer;
    267                 CHECK_FCT( fd_peer_getbyid( c->diamid, (void *)&peer ) );
    268                 if (peer) {
    269                         if (dh
    270                                 && (dh->os.len == strlen(peer->p_hdr.info.pi_diamid))
    271                                 /* Here again we use strncasecmp on UTF8 data... This should probably be changed. */
    272                                 && (strncasecmp(peer->p_hdr.info.pi_diamid, (char *)dh->os.data, dh->os.len) == 0)) {
    273                                 /* The candidate is the Destination-Host */
    274                                 c->score += FD_SCORE_FINALDEST;
    275                         } else {
    276                                 if (dr  && peer->p_hdr.info.runtime.pir_realm
    277                                         && (dr->os.len == strlen(peer->p_hdr.info.runtime.pir_realm))
    278                                         /* Yet another case where we use strncasecmp on UTF8 data... Hmmm :-( */
    279                                         && (strncasecmp(peer->p_hdr.info.runtime.pir_realm, (char *)dr->os.data, dr->os.len) == 0)) {
    280                                         /* The candidate's realm matchs the Destination-Realm */
    281                                         c->score += FD_SCORE_REALM;
    282                                 }
     269                /* Since the candidates list comes from the peers list, we do not have any issue with upper/lower case to find the peer object */
     270                CHECK_FCT( fd_peer_getbyid( c->diamid, c->diamidlen, 0, (void *)&peer ) );
     271                if (!peer)
     272                        continue; /* it has been deleted since the candidate list was generated; avoid sending to this one in that case. */
     273            #endif /* 0 */
     274               
     275                /* In the AVPs, the value comes from the network, so let's be case permissive */
     276                if (dh && !fd_os_almostcasecmp(dh->os.data, dh->os.len, c->diamid, c->diamidlen) ) {
     277                        /* The candidate is the Destination-Host */
     278                        c->score += FD_SCORE_FINALDEST;
     279                } else {
     280                        if (dr && !fd_os_almostcasecmp(dr->os.data, dr->os.len, c->realm, c->realmlen) ) {
     281                                /* The candidate's realm matchs the Destination-Realm */
     282                                c->score += FD_SCORE_REALM;
    283283                        }
    284284                }
     
    298298       
    299299        TRACE_ENTRY("%p %p %p", un, excl_idx, at_idx);
    300         CHECK_PARAMS_DO( un && excl_idx, return );
     300        CHECK_PARAMS_DO( un && excl_idx && at_idx, return );
     301       
    301302        *excl_idx = 0;
     303        *at_idx = 0;
    302304       
    303305        /* Search if there is a '!' before any '@' -- do we need to check it contains a '.' ? */
     
    307309                        if (!*excl_idx)
    308310                                *excl_idx = i;
    309                         if (!at_idx)
    310                                 return;
     311                        continue;
    311312                }
    312313                /* If we reach the realm part, we can stop */
    313314                if ( un->os.data[i] == (unsigned char) '@' ) {
    314                         if (at_idx)
    315                                 *at_idx = i;
     315                        *at_idx = i;
    316316                        break;
     317                }
     318                /* Stop if we find a \0 in the middle */
     319                if ( un->os.data[i] == 0 ) {
     320                        return;
    317321                }
    318322                /* Skip escaped characters */
     
    321325                        continue;
    322326                }
    323                 /* Skip UTF-8 characters spanning on several bytes */
    324                 if ( (un->os.data[i] & 0xF8) == 0xF0 ) { /* 11110zzz */
    325                         i += 3;
    326                         continue;
    327                 }
    328                 if ( (un->os.data[i] & 0xF0) == 0xE0 ) { /* 1110yyyy */
    329                         i += 2;
    330                         continue;
    331                 }
    332                 if ( (un->os.data[i] & 0xE0) == 0xC0 ) { /* 110yyyxx */
    333                         i += 1;
    334                         continue;
    335                 }
    336327        }
    337328       
     
    340331
    341332/* Test if a User-Name AVP contains a Decorated NAI -- RFC4282, RFC5729 */
    342 static int is_decorated_NAI(union avp_value * un)
    343 {
    344         int i;
    345         TRACE_ENTRY("%p", un);
    346        
    347         /* If there was no User-Name, we return false */
    348         if (un == NULL)
    349                 return 0;
    350        
    351         nai_get_indexes(un, &i, NULL);
    352        
    353         return i;
    354 }
    355 
    356333/* Create new User-Name and Destination-Realm values */
    357 static int process_decorated_NAI(union avp_value * un, union avp_value * dr)
    358 {
    359         int at_idx = 0, sep_idx = 0;
     334static int process_decorated_NAI(int * was_nai, union avp_value * un, union avp_value * dr)
     335{
     336        int at_idx, sep_idx;
    360337        unsigned char * old_un;
    361         TRACE_ENTRY("%p %p", un, dr);
    362         CHECK_PARAMS(un && dr);
     338        TRACE_ENTRY("%p %p %p", was_nai, un, dr);
     339        CHECK_PARAMS(was_nai && un && dr);
    363340       
    364341        /* Save the decorated User-Name, for example 'homerealm.example.net!user@otherrealm.example.net' */
     
    367344        /* Search the positions of the first '!' and the '@' in the string */
    368345        nai_get_indexes(un, &sep_idx, &at_idx);
    369         CHECK_PARAMS( (0 < sep_idx) && (sep_idx < at_idx) && (at_idx < un->os.len));
     346        if ((!sep_idx) || (sep_idx > at_idx) || !fd_os_is_valid_DiameterIdentity(old_un, sep_idx /* this is the new realm part */)) {
     347                *was_nai = 0;
     348                return 0;
     349        }
     350       
     351        *was_nai = 1;
    370352       
    371353        /* Create the new User-Name value */
     
    390372}
    391373
     374
    392375/* Function to return an error to an incoming request */
    393376static int return_error(struct msg ** pmsg, char * error_code, char * error_message, struct avp * failedavp)
     
    398381        /* Get the source of the message */
    399382        {
    400                 char * id;
    401                 CHECK_FCT( fd_msg_source_get( *pmsg, &id ) );
     383                DiamId_t id;
     384                size_t   idlen;
     385                CHECK_FCT( fd_msg_source_get( *pmsg, &id, &idlen ) );
    402386               
    403387                if (id == NULL) {
     
    406390               
    407391                        /* Search the peer with this id */
    408                         CHECK_FCT( fd_peer_getbyid( id, (void *)&peer ) );
     392                        CHECK_FCT( fd_peer_getbyid( id, idlen, 0, (void *)&peer ) );
    409393
    410394                        if (!peer) {
     
    439423/****************************************************************************/
    440424
    441 /* These are the functions of each threads: dispatch & routing */
    442425/* The DISPATCH message processing */
    443426static int msg_dispatch(struct msg ** pmsg)
     
    447430        struct session * sess;
    448431        enum disp_action action;
    449         const char * ec = NULL;
    450         const char * em = NULL;
     432        char * ec = NULL;
     433        char * em = NULL;
    451434
    452435        /* Read the message header */
     
    460443        CHECK_FCT_DO( ret = fd_msg_parse_or_error( pmsg ),
    461444                {
    462                         /* in case of error, the message is already dump'd */
     445                        /* in case of error */
    463446                        if ((ret == EBADMSG) && (*pmsg != NULL)) {
    464447                                /* msg now contains the answer message to send back */
     
    512495                                em = "The message was not handled by any extension callback";
    513496                                ec = "DIAMETER_COMMAND_UNSUPPORTED";
    514                        
     497                                /* and continue as if an error occurred... */
    515498                        case DISP_ACT_ERROR:
    516499                                /* We have a problem with delivering the message */
     
    528511                                /* Create an answer with the error code and message */
    529512                                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, pmsg, 0 ) );
    530                                 CHECK_FCT( fd_msg_rescode_set(*pmsg, (char *)ec, (char *)em, NULL, 1 ) );
     513                                CHECK_FCT( fd_msg_rescode_set(*pmsg, ec, em, NULL, 1 ) );
    531514                               
    532515                        case DISP_ACT_SEND:
     
    545528        int is_req = 0;
    546529        int is_err = 0;
    547         char * qry_src = NULL;
     530        DiamId_t qry_src = NULL;
     531        size_t   qry_src_len = 0;
    548532
    549533        /* Read the message header */
     
    572556                /* Check if we have local support for the message application */
    573557                if ( (hdr->msg_appl == 0) || (hdr->msg_appl == AI_RELAY) ) {
    574                         TRACE_DEBUG(INFO, "Received a routable message with application id 0, returning DIAMETER_APPLICATION_UNSUPPORTED");
     558                        TRACE_DEBUG(INFO, "Received a routable message with application id 0 or " _stringize(AI_RELAY) " (relay),\n"
     559                                          " returning DIAMETER_APPLICATION_UNSUPPORTED");
    575560                        CHECK_FCT( return_error( pmsg, "DIAMETER_APPLICATION_UNSUPPORTED", "Routable message with application id 0 or relay", NULL) );
    576561                        return 0;
     
    587572                        struct fd_pei error_info;
    588573                        int ret;
     574                       
     575                        memset(&error_info, 0, sizeof(struct fd_pei));
     576                       
    589577                        CHECK_FCT(  fd_msg_avp_hdr( avp, &ahdr )  );
    590578
     
    604592                                                ASSERT( ahdr->avp_value );
    605593                                                /* Compare the Destination-Host AVP of the message with our identity */
    606                                                 if (ahdr->avp_value->os.len != fd_g_config->cnf_diamid_len) {
     594                                                if (!fd_os_almostcasecmp(ahdr->avp_value->os.data, ahdr->avp_value->os.len, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len)) {
     595                                                        is_dest_host = YES;
     596                                                } else {
    607597                                                        is_dest_host = NO;
    608                                                 } else {
    609                                                         is_dest_host = (strncasecmp(fd_g_config->cnf_diamid, (char *)ahdr->avp_value->os.data, fd_g_config->cnf_diamid_len)
    610                                                                                 ? NO : YES);
    611598                                                }
    612599                                                break;
     
    626613                                                dr_val = ahdr->avp_value;
    627614                                                /* Compare the Destination-Realm AVP of the message with our identity */
    628                                                 if (ahdr->avp_value->os.len != fd_g_config->cnf_diamrlm_len) {
     615                                                if (!fd_os_almostcasecmp(dr_val->os.data, dr_val->os.len, fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len)) {
     616                                                        is_dest_realm = YES;
     617                                                } else {
    629618                                                        is_dest_realm = NO;
    630                                                 } else {
    631                                                         is_dest_realm = (strncasecmp(fd_g_config->cnf_diamrlm, (char *)ahdr->avp_value->os.data, fd_g_config->cnf_diamrlm_len)
    632                                                                                 ? NO : YES);
    633619                                                }
    634620                                                break;
    635621
     622                                        /* we also use User-Name for decorated NAI */
    636623                                        case AC_USER_NAME:
    637624                                                /* Parse this AVP */
     
    652639                        }
    653640
     641                        /* Stop when we found all 3 AVPs -- they are supposed to be at the beginning of the message, so this should be fast */
    654642                        if ((is_dest_host != UNKNOWN) && (is_dest_realm != UNKNOWN) && un)
    655643                                break;
     
    682670                if ((is_dest_host == NO) || (is_dest_realm == NO)) {
    683671                        if (fd_g_config->cnf_flags.no_fwd) {
    684                                 CHECK_FCT( return_error( pmsg, "DIAMETER_UNABLE_TO_DELIVER", "This peer is not an agent", NULL) );
     672                                CHECK_FCT( return_error( pmsg, "DIAMETER_UNABLE_TO_DELIVER", "I am not a Diameter agent", NULL) );
    685673                                return 0;
    686674                        }
    687675                } else {
    688676                /* Destination-Host was not set, and Destination-Realm is matching : we may handle or pass to a fellow peer */
     677                        int is_nai = 0;
    689678
    690679                        /* test for decorated NAI  (RFC5729 section 4.4) */
    691                         if (is_decorated_NAI(un_val)) {
    692                                 /* Handle the decorated NAI */
    693                                 CHECK_FCT_DO( process_decorated_NAI(un_val, dr_val),
    694                                         {
    695                                                 /* If the process failed, we assume it is because of the AVP format */
    696                                                 CHECK_FCT( return_error( pmsg, "DIAMETER_INVALID_AVP_VALUE", "Failed to process decorated NAI", un) );
    697                                                 return 0;
    698                                         } );
    699 
     680                        /* Handle the decorated NAI */
     681                        CHECK_FCT_DO( process_decorated_NAI(&is_nai, un_val, dr_val),
     682                                {
     683                                        /* If the process failed, we assume it is because of the AVP format */
     684                                        CHECK_FCT( return_error( pmsg, "DIAMETER_INVALID_AVP_VALUE", "Failed to process decorated NAI", un) );
     685                                        return 0;
     686                                } );
     687                               
     688                        if (is_nai) {
    700689                                /* We have transformed the AVP, now submit it again in the queue */
    701690                                CHECK_FCT(fd_fifo_post(fd_g_incoming, pmsg) );
     
    724713                /* Retrieve the corresponding query and its origin */
    725714                CHECK_FCT( fd_msg_answ_getq( *pmsg, &qry ) );
    726                 CHECK_FCT( fd_msg_source_get( qry, &qry_src ) );
     715                CHECK_FCT( fd_msg_source_get( qry, &qry_src, &qry_src_len ) );
    727716
    728717                if ((!qry_src) && (!is_err)) {
     
    733722
    734723                /* From that point, for answers, we will call the registered callbacks, then pass it to the dispatch module or forward it */
     724                TODO("Callback for answers with a Redirect code?");
    735725        }
    736726
     
    800790        if ( ! is_req ) {
    801791                struct msg * qry;
    802                 char * qry_src = NULL;
     792                DiamId_t qry_src = NULL;
     793                size_t qry_src_len = 0;
    803794                struct msg_hdr * qry_hdr;
    804795                struct fd_peer * peer = NULL;
     
    806797                /* Retrieve the corresponding query and its origin */
    807798                CHECK_FCT( fd_msg_answ_getq( *pmsg, &qry ) );
    808                 CHECK_FCT( fd_msg_source_get( qry, &qry_src ) );
     799                CHECK_FCT( fd_msg_source_get( qry, &qry_src, &qry_src_len ) );
    809800
    810801                ASSERT( qry_src ); /* if it is NULL, the message should have been in the LOCAL queue! */
    811802
    812803                /* Find the peer corresponding to this name */
    813                 CHECK_FCT( fd_peer_getbyid( qry_src, (void *) &peer ) );
    814                 fd_cpu_flush_cache();
    815                 if ((!peer) || (peer->p_hdr.info.runtime.pir_state != STATE_OPEN)) {
     804                CHECK_FCT( fd_peer_getbyid( qry_src, qry_src_len, 0, (void *) &peer ) );
     805                if (fd_peer_getstate(peer) != STATE_OPEN) {
    816806                        fd_msg_log( FD_MSG_LOG_DROPPED, *pmsg, "Unable to forward answer to deleted / closed peer '%s'.", qry_src);
    817807                        fd_msg_free(*pmsg);
     
    844834                for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) {
    845835                        struct fd_peer * p = (struct fd_peer *)li->o;
    846                         CHECK_FCT_DO( ret = fd_rtd_candidate_add(rtd, p->p_hdr.info.pi_diamid, p->p_hdr.info.runtime.pir_realm), { CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_activ_peers_rw), ); return ret; } );
     836                        CHECK_FCT_DO( ret = fd_rtd_candidate_add(rtd,
     837                                                        p->p_hdr.info.pi_diamid,
     838                                                        p->p_hdr.info.pi_diamidlen,
     839                                                        p->p_hdr.info.runtime.pir_realm,
     840                                                        p->p_hdr.info.runtime.pir_realmlen),
     841                                { CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_activ_peers_rw), ); return ret; } );
    847842                }
    848843                CHECK_FCT( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
     
    867862                                        } );
    868863                                ASSERT( ahdr->avp_value );
    869                                 /* Remove this value from the list */
    870                                 fd_rtd_candidate_del(rtd, (char *)ahdr->avp_value->os.data, ahdr->avp_value->os.len);
     864                                /* Remove this value from the list. We don't need to pay special attention to the contents here. */
     865                                fd_rtd_candidate_del(rtd, ahdr->avp_value->os.data, ahdr->avp_value->os.len);
    871866                        }
    872867
     
    876871        }
    877872
    878         /* Note: we reset the scores and pass the message to the callbacks, maybe we could re-use the saved scores when we have received an error ? */
     873        /* Note: we reset the scores and pass the message to the callbacks, maybe we could re-use the saved scores when we have received an error ? -- TODO */
    879874
    880875        /* Ok, we have our list in rtd now, let's (re)initialize the scores */
     
    928923
    929924                /* Search for the peer */
    930                 CHECK_FCT( fd_peer_getbyid( c->diamid, (void *)&peer ) );
    931 
    932                 fd_cpu_flush_cache();
    933                 if (peer && (peer->p_hdr.info.runtime.pir_state == STATE_OPEN)) {
     925                CHECK_FCT( fd_peer_getbyid( c->diamid, c->diamidlen, 0, (void *)&peer ) );
     926
     927                if (fd_peer_getstate(peer) == STATE_OPEN) {
    934928                        /* Send to this one */
    935929                        CHECK_FCT_DO( fd_out_send(pmsg, NULL, peer, 0), continue );
     
    964958/* Control of the threads */
    965959static enum { RUN = 0, STOP = 1 } order_val = RUN;
    966 static pthread_mutex_t order_lock = PTHREAD_MUTEX_INITIALIZER;
     960static pthread_mutex_t order_state_lock = PTHREAD_MUTEX_INITIALIZER;
    967961
    968962/* Threads report their status */
     
    970964static void cleanup_state(void * state_loc)
    971965{
    972         if (state_loc)
    973                 *(enum thread_state *)state_loc = NOTRUNNING;
     966        CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), );
     967        *(enum thread_state *)state_loc = NOTRUNNING;
     968        CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), );
    974969}
    975970
     
    991986       
    992987        /* Mark the thread running */
     988        CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), );
    993989        *(enum thread_state *)arg = RUNNING;
    994         fd_cpu_flush_cache();
     990        CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), );
    995991       
    996992        do {
     
    1000996                {
    1001997                        int must_stop;
    1002                         CHECK_POSIX_DO( pthread_mutex_lock(&order_lock), { ASSERT(0); } ); /* we lock to flush the caches */
     998                        CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), { ASSERT(0); } ); /* we lock to flush the caches */
    1003999                        must_stop = (order_val == STOP);
    1004                         CHECK_POSIX_DO( pthread_mutex_unlock(&order_lock), { ASSERT(0); } );
     1000                        CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), { ASSERT(0); } );
    10051001                        if (must_stop)
    10061002                                goto end;
     
    10141010                {
    10151011                        int ret;
    1016                         ret = fd_fifo_get ( queue, &msg );
     1012                        struct timespec ts;
     1013                       
     1014                        CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), goto fatal_error );
     1015                        ts.tv_sec += 1;
     1016                       
     1017                        ret = fd_fifo_timedget ( queue, &msg, &ts );
     1018                        if (ret == ETIMEDOUT)
     1019                                /* loop, check if the thread must stop now */
     1020                                continue;
    10171021                        if (ret == EPIPE)
    10181022                                /* The queue was destroyed, we are probably exiting */
     
    11001104        CHECK_FCT( fd_rt_out_register( dont_send_if_no_common_app, NULL, 10, NULL ) );
    11011105        CHECK_FCT( fd_rt_out_register( score_destination_avp, NULL, 10, NULL ) );
     1106       
     1107        TODO("built-in callbacks for Redirect messages?");
     1108       
    11021109        return 0;
    11031110}
     
    11061113int fd_rtdisp_cleanstop(void)
    11071114{
    1108         CHECK_POSIX( pthread_mutex_lock(&order_lock) );
     1115        CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), );
    11091116        order_val = STOP;
    1110         CHECK_POSIX( pthread_mutex_unlock(&order_lock) );
     1117        CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), );
    11111118
    11121119        return 0;
     
    11171124        TRACE_ENTRY("%p %p", st, thr);
    11181125        CHECK_PARAMS_DO(st && thr, return);
     1126        int terminated;
     1127       
     1128        CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), );
     1129        terminated = (*st == NOTRUNNING);
     1130        CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), );
     1131       
    11191132
    11201133        /* Wait for a second for the thread to complete, by monitoring my_state */
    1121         fd_cpu_flush_cache();
    1122         if (*st != NOTRUNNING) {
     1134        if (!terminated) {
    11231135                TRACE_DEBUG(INFO, "Waiting for the %s thread to have a chance to terminate", th_name);
    11241136                do {
     
    11311143                       
    11321144                        while (TS_IS_INFERIOR( &ts, &ts_final )) {
    1133                                 fd_cpu_flush_cache();
    1134                                 if (*st == NOTRUNNING)
     1145                       
     1146                                CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), );
     1147                                terminated = (*st == NOTRUNNING);
     1148                                CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), );
     1149                                if (terminated)
    11351150                                        break;
    11361151                               
  • libfdcore/sctp.c

    r691 r706  
    999999
    10001000/* Send a buffer over a specified stream */
    1001 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len, uint32_t * cc_status)
     1001int fd_sctp_sendstr(struct cnxctx * conn, uint16_t strid, uint8_t * buf, size_t len)
    10021002{
    10031003        struct msghdr mhdr;
     
    10091009        int timedout = 0;
    10101010       
    1011         TRACE_ENTRY("%d %hu %p %zd %p", sock, strid, buf, len, cc_status);
    1012         CHECK_PARAMS(cc_status);
     1011        TRACE_ENTRY("%p %hu %p %zd", conn, strid, buf, len);
     1012        CHECK_PARAMS(conn && buf && len);
    10131013       
    10141014        memset(&mhdr, 0, sizeof(mhdr));
     
    10371037        mhdr.msg_controllen = sizeof(anci);
    10381038       
    1039         TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock);
     1039        TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, conn->cc_socket);
    10401040again: 
    1041         ret = sendmsg(sock, &mhdr, 0);
     1041        ret = sendmsg(conn->cc_socket, &mhdr, 0);
    10421042        /* Handle special case of timeout */
    10431043        if ((ret < 0) && (errno == EAGAIN)) {
    1044                 if (!(*cc_status & CC_STATUS_CLOSING))
     1044                if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
    10451045                        goto again; /* don't care, just ignore */
    10461046                if (!timedout) {
     
    10571057
    10581058/* Receive the next data from the socket, or next notification */
    1059 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event, uint32_t * cc_status)
     1059int fd_sctp_recvmeta(struct cnxctx * conn, uint16_t * strid, uint8_t ** buf, size_t * len, int *event)
    10601060{
    10611061        ssize_t                  ret = 0;
     
    10681068        int                      timedout = 0;
    10691069       
    1070         TRACE_ENTRY("%d %p %p %p %p %p", sock, strid, buf, len, event, cc_status);
    1071         CHECK_PARAMS( (sock > 0) && buf && len && event && cc_status );
     1070        TRACE_ENTRY("%p %p %p %p %p", conn, strid, buf, len, event);
     1071        CHECK_PARAMS( conn && buf && len && event );
    10721072       
    10731073        /* Cleanup out parameters */
     
    10981098again:
    10991099        pthread_cleanup_push(free, data);
    1100         ret = recvmsg(sock, &mhdr, 0);
     1100        ret = recvmsg(conn->cc_socket, &mhdr, 0);
    11011101        pthread_cleanup_pop(0);
    11021102       
    11031103        /* First, handle timeouts (same as fd_cnx_s_recv) */
    11041104        if ((ret < 0) && (errno == EAGAIN)) {
    1105                 if (!(*cc_status & CC_STATUS_CLOSING))
     1105                if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
    11061106                        goto again; /* don't care, just ignore */
    11071107                if (!timedout) {
     
    11321132                union sctp_notification * notif = (union sctp_notification *) data;
    11331133               
    1134                 TRACE_DEBUG(FULL, "Received %db data of notification on socket %d", datasize, sock);
     1134                TRACE_DEBUG(FULL, "Received %db data of notification on socket %d", datasize, conn->cc_socket);
    11351135       
    11361136                switch (notif->sn_header.sn_type) {
     
    12261226                        *strid = sndrcv->sinfo_stream;
    12271227                }
    1228                 TRACE_DEBUG(FULL, "Received %db data on socket %d, stream %hu", datasize, sock, *strid);
     1228                TRACE_DEBUG(FULL, "Received %db data on socket %d, stream %hu", datasize, conn->cc_socket, *strid);
    12291229        } else {
    1230                 TRACE_DEBUG(FULL, "Received %db data on socket %d (stream ignored)", datasize, sock);
     1230                TRACE_DEBUG(FULL, "Received %db data on socket %d (stream ignored)", datasize, conn->cc_socket);
    12311231        }
    12321232       
  • libfdcore/sctps.c

    r662 r706  
    5757*/
    5858
    59 
     59/* TODO: change this whole wrapper to DTLS which should not require many different threads */
    6060
    6161/*************************************************************/
     
    8383       
    8484        ASSERT( conn->cc_proto == IPPROTO_SCTP );
    85         ASSERT( Target_Queue(conn) );
     85        ASSERT( fd_cnx_target_queue(conn) );
    8686        ASSERT( conn->cc_sctps_data.array );
    8787       
    8888        do {
    89                 fd_cpu_flush_cache();
    90                 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, &strid, &buf, &bufsz, &event, &conn->cc_status), goto fatal );
     89                CHECK_FCT_DO( fd_sctp_recvmeta(conn, &strid, &buf, &bufsz, &event), goto fatal );
    9190                switch (event) {
    9291                        case FDEVP_CNX_MSG_RECV:
     
    102101                        case FDEVP_CNX_EP_CHANGE:
    103102                                /* Send this event to the target queue */
    104                                 fd_cpu_flush_cache();
    105                                 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto fatal );
     103                                CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, bufsz, buf), goto fatal );
    106104                                break;
    107105                       
     
    144142        CHECK_PARAMS_DO(ctx && ctx->raw_recv && ctx->parent, goto error);
    145143        cnx = ctx->parent;
    146         ASSERT( Target_Queue(cnx) );
     144        ASSERT( fd_cnx_target_queue(cnx) );
    147145       
    148146        /* Set the thread name */
     
    173171        CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } );
    174172       
    175         fd_cpu_flush_cache();
    176         CHECK_FCT_DO( fd_sctp_sendstr(ctx->parent->cc_socket, ctx->strid, (uint8_t *)data, len, &ctx->parent->cc_status), /* errno is already set */ return -1 );
     173        CHECK_FCT_DO( fd_sctp_sendstr(ctx->parent, ctx->strid, (uint8_t *)data, len), /* errno is already set */ return -1 );
    177174       
    178175        return len;
     
    306303                struct sr_data * sr = (struct sr_data *)ret;
    307304               
    308                 if ( key.size < sr->key.size )
    309                         break;
    310                
    311                 if ( key.size > sr->key.size )
    312                         continue;
    313                
    314                 /* Key sizes are equal */
    315                 cmp = memcmp( key.data, sr->key.data, key.size );
    316                
     305                cmp = fd_os_cmp(key.data, key.size, sr->key.data, sr->key.size);
    317306                if (cmp > 0)
    318307                        continue;
     
    627616        /* End all TLS sessions, in series (not as efficient as paralel, but simpler) */
    628617        for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
    629                 fd_cpu_flush_cache();
    630                 if ( ! (conn->cc_status & CC_STATUS_ERROR)) {
     618                if ( ! fd_cnx_teststate(conn, CC_STATUS_ERROR)) {
    631619                        CHECK_GNUTLS_DO( gnutls_bye(conn->cc_sctps_data.array[i].session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
    632620                }
  • libfdcore/server.c

    r691 r706  
    4141/* We don't need to protect this list, it is only accessed from the main framework thread. */
    4242
     43enum s_state {
     44        NOT_CREATED=0,
     45        RUNNING,
     46        TERMINATED,
     47        ERROR   /* an error occurred, this is not a valid status */
     48};
     49
    4350/* Servers information */
    4451struct server {
     
    5057       
    5158        pthread_t       thr;            /* The thread listening for new connections */
    52         int             status;         /* 0 : not created; 1 : running; 2 : terminated */
     59        enum s_state    state;          /* state of the thread */
    5360       
    5461        struct fd_list  clients;        /* List of clients connected to this server, not yet identified */
    5562        pthread_mutex_t clients_mtx;    /* Mutex to protect the list of clients */
    5663};
     64
    5765
    5866/* Client information (connecting peer for which we don't have the CER yet) */
     
    6573
    6674
     75
     76/* Micro functions to read/change the status thread-safely */
     77static pthread_mutex_t s_lock = PTHREAD_MUTEX_INITIALIZER;
     78static enum s_state get_status(struct server * s)
     79{
     80        enum s_state r;
     81        CHECK_POSIX_DO( pthread_mutex_lock(&s_lock), return ERROR );
     82        r = s->state;
     83        CHECK_POSIX_DO( pthread_mutex_unlock(&s_lock), return ERROR );
     84        return r;
     85}
     86static void set_status(struct server * s, enum s_state st)
     87{
     88        CHECK_POSIX_DO( pthread_mutex_lock(&s_lock), return );
     89        s->state = st;
     90        CHECK_POSIX_DO( pthread_mutex_unlock(&s_lock), return );
     91}
     92       
     93
     94
    6795/* Dump all servers information */
    6896void fd_servers_dump()
     
    73101        for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) {
    74102                struct server * s = (struct server *)li;
    75                 fd_cpu_flush_cache();
     103                enum s_state st = get_status(s);
    76104                fd_log_debug("  Serv %p '%s': %s, %s, %s\n",
    77105                                s, fd_cnx_getid(s->conn),
    78106                                IPPROTO_NAME( s->proto ),
    79107                                s->secur ? "Secur" : "NotSecur",
    80                                 (s->status == 0) ? "Thread not created" :
    81                                 ((s->status == 1) ? "Thread running" :
    82                                 ((s->status == 2) ? "Thread terminated" :
     108                                (st == NOT_CREATED) ? "Thread not created" :
     109                                ((st == RUNNING) ? "Thread running" :
     110                                ((st == TERMINATED) ? "Thread terminated" :
    83111                                                          "Thread status unknown")));
    84112                /* Dump the client list of this server */
     
    192220        CHECK_PARAMS_DO(s, goto error);
    193221        fd_log_threadname ( fd_cnx_getid(s->conn) );
    194         s->status = 1;
    195         fd_cpu_flush_cache();
     222        set_status(s, RUNNING);
    196223       
    197224        /* Accept incoming connections */
     
    225252error: 
    226253        if (s)
    227                 s->status = 2;
     254                set_status(s, TERMINATED);
    228255        /* Send error signal to the daemon */
    229256        TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating...");
     
    266293               
    267294                /* Create the server on unsecure port */
    268                 CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 0) );
    269                 CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port, FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints) ? NULL : &fd_g_config->cnf_endpoints) );
    270                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    271                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     295                if (fd_g_config->cnf_port) {
     296                        CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 0) );
     297                        CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port, empty_conf_ep ? NULL : &fd_g_config->cnf_endpoints) );
     298                        fd_list_insert_before( &FD_SERVERS, &s->chain );
     299                        CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     300                }
    272301               
    273302                /* Create the server on secure port */
    274                 CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 1) );
    275                 CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port_tls, FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints) ? NULL : &fd_g_config->cnf_endpoints) );
    276                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    277                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     303                if (fd_g_config->cnf_port_tls) {
     304                        CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 1) );
     305                        CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port_tls, empty_conf_ep ? NULL : &fd_g_config->cnf_endpoints) );
     306                        fd_list_insert_before( &FD_SERVERS, &s->chain );
     307                        CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     308                }
    278309               
    279310#endif /* DISABLE_SCTP */
     
    287318                        if (!fd_g_config->cnf_flags.no_ip4) {
    288319                               
    289                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
    290                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET, NULL) );
    291                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    292                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    293 
    294                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
    295                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET, NULL) );
    296                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    297                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     320                                if (fd_g_config->cnf_port) {
     321                                        CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
     322                                        CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET, NULL) );
     323                                        fd_list_insert_before( &FD_SERVERS, &s->chain );
     324                                        CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     325                                }
     326
     327                                if (fd_g_config->cnf_port_tls) {
     328                                        CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
     329                                        CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET, NULL) );
     330                                        fd_list_insert_before( &FD_SERVERS, &s->chain );
     331                                        CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     332                                }
    298333                        }
     334                       
    299335                        /* Bind TCP servers on [::] */
    300336                        if (!fd_g_config->cnf_flags.no_ip6) {
    301                                
    302                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
    303                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET6, NULL) );
    304                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    305                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    306 
    307                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
    308                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET6, NULL) );
    309                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    310                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     337
     338                                if (fd_g_config->cnf_port) {
     339                                        CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
     340                                        CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET6, NULL) );
     341                                        fd_list_insert_before( &FD_SERVERS, &s->chain );
     342                                        CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     343                                }
     344
     345                                if (fd_g_config->cnf_port_tls) {
     346                                        CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
     347                                        CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET6, NULL) );
     348                                        fd_list_insert_before( &FD_SERVERS, &s->chain );
     349                                        CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     350                                }
    311351                        }
    312352                } else {
     
    323363                                        continue;
    324364                               
    325                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
    326                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, sa->sa_family, ep) );
    327                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    328                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
    329 
    330                                 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
    331                                 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, sa->sa_family, ep) );
    332                                 fd_list_insert_before( &FD_SERVERS, &s->chain );
    333                                 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     365                                if (fd_g_config->cnf_port) {
     366                                        CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) );
     367                                        CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, sa->sa_family, ep) );
     368                                        fd_list_insert_before( &FD_SERVERS, &s->chain );
     369                                        CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     370                                }
     371
     372                                if (fd_g_config->cnf_port_tls) {
     373                                        CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) );
     374                                        CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, sa->sa_family, ep) );
     375                                        fd_list_insert_before( &FD_SERVERS, &s->chain );
     376                                        CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
     377                                }
    334378                        }
    335379                }
    336380        }
    337381       
    338         /* Now, if we still have not got the list of local adresses, try to read it from the kernel directly */
    339         if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
     382        /* Now, if we had an empty list of local adresses (no address configured), try to read the real addresses from the kernel */
     383        if (empty_conf_ep) {
    340384                CHECK_FCT(fd_cnx_get_local_eps(&fd_g_config->cnf_endpoints));
    341385                if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
    342                         TRACE_DEBUG(INFO, "Unable to find the addresses of the local system. Please use \"ListenOn\" parameter in the configuration.");
     386                        TRACE_DEBUG(INFO, "Unable to find the address(es) of the local system.\n"
     387                                        "Please use \"ListenOn\" parameter in the configuration.\n"
     388                                        "This information is required to generate the CER/CEA messages.\n");
    343389                        return EINVAL;
    344390                }
Note: See TracChangeset for help on using the changeset viewer.