Changeset 706:4ffbc9f1e922 in freeDiameter for libfdcore
- Timestamp:
- Feb 9, 2011, 3:26:58 PM (13 years ago)
- Branch:
- default
- Phase:
- public
- Location:
- libfdcore
- Files:
-
- 21 edited
Legend:
- Unmodified
- Added
- Removed
-
libfdcore/cnxctx.c
r662 r706 51 51 */ 52 52 53 /* Note: this file could be moved to libfreeDiameter instead, but since it uses gnuTLS we prefer to keep it in the daemon */54 55 53 /* Lifetime of a cnxctx object: 56 54 * 1) Creation … … 158 156 TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled..."); 159 157 ASSERT(0); 160 CHECK_FCT_DO( ENOTSUP, ); 161 return NULL; 158 CHECK_FCT_DO( ENOTSUP, return NULL); 162 159 #else /* DISABLE_SCTP */ 163 160 struct cnxctx * cnx = NULL; … … 249 246 int rc; 250 247 251 /* Numeric values for debug */252 248 rc = getnameinfo((sSA *)&ss, sSAlen(&ss), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); 253 249 if (rc) { … … 256 252 } 257 253 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 */ 263 260 rc = getnameinfo((sSA *)&ss, sSAlen(&ss), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0); 264 261 if (rc) … … 334 331 int rc; 335 332 336 /* Numeric values for debug */333 /* Numeric values for debug... */ 337 334 rc = getnameinfo(sa, addrlen, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); 338 335 if (rc) { … … 341 338 } 342 339 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 */ 346 343 rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); 347 344 if (rc) … … 356 353 { 357 354 #ifdef DISABLE_SCTP 358 TRACE_DEBUG(INFO, "This function should never be encalled when SCTP is disabled...");355 TRACE_DEBUG(INFO, "This function should never be called when SCTP is disabled..."); 359 356 ASSERT(0); 360 CHECK_FCT_DO( ENOTSUP, ); 361 return NULL; 357 CHECK_FCT_DO( ENOTSUP, return NULL); 362 358 #else /* DISABLE_SCTP */ 363 359 int sock = 0; … … 416 412 int rc; 417 413 418 /* Numeric values for debug */414 /* Numeric values for debug... */ 419 415 rc = getnameinfo((sSA *)&primary, sSAlen(&primary), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); 420 416 if (rc) { … … 423 419 } 424 420 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 */ 428 424 rc = getnameinfo((sSA *)&primary, sSAlen(&primary), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); 429 425 if (rc) … … 454 450 455 451 /* Set the hostname to check during handshake */ 456 void fd_cnx_sethostname(struct cnxctx * conn, char *hn)452 void fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn) 457 453 { 458 454 CHECK_PARAMS_DO( conn, return ); … … 460 456 } 461 457 458 /* We share a lock with many threads but we hold it only very short time so it is OK */ 459 static pthread_mutex_t state_lock = PTHREAD_MUTEX_INITIALIZER; 460 uint32_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 } 468 int 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 } 476 void 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 } 482 void 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 462 490 /* Return the TLS state of a connection */ 463 491 int fd_cnx_getTLS(struct cnxctx * conn) 464 492 { 465 493 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 */ 498 int 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 469 508 470 509 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */ … … 508 547 } 509 548 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 */ 511 550 int fd_cnx_get_local_eps(struct fd_list * list) 512 551 { 513 552 struct ifaddrs *iflist, *cur; 553 514 554 CHECK_SYS(getifaddrs(&iflist)); 515 555 … … 543 583 CHECK_PARAMS_DO( conn, goto fatal ); 544 584 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); 546 586 547 587 /* Mark the error */ 548 fd_cpu_flush_cache(); 549 conn->cc_status |= CC_STATUS_ERROR; 588 fd_cnx_addstate(conn, CC_STATUS_ERROR); 550 589 551 590 /* 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 )) { 553 592 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 } 558 596 return; 559 597 fatal: 560 598 /* An unrecoverable error occurred, stop the daemon */ 599 ASSERT(0); 561 600 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 562 601 } … … 583 622 /* Handle special case of timeout */ 584 623 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 )) 587 625 goto again; /* don't care, just ignore */ 588 626 if (!timedout) { … … 592 630 } 593 631 594 CHECK_SYS_DO(ret, /* continue */);595 596 632 /* 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 */); 598 635 fd_cnx_markerror(conn); 636 } 599 637 600 638 return ret; … … 610 648 /* Handle special case of timeout */ 611 649 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 )) 614 651 goto again; /* don't care, just ignore */ 615 652 if (!timedout) { … … 643 680 644 681 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) ); 647 684 648 685 /* Receive from a TCP connection: we have to rebuild the message boundaries */ … … 666 703 667 704 /* Check the received word is a valid begining of a Diameter message */ 668 if ((header[0] != DIAMETER_VERSION) /* defined in <libf reeDiameter.h> */705 if ((header[0] != DIAMETER_VERSION) /* defined in <libfdproto.h> */ 669 706 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */ 670 707 /* The message is suspect */ … … 691 728 692 729 /* 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? */); 695 731 696 732 } while (conn->cc_loop); … … 726 762 727 763 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) ); 730 766 731 767 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 ); 734 769 if (event == FDEVP_CNX_ERROR) { 735 770 fd_cnx_markerror(conn); … … 742 777 } 743 778 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 ); 746 780 747 781 } while (conn->cc_loop || (event != FDEVP_CNX_MSG_RECV)); … … 763 797 TRACE_ENTRY("%p %i", conn, loop); 764 798 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)); 766 800 767 801 /* Release resources in case of a previous call was already made */ … … 803 837 switch (ret) { 804 838 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)) 807 840 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), 808 841 { … … 815 848 case GNUTLS_E_AGAIN: 816 849 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)) 819 851 goto again; 820 852 TRACE_DEBUG(FULL, "Connection is closing, so abord gnutls_record_recv now."); … … 849 881 switch (ret) { 850 882 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)) 853 884 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), 854 885 { … … 861 892 case GNUTLS_E_AGAIN: 862 893 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)) 865 895 goto again; 866 896 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now."); … … 927 957 928 958 /* 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), 931 960 { 932 961 free(newmsg); … … 956 985 } 957 986 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) ); 960 989 961 990 /* The next function only returns when there is an error on the socket */ … … 1215 1244 { 1216 1245 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) ); 1218 1247 1219 1248 /* Save the mode */ … … 1248 1277 1249 1278 /* 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 1253 1281 /* Handshake master session */ 1254 1282 { … … 1299 1327 { 1300 1328 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 ); 1302 1330 1303 1331 /* This function only works for X.509 certificates. */ … … 1360 1388 } 1361 1389 1390 /* Where the events are sent */ 1391 struct 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 1362 1400 /* Set an alternate FIFO list to send FDEVP_CNX_* events to */ 1363 1401 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo) 1364 1402 { 1403 int ret; 1365 1404 TRACE_ENTRY( "%p %p", conn, alt_fifo ); 1366 1405 CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming ); 1367 1406 1368 1407 /* 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; 1372 1413 } 1373 1414 … … 1379 1420 TRACE_ENTRY("%p %p %zd", conn, buf, len); 1380 1421 do { 1381 fd_cpu_flush_cache(); 1382 if (conn->cc_status & CC_STATUS_TLS) { 1422 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) { 1383 1423 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), ); 1384 1424 } else { … … 1394 1434 } 1395 1435 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. */ 1397 1437 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len, uint32_t flags) 1398 1438 { 1399 1439 TRACE_ENTRY("%p %p %zd %x", conn, buf, len, flags); 1400 1440 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); 1404 1444 1405 1445 switch (conn->cc_proto) { … … 1410 1450 #ifndef DISABLE_SCTP 1411 1451 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 1438 1452 if (flags & FD_CNX_ORDERED) { 1439 1453 /* We send over stream #0 */ … … 1444 1458 int another_str = 0; /* do we send over stream #0 ? */ 1445 1459 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))) { 1447 1461 /* Update the id of the stream we will send this message over */ 1448 1462 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); 1450 1464 another_str = (conn->cc_sctp_para.next ? 1 : 0); 1451 1465 } … … 1454 1468 CHECK_FCT( send_simple(conn, buf, len) ); 1455 1469 } 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; } ); 1458 1472 } else { 1459 1473 /* push the record to the appropriate session */ … … 1496 1510 CHECK_PARAMS_DO(conn, return); 1497 1511 1498 fd_cpu_flush_cache(); 1499 conn->cc_status |= CC_STATUS_CLOSING; 1512 fd_cnx_addstate(conn, CC_STATUS_CLOSING); 1500 1513 1501 1514 /* 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)) { 1503 1516 #ifndef DISABLE_SCTP 1504 1517 if (conn->cc_sctp_para.pairs > 1) { 1505 if (! (conn->cc_status &CC_STATUS_ERROR )) {1518 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR )) { 1506 1519 /* Bye on master session */ 1507 1520 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) ); 1508 1521 } 1509 1522 1510 if (! (conn->cc_status &CC_STATUS_ERROR ) ) {1523 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) { 1511 1524 /* and other stream pairs */ 1512 1525 fd_sctps_bye(conn); 1513 1526 } 1514 1527 1515 if (! (conn->cc_status &CC_STATUS_ERROR ) ) {1528 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) { 1516 1529 /* Now wait for all decipher threads to terminate */ 1517 1530 fd_sctps_waitthreadsterm(conn); … … 1533 1546 } else { 1534 1547 #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 ) ) { 1537 1550 /* Master session */ 1538 1551 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) ); 1539 1552 } 1540 1553 1541 if (! (conn->cc_status &CC_STATUS_ERROR ) ) {1554 if (! fd_cnx_teststate(conn, CC_STATUS_ERROR ) ) { 1542 1555 /* In this case, just wait for thread rcvthr_tls_single to terminate */ 1543 1556 if (conn->cc_rcvthr != (pthread_t)NULL) { … … 1555 1568 conn->cc_tls_para.session = NULL; 1556 1569 } 1557 1558 1570 #ifndef DISABLE_SCTP 1559 1571 } -
libfdcore/cnxctx.h
r662 r706 48 48 int cc_family; /* AF_INET or AF_INET6 (mixed) */ 49 49 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() */ 51 52 #define CC_STATUS_CLOSING 1 52 53 #define CC_STATUS_ERROR 2 … … 59 60 struct fifo * cc_incoming; /* FIFO queue of events received on the connection, FDEVP_CNX_* */ 60 61 struct fifo * cc_alt; /* alternate fifo to send FDEVP_CNX_* events to. */ 61 #define Target_Queue(cnx) ((cnx)->cc_alt ?: (cnx)->cc_incoming)62 62 63 63 /* If cc_tls == true */ 64 64 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 */ 66 66 int mode; /* GNUTLS_CLIENT / GNUTLS_SERVER */ 67 67 gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */ … … 84 84 85 85 void fd_cnx_markerror(struct cnxctx * conn); 86 uint32_t fd_cnx_getstate(struct cnxctx * conn); 87 int fd_cnx_teststate(struct cnxctx * conn, uint32_t flag); 88 void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate); 89 void fd_cnx_setstate(struct cnxctx * conn, uint32_t abstate); 90 struct fifo * fd_cnx_target_queue(struct cnxctx * conn); 91 86 92 87 93 /* Socket */ … … 109 115 int fd_sctp_get_remote_ep(int sock, struct fd_list * list); 110 116 int 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);117 int fd_sctp_sendstr(struct cnxctx * conn, uint16_t strid, uint8_t * buf, size_t len); 118 int fd_sctp_recvmeta(struct cnxctx * conn, uint16_t * strid, uint8_t ** buf, size_t * len, int *event); 113 119 114 120 /* TLS over SCTP (multi-stream) */ -
libfdcore/config.c
r686 r706 146 146 { 147 147 extern FILE * fddin; 148 char * orig = NULL; 148 149 149 150 /* Attempt to find the configuration file */ … … 154 155 if ((fddin == NULL) && (*fd_g_config->cnf_file != '/')) { 155 156 /* 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 ); 159 160 fddin = fopen(fd_g_config->cnf_file, "r"); 160 161 } 161 162 if (fddin == NULL) { 162 163 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 } 164 173 return ret; 165 174 } … … 178 187 } 179 188 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 180 203 /* Resolve hostname if not provided */ 181 204 if (fd_g_config->cnf_diamid == NULL) { 182 #ifndef HOST_NAME_MAX183 #define HOST_NAME_MAX 1024184 #endif /* HOST_NAME_MAX */185 205 char buf[HOST_NAME_MAX + 1]; 186 206 struct addrinfo hints, *info; … … 202 222 return EINVAL; 203 223 } 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) ); 205 226 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 } 210 230 211 231 /* Handle the realm part */ … … 220 240 fd_g_config->cnf_diamid); 221 241 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 } 227 249 228 250 /* Validate some flags */ -
libfdcore/core.c
r693 r706 45 45 GCRY_THREAD_OPTION_PTHREAD_IMPL; 46 46 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()) */ 48 48 static int is_ready = 0; 49 49 static pthread_mutex_t is_ready_mtx = PTHREAD_MUTEX_INITIALIZER; … … 62 62 /* Thread that process incoming events on the main queue -- and terminates the framework when requested */ 63 63 static pthread_t core_runner = (pthread_t)NULL; 64 65 /* How the thread is terminated */ 64 66 enum core_mode { 65 67 CORE_MODE_EVENTS, -
libfdcore/extensions.c
r695 r706 57 57 struct fd_ext_info * new; 58 58 59 TRACE_ENTRY("%p (%s) %p(%s)", filename, filename?filename:"", conffile, conffile?conffile:"");59 TRACE_ENTRY("%p %p", filename, conffile); 60 60 61 61 /* Check the filename is valid */ … … 106 106 ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL); 107 107 #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 */ 109 109 ext->handler = dlopen(ext->filename, RTLD_NOW | RTLD_GLOBAL); 110 110 #endif /* DEBUG */ -
libfdcore/fdcore-internal.h
r662 r706 138 138 char *p_dbgorig; 139 139 140 /* State of the peer, and its lock */ 141 enum peer_state p_state; 142 pthread_mutex_t p_state_mtx; 143 140 144 /* Chaining in peers sublists */ 141 145 struct fd_list p_actives; /* list of peers in the STATE_OPEN state -- used by routing */ … … 147 151 unsigned pf_responder : 1; /* The peer has been created to handle incoming connection */ 148 152 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 */ 149 154 150 155 unsigned pf_dw_pending : 1; /* A DWR message was sent and not answered yet */ … … 192 197 #define CHECK_PEER( _p ) \ 193 198 (((_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 194 202 195 203 /* Events codespace for struct fd_peer->p_events */ … … 308 316 int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer); 309 317 int fd_p_dp_initiate(struct fd_peer * peer, char * reason); 318 int fd_p_dp_newdelay(struct fd_peer * peer); 310 319 311 320 /* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */ … … 327 336 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list); 328 337 int fd_cnx_start_clear(struct cnxctx * conn, int loop); 329 void fd_cnx_sethostname(struct cnxctx * conn, char *hn);338 void fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn); 330 339 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds); 331 340 char * fd_cnx_getid(struct cnxctx * conn); 332 341 int fd_cnx_getproto(struct cnxctx * conn); 333 342 int fd_cnx_getTLS(struct cnxctx * conn); 343 int fd_cnx_isMultichan(struct cnxctx * conn); 334 344 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size); 335 345 int fd_cnx_get_local_eps(struct fd_list * list); … … 343 353 /* Flags for the fd_cnx_send function : */ 344 354 #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 */346 355 347 356 #endif /* _FDCORE_INTERNAL_H */ -
libfdcore/fdd.y
r662 r706 236 236 appservthreads: APPSERVTHREADS '=' INTEGER ';' 237 237 { 238 CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1024),238 CHECK_PARAMS_DO( ($3 > 0) && ($3 < 256), 239 239 { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); 240 240 conf->cnf_dispthr = (uint16_t)$3; -
libfdcore/messages.c
r688 r706 36 36 #include "fdcore-internal.h" 37 37 38 static struct dict_object * dict_avp_SI = NULL; /* Session-Id */ 38 39 static struct dict_object * dict_avp_OH = NULL; /* Origin-Host */ 39 40 static struct dict_object * dict_avp_OR = NULL; /* Origin-Realm */ … … 54 55 55 56 /* 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) ); 56 58 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &dict_avp_OH , ENOENT) ); 57 59 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &dict_avp_OR , ENOENT) ); … … 89 91 /* Set its value */ 90 92 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; 92 94 val.os.len = fd_g_config->cnf_diamid_len; 93 95 CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) ); … … 102 104 /* Set its value */ 103 105 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; 105 107 val.os.len = fd_g_config->cnf_diamrlm_len; 106 108 CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) ); … … 124 126 return 0; 125 127 } 128 129 /* Create a new Session-Id and add at the beginning of the message. */ 130 int 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 126 165 127 166 /* Add Result-Code and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */ … … 147 186 memset(&req, 0, sizeof(struct dict_enumval_request)); 148 187 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) */ 150 189 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) ); 151 190 … … 184 223 /* Set its value */ 185 224 memset(&val, 0, sizeof(val)); 186 val.os.data = (u nsigned char*)fd_g_config->cnf_diamid;225 val.os.data = (uint8_t *)fd_g_config->cnf_diamid; 187 226 val.os.len = fd_g_config->cnf_diamid_len; 188 227 CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) ); … … 246 285 247 286 if (errormsg) { 248 val.os.data = (u nsigned char*)errormsg;287 val.os.data = (uint8_t *)errormsg; 249 288 val.os.len = strlen(errormsg); 250 289 } else { 251 val.os.data = (u nsigned char*)rescode;290 val.os.data = (uint8_t *)rescode; 252 291 val.os.len = strlen(rescode); 253 292 } … … 311 350 if ((ret != EBADMSG) /* Parsing grouped AVP failed / Conflicting rule found */ 312 351 && (ret != ENOTSUP)) /* Command is not supported / Mandatory AVP is not supported */ 313 return ret; 352 return ret; /* 0 or another error */ 314 353 315 354 TRACE_DEBUG(INFO, "A message does not comply to the dictionary and/or rules (%s)", pei.pei_errcode); -
libfdcore/p_ce.c
r688 r706 38 38 /* This file contains code to handle Capabilities Exchange messages (CER and CEA) and election process */ 39 39 40 /* Compilation option:41 USE_CEA_BROADCAST42 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 stream44 than the CEA, it might be delivered first and thus ignored.45 */46 47 40 /* Save a connection as peer's principal */ 48 41 static int set_peer_cnx(struct fd_peer * peer, struct cnxctx **cnx) … … 88 81 } 89 82 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 */ 91 84 static __inline__ int election_result(struct fd_peer * peer) 92 85 { … … 245 238 static void cleanup_remote_CE_info(struct fd_peer * peer) 246 239 { 240 /* free linked information */ 247 241 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;251 242 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;256 243 while (!FD_IS_LIST_EMPTY(&peer->p_hdr.info.runtime.pir_apps)) { 257 244 struct fd_list * li = peer->p_hdr.info.runtime.pir_apps.next; … … 259 246 free(li); 260 247 } 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 ); 263 258 } 264 259 265 260 /* 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)261 static int save_remote_CE_info(struct msg * msg, struct fd_peer * peer, struct fd_pei * error, uint32_t *rc) 267 262 { 268 263 struct avp * avp = NULL; … … 309 304 310 305 /* 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)) { 313 308 TRACE_DEBUG(INFO, "Received a message with Origin-Host set to '%.*s' while expecting '%s'\n", 314 309 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; 316 313 return EINVAL; 317 314 } … … 330 327 /* In case of multiple AVPs */ 331 328 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; 339 347 break; 340 348 … … 352 360 /* Get the sockaddr value */ 353 361 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 } ); 355 369 356 370 /* Save this endpoint in the list as advertized */ … … 370 384 /* In case of multiple AVPs */ 371 385 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; 374 391 } 375 392 … … 388 405 /* In case of multiple AVPs */ 389 406 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; 392 412 } 393 413 … … 407 427 /* In case of multiple AVPs */ 408 428 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; 411 434 } 412 435 … … 423 446 } 424 447 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 */ 426 452 break; 427 453 … … 477 503 TRACE_DEBUG(FULL, "Invalid Vendor-Specific-Application-Id AVP received, ignored"); 478 504 fd_msg_dump_one(FULL, avp); 505 error->pei_errcode = "ER_DIAMETER_INVALID_AVP_VALUE"; 506 error->pei_avp = avp; 507 return EINVAL; 479 508 } else { 480 509 /* Add an entry in the list */ … … 510 539 511 540 if (hdr->avp_value->u32 == AI_RELAY) { 541 /* Not clear if the relay application can be inside this AVP... */ 512 542 peer->p_hdr.info.runtime.pir_relay = 1; 513 543 } else { 514 /* Not clear if the relay application can be inside this AVP... */515 544 CHECK_FCT( fd_app_merge(&peer->p_hdr.info.runtime.pir_apps, hdr->avp_value->u32, 0, 0, 1) ); 516 545 } … … 537 566 goto next; 538 567 } 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 } 540 574 peer->p_hdr.info.runtime.pir_isi |= (1 << hdr->avp_value->u32); 541 575 break; … … 559 593 CHECK_FCT( fd_msg_new ( fd_dict_cmd_CER, MSGFL_ALLOC_ETEID, cer ) ); 560 594 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... */ 562 596 if (!fd_cnx_getTLS(cnx)) { 563 isi_none = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE; /* we add it even t 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 */ 564 598 isi_tls = peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD; 565 599 } … … 587 621 588 622 /* Reject an incoming connection attempt */ 589 static void receiver_reject(struct cnxctx * recv_cnx, struct msg ** cer, char * rescode, char * errormsg)623 static void receiver_reject(struct cnxctx ** recv_cnx, struct msg ** cer, struct fd_pei * error) 590 624 { 591 625 /* Create and send the CEA with appropriate error code */ 592 626 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 ); 595 629 596 630 /* And now destroy this connection */ 597 631 destroy: 598 fd_cnx_destroy(recv_cnx); 632 fd_cnx_destroy(*recv_cnx); 633 *recv_cnx = NULL; 599 634 if (*cer) { 600 635 fd_msg_log(FD_MSG_LOG_DROPPED, *cer, "An error occurred while rejecting a CER."); … … 614 649 615 650 /* 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) { 618 652 if (election_result(peer)) { 619 653 /* Close initiator connection */ … … 624 658 625 659 } else { 660 struct fd_pei pei; 661 memset(&pei, 0, sizeof(pei)); 662 pei.pei_errcode = "ELECTION_LOST"; 626 663 627 664 /* 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); 630 666 CHECK_FCT( to_waitcea(peer, initiator) ); 631 667 } … … 641 677 int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer) 642 678 { 643 char * ec;644 679 uint32_t rc = 0; 680 int st; 681 struct fd_pei pei; 682 645 683 TRACE_ENTRY("%p %p", msg, peer); 646 684 CHECK_PARAMS( msg && *msg && CHECK_PEER(peer) ); … … 656 694 657 695 /* 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 ) ); 659 697 660 698 /* msg now contains an answer message to send back */ … … 663 701 664 702 /* 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)) { 667 704 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)); 669 706 CHECK_FCT_DO( fd_msg_free(*msg), /* continue */); 670 707 *msg = NULL; … … 674 711 } 675 712 713 memset(&pei, 0, sizeof(pei)); 714 676 715 /* 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 ); 678 717 679 718 /* Dispose of the message, we don't need it anymore */ … … 701 740 default: 702 741 /* 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); 704 743 return EINVAL; 705 744 } … … 751 790 } 752 791 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) */ 754 793 int fd_p_ce_process_receiver(struct fd_peer * peer) 755 794 { 756 char * ec = NULL;795 struct fd_pei pei; 757 796 struct msg * msg = NULL; 758 797 int isi = 0; 759 798 int fatal = 0; 799 int tls_sync=0; 760 800 761 801 TRACE_ENTRY("%p", peer); … … 765 805 peer->p_cer = NULL; 766 806 807 memset(&pei, 0, sizeof(pei)); 808 767 809 /* 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 } 769 821 770 822 /* Validate the peer if needed */ … … 773 825 if (res < 0) { 774 826 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"; 776 828 goto error_abort; 777 829 } … … 785 837 if (!got_common) { 786 838 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"; 788 840 fatal = 1; 789 841 goto error_abort; … … 835 887 if (!isi) { 836 888 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"; 838 890 fatal = 1; 839 891 goto error_abort; … … 849 901 CHECK_FCT( fd_msg_rescode_set(msg, "DIAMETER_SUCCESS", NULL, NULL, 0 ) ); 850 902 CHECK_FCT( add_CE_info(msg, peer->p_cnxctx, isi & PI_SEC_TLS_OLD, isi & PI_SEC_NONE) ); 851 #ifdef USE_CEA_BROADCAST852 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 */854 903 CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED ) ); 855 #endif /* USE_CEA_BROADCAST */856 904 857 905 /* Handshake if needed */ … … 878 926 } ); 879 927 } 880 928 tls_sync = 1; 881 929 } else { 882 930 if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) { … … 891 939 CHECK_FCT( fd_p_dw_reopen(peer) ); 892 940 } 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 } 895 950 } 896 951 … … 898 953 899 954 error_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); 909 958 } 910 959 … … 925 974 int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid) 926 975 { 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) { 929 981 case STATE_CLOSED: 930 982 peer->p_receiver = *cnx; … … 960 1012 961 1013 /* 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); 964 1017 } 965 1018 break; 966 1019 967 1020 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); 970 1024 } 971 1025 -
libfdcore/p_cnx.c
r691 r706 36 36 #include "fdcore-internal.h" 37 37 38 39 /* TODO: change the behavior to handle properly forced ordering at beginning & end of OPEN state */ 40 38 41 /* This file contains code used by a peer state machine to initiate a connection to remote peer */ 39 42 … … 87 90 ret = getaddrinfo(peer->p_hdr.info.pi_diamid, NULL, &hints, &ai); 88 91 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)); 90 93 if (ret != EAI_AGAIN) 91 94 fd_psm_terminate( peer, NULL ); … … 123 126 /* Now check we have at least one address to attempt */ 124 127 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); 126 130 fd_psm_terminate( peer, NULL ); 127 131 return 0; … … 219 223 { 220 224 char buf[48]; 221 s printf(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); 222 226 fd_log_threadname ( buf ); 223 227 } … … 247 251 #ifndef DISABLE_SCTP 248 252 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); 250 255 break; 251 256 #endif /* DISABLE_SCTP */ … … 260 265 pthread_testcancel(); 261 266 262 } while (!cnx); /* and until cancellation */267 } while (!cnx); /* and until cancellation or all addresses attempted without success */ 263 268 264 269 /* Now, we have an established connection in cnx */ … … 274 279 { 275 280 /* 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); 277 282 fd_cnx_destroy(cnx); 278 283 empty_connection_list(peer); -
libfdcore/p_dp.c
r662 r706 38 38 /* This file contains code to handle Disconnect Peer messages (DPR and DPA) */ 39 39 40 /* Delay to use before next reconnect attempt */ 41 int 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 40 62 /* Handle a received message */ 41 63 int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer) … … 44 66 45 67 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 */ 47 69 struct avp * dc; 48 int delay = peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc;49 70 50 71 CHECK_FCT( fd_msg_search_avp ( *msg, fd_dict_avp_DC, &dc )); 51 72 if (dc) { 52 /* Check the value is consistent with the saved one */53 73 struct avp_hdr * hdr; 54 74 CHECK_FCT( fd_msg_avp_hdr( dc, &hdr ) ); … … 60 80 } 61 81 82 /* save the cause */ 62 83 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 }78 84 } 79 85 if (TRACE_BOOL(INFO)) { 80 86 if (dc) { 81 struct dict_object * dictobj = NULL;87 struct dict_object * dictobj; 82 88 struct dict_enumval_request er; 83 89 memset(&er, 0, sizeof(er)); 90 91 /* prepare the request */ 84 92 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT ) ); 85 93 er.search.enum_value.u32 = peer->p_hdr.info.runtime.pir_lastDC; 94 95 /* Search the enum value */ 86 96 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, 0 ) ); 87 97 if (dictobj) { … … 100 110 CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_SUCCESS", NULL, NULL, 1 ) ); 101 111 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...) */ 103 113 CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) ); 104 114 … … 106 116 CHECK_FCT( fd_out_send( msg, NULL, peer, FD_CNX_ORDERED) ); 107 117 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 } 114 130 } else { 115 131 /* 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)); 119 135 } 120 136 121 137 /* 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") */ 122 140 CHECK_FCT_DO( fd_msg_free( *msg ), /* continue */ ); 123 141 *msg = NULL; 124 142 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 */ 126 149 } 127 150 … … 153 176 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT ) ); 154 177 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 */ } ); 156 179 CHECK_FCT( fd_dict_getval( dictobj, &er.search ) ); 157 180 -
libfdcore/p_dw.c
r662 r706 38 38 /* This file contains code to handle Device Watchdog messages (DWR and DWA) */ 39 39 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 voidcheck_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 */ 41 static int check_state_id(struct msg * msg, struct fd_peer * peer) 42 42 { 43 43 struct avp * osi; 44 44 45 /* 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 ) ); 46 47 if (osi) { 47 48 /* Check the value is consistent with the saved one */ 48 49 struct avp_hdr * hdr; 49 CHECK_FCT _DO( fd_msg_avp_hdr( osi, &hdr ), return);50 CHECK_FCT( fd_msg_avp_hdr( osi, &hdr ) ); 50 51 if (hdr->avp_value == NULL) { 51 52 /* This is a sanity check */ … … 56 57 57 58 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", 59 60 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; 62 64 } 63 65 } 66 return 0; 64 67 } 65 68 … … 92 95 93 96 /* Check the value of OSI for information */ 94 check_state_id(*msg, peer);97 CHECK_FCT( check_state_id(*msg, peer) ); 95 98 96 99 if (req) { … … 102 105 103 106 } else { 104 /* Just discard the DWA */107 /* Discard the DWA */ 105 108 CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ ); 106 109 *msg = NULL; … … 123 126 124 127 /* 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) { 127 129 peer->p_flags.pf_reopen_cnt += 1; 128 130 -
libfdcore/p_expiry.c
r691 r706 59 59 60 60 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) 65 64 continue; 66 65 … … 78 77 /* Now delete peers that are in the purge list */ 79 78 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); 81 80 fd_list_unlink(&peer->p_hdr.chain); 82 81 TRACE_DEBUG(INFO, "Garbage Collect: delete zombie peer '%s'", peer->p_hdr.info.pi_diamid); … … 105 104 struct fd_peer * first; 106 105 107 /* Check if there are expiring sessions available */106 /* Check if there are expiring peers available */ 108 107 if (FD_IS_LIST_EMPTY(&exp_list)) { 109 108 /* Just wait for a change or cancelation */ … … 183 182 184 183 /* 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); } ); 186 185 peer->p_exp_timer.tv_sec += peer->p_hdr.info.config.pic_lft; 187 186 -
libfdcore/p_out.c
r691 r706 109 109 { 110 110 char buf[48]; 111 s printf(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); 112 112 fd_log_threadname ( buf ); 113 113 } … … 149 149 CHECK_PARAMS( msg && *msg && (cnx || (peer && peer->p_cnxctx))); 150 150 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) { 153 152 /* Normal case: just queue for the out thread to pick it up */ 154 153 CHECK_FCT( fd_fifo_post(peer->p_tosend, msg) ); -
libfdcore/p_psm.c
r691 r706 36 36 #include "fdcore-internal.h" 37 37 38 /* 39 This 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 44 The delivery of Diameter messages must not always be unordered: order is important at 45 begining and end of a connection lifetime. It means we need agility to 46 switch between "ordering enforced" and "ordering not enforced to counter 47 HotLB" modes of operation. 48 49 The connection state machine represented in RFC3588 (and rfc3588bis) is 50 incomplete, because it lacks the SUSPECT state and the 3 DWR/DWA 51 exchanges (section 5.1) when the peer recovers from this state. 52 Personnally I don't see the rationale for exchanging 3 messages (why 3?) 53 but, if we require at least 1 DWR/DWA exchange to be always performed 54 after the CER/CEA exchange (and initiated by the peer that sent the 55 CEA), we have a simple way to deal with our ordering problem, as resumed 56 bellow. 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, 63 flag "unordered" cleared. 64 [r] Move to STATE_OPEN_NEW state -- equivalent to OPEN except 65 that all messages are sent ordered at the moment. 66 (6) [i] receive CEA, move to OPEN state. All messages can be sent 67 unordered 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 70 sent unordered from this point. 71 72 Note about (5) and (6): if the Diameter Identity received in CER or CEA 73 does not match the credentials from the certificate presented during 74 DTLS handshake, we may need to specify a path of clean disconnection 75 (not blocking the remote peer waiting for something). 76 77 This proposed mechanism removes the problem of application messages 78 received before the CEA by the initiator. Note that if the "old" inband 79 TLS handshake is used, this handshake plays the same synchronization 80 role than the new DWR/DWA, which becomes useless. 81 82 83 The other time where ordering is important is by the end of connection 84 lifetime, when one peer is shutting down the link for some reason 85 (reboot, overload, no activity, etc...). In case of unordered delivery, 86 we may have: 87 - peer A sends an application message followed by a DPR. Peer B receives 88 the 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 90 DPA. Peer A receives the DPA before the application message. The 91 application message is lost. 92 93 This situation is actually quite possible because DPR/DPA messages are 94 very short, while application messages can be quite large. Therefore, 95 they require much more time to deliver. 96 97 I really cannot see a way to counter this effect by using the ordering 98 of the messages, except by applying a timer (state STATE_CLOSING_GRACE). 99 100 However, this problem must be balanced with the fact that the message 101 that is lost will be in many cases sent again as the failover mechanism 102 specifies. 103 */ 104 38 105 /* The actual declaration of peer_state_str */ 39 106 DECLARE_STATE_STR(); … … 101 168 return 0; 102 169 } 170 103 171 /* Insert in the active peers list */ 104 172 CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) ); 105 173 for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) { 106 174 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); 108 177 if (cmp < 0) 109 178 break; … … 115 184 if (peer->p_cb) { 116 185 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? */ 118 187 peer->p_cb = NULL; 119 188 peer->p_cb_data = NULL; … … 178 247 } 179 248 249 /* Read state */ 250 int 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 180 266 181 267 /* Change state */ … … 186 272 TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state)); 187 273 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); 190 276 if (old == new_state) 191 277 return 0; … … 196 282 peer->p_hdr.info.pi_diamid); 197 283 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) ); 200 288 201 289 if (old == STATE_OPEN) { … … 255 343 { 256 344 /* 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) { 259 346 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ ); 260 347 } … … 285 372 struct fd_peer * peer = (struct fd_peer *)arg; 286 373 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), ); 289 377 return; 290 378 } … … 298 386 size_t ev_sz; 299 387 void * ev_data; 388 int cur_state; 300 389 301 390 CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) ); … … 306 395 { 307 396 char buf[48]; 308 s printf(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); 309 398 fd_log_threadname ( buf ); 310 399 } 311 400 312 401 /* 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 ); 314 405 315 406 /* Wait that the PSM are authorized to start in the daemon */ … … 326 417 /* Get next event */ 327 418 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))); 329 420 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 330 426 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), 332 428 fd_pev_str(event), ev_data, ev_sz, 333 429 peer->p_hdr.info.pi_diamid); … … 336 432 337 433 /* 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 */ 341 437 342 438 /* Purge invalid events */ 343 439 if (!CHECK_PEVENT(event)) { 344 440 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 */ 345 442 goto psm_loop; 346 443 } … … 354 451 /* Requests to terminate the peer object */ 355 452 if (event == FDEVP_TERMINATE) { 356 switch ( peer->p_hdr.info.runtime.pir_state) {453 switch (cur_state) { 357 454 case STATE_OPEN: 455 case STATE_OPEN_NEW: 358 456 case STATE_REOPEN: 359 /* We cannot just close the con enction, we have to send a DPR first */457 /* We cannot just close the connection, we have to send a DPR first */ 360 458 CHECK_FCT_DO( fd_p_dp_initiate(peer, ev_data), goto psm_end ); 361 459 goto psm_loop; … … 363 461 /* 364 462 case STATE_CLOSING: 463 case STATE_CLOSING_GRACE: 365 464 case STATE_WAITCNXACK: 366 465 case STATE_WAITCNXACK_ELEC: … … 380 479 struct msg_hdr * hdr; 381 480 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 389 481 /* Parse the received buffer */ 390 482 CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg), … … 396 488 } ); 397 489 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 398 498 /* 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) ); 400 500 401 501 /* Extract the header */ … … 417 517 } 418 518 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 419 524 /* Now handle non-link-local messages */ 420 525 if (fd_msg_is_routable(msg)) { 421 switch ( peer->p_hdr.info.runtime.pir_state) {526 switch (cur_state) { 422 527 /* To maximize compatibility -- should not be a security issue here */ 423 528 case STATE_REOPEN: 424 529 case STATE_SUSPECT: 425 530 case STATE_CLOSING: 531 case STATE_CLOSING_GRACE: 426 532 TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state... "); 427 533 /* The standard situation : */ 534 case STATE_OPEN_NEW: 428 535 case STATE_OPEN: 429 536 /* We received a valid routable message, update the expiry timer */ … … 431 538 432 539 /* 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); 434 541 435 542 /* Requeue to the global incoming queue */ … … 437 544 438 545 /* 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)) { 440 547 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw); 441 548 } … … 449 556 default: 450 557 /* 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) ); 452 559 fd_msg_free(msg); 453 560 } … … 485 592 case CC_DISCONNECT_PEER: 486 593 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) 488 595 goto psm_end; 596 489 597 break; 490 598 … … 494 602 495 603 default: 496 /* Unknown / unexpected / invalid message */604 /* Unknown / unexpected / invalid message -- but validated by our dictionary */ 497 605 TRACE_DEBUG(INFO, "Invalid non-routable command received: %u.", hdr->msg_code); 498 606 if (hdr->msg_flags & CMD_FLAG_REQUEST) { … … 502 610 503 611 /* 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 ); 505 613 506 614 /* Send the answer */ … … 509 617 } else { 510 618 /* 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..."); 512 620 } 513 621 … … 531 639 /* The connection object is broken */ 532 640 if (event == FDEVP_CNX_ERROR) { 533 switch ( peer->p_hdr.info.runtime.pir_state) {641 switch (cur_state) { 534 642 case STATE_WAITCNXACK_ELEC: 535 643 /* Abort the initiating side */ … … 541 649 case STATE_WAITCEA: 542 650 case STATE_OPEN: 651 case STATE_OPEN_NEW: 543 652 case STATE_REOPEN: 544 653 case STATE_WAITCNXACK: … … 558 667 goto psm_end; 559 668 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; 560 678 } 561 679 goto psm_loop; … … 616 734 peer->p_ini_thr = (pthread_t)NULL; 617 735 618 switch ( peer->p_hdr.info.runtime.pir_state) {736 switch (cur_state) { 619 737 case STATE_WAITCNXACK_ELEC: 620 738 case STATE_WAITCNXACK: … … 624 742 default: 625 743 /* 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)); 627 745 fd_cnx_destroy(cnx); 628 746 } … … 638 756 peer->p_ini_thr = (pthread_t)NULL; 639 757 640 switch ( peer->p_hdr.info.runtime.pir_state) {758 switch (cur_state) { 641 759 case STATE_WAITCNXACK_ELEC: 642 760 /* Abort the initiating side */ … … 653 771 default: 654 772 /* 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)); 656 774 } 657 775 … … 661 779 /* The timeout for the current state has been reached */ 662 780 if (event == FDEVP_PSM_TIMEOUT) { 663 switch ( peer->p_hdr.info.runtime.pir_state) {781 switch (cur_state) { 664 782 case STATE_OPEN: 665 783 case STATE_REOPEN: 784 case STATE_OPEN_NEW: 666 785 CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end ); 667 786 goto psm_loop; … … 676 795 /* Mark the connection problem */ 677 796 peer->p_flags.pf_cnx_pb = 1; 678 679 797 case STATE_CLOSING: 680 798 case STATE_WAITCNXACK: … … 683 801 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc); 684 802 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; 685 813 686 814 case STATE_WAITCNXACK_ELEC: … … 697 825 698 826 /* 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)); 700 828 psm_reset: 701 829 if (peer->p_flags.pf_delete) … … 707 835 fd_psm_cleanup(peer, 1); 708 836 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)), 710 838 peer->p_hdr.info.pi_diamid); 711 839 pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ 712 fd_cpu_flush_cache();713 840 peer->p_psm = (pthread_t)NULL; 714 841 pthread_detach(pthread_self()); … … 726 853 727 854 /* 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 ); 729 856 730 857 /* Create the FIFO for events */ … … 744 871 CHECK_PARAMS( CHECK_PEER(peer) ); 745 872 746 fd_cpu_flush_cache(); 747 if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) { 873 if (fd_peer_getstate(peer) != STATE_ZOMBIE) { 748 874 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, reason) ); 749 875 } else { -
libfdcore/p_sr.c
r691 r706 36 36 #include "fdcore-internal.h" 37 37 38 #ifndef SR_DEBUG_LVL39 #define SR_DEBUG_LVL ANNOYING40 #endif /* SR_DEBUG_LVL */41 42 38 /* Structure to store a sent request */ 43 39 struct sentreq { … … 69 65 struct fd_list * li; 70 66 struct timespec now; 71 if (!TRACE_BOOL(SR_DEBUG_LVL)) 67 68 if (!TRACE_BOOL(ANNOYING)) 72 69 return; 70 71 fd_log_debug("%sSentReq list @%p:\n", text, srlist); 72 73 73 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), ); 74 fd_log_debug("%sSentReq list @%p:\n", text, srlist);74 75 75 for (li = srlist->next; li != srlist; li = li->next) { 76 76 struct sentreq * sr = (struct sentreq *)li; 77 77 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, 79 80 (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), 80 81 (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); 82 84 } 83 85 } … … 117 119 } 118 120 119 /* thread that handles messages expiring. The thread is started / cancelledonly when needed */121 /* thread that handles messages expiring. The thread is started only when needed */ 120 122 static void * sr_expiry_th(void * arg) { 121 123 struct sr_list * srlist = arg; … … 129 131 { 130 132 char buf[48]; 131 s printf(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); 132 134 fd_log_threadname ( buf ); 133 135 } … … 313 315 } else { 314 316 /* 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." ); 316 318 CHECK_FCT_DO(fd_msg_free(sr->req), /* Ignore */); 317 319 } -
libfdcore/peers.c
r691 r706 73 73 74 74 p->p_eyec = EYEC_PEER; 75 CHECK_POSIX( pthread_mutex_init(&p->p_state_mtx, NULL) ); 76 75 77 fd_list_init(&p->p_actives, p); 76 78 fd_list_init(&p->p_expiry, p); … … 94 96 struct fd_list * li; 95 97 int ret = 0; 98 96 99 TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data); 97 100 CHECK_PARAMS(info && info->pi_diamid); 98 101 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 99 109 /* Create a structure to contain the new peer information */ 100 110 CHECK_FCT( fd_peer_alloc(&p) ); 101 111 102 112 /* 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) ); 104 115 105 116 memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) ); 117 106 118 /* Duplicate the strings if provided */ 107 119 if (info->config.pic_realm) { … … 109 121 } 110 122 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) ); 112 124 } 113 125 … … 124 136 CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) ); 125 137 } else { 126 CHECK_MALLOC( p->p_dbgorig = strdup("un known") );138 CHECK_MALLOC( p->p_dbgorig = strdup("unspecified") ); 127 139 } 128 140 p->p_cb = cb; … … 134 146 for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { 135 147 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 ); 137 150 if (cmp > 0) 138 151 continue; … … 162 175 163 176 /* Search for a peer */ 164 int fd_peer_getbyid( char * diamid, struct peer_hdr ** peer )177 int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer ) 165 178 { 166 179 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 ); 170 182 171 183 *peer = NULL; … … 175 187 for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { 176 188 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 ); 178 194 if (cmp > 0) 179 195 continue; … … 255 271 256 272 CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ ); 273 CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_state_mtx), /* continue */); 257 274 CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */); 258 275 CHECK_POSIX_DO( pthread_cond_destroy(&p->p_sr.cnd), /* continue */); … … 283 300 CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ ); 284 301 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) { 289 305 CHECK_FCT_DO( fd_psm_terminate(peer, "REBOOTING"), /* continue */ ); 290 306 } else { … … 307 323 308 324 /* Allow the PSM(s) to execute */ 309 sched_yield();325 usleep(100000); 310 326 311 327 /* Remove zombie peers */ 312 328 CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ ); 313 329 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) { 317 332 li = li->prev; /* to avoid breaking the loop */ 318 333 fd_list_unlink(&peer->p_hdr.chain); … … 329 344 CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ ); 330 345 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); 332 347 fd_psm_abord(peer); 333 348 fd_list_unlink(&peer->p_hdr.chain); … … 339 354 /* Free memory objects of all peers */ 340 355 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); 342 357 fd_list_unlink(&peer->p_hdr.chain); 343 358 fd_peer_free(&peer); … … 364 379 } 365 380 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); 367 382 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>"); 369 384 if (peer->p_hdr.info.runtime.pir_prodname) 370 385 fd_log_debug("\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev); … … 398 413 399 414 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; 401 416 fd_peer_dump(np, details); 402 417 } … … 404 419 CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ ); 405 420 } 421 422 static struct dict_object *avp_oh_model = NULL; 423 static pthread_mutex_t cache_avp_lock = PTHREAD_MUTEX_INITIALIZER; 406 424 407 425 /* Handle an incoming CER request on a new connection */ … … 409 427 { 410 428 struct msg * msg; 411 struct dict_object *avp_oh_model;412 avp_code_t code = AC_ORIGIN_HOST;413 429 struct avp *avp_oh; 414 430 struct avp_hdr * avp_hdr; … … 424 440 msg = *cer; 425 441 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 426 452 /* 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) );428 453 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? */ 429 455 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 } 430 466 431 467 /* 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. … … 435 471 436 472 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 ); 440 476 if (cmp > 0) 441 477 continue; … … 451 487 452 488 /* 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; 456 492 CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } ); 457 493 peer->p_flags.pf_responder = 1; … … 470 506 } else { 471 507 /* 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) { 474 509 /* Re-activate the peer */ 475 510 if (peer->p_hdr.info.config.pic_flags.exp) 476 511 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; 478 516 CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out ); 479 517 } 480 518 } 481 519 482 520 /* Send the new connection event to the PSM */ 483 521 CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } ); -
libfdcore/routing_dispatch.c
r691 r706 208 208 struct fd_peer * peer; 209 209 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) { 212 212 /* Check if the remote peer advertised the message's appli */ 213 213 CHECK_FCT( fd_app_check(&peer->p_hdr.info.runtime.pir_apps, hdr->msg_appl, &found) ); … … 264 264 for (li = candidates->next; li != candidates; li = li->next) { 265 265 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 */ 266 268 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; 283 283 } 284 284 } … … 298 298 299 299 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 301 302 *excl_idx = 0; 303 *at_idx = 0; 302 304 303 305 /* Search if there is a '!' before any '@' -- do we need to check it contains a '.' ? */ … … 307 309 if (!*excl_idx) 308 310 *excl_idx = i; 309 if (!at_idx) 310 return; 311 continue; 311 312 } 312 313 /* If we reach the realm part, we can stop */ 313 314 if ( un->os.data[i] == (unsigned char) '@' ) { 314 if (at_idx) 315 *at_idx = i; 315 *at_idx = i; 316 316 break; 317 } 318 /* Stop if we find a \0 in the middle */ 319 if ( un->os.data[i] == 0 ) { 320 return; 317 321 } 318 322 /* Skip escaped characters */ … … 321 325 continue; 322 326 } 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 }336 327 } 337 328 … … 340 331 341 332 /* 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 356 333 /* 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;334 static int process_decorated_NAI(int * was_nai, union avp_value * un, union avp_value * dr) 335 { 336 int at_idx, sep_idx; 360 337 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); 363 340 364 341 /* Save the decorated User-Name, for example 'homerealm.example.net!user@otherrealm.example.net' */ … … 367 344 /* Search the positions of the first '!' and the '@' in the string */ 368 345 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; 370 352 371 353 /* Create the new User-Name value */ … … 390 372 } 391 373 374 392 375 /* Function to return an error to an incoming request */ 393 376 static int return_error(struct msg ** pmsg, char * error_code, char * error_message, struct avp * failedavp) … … 398 381 /* Get the source of the message */ 399 382 { 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 ) ); 402 386 403 387 if (id == NULL) { … … 406 390 407 391 /* 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 ) ); 409 393 410 394 if (!peer) { … … 439 423 /****************************************************************************/ 440 424 441 /* These are the functions of each threads: dispatch & routing */442 425 /* The DISPATCH message processing */ 443 426 static int msg_dispatch(struct msg ** pmsg) … … 447 430 struct session * sess; 448 431 enum disp_action action; 449 c onst char * ec = NULL;450 c onst char * em = NULL;432 char * ec = NULL; 433 char * em = NULL; 451 434 452 435 /* Read the message header */ … … 460 443 CHECK_FCT_DO( ret = fd_msg_parse_or_error( pmsg ), 461 444 { 462 /* in case of error , the message is already dump'd*/445 /* in case of error */ 463 446 if ((ret == EBADMSG) && (*pmsg != NULL)) { 464 447 /* msg now contains the answer message to send back */ … … 512 495 em = "The message was not handled by any extension callback"; 513 496 ec = "DIAMETER_COMMAND_UNSUPPORTED"; 514 497 /* and continue as if an error occurred... */ 515 498 case DISP_ACT_ERROR: 516 499 /* We have a problem with delivering the message */ … … 528 511 /* Create an answer with the error code and message */ 529 512 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 ) ); 531 514 532 515 case DISP_ACT_SEND: … … 545 528 int is_req = 0; 546 529 int is_err = 0; 547 char * qry_src = NULL; 530 DiamId_t qry_src = NULL; 531 size_t qry_src_len = 0; 548 532 549 533 /* Read the message header */ … … 572 556 /* Check if we have local support for the message application */ 573 557 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"); 575 560 CHECK_FCT( return_error( pmsg, "DIAMETER_APPLICATION_UNSUPPORTED", "Routable message with application id 0 or relay", NULL) ); 576 561 return 0; … … 587 572 struct fd_pei error_info; 588 573 int ret; 574 575 memset(&error_info, 0, sizeof(struct fd_pei)); 576 589 577 CHECK_FCT( fd_msg_avp_hdr( avp, &ahdr ) ); 590 578 … … 604 592 ASSERT( ahdr->avp_value ); 605 593 /* 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 { 607 597 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);611 598 } 612 599 break; … … 626 613 dr_val = ahdr->avp_value; 627 614 /* 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 { 629 618 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);633 619 } 634 620 break; 635 621 622 /* we also use User-Name for decorated NAI */ 636 623 case AC_USER_NAME: 637 624 /* Parse this AVP */ … … 652 639 } 653 640 641 /* Stop when we found all 3 AVPs -- they are supposed to be at the beginning of the message, so this should be fast */ 654 642 if ((is_dest_host != UNKNOWN) && (is_dest_realm != UNKNOWN) && un) 655 643 break; … … 682 670 if ((is_dest_host == NO) || (is_dest_realm == NO)) { 683 671 if (fd_g_config->cnf_flags.no_fwd) { 684 CHECK_FCT( return_error( pmsg, "DIAMETER_UNABLE_TO_DELIVER", " This peer is not anagent", NULL) );672 CHECK_FCT( return_error( pmsg, "DIAMETER_UNABLE_TO_DELIVER", "I am not a Diameter agent", NULL) ); 685 673 return 0; 686 674 } 687 675 } else { 688 676 /* Destination-Host was not set, and Destination-Realm is matching : we may handle or pass to a fellow peer */ 677 int is_nai = 0; 689 678 690 679 /* 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) { 700 689 /* We have transformed the AVP, now submit it again in the queue */ 701 690 CHECK_FCT(fd_fifo_post(fd_g_incoming, pmsg) ); … … 724 713 /* Retrieve the corresponding query and its origin */ 725 714 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 ) ); 727 716 728 717 if ((!qry_src) && (!is_err)) { … … 733 722 734 723 /* 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?"); 735 725 } 736 726 … … 800 790 if ( ! is_req ) { 801 791 struct msg * qry; 802 char * qry_src = NULL; 792 DiamId_t qry_src = NULL; 793 size_t qry_src_len = 0; 803 794 struct msg_hdr * qry_hdr; 804 795 struct fd_peer * peer = NULL; … … 806 797 /* Retrieve the corresponding query and its origin */ 807 798 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 ) ); 809 800 810 801 ASSERT( qry_src ); /* if it is NULL, the message should have been in the LOCAL queue! */ 811 802 812 803 /* 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) { 816 806 fd_msg_log( FD_MSG_LOG_DROPPED, *pmsg, "Unable to forward answer to deleted / closed peer '%s'.", qry_src); 817 807 fd_msg_free(*pmsg); … … 844 834 for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) { 845 835 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; } ); 847 842 } 848 843 CHECK_FCT( pthread_rwlock_unlock(&fd_g_activ_peers_rw) ); … … 867 862 } ); 868 863 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); 871 866 } 872 867 … … 876 871 } 877 872 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 */ 879 874 880 875 /* Ok, we have our list in rtd now, let's (re)initialize the scores */ … … 928 923 929 924 /* 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) { 934 928 /* Send to this one */ 935 929 CHECK_FCT_DO( fd_out_send(pmsg, NULL, peer, 0), continue ); … … 964 958 /* Control of the threads */ 965 959 static enum { RUN = 0, STOP = 1 } order_val = RUN; 966 static pthread_mutex_t order_ lock = PTHREAD_MUTEX_INITIALIZER;960 static pthread_mutex_t order_state_lock = PTHREAD_MUTEX_INITIALIZER; 967 961 968 962 /* Threads report their status */ … … 970 964 static void cleanup_state(void * state_loc) 971 965 { 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), ); 974 969 } 975 970 … … 991 986 992 987 /* Mark the thread running */ 988 CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), ); 993 989 *(enum thread_state *)arg = RUNNING; 994 fd_cpu_flush_cache();990 CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), ); 995 991 996 992 do { … … 1000 996 { 1001 997 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 */ 1003 999 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); } ); 1005 1001 if (must_stop) 1006 1002 goto end; … … 1014 1010 { 1015 1011 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; 1017 1021 if (ret == EPIPE) 1018 1022 /* The queue was destroyed, we are probably exiting */ … … 1100 1104 CHECK_FCT( fd_rt_out_register( dont_send_if_no_common_app, NULL, 10, NULL ) ); 1101 1105 CHECK_FCT( fd_rt_out_register( score_destination_avp, NULL, 10, NULL ) ); 1106 1107 TODO("built-in callbacks for Redirect messages?"); 1108 1102 1109 return 0; 1103 1110 } … … 1106 1113 int fd_rtdisp_cleanstop(void) 1107 1114 { 1108 CHECK_POSIX ( pthread_mutex_lock(&order_lock));1115 CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), ); 1109 1116 order_val = STOP; 1110 CHECK_POSIX ( pthread_mutex_unlock(&order_lock));1117 CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), ); 1111 1118 1112 1119 return 0; … … 1117 1124 TRACE_ENTRY("%p %p", st, thr); 1118 1125 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 1119 1132 1120 1133 /* 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) { 1123 1135 TRACE_DEBUG(INFO, "Waiting for the %s thread to have a chance to terminate", th_name); 1124 1136 do { … … 1131 1143 1132 1144 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) 1135 1150 break; 1136 1151 -
libfdcore/sctp.c
r691 r706 999 999 1000 1000 /* 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)1001 int fd_sctp_sendstr(struct cnxctx * conn, uint16_t strid, uint8_t * buf, size_t len) 1002 1002 { 1003 1003 struct msghdr mhdr; … … 1009 1009 int timedout = 0; 1010 1010 1011 TRACE_ENTRY("% d %hu %p %zd %p", sock, strid, buf, len, cc_status);1012 CHECK_PARAMS(c c_status);1011 TRACE_ENTRY("%p %hu %p %zd", conn, strid, buf, len); 1012 CHECK_PARAMS(conn && buf && len); 1013 1013 1014 1014 memset(&mhdr, 0, sizeof(mhdr)); … … 1037 1037 mhdr.msg_controllen = sizeof(anci); 1038 1038 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); 1040 1040 again: 1041 ret = sendmsg( sock, &mhdr, 0);1041 ret = sendmsg(conn->cc_socket, &mhdr, 0); 1042 1042 /* Handle special case of timeout */ 1043 1043 if ((ret < 0) && (errno == EAGAIN)) { 1044 if (! (*cc_status & CC_STATUS_CLOSING))1044 if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) 1045 1045 goto again; /* don't care, just ignore */ 1046 1046 if (!timedout) { … … 1057 1057 1058 1058 /* 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)1059 int fd_sctp_recvmeta(struct cnxctx * conn, uint16_t * strid, uint8_t ** buf, size_t * len, int *event) 1060 1060 { 1061 1061 ssize_t ret = 0; … … 1068 1068 int timedout = 0; 1069 1069 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 ); 1072 1072 1073 1073 /* Cleanup out parameters */ … … 1098 1098 again: 1099 1099 pthread_cleanup_push(free, data); 1100 ret = recvmsg( sock, &mhdr, 0);1100 ret = recvmsg(conn->cc_socket, &mhdr, 0); 1101 1101 pthread_cleanup_pop(0); 1102 1102 1103 1103 /* First, handle timeouts (same as fd_cnx_s_recv) */ 1104 1104 if ((ret < 0) && (errno == EAGAIN)) { 1105 if (! (*cc_status & CC_STATUS_CLOSING))1105 if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) 1106 1106 goto again; /* don't care, just ignore */ 1107 1107 if (!timedout) { … … 1132 1132 union sctp_notification * notif = (union sctp_notification *) data; 1133 1133 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); 1135 1135 1136 1136 switch (notif->sn_header.sn_type) { … … 1226 1226 *strid = sndrcv->sinfo_stream; 1227 1227 } 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); 1229 1229 } 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); 1231 1231 } 1232 1232 -
libfdcore/sctps.c
r662 r706 57 57 */ 58 58 59 59 /* TODO: change this whole wrapper to DTLS which should not require many different threads */ 60 60 61 61 /*************************************************************/ … … 83 83 84 84 ASSERT( conn->cc_proto == IPPROTO_SCTP ); 85 ASSERT( Target_Queue(conn) );85 ASSERT( fd_cnx_target_queue(conn) ); 86 86 ASSERT( conn->cc_sctps_data.array ); 87 87 88 88 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 ); 91 90 switch (event) { 92 91 case FDEVP_CNX_MSG_RECV: … … 102 101 case FDEVP_CNX_EP_CHANGE: 103 102 /* 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 ); 106 104 break; 107 105 … … 144 142 CHECK_PARAMS_DO(ctx && ctx->raw_recv && ctx->parent, goto error); 145 143 cnx = ctx->parent; 146 ASSERT( Target_Queue(cnx) );144 ASSERT( fd_cnx_target_queue(cnx) ); 147 145 148 146 /* Set the thread name */ … … 173 171 CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } ); 174 172 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 ); 177 174 178 175 return len; … … 306 303 struct sr_data * sr = (struct sr_data *)ret; 307 304 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); 317 306 if (cmp > 0) 318 307 continue; … … 627 616 /* End all TLS sessions, in series (not as efficient as paralel, but simpler) */ 628 617 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)) { 631 619 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_sctps_data.array[i].session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) ); 632 620 } -
libfdcore/server.c
r691 r706 41 41 /* We don't need to protect this list, it is only accessed from the main framework thread. */ 42 42 43 enum s_state { 44 NOT_CREATED=0, 45 RUNNING, 46 TERMINATED, 47 ERROR /* an error occurred, this is not a valid status */ 48 }; 49 43 50 /* Servers information */ 44 51 struct server { … … 50 57 51 58 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 */ 53 60 54 61 struct fd_list clients; /* List of clients connected to this server, not yet identified */ 55 62 pthread_mutex_t clients_mtx; /* Mutex to protect the list of clients */ 56 63 }; 64 57 65 58 66 /* Client information (connecting peer for which we don't have the CER yet) */ … … 65 73 66 74 75 76 /* Micro functions to read/change the status thread-safely */ 77 static pthread_mutex_t s_lock = PTHREAD_MUTEX_INITIALIZER; 78 static 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 } 86 static 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 67 95 /* Dump all servers information */ 68 96 void fd_servers_dump() … … 73 101 for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) { 74 102 struct server * s = (struct server *)li; 75 fd_cpu_flush_cache();103 enum s_state st = get_status(s); 76 104 fd_log_debug(" Serv %p '%s': %s, %s, %s\n", 77 105 s, fd_cnx_getid(s->conn), 78 106 IPPROTO_NAME( s->proto ), 79 107 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" : 83 111 "Thread status unknown"))); 84 112 /* Dump the client list of this server */ … … 192 220 CHECK_PARAMS_DO(s, goto error); 193 221 fd_log_threadname ( fd_cnx_getid(s->conn) ); 194 s->status = 1; 195 fd_cpu_flush_cache(); 222 set_status(s, RUNNING); 196 223 197 224 /* Accept incoming connections */ … … 225 252 error: 226 253 if (s) 227 s ->status = 2;254 set_status(s, TERMINATED); 228 255 /* Send error signal to the daemon */ 229 256 TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating..."); … … 266 293 267 294 /* 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 } 272 301 273 302 /* 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 } 278 309 279 310 #endif /* DISABLE_SCTP */ … … 287 318 if (!fd_g_config->cnf_flags.no_ip4) { 288 319 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 } 298 333 } 334 299 335 /* Bind TCP servers on [::] */ 300 336 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 } 311 351 } 312 352 } else { … … 323 363 continue; 324 364 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 } 334 378 } 335 379 } 336 380 } 337 381 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) { 340 384 CHECK_FCT(fd_cnx_get_local_eps(&fd_g_config->cnf_endpoints)); 341 385 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"); 343 389 return EINVAL; 344 390 }
Note: See TracChangeset
for help on using the changeset viewer.