/* This function convert message to message structure */ AAAMessage* AAATranslateMessage( unsigned char* source, unsigned int sourceLen, int attach_buf) { unsigned char *ptr; AAAMessage *msg; unsigned char version; unsigned int msg_len; AAA_AVP *avp; unsigned int avp_code; unsigned char avp_flags; unsigned int avp_len; unsigned int avp_vendorID; unsigned int avp_data_len; /* check the params */ if( !source || !sourceLen || sourceLen<AAA_MSG_HDR_SIZE) { ERROR("ERROR:AAATranslateMessage: invalid buffered received!\n"); goto error; } /* inits */ msg = 0; avp = 0; ptr = source; /* alloc a new message structure */ msg = (AAAMessage*)ad_malloc(sizeof(AAAMessage)); if (!msg) { ERROR("ERROR:AAATranslateMessage: no more free memory!!\n"); goto error; } memset(msg,0,sizeof(AAAMessage)); /* get the version */ version = (unsigned char)*ptr; ptr += VER_SIZE; if (version!=1) { ERROR("ERROR:AAATranslateMessage: invalid version [%d]in " "AAA msg\n",version); goto error; } /* message length */ msg_len = get_3bytes( ptr ); ptr += MESSAGE_LENGTH_SIZE; if (msg_len>sourceLen) { ERROR("ERROR:AAATranslateMessage: AAA message len [%d] bigger then" " buffer len [%d]\n",msg_len,sourceLen); goto error; } /* command flags */ msg->flags = *ptr; ptr += FLAGS_SIZE; /* command code */ msg->commandCode = get_3bytes( ptr ); ptr += COMMAND_CODE_SIZE; /* application-Id */ msg->applicationId = get_4bytes( ptr ); ptr += APPLICATION_ID_SIZE; /* Hop-by-Hop-Id */ msg->hopbyhopId = *((unsigned int*)ptr); ptr += HOP_BY_HOP_IDENTIFIER_SIZE; /* End-to-End-Id */ msg->endtoendId = *((unsigned int*)ptr); ptr += END_TO_END_IDENTIFIER_SIZE; /* start decoding the AVPS */ while (ptr < source+msg_len) { if (ptr+AVP_HDR_SIZE(0x80)>source+msg_len){ ERROR("ERROR:AAATranslateMessage: source buffer to short!! " "Cannot read the whole AVP header!\n"); goto error; } /* avp code */ avp_code = get_4bytes( ptr ); ptr += AVP_CODE_SIZE; /* avp flags */ avp_flags = (unsigned char)*ptr; ptr += AVP_FLAGS_SIZE; /* avp length */ avp_len = get_3bytes( ptr ); ptr += AVP_LENGTH_SIZE; if (avp_len<1) { ERROR("ERROR:AAATranslateMessage: invalid AVP len [%d]\n", avp_len); goto error; } /* avp vendor-ID */ avp_vendorID = 0; if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) { avp_vendorID = get_4bytes( ptr ); ptr += AVP_VENDOR_ID_SIZE; } /* data length */ avp_data_len = avp_len-AVP_HDR_SIZE(avp_flags); /*check the data length */ if ( source+msg_len<ptr+avp_data_len) { ERROR("ERROR:AAATranslateMessage: source buffer to short!! " "Cannot read a whole data for AVP!\n"); goto error; } /* create the AVP */ avp = AAACreateAVP( avp_code, avp_flags, avp_vendorID, (char*)ptr, avp_data_len, AVP_DONT_FREE_DATA); if (!avp) goto error; /* link the avp into aaa message to the end */ AAAAddAVPToMessage( msg, avp, msg->avpList.tail); ptr += to_32x_len( avp_data_len ); } /* link the buffer to the message */ if (attach_buf) { msg->buf.s = (char*)source; msg->buf.len = msg_len; } //AAAPrintMessage( msg ); return msg; error: ERROR("ERROR:AAATranslateMessage: message conversion droped!!\n"); AAAFreeMessage(&msg); return 0; }
/** * Ungroup from a data buffer a list of avps * @param buf - payload to ungroup the list from * @returns the AAA_AVP_LIST or an empty one on error */ AAA_AVP_LIST AAAUngroupAVPS(str buf) { char *ptr; AAA_AVP *avp; unsigned int avp_code; unsigned char avp_flags; unsigned int avp_len; unsigned int avp_vendorID; unsigned int avp_data_len; AAA_AVP_LIST lh; lh.head=0; lh.tail=0; ptr = buf.s; /* start decoding the AVPS */ while (ptr < buf.s+buf.len) { if (ptr+AVP_HDR_SIZE(0x80)>buf.s+buf.len){ LM_ERR("hss3g_ungroup_avps: source buffer to short!! " "Cannot read the whole AVP header!\n"); goto error; } /* avp code */ avp_code = get_4bytes( ptr ); ptr += AVP_CODE_SIZE; /* avp flags */ avp_flags = (unsigned char)*ptr; ptr += AVP_FLAGS_SIZE; /* avp length */ avp_len = get_3bytes( ptr ); ptr += AVP_LENGTH_SIZE; if (avp_len<1) { LM_ERR("hss3g_ungroup_avps: invalid AVP len [%d]\n", avp_len); goto error; } /* avp vendor-ID */ avp_vendorID = 0; if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) { avp_vendorID = get_4bytes( ptr ); ptr += AVP_VENDOR_ID_SIZE; } /* data length */ avp_data_len = avp_len - AVP_HDR_SIZE(avp_flags); /*check the data length */ if ( buf.s+buf.len<ptr+avp_data_len) { LM_ERR("hss3g_ungroup_avps: source buffer to short!! " "Cannot read a whole data for AVP!\n"); goto error; } /* create the AVP */ avp = AAACreateAVP( avp_code, avp_flags, avp_vendorID, ptr, avp_data_len, AVP_DONT_FREE_DATA); if (!avp) { LM_ERR("hss3g_ungroup_avps: can't create avp for member of list\n"); goto error; } /* link the avp into aaa message to the end */ avp->next = 0; avp->prev = lh.tail; if (lh.tail) { lh.tail->next=avp; lh.tail=avp; } else { lh.tail=avp; lh.head=avp; } ptr += to_32x_len( avp_data_len ); } return lh; error: LM_CRIT("AVP:<%.*s>\n",buf.len,buf.s); return lh; }
/** * Receive Loop for Diameter messages. * Decodes the message and calls receive_message(). * @param sock - the socket to receive from * @returns when the socket is closed */ void receive_loop(int sock) { char buf[hdr_len],*msg; int buf_len,length,version,cnt,msg_len; AAAMessage *dmsg; while(!*shutdownx){ buf_len=0; while(buf_len<1){ cnt = select_recv(sock,buf+buf_len,1,0); if (cnt<0) goto error; buf_len+=cnt; } version = (unsigned char)buf[0]; if (version!=1) { LOG(L_ERR,"ERROR:receive_loop():[%d] Recv Unknown version [%d]\n",sock,(unsigned char)buf[0]); continue; } while(buf_len<hdr_len){ cnt = select_recv(sock,buf+buf_len,hdr_len-buf_len,0); if (cnt<0) goto error; buf_len+=cnt; } length = get_3bytes(buf+1); if (length>DP_MAX_MSG_LENGTH){ LOG(L_ERR,"ERROR:receive_loop():[%d] Msg too big [%d] bytes\n",sock,length); goto error; } LOG(L_DBG,"DBG:receive_loop():[%d] Recv Version %d Length %d\n",sock,version,length); msg = shm_malloc(length); if (!msg) { LOG_NO_MEM("shm",length); goto error; } memcpy(msg,buf,hdr_len); msg_len=hdr_len; while(msg_len<length){ cnt = select_recv(sock,msg+msg_len,length-msg_len,0); if (cnt<0) { shm_free(msg); goto error; } msg_len+=cnt; } LOG(L_DBG,"DBG:receive_loop():[%d] Recv message complete\n",sock); dmsg = AAATranslateMessage((unsigned char*)msg,(unsigned int)msg_len,1); /*shm_free(msg);*/ if (dmsg) receive_message(dmsg,sock); else{ shm_free(msg); } } error: if (this_peer) { if (this_peer->I_sock == sock) sm_process(this_peer,I_Peer_Disc,0,0,sock); if (this_peer->R_sock == sock) sm_process(this_peer,R_Peer_Disc,0,0,sock); } LOG(L_ERR,"INFO:receive_loop():[%d] Client closed connection or error... BYE\n",sock); }
/** * Does the actual receive operations on the Diameter TCP socket, for retrieving incoming messages. * The functions is to be called iteratively, each time there is something to be read from the TCP socket. It uses * a simple state machine to read first the version, then the header and then the rest of the message. When an * entire message is received, it is decoded and passed to the processing functions. * @param sp - the serviced peer to operate on * @return 1 on success, 0 on failure */ static inline int do_receive(serviced_peer_t *sp) { int cnt,n,version; char *dst; AAAMessage *dmsg; switch (sp->state){ case Receiver_Waiting: n = 1; /* wait for version */ dst = sp->buf; break; case Receiver_Header: n = DIAMETER_HEADER_LEN - sp->buf_len; /* waiting for rest of header */ dst = sp->buf+sp->buf_len; break; case Receiver_Rest_of_Message: n = sp->length - sp->msg_len; /* waiting for the rest of the message */ dst = sp->msg+sp->msg_len; break; default: LM_ERR("do_receive(): [%.*s] Unknown state %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->state); goto error_and_reset; } cnt = recv(sp->tcp_socket,dst,n,0); if (cnt<=0) goto error_and_reset; switch (sp->state){ case Receiver_Waiting: version = (unsigned char)(sp->buf[0]); if (version!=1) { LM_ERR("do_receive(): [%.*s] Received Unknown version [%d]\n", sp->p->fqdn.len, sp->p->fqdn.s, (unsigned char)sp->buf[0]); goto error_and_reset; }else{ sp->state = Receiver_Header; sp->buf_len = 1; } break; case Receiver_Header: sp->buf_len+=cnt; if (sp->buf_len==DIAMETER_HEADER_LEN){ sp->length = get_3bytes(sp->buf+1); if (sp->length>DP_MAX_MSG_LENGTH){ LM_ERR("do_receive(): [%.*s] Msg too big [%d] bytes\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->length); goto error_and_reset; } LM_DBG("receive_loop(): [%.*s] Recv Version %d Length %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, (unsigned char)(sp->buf[0]), sp->length); sp->msg = shm_malloc(sp->length); if (!sp->msg) { LOG_NO_MEM("shm",sp->length); goto error_and_reset; } memcpy(sp->msg,sp->buf,sp->buf_len); sp->msg_len=sp->buf_len; sp->state = Receiver_Rest_of_Message; } break; case Receiver_Rest_of_Message: sp->msg_len+=cnt; if (sp->msg_len==sp->length){ dmsg = AAATranslateMessage((unsigned char*)sp->msg,(unsigned int)sp->msg_len,1); if (dmsg) { sp->msg = 0; receive_message(dmsg,sp); } else { shm_free(sp->msg); sp->msg = 0; } sp->msg_len = 0; sp->buf_len = 0; sp->state = Receiver_Waiting; } break; default: LM_ERR("do_receive(): [%.*s] Unknown state %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->state); goto error_and_reset; } return 1; error_and_reset: if (sp->msg){ shm_free(sp->msg); sp->msg = 0; sp->msg_len = 0; sp->buf_len = 0; sp->state = Receiver_Waiting; } return 0; }