Ejemplo n.º 1
0
void ServerConnection::receive() {
  int res = tcp_recv_msg(conn.dia_conn, &conn.rb,
			 0, CONN_WAIT_USECS);


  if (res < 0) {
    if (res == AAA_CONN_SHUTDOWN) {
      INFO( M_NAME "receive(): shutdown - closing connection.\n");
      closeConnection(true);
    } else {
      closeConnection();
      ERROR( M_NAME "receive(): tcp_recv_reply() failed.\n");
    }
    return;
  }

  if (!res) // nothing received
    return;

  /* obtain the structure corresponding to the message */
  AAAMessage* msg = AAATranslateMessage(conn.rb.buf, conn.rb.buf_len, 0);	
  if(!msg) {
    ERROR( M_NAME "receive(): message structure not obtained from message.\n");	
    closeConnection();
    return;
  }
    
#ifdef EXTRA_DEBUG 
  AAAPrintMessage(msg);
#endif
  
  if (is_req(msg)) 
    handleRequest(msg);
  else 
    handleReply(msg);
  
  AAAFreeMessage(&msg);  
}
Ejemplo n.º 2
0
/** 
 * 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);
}
Ejemplo n.º 3
0
/*! \brief send a message over an already opened TCP connection */
int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, 
					unsigned int waited_id)
{
	int n, number_of_tries;
	fd_set active_fd_set, read_fd_set;
	struct timeval tv;
	unsigned long int result_code;
	AAAMessage *msg;
	AAA_AVP	*avp;
	char serviceType;
	unsigned int m_id;

	/* try to write the message to the Diameter client */
	while( (n=write(sockfd, buf, len))==-1 ) 
	{
		if (errno==EINTR)
			continue;
		LM_ERR("write returned error: %s\n", strerror(errno));
		return AAA_ERROR;
	}

	if (n!=len) 
	{
		LM_ERR("write gave no error but wrote less than asked\n");
		return AAA_ERROR;
	}
	/* wait for the answer a limited amount of time */
	tv.tv_sec = MAX_WAIT_SEC;
	tv.tv_usec = MAX_WAIT_USEC;

	/* Initialize the set of active sockets. */
	FD_ZERO (&active_fd_set);
	FD_SET (sockfd, &active_fd_set);
	number_of_tries = 0;

	while(number_of_tries<MAX_TRIES)
	{
		read_fd_set = active_fd_set;
		if (select (sockfd+1, &read_fd_set, NULL, NULL, &tv) < 0)
		{
			LM_ERR("select function failed\n");
			return AAA_ERROR;
		}

/*		if (!FD_ISSET (sockfd, &read_fd_set))
		{
			LM_ERR("no response received\n");
//			return AAA_ERROR;
		}
*/		/* Data arriving on a already-connected socket. */
		reset_read_buffer(rb);
		switch( do_read(sockfd, rb) )
		{
			case CONN_ERROR:
				LM_ERR("failed to read from socket\n");
				return AAA_CONN_CLOSED;
			case CONN_CLOSED:
				LM_ERR("failed to read from socket\n");
				return AAA_CONN_CLOSED;
		}
		
		/* obtain the structure corresponding to the message */
		msg = AAATranslateMessage(rb->buf, rb->buf_len, 0);	
		if(!msg)
		{
			LM_ERR("message structure not obtained\n");	
			return AAA_ERROR;
		}
		avp = AAAFindMatchingAVP(msg, NULL, AVP_SIP_MSGID,
								vendorID, AAA_FORWARD_SEARCH);
		if(!avp)
		{
			LM_ERR("AVP_SIP_MSGID not found\n");
			return AAA_ERROR;
		}
		m_id = *((unsigned int*)(avp->data.s));
		LM_DBG("######## m_id=%d\n", m_id);
		if(m_id!=waited_id)
		{
			number_of_tries ++;
			LM_NOTICE("old message received\n");
			continue;
		}
		goto next;
	}

	LM_ERR("too many old messages received\n");
	return AAA_TIMEOUT;
next:

	/* Finally die correct answer */
	avp = AAAFindMatchingAVP(msg, NULL, AVP_Service_Type,
							vendorID, AAA_FORWARD_SEARCH);
	if(!avp)
	{
		LM_ERR("AVP_Service_Type not found\n");
		return AAA_ERROR;
	}
	serviceType = avp->data.s[0];

	result_code = ntohl(*((unsigned long int*)(msg->res_code->data.s)));
	switch(result_code)
	{
		case AAA_SUCCESS:					/* 2001 */
			return ACC_SUCCESS;
		default:							/* error */
			return ACC_FAILURE;
	}
}
Ejemplo n.º 4
0
void ServerConnection::openConnection() {

  DBG("init TCP connection\n");
  if (conn.dia_conn) {
    ERROR("CRITICAL: trying to open new connection, while current one still"
      " opened.\n");
    abort();
  }
  conn.dia_conn = tcp_create_connection(server_name.c_str(), server_port,
					ca_file.c_str(), cert_file.c_str());
  if (!conn.dia_conn) {
    ERROR("establishing connection to %s\n", 
	  server_name.c_str());
    setRetryConnectLater();
    return;
  }

  // send CER
  AAAMessage* cer;
  if ((cer=AAAInMessage(AAA_CC_CER, AAA_APP_DIAMETER_COMMON_MSG))==NULL) {
    ERROR(M_NAME":openConnection(): can't create new "
	  "CER AAA message!\n");
    conn.terminate();
    setRetryConnectLater();
    return;
  }
  if (addOrigin(cer) 
      || addDataAVP(cer, AVP_Host_IP_Address, origin_ip_address, sizeof(origin_ip_address)) 
      || addDataAVP(cer, AVP_Vendor_Id, (char*)&vendorID, sizeof(vendorID)) 
      || addDataAVP(cer, AVP_Supported_Vendor_Id, (char*)&vendorID, sizeof(vendorID)) 
      || addStringAVP(cer, AVP_Product_Name, product_name)) {
    ERROR("openConnection(): adding AVPs failed\n");
    conn.terminate();
    setRetryConnectLater();
    return;
  }

  // supported applications
  AAA_AVP* vs_appid;
  if( (vs_appid=AAACreateAVP(AVP_Vendor_Specific_Application_Id, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, 0, 
			     0, AVP_DONT_FREE_DATA)) == 0) {
    ERROR( M_NAME":openConnection(): creating AVP failed."
	   " (no more free memory!)\n");
    conn.terminate();
    setRetryConnectLater();
    return;
  }

  // feels like c coding...
  if (addGroupedAVP(vs_appid, AVP_Auth_Application_Id, 
		    (char*)&app_id, sizeof(app_id)) ||
      addGroupedAVP(vs_appid, AVP_Vendor_Id, 
		    (char*)&vendorID, sizeof(vendorID)) ||
      (AAAAddAVPToMessage(cer, vs_appid, 0) != AAA_ERR_SUCCESS)
      ) {
    ERROR( M_NAME":openConnection(): creating AVP failed."
	   " (no more free memory!)\n");
    conn.terminate();
    setRetryConnectLater();
    return;
  }

#ifdef EXTRA_DEBUG 
  AAAPrintMessage(cer);
#endif

  conn.setIDs(cer);
  
  if(AAABuildMsgBuffer(cer) != AAA_ERR_SUCCESS) {
    ERROR( " openConnection(): message buffer not created\n");
    AAAFreeMessage(&cer);
    return;
  }
  
  int ret = tcp_send(conn.dia_conn, cer->buf.s, cer->buf.len);
  if (ret) {
    ERROR( "openConnection(): could not send message\n");
    conn.terminate();
    setRetryConnectLater();
    AAAFreeMessage(&cer);
    return;
  }
  
  AAAFreeMessage(&cer);

  unsigned int cea_receive_cnt = 3;
  while (true) {
    int res = tcp_recv_msg(conn.dia_conn, &conn.rb,
			 CONNECT_CEA_REPLY_TIMEOUT, 0);
    
    if (res <= 0) {
      if (!res) {
	ERROR( " openConnection(): did not receive response (CEA).\n");
      } else {
	ERROR( " openConnection(): error receiving response (CEA).\n");
      }
      conn.terminate();
      setRetryConnectLater();
      return;
    }
    
    /* obtain the structure corresponding to the message */
    AAAMessage* cea = AAATranslateMessage(conn.rb.buf, conn.rb.buf_len, 0);	
    if(!cea) {
      ERROR( " openConnection(): could not decipher response (CEA).\n");
      conn.terminate();
      setRetryConnectLater();
      return;
    }

    if (cea->commandCode == AAA_CC_CEA) {
#ifdef EXTRA_DEBUG 
      AAAPrintMessage(cea);
#endif
      AAAFreeMessage(&cea);
      break;
    }

    AAAFreeMessage(&cea);

    if (!(cea_receive_cnt--)) {
      ERROR( " openConnection(): no CEA received.\n");
      conn.terminate();
      setRetryConnectLater();
      return;
    }
  }
  
  DBG("Connection opened.\n");
  open = true;
}
Ejemplo n.º 5
0
/**
 * 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;
}