1. 从利用eXosip的注册开始
int i; char identity[50]; char registerer[50]; char localip[128]; static int flag = 0; int id; eXosip_guess_localip (AF_INET, localip, 128); sprintf(identity,"sip:%s@%s",username,localip); sprintf(registerer,"sip:%s:%s",ip_url,port); //初始化 if( flag == 0) { i = eXosip_init(); if (i != 0) { return -1; } TRACE("eXosip_init success/n"); flag ++; i = eXosip_listen_addr(IPPROTO_UDP, NULL, 5060, AF_INET, 0); if (i != 0) { eXosip_quit(); fprintf(stderr, "could not initialize transport layer/n"); return -1; } TRACE("eXosip_listen_addr success/n"); } osip_message_t *reg = NULL; eXosip_lock(); id = eXosip_register_build_initial_register (identity,registerer, NULL, 1800, ®); printf("id = %d", id); if (id < 0) { eXosip_unlock(); fprintf (stderr, "eXosip_register_build_initial_register failed:(bad arguments?)/n"); return 0; } eXosip_lock(); i = eXosip_register_send_register(id, reg); if (i != 0) { fprintf (stderr, "eXosip_register_send_register failed: (bad arguments?)/n"); return 0; } eXosip_unlock (); TRACE("eXosip_register_send_register OK/n"); eXosip_event_t *je; for (;;) { je = eXosip_event_wait (0, 50); eXosip_lock(); eXosip_automatic_action (); eXosip_unlock(); if (je == NULL) { continue; } if (je->type == EXOSIP_REGISTRATION_SUCCESS) { TRACE("textinfo is %s/n", je->textinfo); return 1; break; } if(je->type == EXOSIP_REGISTRATION_FAILURE) { //注册失败之后,再次提交授权信息, 也可放在上面 eXosip_add_authentication_info(username, username,password, NULL, NULL); } if(je->type == EXOSIP_REGISTRATION_REFRESHED) { TRACE("refreshed"); return 0; } } eXosip_quit(); |
eXosip_guess_localip (AF_INET, localip, 128);
这句在eXosip中的实现为
eXosip_guess_localip (int family, char *address, int size)
address在函数体外首先进行定义为一数组,分配好空间,再给形式参数传指针过去,在函数体内对实际参数address赋值。这里就是本地的ip地址。
参见eXosip_guess_localip 的实现
int eXosip_guess_ip_for_via (int family, char *address, int size) { SOCKET sock; SOCKADDR_STORAGE local_addr; int local_addr_len; struct addrinfo *addrf; address[0] = '\0'; sock = socket (family, SOCK_DGRAM, 0); if (family == AF_INET) { getaddrinfo (eXosip.ipv4_for_gateway, NULL, NULL, &addrf); } else if (family == AF_INET6) { getaddrinfo (eXosip.ipv6_for_gateway, NULL, NULL, &addrf); } if (addrf == NULL) { closesocket (sock); snprintf (address, size, (family == AF_INET) ? "127.0.0.1" : "::1"); return OSIP_NO_NETWORK; } if (WSAIoctl (sock, SIO_ROUTING_INTERFACE_QUERY, addrf->ai_addr, addrf->ai_addrlen, &local_addr, sizeof (local_addr), &local_addr_len, NULL, NULL) != 0) { closesocket (sock); freeaddrinfo (addrf); snprintf (address, size, (family == AF_INET) ? "127.0.0.1" : "::1"); return OSIP_NO_NETWORK; } closesocket (sock); freeaddrinfo (addrf); if (getnameinfo ((const struct sockaddr *) &local_addr, local_addr_len, address, size, NULL, 0, NI_NUMERICHOST)) { snprintf (address, size, (family == AF_INET) ? "127.0.0.1" : "::1"); return OSIP_NO_NETWORK; } return OSIP_SUCCESS; } |
通过debug验证和结合eXosip的code,这里得到的地址为环回地址127.0.0.1.不知道得到这个地址有什么用?
下一步是eXosip_init()
eXosip_init()的源code如下:
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 { 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)); } } #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 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 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 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; eXtl_udp.tl_init (); 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 为全局变量,里面定义了一大堆变量。
接着初始化eXosip的两个成员变量,但是不知道这两个初始化的值是从哪里来的
接下来看win32的部分,是用WSAStartup对windows的网络部分进行初始化。
为了在应用程序当中调用任何一个Winsock API函数,首先第一件事情就是必须通过WSAStartup函数完成对Winsock服务的初始化,因此需要调用WSAStartup函数。使用Socket的程序在使用Socket之前必须调用WSAStartup函数。 |
接下来对eXosip结构的user_agent进行初始化。把参数的字符串复制给user_agent,里面的实现实际就是分配内存,然后进行str拷贝的操作。
eXosip.j_stop_ua = 0;这个变量比较重要,通过这个值判断协议栈是否要一直运行
i = osip_list_init (&eXosip.j_transactions);
初始化,用memset设置为0
……
在初始化完eXosip结构的一些变量后,初始化osip结构
i = osip_init (&osip);
osip_set_application_context (osip, &eXosip);
以上这句很有意思,在很多情况下,我们可以学习这个做法。将eXosip的结构设置到osip中进行保存,然后一边会有一个osip_get_application方法来取出这个eXosip结构。也就是说可以在osip的环境中取出exosip,调用exosip的东西。
eXosip_set_callbacks (osip);
设置osip的回调函数,这里很重要。
……
eXtl_udp.tl_init ();
eXtl_tcp.tl_init ();
这两句是搞社么的?(对udp,tcp两个不同的socket进行一些初始化的工作, 在后面通过判断是使用tcp还是udp,来对应open某个socket)
接下来
eXosip_listen_addr
根据udp或者tcp,open上文定义好的socket。
eXosip_register_build_initial_register
构建注册消息。
eXosip_register_send_register
发出注册消息