從網站上看到了這樣的一篇博文 :Windows下編譯eXosip、osip,以及UAC和UAS的例子 (連接:http://www.cnblogs.com/dyllove98/archive/2013/06/25/3155427.html)html
以爲對學習sip的初學者,包括我,都是頗有幫助的。可是那是在window下的編譯,我在這裏稍微改了一下,讓它支持在linux下編譯測試運行經過。linux
咱們這裏使用庫的版本:libosip2-3.6.0.tar,libeXosip2-3.6.0.tar,你們能夠本身進入正面的連接去下載。shell
osip: http://ftp.twaren.net/Unix/NonGNU//osip/libosip2-3.6.0.tar.gz
eXosip: http://download.savannah.gnu.org/releases/exosip/libeXosip2-3.6.0.tar.gz服務器
一、解壓libosip2-3.6.0.tar ,好比解壓目錄爲 /usr/local/src/,
#tar zxvf libosip2-3.6.0.tar -C /usr/local/srcsession
編譯該lib庫:
#./configure
#make
#make installapp
二、同理編譯libeXosip2
注意最後要更新庫,不然在程序執行時,可能會提示找不到庫,編譯後的庫文件及頭文件會默認放在/usr/local目錄下:
#ldconfigide
三、編譯代碼uac.c 和 uas.c
#gcc uac.c -o uac -losip2 -leXosip2 -lpthread
#gcc uas.c -o uas -losip2 -leXosip2 -lpthreadpost
四、測試運行uas 和 uac,最好打開兩個shell來運行
#./uas
#./uac
注意:若是在運行過程當中提示找不到libosip2.so.6等相似的提示,說明osip動態庫的路徑可能尚未包含進去,可使用下面的命令手動包含動態庫的路徑
#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib學習
代碼uac.c測試
1 #include <eXosip2/eXosip.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <stdarg.h> 5 #include <netinet/in.h> 6 //#include <winsock2.h> 7 8 int main(int argc,char *argv[]) 9 { 10 11 struct eXosip_t *context_eXosip; 12 13 eXosip_event_t *je; 14 osip_message_t *reg=NULL; 15 osip_message_t *invite=NULL; 16 osip_message_t *ack=NULL; 17 osip_message_t *info=NULL; 18 osip_message_t *message=NULL; 19 20 int call_id,dialog_id; 21 int i,flag; 22 int flag1=1; 23 24 char *identity="sip:140@127.0.0.1"; //UAC1,端口是15060 25 char *registar="sip:133@127.0.0.1:15061"; //UAS,端口是15061 26 char *source_call="sip:140@127.0.0.1"; 27 char *dest_call="sip:133@127.0.0.1:15061"; 28 //identify和register這一組地址是和source和destination地址相同的 29 //在這個例子中,uac和uas通訊,則source就是本身的地址,而目的地址就是uac1的地址 30 char command; 31 char tmp[4096]; 32 33 printf("r 向服務器註冊\n\n"); 34 printf("c 取消註冊\n\n"); 35 printf("i 發起呼叫請求\n\n"); 36 printf("h 掛斷\n\n"); 37 printf("q 推出程序\n\n"); 38 printf("s 執行方法INFO\n\n"); 39 printf("m 執行方法MESSAGE\n\n"); 40 41 //初始化 42 i=eXosip_init(); 43 44 if(i!=0) 45 { 46 printf("Couldn't initialize eXosip!\n"); 47 return -1; 48 } 49 else 50 { 51 printf("eXosip_init successfully!\n"); 52 } 53 54 //綁定uac本身的端口15060,並進行端口監聽 55 i=eXosip_listen_addr(IPPROTO_UDP,NULL,15060,AF_INET,0); 56 if(i!=0) 57 { 58 eXosip_quit(); 59 fprintf(stderr,"Couldn't initialize transport layer!\n"); 60 return -1; 61 } 62 flag=1; 63 64 while(flag) 65 { 66 //輸入命令 67 printf("Please input the command:\n"); 68 scanf("%c",&command); 69 getchar(); 70 71 switch(command) 72 { 73 case 'r': 74 printf("This modal is not completed!\n"); 75 break; 76 case 'i'://INVITE,發起呼叫請求 77 i=eXosip_call_build_initial_invite(&invite,dest_call,source_call,NULL,"This is a call for conversation"); 78 if(i!=0) 79 { 80 printf("Initial INVITE failed!\n"); 81 break; 82 } 83 //符合SDP格式,其中屬性a是自定義格式,也就是說能夠存放本身的信息, 84 //可是隻能有兩列,好比賬戶信息 85 //可是通過測試,格式vot必不可少,緣由未知,估計是協議棧在傳輸時須要檢查的 86 snprintf(tmp,4096, 87 "v=0\r\n" 88 "o=anonymous 0 0 IN IP4 0.0.0.0\r\n" 89 "t=1 10\r\n" 90 "a=username:rainfish\r\n" 91 "a=password:123\r\n"); 92 93 osip_message_set_body(invite,tmp,strlen(tmp)); 94 osip_message_set_content_type(invite,"application/sdp"); 95 96 eXosip_lock(); 97 i=eXosip_call_send_initial_invite(invite); //invite SIP INVITE message to send 98 eXosip_unlock(); 99 100 //發送了INVITE消息,等待應答 101 flag1=1; 102 while(flag1) 103 { 104 je=eXosip_event_wait(0,200); //Wait for an eXosip event 105 //(超時時間秒,超時時間毫秒) 106 if(je==NULL) 107 { 108 printf("No response or the time is over!\n"); 109 break; 110 } 111 switch(je->type) //可能會到來的事件類型 112 { 113 case EXOSIP_CALL_INVITE: //收到一個INVITE請求 114 printf("a new invite received!\n"); 115 break; 116 case EXOSIP_CALL_PROCEEDING: //收到100 trying消息,表示請求正在處理中 117 printf("proceeding!\n"); 118 break; 119 case EXOSIP_CALL_RINGING: //收到180 Ringing應答,表示接收到INVITE請求的UAS正在向被叫用戶振鈴 120 printf("ringing!\n"); 121 printf("call_id is %d,dialog_id is %d \n",je->cid,je->did); 122 break; 123 case EXOSIP_CALL_ANSWERED: //收到200 OK,表示請求已經被成功接受,用戶應答 124 printf("ok!connected!\n"); 125 call_id=je->cid; 126 dialog_id=je->did; 127 printf("call_id is %d,dialog_id is %d \n",je->cid,je->did); 128 129 //回送ack應答消息 130 eXosip_call_build_ack(je->did,&ack); 131 eXosip_call_send_ack(je->did,ack); 132 flag1=0; //推出While循環 133 break; 134 case EXOSIP_CALL_CLOSED: //a BYE was received for this call 135 printf("the other sid closed!\n"); 136 break; 137 case EXOSIP_CALL_ACK: //ACK received for 200ok to INVITE 138 printf("ACK received!\n"); 139 break; 140 default: //收到其餘應答 141 printf("other response!\n"); 142 break; 143 } 144 eXosip_event_free(je); //Free ressource in an eXosip event 145 } 146 break; 147 148 case 'h': //掛斷 149 printf("Holded!\n"); 150 151 eXosip_lock(); 152 eXosip_call_terminate(call_id,dialog_id); 153 eXosip_unlock(); 154 break; 155 156 case 'c': 157 printf("This modal is not commpleted!\n"); 158 break; 159 160 case 's': //傳輸INFO方法 161 eXosip_call_build_info(dialog_id,&info); 162 snprintf(tmp,4096,"\nThis is a sip message(Method:INFO)"); 163 osip_message_set_body(info,tmp,strlen(tmp)); 164 //格式能夠任意設定,text/plain表明文本信息; 165 osip_message_set_content_type(info,"text/plain"); 166 eXosip_call_send_request(dialog_id,info); 167 break; 168 169 case 'm': 170 //傳輸MESSAGE方法,也就是即時消息,和INFO方法相比,我認爲主要區別是: 171 //MESSAGE不用創建鏈接,直接傳輸信息,而INFO消息必須在創建INVITE的基礎上傳輸 172 printf("the method : MESSAGE\n"); 173 eXosip_message_build_request(&message,"MESSAGE",dest_call,source_call,NULL); 174 //內容,方法, to ,from ,route 175 snprintf(tmp,4096,"This is a sip message(Method:MESSAGE)"); 176 osip_message_set_body(message,tmp,strlen(tmp)); 177 //假設格式是xml 178 osip_message_set_content_type(message,"text/xml"); 179 eXosip_message_send_request(message); 180 break; 181 182 case 'q': 183 eXosip_quit(); 184 printf("Exit the setup!\n"); 185 flag=0; 186 break; 187 } 188 } 189 190 return(0); 191 }
代碼uas.c
1 # include <eXosip2/eXosip.h> 2 # include <stdio.h> 3 # include <stdlib.h> 4 # include <stdarg.h> 5 # include <netinet/in.h> 6 7 //# include <Winsock2.h> 8 9 10 int main (int argc, char *argv[]) 11 { 12 eXosip_event_t *je = NULL; 13 osip_message_t *ack = NULL; 14 osip_message_t *invite = NULL; 15 osip_message_t *answer = NULL; 16 sdp_message_t *remote_sdp = NULL; 17 int call_id, dialog_id; 18 int i,j; 19 int id; 20 char *sour_call = "sip:140@127.0.0.1"; 21 char *dest_call = "sip:133@127.0.0.1:15060";//client ip 22 char command; 23 char tmp[4096]; 24 char localip[128]; 25 int pos = 0; 26 //初始化sip 27 i = eXosip_init (); 28 if (i != 0) 29 { 30 printf ("Can't initialize eXosip!\n"); 31 return -1; 32 } 33 else 34 { 35 printf ("eXosip_init successfully!\n"); 36 } 37 i = eXosip_listen_addr (IPPROTO_UDP, NULL, 15061, AF_INET, 0); 38 if (i != 0) 39 { 40 eXosip_quit (); 41 fprintf (stderr, "eXosip_listen_addr error!\nCouldn't initialize transport layer!\n"); 42 } 43 for(;;) 44 { 45 //偵聽是否有消息到來 46 je = eXosip_event_wait (0,50); 47 //協議棧帶有此語句,具體做用未知 48 eXosip_lock (); 49 eXosip_default_action (je); 50 eXosip_automatic_refresh (); 51 eXosip_unlock (); 52 if (je == NULL)//沒有接收到消息 53 continue; 54 // printf ("the cid is %s, did is %s/n", je->did, je->cid); 55 switch (je->type) 56 { 57 case EXOSIP_MESSAGE_NEW://新的消息到來 58 printf (" EXOSIP_MESSAGE_NEW!\n"); 59 if (MSG_IS_MESSAGE (je->request))//若是接受到的消息類型是MESSAGE 60 { 61 { 62 osip_body_t *body; 63 osip_message_get_body (je->request, 0, &body); 64 printf ("I get the msg is: %s\n", body->body); 65 //printf ("the cid is %s, did is %s/n", je->did, je->cid); 66 } 67 //按照規則,須要回覆OK信息 68 eXosip_message_build_answer (je->tid, 200,&answer); 69 eXosip_message_send_answer (je->tid, 200,answer); 70 } 71 break; 72 case EXOSIP_CALL_INVITE: 73 //獲得接收到消息的具體信息 74 printf ("Received a INVITE msg from %s:%s, UserName is %s, password is %s\n",je->request->req_uri->host, 75 je->request->req_uri->port, je->request->req_uri->username, je->request->req_uri->password); 76 //獲得消息體,認爲該消息就是SDP格式. 77 remote_sdp = eXosip_get_remote_sdp (je->did); 78 call_id = je->cid; 79 dialog_id = je->did; 80 81 eXosip_lock (); 82 eXosip_call_send_answer (je->tid, 180, NULL); 83 i = eXosip_call_build_answer (je->tid, 200, &answer); 84 if (i != 0) 85 { 86 printf ("This request msg is invalid!Cann't response!\n"); 87 eXosip_call_send_answer (je->tid, 400, NULL); 88 } 89 else 90 { 91 snprintf (tmp, 4096, 92 "v=0\r\n" 93 "o=anonymous 0 0 IN IP4 0.0.0.0\r\n" 94 "t=1 10\r\n" 95 "a=username:rainfish\r\n" 96 "a=password:123\r\n"); 97 98 //設置回覆的SDP消息體,下一步計劃分析消息體 99 //沒有分析消息體,直接回復原來的消息,這一塊作的很差。 100 osip_message_set_body (answer, tmp, strlen(tmp)); 101 osip_message_set_content_type (answer, "application/sdp"); 102 103 eXosip_call_send_answer (je->tid, 200, answer); 104 printf ("send 200 over!\n"); 105 } 106 eXosip_unlock (); 107 108 //顯示出在sdp消息體中的attribute 的內容,裏面計劃存放咱們的信息 109 printf ("the INFO is :\n"); 110 while (!osip_list_eol ( &(remote_sdp->a_attributes), pos)) 111 { 112 sdp_attribute_t *at; 113 114 at = (sdp_attribute_t *) osip_list_get ( &remote_sdp->a_attributes, pos); 115 printf ("%s : %s\n", at->a_att_field, at->a_att_value);//這裏解釋了爲何在SDP消息體中屬性a裏面存放必須是兩列 116 117 pos ++; 118 } 119 break; 120 case EXOSIP_CALL_ACK: 121 printf ("ACK recieved!\n"); 122 // printf ("the cid is %s, did is %s/n", je->did, je->cid); 123 break; 124 case EXOSIP_CALL_CLOSED: 125 printf ("the remote hold the session!\n"); 126 // eXosip_call_build_ack(dialog_id, &ack); 127 //eXosip_call_send_ack(dialog_id, ack); 128 i = eXosip_call_build_answer (je->tid, 200, &answer); 129 if (i != 0) 130 { 131 printf ("This request msg is invalid!Cann't response!\n"); 132 eXosip_call_send_answer (je->tid, 400, NULL); 133 134 } 135 else 136 { 137 eXosip_call_send_answer (je->tid, 200, answer); 138 printf ("bye send 200 over!\n"); 139 } 140 break; 141 case EXOSIP_CALL_MESSAGE_NEW://至於該類型和EXOSIP_MESSAGE_NEW的區別,源代碼這麼解釋的 142 /* 143 // request related events within calls (except INVITE) 144 EXOSIP_CALL_MESSAGE_NEW, < announce new incoming request. 145 // response received for request outside calls 146 EXOSIP_MESSAGE_NEW, < announce new incoming request. 147 我也不是很明白,理解是:EXOSIP_CALL_MESSAGE_NEW是一個呼叫中的新的消息到來,好比ring trying都算,因此在接受到後必須判斷 148 該消息類型,EXOSIP_MESSAGE_NEW而是表示不是呼叫內的消息到來。 149 該解釋有不妥地方,僅供參考。 150 */ 151 printf(" EXOSIP_CALL_MESSAGE_NEW\n"); 152 if (MSG_IS_INFO(je->request) ) //若是傳輸的是INFO方法 153 { 154 eXosip_lock (); 155 i = eXosip_call_build_answer (je->tid, 200, &answer); 156 if (i == 0) 157 { 158 eXosip_call_send_answer (je->tid, 200, answer); 159 } 160 eXosip_unlock (); 161 { 162 osip_body_t *body; 163 osip_message_get_body (je->request, 0, &body); 164 printf ("the body is %s\n", body->body); 165 } 166 } 167 break; 168 default: 169 printf ("Could not parse the msg!\n"); 170 } 171 } 172 }
運行截圖:
uac運行結果:
uas運行結果: