eXosip2研究笔记

1.全局变量eXosip的初始化

全局变量eXosip是eXosip2库工作的核心,它通过osip成员变量与osip库中的osip对应起来,整个协议栈的实现,都是在eXosip的基础上运行的。首先我们看看eXosip_t结构体。

  struct eXosip_t

  {

    struct eXtl_protocol *eXtl;

    char transport[10];

    char *user_agent; /*消息中会添加这个头域,类似于打广告! */

 

    eXosip_call_t *j_calls;     /* my calls        */

#ifndef MINISIZE

    eXosip_subscribe_t *j_subscribes;   /* my friends      */

    eXosip_notify_t *j_notifies;        /* my susbscribers */

#endif

    osip_list_t j_transactions;

 

    eXosip_reg_t *j_reg;        /* my registrations */

#ifndef MINISIZE

    eXosip_pub_t *j_pub;        /* my publications  */

#endif

 

#ifdef OSIP_MT

    void *j_cond;

    void *j_mutexlock;

#endif

 

    osip_t *j_osip;

    int j_stop_ua;

#ifdef OSIP_MT

    void *j_thread;

    jpipe_t *j_socketctl;

    jpipe_t *j_socketctl_event;/*事件管道 */

#endif

 

    osip_fifo_t *j_events;

 

    jauthinfo_t *authinfos;

 

    int keep_alive;

    int learn_port;

#ifndef MINISIZE

    int http_port;

    char http_proxy[256];

    char http_outbound_proxy[256];

    int dontsend_101;

#endif

    int use_rport; /*这两个整形参数是干嘛的呢?*/

    int use_naptr;

    char ipv4_for_gateway[256];

    char ipv6_for_gateway[256];

#ifndef MINISIZE

    char event_package[256];

#endif

    struct eXosip_dns_cache dns_entries[MAX_EXOSIP_DNS_ENTRY];

    struct eXosip_account_info account_entries[MAX_EXOSIP_ACCOUNT_INFO];

    struct eXosip_http_auth http_auths[MAX_EXOSIP_HTTP_AUTH];

 

    CbSipCallback cbsipCallback;

  };

 

初始化函数的定义如下:

int

eXosip_init (void)

{

  osip_t *osip;

  int i;

 

  memset (&eXosip, 0, sizeof (eXosip));

 

  snprintf (eXosip.ipv4_for_gateway, 256, "%s", "217.12.3.11");

  snprintf (eXosip.ipv6_for_gateway, 256, "%s",

            "2001:638:500:101:2e0:81ff:fe24:37c6");

#ifndef MINISIZE

  snprintf (eXosip.event_package, 256, "%s", "dialog");

#endif

 

#ifdef WIN32

  /* Initializing windows socket library */

  {

    WORD wVersionRequested;

    WSADATA wsaData;

 

    wVersionRequested = MAKEWORD (1, 1);

    i = WSAStartup (wVersionRequested, &wsaData);

    if (i != 0)

      {

        OSIP_TRACE (osip_trace

                    (__FILE__, __LINE__, OSIP_WARNING, NULL,

                     "eXosip: Unable to initialize WINSOCK, reason: %d/n", i));

        /* return -1; It might be already initilized?? */

      }

  }

#endif

 

  eXosip.user_agent = osip_strdup ("eXosip/" EXOSIP_VERSION);

  if (eXosip.user_agent == NULL)

    return OSIP_NOMEM;

 

  eXosip.j_calls = NULL;

  eXosip.j_stop_ua = 0;

#ifdef OSIP_MT

  eXosip.j_thread = NULL;

#endif

  i = osip_list_init (&eXosip.j_transactions);

  eXosip.j_reg = NULL;

 

#ifdef OSIP_MT

#if !defined (_WIN32_WCE)

  eXosip.j_cond = (struct osip_cond *) osip_cond_init ();

  if (eXosip.j_cond == NULL)

    {

      osip_free (eXosip.user_agent);

      eXosip.user_agent = NULL;

      return OSIP_NOMEM;

    }

#endif

 

  eXosip.j_mutexlock = (struct osip_mutex *) osip_mutex_init ();

  if (eXosip.j_mutexlock == NULL)

    {

      osip_free (eXosip.user_agent);

      eXosip.user_agent = NULL;

#if !defined (_WIN32_WCE)

      osip_cond_destroy ((struct osip_cond *) eXosip.j_cond);

      eXosip.j_cond = NULL;

#endif

      return OSIP_NOMEM;

    }

#endif

/*对eXosip的各个参数进行初始化*/

  i = osip_init (&osip);

  if (i != 0)

    {

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_ERROR, NULL,

                   "eXosip: Cannot initialize osip!/n"));

      return i;

    }

 

  osip_set_application_context (osip, &eXosip); /*把这两个链接起来*/

 

  eXosip_set_callbacks (osip);/*设置各种回调函数 */

 

  eXosip.j_osip = osip;

 

#ifdef OSIP_MT

  /* open a TCP socket to wake up the application when needed. */

  eXosip.j_socketctl = jpipe ();/*新建管道 */

  if (eXosip.j_socketctl == NULL)

    return OSIP_UNDEFINED_ERROR;

 

  eXosip.j_socketctl_event = jpipe ();/*新建管道 */

  if (eXosip.j_socketctl_event == NULL)

    return OSIP_UNDEFINED_ERROR;

#endif

/*这两个管道的具体区别,还有待进一步研究*/

 

  /* To be changed in osip! */

  eXosip.j_events = (osip_fifo_t *) osip_malloc (sizeof (osip_fifo_t));

  if (eXosip.j_events == NULL)

    return OSIP_NOMEM;

  osip_fifo_init (eXosip.j_events);

 

  eXosip.use_rport = 1;

  eXosip.use_naptr = 1;

  eXosip.keep_alive = 17000; /*17s*/

 

  eXtl_udp.tl_init (); /*调用udp_tl_init对进行UDP通信的一些全局变量进行初始化 */

  eXtl_tcp.tl_init ();

#ifdef HAVE_OPENSSL_SSL_H

#if !(OPENSSL_VERSION_NUMBER < 0x00908000L)

  eXtl_dtls.tl_init ();

#endif

  eXtl_tls.tl_init ();

#endif

  return OSIP_SUCCESS;

}

在这个初始化函数中,主要是对全局变量eXosip的一些成员变量进行了初始化。同时可以看到,在最后通过调用全部变量eXtl_udp(在本文中我们只考虑UDP传输情况)的成员函数tl_init(),即函数udp_tl_init(),对UDP通信的一些全局变量进行初始化。其函数定义如下:

static int

udp_tl_init (void)

{

  udp_socket = 0;

  memset (&ai_addr, 0, sizeof (struct sockaddr_storage));

  memset (udp_firewall_ip, 0, sizeof (udp_firewall_ip));

  memset (udp_firewall_port, 0, sizeof (udp_firewall_port));

  return OSIP_SUCCESS;

}

 

 

2. eXosip_listen_addr

先介绍一个数据结构:

struct eXtl_protocol

{

  int enabled;

 

  int proto_port;

  char proto_name[10];

  char proto_ifs[20];

  int proto_num;/* IPPROTO_UDP*/

  int proto_family;

  int proto_secure;

  int proto_reliable;

 

  int (*tl_init) (void);

  int (*tl_free) (void);

  int (*tl_open) (void);

  int (*tl_set_fdset) (fd_set * osip_fdset, int *fd_max);

  int (*tl_read_message) (fd_set * osip_fdset);

  int (*tl_send_message) (osip_transaction_t * tr, osip_message_t * sip,

                          char *host, int port, int out_socket);

  int (*tl_keepalive) (void);

  int (*tl_set_socket) (int socket);

  int (*tl_masquerade_contact) (const char *ip, int port);

  int (*tl_get_masquerade_contact) (char *ip, int ip_size, char *port,

                                    int port_size);

};

这个是全局变量eXtl_udp的结构类型,在下面这个函数的定义里可以看到,很多都是对它的初始化。

 

这个函数的定义如下:

int

eXosip_listen_addr (int transport, const char *addr, int port, int family,

                    int secure)

