———– UAC 代理客户端的代码整理 —————
- /**
- * 一个使用了 osip 和 eXosip 库的 UAC 代理客户端的演示程序
- *
- * - 只是简单的演示了使用了 osip 和 eXosip2 库的 UAC 代理客户端的如下几个功能:
- * * i 发起呼叫 INVITE 请求
- * * h 挂断会话
- * * s 执行方法 INFO
- * * m 执行方法 MESSAGE
- *
- * 编 译:g++ -I/usr/local/include -L/usr/local/lib ua_client.cpp -o ua_client -leXosip2 -losip2 -losipparser2 -lpthread
- *
- */
- #include <osip2/osip_mt.h>
- #include <eXosip2/eXosip.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <iostream>
- #include <string>
- using namespace std;
- 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;
- string strIdentity = "sip:136@133.37.55.136";
- string strRegisterer = "sip:133.37.55.136:5060"; // server ip
- string strSrcCall = "sip:136@133.37.55.136";
- string strDestCall = "sip:136@133.37.55.136:5060"; // server ip
- char command;
- char tmp[4096];
- char localip[128];
- string strHelp = string("\n\t--> 命令字符 功能描述 <--\n\n")
- + "\t\tr 向服务器注册\n"
- + "\t\tc 取消注册\n"
- + "\t\ti 发起呼叫请求\n"
- + "\t\th 挂断\n"
- + "\t\tq 退出程序\n"
- + "\t\ts 执行方法 INFO\n"
- + "\t\tm 执行方法 MESSAGE\n"
- + "\t\te 帮助\n\n";
- cout << strHelp;
- string strMsg;
- i = eXosip_init ();
- if (i != 0)
- {
- cout << "\t--> Couldn't initialize eXosip! <--\n";
- return -1;
- }
- else
- {
- cout << "\t--> eXosip_init successfully! <-- \n\n";
- }
- i = eXosip_listen_addr (IPPROTO_UDP, NULL, 5061, AF_INET, 0);
- if (i != 0)
- {
- eXosip_quit ();
- cerr << "\n\t--> Couldn't initialize transport layer! <-- \n\n";
- return -1;
- }
- flag = 1;
- while (flag)
- {
- cout << "请输入一个命令字符:\t";
- cin >> command;
- switch (command)
- {
- case 'r':
- cout << "\n\t--> This modal isn't commpleted! \n" << endl;
- break;
- case 'i': // 初始化的 INVITE 请求
- i = eXosip_call_build_initial_invite (&invite,
- strDestCall.c_str(),
- strSrcCall.c_str(),
- NULL,
- "This is a call for a conversation");
- if (i != 0)
- {
- cout << "\n --> Intial INVITE failed! <-- \n";
- break;
- }
- // 符合 SDP 格式, 其中属性 a 是自定义格式,也就是说可以存放自己的信息,
- // 但是只能是两列,比如帐户信息
- // 但是经测试,格式: v o t必不可少,原因未知,估计是协议栈在传输时需要检查的
- strMsg = string("v=0\r\n")
- + "o=anonymous 0 0 IN IP4 0.0.0.0\r\n"
- + "t=1 10\r\n"
- + "a=username:bluesea\r\n"
- + "a=password:123456\r\n";
- osip_message_set_body (invite, strMsg.c_str(), strMsg.length());
- 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)
- {
- cout << "\n\t--> No response or the time is over! <--\n" << endl;
- break;
- }
- switch (je->type)
- {
- case EXOSIP_CALL_INVITE:
- cout << "\n\t--> a new invite reveived! <--\n" << endl;
- break;
- // announce processing by a remote app
- case EXOSIP_CALL_PROCEEDING:
- cout << "\n\t--> proceeding! <--\n" << endl;
- break;
- // announce ringback
- case EXOSIP_CALL_RINGING:
- cout << "\n\t--> ringing! <--\n"
- << "\n\tcall_id is " << je->cid
- << ", dialog_id is " << je->did << endl;
- break;
- // 收到请求,表示连接成功,下面发送回复确认
- case EXOSIP_CALL_ANSWERED:
- cout << "\n\t--> ok! connected! <--\n" << endl;
- call_id = je->cid;
- dialog_id = je->did;
- cout << "\n\tcall_id is " << je->cid
- << ", dialog_id is " << je->did << endl;
- eXosip_call_build_ack (je->did, &ack);
- eXosip_call_send_ack (je->did, ack);
- flag1 = 0;
- break;
- case EXOSIP_CALL_CLOSED:
- cout << "\n\t--> the other sid closed! <--\n" << endl;
- break;
- case EXOSIP_CALL_ACK:
- cout << "\n\t--> ACK received! <--\n" << endl;
- break;
- default:
- cout << "\n\t--> other response!\n" <<endl;
- break;
- }
- eXosip_event_free (je);
- }
- break;
- case 'h':
- cout << "\n\t--> Holded ! \n" << endl;
- eXosip_lock ();
- eXosip_call_terminate (call_id, dialog_id);
- eXosip_unlock ();
- break;
- case 'c':
- cout << "\n\t--> This modal isn't commpleted! \n" << endl;
- break;
- case 's':
- // 传输 INFO 方法
- eXosip_call_build_info (dialog_id, &info);
- snprintf (tmp , 4096, "hello,bluesea");
- 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 的基础上传输。
- cout << "\n\t--> the mothed :MESSAGE \n" << endl;
- eXosip_message_build_request (&message,
- "MESSAGE",
- strDestCall.c_str(),
- strSrcCall.c_str(),
- NULL);
- strMsg = "message: hello bluesea!";
- osip_message_set_body (message, strMsg.c_str(), strMsg.length());
- // 假设格式是xml
- osip_message_set_content_type (message, "text/xml");
- eXosip_message_send_request (message);
- break;
- case 'q':
- eXosip_quit ();
- cout << "\n\t--> Exit the setup! \n" << endl;;
- flag = 0;
- break;
- case 'e':
- cout << strHelp << endl;
- break;
- default:
- cout << "\n\t--> 不支持的命令 <--\n" << endl;
- break;
- }
- }
- return 0;
- }
———– UAS 代理服务器端的代码整理 —————
- /**
- * 一个使用了 osip 和 eXosip 库的 UAS 代理服务端的演示程序
- *
- * - 只是简单的演示了使用了 osip 和 eXosip2 库的 UAS 代理服务端的如下几个功能:
- *
- * 编 译:g++ -I/usr/local/include -L/usr/local/lib ua_server.cpp -o ua_server -leXosip2 -losip2 -losipparser2 -lpthread
- *
- */
- #include <eXosip2/eXosip.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <iostream>
- #include <fstream>
- #include <string>
- using namespace std;
- int main()
- {
- 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:136@133.37.55.136";
- char *dest_call = "sip:136@133.37.55.136:5061"; //client ip/port
- char command;
- char tmp[4096];
- char localip[128];
- int pos = 0;
- // 初始化 sip
- i = eXosip_init ();
- if (i != 0)
- {
- cerr << "\n\t--> Can't initialize eXosip!\n";
- return -1;
- }
- else
- {
- cout << "\n\t--> eXosip_init successfully!\n";
- }
- i = eXosip_listen_addr (IPPROTO_UDP, NULL, 5060, AF_INET, 0);
- if (i != 0)
- {
- eXosip_quit ();
- cerr << "\n\t--> eXosip_listen_addr error! Couldn'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;
- }
- switch (je->type)
- {
- case EXOSIP_MESSAGE_NEW: // 新的消息到来
- cout << "\n\t*** EXOSIP_MESSAGE_NEW!\n" << endl;
- if (MSG_IS_MESSAGE (je->request)) // 如果接收到的消息类型是 MESSAGE
- {
- {
- osip_body_t *body;
- osip_message_get_body (je->request, 0, &body);
- cout << "I get the msg is: " << body->body << endl;
- }
- // 按照规则,需要回复 OK 信息
- eXosip_message_build_answer (je->tid, 200, &answer);
- eXosip_message_send_answer (je->tid, 200, answer);
- }
- break;
- case EXOSIP_CALL_INVITE: // INVITE 请求消息
- // 得到接收到消息的具体信息
- cout << "\n\tReceived a INVITE msg from " << je->request->req_uri->host
- << " : " << je->request->req_uri->port
- << ", username is " << je->request->req_uri->username << endl;
- // 得到消息体,认为该消息就是 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)
- {
- cout << "\n\t--> This request msg is invalid! Cann't response!\n" << endl;
- 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);
- cout << "\n\t--> send 200 over!" << endl;
- }
- eXosip_unlock ();
- // 显示出在 sdp 消息体中的 attribute 的内容,里面计划存放我们的信息
- cout << "\n\t--> The INFO is :\n" ;
- while (!osip_list_eol ( &(remote_sdp->a_attributes), pos))
- {
- sdp_attribute_t *at;
- //这里解释了为什么在SDP消息体中属性a里面存放必须是两列
- at = (sdp_attribute_t *) osip_list_get ( &remote_sdp->a_attributes, pos);
- cout << "\n\t" << at->a_att_field
- << " : " << at->a_att_value << endl;
- pos ++;
- }
- break;
- case EXOSIP_CALL_ACK:
- cout << "\n\t--> ACK recieved!\n" << endl;
- // printf ("the cid is %s, did is %s\n", je->did, je->cid);
- break;
- case EXOSIP_CALL_CLOSED:
- cout << "\n\t--> the remote hold the session!\n" << endl;
- // 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);
- cout << "\n\t--> bye send 200 over!\n";
- }
- break;
- case EXOSIP_CALL_MESSAGE_NEW:
- cout << "\n\t*** EXOSIP_CALL_MESSAGE_NEW\n" << endl;
- 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);
- cout << "the body is " << body->body << endl;
- }
- }
- break;
- default:
- cout << "\n\t--> Could not parse the msg!\n" << endl;
- }
- }
- return 0;
- }