程序会在最后面贴出。
--------------------------------------------------------------------------------------------
程序开始没别的说,根据官方指南必须要进行eXosip的初始化,
int i;
TRACE_INITIALIZE (6,stdout);
i=eXosip_init();
if (i!=0)
return -1;
i = eXosip_listen_addr (IPPROTO_UDP, NULL,5060, AF_INET, 0);
if (i!=0)
{
eXosip_quit();
fprintf (stderr, "could not initialize transport layern");
return -1;
}
----------------------------------------------------------------------------------------
解析:
1、Int eXosip_init (void):初始化扩展的oSIP库
2、int eXosip_listen_addr(inttransport,
const char *addr,
intport,
intfamily,
intsecure
)
监听特定的socket
参数:
transportUDP时为IPPROTO_UDP.(TCP/TLS会在后面版本完善)
addr需要绑定的地址.(NULL:对于所有接口)
port监听的端口.(0是对于一个随机的端口)本程序设为了5060
familyIP协议族 (AF_INET 或者AF_INET6).
secure0:UDP 或者 TCP, 1:TLS(with TCP).
3、TRACE_INITIALIZE (6, stdout):待查,此过程应该是为了初始化osiptrace,可能在osip2的介绍中能查找
----------------------------------------------------------------------------------------
接下来应该需要从eXosip2协议中得到eXosip事件
eXosip_event_t *je;
for ( ; ; )
{
je = eXosip_event_wait (0, 50);
eXosip_lock();
eXosip_automatic_action ();
eXosip_unlock();
if (je == NULL)
break;
if (je->type == EXOSIP_CALL_NEW)
{
....
....
}
else if (je->type == EXOSIP_CALL_ACK)
{
....
....
}
else if (je->type == EXOSIP_CALL_ANSWERED)
{
....
....
}
else .....
....
....eXosip_event_free(je);
----------------------------------------------------------------------------------------
解析:
1.eXosip_event_t数据结构:在eXosip.h中有语句typedef structeXosip_event eXosip_event_t为现有类型创建一个新的名称,表明eXosip_event_t实际就是结构体eXosip_event,在官方DataStructures中有如下说明:
eXosip_event_type_t type ——事件类型
char textinfo [256] ——事件的文字描述
void * external_reference ——待查,另外void*是什么意思?
osip_message_t* request ——目前transaction中的request
osip_message_t* response ——目前transaction中的last response
osip_message_t* ack ——目前transaction中的ack
int tid——transaction的识别id
int did——SIPdialog的识别id
int rid ——注册的识别id
int cid——SIP calls的识别id(but multipledialogs!)
int sid ——unique id for outgoing subscriptions
int nid ——unique idforincomingsubscriptions
int ss_status——current Subscription-State forsubscription
int ss_reason——current Reason status forsubscription
下面对事件类型再进行描述,定义下述枚举变量:
enum eXosip_event_type{
EXOSIP_REGISTRATION_NEW, ——宣称新的注册
EXOSIP_REGISTRATION_SUCCESS, ——用户成功注册
EXOSIP_REGISTRATION_FAILURE, ——用户没有注册
EXOSIP_REGISTRATION_REFRESHED, ——注册已经更新
EXOSIP_REGISTRATION_TERMINATED, ——UA is notregistred any more
EXOSIP_CALL_INVITE, ——宣布新的呼叫
EXOSIP_CALL_REINVITE, ——announce a new INVITEwithin call
EXOSIP_CALL_NOANSWER, ——announce no answerwithin the timeout
EXOSIP_CALL_PROCEEDING,——announce processing bya remote app
EXOSIP_CALL_RINGING,
EXOSIP_CALL_ANSWERED,
EXOSIP_CALL_REDIRECTED,
EXOSIP_CALL_REQUESTFAILURE,
EXOSIP_CALL_SERVERFAILURE,
EXOSIP_CALL_GLOBALFAILURE,
EXOSIP_CALL_ACK,
EXOSIP_CALL_CANCELLED,
EXOSIP_CALL_TIMEOUT,
EXOSIP_CALL_MESSAGE_NEW,
EXOSIP_CALL_MESSAGE_PROCEEDING,
EXOSIP_CALL_MESSAGE_ANSWERED,
EXOSIP_CALL_MESSAGE_REDIRECTED,
EXOSIP_CALL_MESSAGE_REQUESTFAILURE,
EXOSIP_CALL_MESSAGE_SERVERFAILURE,
EXOSIP_CALL_MESSAGE_GLOBALFAILURE,
EXOSIP_CALL_CLOSED,
EXOSIP_CALL_RELEASED,
EXOSIP_MESSAGE_NEW,
EXOSIP_MESSAGE_PROCEEDING,
EXOSIP_MESSAGE_ANSWERED,
EXOSIP_MESSAGE_REDIRECTED,
EXOSIP_MESSAGE_REQUESTFAILURE,
EXOSIP_MESSAGE_SERVERFAILURE,
EXOSIP_MESSAGE_GLOBALFAILURE,
EXOSIP_SUBSCRIPTION_UPDATE,
EXOSIP_SUBSCRIPTION_CLOSED,
EXOSIP_SUBSCRIPTION_NOANSWER,
EXOSIP_SUBSCRIPTION_PROCEEDING,
EXOSIP_SUBSCRIPTION_ANSWERED,
EXOSIP_SUBSCRIPTION_REDIRECTED,
EXOSIP_SUBSCRIPTION_REQUESTFAILURE,
EXOSIP_SUBSCRIPTION_SERVERFAILURE,
EXOSIP_SUBSCRIPTION_GLOBALFAILURE,
EXOSIP_SUBSCRIPTION_NOTIFY,
EXOSIP_SUBSCRIPTION_RELEASED,
EXOSIP_IN_SUBSCRIPTION_NEW,
EXOSIP_IN_SUBSCRIPTION_RELEASED,
EXOSIP_NOTIFICATION_NOANSWER,
EXOSIP_NOTIFICATION_PROCEEDING,
EXOSIP_NOTIFICATION_ANSWERED,
EXOSIP_NOTIFICATION_REDIRECTED,
EXOSIP_NOTIFICATION_REQUESTFAILURE,
EXOSIP_NOTIFICATION_SERVERFAILURE,
EXOSIP_NOTIFICATION_GLOBALFAILURE,
EXOSIP_EVENT_COUNT
}
2、eXosip_event_wait:等待一个eXosip事件,timeout的秒数使用第一个参数,微秒使用第二个参数。
3、 eXosip_lock();待查:原句为un/Lock the eXtented oSIPlibrary.难道是为了锁定使用Osip库?有说是为了同步,但是不懂。
eXosip_unlock();
eXosip_automatic_action ();待查:Initiate some automaticactions:Retry with credentials upon reception of 401/407. RefreshREGISTER and SUBSCRIBE before the expiration delay. Retry withContact header upon reception of 3xx request.
----------------------------------------------------------------------------------------
下面完善那个case,当然,这里由于篇幅,只给出我们UAC发过来有响应的部分:
case EXOSIP_CALL_INVITE:
//得到接收到消息的具体信息
printf("Received a INVITE msg from %s:%s, UserName is %s, password is%sn",je>request->req_uri->host,
je->request->req_uri->port,je->request->req_uri->username,je->request->req_uri->password);
//得到消息体,认为该消息就是SDP格式.
remote_sdp = eXosip_get_remote_sdp (je->did);
call_id = je->cid;
dialog_id = je->did;
eXosip_lock ();
eXosip_call_send_answer (je->tid, 180, NULL);
i = eXosip_call_build_answer (je->tid, 200,&answer);
if (i != 0)
{
printf ("This request msg is invalid!Cann't response!n");
eXosip_call_send_answer (je->tid, 400, NULL);
}
else
{
snprintf (tmp, 4096,
"v=0rn"
"o=anonymous 0 0 IN IP4 0.0.0.0rn"
"t=1 10rn"
"a=username:rainfishrn"
"a=password:123rn");
//设置回复的SDP消息体,下一步计划分析消息体
//没有分析消息体,直接回复原来的消息,这一块做的不好。
osip_message_set_body (answer, tmp, strlen(tmp));
osip_message_set_content_type (answer, "application/sdp");
eXosip_call_send_answer (je->tid, 200,answer);
printf ("send 200 over!n");
}
eXosip_unlock ();
//显示出在sdp消息体中的attribute 的内容,里面计划存放我们的信息
printf ("the INFO is :n");
while (!osip_list_eol (&(remote_sdp->a_attributes),pos))
{
sdp_attribute_t *at;
at = (sdp_attribute_t *) osip_list_get (&remote_sdp->a_attributes,pos);
printf ("%s : %sn", at->a_att_field,at->a_att_value);//这里解释了为什么在SDP消息体中属性a里面存放必须是两列
pos ++;
}
break;
----------------------------------------------------------------------------------------
看到这里已经无力吐槽了,电脑待机回寝室吧。
继续。。。。
插入>>今天开会老师透露了好消息,希望能找到专业人士给我们培训一下,毕竟这样在电脑前单干效率太低,希望能早点到位;另外今天也找到对osip各处有解释的网站:http://www.gnu.org/software/osip/doc/html/structosip__message.html#o15
继续正文:
1、je->request为osip_message_t的指针,其中osip_message_t结构如下:
char * sip_version
osip_uri_t * req_uri
char * sip_method
int status_code
char * reason_phrase
osip_list_t * accepts
osip_list_t * accept_encodings
osip_list_t * accept_languages
osip_list_t * alert_infos
osip_list_t * allows
osip_list_t * authentication_infos
osip_list_t * authorizations
osip_call_id_t * call_id
osip_list_t * call_infos
osip_list_t * contacts
osip_list_t * content_dispositions
osip_list_t * content_encodings
osip_content_length_t * content_length
osip_content_type_t * content_type
osip_cseq_t * cseq
osip_list_t * error_infos
osip_from_t * from
osip_mime_version_t * mime_version
osip_list_t * proxy_authenticates
osip_list_t * proxy_authentication_infos
osip_list_t * proxy_authorizations
osip_list_t * record_routes
osip_list_t * routes
osip_to_t * to
osip_list_t * vias
osip_list_t * www_authenticates
osip_list_t * headers
osip_list_t * bodies
int message_property
char * message
size_t message_length
void * application_data
2、其中osip_uri_t结构中包含下述内容
char * scheme
char * username
char * password
char * host
char * port
osip_list_t * url_params
osip_list_t * url_headers
char * string
3、函数int eXosip_call_build_answer (int tid,
intstatus,
osip_message_t **answer
)
用来对request建立默认的应答
参数说明:
tid:要回复transaction的id号;我认为客户端和服务端的transactionid号应该是一样的。直接从eXosip_event_wait获得的je内容可以得到。
status:状态码,用代码来表示处理请求的一个结果,第一个数字表示应答的类型,接下来两个数字不作为分类使用。
answer:要建立的sip 应答。
4、函数int eXosip_call_send_answer (int tid,
intstatus,
osip_message_t *answer
)
对invite发送应答
参数说明:
tid:transaction的id号;
status:response status if answer is NULL. (not allowed for2XX)
answer:要发送的sip应答。
5、函数sdp_message_t* eXosip_get_remote_sdp (int did )
从最近的call invite中获取SDP body
参数:会话的dialog id
至于sdp_message_t的结构在http://www.gnu.org/software/osip/doc/html/structsdp__message.html,但是我看了也没看出什么花来,而且示例程序中也没有具体使用到这个,所以也就不罗列。
6、函数int osip_message_set_body( osip_message_t *sip,const char * buf,size_tlength)
作用:fill the body of the message
参数:sip The structure to store results.
buf Thepointer to the start of body.
lengthThe length of body;
7、函数int osip_message_set_content_type( osip_message_t * sip,const char * hvalue)
作用:Set the Content-type header.
参数:sip The element to work on.
hvalueThe string describing the element.
8、现在说说程序里的snprintf{char *buffer,size_t count,const char*format}函数,就是把后面的一堆东西放入到buffer里面。count是指最大存储的字符(包含 !!)
需要头文件<stdio.h>,网上查了一下,在Windows下是_snprintf,在Linux下是snprintf,这里就用到三个参数。其实个人觉得也可以用C语言中的strcpy和strcat就可以解决了,而且他们也支持类似strcpy(buffer,"ad""afas""....""....")之类的,也许是为了多系统的兼容性吧,猜想,哈哈。
但是需要注意,上述函数都有个特点,就是在字符串里面输入r相当于ASC ii中的CR(13),n相当于ASCii中的LF(10)。而在DOS和Windows采用换行加回车表示下一行CR+LF,而Unix和Linux采用换行符LF表示下一行。所以查看buffer可以看到,要换行需要用两个符号的空间。
9、函数int osip_list_eol (const osip_list_t * li, intpos)
作用:Check if the end of list isdetected(就是看pos所指是不是list的末尾,个人是这么理解的)
参数:li The element to work on.
pos Theindex of the possible element.
10、函数void* osip_list_get ( const osip_list_t *li,int pos)
作用:Getan element from a list.等下要去看看这里list有什么东西有什么作用
参数:li The element to work on.
pos the index of the element toget.
11、好了,看看这个osip_list结构,就两个参数:
int nb_elt :表中元素的个数
__node_t * node :指向下个元素(感觉就像链表)
12、至于程序中将提出的元素转化成sdp_attribute_t结构
描述:SDP attributedefination:SDP属性定义
参数:char* sdp_attribute::a_att_field: attributefield
char*sdp_attribute::a_att_value: attribute value (optional)
13、在程序中感觉客户端是先直接回复了,在去分析SDP信息,这一点原来程序的注释中也有标明其不足,需要注意。另外分析到现在基本上整个框架就可以出来了,下一步把客户端的程序看了,知道各个用户信息是如何加到我们的结构体中的,SDP里面放的到底是什么信息。就是弄明白何种信息放到何种结构体,这样就可以利用这些结构体来联系各个界面数据库什么的了。希望后面顺利吧^_^~~