{

  int i = -1;

  struct eXtl_protocol *eXtl = NULL;

 

  if (eXosip.eXtl != NULL)

    {

      /* already set */

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_ERROR, NULL,

                   "eXosip: already listening somewhere/n"));

      return OSIP_WRONG_STATE;

    }

 

  if (transport == IPPROTO_UDP && secure == 0)

    eXtl = &eXtl_udp;

  else if (transport == IPPROTO_TCP && secure == 0)

    eXtl = &eXtl_tcp;

#ifdef HAVE_OPENSSL_SSL_H

#if !(OPENSSL_VERSION_NUMBER < 0x00908000L)

  else if (transport == IPPROTO_UDP)

    eXtl = &eXtl_dtls;

#endif

  else if (transport == IPPROTO_TCP)

    eXtl = &eXtl_tls;

#endif

 

  if (eXtl == NULL)

    return OSIP_BADPARAMETER;

 

  eXtl->proto_family = family;

  eXtl->proto_port = port;

  if (addr != NULL)/*注意如果addr == NULL,那么eXtl->proto_ifs的初始值在eXtl_udp的声明处定义为”0.0.0.0”*/

    snprintf (eXtl->proto_ifs, sizeof (eXtl->proto_ifs), "%s", addr);

 

#ifdef      AF_INET6

  if (family == AF_INET6 && !addr)

    snprintf (eXtl->proto_ifs, sizeof (eXtl->proto_ifs), "::0");

#endif

 

  i = eXtl->tl_open ();/*调用eXtl_udp->tl_open()创建套接字并绑定 */

 

  if (i != 0)

    return i;

 

  eXosip.eXtl = eXtl;

 

  if (transport == IPPROTO_UDP && secure == 0)

    snprintf (eXosip.transport, sizeof (eXosip.transport), "%s", "UDP");

  else if (transport == IPPROTO_TCP && secure == 0)

    snprintf (eXosip.transport, sizeof (eXosip.transport), "%s", "TCP");

  else if (transport == IPPROTO_UDP)

    snprintf (eXosip.transport, sizeof (eXosip.transport), "%s", "DTLS-UDP");

  else if (transport == IPPROTO_TCP)

    snprintf (eXosip.transport, sizeof (eXosip.transport), "%s", "TLS");

 

  /* 上面都是对eXosip.eXtl的相关参数进行设置,对传输协议初始化 */

#ifdef OSIP_MT

  if (eXosip.j_thread == NULL)

    {

      eXosip.j_thread = (void *) osip_thread_create (20000, _eXosip_thread, NULL);/* 创建新的线程,进行监听

                                                                                                                                    转入_eXosip_thread执行*/

      if (eXosip.j_thread == NULL)

        {

          OSIP_TRACE (osip_trace

                      (__FILE__, __LINE__, OSIP_ERROR, NULL,

                       "eXosip: Cannot start thread!/n"));

          return OSIP_UNDEFINED_ERROR;

        }

    }

#endif

 

  return OSIP_SUCCESS;/*注意如果没有使用多线程,那这里仅仅是对传输协议进行了初始化而已 */

}

上面主要的内容是对eXosip.eXtl,eXosip.transport进行初始化,最后新建一个线程,执行_eXosip_thread函数。

 

2.1调用eXtl_udp->tl_open()创建套接字并绑定

上述初始化过程中,调用了eXtl_udp->tl_open(),即udp_tl_open()函数,来进行套接字的创建与绑定,函数定义为:

 

static int

udp_tl_open (void)/* 这个函数主要用来创建套接字,并进行端口绑定,socket为 udp_socket*/

