Changeset 87:c1c0f8a45c67 in freeDiameter
- Timestamp:
- Dec 4, 2009, 5:23:06 PM (14 years ago)
- Branch:
- default
- Phase:
- public
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
freeDiameter/apps.c
r43 r87 77 77 } 78 78 79 /* Tag any common application between target and reference (into target)*/80 int fd_app_ find_common(struct fd_list * target, struct fd_list * reference)79 /* Check if a given application id is in a list */ 80 int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail) 81 81 { 82 struct fd_list * li; 82 83 84 TRACE_ENTRY("%p %d %p", list, aid, detail); 85 CHECK_PARAMS(list && detail); 83 86 87 *detail = NULL; 88 89 /* Search in the list */ 90 for (li = list->next; li != list; li = li->next) { 91 struct fd_app * a = (struct fd_app *)li; 92 if (a->appid < aid) 93 continue; 94 95 if (a->appid == aid) 96 *detail = a; 97 break; 98 } 99 100 return 0; 84 101 } 85 86 /* Return true if at least one app was tagged common, false otherwise */87 int fd_app_gotcommon(struct fd_list * apps)88 {89 90 }91 -
freeDiameter/dispatch.c
r43 r87 65 65 return fd_app_merge(&fd_g_config->cnf_apps, aid, vid, auth, acct); 66 66 } 67 68 69 /* Note2: if the message is still for local delivery, we should test for duplicate 70 (draft-asveren-dime-dupcons-00). This may conflict with path validation decisions, no clear answer yet */ 71 -
freeDiameter/p_ce.c
r78 r87 730 730 } 731 731 732 /* Check if we have common applications */ 733 TODO("DIAMETER_NO_COMMON_APPLICATION ?"); 734 732 735 /* Do we send ISI back ? */ 733 736 if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) { -
freeDiameter/routing.c
r86 r87 191 191 */ 192 192 193 /* Test if a User-Name AVP contains a Decorated NAI -- RFC4282, draft-ietf-dime-nai-routing-04 */ 194 static int is_decorated_NAI(union avp_value * un) 195 { 196 int i; 197 TRACE_ENTRY("%p", un); 198 199 /* If there was no User-Name, we return false */ 200 if (un == NULL) 201 return 0; 202 203 /* Search if there is a '!' before any '@' -- do we need to check it contains a '.' ? */ 204 for (i = 0; i < un->os.len; i++) { 205 if ( un->os.data[i] == (unsigned char) '!' ) 206 return 1; 207 if ( un->os.data[i] == (unsigned char) '@' ) 208 break; 209 if ( un->os.data[i] == (unsigned char) '\\' ) 210 i++; /* next one was escaped */ 211 } 212 213 return 0; 214 } 215 216 /* Create new User-Name and Destination-Realm values */ 217 static int process_decorated_NAI(union avp_value * un, union avp_value * dr) 218 { 219 int i, at_idx = 0, sep_idx = 0; 220 unsigned char * old_un; 221 TRACE_ENTRY("%p %p", un, dr); 222 CHECK_PARAMS(un && dr); 223 224 /* Save the decorated User-Name, for example 'homerealm.example.net!user@otherrealm.example.net' */ 225 old_un = un->os.data; 226 227 /* Search the positions of the first '!' and the '@' in the string */ 228 for (i = 0; i < un->os.len; i++) { 229 if ( (!sep_idx) && (old_un[i] == (unsigned char) '!') ) 230 sep_idx = i; 231 if ( old_un[i] == (unsigned char) '@' ) { 232 at_idx = i; 233 break; 234 } 235 if ( un->os.data[i] == (unsigned char) '\\' ) 236 i++; /* next one is escaped */ 237 } 238 239 CHECK_PARAMS( 0 < sep_idx < at_idx < un->os.len); 240 241 /* Create the new User-Name value */ 242 CHECK_MALLOC( un->os.data = malloc( at_idx ) ); 243 memcpy( un->os.data, old_un + sep_idx + 1, at_idx - sep_idx ); /* user@ */ 244 memcpy( un->os.data + at_idx - sep_idx, old_un, sep_idx ); /* homerealm.example.net */ 245 246 /* Create the new Destination-Realm value */ 247 CHECK_MALLOC( dr->os.data = realloc(dr->os.data, sep_idx) ); 248 memcpy( dr->os.data, old_un, sep_idx ); 249 dr->os.len = sep_idx; 250 251 TRACE_DEBUG(FULL, "Processed Decorated NAI '%.*s' into '%.*s' (%.*s)", 252 un->os.len, old_un, 253 at_idx, un->os.data, 254 dr->os.len, dr->os.data); 255 256 un->os.len = at_idx; 257 free(old_un); 258 259 return 0; 260 } 261 262 263 193 264 /* Function to return an error to an incoming request */ 194 static int return_error(struct msg * msg, char * error_code )265 static int return_error(struct msg * msg, char * error_code, char * error_message, struct avp * failedavp) 195 266 { 196 267 struct fd_peer * peer; … … 216 287 217 288 /* Set the error code */ 218 CHECK_FCT( fd_msg_rescode_set(msg, error_code, NULL, NULL, 1 ) );289 CHECK_FCT( fd_msg_rescode_set(msg, error_code, error_message, failedavp, 1 ) ); 219 290 220 291 /* Send the answer */ … … 246 317 int is_req = 0; 247 318 int is_err = 0; 319 char * qry_src = NULL; 248 320 249 321 /* Test if we were told to stop */ … … 265 337 /* Handle incorrect bits */ 266 338 if (is_req && is_err) { 267 CHECK_FCT_DO( return_error( msg, "DIAMETER_INVALID_HDR_BITS" ), goto fatal_error );339 CHECK_FCT_DO( return_error( msg, "DIAMETER_INVALID_HDR_BITS", "R & E bits were set", NULL), goto fatal_error ); 268 340 continue; 269 341 } 270 342 271 272 273 274 275 343 /* If it is a request, we must analyze its content to decide what we do with it */ 344 if (is_req) { 345 struct avp * avp, *un = NULL; 346 union avp_value * un_val = NULL, *dr_val = NULL; 347 enum status { UNKNOWN, YES, NO }; 348 /* Are we Destination-Host? */ 349 enum status is_dest_host = UNKNOWN; 350 /* Are we Destination-Realm? */ 351 enum status is_dest_realm = UNKNOWN; 352 /* Do we support the application of the message? */ 353 enum status is_local_app = UNKNOWN; 354 355 /* Check if we have local support for the message application */ 356 if ( (hdr->msg_appl == 0) || (hdr->msg_appl == AI_RELAY) ) { 357 TRACE_DEBUG(INFO, "Received a routable message with application id 0, returning DIAMETER_APPLICATION_UNSUPPORTED"); 358 CHECK_FCT_DO( return_error( msg, "DIAMETER_APPLICATION_UNSUPPORTED", "Routable message with application id 0 or relay", NULL), goto fatal_error ); 359 continue; 360 } else { 361 struct fd_app * app; 362 CHECK_FCT_DO( fd_app_check(&fd_g_config->cnf_apps, hdr->msg_appl, &app), goto fatal_error ); 363 is_local_app = (app ? YES : NO); 364 } 365 366 /* Parse the message for Dest-Host and Dest-Realm */ 367 CHECK_FCT_DO( fd_msg_browse(msg, MSG_BRW_FIRST_CHILD, &avp, NULL), goto fatal_error ); 368 while (avp) { 369 struct avp_hdr * ahdr; 370 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &ahdr ), goto fatal_error ); 371 372 if (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) { 373 switch (ahdr->avp_code) { 374 case AC_DESTINATION_HOST: 375 /* Parse this AVP */ 376 CHECK_FCT_DO( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict ), goto fatal_error ); 377 ASSERT( ahdr->avp_value ); 378 /* Compare the Destination-Host AVP of the message with our identity */ 379 if (ahdr->avp_value->os.len != fd_g_config->cnf_diamid_len) { 380 is_dest_host = NO; 381 } else { 382 is_dest_host = (strncasecmp(fd_g_config->cnf_diamid, (char *)ahdr->avp_value->os.data, fd_g_config->cnf_diamid_len) 383 ? NO : YES); 384 } 385 break; 386 387 case AC_DESTINATION_REALM: 388 /* Parse this AVP */ 389 CHECK_FCT_DO( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict ), goto fatal_error ); 390 ASSERT( ahdr->avp_value ); 391 dr_val = ahdr->avp_value; 392 /* Compare the Destination-Realm AVP of the message with our identity */ 393 if (ahdr->avp_value->os.len != fd_g_config->cnf_diamrlm_len) { 394 is_dest_realm = NO; 395 } else { 396 is_dest_realm = (strncasecmp(fd_g_config->cnf_diamrlm, (char *)ahdr->avp_value->os.data, fd_g_config->cnf_diamrlm_len) 397 ? NO : YES); 398 } 399 break; 400 401 case AC_USER_NAME: 402 /* Parse this AVP */ 403 CHECK_FCT_DO( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict ), goto fatal_error ); 404 ASSERT( ahdr->avp_value ); 405 un = avp; 406 un_val = ahdr->avp_value; 407 break; 408 } 409 } 410 411 if ((is_dest_host != UNKNOWN) && (is_dest_realm != UNKNOWN) && un) 412 break; 413 414 /* Go to next AVP */ 415 CHECK_FCT_DO( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), goto fatal_error ); 416 } 417 418 /* OK, now decide what we do with the request */ 419 420 /* Handle the missing routing AVPs first */ 421 if ( is_dest_realm == UNKNOWN ) { 422 CHECK_FCT_DO( return_error( msg, "DIAMETER_COMMAND_UNSUPPORTED", "Non-routable message not supported (invalid bit ? missing Destination-Realm ?)", NULL), goto fatal_error ); 423 continue; 424 } 425 426 /* If we are listed as Destination-Host */ 427 if (is_dest_host == YES) { 428 if (is_local_app == YES) { 429 /* Ok, give the message to the dispatch thread */ 430 CHECK_FCT_DO(fd_fifo_post(fd_g_local, &msg), goto fatal_error ); 431 } else { 432 /* We don't support the application, reply an error */ 433 CHECK_FCT_DO( return_error( msg, "DIAMETER_APPLICATION_UNSUPPORTED", NULL, NULL), goto fatal_error ); 434 } 435 continue; 436 } 437 438 /* If the message is explicitely for someone else */ 439 if ((is_dest_host == NO) || (is_dest_realm == NO)) { 440 if (fd_g_config->cnf_flags.no_fwd) { 441 CHECK_FCT_DO( return_error( msg, "DIAMETER_UNABLE_TO_DELIVER", "This peer is not an agent", NULL), goto fatal_error ); 442 continue; 443 } 444 } else { 445 /* Destination-Host was not set, and Destination-Realm is matching : we may handle or pass to a fellow peer */ 446 447 /* test for decorated NAI (draft-ietf-dime-nai-routing-04 section 4.4) */ 448 if (is_decorated_NAI(un_val)) { 449 /* Handle the decorated NAI */ 450 CHECK_FCT_DO( process_decorated_NAI(un_val, dr_val), 451 { 452 /* If the process failed, we assume it is because of the AVP format */ 453 CHECK_FCT_DO( return_error( msg, "DIAMETER_INVALID_AVP_VALUE", "Failed to process decorated NAI", un), goto fatal_error ); 454 continue; 455 } ); 456 457 /* We have transformed the AVP, now submit it again in the queue */ 458 CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto fatal_error ); 459 continue; 460 } 461 462 if (is_local_app == YES) { 463 /* Handle localy since we are able to */ 464 CHECK_FCT_DO(fd_fifo_post(fd_g_local, &msg), goto fatal_error ); 465 continue; 466 } 467 468 if (fd_g_config->cnf_flags.no_fwd) { 469 /* We return an error */ 470 CHECK_FCT_DO( return_error( msg, "DIAMETER_APPLICATION_UNSUPPORTED", NULL, NULL), goto fatal_error ); 471 continue; 472 } 473 } 474 475 /* From that point, for requests, we will call the registered callbacks, then forward to another peer */ 476 477 } else { 478 /* The message is an answer */ 479 struct msg * qry; 480 481 /* Retrieve the corresponding query and its origin */ 482 CHECK_FCT_DO( fd_msg_answ_getq( msg, &qry ), goto fatal_error ); 483 CHECK_FCT_DO( fd_msg_source_get( qry, &qry_src ), goto fatal_error ); 484 485 if ((!qry_src) && (!is_err)) { 486 /* The message is a normal answer to a request issued localy, we do not call the callbacks chain on it. */ 487 CHECK_FCT_DO(fd_fifo_post(fd_g_local, &msg), goto fatal_error ); 488 continue; 489 } 490 491 /* From that point, for answers, we will call the registered callbacks, then pass it to the dispatch module or forward it */ 492 } 493 494 /* Call all registered callbacks for this message */ 495 { 496 struct fd_list * li; 497 498 CHECK_FCT_DO( pthread_rwlock_rdlock( &rt_fwd_lock ), goto fatal_error ); 499 pthread_cleanup_push( fd_cleanup_rwlock, &rt_fwd_lock ); 500 501 /* requests: dir = 1 & 2 => in order; answers = 3 & 2 => in reverse order */ 502 for ( li = (is_req ? rt_fwd_list.next : rt_fwd_list.prev) ; msg && (li != &rt_fwd_list) ; li = (is_req ? li->next : li->prev) ) { 503 struct rt_hdl * rh = (struct rt_hdl *)li; 504 505 if (is_req && (rh->dir > RT_FWD_ALL)) 506 break; 507 if ((!is_req) && (rh->dir < RT_FWD_ALL)) 508 break; 509 510 /* Ok, call this cb */ 511 TRACE_DEBUG(ANNOYING, "Calling next FWD callback on %p : %p", msg, rh->rt_fwd_cb); 512 CHECK_FCT_DO( (*rh->rt_fwd_cb)(rh->cbdata, &msg), 513 { 514 TRACE_DEBUG(INFO, "A FWD routing callback returned an error, message discarded."); 515 fd_msg_dump_walk(INFO, msg); 516 fd_msg_free(msg); 517 msg = NULL; 518 } ); 519 } 520 521 pthread_cleanup_pop(0); 522 CHECK_FCT_DO( pthread_rwlock_unlock( &rt_fwd_lock ), goto fatal_error ); 523 524 /* If a callback has handled the message, we stop now */ 525 if (!msg) 526 continue; 527 } 528 529 /* Now handle the message to the next step: either forward to another peer, or for local delivery */ 530 if (is_req || qry_src) { 531 CHECK_FCT_DO(fd_fifo_post(fd_g_outgoing, &msg), goto fatal_error ); 532 } else { 533 CHECK_FCT_DO(fd_fifo_post(fd_g_local, &msg), goto fatal_error ); 534 } 535 536 /* We're done with this message */ 276 537 } while (1); 277 538 … … 282 543 } 283 544 284 /* Note: after testing if the message is to be handled locally, we should test for decorated NAI 285 (draft-ietf-dime-nai-routing-04 section 4.4) */ 286 287 /* Note2: if the message is still for local delivery, we should test for duplicate 288 (draft-asveren-dime-dupcons-00). This may conflict with path validation decisions, no clear answer yet */ 545 546 /* The (routing-out) thread -- see description in freeDiameter.h */ 547 static void * routing_out_thr(void * arg) 548 { 549 TRACE_ENTRY("%p", arg); 550 551 /* Set the thread name */ 552 if (arg) { 553 char buf[48]; 554 snprintf(buf, sizeof(buf), "Routing-OUT %p", arg); 555 fd_log_threadname ( buf ); 556 } else { 557 fd_log_threadname ( "Routing-OUT" ); 558 } 559 560 /* Main thread loop */ 561 do { 562 struct msg * msg; 563 struct msg_hdr * hdr; 564 int is_req = 0; 565 566 /* Test if we were told to stop */ 567 pthread_testcancel(); 568 569 /* Get the next message from the ougoing queue */ 570 CHECK_FCT_DO( fd_fifo_get ( fd_g_outgoing, &msg ), goto fatal_error ); 571 572 if (TRACE_BOOL(FULL)) { 573 TRACE_DEBUG(FULL, "Picked next message:"); 574 fd_msg_dump_one(FULL, msg); 575 } 576 577 /* Read the message header */ 578 CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto fatal_error ); 579 is_req = hdr->msg_flags & CMD_FLAG_REQUEST; 580 581 /* For answers, the routing is very easy */ 582 if ( ! is_req ) { 583 struct msg * qry; 584 char * qry_src = NULL; 585 struct fd_peer * peer = NULL; 586 587 /* Retrieve the corresponding query and its origin */ 588 CHECK_FCT_DO( fd_msg_answ_getq( msg, &qry ), goto fatal_error ); 589 CHECK_FCT_DO( fd_msg_source_get( qry, &qry_src ), goto fatal_error ); 590 591 ASSERT( qry_src ); /* if it is NULL, the message should have been in the LOCAL queue! */ 592 593 /* Find the peer corresponding to this name */ 594 CHECK_FCT_DO( fd_peer_getbyid( qry_src, (void *) &peer ), goto fatal_error ); 595 if ((!peer) || (peer->p_hdr.info.runtime.pir_state != STATE_OPEN)) { 596 TRACE_DEBUG(INFO, "Unable to forward answer message to peer '%s', deleted or not in OPEN state.", qry_src); 597 fd_msg_dump_walk(INFO, msg); 598 fd_msg_free(msg); 599 continue; 600 } 601 602 /* Push the message into this peer */ 603 CHECK_FCT_DO( fd_out_send(&msg, NULL, peer), goto fatal_error ); 604 605 /* We're done with this answer */ 606 continue; 607 } 608 609 /* The message is a request */ 610 TODO("use struct rt_data and fd_msg_rt_get"); 611 612 /* We're done with this message */ 613 } while (1); 614 615 fatal_error: 616 TRACE_DEBUG(INFO, "An error occurred in routing module! OUT thread is terminating..."); 617 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 618 return NULL; 619 } 289 620 290 621 … … 294 625 { 295 626 TODO("Start the routing threads"); 627 628 /* Later: TODO("Set the thresholds for the IN and OUT queues to create more routing threads as needed"); */ 296 629 return ENOTSUP; 297 630 } -
include/freeDiameter/freeDiameter.h
r86 r87 705 705 706 706 int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct); 707 int fd_app_find_common(struct fd_list * target, struct fd_list * reference); 708 int fd_app_gotcommon(struct fd_list * apps); 707 int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail); 709 708 710 709 #endif /* _FREEDIAMETER_H */ -
include/freeDiameter/libfreeDiameter.h
r85 r87 1344 1344 1345 1345 /* AVPs (Vendor 0) */ 1346 #define AC_USER_NAME 1 1346 1347 #define AC_PROXY_STATE 33 1347 1348 #define AC_HOST_IP_ADDRESS 257
Note: See TracChangeset
for help on using the changeset viewer.