eX.osip3.0.1在Windows下編譯方法及簡單UA示例 |
[ 2007-2-3 9:37:00 | By: sipot ]
|
說明:
1.以下文章中的osip版本爲3.0.1 2.eXosip版本爲3.0.1 3.編譯環境爲:Windows XP 專業版本+VS 2005 4.示例程序是在http://blog.csdn.net/bat603/中下載,修改而成(原來是在linux下的示例) 5.如要轉載此文章,請說明出處 6.本人也是才接觸SIP(呵呵,不到一週),其中一定有很多不對之處,請指正。 第一步,下載: 到http://www.gnu.org/software/osip/下載最新的osip庫並解壓 到http://savannah.gnu.org/projects/exosip/下載最新的eXsoip庫並解壓 第二步,編譯osip3.0.1: 1.用VS2005打開libosip2-3.0.1/platform/vsnet/osip.sln 2.對osip2和osipparser2項目生成Release DLL 3.其生成的LIB/DLL 位於:libosip2-3.0.1/platform/vsnet/Release DLL/下 第三步,編譯eXosip3.0.1: 1.用VS2005打開libeXosip2-3.0.1/platform/vsnet/eXosip.sln 2.將libosip2-3.0.1/include/osip2目錄COPY到libeXosip2-3.0.1/include/下 3.將libosip2-3.0.1/include/osipparser2目錄COPY到libeXosip2-3.0.1/include/下 4.在libeXosip2-3.0.1目錄下新建lib目錄 5.將“第二步”中生成的libosip2-3.0.1/platform/vsnet/Release DLL/osip2.lib文件COPY到libeXosip2-3.0.1/lib目錄下 6.將“第二步”中生成的libosip2-3.0.1/platform/vsnet/Release DLL/osipparser2.lib文件COPY到libeXosip2-3.0.1/lib目錄下 7.修改項目屬性,新增Dnsapi.lib Iphlpapi.lib Ws2_32.lib osip2.lib osipparser2.lib庫輸入 8.修改項目屬性,新增庫目錄../../lib 9.修改項目的輸出爲.DLL,默認爲.lib 10.編譯Relase DLL 11.其生成的LIB/DLL 位於:libeXosip2-3.0.1/platform/vsnet/Release/下 第四步,編譯示例程序: 將以下程序作爲UAS.CPP保存
CODE:
// UAS.cpp : 定義控制檯應用程序的入口點。
// #i nclude <eXosip2/eXosip.h> #i nclude <stdio.h> #i nclude <stdlib.h> #i nclude <Winsock2.h> /* #i nclude <netinet/in.h> #i nclude <sys/socket.h> #i nclude <sys/types.h>*/ #pragma comment(lib, "osip2.lib") #pragma comment(lib, "osipparser2.lib") #pragma comment(lib, "eXosip.lib") #pragma comment(lib, "Iphlpapi.lib") #pragma comment(lib, "Dnsapi.lib") #pragma comment(lib, "ws2_32.lib") int main (int argc, char *argv[]) { eXosip_event_t *je = NULL; osip_message_t *ack = NULL; osip_message_t *invite = NULL; osip_message_t *answer = NULL; sdp_message_t *remote_sdp = NULL; int call_id, dialog_id; int i,j; int id; char *sour_call = "sip:[email protected]"; char *dest_call = "sip:[email protected]:5061";//client ip char command; char tmp[4096]; char localip[128]; int pos = 0; //初始化sip i = eXosip_init (); if (i != 0) { printf ("Can't initialize eXosip!/n"); return -1; } else { printf ("eXosip_init successfully!/n"); } i = eXosip_listen_addr (IPPROTO_UDP, NULL, 5060, AF_INET, 0); if (i != 0) { eXosip_quit (); fprintf (stderr, "eXosip_listen_addr error!/nCouldn't initialize transport layer!/n"); } for(;;) { //偵聽是否有消息到來 je = eXosip_event_wait (0,50); //協議棧帶有此語句,具體作用未知 eXosip_lock (); eXosip_default_action (je); eXosip_automatic_refresh (); eXosip_unlock (); if (je == NULL)//沒有接收到消息 continue; // printf ("the cid is %s, did is %s/n", je->did, je->cid); switch (je->type) { case EXOSIP_MESSAGE_NEW://新的消息到來 printf (" EXOSIP_MESSAGE_NEW!/n"); if (MSG_IS_MESSAGE (je->request))//如果接受到的消息類型是MESSAGE { { osip_body_t *body; osip_message_get_body (je->request, 0, &body); printf ("I get the msg is: %s/n", body->body); //printf ("the cid is %s, did is %s/n", je->did, je->cid); } //按照規則,需要回復OK信息 eXosip_message_build_answer (je->tid, 200,&answer); eXosip_message_send_answer (je->tid, 200,answer); } break; case EXOSIP_CALL_INVITE: //得到接收到消息的具體信息 printf ("Received a INVITE msg from %s:%s, UserName is %s, password is %s/n",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=0/r/n" "o=anonymous 0 0 IN IP4 0.0.0.0/r/n" "t=1 10/r/n" "a=username:rainfish/r/n" "a=password:123/r/n"); //設置回覆的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 : %s/n", at->a_att_field, at->a_att_value);//這裏解釋了爲什麼在SDP消息體中屬性a裏面存放必須是兩列 pos ++; } break; case EXOSIP_CALL_ACK: printf ("ACK recieved!/n"); // printf ("the cid is %s, did is %s/n", je->did, je->cid); break; case EXOSIP_CALL_CLOSED: printf ("the remote hold the session!/n"); // eXosip_call_build_ack(dialog_id, &ack); //eXosip_call_send_ack(dialog_id, ack); 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 { eXosip_call_send_answer (je->tid, 200, answer); printf ("bye send 200 over!/n"); } break; case EXOSIP_CALL_MESSAGE_NEW://至於該類型和EXOSIP_MESSAGE_NEW的區別,源代碼這麼解釋的 /* // request related events within calls (except INVITE) EXOSIP_CALL_MESSAGE_NEW, < announce new incoming request. // response received for request outside calls EXOSIP_MESSAGE_NEW, < announce new incoming request. 我也不是很明白,理解是:EXOSIP_CALL_MESSAGE_NEW是一個呼叫中的新的消息到來,比如ring trying都算,所以在接受到後必須判斷 該消息類型,EXOSIP_MESSAGE_NEW而是表示不是呼叫內的消息到來。 該解釋有不妥地方,僅供參考。 */ printf(" EXOSIP_CALL_MESSAGE_NEW/n"); if (MSG_IS_INFO(je->request) ) //如果傳輸的是INFO方法 { eXosip_lock (); i = eXosip_call_build_answer (je->tid, 200, &answer); if (i == 0) { eXosip_call_send_answer (je->tid, 200, answer); } eXosip_unlock (); { osip_body_t *body; osip_message_get_body (je->request, 0, &body); printf ("the body is %s/n", body->body); } } break; default: printf ("Could not parse the msg!/n"); } } } 將以下程序作爲UAC.CPP保存
CODE:
// UAC.cpp : 定義控制檯應用程序的入口點。
// #i nclude <eXosip2/eXosip.h> #i nclude <stdio.h> #i nclude <stdlib.h> #i nclude <Winsock2.h> /* #i nclude <netinet/in.h> #i nclude <sys/socket.h> #i nclude <sys/types.h>*/ #pragma comment(lib, "osip2.lib") #pragma comment(lib, "osipparser2.lib") #pragma comment(lib, "eXosip.lib") #pragma comment(lib, "Iphlpapi.lib") #pragma comment(lib, "Dnsapi.lib") #pragma comment(lib, "ws2_32.lib") int main (int argc, char *argv[]) { eXosip_event_t *je; osip_message_t *reg = NULL; osip_message_t *invite = NULL; osip_message_t *ack = NULL; osip_message_t *info = NULL; osip_message_t *message = NULL; int call_id, dialog_id; int i,flag; int flag1 = 1; int id; char *identity = "sip:[email protected]"; char *registerer = "sip:10.16.79.24:5060";//server ip char *source_call = "sip:[email protected]"; char *dest_call = "sip:[email protected]:5060";//server ip char command; char tmp[4096]; char localip[128]; printf("r 向服務器註冊/n/n"); printf("c 取消註冊/n/n"); printf("i 發起呼叫請求/n/n"); printf("h 掛斷/n/n"); printf("q 退出程序/n/n"); printf("s 執行方法INFO/n/n"); printf("m 執行方法MESSAGE/n/n"); //初始化 i = eXosip_init (); if (i != 0) { printf ("Couldn't initialize eXosip!/n"); return -1; } else { printf ("eXosip_init successfully!/n"); } i = eXosip_listen_addr (IPPROTO_UDP, NULL, 5061, AF_INET, 0); if (i != 0) { eXosip_quit (); fprintf (stderr, "Couldn't initialize transport layer!/n"); return -1; } flag = 1; while (flag) { printf ("please input the comand:/n"); scanf ("%c", &command); getchar (); switch (command) { case 'r': printf ("This modal isn't commpleted!/n"); break; case 'i':/* INVITE */ i = eXosip_call_build_initial_invite (&invite, dest_call, source_call, NULL, "This si a call for a conversation"); if (i != 0) { printf ("Intial INVITE failed!/n"); break; } //符合SDP格式,其中屬性a是自定義格式,也就是說可以存放自己的信息,但是隻能是兩列,比如帳戶信息 //但是經測試,格式:v o t必不可少,原因未知,估計是協議棧在傳輸時需要檢查的 snprintf (tmp, 4096, "v=0/r/n" "o=anonymous 0 0 IN IP4 0.0.0.0/r/n" "t=1 10/r/n" "a=username:rainfish/r/n" "a=password:123/r/n"); osip_message_set_body (invite, tmp, strlen(tmp)); osip_message_set_content_type (invite, "application/sdp"); eXosip_lock (); i = eXosip_call_send_initial_invite (invite); eXosip_unlock (); flag1 = 1; while (flag1) { je = eXosip_event_wait (0, 200); if (je == NULL) { printf ("No response or the time is over!/n"); break; } switch (je->type) { case EXOSIP_CALL_INVITE: printf ("a new invite reveived!/n"); break; case EXOSIP_CALL_PROCEEDING: printf ("proceeding!/n"); break; case EXOSIP_CALL_RINGING: printf ("ringing!/n"); // call_id = je->cid; // dialog_id = je->did; printf ("call_id is %d, dialog_id is %d /n", je->cid, je->did); break; case EXOSIP_CALL_ANSWERED: printf ("ok! connected!/n"); call_id = je->cid; dialog_id = je->did; printf ("call_id is %d, dialog_id is %d /n", je->cid, je->did); eXosip_call_build_ack (je->did, &ack); eXosip_call_send_ack (je->did, ack); flag1 = 0; break; case EXOSIP_CALL_CLOSED: printf ("the other sid closed!/n"); break; case EXOSIP_CALL_ACK: printf ("ACK received!/n"); break; default: printf ("other response!/n"); break; } eXosip_event_free (je); } break; case 'h': printf ("Holded !/n"); eXosip_lock (); eXosip_call_terminate (call_id, dialog_id); eXosip_unlock (); break; case 'c': printf ("This modal isn't commpleted!/n"); break; case 's': //傳輸INFO方法 eXosip_call_build_info (dialog_id, &info); snprintf (tmp , 4096, "hello,rainfish"); osip_message_set_body (info, tmp, strlen(tmp)); //格式可以任意設定,text/plain代表文本信息 osip_message_set_content_type (info, "text/plain"); eXosip_call_send_request (dialog_id, info); break; case 'm': //傳輸MESSAGE方法,也就是即時消息,和INFO方法相比,我認爲主要區別,是MESSAGE不用建立連接,直接傳輸信息,而INFO必須 //在建立INVITE的基礎上傳輸。 printf ("the mothed :MESSAGE/n"); eXosip_message_build_request (&message, "MESSAGE", dest_call, source_call, NULL); snprintf (tmp, 4096, "hellor rainfish"); osip_message_set_body (message, tmp, strlen(tmp)); //假設格式是xml osip_message_set_content_type (message, "text/xml"); eXosip_message_send_request (message); break; case 'q': eXosip_quit (); printf ("Exit the setup!/n"); flag = 0; break; } } return (0); } 編譯這兩個程序,需要注意的是:osip/eXosip的頭文件路徑和第二步/第三步生成出來的LIB庫路徑應設置對,就OK 第五步,運行示例程序: 1.將第二步/第三步生成出來的三個DLL文件COPY到程序運行目錄 2.現在可以運行了! |