{

  int res;

  struct addrinfo *addrinfo = NULL;

  struct addrinfo *curinfo;

  int sock = -1;

 

  if (eXtl_udp.proto_port < 0)

    eXtl_udp.proto_port = 5060;

 

 

  res = eXosip_get_addrinfo (&addrinfo,

                             eXtl_udp.proto_ifs,

                             eXtl_udp.proto_port, eXtl_udp.proto_num);/*初始化addrinfo */

  if (res)

    return -1;

 

  for (curinfo = addrinfo; curinfo; curinfo = curinfo->ai_next)

    {

      socklen_t len;

 

      if (curinfo->ai_protocol && curinfo->ai_protocol != eXtl_udp.proto_num)

        {

          OSIP_TRACE (osip_trace

                      (__FILE__, __LINE__, OSIP_INFO3, NULL,

                       "eXosip: Skipping protocol %d/n", curinfo->ai_protocol));

          continue;

        }

 

      sock = (int) socket (curinfo->ai_family, curinfo->ai_socktype,

                           curinfo->ai_protocol);

      if (sock < 0)

        {

          OSIP_TRACE (osip_trace

                      (__FILE__, __LINE__, OSIP_ERROR, NULL,

                       "eXosip: Cannot create socket %s!/n", strerror (errno)));

          continue;

        }

 

      if (curinfo->ai_family == AF_INET6)

        {

#ifdef IPV6_V6ONLY

          if (setsockopt_ipv6only (sock))

            {

              close (sock);

              sock = -1;

              OSIP_TRACE (osip_trace

                          (__FILE__, __LINE__, OSIP_ERROR, NULL,

                           "eXosip: Cannot set socket option %s!/n",

                           strerror (errno)));

              continue;

            }

#endif /* IPV6_V6ONLY */

        }

 

      res = bind (sock, curinfo->ai_addr, curinfo->ai_addrlen);

      if (res < 0)

        {

          OSIP_TRACE (osip_trace

                      (__FILE__, __LINE__, OSIP_ERROR, NULL,

                       "eXosip: Cannot bind socket node:%s family:%d %s/n",

                       eXtl_udp.proto_ifs, curinfo->ai_family, strerror (errno)));

          close (sock);

          sock = -1;

          continue;

        }

      len = sizeof (ai_addr);

      res = getsockname (sock, (struct sockaddr *) &ai_addr, &len); /*ai_addr里面保存的是这个套接字对应的本地地址信息*/

      if (res != 0)

        {

          OSIP_TRACE (osip_trace

                      (__FILE__, __LINE__, OSIP_ERROR, NULL,

                       "eXosip: Cannot get socket name (%s)/n", strerror (errno)));

          memcpy (&ai_addr, curinfo->ai_addr, curinfo->ai_addrlen);

        }

 

      if (eXtl_udp.proto_num != IPPROTO_UDP)

        {

          res = listen (sock, SOMAXCONN);

          if (res < 0)

            {

              OSIP_TRACE (osip_trace

                          (__FILE__, __LINE__, OSIP_ERROR, NULL,

                           "eXosip: Cannot bind socket node:%s family:%d %s/n",

                           eXtl_udp.proto_ifs, curinfo->ai_family,

                           strerror (errno)));

              close (sock);

              sock = -1;

              continue;

            }

        }

 

      break;

    }/* 利用for循环,对每一个地址创建套接字并绑定*/

 

  eXosip_freeaddrinfo (addrinfo);

 

  if (sock < 0)

    {

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_ERROR, NULL,

                   "eXosip: Cannot bind on port: %i/n", eXtl_udp.proto_port));

      return -1;

    }

 

  udp_socket = sock;/*这是已经绑定过的套接字*/

 

  if (eXtl_udp.proto_port == 0)

    {

      /* get port number from socket */

      if (eXtl_udp.proto_family == AF_INET)

        eXtl_udp.proto_port = ntohs (((struct sockaddr_in *) &ai_addr)->sin_port);/*这里是本地端口号*/

      else

        eXtl_udp.proto_port =

          ntohs (((struct sockaddr_in6 *) &ai_addr)->sin6_port);

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_INFO1, NULL,

                   "eXosip: Binding on port %i!/n", eXtl_udp.proto_port));

    }

  snprintf (udp_firewall_port, sizeof (udp_firewall_port), "%i",

            eXtl_udp.proto_port);

  return OSIP_SUCCESS;

}

分析这个函数之前,首先看看struct addrinfo结构体的声明:

  struct addrinfo

  {

    int ai_flags;               /* Input flags.  */

    int ai_family;              /* Protocol family for socket.  */

    int ai_socktype;            /* Socket type.  */

    int ai_protocol;            /* Protocol for socket.  */

    socklen_t ai_addrlen;       /* Length of socket address.  */

    struct sockaddr *ai_addr;   /* Socket address for socket.  */

    char *ai_canonname;         /* Canonical name for service location.  */

    struct addrinfo *ai_next;   /* Pointer to next in list.  */

  };

