Changeset 706:4ffbc9f1e922 in freeDiameter
- Timestamp:
- Feb 9, 2011, 3:26:58 PM (11 years ago)
- Branch:
- default
- Phase:
- public
- Files:
-
- 1 added
- 59 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
contrib/debian/changelog
r683 r706 5 5 libfreeDiameter renamed as libfdproto. 6 6 This closes #15. 7 * API version bumped to version 4 accordingly.7 * API version bumped to version 4. 8 8 * Improved fd_dict_new() when the same object already exists. 9 9 * Improvements to dict_legacy_xml extension. … … 13 13 * Allow default signals such as SIGTSTP (ctrl-z) to be used with 14 14 freeDiameterd 15 * Improved DiameterIdentity handling (esp. interationalization issues), 16 and improve efficiency of some string operations in peers, sessions, 17 and dictionary modules (closes #7) 18 * Cleanup in the session module to free only unreferenced sessions (#16) 19 * Removed fd_cpu_flush_cache(), replaced by more robust alternatives. 20 * Improved peer state machine algorithm to counter SCTP multistream race 21 condition. 15 22 16 -- Sebastien Decugis <sdecugis@nict.go.jp> Tue, 18 Jan 2011 15:13:00 +090023 -- Sebastien Decugis <sdecugis@nict.go.jp> Mon, 07 Feb 2011 17:24:20 +0900 17 24 18 25 freediameter (1.0.4) UNRELEASED; urgency=low -
doc/dbg_interactive.py.sample
r688 r706 105 105 ############# Hash ############ 106 106 107 hex(fd_ hash("hello world")) # It accepts binary data107 hex(fd_os_hash("hello world")) # It accepts binary data 108 108 109 109 -
doc/freediameter.conf.sample
r578 r706 211 211 # ConnectTo = "2001:200:903:2::202:1"; 212 212 # TLS_Prio = "NORMAL"; 213 # Realm = "realm.net"; # Reject the peer if it does not advertise this realm. 213 214 # Examples: 214 215 #ConnectPeer = "aaa.wide.ad.jp"; -
extensions/app_radgw/rgw_clients.c
r554 r706 86 86 int is_local; /* true if the RADIUS client runs on the same host -- we use Diameter Identity in that case */ 87 87 enum rgw_cli_type type; /* is it a proxy ? */ 88 char *fqdn;88 DiamId_t fqdn; /* malloc'd here */ 89 89 size_t fqdn_len; 90 char *realm; 91 char **aliases; 90 DiamId_t realm; /* references another string, do not free */ 91 size_t realm_len; 92 struct { 93 os0_t name; 94 size_t len; 95 } *aliases; /* Received aliases */ 92 96 size_t aliases_nb; 93 97 … … 210 214 { 211 215 struct rgw_client *tmp = NULL; 212 char buf[255]; 216 DiamId_t fqdn; 217 size_t fqdn_len; 213 218 int ret, i; 214 219 int loc = 0; … … 220 225 loc = 1; 221 226 } else { 227 char buf[255]; 222 228 223 229 /* Search FQDN for the client */ … … 227 233 return EINVAL; 228 234 } 235 fqdn = &buf[0]; 236 CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&fqdn, &fqdn_len, 1), 237 { 238 TRACE_DEBUG(INFO, "Unable to use resolved peer name '%s' as DiameterIdentity: %s", buf, strerror(ret)); 239 return ret; 240 } ); 229 241 } 230 242 … … 246 258 } else { 247 259 /* Copy the fqdn */ 248 CHECK_MALLOC( tmp->fqdn = strdup(buf) ); 249 tmp->fqdn_len = strlen(tmp->fqdn); 260 tmp->fqdn = fqdn; 261 tmp->fqdn_len = fqdn_len; 262 250 263 /* Find an appropriate realm */ 251 tmp->realm = strchr( tmp->fqdn, '.');252 if (tmp->realm) 264 tmp->realm = strchr(fqdn, '.'); 265 if (tmp->realm) { 253 266 tmp->realm += 1; 254 if ((!tmp->realm) || (*tmp->realm == '\0')) /* in case the fqdn was "localhost." for example, if it is possible... */ 267 tmp->realm_len = tmp->fqdn_len - (tmp->realm - fqdn); 268 } 269 if ((!tmp->realm) || (*tmp->realm == '\0')) { /* in case the fqdn was "localhost." for example, if it is possible... */ 255 270 tmp->realm = fd_g_config->cnf_diamrlm; 271 tmp->realm_len = fd_g_config->cnf_diamrlm_len; 272 } 256 273 } 257 274 … … 282 299 /* Free the data */ 283 300 for (idx = 0; idx < client->aliases_nb; idx++) 284 free(client->aliases[idx] );301 free(client->aliases[idx].name); 285 302 free(client->aliases); 286 303 free(client->fqdn); … … 532 549 int valid_nas_info = 0; 533 550 struct radius_attr_hdr *nas_ip = NULL, *nas_ip6 = NULL, *nas_id = NULL; 534 char * oh_str = NULL; 535 char * or_str = NULL; 536 char * rr_str = NULL; 551 size_t nas_id_len; 552 char * oh_str = NULL; size_t oh_strlen; int oh_free = 0; 553 char * or_str = NULL; size_t or_strlen; 554 char * rr_str = NULL; size_t rr_strlen; 537 555 char buf[REVERSE_DNS_SIZE_MAX]; /* to store DNS lookups results */ 538 556 … … 555 573 if ((attr->type == RADIUS_ATTR_NAS_IDENTIFIER) && (attr_len > 0)) { 556 574 nas_id = attr; 575 nas_id_len = attr_len; 557 576 continue; 558 577 } … … 568 587 569 588 /* Get information on this peer */ 570 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &o r_str) );589 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) ); 571 590 572 591 goto diameter; … … 619 638 return EINVAL; 620 639 } else { 640 int ret; 641 sSS ss; 621 642 /* the peer is configured as a proxy, or running on localhost, so accept the message */ 622 sSS ss;623 643 624 644 /* In that case, the cli will be stored as Route-Record and the NAS-IP-Address as origin */ 625 645 if (!cli->is_local) { 626 646 rr_str = cli->fqdn; 647 rr_strlen = cli->fqdn_len; 627 648 } 628 649 … … 641 662 { 642 663 if (cli->is_local) { 643 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &o r_str) );664 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) ); 644 665 goto diameter; 645 666 } … … 648 669 return EINVAL; 649 670 } ); 671 672 oh_str = &buf[0]; 673 CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&oh_str, &oh_strlen, 1), 674 { 675 if (cli->is_local) { 676 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) ); 677 goto diameter; 678 } 679 680 TRACE_DEBUG(INFO, "Unable to use resolved client name '%s' as DiameterIdentity: %s", buf, strerror(ret)); 681 return ret; 682 } ); 683 oh_free = 1; 650 684 651 oh_str = &buf[0];652 685 or_str = strchr(oh_str, '.'); 653 686 if (or_str) { … … 655 688 if (*or_str == '\0') 656 689 or_str = NULL; /* Discard this realm, we will use the local realm later */ 690 else 691 or_strlen = oh_strlen - (or_str - oh_str); 657 692 } 658 693 } 659 694 } else { 660 695 /* The attribute matches the source address, just use this in origin-host */ 661 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &o r_str) );696 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) ); 662 697 } 663 698 … … 668 703 if (cli->is_local) { 669 704 /* Simple: we use our own configuration */ 670 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &o r_str) );705 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) ); 671 706 goto diameter; 672 707 } … … 697 732 698 733 /* first, check if the nas_id is the fqdn of the peer or a known alias */ 699 if ( (cli->fqdn_len == (nas_id->length - sizeof(struct radius_attr_hdr)))700 && (!strncasecmp((char *)(nas_id + 1), cli->fqdn, nas_id->length - sizeof(struct radius_attr_hdr)))) {734 if (!fd_os_almostcasecmp(nas_id + 1, nas_id_len, 735 cli->fqdn, cli->fqdn_len)) { 701 736 TRACE_DEBUG(FULL, "NAS-Identifier contains the fqdn of the client"); 702 737 found = 1; 703 738 } else { 704 739 for (idx = 0; idx < cli->aliases_nb; idx++) { 705 if ( ((nas_id->length - sizeof(struct radius_attr_hdr)) == strlen(cli->aliases[idx]))706 && (!strncasecmp((char *)(nas_id + 1), cli->aliases[idx], nas_id->length - sizeof(struct radius_attr_hdr)))) {740 if (!fd_os_cmp(nas_id + 1, nas_id_len, 741 cli->aliases[idx].name, cli->aliases[idx].len)) { 707 742 TRACE_DEBUG(FULL, "NAS-Identifier valid value found in the cache"); 708 743 found = 1; … … 714 749 if (found) { 715 750 /* The NAS-Identifier matches the source IP */ 716 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &o r_str) );751 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) ); 717 752 718 753 goto diameter; … … 720 755 721 756 /* Attempt DNS resolution of the identifier */ 722 ASSERT( nas_id ->length - sizeof(struct radius_attr_hdr)< sizeof(buf) );723 memcpy(buf, nas_id + 1, nas_id ->length - sizeof(struct radius_attr_hdr));757 ASSERT( nas_id_len < sizeof(buf) ); 758 memcpy(buf, nas_id + 1, nas_id_len); 724 759 buf[nas_id->length - sizeof(struct radius_attr_hdr)] = '\0'; 725 760 … … 745 780 if (cli->type == RGW_CLI_NAS) { 746 781 TRACE_DEBUG(INFO, "The NAS-Identifier value '%.*s' resolves to a different IP than the client's, discarding the message. \nConfigure this client as a Proxy if this message should be valid.", 747 nas_id ->length - sizeof(struct radius_attr_hdr), nas_id + 1);782 nas_id_len, nas_id + 1); 748 783 return EINVAL; 749 784 } else { … … 751 786 if (!cli->is_local) { 752 787 rr_str = cli->fqdn; 788 rr_strlen = cli->fqdn_len; 753 789 } 754 790 oh_str = &buf[0]; /* The canonname resolved */ 791 CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&oh_str, &oh_strlen, 1), 792 { 793 TRACE_DEBUG(INFO, "Unable to use resolved client name '%s' as DiameterIdentity: %s", buf, strerror(ret)); 794 return ret; 795 } ); 796 oh_free = 1; 755 797 or_str = strchr(oh_str, '.'); 756 798 if (or_str) { … … 758 800 if (*or_str == '\0') 759 801 or_str = NULL; /* Discard this realm, we will use the local realm later */ 802 else 803 or_strlen = oh_strlen - (or_str - oh_str); 760 804 } 761 805 } 762 806 } else { 763 807 /* It is a valid alias, save it */ 764 CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(char *)) ); 765 CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1] = malloc( 1 + nas_id->length - sizeof(struct radius_attr_hdr) )); 766 memcpy( cli->aliases[cli->aliases_nb + 1], nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr)); 767 *(cli->aliases[cli->aliases_nb + 1] + nas_id->length - sizeof(struct radius_attr_hdr)) = '\0'; 808 CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(cli->aliases[0])) ); 809 810 CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1].name = os0dup(nas_id + 1, nas_id_len ) ); 811 cli->aliases[cli->aliases_nb + 1].len = nas_id_len; 812 768 813 cli->aliases_nb ++; 769 TRACE_DEBUG(FULL, "Saved valid alias for client: '% s' -> '%s'", cli->aliases[cli->aliases_nb + 1], cli->fqdn);770 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &o r_str) );814 TRACE_DEBUG(FULL, "Saved valid alias for client: '%.*s' -> '%s'", nas_id_len, nas_id + 1, cli->fqdn); 815 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) ); 771 816 } 772 817 } else { … … 774 819 TRACE_DEBUG(INFO, "NAS-Identifier '%s' cannot be resolved: %s. Ignoring...", buf, gai_strerror(ret)); 775 820 /* Assume this is a valid identifier for the client */ 776 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &o r_str) );821 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) ); 777 822 } 778 823 } … … 781 826 diameter: 782 827 ASSERT(oh_str); /* If it is not defined here, there is a bug... */ 783 if (!or_str) 828 if (!or_str) { 784 829 or_str = fd_g_config->cnf_diamrlm; /* Use local realm in that case */ 830 or_strlen = fd_g_config->cnf_diamrlm_len; 831 } 785 832 786 833 /* Create an empty Diameter message so that extensions can store their AVPs */ … … 791 838 memset(&avp_val, 0, sizeof(avp_val)); 792 839 avp_val.os.data = (unsigned char *)oh_str; 793 avp_val.os.len = strlen(oh_str);840 avp_val.os.len = oh_strlen; 794 841 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) ); 795 842 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) ); … … 799 846 memset(&avp_val, 0, sizeof(avp_val)); 800 847 avp_val.os.data = (unsigned char *)or_str; 801 avp_val.os.len = strlen(or_str);848 avp_val.os.len = or_strlen; 802 849 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) ); 803 850 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) ); … … 807 854 memset(&avp_val, 0, sizeof(avp_val)); 808 855 avp_val.os.data = (unsigned char *)rr_str; 809 avp_val.os.len = strlen(rr_str);856 avp_val.os.len = rr_strlen; 810 857 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) ); 811 858 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) ); 812 859 } 813 860 861 if (oh_free) 862 free(oh_str); 863 814 864 /* Done! */ 815 865 return 0; 816 866 } 817 867 818 int rgw_clients_get_origin(struct rgw_client *cli, char **fqdn, char **realm)819 { 820 TRACE_ENTRY("%p %p %p ", cli, fqdn, realm);821 CHECK_PARAMS(cli && fqdn );868 int rgw_clients_get_origin(struct rgw_client *cli, DiamId_t *fqdn, size_t *fqdnlen, DiamId_t *realm, size_t *realmlen) 869 { 870 TRACE_ENTRY("%p %p %p %p %p", cli, fqdn, fqdnlen, realm, realmlen); 871 CHECK_PARAMS(cli && fqdn && fqdnlen); 822 872 823 873 if (cli->is_local) { 824 874 *fqdn = fd_g_config->cnf_diamid; 875 *fqdnlen = fd_g_config->cnf_diamid_len; 825 876 if (realm) 826 877 *realm= fd_g_config->cnf_diamrlm; 878 if (realmlen) 879 *realmlen= fd_g_config->cnf_diamrlm_len; 827 880 } else { 828 881 *fqdn = cli->fqdn; 882 *fqdnlen = cli->fqdn_len; 829 883 if (realm) 830 884 *realm= cli->realm; 885 if (realmlen) 886 *realmlen= cli->realm_len; 831 887 } 832 888 -
extensions/app_radgw/rgw_common.h
r403 r706 59 59 int rgw_clients_getkey(struct rgw_client * cli, unsigned char **key, size_t *key_len); 60 60 char * rgw_clients_id(struct rgw_client *cli); 61 int rgw_clients_get_origin(struct rgw_client *cli, char **fqdn, char **realm);61 int rgw_clients_get_origin(struct rgw_client *cli, DiamId_t *fqdn, size_t *fqdnlen, DiamId_t *realm, size_t *realmlen); 62 62 63 63 /* Each plugin must provide the following structure. */ -
extensions/app_radgw/rgw_servers.c
r553 r706 148 148 CHECK_FCT_DO( rgw_msg_parse(&buf[0], len, &msg), 149 149 { 150 char * cliname = NULL; 151 CHECK_FCT_DO( rgw_clients_get_origin(nas_info, &cliname, NULL), ); 150 DiamId_t cliname = NULL; 151 size_t clisz; 152 CHECK_FCT_DO( rgw_clients_get_origin(nas_info, &cliname, &clisz, NULL, NULL), ); 152 153 TRACE_DEBUG(INFO, "Discarding invalid RADIUS message from '%s'", cliname); 153 154 rgw_clients_dispose(&nas_info); -
extensions/app_radgw/rgwx_acct.c
r705 r706 306 306 const char * prefix = "Diameter/"; 307 307 size_t pref_len; 308 uint8_t *si = NULL;308 os0_t si = NULL; 309 309 size_t si_len = 0; 310 uint8_t *un = NULL;310 os0_t un = NULL; 311 311 size_t un_len = 0; 312 312 … … 487 487 /* Create the Session-Id AVP if needed */ 488 488 if (!*session) { 489 CHECK_FCT( fd_sess_fromsid ( (char *)/* cast should be removed later */si, si_len, session, NULL) );489 CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) ); 490 490 491 491 TRACE_DEBUG(FULL, "[acct.rgwx] Translating new accounting message for session '%.*s'...", si_len, si); … … 663 663 char * attr_val, *auth_val; 664 664 attr_val = (char *)(attr + 1); 665 auth_val = attr_val + strlen(CLASS_AAI_PREFIX);666 if ( (attr->length > sizeof(struct radius_attr_hdr) + strlen(CLASS_AAI_PREFIX) )667 && (attr->length < sizeof(struct radius_attr_hdr) + strlen(CLASS_AAI_PREFIX) + sizeof(buf))668 && ! strncmp(attr_val, CLASS_AAI_PREFIX, strlen(CLASS_AAI_PREFIX))) {665 auth_val = attr_val + CONSTSTRLEN(CLASS_AAI_PREFIX); 666 if ( (attr->length > sizeof(struct radius_attr_hdr) + CONSTSTRLEN(CLASS_AAI_PREFIX) ) 667 && (attr->length < sizeof(struct radius_attr_hdr) + CONSTSTRLEN(CLASS_AAI_PREFIX) + sizeof(buf)) 668 && ! strncmp(attr_val, CLASS_AAI_PREFIX, CONSTSTRLEN(CLASS_AAI_PREFIX))) { 669 669 670 670 memset(buf, 0, sizeof(buf)); 671 memcpy(buf, auth_val, attr->length - sizeof(struct radius_attr_hdr) - strlen(CLASS_AAI_PREFIX));671 memcpy(buf, auth_val, attr->length - sizeof(struct radius_attr_hdr) - CONSTSTRLEN(CLASS_AAI_PREFIX)); 672 672 if (sscanf(buf, "%u", &auth_appl) == 1) { 673 673 TRACE_DEBUG(ANNOYING, "Found Class attribute with '%s' prefix (attr #%d), AAI:%u.", CLASS_AAI_PREFIX, idx, auth_appl); … … 1301 1301 struct msg * str = NULL; 1302 1302 struct msg_hdr * hdr = NULL; 1303 char * fqdn; 1304 char * realm; 1303 DiamId_t fqdn; 1304 size_t fqdn_len; 1305 DiamId_t realm; 1306 size_t realm_len; 1305 1307 union avp_value avp_val; 1306 1308 … … 1323 1325 1324 1326 /* Get information on the NAS */ 1325 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, & realm) );1327 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &fqdn_len, &realm, &realm_len) ); 1326 1328 1327 1329 /* Add the Origin-Host as next AVP */ … … 1329 1331 memset(&avp_val, 0, sizeof(avp_val)); 1330 1332 avp_val.os.data = (unsigned char *)fqdn; 1331 avp_val.os.len = strlen(fqdn);1333 avp_val.os.len = fqdn_len; 1332 1334 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) ); 1333 1335 CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) ); … … 1337 1339 memset(&avp_val, 0, sizeof(avp_val)); 1338 1340 avp_val.os.data = (unsigned char *)realm; 1339 avp_val.os.len = strlen(realm);1341 avp_val.os.len = realm_len; 1340 1342 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) ); 1341 1343 CHECK_FCT( fd_msg_avp_add ( str, MSG_BRW_LAST_CHILD, avp) ); -
extensions/app_radgw/rgwx_auth.c
r705 r706 239 239 const char * prefix = "Diameter/"; 240 240 size_t pref_len; 241 uint8_t *dh = NULL;241 os0_t dh = NULL; 242 242 size_t dh_len = 0; 243 uint8_t *dr = NULL;243 os0_t dr = NULL; 244 244 size_t dr_len = 0; 245 uint8_t *si = NULL;245 os0_t si = NULL; 246 246 size_t si_len = 0; 247 uint8_t *un = NULL;247 os0_t un = NULL; 248 248 size_t un_len = 0; 249 249 size_t nattr_used = 0; … … 293 293 and/or to the NAS-Identifier attribute. (Note that the RADIUS 294 294 NAS-Identifier is not required to be an FQDN.) 295 -> done in rgw_ msg_create_base.295 -> done in rgw_clients_create_origin. 296 296 297 297 - The response MUST have an Origin-AAA-Protocol AVP added, … … 453 453 /* Create the session if it is not already done */ 454 454 if (*session == NULL) { 455 char * sess_str = NULL; 455 os0_t sess_str = NULL; 456 size_t sess_strlen; 456 457 457 458 if (si_len) { 458 459 /* We already have the Session-Id, just use it */ 459 CHECK_FCT( fd_sess_fromsid ( (char *) /* this cast will be removed later */si, si_len, session, NULL) );460 CHECK_FCT( fd_sess_fromsid ( si, si_len, session, NULL) ); 460 461 } else { 461 462 /* Create a new Session-Id string */ 462 463 463 char * fqdn; 464 char * realm; 464 DiamId_t fqdn; 465 size_t fqdnlen; 466 DiamId_t realm; 467 size_t realmlen; 465 468 466 469 /* Get information on the RADIUS client */ 467 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, & realm) );470 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &fqdnlen, &realm, &realmlen) ); 468 471 469 472 /* If we have a user name, create the new session with it */ 470 473 if (un) { 471 474 int len; 472 /* If not found, create a new Session-Id. Theformat is: {fqdn;hi32;lo32;username;diamid} */475 /* If not found, create a new Session-Id. Our format is: {fqdn;hi32;lo32;username;diamid} */ 473 476 CHECK_MALLOC( sess_str = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) ); 474 len = sprintf( sess_str, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);475 CHECK_FCT( fd_sess_new(session, fqdn, sess_str, len) );477 len = sprintf((char *)sess_str, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid); 478 CHECK_FCT( fd_sess_new(session, fqdn, fqdnlen, sess_str, len) ); 476 479 free(sess_str); 477 480 } else { … … 483 486 484 487 /* Now, add the Session-Id AVP at beginning of Diameter message */ 485 CHECK_FCT( fd_sess_getsid(*session, &sess_str ) );488 CHECK_FCT( fd_sess_getsid(*session, &sess_str, &sess_strlen) ); 486 489 487 490 TRACE_DEBUG(FULL, "[auth.rgwx] Translating new message for session '%s'...", sess_str); … … 489 492 /* Add the Session-Id AVP as first AVP */ 490 493 CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) ); 491 value.os.data = (unsigned char *)sess_str;492 value.os.len = s trlen(sess_str);494 value.os.data = sess_str; 495 value.os.len = sess_strlen; 493 496 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); 494 497 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) ); … … 564 567 /* This macro converts a RADIUS attribute to a Diameter AVP of type OctetString */ 565 568 #define CONV2DIAM_STR( _dictobj_ ) \ 566 CHECK_PARAMS( attr->length >= 2 );\569 CHECK_PARAMS( attr->length >= sizeof(struct radius_attr_hdr) ); \ 567 570 /* Create the AVP with the specified dictionary model */ \ 568 571 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \ 569 value.os.len = attr->length - 2;\570 value.os.data = ( unsigned char *)(attr + 1);\572 value.os.len = attr->length - sizeof(struct radius_attr_hdr); \ 573 value.os.data = (os0_t)(attr + 1); \ 571 574 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); \ 572 575 /* Add the AVP in the Diameter message. */ \ … … 575 578 /* Same thing, for scalar AVPs of 32 bits */ 576 579 #define CONV2DIAM_32B( _dictobj_ ) \ 577 CHECK_PARAMS( attr->length == 6 );\580 CHECK_PARAMS( attr->length == sizeof(struct radius_attr_hdr)+sizeof(uint32_t) );\ 578 581 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \ 579 582 { \ … … 589 592 /* And the 64b version */ 590 593 #define CONV2DIAM_64B( _dictobj_ ) \ 591 CHECK_PARAMS( attr->length == 10);\594 CHECK_PARAMS( attr->length == sizeof(struct radius_attr_hdr)+sizeof(uint64_t) );\ 592 595 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \ 593 596 { \ … … 609 612 - The Destination-Realm AVP is created from the information found 610 613 in the RADIUS User-Name attribute. 611 -> done in rgw_ msg_create_base614 -> done in rgw_clients_create_origin 612 615 */ 613 616 case RADIUS_ATTR_USER_NAME: -
extensions/app_radgw/rgwx_debug.c
r356 r706 102 102 fd_log_debug(" Diameter session: NULL pointer\n"); 103 103 } else { 104 char * str; 105 CHECK_FCT( fd_sess_getsid(*session, &str) ); 104 os0_t str; 105 size_t str_len; 106 CHECK_FCT( fd_sess_getsid(*session, &str, &str_len) ); 106 107 107 108 fd_log_debug(" Diameter session: %s\n", str); -
extensions/app_radgw/rgwx_sip.c
r705 r706 58 58 /* This macro converts a RADIUS attribute to a Diameter AVP of type OctetString */ 59 59 #define CONV2DIAM_STR( _dictobj_ ) \ 60 CHECK_PARAMS( attr->length >= 2 );\60 CHECK_PARAMS( attr->length >= sizeof(struct radius_attr_hdr) ); \ 61 61 /* Create the AVP with the specified dictionary model */ \ 62 62 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \ 63 value.os.len = attr->length - 2;\64 value.os.data = ( unsigned char *)(attr + 1);\63 value.os.len = attr->length - sizeof(struct radius_attr_hdr); \ 64 value.os.data = (os0_t)(attr + 1); \ 65 65 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); \ 66 66 /* Add the AVP in the Diameter message. */ \ … … 68 68 69 69 #define CONV2DIAM_STR_AUTH( _dictobj_ ) \ 70 CHECK_PARAMS( attr->length >= 2 );\70 CHECK_PARAMS( attr->length >= sizeof(struct radius_attr_hdr) ); \ 71 71 /* Create the AVP with the specified dictionary model */ \ 72 72 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \ 73 value.os.len = attr->length - 2;\74 value.os.data = ( unsigned char *)(attr + 1);\73 value.os.len = attr->length - sizeof(struct radius_attr_hdr); \ 74 value.os.data = (os0_t)(attr + 1); \ 75 75 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); \ 76 76 /* Add the AVP in the Diameter message. */ \ 77 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) ); \77 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) ); \ 78 78 79 79 /* Same thing, for scalar AVPs of 32 bits */ 80 80 #define CONV2DIAM_32B( _dictobj_ ) \ 81 CHECK_PARAMS( attr->length == 6 );\81 CHECK_PARAMS( attr->length == sizeof(struct radius_attr_hdr)+sizeof(uint32_t) );\ 82 82 CHECK_FCT( fd_msg_avp_new ( cs->dict._dictobj_, 0, &avp ) ); \ 83 83 { \ 84 84 uint8_t * v = (uint8_t *)(attr + 1); \ 85 85 value.u32 = (v[0] << 24) \ 86 87 88 86 | (v[1] << 16) \ 87 | (v[2] << 8) \ 88 | v[3] ; \ 89 89 } \ 90 90 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); \ 91 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) ); 91 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) ); \ 92 92 93 93 … … 145 145 { 146 146 struct fd_list chain; 147 char *sid;147 os0_t sid; 148 148 size_t sidlen; 149 char *nonce;149 os0_t nonce; 150 150 size_t noncelen; 151 151 152 152 }; 153 153 154 static int nonce_add_element( char * nonce, size_t noncelen,char *sid, size_t sidlen, struct rgwp_config * state)154 static int nonce_add_element(os0_t nonce, size_t noncelen, os0_t sid, size_t sidlen, struct rgwp_config * state) 155 155 { 156 156 CHECK_PARAMS(nonce && state && sid && sidlen && noncelen); … … 159 159 CHECK_MALLOC(newelt=malloc(sizeof(noncechain))); 160 160 161 CHECK_MALLOC(newelt->nonce=malloc(noncelen)); 162 memcpy(newelt->nonce,nonce,noncelen); 161 CHECK_MALLOC(newelt->nonce= os0dup(nonce, noncelen)); 163 162 newelt->noncelen=noncelen; 164 163 165 CHECK_MALLOC(newelt->sid=malloc(sidlen)); 166 memcpy(newelt->sid,sid,sidlen); 164 CHECK_MALLOC(newelt->sid=os0dup(sid, sidlen)); 167 165 newelt->sidlen=sidlen; 168 166 … … 198 196 */ 199 197 //Retrieve sid from nonce 200 static char * nonce_get_sid(char *nonce, size_t noncelen, size_t * sidlen, struct rgwp_config *state)198 static os0_t nonce_get_sid(os0_t nonce, size_t noncelen, size_t * sidlen, struct rgwp_config *state) 201 199 { 202 200 struct fd_list * li; 203 char *sid=NULL;201 os0_t sid=NULL; 204 202 205 203 CHECK_PARAMS_DO(nonce && state && noncelen && sidlen, return NULL); 206 204 *sidlen=0; 207 205 208 // **Start mutex206 // **Start mutex 209 207 CHECK_POSIX_DO(pthread_mutex_lock(&state->nonce_mutex),); 210 208 for(li=state->listnonce.next;li!=&state->listnonce;li=li->next) … … 212 210 noncechain *temp=(noncechain *)li; 213 211 214 if (temp->noncelen==noncelen && strncmp(temp->nonce,nonce, noncelen)==0)212 if (!fd_os_cmp(temp->nonce, temp->noncelen, nonce, noncelen)) 215 213 { 216 214 fd_list_unlink (li); … … 224 222 } 225 223 CHECK_POSIX_DO(pthread_mutex_unlock(&state->nonce_mutex),); 226 // ***Stop mutex224 // ***Stop mutex 227 225 return sid; 228 226 } … … 230 228 static void nonce_deletelistnonce(struct rgwp_config *state) 231 229 { 232 // **Start mutex230 // **Start mutex 233 231 CHECK_POSIX_DO(pthread_mutex_lock(&state->nonce_mutex),); 234 232 while(!(FD_IS_LIST_EMPTY(&state->listnonce)) ) … … 243 241 } 244 242 CHECK_POSIX_DO(pthread_mutex_unlock(&state->nonce_mutex),); 245 // ***Stop mutex243 // ***Stop mutex 246 244 } 247 245 … … 338 336 int got_Dresponse = 0; 339 337 int got_Dalgorithm = 0; 340 char * sid = NULL; 341 char * un=NULL; 338 os0_t sid = NULL; 339 size_t sidlen; 340 os0_t un=NULL; 342 341 size_t un_len; 343 342 size_t nattr_used = 0; … … 352 351 if(*session) 353 352 { 354 TRACE_DEBUG(INFO," We are not supposed to receive a session in radSIP plugin.");353 TRACE_DEBUG(INFO,"INTERNAL ERROR: We are not supposed to receive a session in radSIP plugin."); 355 354 return EINVAL; 356 355 } … … 371 370 { 372 371 TRACE_DEBUG(ANNOYING, "Found a User-Name attribute: '%.*s'", attr->length- sizeof(struct radius_attr_hdr), (char *)(attr+1)); 373 un = ( char *)(attr + 1);372 un = (os0_t)(attr + 1); 374 373 un_len =attr->length - sizeof(struct radius_attr_hdr); 375 374 } … … 396 395 got_Dnonce = 1; 397 396 398 size_t sidlen; 399 400 sid=nonce_get_sid((char *)(attr+1),attr->length-2,&sidlen,cs); 397 sid=nonce_get_sid((os0_t)(attr+1), attr->length - sizeof(struct radius_attr_hdr), &sidlen, cs); 401 398 if(!sid) 402 399 { … … 406 403 CHECK_FCT(fd_sess_fromsid (sid, sidlen, session, NULL)); 407 404 free(sid); 408 405 409 406 410 407 break; … … 432 429 if (!*session) { 433 430 434 char * fqdn; 435 char * realm; 431 DiamId_t fqdn; 432 size_t fqdn_len; 433 DiamId_t realm; 434 size_t realm_len; 436 435 437 436 … … 439 438 440 439 /* Get information on the RADIUS client */ 441 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &realm) ); 442 443 int len; 440 CHECK_FCT( rgw_clients_get_origin(cli, &fqdn, &fqdn_len, &realm, &realm_len) ); 441 444 442 /* Create a new Session-Id. The format is: {fqdn;hi32;lo32;username;diamid} */ 445 443 CHECK_MALLOC( sid = malloc(un_len + 1 /* ';' */ + fd_g_config->cnf_diamid_len + 1 /* '\0' */) ); 446 len = sprintf(sid, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid);447 CHECK_FCT( fd_sess_new(session, fqdn, sid,len) );444 sidlen = sprintf((char *)sid, "%.*s;%s", (int)un_len, un, fd_g_config->cnf_diamid); 445 CHECK_FCT( fd_sess_new(session, fqdn, fqdn_len, sid, sidlen) ); 448 446 free(sid); 449 447 } … … 453 451 454 452 int i = 0; 455 if (un) { 456 /* Is there an '@' in the user name? We don't care for decorated NAI here */ 457 for (i = un_len - 2; i > 0; i--) { 458 if (un[i] == '@') { 459 i++; 460 break; 461 } 453 454 /* Is there an '@' in the user name? We don't care for decorated NAI here */ 455 for (i = un_len - 2; i > 0; i--) { 456 if (un[i] == '@') { 457 i++; 458 break; 462 459 } 463 460 } 461 464 462 if (i == 0) { 465 463 /* Not found in the User-Name => we use the local domain of this gateway */ 466 value.os.data = ( unsigned char *)fd_g_config->cnf_diamrlm;464 value.os.data = (os0_t)fd_g_config->cnf_diamrlm; 467 465 value.os.len = fd_g_config->cnf_diamrlm_len; 468 466 } else { 469 value.os.data = (unsigned char *)(un + i);467 value.os.data = un + i; 470 468 value.os.len = un_len - i; 471 469 } … … 475 473 476 474 /* Now, add the Session-Id AVP at beginning of Diameter message */ 477 CHECK_FCT( fd_sess_getsid(*session, &sid ) );475 CHECK_FCT( fd_sess_getsid(*session, &sid, &sidlen) ); 478 476 479 477 TRACE_DEBUG(FULL, "[sip.rgwx] Translating new message for session '%s'...", sid); … … 481 479 /* Add the Session-Id AVP as first AVP */ 482 480 CHECK_FCT( fd_msg_avp_new ( cs->dict.Session_Id, 0, &avp ) ); 483 value.os.data = (unsigned char *)sid;484 value.os.len = s trlen(sid);481 value.os.data = sid; 482 value.os.len = sidlen; 485 483 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); 486 484 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_FIRST_CHILD, avp) ); … … 552 550 CHECK_FCT( fd_msg_avp_add ( auth_data, MSG_BRW_LAST_CHILD, auth) ); 553 551 } 554 char * temp=NULL,*sipuri=NULL;555 552 556 553 for (idx = 0; idx < rad_req->attr_used; idx++) … … 597 594 { 598 595 //We extract Realm from Digest_URI 599 char *realm=NULL; 600 601 CHECK_MALLOC(temp=malloc(attr->length -1)); 602 strncpy(temp, (char *)(attr + 1), attr->length -2); 603 temp[attr->length-2] = '\0'; 604 605 realm = strtok( (char *)(temp), "@" ); 606 realm = strtok( NULL, "@" ); 607 free(temp); 608 temp=NULL; 596 DiamId_t realm=NULL; 597 size_t realm_len; 598 os0_t temp; 599 600 temp = (os0_t)(attr + 1); 601 602 for (i=attr->length - sizeof(struct radius_attr_hdr) - 1; i>=0; i--) { 603 if (temp[i] == '@') { 604 realm = (DiamId_t)temp + i + 1; 605 CHECK_FCT_DO( fd_os_validate_DiameterIdentity(&realm, &realm_len, 1), 606 realm = NULL ); 607 break; 608 } 609 } 610 609 611 if(realm!=NULL) 610 612 { 611 613 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Realm, 0, &avp ) ); 612 value.os.data=( unsigned char *)realm;613 value.os.len= strlen(realm);614 value.os.data=(os0_t)realm; 615 value.os.len=realm_len; 614 616 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); 615 617 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) ); … … 617 619 //We add SIP-Server-URI AVP because SIP server is registrar (through gateway) 618 620 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Server_URI, 0, &avp ) ); 619 value.os.data=( unsigned char *)realm;620 value.os.len= strlen(realm);621 value.os.data=(os0_t)realm; 622 value.os.len=realm_len; 621 623 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); 622 624 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) ); 623 625 626 free(realm); 624 627 } 625 628 else … … 641 644 //We add SIP-Server-URI AVP because SIP server is registrar (through gateway) 642 645 CHECK_FCT( fd_msg_avp_new ( cs->dict.SIP_Server_URI, 0, &avp ) ); 643 644 645 CHECK_MALLOC(temp=malloc(attr->length -1)); 646 strncpy(temp, (char *)(attr + 1), attr->length -2); 647 648 649 CHECK_MALLOC(sipuri=malloc(attr->length +3)); 650 strcpy(sipuri,"sip:"); 651 strcat(sipuri,(const char *)temp); 652 value.os.data=(unsigned char *)sipuri; 653 value.os.len=attr->length +2; 646 os0_t temp; 647 #define SIP_PREFIX "sip:" 648 size_t temp_len = attr->length - sizeof(struct radius_attr_hdr) + CONSTSTRLEN(SIP_PREFIX) + 1; 649 CHECK_MALLOC( temp = malloc(temp_len) ); 650 temp_len = snprintf((char *)temp, temp_len, SIP_PREFIX "%.*s", attr->length - sizeof(struct radius_attr_hdr), (char *)(attr + 1)); 651 652 value.os.data=temp; 653 value.os.len=temp_len; 654 654 655 655 free(temp); 656 temp=NULL;656 657 657 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); 658 658 CHECK_FCT( fd_msg_avp_add ( *diam_fw, MSG_BRW_LAST_CHILD, avp) ); … … 689 689 { 690 690 //[Note 3] If Digest-Algorithm is missing, 'MD5' is assumed. 691 #define DIGEST_ALGO_MD5 "MD5" 691 692 692 693 CHECK_FCT( fd_msg_avp_new ( cs->dict.Digest_Algorithm, 0, &avp ) ); 693 694 694 value.os.data = ( unsigned char *)"MD5";695 value.os.len = strlen((const char *)value.os.data);695 value.os.data = (os0_t)DIGEST_ALGO_MD5; 696 value.os.len = CONSTSTRLEN(DIGEST_ALGO_MD5) - 1; 696 697 CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); 697 698 CHECK_FCT( fd_msg_avp_add ( auth, MSG_BRW_LAST_CHILD, avp) ); … … 831 832 /* Retrieve the request identified which was stored in the session */ 832 833 if (session) { 833 char *sid=NULL;834 os0_t sid=NULL; 834 835 size_t sidlen; 835 fd_sess_getsid (session, &sid ); 836 sidlen=strlen(sid); 836 fd_sess_getsid (session, &sid, &sidlen ); 837 837 838 nonce_add_element( (char *)ahdr->avp_value->os.data,ahdr->avp_value->os.len, sid,sidlen, cs);838 nonce_add_element(ahdr->avp_value->os.data, ahdr->avp_value->os.len, sid, sidlen, cs); 839 839 } 840 840 break; -
extensions/app_sip/registrationtermination.c
r639 r706 147 147 // Create a new session 148 148 { 149 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "app_sip", 7 )); 150 char * sid; 151 CHECK_FCT( fd_sess_getsid ( sess, &sid )); 149 #define APP_SIP_SID_OPT "app_sip" 150 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)APP_SIP_SID_OPT, CONSTSTRLEN(APP_SIP_SID_OPT) )); 151 os0_t sid; 152 size_t sidlen; 153 CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); 152 154 CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); 153 value.os.data = (uint8_t *)sid;154 value.os.len = s trlen(sid);155 value.os.data = sid; 156 value.os.len = sidlen; 155 157 CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); 156 158 CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); -
extensions/dbg_interactive/dbg_interactive.i
r662 r706 152 152 153 153 /* Overwrite declaration to apply typemaps */ 154 int fd_sess_fromsid ( char * STRING, size_t LENGTH, struct session ** OUTPUT, int * BOOL_OUT);154 int fd_sess_fromsid ( unsigned char * STRING, size_t LENGTH, struct session ** OUTPUT, int * BOOL_OUT); 155 155 156 156 -
extensions/dbg_interactive/messages.i
r688 r706 341 341 342 342 /* Get the source */ 343 char *source() {344 char * s = NULL;345 int ret = fd_msg_source_get($self, &s);346 if (ret != 0) { 347 DI_ERROR(ret, NULL, NULL); 348 return NULL;349 } 350 return s;343 %cstring_output_allocate_size(char ** outid, size_t * outlen, /* do not free */); 344 void source(char ** outid, size_t * outlen) { 345 int ret = fd_msg_source_get($self, outid, outlen); 346 if (ret != 0) { 347 DI_ERROR(ret, NULL, NULL); 348 return; 349 } 350 return; 351 351 } 352 352 -
extensions/dbg_interactive/peers.i
r640 r706 97 97 98 98 %inline %{ 99 static struct peer_hdr * peer_search(char * diamid) {99 static struct peer_hdr * peer_search(char *STRING, size_t LENGTH) { 100 100 struct peer_hdr *r = NULL; 101 int ret = fd_peer_getbyid( diamid, &r );101 int ret = fd_peer_getbyid( STRING, LENGTH, 0, &r ); 102 102 if (ret) { 103 103 DI_ERROR(ret, NULL, NULL); -
extensions/dbg_interactive/routing.i
r640 r706 55 55 fd_rtd_free(&r); 56 56 } 57 void add(char * peerid, char * realm) { 58 int ret = fd_rtd_candidate_add($self, peerid, realm); 57 %apply (char *STRING, int LENGTH) { (char * peerid, size_t peeridlen) }; 58 %apply (char *STRING, int LENGTH) { (char * realm, size_t realmlen) }; 59 void add(char * peerid, size_t peeridlen, char * realm, size_t realmlen) { 60 int ret = fd_rtd_candidate_add($self, peerid, peeridlen, realm, realmlen); 59 61 if (ret != 0) { 60 62 DI_ERROR(ret, NULL, NULL); … … 62 64 } 63 65 void remove(char * STRING, size_t LENGTH) { 64 fd_rtd_candidate_del($self, STRING, LENGTH);65 } 66 void error(char * dest, char * STRING, size_t LENGTH, uint32_t rcode) {67 int ret = fd_rtd_error_add($self, dest, (uint8_t *)STRING, LENGTH, rcode);66 fd_rtd_candidate_del($self, (os0_t)STRING, LENGTH); 67 } 68 void error(char * peerid, size_t peeridlen, char * STRING, size_t LENGTH, uint32_t rcode) { 69 int ret = fd_rtd_error_add($self, peerid, peeridlen, (os0_t)STRING, LENGTH, rcode); 68 70 if (ret != 0) { 69 71 DI_ERROR(ret, NULL, NULL); -
extensions/dbg_interactive/sessions.i
r639 r706 40 40 %{ 41 41 /* call it (might be called from a different thread than the interpreter, when session times out) */ 42 static void call_the_python_cleanup_callback(session_state * state, char *sid, void * cb) {42 static void call_the_python_cleanup_callback(session_state * state, os0_t sid, void * cb) { 43 43 PyObject *result; 44 44 if (!cb) { … … 100 100 int ret; 101 101 struct session * s = NULL; 102 ret = fd_sess_new(&s, fd_g_config->cnf_diamid, "dbg_interactive", sizeof("dbg_interactive"));102 ret = fd_sess_new(&s, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"dbg_interactive", CONSTSTRLEN("dbg_interactive")); 103 103 if (ret != 0) { 104 104 DI_ERROR(ret, NULL, NULL); … … 110 110 int ret; 111 111 struct session * s = NULL; 112 ret = fd_sess_new(&s, diamid, STRING, LENGTH);112 ret = fd_sess_new(&s, diamid, 0, (os0_t)STRING, LENGTH); 113 113 if (ret != 0) { 114 114 DI_ERROR(ret, NULL, NULL); … … 120 120 int ret, n; 121 121 struct session * s = NULL; 122 ret = fd_sess_fromsid( STRING, LENGTH, &s, &n);122 ret = fd_sess_fromsid((os0_t)STRING, LENGTH, &s, &n); 123 123 if (ret != 0) { 124 124 DI_ERROR(ret, NULL, NULL); … … 144 144 return; 145 145 } 146 char * getsid() { 146 147 %cstring_output_allocate_size(char ** outsid, size_t * sidlen, /* do not free */); 148 void getsid(char ** outsid, size_t * sidlen) { 147 149 int ret; 148 char * sid = NULL; 149 ret = fd_sess_getsid( $self, &sid); 150 ret = fd_sess_getsid( $self, (void *)outsid, sidlen); 150 151 if (ret != 0) { 151 152 DI_ERROR(ret, NULL, NULL); 152 return NULL;153 return; 153 154 } 154 return sid;155 return; 155 156 } 156 157 void settimeout(long seconds) { -
extensions/test_app/ta_bench.c
r662 r706 130 130 131 131 /* Create a new session */ 132 CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, "app_test", 8 ), goto out ); 132 #define TEST_APP_SID_OPT "app_testb" 133 CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out ); 133 134 134 135 /* Create the random value to store with the session */ … … 145 146 /* Session-Id */ 146 147 { 147 char * sid; 148 CHECK_FCT_DO( fd_sess_getsid ( sess, &sid ), goto out ); 148 os0_t sid; 149 size_t sidlen; 150 CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), goto out ); 149 151 CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out ); 150 val.os.data = (uint8_t *)sid;151 val.os.len = s trlen(sid);152 val.os.data = sid; 153 val.os.len = sidlen; 152 154 CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); 153 155 CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out ); -
extensions/test_app/ta_cli.c
r662 r706 150 150 151 151 /* Create a new session */ 152 CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, "app_test", 8 ), goto out ); 152 #define TEST_APP_SID_OPT "app_test" 153 CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out ); 153 154 154 155 /* Create the random value to store with the session */ … … 165 166 /* Session-Id */ 166 167 { 167 char * sid; 168 CHECK_FCT_DO( fd_sess_getsid ( sess, &sid ), goto out ); 168 os0_t sid; 169 size_t sidlen; 170 CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), goto out ); 169 171 CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out ); 170 val.os.data = (uint8_t *)sid;171 val.os.len = s trlen(sid);172 val.os.data = sid; 173 val.os.len = sidlen; 172 174 CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); 173 175 CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out ); -
extensions/test_netemul/tne_process.c
r691 r706 88 88 /* Duplicate eventually, unless deactivated */ 89 89 if (tne_conf.dupl_proba != 0.0) { 90 char * src; 90 DiamId_t src; 91 size_t srclen; 91 92 /* Pick a random value in [0, 1] */ 92 93 double my_rand = drand48(); 93 94 m = pi->chain.o; 94 CHECK_FCT( fd_msg_source_get(m, &src ) );95 CHECK_FCT( fd_msg_source_get(m, &src, &srclen) ); 95 96 96 97 while (my_rand < (double) tne_conf.dupl_proba) { … … 105 106 CHECK_FCT( fd_msg_bufferize(m, &buf, &len) ); 106 107 CHECK_FCT( fd_msg_parse_buffer(&buf, len, &nm) ); 107 CHECK_FCT( fd_msg_source_set(nm, src, 0, NULL) );108 CHECK_FCT( fd_msg_source_set(nm, src, srclen, 0, NULL) ); 108 109 CHECK_FCT( fd_msg_hdr(nm, &nh) ); 109 110 nh->msg_flags |= CMD_FLAG_RETRANSMIT; /* Add the 'T' flag */ -
extensions/test_sip/locationinfo.c
r639 r706 62 62 // Create a new session 63 63 { 64 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "appsip", 6 )); 65 char * sid; 66 CHECK_FCT( fd_sess_getsid ( sess, &sid )); 64 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 )); 65 os0_t sid; 66 size_t sidlen; 67 CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); 67 68 CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); 68 value.os.data = (uint8_t *)sid;69 value.os.len = s trlen(sid);69 value.os.data = sid; 70 value.os.len = sidlen; 70 71 CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); 71 72 CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); -
extensions/test_sip/locationinfosl.c
r639 r706 62 62 // Create a new session 63 63 { 64 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "appsip", 6 )); 65 char * sid; 66 CHECK_FCT( fd_sess_getsid ( sess, &sid )); 64 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 )); 65 os0_t sid; 66 size_t sidlen; 67 CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); 67 68 CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); 68 value.os.data = (uint8_t *)sid;69 value.os.len = s trlen(sid);69 value.os.data = sid; 70 value.os.len = sidlen; 70 71 CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); 71 72 CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); -
extensions/test_sip/serverassignment.c
r639 r706 71 71 // Create a new session 72 72 { 73 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "appsip", 6 )); 74 char * sid; 75 CHECK_FCT( fd_sess_getsid ( sess, &sid )); 73 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 )); 74 os0_t sid; 75 size_t sidlen; 76 CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); 76 77 CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); 77 value.os.data = (uint8_t *)sid;78 value.os.len = s trlen(sid);78 value.os.data = sid; 79 value.os.len = sidlen; 79 80 CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); 80 81 CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); -
extensions/test_sip/userauthorization.c
r639 r706 67 67 // Create a new session 68 68 { 69 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, "appsip", 6 )); 70 char * sid; 71 CHECK_FCT( fd_sess_getsid ( sess, &sid )); 69 CHECK_FCT( fd_sess_new( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, (os0_t)"appsip", 6 )); 70 os0_t sid; 71 size_t sidlen; 72 CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen )); 72 73 CHECK_FCT( fd_msg_avp_new ( sip_dict.Session_Id, 0, &avp )); 73 value.os.data = (uint8_t *)sid;74 value.os.len = s trlen(sid);74 value.os.data = sid; 75 value.os.len = sidlen; 75 76 CHECK_FCT( fd_msg_avp_setvalue( avp, &value )); 76 77 CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_FIRST_CHILD, avp )); -
include/freeDiameter/libfdcore.h
r658 r706 108 108 char *cnf_file; /* Configuration file to parse, default is DEFAULT_CONF_FILE */ 109 109 110 char *cnf_diamid; /* Diameter Identity of the local peer (FQDN -- UTF-8) */111 size_t cnf_diamid_len; /*length of the previous string */112 char *cnf_diamrlm; /* Diameter realm of the local peer, default to realm part of diam_id */110 DiamId_t cnf_diamid; /* Diameter Identity of the local peer (FQDN -- ASCII) */ 111 size_t cnf_diamid_len;/* cached length of the previous string */ 112 DiamId_t cnf_diamrlm; /* Diameter realm of the local peer, default to realm part of cnf_diamid */ 113 113 size_t cnf_diamrlm_len;/* length of the previous string */ 114 114 … … 187 187 STATE_SUSPECT, /* A DWR was sent and not answered within TwTime. Failover in progress. */ 188 188 STATE_REOPEN, /* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */ 189 190 /* Ordering issues with multistream & state machine. -- see top of p_psm.c for explanation */ 191 STATE_OPEN_NEW, /* after CEA is sent, until a new message is received. Force ordering in this state */ 192 STATE_CLOSING_GRACE, /* after DPA is sent or received, give a short delay for messages in the pipe to be received. */ 189 193 190 194 /* Error state */ … … 205 209 , "STATE_SUSPECT" \ 206 210 , "STATE_REOPEN" \ 211 , "STATE_OPEN_NEW" \ 212 , "STATE_CLOSING_GRACE" \ 207 213 , "STATE_ZOMBIE" \ 208 214 }; … … 237 243 struct peer_info { 238 244 239 char * pi_diamid; /* UTF-8, \0 terminated. The Diameter Identity of the remote peer. */ 245 DiamId_t pi_diamid; /* (supposedly) UTF-8, \0 terminated. The Diameter Identity of the remote peer. */ 246 size_t pi_diamidlen; /* cached length of pi_diamid */ 240 247 241 248 struct { … … 250 257 } pic_flags; /* Flags influencing the connection to the remote peer */ 251 258 252 char * pic_realm; /* If configured, the daemon will matchthe received realm in CER/CEA matches this. */259 DiamId_t pic_realm; /* If configured, the daemon will check the received realm in CER/CEA matches this. */ 253 260 uint16_t pic_port; /* port to connect to. 0: default. */ 254 261 … … 263 270 struct { 264 271 265 enum peer_state pir_state; /* Current state of the peer in the state machine. fd_cpu_flush_cache() might be useful before reading. */ 266 267 char * pir_realm; /* The received realm in CER/CEA. */ 272 /* enum peer_state pir_state; */ 273 /* Since 1.1.0, read the state with fd_peer_getstate(peer). */ 274 275 DiamId_t pir_realm; /* The received realm in CER/CEA. */ 276 size_t pir_realmlen; /* length of the realm */ 268 277 269 278 uint32_t pir_vendorid; /* Content of the Vendor-Id AVP, or 0 by default */ 270 279 uint32_t pir_orstate; /* Origin-State-Id value */ 271 char * pir_prodname; /* copy of UTF-8Product-Name AVP (\0 terminated) */280 os0_t pir_prodname; /* copy of Product-Name AVP (\0 terminated) */ 272 281 uint32_t pir_firmrev; /* Content of the Firmware-Revision AVP */ 273 282 int pir_relay; /* The remote peer advertized the relay application */ … … 290 299 291 300 struct peer_hdr { 292 struct fd_list chain; /* Li st of all the peers, ordered by their Diameter Id*/301 struct fd_list chain; /* Link into the list of all the peers, ordered by their Diameter Id (fd_os_cmp) */ 293 302 struct peer_info info; /* The public data */ 294 303 … … 339 348 * 340 349 * PARAMETERS: 341 * diamid : A \0 terminated string. 350 * diamid : an UTF8 string describing the diameter Id of the peer to seek 351 * diamidlen : length of the diamid 352 * igncase : perform an almost-case-insensitive search? (slower) 342 353 * peer : The peer is stored here if it exists. 343 354 * … … 349 360 * !0 : An error occurred. 350 361 */ 351 int fd_peer_getbyid( char * diamid, struct peer_hdr ** peer ); 362 int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer ); 363 364 /* 365 * FUNCTION: fd_peer_get_state 366 * 367 * PARAMETERS: 368 * peer : The peer which state to read 369 * 370 * DESCRIPTION: 371 * Returns the current state of the peer. 372 * 373 * RETURN VALUE: 374 * -1 : peer is invalid 375 * >=0 : the state of the peer at the time of reading. 376 */ 377 int fd_peer_get_state(struct peer_hdr *peer); 352 378 353 379 /* … … 474 500 /* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */ 475 501 int fd_msg_add_origin ( struct msg * msg, int osi ); 502 503 /* Generate a new Session-Id and add it at the beginning of the message (opt is added at the end of the sid if provided) */ 504 int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen ); 505 476 506 477 507 /* Parse a message against our dictionary, and in case of error log and eventually build the error reply (on return and EBADMSG, *msg == NULL or *msg is the error message ready to send) */ -
include/freeDiameter/libfdproto.h
r705 r706 45 45 * DEBUG 46 46 * MACROS 47 * OCTET STRINGS 47 48 * THREADS 48 49 * LISTS … … 567 568 #endif /* BUFSIZ */ 568 569 570 /* This gives the length of a const string */ 571 #define CONSTSTRLEN( str ) (sizeof(str) - 1) 572 573 574 /*============================================================*/ 575 /* BINARY STRINGS */ 576 /*============================================================*/ 577 578 /* Compute a hash value of a binary string. 579 The hash must remain local to this machine, there is no guarantee that same input 580 will give same output on a different system (endianness) */ 581 uint32_t fd_os_hash ( uint8_t * string, size_t len ); 582 583 /* This type used for binary strings that contain no \0 except as their last character. 584 It means some string operations can be used on it. */ 585 typedef uint8_t * os0_t; 586 587 /* Same as strdup but for os0_t strings */ 588 os0_t os0dup_int(os0_t s, size_t l); 589 #define os0dup( _s, _l) (void *)os0dup_int((os0_t)(_s), _l) 590 591 /* Check that an octet string value can be used as os0_t */ 592 static __inline__ int fd_os_is_valid_os0(uint8_t * os, size_t oslen) { 593 /* The only situation where it is not valid is when it contains a \0 inside the octet string */ 594 return (memchr(os, '\0', oslen) == NULL); 595 } 596 597 /* The following type denotes a verified DiameterIdentity value (that contains only pure letters, digits, hyphen, dot) */ 598 typedef char * DiamId_t; 599 600 /* Maximum length of a hostname we accept */ 601 #ifndef HOST_NAME_MAX 602 #define HOST_NAME_MAX 512 603 #endif /* HOST_NAME_MAX */ 604 605 /* Check if a binary string contains a valid Diameter Identity value. 606 rfc3588 states explicitely that such a Diameter Identity consists only of ASCII characters. */ 607 int fd_os_is_valid_DiameterIdentity(uint8_t * os, size_t ossz); 608 609 /* This checks a string is a valid DiameterIdentity and applies IDNA transformations otherwise (xn--...) */ 610 int fd_os_validate_DiameterIdentity(char ** id, size_t * outsz, int memory /* 0: *id can be realloc'd. 1: *id must be malloc'd on output (was static) */ ); 611 612 /* Create an order relationship for binary strings (not needed to be \0 terminated). 613 It does NOT mimic strings relationships so that it is more efficient. It is case sensitive. 614 (the strings are actually first ordered by their lengh, then by their bytes contents) 615 returns: -1 if os1 < os2; +1 if os1 > os2; 0 if they are equal */ 616 int fd_os_cmp_int(os0_t os1, size_t os1sz, os0_t os2, size_t os2sz); 617 #define fd_os_cmp(_o1, _l1, _o2, _l2) fd_os_cmp_int((os0_t)(_o1), _l1, (os0_t)(_o2), _l2) 618 619 /* A roughly case-insensitive variant, which actually only compares ASCII chars (0-127) in a case-insentitive maneer 620 -- this should be OK with (old) DNS names. Not sure how it works with IDN... 621 -- it also clearly does not support locales where a lowercase letter uses more space than upper case, such as ß -> ss 622 It is slower than fd_os_cmp... 623 This function should give the same order as fd_os_cmp, except when it finds 2 strings to be equal. 624 Note that the result is NOT the same as strcasecmp !!! 625 */ 626 int fd_os_almostcasecmp_int(uint8_t * os1, size_t os1sz, uint8_t * os2, size_t os2sz); 627 #define fd_os_almostcasecmp(_o1, _l1, _o2, _l2) fd_os_almostcasecmp_int((os0_t)(_o1), _l1, (os0_t)(_o2), _l2) 569 628 570 629 … … 602 661 } 603 662 604 /* Force flushing the cache of a CPU before reading a shared memory area (use only for atomic reads such as int and void*) */605 extern pthread_mutex_t fd_cpu_mtx_dummy; /* only for the macro bellow, so that we have reasonably fresh pir_state value when needed */606 #define fd_cpu_flush_cache() { \607 (void)pthread_mutex_lock(&fd_cpu_mtx_dummy); \608 (void)pthread_mutex_unlock(&fd_cpu_mtx_dummy); \609 }610 611 663 612 664 /************* … … 673 725 674 726 675 /*============================================================*/676 /* HASH */677 /*============================================================*/678 679 /* Compute a hash value of a string (session id, diameter id, ...) */680 uint32_t fd_hash ( char * string, size_t len );681 682 683 727 684 728 /*============================================================*/ … … 802 846 struct dict_vendor_data { 803 847 vendor_id_t vendor_id; /* ID of a vendor */ 804 char *vendor_name; /* The name of this vendor */848 char * vendor_name; /* The name of this vendor */ 805 849 }; 806 850 … … 808 852 enum { 809 853 VENDOR_BY_ID = 10, /* "what" points to a vendor_id_t */ 810 VENDOR_BY_NAME, /* "what" points to a string*/854 VENDOR_BY_NAME, /* "what" points to a char * */ 811 855 VENDOR_OF_APPLICATION /* "what" points to a struct dict_object containing an application (see bellow) */ 812 856 }; … … 872 916 struct dict_application_data { 873 917 application_id_t application_id; /* ID of the application */ 874 char *application_name; /* The name of this application */918 char * application_name; /* The name of this application */ 875 919 }; 876 920 … … 878 922 enum { 879 923 APPLICATION_BY_ID = 20, /* "what" points to a application_id_t */ 880 APPLICATION_BY_NAME, /* "what" points to a string*/924 APPLICATION_BY_NAME, /* "what" points to a char * */ 881 925 APPLICATION_OF_TYPE, /* "what" points to a struct dict_object containing a type object (see bellow) */ 882 926 APPLICATION_OF_COMMAND /* "what" points to a struct dict_object containing a command (see bellow) */ … … 947 991 uint8_t *data; /* bytes buffer */ 948 992 size_t len; /* length of the data buffer */ 949 } os; /* Storage for an octet string , data is alloc'd and must be freed*/993 } os; /* Storage for an octet string */ 950 994 int32_t i32; /* integer 32 */ 951 995 int64_t i64; /* integer 64 */ … … 1011 1055 struct dict_type_data { 1012 1056 enum dict_avp_basetype type_base; /* How the data of such AVP must be interpreted */ 1013 char *type_name; /* The name of this type */1057 char * type_name; /* The name of this type */ 1014 1058 dict_avpdata_interpret type_interpret;/* cb to convert the AVP value in more comprehensive format (or NULL) */ 1015 1059 dict_avpdata_encode type_encode; /* cb to convert formatted data into an AVP value (or NULL) */ … … 1019 1063 /* The criteria for searching a type object in the dictionary */ 1020 1064 enum { 1021 TYPE_BY_NAME = 30, /* "what" points to a string*/1065 TYPE_BY_NAME = 30, /* "what" points to a char * */ 1022 1066 TYPE_OF_ENUMVAL, /* "what" points to a struct dict_object containing an enumerated constant (DICT_ENUMVAL, see bellow). */ 1023 1067 TYPE_OF_AVP /* "what" points to a struct dict_object containing an AVP object. */ … … 1068 1112 /* Type to hold data of named constants for AVP */ 1069 1113 struct dict_enumval_data { 1070 char *enum_name; /* The name of this constant */1114 char * enum_name; /* The name of this constant */ 1071 1115 union avp_value enum_value; /* Value of the constant. Union term depends on parent type's base type. */ 1072 1116 }; … … 1080 1124 /* Identifier of the parent type, one of the following must not be NULL */ 1081 1125 struct dict_object *type_obj; 1082 char *type_name;1126 char * type_name; 1083 1127 1084 1128 /* Search criteria for the constant */ … … 1183 1227 avp_code_t avp_code; /* Code of the avp */ 1184 1228 vendor_id_t avp_vendor; /* Vendor of the AVP, or 0 */ 1185 char *avp_name; /* Name of this AVP */1229 char * avp_name; /* Name of this AVP */ 1186 1230 uint8_t avp_flag_mask; /* Mask of fixed AVP flags */ 1187 1231 uint8_t avp_flag_val; /* Values of the fixed flags */ … … 1192 1236 enum { 1193 1237 AVP_BY_CODE = 50, /* "what" points to an avp_code_t, vendor is always 0 */ 1194 AVP_BY_NAME, /* "what" points to a string, vendor is always 0 */1238 AVP_BY_NAME, /* "what" points to a char *, vendor is always 0 */ 1195 1239 AVP_BY_CODE_AND_VENDOR, /* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_code are set */ 1196 1240 AVP_BY_NAME_AND_VENDOR, /* "what" points to a struct dict_avp_request (see bellow), where avp_vendor and avp_name are set */ … … 1202 1246 vendor_id_t avp_vendor; 1203 1247 avp_code_t avp_code; 1204 char *avp_name;1248 char * avp_name; 1205 1249 }; 1206 1250 … … 1310 1354 struct dict_cmd_data { 1311 1355 command_code_t cmd_code; /* code of the command */ 1312 char *cmd_name; /* Name of the command */1356 char * cmd_name; /* Name of the command */ 1313 1357 uint8_t cmd_flag_mask; /* Mask of fixed-value flags */ 1314 1358 uint8_t cmd_flag_val; /* values of the fixed flags */ … … 1317 1361 /* The criteria for searching an avp object in the dictionary */ 1318 1362 enum { 1319 CMD_BY_NAME = 60, /* "what" points to a string*/1363 CMD_BY_NAME = 60, /* "what" points to a char * */ 1320 1364 CMD_BY_CODE_R, /* "what" points to a command_code_t. The "Request" command is returned. */ 1321 1365 CMD_BY_CODE_A, /* "what" points to a command_code_t. The "Answer" command is returned. */ … … 1590 1634 * ENOMEM : Not enough memory to complete the operation 1591 1635 */ 1592 int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char *sid, void * opaque), void * opaque );1636 int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, os0_t sid, void * opaque), void * opaque ); 1593 1637 /* Macro to avoid casting everywhere */ 1594 1638 #define fd_sess_handler_create( _handler, _cleanup, _opaque ) \ 1595 fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, char *, void *))(_cleanup), (void *)(_opaque) )1639 fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, os0_t, void *))(_cleanup), (void *)(_opaque) ) 1596 1640 1597 1641 … … 1621 1665 * PARAMETERS: 1622 1666 * session : The location where the session object will be created upon success. 1623 * diamId : \0-terminated string containing a Diameter Identity. 1624 * opt : Additional string. Usage is described bellow. 1667 * diamid : a Diameter Identity, or NULL. 1668 * diamidlen : if diamid is \0-terminated, this can be 0. Otherwise, the length of diamid. 1669 * opt : Additional string, or NULL. Usage is described bellow. 1625 1670 * optlen : if opt is \0-terminated, this can be 0. Otherwise, the length of opt. 1626 1671 * … … 1639 1684 * ENOMEM : Not enough memory to complete the operation 1640 1685 */ 1641 int fd_sess_new ( struct session ** session, char * diamId, char* opt, size_t optlen );1686 int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen ); 1642 1687 1643 1688 /* … … 1645 1690 * 1646 1691 * PARAMETERS: 1647 * sid : pointer to a string containing a Session-Id ( UTF-8).1692 * sid : pointer to a string containing a Session-Id (should be UTF-8). 1648 1693 * len : length of the sid string (which does not need to be '\0'-terminated) 1649 1694 * session : On success, pointer to the session object created / retrieved. … … 1659 1704 * ENOMEM : Not enough memory to complete the operation 1660 1705 */ 1661 int fd_sess_fromsid ( char* sid, size_t len, struct session ** session, int * isnew);1706 int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * isnew); 1662 1707 1663 1708 /* … … 1666 1711 * PARAMETERS: 1667 1712 * session : Pointer to a session object. 1668 * sid : On success, the location of a (\0-terminated) stringis stored here.1713 * sid : On success, the location of the sid is stored here. 1669 1714 * 1670 1715 * DESCRIPTION: 1671 1716 * Retrieve the session identifier (Session-Id) corresponding to a session object. 1672 * The returned sid is a n UTF-8 string terminated by \0, suitable for calls to strlen and strcpy.1717 * The returned sid is a \0-terminated binary string which might be UTF-8 (but there is no guarantee in the framework). 1673 1718 * It may be used for example to set the value of an AVP. 1674 1719 * Note that the sid string is not copied, just its reference... do not free it! 1675 1720 * 1676 1721 * RETURN VALUE: 1677 * 0 : The sid parameter hasbeen updated.1678 * EINVAL : A parameter is invalid. 1679 */ 1680 int fd_sess_getsid ( struct session * session, char ** sid);1722 * 0 : The sid & len parameters have been updated. 1723 * EINVAL : A parameter is invalid. 1724 */ 1725 int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen ); 1681 1726 1682 1727 /* … … 1711 1756 * 1712 1757 * DESCRIPTION: 1713 * Destroys a session an all associated data, if any.1758 * Destroys all associated states of a session, if any. 1714 1759 * Equivalent to a session timeout expired, but the effect is immediate. 1760 * The session itself is marked as deleted, and will be freed when it is not referenced 1761 * by any message anymore. 1715 1762 * 1716 1763 * RETURN VALUE: … … 1727 1774 * 1728 1775 * DESCRIPTION: 1729 * Destroys the resources of a session, only if no session_state is associated with it. 1730 * 1731 * RETURN VALUE: 1732 * 0 : The session no longer exists. 1776 * Equivalent to fd_sess_destroy, only if no session_state is associated with the session. 1777 * Otherwise, this function has no effect (except that it sets *session to NULL). 1778 * 1779 * RETURN VALUE: 1780 * 0 : The session was reclaimed. 1733 1781 * EINVAL : A parameter is invalid. 1734 1782 */ … … 1802 1850 void fd_rtd_free(struct rt_data ** rtd); 1803 1851 1804 /* Add a peer to the candidates list */1805 int fd_rtd_candidate_add(struct rt_data * rtd, char * peerid, char * realm);1806 1807 /* Remove a peer from the candidates (if it is found) */1808 void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */);1852 /* Add a peer to the candidates list. */ 1853 int fd_rtd_candidate_add(struct rt_data * rtd, DiamId_t peerid, size_t peeridlen, DiamId_t realm, size_t realmlen); 1854 1855 /* Remove a peer from the candidates (if it is found). The search is case-insensitive. */ 1856 void fd_rtd_candidate_del(struct rt_data * rtd, uint8_t * id, size_t idsz); 1809 1857 1810 1858 /* Extract the list of valid candidates, and initialize their scores to 0 */ … … 1812 1860 1813 1861 /* If a peer returned a protocol error for this message, save it so that we don't try to send it there again */ 1814 int fd_rtd_error_add(struct rt_data * rtd, char * sentto, uint8_t * origin, size_t originsz, uint32_t rcode);1862 int fd_rtd_error_add(struct rt_data * rtd, DiamId_t sentto, size_t senttolen, uint8_t * origin, size_t originsz, uint32_t rcode); 1815 1863 1816 1864 /* The extracted list items have the following structure: */ 1817 1865 struct rtd_candidate { 1818 1866 struct fd_list chain; /* link in the list returned by the previous fct */ 1819 char * diamid; /* the diameter Id of the peer */ 1820 char * realm; /* the diameter realm of the peer (if known) */ 1867 DiamId_t diamid; /* the diameter Id of the peer */ 1868 size_t diamidlen; /* cached size of the diamid string */ 1869 DiamId_t realm; /* the diameter realm of the peer */ 1870 size_t realmlen; /* cached size of realm */ 1821 1871 int score; /* the current routing score for this peer, see fd_rt_out_register definition for details */ 1822 1872 }; 1823 1873 1824 /* Reorder the list of peers */1874 /* Reorder the list of peers by score */ 1825 1875 int fd_rtd_candidate_reorder(struct fd_list * candidates); 1826 1876 … … 2239 2289 * PARAMETERS: 2240 2290 * msg : A msg object. 2241 * diamid : The diameter id of the peer from which this message was received.2291 * diamid,len : The diameter id of the peer from which this message was received. 2242 2292 * add_rr : if true, a Route-Record AVP is added to the message with content diamid. In that case, dict must be supplied. 2243 2293 * dict : a dictionary with definition of Route-Record AVP (if add_rr is true) … … 2252 2302 * !0 : an error occurred. 2253 2303 */ 2254 int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict );2255 int fd_msg_source_get( struct msg * msg, char ** diamid);2304 int fd_msg_source_set( struct msg * msg, DiamId_t diamid, size_t diamidlen, int add_rr, struct dictionary * dict ); 2305 int fd_msg_source_get( struct msg * msg, DiamId_t *diamid, size_t * diamidlen ); 2256 2306 2257 2307 /* … … 2370 2420 * ENOMEM : Unable to allocate enough memory to create the buffer object. 2371 2421 */ 2372 int fd_msg_bufferize ( struct msg * msg, u nsigned char** buffer, size_t * len );2422 int fd_msg_bufferize ( struct msg * msg, uint8_t ** buffer, size_t * len ); 2373 2423 2374 2424 /* … … 2392 2442 * EINVAL : A parameter is invalid. 2393 2443 */ 2394 int fd_msg_parse_buffer ( u nsigned char** buffer, size_t buflen, struct msg ** msg );2444 int fd_msg_parse_buffer ( uint8_t ** buffer, size_t buflen, struct msg ** msg ); 2395 2445 2396 2446 /* Parsing Error Information structure */ … … 2654 2704 * session : The session corresponding to this object, if any. 2655 2705 * action : Upon return, the action that must be taken on the message 2706 * error_code : Upon return with action == DISP_ACT_ERROR, contains the error (such as "DIAMETER_UNABLE_TO_COMPLY") 2656 2707 * 2657 2708 * DESCRIPTION: … … 2666 2717 * (other errors) 2667 2718 */ 2668 int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, c onst char ** error_code );2719 int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, char ** error_code ); 2669 2720 2670 2721 -
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