Changeset 706:4ffbc9f1e922 in freeDiameter for libfdcore/routing_dispatch.c
- Timestamp:
- Feb 9, 2011, 3:26:58 PM (13 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libfdcore/routing_dispatch.c
r691 r706 208 208 struct fd_peer * peer; 209 209 struct fd_app *found; 210 CHECK_FCT( fd_peer_getbyid( c->diamid, (void *)&peer ) );211 if (peer && (peer->p_hdr.info.runtime.pir_relay == 0)) {210 CHECK_FCT( fd_peer_getbyid( c->diamid, c->diamidlen, 0, (void *)&peer ) ); 211 if (peer && !peer->p_hdr.info.runtime.pir_relay) { 212 212 /* Check if the remote peer advertised the message's appli */ 213 213 CHECK_FCT( fd_app_check(&peer->p_hdr.info.runtime.pir_apps, hdr->msg_appl, &found) ); … … 264 264 for (li = candidates->next; li != candidates; li = li->next) { 265 265 struct rtd_candidate *c = (struct rtd_candidate *) li; 266 267 #if 0 /* this is actually useless since the sending process will also ensure that the peer is still available */ 266 268 struct fd_peer * peer; 267 CHECK_FCT( fd_peer_getbyid( c->diamid, (void *)&peer ) ); 268 if (peer) { 269 if (dh 270 && (dh->os.len == strlen(peer->p_hdr.info.pi_diamid)) 271 /* Here again we use strncasecmp on UTF8 data... This should probably be changed. */ 272 && (strncasecmp(peer->p_hdr.info.pi_diamid, (char *)dh->os.data, dh->os.len) == 0)) { 273 /* The candidate is the Destination-Host */ 274 c->score += FD_SCORE_FINALDEST; 275 } else { 276 if (dr && peer->p_hdr.info.runtime.pir_realm 277 && (dr->os.len == strlen(peer->p_hdr.info.runtime.pir_realm)) 278 /* Yet another case where we use strncasecmp on UTF8 data... Hmmm :-( */ 279 && (strncasecmp(peer->p_hdr.info.runtime.pir_realm, (char *)dr->os.data, dr->os.len) == 0)) { 280 /* The candidate's realm matchs the Destination-Realm */ 281 c->score += FD_SCORE_REALM; 282 } 269 /* Since the candidates list comes from the peers list, we do not have any issue with upper/lower case to find the peer object */ 270 CHECK_FCT( fd_peer_getbyid( c->diamid, c->diamidlen, 0, (void *)&peer ) ); 271 if (!peer) 272 continue; /* it has been deleted since the candidate list was generated; avoid sending to this one in that case. */ 273 #endif /* 0 */ 274 275 /* In the AVPs, the value comes from the network, so let's be case permissive */ 276 if (dh && !fd_os_almostcasecmp(dh->os.data, dh->os.len, c->diamid, c->diamidlen) ) { 277 /* The candidate is the Destination-Host */ 278 c->score += FD_SCORE_FINALDEST; 279 } else { 280 if (dr && !fd_os_almostcasecmp(dr->os.data, dr->os.len, c->realm, c->realmlen) ) { 281 /* The candidate's realm matchs the Destination-Realm */ 282 c->score += FD_SCORE_REALM; 283 283 } 284 284 } … … 298 298 299 299 TRACE_ENTRY("%p %p %p", un, excl_idx, at_idx); 300 CHECK_PARAMS_DO( un && excl_idx, return ); 300 CHECK_PARAMS_DO( un && excl_idx && at_idx, return ); 301 301 302 *excl_idx = 0; 303 *at_idx = 0; 302 304 303 305 /* Search if there is a '!' before any '@' -- do we need to check it contains a '.' ? */ … … 307 309 if (!*excl_idx) 308 310 *excl_idx = i; 309 if (!at_idx) 310 return; 311 continue; 311 312 } 312 313 /* If we reach the realm part, we can stop */ 313 314 if ( un->os.data[i] == (unsigned char) '@' ) { 314 if (at_idx) 315 *at_idx = i; 315 *at_idx = i; 316 316 break; 317 } 318 /* Stop if we find a \0 in the middle */ 319 if ( un->os.data[i] == 0 ) { 320 return; 317 321 } 318 322 /* Skip escaped characters */ … … 321 325 continue; 322 326 } 323 /* Skip UTF-8 characters spanning on several bytes */324 if ( (un->os.data[i] & 0xF8) == 0xF0 ) { /* 11110zzz */325 i += 3;326 continue;327 }328 if ( (un->os.data[i] & 0xF0) == 0xE0 ) { /* 1110yyyy */329 i += 2;330 continue;331 }332 if ( (un->os.data[i] & 0xE0) == 0xC0 ) { /* 110yyyxx */333 i += 1;334 continue;335 }336 327 } 337 328 … … 340 331 341 332 /* Test if a User-Name AVP contains a Decorated NAI -- RFC4282, RFC5729 */ 342 static int is_decorated_NAI(union avp_value * un)343 {344 int i;345 TRACE_ENTRY("%p", un);346 347 /* If there was no User-Name, we return false */348 if (un == NULL)349 return 0;350 351 nai_get_indexes(un, &i, NULL);352 353 return i;354 }355 356 333 /* Create new User-Name and Destination-Realm values */ 357 static int process_decorated_NAI( union avp_value * un, union avp_value * dr)358 { 359 int at_idx = 0, sep_idx = 0;334 static int process_decorated_NAI(int * was_nai, union avp_value * un, union avp_value * dr) 335 { 336 int at_idx, sep_idx; 360 337 unsigned char * old_un; 361 TRACE_ENTRY("%p %p ", un, dr);362 CHECK_PARAMS( un && dr);338 TRACE_ENTRY("%p %p %p", was_nai, un, dr); 339 CHECK_PARAMS(was_nai && un && dr); 363 340 364 341 /* Save the decorated User-Name, for example 'homerealm.example.net!user@otherrealm.example.net' */ … … 367 344 /* Search the positions of the first '!' and the '@' in the string */ 368 345 nai_get_indexes(un, &sep_idx, &at_idx); 369 CHECK_PARAMS( (0 < sep_idx) && (sep_idx < at_idx) && (at_idx < un->os.len)); 346 if ((!sep_idx) || (sep_idx > at_idx) || !fd_os_is_valid_DiameterIdentity(old_un, sep_idx /* this is the new realm part */)) { 347 *was_nai = 0; 348 return 0; 349 } 350 351 *was_nai = 1; 370 352 371 353 /* Create the new User-Name value */ … … 390 372 } 391 373 374 392 375 /* Function to return an error to an incoming request */ 393 376 static int return_error(struct msg ** pmsg, char * error_code, char * error_message, struct avp * failedavp) … … 398 381 /* Get the source of the message */ 399 382 { 400 char * id; 401 CHECK_FCT( fd_msg_source_get( *pmsg, &id ) ); 383 DiamId_t id; 384 size_t idlen; 385 CHECK_FCT( fd_msg_source_get( *pmsg, &id, &idlen ) ); 402 386 403 387 if (id == NULL) { … … 406 390 407 391 /* Search the peer with this id */ 408 CHECK_FCT( fd_peer_getbyid( id, (void *)&peer ) );392 CHECK_FCT( fd_peer_getbyid( id, idlen, 0, (void *)&peer ) ); 409 393 410 394 if (!peer) { … … 439 423 /****************************************************************************/ 440 424 441 /* These are the functions of each threads: dispatch & routing */442 425 /* The DISPATCH message processing */ 443 426 static int msg_dispatch(struct msg ** pmsg) … … 447 430 struct session * sess; 448 431 enum disp_action action; 449 c onst char * ec = NULL;450 c onst char * em = NULL;432 char * ec = NULL; 433 char * em = NULL; 451 434 452 435 /* Read the message header */ … … 460 443 CHECK_FCT_DO( ret = fd_msg_parse_or_error( pmsg ), 461 444 { 462 /* in case of error , the message is already dump'd*/445 /* in case of error */ 463 446 if ((ret == EBADMSG) && (*pmsg != NULL)) { 464 447 /* msg now contains the answer message to send back */ … … 512 495 em = "The message was not handled by any extension callback"; 513 496 ec = "DIAMETER_COMMAND_UNSUPPORTED"; 514 497 /* and continue as if an error occurred... */ 515 498 case DISP_ACT_ERROR: 516 499 /* We have a problem with delivering the message */ … … 528 511 /* Create an answer with the error code and message */ 529 512 CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, pmsg, 0 ) ); 530 CHECK_FCT( fd_msg_rescode_set(*pmsg, (char *)ec, (char *)em, NULL, 1 ) );513 CHECK_FCT( fd_msg_rescode_set(*pmsg, ec, em, NULL, 1 ) ); 531 514 532 515 case DISP_ACT_SEND: … … 545 528 int is_req = 0; 546 529 int is_err = 0; 547 char * qry_src = NULL; 530 DiamId_t qry_src = NULL; 531 size_t qry_src_len = 0; 548 532 549 533 /* Read the message header */ … … 572 556 /* Check if we have local support for the message application */ 573 557 if ( (hdr->msg_appl == 0) || (hdr->msg_appl == AI_RELAY) ) { 574 TRACE_DEBUG(INFO, "Received a routable message with application id 0, returning DIAMETER_APPLICATION_UNSUPPORTED"); 558 TRACE_DEBUG(INFO, "Received a routable message with application id 0 or " _stringize(AI_RELAY) " (relay),\n" 559 " returning DIAMETER_APPLICATION_UNSUPPORTED"); 575 560 CHECK_FCT( return_error( pmsg, "DIAMETER_APPLICATION_UNSUPPORTED", "Routable message with application id 0 or relay", NULL) ); 576 561 return 0; … … 587 572 struct fd_pei error_info; 588 573 int ret; 574 575 memset(&error_info, 0, sizeof(struct fd_pei)); 576 589 577 CHECK_FCT( fd_msg_avp_hdr( avp, &ahdr ) ); 590 578 … … 604 592 ASSERT( ahdr->avp_value ); 605 593 /* Compare the Destination-Host AVP of the message with our identity */ 606 if (ahdr->avp_value->os.len != fd_g_config->cnf_diamid_len) { 594 if (!fd_os_almostcasecmp(ahdr->avp_value->os.data, ahdr->avp_value->os.len, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len)) { 595 is_dest_host = YES; 596 } else { 607 597 is_dest_host = NO; 608 } else {609 is_dest_host = (strncasecmp(fd_g_config->cnf_diamid, (char *)ahdr->avp_value->os.data, fd_g_config->cnf_diamid_len)610 ? NO : YES);611 598 } 612 599 break; … … 626 613 dr_val = ahdr->avp_value; 627 614 /* Compare the Destination-Realm AVP of the message with our identity */ 628 if (ahdr->avp_value->os.len != fd_g_config->cnf_diamrlm_len) { 615 if (!fd_os_almostcasecmp(dr_val->os.data, dr_val->os.len, fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len)) { 616 is_dest_realm = YES; 617 } else { 629 618 is_dest_realm = NO; 630 } else {631 is_dest_realm = (strncasecmp(fd_g_config->cnf_diamrlm, (char *)ahdr->avp_value->os.data, fd_g_config->cnf_diamrlm_len)632 ? NO : YES);633 619 } 634 620 break; 635 621 622 /* we also use User-Name for decorated NAI */ 636 623 case AC_USER_NAME: 637 624 /* Parse this AVP */ … … 652 639 } 653 640 641 /* Stop when we found all 3 AVPs -- they are supposed to be at the beginning of the message, so this should be fast */ 654 642 if ((is_dest_host != UNKNOWN) && (is_dest_realm != UNKNOWN) && un) 655 643 break; … … 682 670 if ((is_dest_host == NO) || (is_dest_realm == NO)) { 683 671 if (fd_g_config->cnf_flags.no_fwd) { 684 CHECK_FCT( return_error( pmsg, "DIAMETER_UNABLE_TO_DELIVER", " This peer is not anagent", NULL) );672 CHECK_FCT( return_error( pmsg, "DIAMETER_UNABLE_TO_DELIVER", "I am not a Diameter agent", NULL) ); 685 673 return 0; 686 674 } 687 675 } else { 688 676 /* Destination-Host was not set, and Destination-Realm is matching : we may handle or pass to a fellow peer */ 677 int is_nai = 0; 689 678 690 679 /* test for decorated NAI (RFC5729 section 4.4) */ 691 if (is_decorated_NAI(un_val)) {692 /* Handle the decorated NAI */693 CHECK_FCT_DO( process_decorated_NAI(un_val, dr_val),694 {695 /* If the process failed, we assume it is because of the AVP format */696 CHECK_FCT( return_error( pmsg, "DIAMETER_INVALID_AVP_VALUE", "Failed to process decorated NAI", un) );697 return 0;698 } );699 680 /* Handle the decorated NAI */ 681 CHECK_FCT_DO( process_decorated_NAI(&is_nai, un_val, dr_val), 682 { 683 /* If the process failed, we assume it is because of the AVP format */ 684 CHECK_FCT( return_error( pmsg, "DIAMETER_INVALID_AVP_VALUE", "Failed to process decorated NAI", un) ); 685 return 0; 686 } ); 687 688 if (is_nai) { 700 689 /* We have transformed the AVP, now submit it again in the queue */ 701 690 CHECK_FCT(fd_fifo_post(fd_g_incoming, pmsg) ); … … 724 713 /* Retrieve the corresponding query and its origin */ 725 714 CHECK_FCT( fd_msg_answ_getq( *pmsg, &qry ) ); 726 CHECK_FCT( fd_msg_source_get( qry, &qry_src ) );715 CHECK_FCT( fd_msg_source_get( qry, &qry_src, &qry_src_len ) ); 727 716 728 717 if ((!qry_src) && (!is_err)) { … … 733 722 734 723 /* From that point, for answers, we will call the registered callbacks, then pass it to the dispatch module or forward it */ 724 TODO("Callback for answers with a Redirect code?"); 735 725 } 736 726 … … 800 790 if ( ! is_req ) { 801 791 struct msg * qry; 802 char * qry_src = NULL; 792 DiamId_t qry_src = NULL; 793 size_t qry_src_len = 0; 803 794 struct msg_hdr * qry_hdr; 804 795 struct fd_peer * peer = NULL; … … 806 797 /* Retrieve the corresponding query and its origin */ 807 798 CHECK_FCT( fd_msg_answ_getq( *pmsg, &qry ) ); 808 CHECK_FCT( fd_msg_source_get( qry, &qry_src ) );799 CHECK_FCT( fd_msg_source_get( qry, &qry_src, &qry_src_len ) ); 809 800 810 801 ASSERT( qry_src ); /* if it is NULL, the message should have been in the LOCAL queue! */ 811 802 812 803 /* Find the peer corresponding to this name */ 813 CHECK_FCT( fd_peer_getbyid( qry_src, (void *) &peer ) ); 814 fd_cpu_flush_cache(); 815 if ((!peer) || (peer->p_hdr.info.runtime.pir_state != STATE_OPEN)) { 804 CHECK_FCT( fd_peer_getbyid( qry_src, qry_src_len, 0, (void *) &peer ) ); 805 if (fd_peer_getstate(peer) != STATE_OPEN) { 816 806 fd_msg_log( FD_MSG_LOG_DROPPED, *pmsg, "Unable to forward answer to deleted / closed peer '%s'.", qry_src); 817 807 fd_msg_free(*pmsg); … … 844 834 for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) { 845 835 struct fd_peer * p = (struct fd_peer *)li->o; 846 CHECK_FCT_DO( ret = fd_rtd_candidate_add(rtd, p->p_hdr.info.pi_diamid, p->p_hdr.info.runtime.pir_realm), { CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_activ_peers_rw), ); return ret; } ); 836 CHECK_FCT_DO( ret = fd_rtd_candidate_add(rtd, 837 p->p_hdr.info.pi_diamid, 838 p->p_hdr.info.pi_diamidlen, 839 p->p_hdr.info.runtime.pir_realm, 840 p->p_hdr.info.runtime.pir_realmlen), 841 { CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_activ_peers_rw), ); return ret; } ); 847 842 } 848 843 CHECK_FCT( pthread_rwlock_unlock(&fd_g_activ_peers_rw) ); … … 867 862 } ); 868 863 ASSERT( ahdr->avp_value ); 869 /* Remove this value from the list */870 fd_rtd_candidate_del(rtd, (char *)ahdr->avp_value->os.data, ahdr->avp_value->os.len);864 /* Remove this value from the list. We don't need to pay special attention to the contents here. */ 865 fd_rtd_candidate_del(rtd, ahdr->avp_value->os.data, ahdr->avp_value->os.len); 871 866 } 872 867 … … 876 871 } 877 872 878 /* Note: we reset the scores and pass the message to the callbacks, maybe we could re-use the saved scores when we have received an error ? */873 /* Note: we reset the scores and pass the message to the callbacks, maybe we could re-use the saved scores when we have received an error ? -- TODO */ 879 874 880 875 /* Ok, we have our list in rtd now, let's (re)initialize the scores */ … … 928 923 929 924 /* Search for the peer */ 930 CHECK_FCT( fd_peer_getbyid( c->diamid, (void *)&peer ) ); 931 932 fd_cpu_flush_cache(); 933 if (peer && (peer->p_hdr.info.runtime.pir_state == STATE_OPEN)) { 925 CHECK_FCT( fd_peer_getbyid( c->diamid, c->diamidlen, 0, (void *)&peer ) ); 926 927 if (fd_peer_getstate(peer) == STATE_OPEN) { 934 928 /* Send to this one */ 935 929 CHECK_FCT_DO( fd_out_send(pmsg, NULL, peer, 0), continue ); … … 964 958 /* Control of the threads */ 965 959 static enum { RUN = 0, STOP = 1 } order_val = RUN; 966 static pthread_mutex_t order_ lock = PTHREAD_MUTEX_INITIALIZER;960 static pthread_mutex_t order_state_lock = PTHREAD_MUTEX_INITIALIZER; 967 961 968 962 /* Threads report their status */ … … 970 964 static void cleanup_state(void * state_loc) 971 965 { 972 if (state_loc) 973 *(enum thread_state *)state_loc = NOTRUNNING; 966 CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), ); 967 *(enum thread_state *)state_loc = NOTRUNNING; 968 CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), ); 974 969 } 975 970 … … 991 986 992 987 /* Mark the thread running */ 988 CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), ); 993 989 *(enum thread_state *)arg = RUNNING; 994 fd_cpu_flush_cache();990 CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), ); 995 991 996 992 do { … … 1000 996 { 1001 997 int must_stop; 1002 CHECK_POSIX_DO( pthread_mutex_lock(&order_ lock), { ASSERT(0); } ); /* we lock to flush the caches */998 CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), { ASSERT(0); } ); /* we lock to flush the caches */ 1003 999 must_stop = (order_val == STOP); 1004 CHECK_POSIX_DO( pthread_mutex_unlock(&order_ lock), { ASSERT(0); } );1000 CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), { ASSERT(0); } ); 1005 1001 if (must_stop) 1006 1002 goto end; … … 1014 1010 { 1015 1011 int ret; 1016 ret = fd_fifo_get ( queue, &msg ); 1012 struct timespec ts; 1013 1014 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), goto fatal_error ); 1015 ts.tv_sec += 1; 1016 1017 ret = fd_fifo_timedget ( queue, &msg, &ts ); 1018 if (ret == ETIMEDOUT) 1019 /* loop, check if the thread must stop now */ 1020 continue; 1017 1021 if (ret == EPIPE) 1018 1022 /* The queue was destroyed, we are probably exiting */ … … 1100 1104 CHECK_FCT( fd_rt_out_register( dont_send_if_no_common_app, NULL, 10, NULL ) ); 1101 1105 CHECK_FCT( fd_rt_out_register( score_destination_avp, NULL, 10, NULL ) ); 1106 1107 TODO("built-in callbacks for Redirect messages?"); 1108 1102 1109 return 0; 1103 1110 } … … 1106 1113 int fd_rtdisp_cleanstop(void) 1107 1114 { 1108 CHECK_POSIX ( pthread_mutex_lock(&order_lock));1115 CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), ); 1109 1116 order_val = STOP; 1110 CHECK_POSIX ( pthread_mutex_unlock(&order_lock));1117 CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), ); 1111 1118 1112 1119 return 0; … … 1117 1124 TRACE_ENTRY("%p %p", st, thr); 1118 1125 CHECK_PARAMS_DO(st && thr, return); 1126 int terminated; 1127 1128 CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), ); 1129 terminated = (*st == NOTRUNNING); 1130 CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), ); 1131 1119 1132 1120 1133 /* Wait for a second for the thread to complete, by monitoring my_state */ 1121 fd_cpu_flush_cache(); 1122 if (*st != NOTRUNNING) { 1134 if (!terminated) { 1123 1135 TRACE_DEBUG(INFO, "Waiting for the %s thread to have a chance to terminate", th_name); 1124 1136 do { … … 1131 1143 1132 1144 while (TS_IS_INFERIOR( &ts, &ts_final )) { 1133 fd_cpu_flush_cache(); 1134 if (*st == NOTRUNNING) 1145 1146 CHECK_POSIX_DO( pthread_mutex_lock(&order_state_lock), ); 1147 terminated = (*st == NOTRUNNING); 1148 CHECK_POSIX_DO( pthread_mutex_unlock(&order_state_lock), ); 1149 if (terminated) 1135 1150 break; 1136 1151
Note: See TracChangeset
for help on using the changeset viewer.