这是一个单向链表,通过ai_next指向下一位。

在这个函数的开始,便调用eXosip_get_addrinfo()函数来对addrinfo进行了一些初始化。

 

2.2_eXosip_thread

这个函数是新线程所执行的函数,其原代码如下:

void *

_eXosip_thread (void *arg)

{

  int i;

 

  while (eXosip.j_stop_ua == 0)/*不等于0表示停止工作,等于0就一直工作*/

    {

      i = eXosip_execute ();/*一直执行eXosip_execute函数,可见关键在就这里 */

      if (i == -2000)

        osip_thread_exit ();

    }

  osip_thread_exit ();

  return NULL;

}

只要eXosip.j_stop_ua等于0,就一直执行eXosip_execute()。

 

2.3 eXosip_execute

这个函数是整个协议栈的核心,对所有事务和事件的处理部分,都通过在这个函数里面调用来执行。先看下它的源代码:

int

eXosip_execute (void)

{

  struct timeval lower_tv;

  int i;

 

#ifdef OSIP_MT

  osip_timers_gettimeout (eXosip.j_osip, &lower_tv);

  if (lower_tv.tv_sec > 10)

    {

      lower_tv.tv_sec = 10;

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_INFO2, NULL,

                   "eXosip: Reseting timer to 10s before waking up!/n"));

  } else

    {

      /*  add a small amount of time on windows to avoid

         waking up too early. (probably a bad time precision) */

      if (lower_tv.tv_usec < 900000)

        lower_tv.tv_usec = 100000;      /* add 10ms */

      else

        {

          lower_tv.tv_usec = 10000;     /* add 10ms */

          lower_tv.tv_sec++;

        }

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_INFO2, NULL,

                   "eXosip: timer sec:%i usec:%i!/n",

                   lower_tv.tv_sec, lower_tv.tv_usec));

    }

#else

  lower_tv.tv_sec = 0;

  lower_tv.tv_usec = 0;

#endif

  i = eXosip_read_message (1, lower_tv.tv_sec, lower_tv.tv_usec);/*如果在超时前有消息到达,就将其转化成osip_event_t事件,并且添加到对应的事务里面(可以在下面进行处理)*/

 

  if (i == -2000)

    {

      return -2000;

    }

 

  eXosip_lock ();

  osip_timers_ict_execute (eXosip.j_osip); /* 给已经超时的事务添加定时器超时事件*/

  osip_timers_nict_execute (eXosip.j_osip);

  osip_timers_ist_execute (eXosip.j_osip);

  osip_timers_nist_execute (eXosip.j_osip);

 

  osip_nist_execute (eXosip.j_osip);/*执行指定事务类型的所有事务的所有事件(包括定时器超时事件) */

  osip_nict_execute (eXosip.j_osip);

  osip_ist_execute (eXosip.j_osip);

  osip_ict_execute (eXosip.j_osip);

 

  /* free all Calls that are in the TERMINATED STATE? */

  eXosip_release_terminated_calls ();

  eXosip_release_terminated_registrations ();

  eXosip_release_terminated_publications ();

#ifndef MINISIZE

  eXosip_release_terminated_subscriptions ();

  eXosip_release_terminated_in_subscriptions ();

#endif

 

  eXosip_unlock ();

 

 

  if (eXosip.keep_alive > 0)

    {

      _eXosip_keep_alive ();/* 如果alive期限过了,重设alive时间,并执行 eXtl_udp.tl_keepalive*/

    }

 

  return OSIP_SUCCESS;

}

 

我们从上到下来分析这个函数。

 

2.3.1 osip_timers_gettimeout

在上面的函数里,首先调用的是这个函数,这个函数的原型是这样的:(函数定义请参考源代码)

void

osip_timers_gettimeout (osip_t * osip, struct timeval *lower_tv)

这个函数主要是用来得到定时器超时的时间距离现在的时间间隔,它查找每种类型的事务列表,依次查询每个事务,如果事务中的事件队列里面有事件发生,就令lower_tv为0返回.否则就将lower_tv赋值为对应事务状态下定时器超时的时间,并检查当前是否已经超时,如果已经超时,就让lower_tv为0返回,否则检测下种类型的事务,最后返回的是最近的超时的一个事务的时间间隔。

 

