📄 sipua.c
字号:
sip_rc = sip_call_evt_subscribe/*此例程发送SUBSCRIBE请求,此例程比较复杂,参看读书笔记*/
(sip_ch_inst,
&call,
&dialog,
&transaction,
&subscription_id,
request_uri,
from,
to,
contact,
event,
NULL, /* expires header */
NULL,
sdp_body,
NULL);
if(sip_rc != SIP_NORMAL) {
printf("Error %d returned from sip_call_evt_subscribe\n", sip_rc);
return(1);
} else {
printf("SUBSCRIBE sent...\n");
}
}
sip_msg_free_uri(calling_uri);/*此例程递归地删除一个sip msg uri t结构和它的所有部分(参数,头,等),如果引用计数器的值大于一,则此值必须减少*/
sip_msg_free_uri(request_uri);
sip_msg_free_header(from);/*此例程递归删除一个头和他的所有部分(URIs,参数,等等),如果引用计数器的值大于1,则减少引用计数器的值*/
sip_msg_free_header(to);
sip_msg_free_header(contact);
if(do_body) {
sip_msg_free_body(sdp_body);/*此例程递归地删除SIP体结构和它所有部分(SDP announcement等等),当引用计数器的值大于1时,减少它的值*/
}
if(cancel_delay) {
sip_trans_t new_trans;
sleep(cancel_delay);
printf("Releasing the call with a CANCEL or a BYE\n");
/* send a CANCEL request *//*依靠呼叫状态,SIPcallhandling级处理用户请求也不同,这里怎么知道是发送CANCEL呢*/
sip_call_release(sip_ch_inst,
call,
dialog,
&new_trans,
NULL,
NULL,
SIP_CALL_RELEASE_AUTOMATIC,/*从SIP角度看,正常释放。释放呼叫事件回调不被调用*/
NULL);/*此例程允许用户释放一个指定呼叫*/
}
return(0);
}
/*
* FACILITY:
*
* usage
*
* ABSTRACT:
*
* The help string displayed in case of error when
* parsing the comand line.
*
* FORMAL PARAMETERS:
*
* The name of the command (argv[0]).
*
* RETURN VALUE:
*
* None
*
*/
void usage(char * command_name, char * local_ip)
{
printf("\n%s [-c request_URI]"
"\n"
"\n Starts a SIP UAS on the specified port, and an optional UAC"
"\n initiating a call (with the -c option)."
"\n"
"\n -p port : The -p option specifies the UDP port number"
"\n for the proxy server. The default port is 5060."
"\n"
"\n -c Req_URI : The -c option sends an INVITE request"
"\n to the specified URI, and manage the call"
"\n as a UAC. You can use the URI syntax to"
"\n set the destination port number (e.g."
"\n sip:user@%s:6060). 3 seconds after"
"\n call establishment, this option sends a"
"\n BYE request to terminate the call."
"\n"
"\n -cc delay : Modifier for the -c option. This option"
"\n sends a CANCEL request 'delay' seconds after"
"\n the INVITE request, if and only if a 1xx"
"\n response has been recieved."
"\n"
"\n -cb : Modifier for the -c option. This option"
"\n remove the BYE transaction after call"
"\n establishment. The call is leaved opened"
"\n once established."
"\n"
"\n -cs event : Modifier for the -c option. Sends a SUBSCRIBE"
"\n request (with the given event name) instead the"
"\n normal INVITE request."
"\n"
"\n -us nb : Modifier for the -cs option: Unsubscribe after"
"\n nb NOTIFY have been reveived."
"\n"
"\n -b delay : When UAS, send a BYE 'delay' seconds after"
"\n call establishment."
"\n"
"\n -d delay : When UAS, wait for 'delay' seconds before"
"\n answering an INVITE request."
"\n"
"\n -nd : When UAS, do not wait before accepting calls."
"\n"
"\n -ne : Do not exit when the first call is finished."
"\n"
"\n -i : Interactive mode."
"\n"
"\n -h : Displays this help screen."
"\n"
"\n -bd : Insert fake SDP body in INVITE request."
"\n"
"\n",
command_name,
local_ip);
}
/*
* FACILITY:
*
* main
*
* ABSTRACT:
*
* The main entry of the process
*
* FORMAL PARAMETERS:
*
* argc, argv command line parameters
*
* RETURN VALUE:
*
* None
*
*/
int main(int argc, char *argv[])
{
sip_status_t sip_status = SIP_NORMAL;
sip_trp_info_t sip_trp_info[1];
sip_uint32_t sip_nb_trp = 1;
sip_call_callback_vector_t sip_ch_callback;
sip_call_inst_t sip_ch_inst;
sip_uint32_t sip_remaining_indic = 0;
struct hostent * sip_local_host = NULL;
char hostname[80] = { 0 };
int sip_port = 5060;
char * sip_called_uri = NULL;
char sip_local_ip[50];
char sip_pid[16] = { 0 };
sip_bool_t do_body = SIP_FALSE;
sigset_t sig_set;
int argi;
/* Mask the SIPPIPE signal */
//为了实现SIGPIPE信号阻塞,详见service API开发手册3。1节
sigemptyset(&sig_set);
sigaddset(&sig_set, SIGPIPE);
pthread_sigmask( SIG_BLOCK, &sig_set, 0 );
if ((gethostname(hostname,64) != 0)
|| (!(sip_local_host = gethostbyname(hostname))))
{
printf("cannot get local host informations\n");
exit(1);
}
strcpy(sip_local_ip,
(char *) inet_ntoa
(*(struct in_addr *)(sip_local_host->h_addr_list[0])));
for(argi = 1; argi < argc; argi++) {
if(!strcmp(argv[argi], "-p")) {
if((++argi) < argc) {
sip_port = atol(argv[argi]);
} else {
usage(argv[0],sip_local_ip);
exit(1);
}
}
if((!strcmp(argv[argi], "-h" )) ||
(!strcmp(argv[argi], "--h" )) ||
(!strcmp(argv[argi], "--help")) ||
(!strcmp(argv[argi], "-help" )) ) {
usage(argv[0],sip_local_ip);
exit(0);
}
if(!strcmp(argv[argi], "-i")) {
interactive = SIP_TRUE;
}
if(!strcmp(argv[argi], "-bd")) {
do_body = SIP_TRUE;
}
if(!strcmp(argv[argi], "-cb")) {
no_bye = SIP_TRUE;
}
if(!strcmp(argv[argi], "-nd")) {
no_delay = SIP_TRUE;
}
if(!strcmp(argv[argi], "-ne")) {
auto_exit = SIP_FALSE;
}
if(!strcmp(argv[argi], "-c")) {
if((++argi) < argc) {
sip_called_uri = argv[argi];
} else {
usage(argv[0],sip_local_ip);
exit(1);
}
}
if(!strcmp(argv[argi], "-cc")) {
if((++argi) < argc) {
cancel_delay = atol(argv[argi]);
} else {
usage(argv[0],sip_local_ip);
exit(1);
}
}
if(!strcmp(argv[argi], "-cs")) {
if((++argi) < argc) {
subscribe_event_name = argv[argi];
} else {
usage(argv[0],sip_local_ip);
exit(1);
}
}
if(!strcmp(argv[argi], "-b")) {
if((++argi) < argc) {
uas_bye_delay = atol(argv[argi]);
} else {
usage(argv[0],sip_local_ip);
exit(1);
}
}
if(!strcmp(argv[argi], "-us")) {
if((++argi) < argc) {
unscuscribe_counter = atol(argv[argi]);
} else {
usage(argv[0],sip_local_ip);
exit(1);
}
}
if(!strcmp(argv[argi], "-d")) {
if((++argi) < argc) {
uas_invite_delay = atol(argv[argi]);
} else {
usage(argv[0],sip_local_ip);
exit(1);
}
}
}
strcat(hostname,"_sipua_");
sprintf(sip_pid,"%d",getpid());
strcat(hostname,sip_pid);
sip_status = sip_init_lib(hostname,
0,
NULL,
SIP_API_VERSION);/*初始化网络层库,之后才能调用任何其他库*/
printf("SIP User-Agent (%s) IP:%s started using UDP port %d\n",
hostname,
sip_local_ip,
sip_port);
/* Fill the SIP Call-Handling callback vector */
memset(&sip_ch_callback, 0, sizeof(sip_call_callback_vector_t));
sip_ch_callback.sip_call_on_initiate = sip_call_on_initiate;
sip_ch_callback.sip_call_on_connect = sip_call_on_connect;
sip_ch_callback.sip_call_on_release = sip_call_on_release;
sip_ch_callback.sip_call_on_cancel = sip_call_on_cancel;
sip_ch_callback.sip_call_on_progress = sip_call_on_progress;
sip_ch_callback.sip_call_on_accept = sip_call_on_accept;
sip_ch_callback.sip_call_on_get_media = sip_call_on_get_media;
sip_ch_callback.sip_call_on_request = sip_call_on_request;
sip_ch_callback.sip_call_on_reply = sip_call_on_reply;
sip_ch_callback.sip_call_on_event = sip_call_on_event;
sip_ch_callback.sip_call_on_evt_subscribe = sip_call_on_evt_subscribe;
sip_ch_callback.sip_call_on_evt_notify = sip_call_on_evt_notify;
/* Fill the transport info array */
sip_trp_info[0].trp_name = strdup("my_address");
sip_trp_info[0].dns_name = NULL;
sip_trp_info[0].address = sip_local_ip;
sip_trp_info[0].port = sip_port;
sip_trp_info[0].trp_type = SIP_TRP_UDP;
/* Create the SIP transaction instance */
sip_status = sip_call_create_instance(&sip_ch_inst,
hostname,
SIP_CALL_ENTITY_UA,
&sip_ch_callback,
sip_trp_info,
sip_nb_trp,
NULL,
NULL);/*创建新的SIPcallhandling实例*/
if (sip_status != SIP_NORMAL)
{
printf("Error in sip_call_create_instance function: %d\n", sip_status);
exit(1);
}
/* Enable the SIP transaction instance */
sip_status = sip_call_enable_instance(sip_ch_inst);/*此例程使能SIPcallhandling实例,即,它开始处理底层transaction实例传送的indication,并且使用户为此实例调用callhandling例程*/
if (sip_status != SIP_NORMAL)
{
printf("Error in sip_call_enable_instance function: %d\n", sip_status);
exit(1);
}
if ((sip_called_uri)
&& (call_uri(sip_called_uri,
sip_ch_inst,
sip_port,
do_body)))
{
sip_call_delete_instance(sip_ch_inst);/*此例程终止callhandling实例,并释放所有相关的对象(如呼叫)*/
exit(1);
}
/* Waiting for incoming messages */
while (1)
{// 4
sip_status = sip_call_deliver_indic(sip_ch_inst,
SIP_FALSE, /* non blocking */
SIP_DELIVER_ALL_MSG,
&sip_remaining_indic);/*此例程传送与SIPcallhandling实例相关的indication。此例程比较复杂,参考读书笔记*/
if (sip_status != SIP_NORMAL)
{// 1
sip_call_delete_instance(sip_ch_inst);/*此例程终止callhandling实例,并释放所有相关的对象(如呼叫)*/
printf("Error %d in delivering indication\n", sip_status);
exit(1);
}//end 1
if (sip_exit && auto_exit)
{// 3
sleep(1);
if(interactive) {// 2
printf("Press enter to exit...\n");
getchar();
}//end 2
sip_call_delete_instance(sip_ch_inst);/*此例程终止callhandling实例,并释放所有相关的对象(如呼叫)*/
// printf("Exiting\n");
exit(0);
}//end 3
}//end 4
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -