Navigation


Changeset 34:0e2b57789361 in freeDiameter


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

Backup for the WE, some warnings remaining

Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/CMakeLists.txt

    r33 r34  
    2323        p_out.c
    2424        p_psm.c
     25        p_sr.c
    2526        server.c
    2627        tcp.c
  • freeDiameter/fD.h

    r33 r34  
    9393int fd_dict_base_protocol(struct dictionary * dict);
    9494
     95/* Sentinel for the sent requests list */
     96struct sr_list {
     97        struct fd_list  srs;
     98        pthread_mutex_t mtx;
     99};
     100
    95101/* Peers */
    96102struct fd_peer { /* The "real" definition of the peer structure */
     
    137143       
    138144        /* Sent requests (for fallback), list of struct sentreq ordered by hbh */
    139         struct fd_list   p_sentreq;
     145        struct sr_list   p_sr;
    140146       
    141147        /* connection context: socket and related information */
     
    204210};
    205211
    206 /* Structure to store a sent request */
    207 struct sentreq {
    208         struct fd_list  chain;  /* the "o" field points directly to the hop-by-hop of the request (uint32_t *)  */
    209         struct msg      *req;   /* A request that was sent and not yet answered. */
    210 };
    211 
    212212
    213213/* Functions */
     
    220220/* fd_peer_add declared in freeDiameter.h */
    221221int fd_peer_validate( struct fd_peer * peer );
     222void fd_peer_failover_msg(struct fd_peer * peer);
    222223
    223224/* Peer expiry */
     
    236237int fd_out_start(struct fd_peer * peer);
    237238int fd_out_stop(struct fd_peer * peer);
     239
     240/* Peer sent requests cache */
     241int fd_p_sr_store(struct sr_list * srlist, struct msg **req, uint32_t *hbhloc);
     242int fd_p_sr_fetch(struct sr_list * srlist, uint32_t hbh, struct msg **req);
     243void fd_p_sr_failover(struct sr_list * srlist);
    238244
    239245/* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */
  • freeDiameter/messages.c

    r10 r34  
    265265}
    266266
     267/* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */
     268int fd_msg_parse_or_error( struct msg ** msg )
     269{
     270        int ret = 0;
     271        struct msg * m;
     272        struct msg_hdr * hdr = NULL;
     273        struct fd_pei   pei;
     274       
     275        TRACE_ENTRY("%p", msg);
     276       
     277        CHECK_PARAMS(msg && *msg);
     278        m = *msg;
     279       
     280        /* Parse the message against our dictionary */
     281        ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei);
     282        if (ret != EBADMSG)
     283                return ret;
     284       
     285        fd_log_debug("The following message does not comply to the dictionary and rules (%s):\n", pei.pei_errcode);
     286        fd_msg_dump_walk(NONE, m);
     287       
     288        /* Now create an answer error if the message is a query */
     289        CHECK_FCT( fd_msg_hdr(m, &hdr) );
     290       
     291        if (hdr->msg_flags & CMD_FLAG_REQUEST) {
     292               
     293                /* Create the error message */
     294                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) );
     295               
     296                /* Set the error code */
     297                CHECK_FCT( fd_msg_rescode_set(*msg, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) );
     298               
     299        } else {
     300                /* Just discard */
     301                CHECK_FCT( fd_msg_free( m ) );
     302                *msg = NULL;
     303        }
     304       
     305        return ret;
     306}
  • freeDiameter/p_out.c

    r33 r34  
    3737
    3838/* Alloc a new hbh for requests, bufferize the message and send on the connection, save in sentreq if provided */
    39 static int do_send(struct msg ** msg, struct cnxctx * cnx, uint32_t * hbh, struct fd_list * sentreq)
     39static int do_send(struct msg ** msg, struct cnxctx * cnx, uint32_t * hbh, struct sr_list * srl)
    4040{
    41         TRACE_ENTRY("%p %p %p %p", msg, cnx, hbh, sentreq);
     41        struct msg_hdr * hdr;
     42        int msg_is_a_req;
     43        uint8_t * buf;
     44        size_t sz;
     45        int ret;
    4246       
    43         TODO("If message is a request");
    44                 TODO("Alloc new *hbh");
     47        TRACE_ENTRY("%p %p %p %p", msg, cnx, hbh, srl);
    4548       
    46         TODO("Bufferize the message, send it");
     49        /* Retrieve the message header */
     50        CHECK_FCT( fd_msg_hdr(*msg, &hdr) );
    4751       
    48         TODO("Save in sentreq or free")
     52        msg_is_a_req = (hdr->msg_flags & CMD_FLAG_REQUEST);
     53        if (msg_is_a_req) {
     54                CHECK_PARAMS(hbh && srl);
     55                /* Alloc the hop-by-hop id and increment the value for next message */
     56                hdr->msg_hbhid = *hbh;
     57                *hbh = hdr->msg_hbhid + 1;
     58        }
    4959       
    50         return ENOTSUP;
     60        /* Create the message buffer */
     61        CHECK_FCT(fd_msg_bufferize( *msg, &buf, &sz ));
     62       
     63        /* Send the message */
     64        pthread_cleanup_push( free, buf );
     65        CHECK_FCT_DO( ret = fd_cnx_send(cnx, buf, sz), { free(buf); return ret; } );
     66        pthread_cleanup_pop(1);
     67       
     68        /* Save a request */
     69        if (msg_is_a_req) {
     70                CHECK_FCT_DO( fd_p_sr_store(srl, msg, &hdr->msg_hbhid),
     71                        {
     72                                fd_log_debug("The following request was sent successfully but not saved locally:\n" );
     73                                fd_log_debug("  (as a result the matching answer will be discarded)\n" );
     74                                fd_msg_dump_walk(NONE, *msg);
     75                        } );
     76                               
     77        }
     78       
     79        /* Free answers and unsaved requests */
     80        if (*msg) {
     81                CHECK_FCT( fd_msg_free(*msg) );
     82                *msg = NULL;
     83        }
     84       
     85        return 0;
     86}
     87
     88static void cleanup_requeue(void * arg)
     89{
     90        struct msg *msg = arg;
     91        CHECK_FCT_DO(fd_fifo_post(fd_g_outgoing, &msg),
     92                        CHECK_FCT_DO(fd_msg_free(msg), /* What can we do more? */));
    5193}
    5294
     
    5496static void * out_thr(void * arg)
    5597{
    56         TODO("Pick next message in peer->p_tosend");
    57         TODO("do_send, log errors");
    58         TODO("In case of cancellation, requeue the message");
    59         return NULL;
     98        struct fd_peer * peer = arg;
     99        ASSERT( CHECK_PEER(peer) );
     100       
     101        /* Set the thread name */
     102        {
     103                char buf[48];
     104                sprintf(buf, "OUT/%.*s", sizeof(buf) - 5, peer->p_hdr.info.pi_diamid);
     105                fd_log_threadname ( buf );
     106        }
     107       
     108        /* Loop until cancelation */
     109        while (1) {
     110                struct msg * msg;
     111               
     112                /* Retrieve next message to send */
     113                CHECK_FCT_DO( fd_fifo_get(peer->p_tosend, &msg), goto error );
     114               
     115                /* Now if we are cancelled, we requeue this message */
     116                pthread_cleanup_push(cleanup_requeue, msg);
     117               
     118                /* Send the message, log any error */
     119                CHECK_FCT_DO( do_send(&msg, peer->p_cnxctx, &peer->p_hbh, &peer->p_sr),
     120                        {
     121                                fd_log_debug("An error occurred while sending this message, it is lost:\n");
     122                                fd_msg_dump_walk(NONE, msg);
     123                                fd_msg_free(msg);
     124                        } );
     125                       
     126                /* Loop */
     127                pthread_cleanup_pop(0);
     128        }
     129       
    60130error:
    61         TODO(" Send an event to the peer ");
     131        /* It is not really a connection error, but the effect is the same, we are not able to send anymore message */
     132        CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), /* What do we do if it fails? */ );
    62133        return NULL;
    63134}
     
    84155
    85156                /* Do send the message */
    86                 CHECK_FCT( do_send(msg, cnx, hbh, peer ? &peer->p_sentreq : NULL) );
     157                CHECK_FCT( do_send(msg, cnx, hbh, peer ? &peer->p_sr : NULL) );
    87158        }
    88159       
  • freeDiameter/p_psm.c

    r33 r34  
    8484/************************************************************************/
    8585
    86 
    8786/* Enter/leave OPEN state */
    8887static int enter_open_state(struct fd_peer * peer)
    8988{
     89        struct fd_list * li;
     90        CHECK_PARAMS( FD_IS_LIST_EMPTY(&peer->p_actives) );
     91       
     92        /* Callback registered by the credential validator (fd_peer_validate_register) */
     93        if (peer->p_cb2) {
     94                CHECK_FCT_DO( (*peer->p_cb2)(&peer->p_hdr.info),
     95                        {
     96                                TRACE_DEBUG(FULL, "Validation failed, moving to state CLOSING");
     97                                peer->p_hdr.info.pi_state = STATE_CLOSING;
     98                                fd_psm_terminate(peer);
     99                        } );
     100                peer->p_cb2 = NULL;
     101                return 0;
     102        }
     103        /* Insert in the active peers list */
    90104        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) );
    91         TODO(" insert in fd_g_activ_peers ");
    92        
     105        for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) {
     106                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);
     108                if (cmp < 0)
     109                        break;
     110        }
     111        fd_list_insert_before(li, &peer->p_actives);
    93112        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
     113       
     114        /* Callback registered when the peer was added, by fd_peer_add */
     115        if (peer->p_cb) {
     116                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);
     118                peer->p_cb = NULL;
     119                peer->p_cb_data = NULL;
     120        }
    94121       
    95122        /* Start the thread to handle outgoing messages */
    96123        CHECK_FCT( fd_out_start(peer) );
    97124       
    98         return ENOTSUP;
     125        return 0;
    99126}
    100127static int leave_open_state(struct fd_peer * peer)
    101128{
    102         TODO("Remove from active list");
     129        /* Remove from active peers list */
     130        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) );
     131        fd_list_unlink( &peer->p_actives );
     132        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
    103133       
    104134        /* Stop the "out" thread */
    105135        CHECK_FCT( fd_out_stop(peer) );
    106136       
    107         TODO("Failover pending messages: requeue in global structures");
    108        
    109         return ENOTSUP;
    110 }
     137        /* Failover the messages */
     138        fd_peer_failover_msg(peer);
     139       
     140        return 0;
     141}
     142
    111143
    112144/************************************************************************/
     
    165197        peer->p_psm_timer.tv_sec += delay;
    166198       
    167 #if 0
     199#ifdef SLOW_PSM
    168200        /* temporary for debug */
    169201        peer->p_psm_timer.tv_sec += 10;
     
    188220{
    189221        struct fd_peer * peer = (struct fd_peer *)arg;
    190         int created_started = started;
     222        int created_started = started ? 1 : 0;
    191223        int event;
    192224        size_t ev_sz;
     
    214246                psm_next_timeout(peer, 0, INCNX_TIMEOUT);
    215247        } else {
    216                 psm_next_timeout(peer, created_started ? 0 : 1, 0);
     248                psm_next_timeout(peer, created_started, 0);
    217249        }
    218250       
     
    236268                TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event);
    237269                goto psm_loop;
    238         }
    239 
    240         /* Call the extension callback if needed */
    241         if (peer->p_cb) {
    242                 /* Check if we must call it */
    243                         /*  */
    244                 /* OK */
    245                 TODO("Call CB");
    246                 TODO("Clear CB");
    247270        }
    248271
     
    277300        /* A message was received */
    278301        if (event == FDEVP_CNX_MSG_RECV) {
    279                 TODO("Parse the buffer into a message");
    280                 /* parse_and_get_local_ccode */
     302                struct msg * msg = NULL;
     303                struct msg_hdr * hdr;
     304               
     305                /* Parse the received buffer */
     306                CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg),
     307                        {
     308                                fd_log_debug("Received invalid data from peer '%s', closing the connection\n", peer->p_hdr.info.pi_diamid);
     309                                CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_end );
     310                                goto psm_loop;
     311                        } );
     312               
     313                TRACE_DEBUG(FULL, "Received this message from '%s':", peer->p_hdr.info.pi_diamid);
     314                fd_msg_dump_walk(FULL, msg);
     315       
     316                /* Extract the header */
     317                CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end );
     318               
     319                /* If it is an answer, associate with the request */
     320                if (!(hdr->msg_flags & CMD_FLAG_REQUEST)) {
     321                        struct msg * req;
     322                        /* Search matching request (same hbhid) */
     323                        CHECK_FCT_DO( fd_p_sr_fetch(&peer->p_sr, hdr->msg_hbhid, &req), goto psm_end );
     324                        if (req == NULL) {
     325                                fd_log_debug("Received a Diameter answer message with no corresponding sent request, discarding...\n");
     326                                fd_msg_dump_walk(NONE, msg);
     327                                fd_msg_free(msg);
     328                                goto psm_loop;
     329                        }
     330                       
     331                        /* Associate */
     332                        CHECK_FCT_DO( fd_msg_answ_associate( msg, req ), goto psm_end );
     333                }
     334               
     335                /* We received a valid message, update the expiry timer */
     336                CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end );
     337
     338                /* Now handle non-link-local messages */
     339                if (fd_msg_is_routable(msg)) {
     340                        /* If we are not in OPEN state, discard the message */
     341                        if (peer->p_hdr.info.pi_state != STATE_OPEN) {
     342                                fd_log_debug("Received a routable message while not in OPEN state from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid);
     343                                fd_msg_dump_walk(NONE, msg);
     344                                fd_msg_free(msg);
     345                        } else {
     346                                /* Set the message source and add the Route-Record */
     347                                CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), goto psm_end);
     348
     349                                /* Requeue to the global incoming queue */
     350                                CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end );
     351                               
     352                                /* Update the peer timer */
     353                                if (!peer->p_flags.pf_dw_pending) {
     354                                        psm_next_timeout(peer, 1, peer->p_hdr.info.pi_twtimer ?: fd_g_config->cnf_timer_tw);
     355                                }
     356                        }
     357                        goto psm_loop;
     358                }
     359               
     360                /* Link-local message: They must be understood by our dictionary */
     361               
    281362                TODO("Check if it is a local message (CER, DWR, ...)");
    282363                TODO("If not, check we are in OPEN state");
     
    319400                        case STATE_CLOSED:
    320401                                TODO("Handle the CER, validate the peer if needed (and set expiry), set the alt_fifo in the connection, reply a CEA, eventually handshake, move to OPEN or REOPEN state");
     402                                /* In case of error : DIAMETER_UNKNOWN_PEER */
    321403                                break;
    322404                               
     
    353435       
    354436        goto psm_loop;
    355        
     437
    356438psm_end:
    357439        pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
     
    398480{
    399481        TRACE_ENTRY("%p", peer);
    400         TODO("Cancel PSM thread");
    401         TODO("Cancel OUT thread");
    402         TODO("Cleanup the peer connection object");
    403         TODO("Cleanup the message queues (requeue)");
    404         TODO("Call p_cb with NULL parameter if needed");
    405        
     482       
     483        /* Cancel PSM thread */
     484        CHECK_FCT_DO( fd_thr_term(&peer->p_psm), /* continue */ );
     485       
     486        /* Cancel the OUT thread */
     487        CHECK_FCT_DO( fd_out_stop(peer), /* continue */ );
     488       
     489        /* Cleanup the connection */
     490        if (peer->p_cnxctx) {
     491                fd_cnx_destroy(peer->p_cnxctx);
     492        }
     493       
     494        /* Failover the messages */
     495        fd_peer_failover_msg(peer);
     496       
     497        /* Empty the events list, this might leak some memory, but we only do it on exit, so... */
     498        fd_event_destroy(&peer->p_events, free);
     499       
     500        /* More cleanups are performed in fd_peer_free */
    406501        return;
    407502}
  • freeDiameter/peers.c

    r33 r34  
    7878        CHECK_FCT( fd_fifo_new(&p->p_events) );
    7979        CHECK_FCT( fd_fifo_new(&p->p_tosend) );
    80         fd_list_init(&p->p_sentreq, p);
     80        fd_list_init(&p->p_sr.srs, p);
     81        CHECK_POSIX( pthread_mutex_init(&p->p_sr.mtx, NULL) );
    8182       
    8283        return 0;
     
    180181        }
    181182
     183/* Empty the lists of p_tosend and p_sentreq messages */
     184void fd_peer_failover_msg(struct fd_peer * peer)
     185{
     186        struct msg *m;
     187        TRACE_ENTRY("%p", peer);
     188        CHECK_PARAMS_DO(CHECK_PEER(peer), return);
     189       
     190        /* Requeue all messages in the "out" queue */
     191        while ( fd_fifo_tryget(peer->p_tosend, &m) == 0 ) {
     192                CHECK_FCT_DO(fd_fifo_post(fd_g_outgoing, &m),
     193                                /* fallback: destroy the message */
     194                                CHECK_FCT_DO(fd_msg_free(m), /* What can we do more? */));
     195        }
     196       
     197        /* Requeue all routable sent requests */
     198        fd_p_sr_failover(&peer->p_sr);
     199       
     200        /* Done */
     201        return;
     202}
     203
    182204/* Destroy a structure once all cleanups have been performed */
    183205int fd_peer_free(struct fd_peer ** ptr)
     
    197219        free_null(p->p_hdr.info.pi_realm);
    198220        free_list( &p->p_hdr.info.pi_endpoints );
    199         /* Assume the security data is already freed */
     221        TODO("Free the security data if any ?");
    200222        free_null(p->p_hdr.info.pi_prodname);
    201223        free_list( &p->p_hdr.info.pi_apps );
     
    214236       
    215237        CHECK_FCT( fd_thr_term(&p->p_outthr) );
    216         while ( fd_fifo_tryget(p->p_tosend, &t) == 0 ) {
    217                 struct msg * m = t;
    218                 TRACE_DEBUG(FULL, "Found message %p in outgoing queue of peer %p being destroyed, requeue", m, p);
    219                 /* We simply requeue in global, the routing thread will re-handle it. */
    220                 CHECK_FCT(fd_fifo_post(fd_g_outgoing, &m));
    221         }
    222         CHECK_FCT( fd_fifo_del(&p->p_tosend) );
    223        
    224         while (!FD_IS_LIST_EMPTY(&p->p_sentreq)) {
    225                 struct sentreq * sr = (struct sentreq *)(p->p_sentreq.next);
    226                 fd_list_unlink(&sr->chain);
    227                 TRACE_DEBUG(FULL, "Found message %p in list of sent requests to peer %p being destroyed, requeue (fallback)", sr->req, p);
    228                 CHECK_FCT(fd_fifo_post(fd_g_outgoing, &sr->req));
    229                 free(sr);
    230         }
    231238       
    232239        if (p->p_cnxctx) {
     
    234241        }
    235242       
     243        /* Requeue any remaining message into global structures if possible */
     244        fd_peer_failover_msg(p);
     245        CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ );
     246        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */);
     247       
     248        /* If the callback is still around... */
    236249        if (p->p_cb)
    237250                (*p->p_cb)(NULL, p->p_cb_data);
    238251       
     252        /* Free the structure */
    239253        free(p);
    240        
    241254        return 0;
    242255}
  • include/freeDiameter/freeDiameter.h

    r33 r34  
    492492int fd_msg_add_origin ( struct msg * msg, int osi );
    493493
     494/* 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) */
     495int fd_msg_parse_or_error( struct msg ** msg );
    494496
    495497
  • include/freeDiameter/libfreeDiameter.h

    r33 r34  
    19901990 *  !0          : an error occurred.
    19911991 */
    1992 int fd_msg_source_set( struct msg * msg, char * diamid, uint32_t hash, int add_rr, struct dictionary * dict );
    1993 int fd_msg_source_get( struct msg * msg, char ** diamid, uint32_t *hash );
     1992int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict );
     1993int fd_msg_source_get( struct msg * msg, char ** diamid );
    19941994
    19951995/*
     
    21382138int fd_msg_parse_dict ( msg_or_avp * object, struct dictionary * dict );
    21392139
     2140/* Parsing Error Information structure */
     2141struct fd_pei {
     2142        char *          pei_errcode;    /* name of the error code to use */
     2143        struct avp *    pei_avp;        /* pointer to invalid or missing AVP (to be freed) */
     2144        char *          pei_message;    /* Overwrite default message if needed */
     2145        int             pei_protoerr;   /* do we set the 'E' bit in the error message ? */
     2146};
     2147
    21402148/*
    21412149 * FUNCTION:    fd_msg_parse_rules
     
    21442152 *  object      : A msg or grouped avp object that must be verified.
    21452153 *  dict        : The dictionary containing the rules definitions.
    2146  *  rule        : If not NULL, the first conflicting rule will be saved here if a conflict is found.
     2154 *  error_info  : If not NULL, the first problem information will be saved here.
    21472155 *
    21482156 * DESCRIPTION:
     
    21552163 *  ENOMEM      : Unable to allocate enough memory to complete the operation.
    21562164 */
    2157 int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct dict_object ** rule);
     2165int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct fd_pei *error_info);
     2166
    21582167
    21592168
  • libfreeDiameter/messages.c

    r7 r34  
    124124                }                msg_cb;                /* Callback to be called when an answer is received, if not NULL */
    125125        char *                   msg_src_id;            /* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */
    126         uint32_t                 msg_src_hash;          /* Hash of the msg_src_id value */
    127126};
    128127
     
    668667                msg->msg_public.msg_eteid
    669668                );
    670         fd_log_debug(INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p h:%x src:%s\n",
    671                         INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.fct, msg->msg_cb.data, msg->msg_query, msg->msg_src_hash, msg->msg_src_id?:"(nil)");
     669        fd_log_debug(INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p src:%s\n",
     670                        INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.fct, msg->msg_cb.data, msg->msg_query, msg->msg_src_id?:"(nil)");
    672671}
    673672
     
    10771076
    10781077/* Associate source peer */
    1079 int fd_msg_source_set( struct msg * msg, char * diamid, uint32_t hash, int add_rr, struct dictionary * dict )
    1080 {
    1081         TRACE_ENTRY( "%p %p %x %d %p", msg, diamid, hash, add_rr, dict);
     1078int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict )
     1079{
     1080        TRACE_ENTRY( "%p %p %d %p", msg, diamid, add_rr, dict);
    10821081       
    10831082        /* Check we received a valid message */
     
    10891088        /* If the request is to cleanup the source, we are done */
    10901089        if (diamid == NULL) {
    1091                 msg->msg_src_hash = 0;
    10921090                return 0;
    10931091        }
     
    10951093        /* Otherwise save the new informations */
    10961094        CHECK_MALLOC( msg->msg_src_id = strdup(diamid) );
    1097         msg->msg_src_hash = hash;
    10981095       
    10991096        if (add_rr) {
     
    11231120}
    11241121
    1125 int fd_msg_source_get( struct msg * msg, char ** diamid, uint32_t *hash )
    1126 {
    1127         TRACE_ENTRY( "%p %p %p", msg, diamid, hash);
     1122int fd_msg_source_get( struct msg * msg, char ** diamid )
     1123{
     1124        TRACE_ENTRY( "%p %p", msg, diamid);
    11281125       
    11291126        /* Check we received valid parameters */
     
    11331130        /* Copy the informations */
    11341131        *diamid = msg->msg_src_id;
    1135         if (hash)
    1136                 *hash = msg->msg_src_hash;
    11371132       
    11381133        /* done */
     
    18631858/* We use this structure as parameter for the next function */
    18641859struct parserules_data {
    1865         struct fd_list     * sentinel;  /* Sentinel of the list of children AVP */
    1866         struct dict_object * ruleavp;   /* If the rule conflicts, save the rule_avp here (we don't have direct access to the rule but it can be searched) */
     1860        struct fd_list  * sentinel;     /* Sentinel of the list of children AVP */
     1861        struct fd_pei   * pei;          /* If the rule conflicts, save the error here */
    18671862};
     1863
     1864/* Create an empty AVP of a given model (to use in Failed-AVP) */
     1865static struct avp * empty_avp(struct dict_object * model_avp)
     1866{
     1867        TODO("Create the AVP instance and set a 0 value");
     1868        return NULL;
     1869}
    18681870
    18691871/* Check that a list of AVPs is compliant with a given rule -- will be iterated on the list of rules */
    18701872static int parserules_check_one_rule(void * data, struct dict_rule_data *rule)
    18711873{
    1872         int ret = 0, count, first, last, min;
    1873         struct parserules_data * pr_data = (struct parserules_data *) data;
     1874        int count, first, last, min;
     1875        struct parserules_data * pr_data = data;
    18741876       
    18751877        TRACE_ENTRY("%p %p", data, rule);
    18761878       
    1877         /* Get statistics of the AVP concerned by this rule in the message instance */
     1879        /* Get statistics of the AVP concerned by this rule in the parent instance */
    18781880        parserules_stat_avps( rule->rule_avp, pr_data->sentinel, &count, &first, &last);
    18791881       
     
    18811883        {
    18821884                struct dict_avp_data avpdata;
     1885                int ret;
    18831886                ret = fd_dict_getval(rule->rule_avp, &avpdata);
    18841887               
     
    18961899       
    18971900        /* Now check the rule is not conflicting */
    1898         ret = 0;
    18991901       
    19001902        /* Check the "min" value */
     
    19071909        if (count < min) {
    19081910                TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is < the rule min (%d).", count, min);
    1909                 ret = EBADMSG;
    1910                 goto end;
     1911                if (pr_data->pei) {
     1912                        pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
     1913                        pr_data->pei->pei_avp = empty_avp(rule->rule_avp);
     1914                }
     1915                return EBADMSG;
    19111916        }
    19121917       
     
    19141919        if ((rule->rule_max != -1) && (count > rule->rule_max)) {
    19151920                TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is > the rule max (%d).", count, rule->rule_max);
    1916                 ret = EBADMSG;
    1917                 goto end;
     1921                if (pr_data->pei) {
     1922                        if (rule->rule_max == 0)
     1923                                pr_data->pei->pei_errcode = "DIAMETER_AVP_NOT_ALLOWED";
     1924                        else
     1925                                pr_data->pei->pei_errcode = "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
     1926                        pr_data->pei->pei_avp = empty_avp(rule->rule_avp); /* Well we are supposed to return the (max + 1)th instance of the AVP instead... Pfff... */ TODO("Improve...");
     1927                }
     1928                return EBADMSG;
    19181929        }
    19191930               
     
    19291940                        if (first > rule->rule_order) {
    19301941                                TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_HEAD AVP appears first in (%d) position, the rule requires (%d).", first, rule->rule_order);
    1931                                 ret = EBADMSG;
    1932                                 goto end;
     1942                                if (pr_data->pei) {
     1943                                        pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
     1944                                        pr_data->pei->pei_message = "AVP was not in its fixed position";
     1945                                        pr_data->pei->pei_avp = empty_avp(rule->rule_avp);
     1946                                }
     1947                                return EBADMSG;
    19331948                        }
    19341949                        break;
     
    19381953                        if (last > rule->rule_order) {  /* We have a ">" here because we count in reverse order (i.e. from the end) */
    19391954                                TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_TAIL AVP appears last in (%d) position, the rule requires (%d).", last, rule->rule_order);
    1940                                 ret = EBADMSG;
    1941                                 goto end;
     1955                                if (pr_data->pei) {
     1956                                        pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
     1957                                        pr_data->pei->pei_message = "AVP was not in its fixed position";
     1958                                        pr_data->pei->pei_avp = empty_avp(rule->rule_avp);
     1959                                }
     1960                                return EBADMSG;
    19421961                        }
    19431962                        break;
     
    19461965                        /* What is this position ??? */
    19471966                        ASSERT(0);
    1948                         ret = ENOTSUP;
     1967                        return ENOTSUP;
    19491968        }
    19501969       
    19511970        /* We've checked all the parameters */
    1952 end:
    1953         if (ret == EBADMSG) {
    1954                 pr_data->ruleavp = rule->rule_avp;
    1955         }
    1956 
    1957         return ret;
     1971        return 0;
    19581972}
    19591973
    19601974/* Check the rules recursively */
    1961 static int parserules_do ( struct dictionary * dict, msg_or_avp * object, struct dict_object ** conflict_rule, int mandatory)
    1962 {
    1963         int ret = 0;
     1975static int parserules_do ( struct dictionary * dict, msg_or_avp * object, struct fd_pei *error_info, int mandatory)
     1976{
    19641977        struct parserules_data data;
    19651978        struct dict_object * model = NULL;
    19661979       
    1967         TRACE_ENTRY("%p %p %p %d", dict, object, conflict_rule, mandatory);
     1980        TRACE_ENTRY("%p %p %p %d", dict, object, error_info, mandatory);
    19681981       
    19691982        /* object has already been checked and dict-parsed when we are called. */
     
    19811994                        if (model == NULL) {
    19821995                                TRACE_DEBUG(INFO, "Message with no dictionary model. EBADMSG");
     1996                                if (error_info) {
     1997                                        error_info->pei_errcode = "DIAMETER_COMMAND_UNSUPPORTED";
     1998                                        error_info->pei_protoerr = 1;
     1999                                }
    19832000                                return EBADMSG;
    19842001                        }
     
    19902007                                /* Return an error in this case */
    19912008                                TRACE_DEBUG(INFO, "Mandatory AVP with no dictionary model. EBADMSG");
     2009                                if (error_info) {
     2010                                        error_info->pei_errcode = "DIAMETER_AVP_UNSUPPORTED";
     2011                                        error_info->pei_avp = object;
     2012                                }
    19922013                                return EBADMSG;
    19932014                        } else {
     
    20192040                        is_child_mand = 1;
    20202041                for (ch = _C(object)->children.next; ch != &_C(object)->children; ch = ch->next) {
    2021                         CHECK_FCT(  parserules_do ( dict, _C(ch->o), conflict_rule, is_child_mand )  );
     2042                        CHECK_FCT(  parserules_do ( dict, _C(ch->o), error_info, is_child_mand )  );
    20222043                }
    20232044        }
     
    20252046        /* Now check all rules of this object */
    20262047        data.sentinel = &_C(object)->children;
    2027         data.ruleavp  = NULL;
    2028         ret = fd_dict_iterate_rules ( model, &data, parserules_check_one_rule );
    2029        
    2030         /* Save the reference to the eventual conflicting rule; otherwise set to NULL */
    2031         if (conflict_rule && data.ruleavp) {
    2032                 /* data.ruleavp contains the AVP, and model is the parent */
    2033                 struct dict_object * rule = NULL;
    2034                 struct dict_rule_request req = { model, data.ruleavp };
    2035                
    2036                 CHECK_FCT_DO( fd_dict_search ( dict, DICT_RULE, RULE_BY_AVP_AND_PARENT, &req, &rule, ENOENT),  rule = NULL );
    2037                
    2038                 *conflict_rule = rule;
    2039         }
    2040        
    2041         return ret;
    2042 }
    2043 
    2044 int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct dict_object ** rule)
    2045 {
    2046         TRACE_ENTRY("%p %p", object, rule);
     2048        data.pei  = error_info;
     2049        CHECK_FCT( fd_dict_iterate_rules ( model, &data, parserules_check_one_rule ) );
     2050       
     2051        return 0;
     2052}
     2053
     2054int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct fd_pei *error_info)
     2055{
     2056        TRACE_ENTRY("%p %p %p", object, dict, error_info);
    20472057       
    20482058        /* Resolve the dictionary objects when missing. This also validates the object. */
    20492059        CHECK_FCT(  fd_msg_parse_dict ( object, dict )  );
    20502060       
     2061        if (error_info)
     2062                memset(error_info, 0, sizeof(struct fd_pei));
     2063       
    20512064        /* Call the recursive function */
    2052         return parserules_do ( dict, object, rule, 1 ) ;
     2065        return parserules_do ( dict, object, error_info, 1 ) ;
    20532066}
    20542067
Note: See TracChangeset for help on using the changeset viewer.