2.3.2 eXosip_read_message

这个函数的定义如下:

int

eXosip_read_message (int max_message_nb, int sec_max, int usec_max)

{

  fd_set osip_fdset;

  struct timeval tv;

 

  tv.tv_sec = sec_max;

  tv.tv_usec = usec_max;

 

  while (max_message_nb != 0 && eXosip.j_stop_ua == 0)

    {

      int i;

      int max = 0;

#ifdef OSIP_MT

      int wakeup_socket = jpipe_get_read_descr (eXosip.j_socketctl);/*获取读管道 */

#endif

 

      FD_ZERO (&osip_fdset);

      eXtl_udp.tl_set_fdset (&osip_fdset, &max); /*这里我们只考虑UDP,这个函数将全局变量udp_socket添加到监听集 */

      eXtl_tcp.tl_set_fdset (&osip_fdset, &max);

#ifdef HAVE_OPENSSL_SSL_H

#if !(OPENSSL_VERSION_NUMBER < 0x00908000L)

      eXtl_dtls.tl_set_fdset (&osip_fdset, &max);

#endif

      eXtl_tls.tl_set_fdset (&osip_fdset, &max);

#endif

 

#ifdef OSIP_MT

      eXFD_SET (wakeup_socket, &osip_fdset);

      if (wakeup_socket > max)

        max = wakeup_socket;/*将wakeup_socket加入监听集*/

#endif

 

      if ((sec_max == -1) || (usec_max == -1))

        i = select (max + 1, &osip_fdset, NULL, NULL, NULL);/*如果定时器没启动,那么当udp_socket有消息到来的时候即收到消息,或者读管道读到事件(比如发送消息,传输层错误)退出,如果定时器启动,定时器超时也会退出*/

      else

        i = select (max + 1, &osip_fdset, NULL, NULL, &tv);

 

#if defined (_WIN32_WCE)

      /* TODO: fix me for wince */

      /* if (i == -1)

         continue; */

#else

      if ((i == -1) && (errno == EINTR || errno == EAGAIN))

        continue;

#endif

#ifdef OSIP_MT

      if ((i > 0) && FD_ISSET (wakeup_socket, &osip_fdset))

        {

          char buf2[500];

 

          jpipe_read (eXosip.j_socketctl, buf2, 499);/*如果有事件发生,就读取读管道的内容到buf2里面*/

        }

#endif

 

      if (0 == i || eXosip.j_stop_ua != 0) /*i=0表示超时返回,定时器超时了,什么代码也不执行!函数马上退出,因为下面会马上添加定时器超时事件*/

        {

      } else if (-1 == i)

        {

#if !defined (_WIN32_WCE)       /* TODO: fix me for wince */

          return -2000;         /* error *//*在非windows出错则返回-2000 */

#endif

      } else/* 这部分是在i>0,也就是udp_socket读到消息的条件下执行的*/

        {

          eXtl_udp.tl_read_message (&osip_fdset);

          eXtl_tcp.tl_read_message (&osip_fdset);

#ifdef HAVE_OPENSSL_SSL_H

#if !(OPENSSL_VERSION_NUMBER < 0x00908000L)

          eXtl_dtls.tl_read_message (&osip_fdset);

#endif

          eXtl_tls.tl_read_message (&osip_fdset);

#endif

        }

 

      max_message_nb--;/*这里的循环只执行一次! */

    }

  return OSIP_SUCCESS;

}

这个函数的作用可以概括为:

如果在超时前有消息到达,就将其转化成osip_event_t事件,并且添加到对应的事务里面(可以在下面进行处理)。

 

2.3.3 udp_tl_read_message

可以看到,在上面的eXosip_read_message函数里,当有消息通过udp_socket到达的时候,对消息的处理是通过eXtl_udp.tl_read_message,即udp_tl_read_message来进行处理的。

static int

udp_tl_read_message (fd_set * osip_fdset)

