Changeset 141 for pjproject/trunk/pjsip/src/pjsua/main.c
- Timestamp:
- Feb 7, 2006 6:48:01 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsua/main.c
r139 r141 18 18 */ 19 19 #include "pjsua.h" 20 #include "getopt.h" 21 20 22 21 23 /* For debugging, disable threading. */ … … 33 35 * Notify UI when invite state has changed. 34 36 */ 35 void ui_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)37 void pjsua_ui_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) 36 38 { 37 39 const char *state_names[] = … … 51 53 PJ_LOG(3,(THIS_FILE, "INVITE session state changed to %s", state_names[inv->state])); 52 54 53 if (inv->state == PJSIP_INV_STATE_DISCONNECTED || 54 inv->state == PJSIP_INV_STATE_TERMINATED) 55 { 55 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { 56 56 if (inv == inv_session) 57 57 inv_session = NULL; … … 104 104 } 105 105 106 #if 0106 #if 1 107 107 printf("Enter URL to call: "); 108 108 fgets(buf, sizeof(buf), stdin); … … 122 122 123 123 pjsua_invite(buf, &inv); 124 125 #else 126 127 pjsua_invite("sip:localhost:5061", &inv); 124 128 #endif 125 126 pjsua_invite("sip:localhost:5061", &inv);127 129 break; 128 130 … … 163 165 } 164 166 167 168 /***************************************************************************** 169 * This is a very simple PJSIP module, whose sole purpose is to display 170 * incoming and outgoing messages to log. This module will have priority 171 * higher than transport layer, which means: 172 * 173 * - incoming messages will come to this module first before reaching 174 * transaction layer. 175 * 176 * - outgoing messages will come to this module last, after the message 177 * has been 'printed' to contiguous buffer by transport layer and 178 * appropriate transport instance has been decided for this message. 179 * 180 */ 181 182 /* Notification on incoming messages */ 165 183 static pj_bool_t console_on_rx_msg(pjsip_rx_data *rdata) 166 184 { … … 174 192 rdata->msg_info.msg_buf)); 175 193 176 /* Must return false for logger! */194 /* Always return false, otherwise messages will not get processed! */ 177 195 return PJ_FALSE; 178 196 } 179 197 198 /* Notification on outgoing messages */ 180 199 static pj_status_t console_on_tx_msg(pjsip_tx_data *tdata) 181 200 { 201 202 /* Important note: 203 * tp_info field is only valid after outgoing messages has passed 204 * transport layer. So don't try to access tp_info when the module 205 * has lower priority than transport layer. 206 */ 207 182 208 PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n" 183 209 "%s\n" … … 189 215 tdata->buf.start)); 190 216 217 /* Always return success, otherwise message will not get sent! */ 191 218 return PJ_SUCCESS; 192 219 } 193 220 221 /* The module instance. */ 194 222 static pjsip_module console_msg_logger = 195 223 { … … 212 240 213 241 214 int main() 242 243 /***************************************************************************** 244 * Console application custom logging: 245 */ 246 247 248 static FILE *log_file; 249 250 251 static void app_log_writer(int level, const char *buffer, int len) 252 { 253 /* Write to both stdout and file. */ 254 255 if (level <= pjsua.app_log_level) 256 pj_log_write(level, buffer, len); 257 258 if (log_file) { 259 fwrite(buffer, len, 1, log_file); 260 fflush(log_file); 261 } 262 } 263 264 265 void app_logging_init(void) 266 { 267 /* Redirect log function to ours */ 268 269 pj_log_set_log_func( &app_log_writer ); 270 271 /* If output log file is desired, create the file: */ 272 273 if (pjsua.log_filename) 274 log_file = fopen(pjsua.log_filename, "wt"); 275 } 276 277 278 void app_logging_shutdown(void) 279 { 280 /* Close logging file, if any: */ 281 282 if (log_file) { 283 fclose(log_file); 284 log_file = NULL; 285 } 286 } 287 288 /***************************************************************************** 289 * Command line argument processing: 290 */ 291 292 293 /* Show usage */ 294 static void usage(void) 295 { 296 puts("Usage:"); 297 puts(" pjsua [options] [sip-url]"); 298 puts(""); 299 puts(" [sip-url] Default URL to invite."); 300 puts(""); 301 puts("General options:"); 302 puts(" --config-file=file Read the config/arguments from file."); 303 puts(" --log-file=fname Log to filename (default stderr)"); 304 puts(" --log-level=N Set log max level to N (0(none) to 6(trace))"); 305 puts(" --app-log-level=N Set log max level for stdout display to N"); 306 puts(" --help Display this help screen"); 307 puts(" --version Display version info"); 308 puts(""); 309 puts("Media options:"); 310 puts(" --null-audio Use NULL audio device"); 311 puts(""); 312 puts("User Agent options:"); 313 puts(" --auto-answer=sec Auto-answer all incoming calls after sec seconds."); 314 puts(" --auto-hangup=sec Auto-hangup all calls after sec seconds."); 315 puts(""); 316 puts("SIP options:"); 317 puts(" --local-port=port Set TCP/UDP port"); 318 puts(" --id=url Set the URL of local ID (used in From header)"); 319 puts(" --contact=url Override the Contact information"); 320 puts(" --proxy=url Set the URL of proxy server"); 321 puts(" --outbound=url Set the URL of outbound proxy server"); 322 puts(" --registrar=url Set the URL of registrar server"); 323 puts(" --reg-timeout=secs Set registration interval to secs (default 3600)"); 324 puts(""); 325 puts("Authentication options:"); 326 puts(" --realm=string Set realm"); 327 puts(" --username=string Set authentication username"); 328 puts(" --password=string Set authentication password"); 329 puts(""); 330 puts("STUN options (all must be specified):"); 331 puts(" --use-stun1=host[:port]"); 332 puts(" --use-stun2=host[:port] Use STUN and set host name and port of STUN servers"); 333 puts(""); 334 puts("SIMPLE options (may be specified more than once):"); 335 puts(" --add-buddy url Add the specified URL to the buddy list."); 336 puts(" --offer-x-ms-msg Offer \"x-ms-message\" in outgoing INVITE"); 337 puts(" --no-presence Do not subscribe presence of buddies"); 338 puts(""); 339 fflush(stdout); 340 } 341 342 343 /* 344 * Verify that valid SIP url is given. 345 */ 346 static pj_status_t verify_sip_url(char *url) 347 { 348 pjsip_uri *p; 349 pj_pool_t *pool; 350 int len = (url ? strlen(url) : 0); 351 352 if (!len) return -1; 353 354 pool = pj_pool_create(&pjsua.cp.factory, "check%p", 1024, 0, NULL); 355 if (!pool) return -1; 356 357 p = pjsip_parse_uri(pool, url, len, 0); 358 if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0) 359 p = NULL; 360 361 pj_pool_release(pool); 362 return p ? 0 : -1; 363 } 364 365 366 /* 367 * Read command arguments from config file. 368 */ 369 static int read_config_file(pj_pool_t *pool, const char *filename, 370 int *app_argc, char ***app_argv) 371 { 372 int i; 373 FILE *fhnd; 374 char line[200]; 375 int argc = 0; 376 char **argv; 377 enum { MAX_ARGS = 64 }; 378 379 /* Allocate MAX_ARGS+1 (argv needs to be terminated with NULL argument) */ 380 argv = pj_pool_calloc(pool, MAX_ARGS+1, sizeof(char*)); 381 argv[argc++] = *app_argv[0]; 382 383 /* Open config file. */ 384 fhnd = fopen(filename, "rt"); 385 if (!fhnd) { 386 printf("Unable to open config file %s\n", filename); 387 return -1; 388 } 389 390 /* Scan tokens in the file. */ 391 while (argc < MAX_ARGS && !feof(fhnd)) { 392 char *token, *p = line; 393 394 if (fgets(line, sizeof(line), fhnd) == NULL) break; 395 396 for (token = strtok(p, " \t\r\n"); argc < MAX_ARGS; 397 token = strtok(NULL, " \t\r\n")) 398 { 399 int token_len; 400 401 if (!token) break; 402 if (*token == '#') break; 403 404 token_len = strlen(token); 405 if (!token_len) 406 continue; 407 argv[argc] = pj_pool_alloc(pool, token_len+1); 408 pj_memcpy(argv[argc], token, token_len+1); 409 ++argc; 410 } 411 } 412 413 /* Copy arguments from command line */ 414 for (i=1; i<*app_argc && argc < MAX_ARGS; ++i) 415 argv[argc++] = (*app_argv)[i]; 416 417 if (argc == MAX_ARGS && (i!=*app_argc || !feof(fhnd))) { 418 printf("Too many arguments specified in cmd line/config file\n"); 419 fclose(fhnd); 420 return -1; 421 } 422 423 fclose(fhnd); 424 425 /* Assign the new command line back to the original command line. */ 426 *app_argc = argc; 427 *app_argv = argv; 428 return 0; 429 430 } 431 432 433 /* Parse arguments. */ 434 static pj_status_t parse_args(int argc, char *argv[]) 435 { 436 int c; 437 int option_index; 438 enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL, 439 OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, 440 OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR, 441 OPT_REG_TIMEOUT, OPT_ID, OPT_CONTACT, 442 OPT_REALM, OPT_USERNAME, OPT_PASSWORD, 443 OPT_USE_STUN1, OPT_USE_STUN2, 444 OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE, 445 OPT_AUTO_ANSWER, OPT_AUTO_HANGUP}; 446 struct option long_options[] = { 447 { "config-file",1, 0, OPT_CONFIG_FILE}, 448 { "log-file", 1, 0, OPT_LOG_FILE}, 449 { "log-level", 1, 0, OPT_LOG_LEVEL}, 450 { "app-log-level",1,0,OPT_APP_LOG_LEVEL}, 451 { "help", 0, 0, OPT_HELP}, 452 { "version", 0, 0, OPT_VERSION}, 453 { "null-audio", 0, 0, OPT_NULL_AUDIO}, 454 { "local-port", 1, 0, OPT_LOCAL_PORT}, 455 { "proxy", 1, 0, OPT_PROXY}, 456 { "outbound", 1, 0, OPT_OUTBOUND_PROXY}, 457 { "registrar", 1, 0, OPT_REGISTRAR}, 458 { "reg-timeout",1, 0, OPT_REG_TIMEOUT}, 459 { "id", 1, 0, OPT_ID}, 460 { "contact", 1, 0, OPT_CONTACT}, 461 { "realm", 1, 0, OPT_REALM}, 462 { "username", 1, 0, OPT_USERNAME}, 463 { "password", 1, 0, OPT_PASSWORD}, 464 { "use-stun1", 1, 0, OPT_USE_STUN1}, 465 { "use-stun2", 1, 0, OPT_USE_STUN2}, 466 { "add-buddy", 1, 0, OPT_ADD_BUDDY}, 467 { "offer-x-ms-msg",0,0,OPT_OFFER_X_MS_MSG}, 468 { "no-presence", 0, 0, OPT_NO_PRESENCE}, 469 { "auto-answer",1, 0, OPT_AUTO_ANSWER}, 470 { "auto-hangup",1, 0, OPT_AUTO_HANGUP}, 471 { NULL, 0, 0, 0} 472 }; 473 pj_status_t status; 474 char *config_file = NULL; 475 476 /* Run getopt once to see if user specifies config file to read. */ 477 while ((c=getopt_long(argc, argv, "", long_options, &option_index)) != -1) { 478 switch (c) { 479 case OPT_CONFIG_FILE: 480 config_file = optarg; 481 break; 482 } 483 if (config_file) 484 break; 485 } 486 487 if (config_file) { 488 status = read_config_file(pjsua.pool, config_file, &argc, &argv); 489 if (status != 0) 490 return status; 491 } 492 493 494 /* Reinitialize and re-run getopt again, possibly with new arguments 495 * read from config file. 496 */ 497 optind = 0; 498 while ((c=getopt_long(argc, argv, "", long_options, &option_index)) != -1) { 499 char *p; 500 pj_str_t tmp; 501 long lval; 502 503 switch (c) { 504 505 case OPT_LOG_FILE: 506 pjsua.log_filename = optarg; 507 break; 508 509 case OPT_LOG_LEVEL: 510 c = pj_strtoul(pj_cstr(&tmp, optarg)); 511 if (c < 0 || c > 6) { 512 printf("Error: expecting integer value 0-6 for --log-level\n"); 513 return PJ_EINVAL; 514 } 515 pj_log_set_level( c ); 516 break; 517 518 case OPT_APP_LOG_LEVEL: 519 pjsua.app_log_level = pj_strtoul(pj_cstr(&tmp, optarg)); 520 if (pjsua.app_log_level < 0 || pjsua.app_log_level > 6) { 521 printf("Error: expecting integer value 0-6 for --app-log-level\n"); 522 return PJ_EINVAL; 523 } 524 break; 525 526 case OPT_HELP: 527 usage(); 528 return PJ_EINVAL; 529 530 case OPT_VERSION: /* version */ 531 pj_dump_config(); 532 return PJ_EINVAL; 533 534 case OPT_NULL_AUDIO: 535 pjsua.null_audio = 1; 536 break; 537 538 case OPT_LOCAL_PORT: /* local-port */ 539 lval = pj_strtoul(pj_cstr(&tmp, optarg)); 540 if (lval < 1 || lval > 65535) { 541 printf("Error: expecting integer value for --local-port\n"); 542 return PJ_EINVAL; 543 } 544 pjsua.sip_port = (pj_uint16_t)lval; 545 break; 546 547 case OPT_PROXY: /* proxy */ 548 if (verify_sip_url(optarg) != 0) { 549 printf("Error: invalid SIP URL '%s' in proxy argument\n", optarg); 550 return PJ_EINVAL; 551 } 552 pjsua.proxy = pj_str(optarg); 553 break; 554 555 case OPT_OUTBOUND_PROXY: /* outbound proxy */ 556 if (verify_sip_url(optarg) != 0) { 557 printf("Error: invalid SIP URL '%s' in outbound proxy argument\n", optarg); 558 return PJ_EINVAL; 559 } 560 pjsua.outbound_proxy = pj_str(optarg); 561 break; 562 563 case OPT_REGISTRAR: /* registrar */ 564 if (verify_sip_url(optarg) != 0) { 565 printf("Error: invalid SIP URL '%s' in registrar argument\n", optarg); 566 return PJ_EINVAL; 567 } 568 pjsua.registrar_uri = pj_str(optarg); 569 break; 570 571 case OPT_REG_TIMEOUT: /* reg-timeout */ 572 pjsua.reg_timeout = pj_strtoul(pj_cstr(&tmp,optarg)); 573 if (pjsua.reg_timeout < 1 || pjsua.reg_timeout > 3600) { 574 printf("Error: invalid value for --reg-timeout (expecting 1-3600)\n"); 575 return PJ_EINVAL; 576 } 577 break; 578 579 case OPT_ID: /* id */ 580 if (verify_sip_url(optarg) != 0) { 581 printf("Error: invalid SIP URL '%s' in local id argument\n", optarg); 582 return PJ_EINVAL; 583 } 584 pjsua.local_uri = pj_str(optarg); 585 break; 586 587 case OPT_CONTACT: /* contact */ 588 if (verify_sip_url(optarg) != 0) { 589 printf("Error: invalid SIP URL '%s' in contact argument\n", optarg); 590 return PJ_EINVAL; 591 } 592 pjsua.contact_uri = pj_str(optarg); 593 break; 594 595 case OPT_USERNAME: /* Default authentication user */ 596 if (!pjsua.cred_count) pjsua.cred_count = 1; 597 pjsua.cred_info[0].username = pj_str(optarg); 598 break; 599 600 case OPT_REALM: /* Default authentication realm. */ 601 if (!pjsua.cred_count) pjsua.cred_count = 1; 602 pjsua.cred_info[0].realm = pj_str(optarg); 603 break; 604 605 case OPT_PASSWORD: /* authentication password */ 606 if (!pjsua.cred_count) pjsua.cred_count = 1; 607 pjsua.cred_info[0].data_type = 0; 608 pjsua.cred_info[0].data = pj_str(optarg); 609 break; 610 611 case OPT_USE_STUN1: /* STUN server 1 */ 612 p = pj_native_strchr(optarg, ':'); 613 if (p) { 614 *p = '\0'; 615 pjsua.stun_srv1 = pj_str(optarg); 616 pjsua.stun_port1 = pj_strtoul(pj_cstr(&tmp, p+1)); 617 if (pjsua.stun_port1 < 1 || pjsua.stun_port1 > 65535) { 618 printf("Error: expecting port number with option --use-stun1\n"); 619 return PJ_EINVAL; 620 } 621 } else { 622 pjsua.stun_port1 = 3478; 623 pjsua.stun_srv1 = pj_str(optarg); 624 } 625 break; 626 627 case OPT_USE_STUN2: /* STUN server 2 */ 628 p = pj_native_strchr(optarg, ':'); 629 if (p) { 630 *p = '\0'; 631 pjsua.stun_srv2 = pj_str(optarg); 632 pjsua.stun_port2 = pj_strtoul(pj_cstr(&tmp,p+1)); 633 if (pjsua.stun_port2 < 1 || pjsua.stun_port2 > 65535) { 634 printf("Error: expecting port number with option --use-stun2\n"); 635 return PJ_EINVAL; 636 } 637 } else { 638 pjsua.stun_port2 = 3478; 639 pjsua.stun_srv2 = pj_str(optarg); 640 } 641 break; 642 } 643 } 644 645 if (optind != argc) { 646 printf("Error: unknown options %s\n", argv[optind]); 647 return PJ_EINVAL; 648 } 649 650 if (pjsua.reg_timeout == 0) 651 pjsua.reg_timeout = 3600; 652 653 654 return PJ_SUCCESS; 655 } 656 657 658 659 /***************************************************************************** 660 * main(): 661 */ 662 int main(int argc, char *argv[]) 215 663 { 216 664 /* Init default settings. */ … … 224 672 225 673 226 /* Initialize pjsua. 227 * This will start worker thread, client registration, etc. 674 /* Initialize pjsua (to create pool etc). 228 675 */ 229 676 230 677 if (pjsua_init() != PJ_SUCCESS) 231 678 return 1; 679 680 681 /* Parse command line arguments: */ 682 683 if (parse_args(argc, argv) != PJ_SUCCESS) 684 return 1; 685 686 687 /* Init logging: */ 688 689 app_logging_init(); 690 232 691 233 692 /* Register message logger to print incoming and outgoing … … 238 697 239 698 699 /* Start pjsua! */ 700 701 if (pjsua_start() != PJ_SUCCESS) { 702 703 pjsua_destroy(); 704 return 1; 705 } 706 707 240 708 /* Sleep for a while, let any messages get printed to console: */ 241 709 … … 252 720 pjsua_destroy(); 253 721 722 723 /* Close logging: */ 724 725 app_logging_shutdown(); 726 727 254 728 /* Exit... */ 255 729
Note: See TracChangeset
for help on using the changeset viewer.