├── doc ├── Architecture.vsd ├── UAC.jpg ├── UAS.jpg └── ua.pcap ├── readme └── ua.c /doc/Architecture.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larkguo/SIP_UA/04f6809e60b083a854b69d1f366a42e819f373ad/doc/Architecture.vsd -------------------------------------------------------------------------------- /doc/UAC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larkguo/SIP_UA/04f6809e60b083a854b69d1f366a42e819f373ad/doc/UAC.jpg -------------------------------------------------------------------------------- /doc/UAS.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larkguo/SIP_UA/04f6809e60b083a854b69d1f366a42e819f373ad/doc/UAS.jpg -------------------------------------------------------------------------------- /doc/ua.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larkguo/SIP_UA/04f6809e60b083a854b69d1f366a42e819f373ad/doc/ua.pcap -------------------------------------------------------------------------------- /readme: -------------------------------------------------------------------------------- 1 | SIP UserAgent(UAS and UAC) Sample -- by larkguo@gmail.com 2 | 3 | 4 | 1.Architecture: 5 | UA ==command==> eXosip2 6 | UA <==notify== eXosip2 7 | 8 | 2.Requires: 9 | libosip2-5.0.0 10 | libeXosip2-5.0.0 11 | 12 | 3.Compile:(assumed that osip2 & eXosip2 are installed in /usr/local) 13 | gcc -I/usr/local/include -L/usr/local/lib ua.c -o ua -leXosip2 \ 14 | -losip2 -losipparser2 -lpthread 15 | 16 | 4.Run: 17 | export LD_LIBRARY_PATH+=/usr/local/lib: 18 | ./ua -r sip:DOMAIN-OR-IP -R sip:X.X.X.X:5060 -f sip:FROM-USER@DOMAIN \ 19 | -t sip:TO-USER@DOMAIN -U AUTH-USER -P AUTH-PASSWORD 20 | 21 | 6.Register: 22 | UAC/UAS PROXY 23 | 1 -REGISTER-> 24 | <-401- 25 | -REGISTER(auth)-> 26 | <-200- 27 | 28 | 7.Call: 29 | UAC (PROXY) UAS 30 | 2 -INVITE-> 31 | <-407- 32 | -INVITE(auth)-> 33 | <-180- 34 | <-200- 3 35 | -ACK-> 36 | 4 -reINVITE-> 37 | <-200- 38 | -ACK-> 39 | 5 -BYE-> 40 | <-200- -------------------------------------------------------------------------------- /ua.c: -------------------------------------------------------------------------------- 1 | /* 2 | SIP User Agent Sample -- by larkguo@gmail.com 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | 18 | 1.Architecture: 19 | UA ==command==> eXosip2 20 | UA <==notify== eXosip2 21 | 22 | 2.Requires: 23 | libosip2-5.0.0 24 | libeXosip2-5.0.0 25 | 26 | 3.Compile:(assumed that osip2 & eXosip2 are installed in /usr/local) 27 | gcc -I/usr/local/include -L/usr/local/lib ua.c -o ua -leXosip2 \ 28 | -losip2 -losipparser2 -lpthread 29 | 30 | 4.Run: 31 | export LD_LIBRARY_PATH+=/usr/local/lib: 32 | ./ua -r sip:DOMAIN-OR-IP -R sip:X.X.X.X:5060 -f sip:FROM-USER@DOMAIN \ 33 | -t sip:TO-USER@DOMAIN -U AUTH-USER -P AUTH-PASSWORD 34 | 35 | 5.Register: 36 | UAC/UAS PROXY 37 | 1 -REGISTER-> 38 | <-401- 39 | -REGISTER(auth)-> 40 | <-200- 41 | 42 | 6.Call: 43 | UAC (PROXY) UAS 44 | 2 -INVITE-> 45 | <-407- 46 | -INVITE(auth)-> 47 | <-180- 48 | <-200- 3 49 | -ACK-> 50 | 4 -reINVITE-> 51 | <-200- 52 | -ACK-> 53 | 5 -BYE-> 54 | <-200- 55 | */ 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | 69 | #define ualog(a,b...) fprintf(stderr,b);fprintf(stderr,"\n>") 70 | #define null_if_empty(s) (((s)!=NULL&&(s)[0]!='\0')?(s):NULL) 71 | #define UA_VERSION "SipUAv0.1" 72 | #define BUFFER_LEN (1024) 73 | 74 | #define UA_CMD_REGISTER ('1') 75 | #define UA_CMD_CALL_START ('2') 76 | #define UA_CMD_CALL_ANSWER ('3') 77 | #define UA_CMD_CALL_KEEP ('4') 78 | #define UA_CMD_CALL_STOP ('5') 79 | #define UA_CMD_UNREGISTER ('6') 80 | #define UA_CMD_HELP ('h') 81 | #define UA_CMD_QUIT ('q') 82 | 83 | typedef struct ua_core{ 84 | /* config */ 85 | int expiry; 86 | int localport; 87 | int calltimeout; 88 | char *proxy; 89 | char *outboundproxy; 90 | char *username; 91 | char *password; 92 | char *from; 93 | char *to; 94 | char *contact; 95 | char *localip; 96 | char *firewallip; 97 | char *transport; 98 | 99 | /* dynamic */ 100 | struct eXosip_t *context; 101 | pthread_t notifythread; 102 | int running; 103 | int regid; 104 | int callid; 105 | int dialogid; 106 | int transactionid; 107 | int cmd; 108 | } uacore; 109 | 110 | uacore g_core; 111 | char g_test_sdp[] = 112 | "v=0\r\n" 113 | "o=1 2 3 IN IP4 0.0.0.0\r\n" 114 | "s=Talk\r\n" 115 | "c=IN IP4 0.0.0.0\r\n" 116 | "t=0 0\r\n" 117 | "m=audio 8288 RTP/AVP 0\r\n" 118 | "a=rtpmap:0 PCMU/8000\r\n" 119 | "a=ptime:20\r\n"; 120 | 121 | static int ua_add_outboundproxy(osip_message_t *msg, const char *outboundproxy); 122 | int ua_cmd_register(uacore *core); 123 | int ua_cmd_unregister(uacore *core); 124 | int ua_cmd_callstart(uacore *core); 125 | int ua_cmd_callring(uacore *core); 126 | int ua_cmd_callanswer(uacore *core); 127 | int ua_cmd_callkeep(uacore *core); 128 | int ua_cmd_callstop(uacore *core); 129 | int ua_notify_callack(uacore *core, eXosip_event_t *je); 130 | int ua_notify_callkeep(uacore *core, eXosip_event_t *je); 131 | void *ua_notify_thread(void *arg); 132 | void ua_stop(int signum); 133 | void usage(void); 134 | 135 | void 136 | ua_stop(int signum){ 137 | g_core.running = 0; 138 | } 139 | 140 | void 141 | usage(void){ 142 | #define short_options "r:f:t:k:U:P:T:e:p:c:l:F:R:hv" 143 | printf("Usage: " UA_VERSION " [required] [optional]\n" 144 | "\n\t[required]\n" 145 | "\t-r --proxy\tsip:proxyhost[:port]\n" 146 | "\t-f --fromuser\tsip:fromuser@host[:port]\n" 147 | "\n\t[optional]\n" 148 | "\t-t --touser\tsip:touser@host[:port]\n" 149 | "\t-U --username\tauthentication username\n" 150 | "\t-P --password\tauthentication password\n" 151 | "\t-T --transport\tUDP|TCP|TLS|DTLS(default UDP)\n" 152 | "\t-e --expiry\tnumber(default 3600)\n" 153 | "\t-p --port\tnumber(default 5060)\n" 154 | "\t-c --contact\tsip:user@host[:port]\n" 155 | "\t-l --localip\tX.X.X.X(force local IP address)\n" 156 | "\t-k --keep\tcall keep timeout(default 1800)\n" 157 | "\t-F --firewallip\tX.X.X.X\n" 158 | "\t-R --route\toutboundproxy or SBC or P-CSCF(sip:outboundproxyhost[:port])\n" 159 | "\n\t[help]\n" 160 | "\t-v --version\n" 161 | "\t-h --help\n" 162 | "\n\t[uas example]\n" 163 | "\tua -r sip:192.168.1.X:5060 -f sip:1001@domain.com" 164 | " -U 1001 -P 1001 -p 5080\n" 165 | "\n\t[uac example]\n" 166 | "\tua -r sip:domain.com -R sip:192.168.1.X:5060 -f sip:1002@domain.com" 167 | " -t sip:1001@domain.com -U 1002 -P 1002\n" 168 | "\n\t[ims uac example]\n" 169 | "\tua -r sip:domain.com -R sip:192.168.1.X:5060 -f sip:1002@domain.com" 170 | " -t sip:1001@domain.com -U 1001@domain.com -P 1002\n\n" 171 | ); 172 | } 173 | void 174 | ua_cmd_usage(void){ 175 | printf("please select:\n" 176 | "\t1: register\n" 177 | "\t2: call start\n" 178 | "\t3: call answer\n" 179 | "\t4: call keep\n" 180 | "\t5: call stop\n" 181 | "\t6: unregister\n" 182 | "\th: help\n" 183 | "\tq: quit\n"); 184 | } 185 | 186 | int ua_quit(uacore *core){ 187 | if (NULL != core->proxy) free(core->proxy); 188 | if (NULL != core->from) free(core->from); 189 | if (NULL != core->to) free(core->to); 190 | if (NULL != core->contact) free(core->contact); 191 | if (NULL != core->localip) free(core->localip); 192 | if (NULL != core->username) free(core->username); 193 | if (NULL != core->password) free(core->password); 194 | if (NULL != core->outboundproxy) free(core->outboundproxy); 195 | if (NULL != core->firewallip) free(core->firewallip); 196 | if (NULL != core->transport) free(core->transport); 197 | return 0; 198 | } 199 | 200 | /***************************** command *****************************/ 201 | static int 202 | ua_add_outboundproxy(osip_message_t *msg, const char *outboundproxy) 203 | { 204 | int ret = 0; 205 | char head[BUFFER_LEN] = { 0 }; 206 | 207 | if (NULL == null_if_empty(outboundproxy)){ 208 | return 0; 209 | } 210 | snprintf(head, sizeof(head)-1, "<%s;lr>", outboundproxy); 211 | 212 | osip_list_special_free(&msg->routes, (void(*)(void*))osip_route_free); 213 | ret = osip_message_set_route(msg, head); 214 | return ret; 215 | } 216 | 217 | int 218 | ua_cmd_register(uacore *core) 219 | { 220 | int ret = -1; 221 | osip_message_t *msg = NULL; 222 | 223 | if (core->regid > 0){ // refresh register 224 | ret = eXosip_register_build_register(core->context, core->regid, core->expiry, &msg); 225 | if (0 != ret){ 226 | ualog(LOG_ERR, "register %d refresh build failed %d", core->regid, ret); 227 | return -1; 228 | } 229 | } 230 | else{ // new register 231 | core->regid = eXosip_register_build_initial_register(core->context, 232 | core->from, core->proxy, core->contact, core->expiry, &msg); 233 | if (core->regid <= 0){ 234 | ualog(LOG_ERR, "register build failed %d", core->regid); 235 | return -1; 236 | } 237 | ua_add_outboundproxy(msg, core->outboundproxy); 238 | } 239 | ret = eXosip_register_send_register(core->context, core->regid, msg); 240 | if (0 != ret){ 241 | ualog(LOG_ERR, "register %d send failed", core->regid); 242 | return ret; 243 | } 244 | return ret; 245 | } 246 | 247 | int 248 | ua_cmd_unregister(uacore *core) 249 | { 250 | int ret = -1; 251 | osip_message_t *msg = NULL; 252 | int expiry = 0; //unregister 253 | 254 | ret = eXosip_register_build_register(core->context, core->regid, expiry, &msg); 255 | if (0 != ret){ 256 | ualog(LOG_ERR, "unregister %d build failed %d", core->regid, ret); 257 | return -1; 258 | } 259 | 260 | ret = eXosip_register_send_register(core->context, core->regid, msg); 261 | if (0 != ret){ 262 | ualog(LOG_ERR, "register %d send failed %d", core->regid, ret); 263 | return ret; 264 | } 265 | core->regid = 0; 266 | return ret; 267 | } 268 | 269 | int 270 | ua_cmd_callstart(uacore *core) 271 | { 272 | int ret = -1; 273 | char session_exp[BUFFER_LEN] = { 0 }; 274 | osip_message_t *msg = NULL; 275 | 276 | ret = eXosip_call_build_initial_invite(core->context, &msg, core->to, core->from, NULL, NULL); 277 | if (0 != ret){ 278 | ualog(LOG_ERR, "call build failed", core->from, core->to); 279 | return -1; 280 | } 281 | ua_add_outboundproxy(msg, core->outboundproxy); 282 | osip_message_set_body(msg, g_test_sdp, strlen(g_test_sdp)); 283 | osip_message_set_content_type(msg, "application/sdp"); 284 | 285 | /* UAC call timeout */ 286 | snprintf(session_exp, sizeof(session_exp)-1, "%i;refresher=uac", core->calltimeout); 287 | osip_message_set_header(msg, "Session-Expires", session_exp); 288 | osip_message_set_supported(msg, "timer"); 289 | 290 | core->callid = eXosip_call_send_initial_invite(core->context, msg); 291 | ret = (core->callid > 0) ? 0 : -1; 292 | return ret; 293 | } 294 | 295 | int 296 | ua_cmd_callring(uacore *core) 297 | { 298 | int ret = 0; 299 | int code = 180; 300 | osip_message_t *msg = NULL; 301 | 302 | ret = eXosip_call_build_answer(core->context, core->transactionid, code, &msg); 303 | if (0 != ret){ 304 | ualog(LOG_ERR, "call %d build ring failed", core->callid); 305 | return ret; 306 | } 307 | 308 | ret = eXosip_call_send_answer(core->context, core->transactionid, code, msg); 309 | if (0 != ret){ 310 | ualog(LOG_ERR, "call %d send ring failed", core->callid); 311 | return ret; 312 | } 313 | return ret; 314 | } 315 | 316 | int 317 | ua_cmd_callanswer(uacore *core) 318 | { 319 | int ret = 0; 320 | int code = 200; 321 | osip_message_t *msg = NULL; 322 | 323 | ret = eXosip_call_build_answer(core->context, core->transactionid, code, &msg); 324 | if (0 != ret){ 325 | ualog(LOG_ERR, "call %d build answer failed", core->callid); 326 | return ret; 327 | } 328 | 329 | /* UAS call timeout */ 330 | osip_message_set_supported(msg, "timer"); 331 | 332 | osip_message_set_body(msg, g_test_sdp, strlen(g_test_sdp)); 333 | osip_message_set_content_type(msg, "application/sdp"); 334 | 335 | ret = eXosip_call_send_answer(core->context, core->transactionid, code, msg); 336 | if (0 != ret){ 337 | ualog(LOG_ERR, "call %d send answer failed", core->callid); 338 | return ret; 339 | } 340 | return ret; 341 | } 342 | 343 | int 344 | ua_cmd_callkeep(uacore *core) 345 | { 346 | int ret = -1; 347 | char session_exp[BUFFER_LEN] = { 0 }; 348 | osip_message_t *msg = NULL; 349 | 350 | ret = eXosip_call_build_request(core->context, core->dialogid, "INVITE", &msg); 351 | if (NULL == msg){ 352 | ualog(LOG_ERR, "call %d build keep failed", core->callid); 353 | return ret; 354 | } 355 | 356 | ret = eXosip_call_send_request(core->context, core->dialogid, msg); 357 | if (0 != ret){ 358 | ualog(LOG_ERR, "call %d send keep failed", core->callid); 359 | return ret; 360 | } 361 | return ret; 362 | } 363 | 364 | int 365 | ua_cmd_callstop(uacore *core) 366 | { 367 | int ret = 0; 368 | ret = eXosip_call_terminate(core->context, core->callid, core->dialogid); 369 | if (0 != ret){ 370 | ualog(LOG_ERR, "call %d send stop failed", core->callid); 371 | return ret; 372 | } 373 | return ret; 374 | } 375 | 376 | /***************************** notify *****************************/ 377 | int 378 | ua_notify_callack(uacore *core, eXosip_event_t *je) 379 | { 380 | int ret = 0; 381 | osip_message_t *msg = NULL; 382 | 383 | ret = eXosip_call_build_ack(core->context, je->did, &msg); 384 | if (0 != ret){ 385 | ualog(LOG_ERR, "call %d build ack failed", je->cid); 386 | return ret; 387 | } 388 | ua_add_outboundproxy(msg, core->outboundproxy); 389 | 390 | ret = eXosip_call_send_ack(core->context, je->did, msg); 391 | if (0 != ret){ 392 | ualog(LOG_ERR, "call %d send ack failed", je->cid); 393 | return ret; 394 | } 395 | return ret; 396 | } 397 | 398 | int 399 | ua_notify_callkeep(uacore *core, eXosip_event_t *je) 400 | { 401 | int ret = 0; 402 | int code = 200; 403 | osip_message_t *msg = NULL; 404 | eXosip_call_build_answer(core->context, je->tid, code, &msg); 405 | if (NULL == msg){ 406 | ualog(LOG_ERR, "call %d send keep answer failed", je->cid); 407 | } 408 | ret = eXosip_call_send_answer(core->context, je->tid, code, msg); 409 | if (0 != ret){ 410 | ualog(LOG_ERR, "call %d send keep answer failed", je->cid); 411 | return ret; 412 | } 413 | return ret; 414 | } 415 | 416 | int 417 | ua_notidy_callid(uacore *core, eXosip_event_t *je) 418 | { 419 | core->callid = je->cid; 420 | core->dialogid = je->did; 421 | core->transactionid = je->tid; 422 | return 0; 423 | } 424 | 425 | /* event notify loop */ 426 | void * 427 | ua_notify_thread(void *arg) 428 | { 429 | uacore *core = (uacore *)arg; 430 | int ret = 0; 431 | int code = -1; 432 | 433 | while (core->running){ 434 | osip_message_t *msg = NULL; 435 | eXosip_event_t *je = eXosip_event_wait(core->context, 0, 1); 436 | if (NULL == je){ 437 | /* auto process,such as:register refresh,auth,call keep... */ 438 | eXosip_automatic_action(core->context); 439 | osip_usleep(100000); 440 | continue; 441 | } 442 | 443 | eXosip_lock(core->context); 444 | eXosip_automatic_action(core->context); 445 | switch (je->type){ 446 | case EXOSIP_REGISTRATION_SUCCESS: 447 | if (UA_CMD_REGISTER == core->cmd){ 448 | ualog(LOG_INFO, "register %d sucess", je->rid); 449 | } 450 | else { 451 | ualog(LOG_INFO, "unregister %d sucess", je->rid); 452 | } 453 | break; 454 | case EXOSIP_REGISTRATION_FAILURE: 455 | if (UA_CMD_REGISTER == core->cmd){ 456 | ualog(LOG_INFO, "register %d failure", je->rid); 457 | } 458 | else{ 459 | ualog(LOG_INFO, "unregister %d failure", je->rid); 460 | } 461 | break; 462 | case EXOSIP_CALL_INVITE: 463 | ua_notidy_callid(core, je); 464 | ua_cmd_callring(core); 465 | ualog(LOG_INFO, "call %d incoming,please answer...", je->cid); 466 | break; 467 | case EXOSIP_CALL_REINVITE: 468 | ua_notidy_callid(core, je); 469 | ualog(LOG_INFO, "call %d keep", je->cid); 470 | ua_notify_callkeep(core, je); 471 | break; 472 | case EXOSIP_CALL_RINGING: 473 | ua_notidy_callid(core, je); 474 | ualog(LOG_INFO, "call %d ring", je->cid); 475 | break; 476 | case EXOSIP_CALL_ANSWERED: 477 | ua_notidy_callid(core, je); 478 | if (je->response) 479 | code = osip_message_get_status_code(je->response); 480 | ualog(LOG_INFO, "call %d answer %d", je->cid, code); 481 | ua_notify_callack(core, je); 482 | break; 483 | case EXOSIP_CALL_NOANSWER: 484 | ua_notidy_callid(core, je); 485 | ualog(LOG_INFO, "call %d noanswer", je->cid); 486 | break; 487 | case EXOSIP_CALL_REQUESTFAILURE: 488 | case EXOSIP_CALL_GLOBALFAILURE: 489 | case EXOSIP_CALL_SERVERFAILURE: 490 | ua_notidy_callid(core, je); 491 | if (je->response) 492 | code = osip_message_get_status_code(je->response); 493 | ualog(LOG_INFO, "call %d failture %d", je->cid, code); 494 | break; 495 | case EXOSIP_CALL_ACK: 496 | ua_notidy_callid(core, je); 497 | ualog(LOG_INFO, "call %d ack", je->cid); 498 | break; 499 | case EXOSIP_CALL_CLOSED: 500 | ualog(LOG_INFO, "call %d stop", je->cid); 501 | break; 502 | case EXOSIP_CALL_CANCELLED: 503 | ualog(LOG_INFO, "call %d cancel", je->cid); 504 | break; 505 | case EXOSIP_CALL_RELEASED: 506 | ualog(LOG_INFO, "call %d release", je->cid); 507 | break; 508 | default: 509 | break; 510 | } 511 | eXosip_unlock(core->context); 512 | eXosip_event_free(je); 513 | } 514 | eXosip_quit(core->context); 515 | osip_free(core->context); 516 | 517 | pthread_detach(pthread_self()); 518 | return 0; 519 | } 520 | 521 | /***************************** main *****************************/ 522 | int 523 | main(int argc, char *argv[]) 524 | { 525 | int ret = 0; 526 | struct servent *service = NULL; 527 | 528 | /* init */ 529 | signal(SIGINT, ua_stop); 530 | memset(&g_core, 0, sizeof(uacore)); 531 | g_core.running = 1; 532 | g_core.expiry = 3600; 533 | g_core.localport = 5060; 534 | g_core.calltimeout = 1800; 535 | 536 | /* config */ 537 | for (;;){ 538 | int c = getopt(argc, argv, short_options); 539 | if (-1 == c) 540 | break; 541 | switch (c){ 542 | case 'r': 543 | g_core.proxy = strdup(optarg); 544 | break; 545 | case 'f': 546 | g_core.from = strdup(optarg); 547 | break; 548 | case 't': 549 | g_core.to = strdup(optarg); 550 | break; 551 | case 'c': 552 | g_core.contact = strdup(optarg); 553 | break; 554 | case 'e': 555 | g_core.expiry = atoi(optarg); 556 | break; 557 | case 'l': 558 | g_core.localip = strdup(optarg); 559 | break; 560 | case 'p': 561 | service = getservbyname(optarg, "udp"); 562 | if (service) g_core.localport = ntohs(service->s_port); 563 | else g_core.localport = atoi(optarg); 564 | break; 565 | case 'k': 566 | g_core.calltimeout = atoi(optarg); 567 | break; 568 | case 'U': 569 | g_core.username = strdup(optarg); 570 | break; 571 | case 'P': 572 | g_core.password = strdup(optarg); 573 | break; 574 | case 'R': 575 | g_core.outboundproxy = strdup(optarg); 576 | break; 577 | case 'F': 578 | g_core.firewallip = strdup(optarg); 579 | break; 580 | case 'T': 581 | g_core.transport = strdup(optarg); 582 | break; 583 | case 'v': 584 | printf("%s\n", UA_VERSION); 585 | return 0; 586 | case 'h': 587 | default: 588 | usage(); 589 | return 0; 590 | } 591 | } 592 | if (!g_core.proxy || !g_core.from){ 593 | usage(); 594 | return -1; 595 | } 596 | if (NULL == g_core.transport) 597 | g_core.transport = strdup("UDP"); 598 | ualog(LOG_INFO, "proxy: %s", g_core.proxy); 599 | ualog(LOG_INFO, "outboundproxy: %s", g_core.outboundproxy); 600 | ualog(LOG_INFO, "from: %s", g_core.from); 601 | ualog(LOG_INFO, "to: %s", g_core.to); 602 | ualog(LOG_INFO, "contact: %s", g_core.contact); 603 | ualog(LOG_INFO, "expiry: %d", g_core.expiry); 604 | ualog(LOG_INFO, "localport: %d", g_core.localport); 605 | ualog(LOG_INFO, "transport: %s", g_core.transport); 606 | ualog(LOG_INFO, "calltimeout: %d", g_core.calltimeout); 607 | 608 | g_core.context = eXosip_malloc(); 609 | if (eXosip_init(g_core.context)){ 610 | ualog(LOG_ERR, "init failed"); 611 | return -1; 612 | } 613 | if (osip_strcasecmp(g_core.transport, "UDP") == 0){ 614 | ret = eXosip_listen_addr(g_core.context, IPPROTO_UDP, NULL, g_core.localport, AF_INET, 0); 615 | } 616 | else if (osip_strcasecmp(g_core.transport, "TCP") == 0){ 617 | ret = eXosip_listen_addr(g_core.context, IPPROTO_TCP, NULL, g_core.localport, AF_INET, 0); 618 | } 619 | else if (osip_strcasecmp(g_core.transport, "TLS") == 0){ 620 | ret = eXosip_listen_addr(g_core.context, IPPROTO_TCP, NULL, g_core.localport, AF_INET, 1); 621 | } 622 | else if (osip_strcasecmp(g_core.transport, "DTLS") == 0){ 623 | ret = eXosip_listen_addr(g_core.context, IPPROTO_UDP, NULL, g_core.localport, AF_INET, 1); 624 | } 625 | else{ 626 | ret = -1; 627 | } 628 | if (ret){ 629 | ualog(LOG_ERR, "listen failed"); 630 | return -1; 631 | } 632 | if (g_core.localip){ 633 | ualog(LOG_INFO, "local address: %s", g_core.localip); 634 | eXosip_masquerade_contact(g_core.context, g_core.localip, g_core.localport); 635 | } 636 | if (g_core.firewallip){ 637 | ualog(LOG_INFO, "firewall address: %s:%i", g_core.firewallip, g_core.localport); 638 | eXosip_masquerade_contact(g_core.context, g_core.firewallip, g_core.localport); 639 | } 640 | eXosip_set_user_agent(g_core.context, UA_VERSION); 641 | if (g_core.username && g_core.password){ 642 | ualog(LOG_INFO, "username: %s", g_core.username); 643 | ualog(LOG_INFO, "password: ******"); 644 | if (eXosip_add_authentication_info(g_core.context, g_core.username, 645 | g_core.username, g_core.password, NULL, NULL)){ 646 | ualog(LOG_ERR, "add_authentication_info failed"); 647 | return -1; 648 | } 649 | } 650 | 651 | /* start */ 652 | pthread_create(&g_core.notifythread, NULL, ua_notify_thread, &g_core); 653 | ualog(LOG_INFO, UA_VERSION " start"); 654 | ua_cmd_usage(); 655 | printf(">"); 656 | while (g_core.running){ //command loop 657 | char c = getchar(); 658 | 659 | eXosip_lock(g_core.context); 660 | switch (c){ 661 | case UA_CMD_REGISTER: 662 | g_core.cmd = c; 663 | ua_cmd_register(&g_core); 664 | break; 665 | case UA_CMD_CALL_START: 666 | ua_cmd_callstart(&g_core); 667 | break; 668 | case UA_CMD_CALL_ANSWER: 669 | ua_cmd_callanswer(&g_core); 670 | break; 671 | case UA_CMD_CALL_KEEP: 672 | ua_cmd_callkeep(&g_core); 673 | break; 674 | case UA_CMD_CALL_STOP: 675 | ua_cmd_callstop(&g_core); 676 | break; 677 | case UA_CMD_UNREGISTER: 678 | g_core.cmd = c; 679 | ua_cmd_unregister(&g_core); 680 | break; 681 | case UA_CMD_HELP: 682 | ua_cmd_usage(); 683 | break; 684 | case UA_CMD_QUIT: 685 | g_core.running = 0; 686 | break; 687 | case '\n': 688 | printf(">"); 689 | break; 690 | default: 691 | ualog(LOG_ERR, "unknown '%c'", c); 692 | break; 693 | } 694 | eXosip_unlock(g_core.context); 695 | } 696 | 697 | /* stop */ 698 | ua_quit(&g_core); 699 | printf("%s stop\n", UA_VERSION); 700 | return 0; 701 | } 702 | --------------------------------------------------------------------------------