{

  char *buf;

  int i;

 

  if (udp_socket <= 0)

    return -1;

 

  if (FD_ISSET (udp_socket, osip_fdset))

    {

      struct sockaddr_storage sa;

 

#ifdef __linux

      socklen_t slen;

#else

      int slen;

#endif

      if (eXtl_udp.proto_family == AF_INET)

        slen = sizeof (struct sockaddr_in);

      else

        slen = sizeof (struct sockaddr_in6);

 

      buf = (char *) osip_malloc (SIP_MESSAGE_MAX_LENGTH * sizeof (char) + 1);

      if (buf == NULL)

        return OSIP_NOMEM;

 

      i = recvfrom (udp_socket, buf,

                    SIP_MESSAGE_MAX_LENGTH, 0, (struct sockaddr *) &sa, &slen);/* 读取接收到的消息*/

 

      if (i > 5)

        {

          char src6host[NI_MAXHOST];

          int recvport = 0;

          int err;

 

          osip_strncpy (buf + i, "/0", 1);

          OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL,

                                  "Received message: /n%s/n", buf));

 

          memset (src6host, 0, sizeof (src6host));

 

          if (eXtl_udp.proto_family == AF_INET)

            recvport = ntohs (((struct sockaddr_in *) &sa)->sin_port);/*对方发送消息的端口号 */

          else

            recvport = ntohs (((struct sockaddr_in6 *) &sa)->sin6_port);

 

#if defined(__arc__)

          {

            struct sockaddr_in *fromsa = (struct sockaddr_in *) &sa;

            char *tmp;

            tmp = inet_ntoa (fromsa->sin_addr);

            if (tmp == NULL)

              {

                OSIP_TRACE (osip_trace

                            (__FILE__, __LINE__, OSIP_ERROR, NULL,

                             "Message received from: NULL:%i inet_ntoa failure/n",

                             recvport));

            } else

              {

                snprintf (src6host, sizeof (src6host), "%s", tmp);/*src6host里面存的是发送方的IP*/

                OSIP_TRACE (osip_trace

                            (__FILE__, __LINE__, OSIP_INFO1, NULL,

                             "Message received from: %s:%i/n", src6host,

                             recvport));

              }

          }

#else

          err = getnameinfo ((struct sockaddr *) &sa, slen,

                             src6host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);

 

          if (err != 0)

            {

              OSIP_TRACE (osip_trace

                          (__FILE__, __LINE__, OSIP_ERROR, NULL,

                           "Message received from: NULL:%i getnameinfo failure/n",

                           recvport));

              snprintf (src6host, sizeof (src6host), "127.0.0.1");

          } else

            {

              OSIP_TRACE (osip_trace

                          (__FILE__, __LINE__, OSIP_INFO1, NULL,

                           "Message received from: %s:%i/n", src6host, recvport));

            }

#endif/*这里主要是打印调试信息,从哪里接收到消息 */

 

          OSIP_TRACE (osip_trace

                      (__FILE__, __LINE__, OSIP_INFO1, NULL,

                       "Message received from: %s:%i/n", src6host, recvport));

 

          _eXosip_handle_incoming_message (buf, i, udp_socket, src6host, recvport);/*对接收的消息的处理主要在这个函数

                                                                                                                                            里面*/

 

        }

#ifndef MINISIZE

      else if (i < 0)

        {

          OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL,

                                  "Could not read socket/n"));

      } else

        {

          OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL,

                                  "Dummy SIP message received/n"));

        }

#endif

 

      osip_free (buf);

    }

 

  return OSIP_SUCCESS;

}

 

2.3.4_eXosip_handle_incoming_message

在上面的函数里面可以看到,对接受到的消息,又是通过调用_eXosip_handle_incoming_message来进行处理的,这个函数的代码是:

int

_eXosip_handle_incoming_message (char *buf, size_t length, int socket,

                                 char *host, int port)

