Navigation


Changeset 87:c1c0f8a45c67 in freeDiameter


Ignore:
Timestamp:
Dec 4, 2009, 5:23:06 PM (14 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Backup

Files:
6 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/apps.c

    r43 r87  
    7777}
    7878
    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 */
     80int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail)
    8181{
     82        struct fd_list * li;
    8283       
     84        TRACE_ENTRY("%p %d %p", list, aid, detail);
     85        CHECK_PARAMS(list && detail);
    8386       
     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;
    84101}
    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  
    6565        return fd_app_merge(&fd_g_config->cnf_apps, aid, vid, auth, acct);
    6666}
     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  
    730730        }
    731731       
     732        /* Check if we have common applications */
     733        TODO("DIAMETER_NO_COMMON_APPLICATION ?");
     734       
    732735        /* Do we send ISI back ? */
    733736        if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
  • freeDiameter/routing.c

    r86 r87  
    191191 */
    192192
     193/* Test if a User-Name AVP contains a Decorated NAI -- RFC4282, draft-ietf-dime-nai-routing-04 */
     194static 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 */
     217static 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
    193264/* Function to return an error to an incoming request */
    194 static int return_error(struct msg * msg, char * error_code)
     265static int return_error(struct msg * msg, char * error_code, char * error_message, struct avp * failedavp)
    195266{
    196267        struct fd_peer * peer;
     
    216287
    217288        /* 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 ) );
    219290
    220291        /* Send the answer */
     
    246317                int is_req = 0;
    247318                int is_err = 0;
     319                char * qry_src = NULL;
    248320               
    249321                /* Test if we were told to stop */
     
    265337                /* Handle incorrect bits */
    266338                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 );
    268340                        continue;
    269341                }
    270342               
    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 */
    276537        } while (1);
    277538       
     
    282543}
    283544
    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 */
     547static 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       
     615fatal_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}
    289620
    290621
     
    294625{
    295626        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"); */
    296629        return ENOTSUP;
    297630}
  • include/freeDiameter/freeDiameter.h

    r86 r87  
    705705       
    706706int 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);
     707int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail);
    709708
    710709#endif /* _FREEDIAMETER_H */
  • include/freeDiameter/libfreeDiameter.h

    r85 r87  
    13441344
    13451345/* AVPs (Vendor 0) */
     1346#define AC_USER_NAME                    1
    13461347#define AC_PROXY_STATE                  33
    13471348#define AC_HOST_IP_ADDRESS              257
Note: See TracChangeset for help on using the changeset viewer.