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);