{

  int i;

  osip_event_t *se;

 

  se = (osip_event_t *) osip_malloc (sizeof (osip_event_t));

  if (se == NULL)

    return OSIP_NOMEM;

  se->type = UNKNOWN_EVT;

  se->sip = NULL;

  se->transactionid = 0;

 

  /* parse message and set up an event */

  i = osip_message_init (&(se->sip));

  if (i != 0)

    {

      osip_free (se);

      return i;

    }

  i = osip_message_parse (se->sip, buf, length);

  if (i != 0)

    {

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_ERROR, NULL,

                   "could not parse message/n"));

      osip_message_free (se->sip);

      osip_free (se);

      return i;

    } /*将接收到的消息存储在osip_message_t结构se->sip里面 */

 

  if (se->sip->call_id != NULL && se->sip->call_id->number != NULL)

    {

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_INFO3, NULL,

                   "MESSAGE REC. CALLID:%s/n", se->sip->call_id->number));

    }

 

  if (eXosip.cbsipCallback != NULL)

    {

      eXosip.cbsipCallback (se->sip, 1); /*这个在那里设置的呢?*/

    }

 

  if (MSG_IS_REQUEST (se->sip))

    {

      if (se->sip->sip_method == NULL || se->sip->req_uri == NULL)

        {

          osip_message_free (se->sip);

          osip_free (se);

          return OSIP_SYNTAXERROR;

        }

    }

 

  if (MSG_IS_REQUEST (se->sip))

    {

      if (MSG_IS_INVITE (se->sip))

        se->type = RCV_REQINVITE;

      else if (MSG_IS_ACK (se->sip))

        se->type = RCV_REQACK;

      else

        se->type = RCV_REQUEST;

  } else

    {

      if (MSG_IS_STATUS_1XX (se->sip))

        se->type = RCV_STATUS_1XX;

      else if (MSG_IS_STATUS_2XX (se->sip))

        se->type = RCV_STATUS_2XX;

      else

        se->type = RCV_STATUS_3456XX;

    }

/* 这里都是确定se->type的类型*/

  OSIP_TRACE (osip_trace

              (__FILE__, __LINE__, OSIP_INFO1, NULL,

               "Message received from: %s:%i/n", host, port));

 

  osip_message_fix_last_via_header (se->sip, host, port);

 

  i = osip_find_transaction_and_add_event (eXosip.j_osip, se);

  if (i != 0)/*没有找到事务,进行相应的处理 */

    {

      /* this event has no transaction, */

      OSIP_TRACE (osip_trace

                  (__FILE__, __LINE__, OSIP_INFO1, NULL,

                   "This is a request/n", buf));

      eXosip_lock ();

      if (MSG_IS_REQUEST (se->sip))

        eXosip_process_newrequest (se, socket);/*没有找到事务,说明是一个新请求,当新请求来出来*/

      else if (MSG_IS_RESPONSE (se->sip))

        eXosip_process_response_out_of_transaction (se);/*如果是一个响应,说明是事务外的响应*/

      eXosip_unlock ();

  } else

    {

      /* handled by oSIP ! */ /* 找到了就不用处理,因为osip已经将event添加到对应事务的event列表里面了*/

      return OSIP_SUCCESS;

    }

  return OSIP_SUCCESS;

  /*综合来看,这个函数的作用是,首先将缓存区的内容转换成osip_message_t结构体,然后通过这个结构体生成一个事件,之后

  判断这个事件所属于的类型。然后再查找是否有这个事件对应的事务存在,如果有,就将事件添加到对应事务的事件列表里面  */

}

分析已经在代码里面了,可以很清楚的看到,对接受到的消息的处理主要是将其转化成一个事件,然后添加到对应事务类型的事务的事件列表里面,等待处理。

 

2.3.5添加定时器超时事件

通过上面的分析,对eXosip协议栈接收消息处理消息的过程可以说已经很清楚了,下面继续分析eXosip_execute()函数。

  osip_timers_ict_execute (eXosip.j_osip); /* 给已经超时的事务添加定时器超时事件*/

  osip_timers_nict_execute (eXosip.j_osip);

  osip_timers_ist_execute (eXosip.j_osip);

  osip_timers_nist_execute (eXosip.j_osip);

这四个函数的作用是查找对应的事务,看是否有超时的事务,如果有,就给超时的事务添加一个定时器超时事件。

 

  osip_nist_execute (eXosip.j_osip);/*执行指定事务类型的所有事务的所有事件(包括定时器超时事件) */

  osip_nict_execute (eXosip.j_osip);

  osip_ist_execute (eXosip.j_osip);

  osip_ict_execute (eXosip.j_osip);


你可能感兴趣的:(SIP,网络编程,socket,null,struct,thread,file,transactions)