diam_tcp.c

Go to the documentation of this file.
00001 /*
00002  * $Id: diam_tcp.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 /*! \file
00024  * \ingroup acc
00025  * \brief Acc:: Diameter TCP connections
00026  *
00027  * - Module: \ref acc
00028  */
00029 
00030 #ifdef DIAM_ACC
00031 
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <unistd.h>
00035 #include <netdb.h> 
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <errno.h>
00039 
00040 #include "../../dprint.h"
00041 #include "../../parser/msg_parser.h"
00042 #include "../../parser/parse_to.h"
00043 #include "../../parser/parse_from.h"
00044 #include "../../mem/mem.h"
00045 
00046 #include "diam_message.h"
00047 #include "diam_tcp.h"
00048 #include "diam_dict.h"
00049 
00050 #define M_NAME "acc"
00051 
00052 /*! \brief TCP connection setup */ 
00053 int init_mytcp(char* host, int port)
00054 {
00055    int sockfd;
00056    struct sockaddr_in serv_addr;
00057    struct hostent *server;
00058     
00059    sockfd = socket(PF_INET, SOCK_STREAM, 0);
00060    
00061     if (sockfd < 0) 
00062    {
00063       LM_ERR("failed to create the socket\n");
00064       return -1;
00065    }  
00066    
00067     server = gethostbyname(host);
00068     if (server == NULL) 
00069    {
00070       LM_ERR("failed to find the host\n");
00071       return -1;
00072     }
00073 
00074     memset((char *) &serv_addr, 0, sizeof(serv_addr));
00075     serv_addr.sin_family = PF_INET;
00076     memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr,
00077                server->h_length);
00078     serv_addr.sin_port = htons(port);
00079    
00080     if (connect(sockfd, (const struct sockaddr *)&serv_addr, 
00081                      sizeof(serv_addr)) < 0) 
00082    {
00083         LM_ERR("failed to connec to the DIAMETER client\n");
00084       return -1;
00085    }  
00086 
00087    return sockfd;
00088 }
00089 
00090 /*! \brief send a message over an already opened TCP connection */
00091 int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, 
00092                unsigned int waited_id)
00093 {
00094    int n, number_of_tries;
00095    fd_set active_fd_set, read_fd_set;
00096    struct timeval tv;
00097    unsigned long int result_code;
00098    AAAMessage *msg;
00099    AAA_AVP  *avp;
00100    char serviceType;
00101    unsigned int m_id;
00102 
00103    /* try to write the message to the Diameter client */
00104    while( (n=write(sockfd, buf, len))==-1 ) 
00105    {
00106       if (errno==EINTR)
00107          continue;
00108       LM_ERR("write returned error: %s\n", strerror(errno));
00109       return AAA_ERROR;
00110    }
00111 
00112    if (n!=len) 
00113    {
00114       LM_ERR("write gave no error but wrote less than asked\n");
00115       return AAA_ERROR;
00116    }
00117    /* wait for the answer a limited amount of time */
00118    tv.tv_sec = MAX_WAIT_SEC;
00119    tv.tv_usec = MAX_WAIT_USEC;
00120 
00121    /* Initialize the set of active sockets. */
00122    FD_ZERO (&active_fd_set);
00123    FD_SET (sockfd, &active_fd_set);
00124    number_of_tries = 0;
00125 
00126    while(number_of_tries<MAX_TRIES)
00127    {
00128       read_fd_set = active_fd_set;
00129       if (select (sockfd+1, &read_fd_set, NULL, NULL, &tv) < 0)
00130       {
00131          LM_ERR("select function failed\n");
00132          return AAA_ERROR;
00133       }
00134 
00135 /*    if (!FD_ISSET (sockfd, &read_fd_set))
00136       {
00137          LM_ERR("no response received\n");
00138 //       return AAA_ERROR;
00139       }
00140 */    /* Data arriving on a already-connected socket. */
00141       reset_read_buffer(rb);
00142       switch( do_read(sockfd, rb) )
00143       {
00144          case CONN_ERROR:
00145             LM_ERR("failed to read from socket\n");
00146             return AAA_CONN_CLOSED;
00147          case CONN_CLOSED:
00148             LM_ERR("failed to read from socket\n");
00149             return AAA_CONN_CLOSED;
00150       }
00151       
00152       /* obtain the structure corresponding to the message */
00153       msg = AAATranslateMessage(rb->buf, rb->buf_len, 0);   
00154       if(!msg)
00155       {
00156          LM_ERR("message structure not obtained\n");  
00157          return AAA_ERROR;
00158       }
00159       avp = AAAFindMatchingAVP(msg, NULL, AVP_SIP_MSGID,
00160                         vendorID, AAA_FORWARD_SEARCH);
00161       if(!avp)
00162       {
00163          LM_ERR("AVP_SIP_MSGID not found\n");
00164          return AAA_ERROR;
00165       }
00166       m_id = *((unsigned int*)(avp->data.s));
00167       LM_DBG("######## m_id=%d\n", m_id);
00168       if(m_id!=waited_id)
00169       {
00170          number_of_tries ++;
00171          LM_NOTICE("old message received\n");
00172          continue;
00173       }
00174       goto next;
00175    }
00176 
00177    LM_ERR("too many old messages received\n");
00178    return AAA_TIMEOUT;
00179 next:
00180 
00181    /* Finally die correct answer */
00182    avp = AAAFindMatchingAVP(msg, NULL, AVP_Service_Type,
00183                      vendorID, AAA_FORWARD_SEARCH);
00184    if(!avp)
00185    {
00186       LM_ERR("AVP_Service_Type not found\n");
00187       return AAA_ERROR;
00188    }
00189    serviceType = avp->data.s[0];
00190 
00191    result_code = ntohl(*((unsigned long int*)(msg->res_code->data.s)));
00192    switch(result_code)
00193    {
00194       case AAA_SUCCESS:             /* 2001 */
00195          return ACC_SUCCESS;
00196       default:                   /* error */
00197          return ACC_FAILURE;
00198    }
00199 }
00200 
00201 void reset_read_buffer(rd_buf_t *rb)
00202 {
00203    rb->first_4bytes  = 0;
00204    rb->buf_len       = 0;
00205    if(rb->buf)
00206       pkg_free(rb->buf);
00207    rb->buf           = 0;
00208 }
00209 
00210 /*! \brief read from a socket, an AAA message buffer */
00211 int do_read( int socket, rd_buf_t *p)
00212 {
00213    unsigned char  *ptr;
00214    unsigned int   wanted_len, len;
00215    int n;
00216 
00217    if (p->buf==0)
00218    {
00219       wanted_len = sizeof(p->first_4bytes) - p->buf_len;
00220       ptr = ((unsigned char*)&(p->first_4bytes)) + p->buf_len;
00221    }
00222    else
00223    {
00224       wanted_len = p->first_4bytes - p->buf_len;
00225       ptr = p->buf + p->buf_len;
00226    }
00227 
00228    while( (n=recv( socket, ptr, wanted_len, MSG_DONTWAIT ))>0 ) 
00229    {
00230 //    LM_DBG("(sock=%d)  -> n=%d (expected=%d)\n", p->sock,n,wanted_len);
00231       p->buf_len += n;
00232       if (n<wanted_len)
00233       {
00234          //LM_DBG("only %d bytes read from %d expected\n",n,wanted_len);
00235          wanted_len -= n;
00236          ptr += n;
00237       }
00238       else 
00239       {
00240          if (p->buf==0)
00241          {
00242             /* I just finished reading the first 4 bytes from msg */
00243             len = ntohl(p->first_4bytes)&0x00ffffff;
00244             if (len<AAA_MSG_HDR_SIZE || len>MAX_AAA_MSG_SIZE)
00245             {
00246                LM_ERR("(sock=%d): invalid message "
00247                   "length read %u (%x)\n", socket, len, p->first_4bytes);
00248                goto error;
00249             }
00250             //LM_DBG("message length = %d(%x)\n",len,len);
00251             if ( (p->buf=pkg_malloc(len))==0  )
00252             {
00253                LM_ERR("no more pkg memory\n");
00254                goto error;
00255             }
00256             *((unsigned int*)p->buf) = p->first_4bytes;
00257             p->buf_len = sizeof(p->first_4bytes);
00258             p->first_4bytes = len;
00259             /* update the reading position and len */
00260             ptr = p->buf + p->buf_len;
00261             wanted_len = p->first_4bytes - p->buf_len;
00262          }
00263          else
00264          {
00265             /* I finished reading the whole message */
00266             LM_DBG("(sock=%d): whole message read (len=%d)!\n",
00267                socket, p->first_4bytes);
00268             return CONN_SUCCESS;
00269          }
00270       }
00271    }
00272 
00273    if (n==0)
00274    {
00275       LM_INFO("(sock=%d): FIN received\n", socket);
00276       return CONN_CLOSED;
00277    }
00278    if ( n==-1 && errno!=EINTR && errno!=EAGAIN )
00279    {
00280       LM_ERR("(on sock=%d): n=%d , errno=%d (%s)\n",
00281          socket, n, errno, strerror(errno));
00282       goto error;
00283    }
00284 error:
00285    return CONN_ERROR;
00286 }
00287 
00288 
00289 void close_tcp_connection(int sfd)
00290 {
00291    shutdown(sfd, 2);
00292 }
00293 
00294 /*! \brief 
00295  * Extract URI depending on the request from To or From header 
00296  */
00297 int get_uri(struct sip_msg* m, str** uri)
00298 {
00299    if ((REQ_LINE(m).method.len == 8) && 
00300                (memcmp(REQ_LINE(m).method.s, "REGISTER", 8) == 0)) 
00301    {/* REGISTER */
00302       if (!m->to && ((parse_headers(m, HDR_TO_F, 0) == -1) || !m->to )) 
00303       {
00304          LM_ERR("the To header field was not found or malformed\n");
00305          return -1;
00306       }
00307       *uri = &(get_to(m)->uri);
00308    } 
00309    else 
00310    {
00311       if (parse_from_header(m)<0)
00312       {
00313          LM_ERR("failed to parse headers\n");
00314          return -2;
00315       }
00316       *uri = &(get_from(m)->uri);
00317    }
00318    return 0;
00319 }
00320 
00321 
00322 #endif

Generated on Tue May 22 16:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6