Changeset 34:0e2b57789361 in freeDiameter
- Timestamp:
- Oct 30, 2009, 5:23:06 PM (15 years ago)
- Branch:
- default
- Phase:
- public
- Files:
-
- 1 added
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
freeDiameter/CMakeLists.txt
r33 r34 23 23 p_out.c 24 24 p_psm.c 25 p_sr.c 25 26 server.c 26 27 tcp.c -
freeDiameter/fD.h
r33 r34 93 93 int fd_dict_base_protocol(struct dictionary * dict); 94 94 95 /* Sentinel for the sent requests list */ 96 struct sr_list { 97 struct fd_list srs; 98 pthread_mutex_t mtx; 99 }; 100 95 101 /* Peers */ 96 102 struct fd_peer { /* The "real" definition of the peer structure */ … … 137 143 138 144 /* Sent requests (for fallback), list of struct sentreq ordered by hbh */ 139 struct fd_list p_sentreq;145 struct sr_list p_sr; 140 146 141 147 /* connection context: socket and related information */ … … 204 210 }; 205 211 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 212 212 213 213 /* Functions */ … … 220 220 /* fd_peer_add declared in freeDiameter.h */ 221 221 int fd_peer_validate( struct fd_peer * peer ); 222 void fd_peer_failover_msg(struct fd_peer * peer); 222 223 223 224 /* Peer expiry */ … … 236 237 int fd_out_start(struct fd_peer * peer); 237 238 int fd_out_stop(struct fd_peer * peer); 239 240 /* Peer sent requests cache */ 241 int fd_p_sr_store(struct sr_list * srlist, struct msg **req, uint32_t *hbhloc); 242 int fd_p_sr_fetch(struct sr_list * srlist, uint32_t hbh, struct msg **req); 243 void fd_p_sr_failover(struct sr_list * srlist); 238 244 239 245 /* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */ -
freeDiameter/messages.c
r10 r34 265 265 } 266 266 267 /* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */ 268 int 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 37 37 38 38 /* 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)39 static int do_send(struct msg ** msg, struct cnxctx * cnx, uint32_t * hbh, struct sr_list * srl) 40 40 { 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; 42 46 43 TODO("If message is a request"); 44 TODO("Alloc new *hbh"); 47 TRACE_ENTRY("%p %p %p %p", msg, cnx, hbh, srl); 45 48 46 TODO("Bufferize the message, send it"); 49 /* Retrieve the message header */ 50 CHECK_FCT( fd_msg_hdr(*msg, &hdr) ); 47 51 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 } 49 59 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 88 static 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? */)); 51 93 } 52 94 … … 54 96 static void * out_thr(void * arg) 55 97 { 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 60 130 error: 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? */ ); 62 133 return NULL; 63 134 } … … 84 155 85 156 /* Do send the message */ 86 CHECK_FCT( do_send(msg, cnx, hbh, peer ? &peer->p_s entreq: NULL) );157 CHECK_FCT( do_send(msg, cnx, hbh, peer ? &peer->p_sr : NULL) ); 87 158 } 88 159 -
freeDiameter/p_psm.c
r33 r34 84 84 /************************************************************************/ 85 85 86 87 86 /* Enter/leave OPEN state */ 88 87 static int enter_open_state(struct fd_peer * peer) 89 88 { 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 */ 90 104 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); 93 112 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 } 94 121 95 122 /* Start the thread to handle outgoing messages */ 96 123 CHECK_FCT( fd_out_start(peer) ); 97 124 98 return ENOTSUP;125 return 0; 99 126 } 100 127 static int leave_open_state(struct fd_peer * peer) 101 128 { 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) ); 103 133 104 134 /* Stop the "out" thread */ 105 135 CHECK_FCT( fd_out_stop(peer) ); 106 136 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 111 143 112 144 /************************************************************************/ … … 165 197 peer->p_psm_timer.tv_sec += delay; 166 198 167 #if 0199 #ifdef SLOW_PSM 168 200 /* temporary for debug */ 169 201 peer->p_psm_timer.tv_sec += 10; … … 188 220 { 189 221 struct fd_peer * peer = (struct fd_peer *)arg; 190 int created_started = started ;222 int created_started = started ? 1 : 0; 191 223 int event; 192 224 size_t ev_sz; … … 214 246 psm_next_timeout(peer, 0, INCNX_TIMEOUT); 215 247 } else { 216 psm_next_timeout(peer, created_started ? 0 : 1, 0);248 psm_next_timeout(peer, created_started, 0); 217 249 } 218 250 … … 236 268 TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event); 237 269 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");247 270 } 248 271 … … 277 300 /* A message was received */ 278 301 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 281 362 TODO("Check if it is a local message (CER, DWR, ...)"); 282 363 TODO("If not, check we are in OPEN state"); … … 319 400 case STATE_CLOSED: 320 401 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 */ 321 403 break; 322 404 … … 353 435 354 436 goto psm_loop; 355 437 356 438 psm_end: 357 439 pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ … … 398 480 { 399 481 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 */ 406 501 return; 407 502 } -
freeDiameter/peers.c
r33 r34 78 78 CHECK_FCT( fd_fifo_new(&p->p_events) ); 79 79 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) ); 81 82 82 83 return 0; … … 180 181 } 181 182 183 /* Empty the lists of p_tosend and p_sentreq messages */ 184 void 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 182 204 /* Destroy a structure once all cleanups have been performed */ 183 205 int fd_peer_free(struct fd_peer ** ptr) … … 197 219 free_null(p->p_hdr.info.pi_realm); 198 220 free_list( &p->p_hdr.info.pi_endpoints ); 199 /* Assume the security data is already freed */221 TODO("Free the security data if any ?"); 200 222 free_null(p->p_hdr.info.pi_prodname); 201 223 free_list( &p->p_hdr.info.pi_apps ); … … 214 236 215 237 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 }231 238 232 239 if (p->p_cnxctx) { … … 234 241 } 235 242 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... */ 236 249 if (p->p_cb) 237 250 (*p->p_cb)(NULL, p->p_cb_data); 238 251 252 /* Free the structure */ 239 253 free(p); 240 241 254 return 0; 242 255 } -
include/freeDiameter/freeDiameter.h
r33 r34 492 492 int fd_msg_add_origin ( struct msg * msg, int osi ); 493 493 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) */ 495 int fd_msg_parse_or_error( struct msg ** msg ); 494 496 495 497 -
include/freeDiameter/libfreeDiameter.h
r33 r34 1990 1990 * !0 : an error occurred. 1991 1991 */ 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);1992 int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict ); 1993 int fd_msg_source_get( struct msg * msg, char ** diamid ); 1994 1994 1995 1995 /* … … 2138 2138 int fd_msg_parse_dict ( msg_or_avp * object, struct dictionary * dict ); 2139 2139 2140 /* Parsing Error Information structure */ 2141 struct 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 2140 2148 /* 2141 2149 * FUNCTION: fd_msg_parse_rules … … 2144 2152 * object : A msg or grouped avp object that must be verified. 2145 2153 * 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. 2147 2155 * 2148 2156 * DESCRIPTION: … … 2155 2163 * ENOMEM : Unable to allocate enough memory to complete the operation. 2156 2164 */ 2157 int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct dict_object ** rule); 2165 int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct fd_pei *error_info); 2166 2158 2167 2159 2168 -
libfreeDiameter/messages.c
r7 r34 124 124 } msg_cb; /* Callback to be called when an answer is received, if not NULL */ 125 125 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 */127 126 }; 128 127 … … 668 667 msg->msg_public.msg_eteid 669 668 ); 670 fd_log_debug(INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p h:%xsrc:%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)"); 672 671 } 673 672 … … 1077 1076 1078 1077 /* 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);1078 int 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); 1082 1081 1083 1082 /* Check we received a valid message */ … … 1089 1088 /* If the request is to cleanup the source, we are done */ 1090 1089 if (diamid == NULL) { 1091 msg->msg_src_hash = 0;1092 1090 return 0; 1093 1091 } … … 1095 1093 /* Otherwise save the new informations */ 1096 1094 CHECK_MALLOC( msg->msg_src_id = strdup(diamid) ); 1097 msg->msg_src_hash = hash;1098 1095 1099 1096 if (add_rr) { … … 1123 1120 } 1124 1121 1125 int fd_msg_source_get( struct msg * msg, char ** diamid , uint32_t *hash)1126 { 1127 TRACE_ENTRY( "%p %p %p", msg, diamid, hash);1122 int fd_msg_source_get( struct msg * msg, char ** diamid ) 1123 { 1124 TRACE_ENTRY( "%p %p", msg, diamid); 1128 1125 1129 1126 /* Check we received valid parameters */ … … 1133 1130 /* Copy the informations */ 1134 1131 *diamid = msg->msg_src_id; 1135 if (hash)1136 *hash = msg->msg_src_hash;1137 1132 1138 1133 /* done */ … … 1863 1858 /* We use this structure as parameter for the next function */ 1864 1859 struct 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 */ 1867 1862 }; 1863 1864 /* Create an empty AVP of a given model (to use in Failed-AVP) */ 1865 static 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 } 1868 1870 1869 1871 /* Check that a list of AVPs is compliant with a given rule -- will be iterated on the list of rules */ 1870 1872 static int parserules_check_one_rule(void * data, struct dict_rule_data *rule) 1871 1873 { 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; 1874 1876 1875 1877 TRACE_ENTRY("%p %p", data, rule); 1876 1878 1877 /* Get statistics of the AVP concerned by this rule in the messageinstance */1879 /* Get statistics of the AVP concerned by this rule in the parent instance */ 1878 1880 parserules_stat_avps( rule->rule_avp, pr_data->sentinel, &count, &first, &last); 1879 1881 … … 1881 1883 { 1882 1884 struct dict_avp_data avpdata; 1885 int ret; 1883 1886 ret = fd_dict_getval(rule->rule_avp, &avpdata); 1884 1887 … … 1896 1899 1897 1900 /* Now check the rule is not conflicting */ 1898 ret = 0;1899 1901 1900 1902 /* Check the "min" value */ … … 1907 1909 if (count < min) { 1908 1910 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; 1911 1916 } 1912 1917 … … 1914 1919 if ((rule->rule_max != -1) && (count > rule->rule_max)) { 1915 1920 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; 1918 1929 } 1919 1930 … … 1929 1940 if (first > rule->rule_order) { 1930 1941 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; 1933 1948 } 1934 1949 break; … … 1938 1953 if (last > rule->rule_order) { /* We have a ">" here because we count in reverse order (i.e. from the end) */ 1939 1954 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; 1942 1961 } 1943 1962 break; … … 1946 1965 /* What is this position ??? */ 1947 1966 ASSERT(0); 1948 ret =ENOTSUP;1967 return ENOTSUP; 1949 1968 } 1950 1969 1951 1970 /* 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; 1958 1972 } 1959 1973 1960 1974 /* 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; 1975 static int parserules_do ( struct dictionary * dict, msg_or_avp * object, struct fd_pei *error_info, int mandatory) 1976 { 1964 1977 struct parserules_data data; 1965 1978 struct dict_object * model = NULL; 1966 1979 1967 TRACE_ENTRY("%p %p %p %d", dict, object, conflict_rule, mandatory);1980 TRACE_ENTRY("%p %p %p %d", dict, object, error_info, mandatory); 1968 1981 1969 1982 /* object has already been checked and dict-parsed when we are called. */ … … 1981 1994 if (model == NULL) { 1982 1995 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 } 1983 2000 return EBADMSG; 1984 2001 } … … 1990 2007 /* Return an error in this case */ 1991 2008 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 } 1992 2013 return EBADMSG; 1993 2014 } else { … … 2019 2040 is_child_mand = 1; 2020 2041 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 ) ); 2022 2043 } 2023 2044 } … … 2025 2046 /* Now check all rules of this object */ 2026 2047 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 2054 int 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); 2047 2057 2048 2058 /* Resolve the dictionary objects when missing. This also validates the object. */ 2049 2059 CHECK_FCT( fd_msg_parse_dict ( object, dict ) ); 2050 2060 2061 if (error_info) 2062 memset(error_info, 0, sizeof(struct fd_pei)); 2063 2051 2064 /* Call the recursive function */ 2052 return parserules_do ( dict, object, rule, 1 ) ;2065 return parserules_do ( dict, object, error_info, 1 ) ; 2053 2066 } 2054 2067
Note: See TracChangeset
for help on using the changeset viewer.