📄 pjsip-perf.c
字号:
#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC!=0 pjmedia_codec_gsm_init(app.med_endpt);#endif#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0 pjmedia_codec_speex_init(app.med_endpt, PJMEDIA_SPEEX_NO_UWB, 3, 3);#endif /* Init dummy socket addresses */ app.skinfo_cnt = 0; for (i=0, rtp_port=4000; i<PJ_ARRAY_SIZE(app.skinfo); ++i, rtp_port+=2) { pjmedia_sock_info *skinfo; skinfo = &app.skinfo[i]; pj_sockaddr_in_init(&skinfo->rtp_addr_name, &app.local_addr, (pj_uint16_t)rtp_port); pj_sockaddr_in_init(&skinfo->rtp_addr_name, &app.local_addr, (pj_uint16_t)(rtp_port+1)); app.skinfo_cnt++; } /* Generate dummy SDP */ dummy_sdp_str.slen = pj_ansi_strlen(dummy_sdp_str.ptr); status = pjmedia_sdp_parse(app.pool, dummy_sdp_str.ptr, dummy_sdp_str.slen, &app.dummy_sdp); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Error parsing dummy SDP", status); return status; } /* Done */ return PJ_SUCCESS;}/* This is notification from the call about media negotiation * status. This is called for client calls only. */static void call_on_media_update( pjsip_inv_session *inv, pj_status_t status){ if (status != PJ_SUCCESS) { pjsip_tx_data *tdata; pj_status_t status; status = pjsip_inv_end_session(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE, NULL, &tdata); if (status == PJ_SUCCESS && tdata) status = pjsip_inv_send_msg(inv, tdata); }}/* This is notification from the call when the call state has changed. * This is called for client calls only. */static void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e){ PJ_UNUSED_ARG(e); /* Bail out if the session has been counted before */ if (inv->mod_data[mod_test.id] != NULL) return; /* Bail out if this is not an outgoing call */ if (inv->role != PJSIP_UAC_ROLE) return; if (inv->state == PJSIP_INV_STATE_CONFIRMED) { pjsip_tx_data *tdata; pj_status_t status; //report_completion(200); //inv->mod_data[mod_test.id] = (void*)1; status = pjsip_inv_end_session(inv, PJSIP_SC_OK, NULL, &tdata); if (status == PJ_SUCCESS && tdata) status = pjsip_inv_send_msg(inv, tdata); } else if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { report_completion(inv->cause); inv->mod_data[mod_test.id] = (void*)1; }}/* Not implemented for now */static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e){ /* Do nothing */ PJ_UNUSED_ARG(inv); PJ_UNUSED_ARG(e);}/* * Make outgoing call. */static pj_status_t make_call(const pj_str_t *dst_uri){ struct call *call; pjsip_dialog *dlg; pjmedia_sdp_session *sdp; pjsip_tx_data *tdata; pj_status_t status; /* Create UAC dialog */ status = pjsip_dlg_create_uac( pjsip_ua_instance(), &app.local_uri, /* local URI */ &app.local_contact, /* local Contact */ dst_uri, /* remote URI */ dst_uri, /* remote target */ &dlg); /* dialog */ if (status != PJ_SUCCESS) { return status; } /* Create call */ call = pj_pool_zalloc(dlg->pool, sizeof(struct call)); /* Create SDP */ if (app.real_sdp) { status = pjmedia_endpt_create_sdp(app.med_endpt, dlg->pool, 1, app.skinfo, &sdp); if (status != PJ_SUCCESS) { pjsip_dlg_terminate(dlg); return status; } } else sdp = app.dummy_sdp; /* Create the INVITE session. */ status = pjsip_inv_create_uac( dlg, sdp, 0, &call->inv); if (status != PJ_SUCCESS) { pjsip_dlg_terminate(dlg); return status; } /* Create initial INVITE request. * This INVITE request will contain a perfectly good request and * an SDP body as well. */ status = pjsip_inv_invite(call->inv, &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Send initial INVITE request. * From now on, the invite session's state will be reported to us * via the invite session callbacks. */ status = pjsip_inv_send_msg(call->inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); return PJ_SUCCESS;}/* * Verify that valid SIP url is given. */static pj_status_t verify_sip_url(const char *c_url){ pjsip_uri *p; pj_pool_t *pool; char *url; int len = (c_url ? pj_ansi_strlen(c_url) : 0); if (!len) return -1; pool = pj_pool_create(&app.cp.factory, "check%p", 1024, 0, NULL); if (!pool) return PJ_ENOMEM; url = pj_pool_alloc(pool, len+1); pj_ansi_strcpy(url, c_url); url[len] = '\0'; p = pjsip_parse_uri(pool, url, len, 0); if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0) p = NULL; pj_pool_release(pool); return p ? 0 : -1;}static void usage(void){ printf( "Usage:\n" " pjsip-perf [OPTIONS] -- to start as server\n" " pjsip-perf [OPTIONS] URL -- to call server (possibly itself)\n" "\n" "where:\n" " URL The SIP URL to be contacted.\n" "\n" "Client options:\n" " --method=METHOD, -m Set test method (set to INVITE for call benchmark)\n" " [default: OPTIONS]\n" " --count=N, -n Set total number of requests to initiate\n" " [default=%d]\n" " --stateless, -s Set to operate in stateless mode\n" " [default: stateful]\n" " --timeout=SEC, -t Set client timeout [default=60 sec]\n" " --window=COUNT, -w Set maximum outstanding job [default: %d]\n" "\n" "SDP options (client and server):\n" " --real-sdp Generate real SDP from pjmedia, and also perform\n" " proper SDP negotiation [default: dummy]\n" "\n" "Client and Server options:\n" " --local-port=PORT, -p Set local port [default: 5060]\n" " --use-tcp, -T Use TCP instead of UDP. Note that when started as\n" " client, you must add ;transport=tcp parameter to URL\n" " [default: no]\n" " --thread-count=N Set number of worker threads [default=1]\n" " --trying Send 100/Trying response (server, default no)\n" " --ringing Send 180/Ringing response (server, default no)\n" " --delay=MS, -d Delay answering call by MS (server, default no)\n" "\n" "Misc options:\n" " --help, -h Display this screen\n" " --verbose, -v Verbose logging (put more than once for even more)\n" "\n" "When started as server, pjsip-perf can be contacted on the following URIs:\n" " - sip:0@server-addr To handle requests statelessly.\n" " - sip:1@server-addr To handle requests statefully.\n" " - sip:2@server-addr To handle INVITE call.\n", DEFAULT_COUNT, JOB_WINDOW);}static int my_atoi(const char *s){ pj_str_t ss = pj_str((char*)s); return pj_strtoul(&ss);}static pj_status_t init_options(int argc, char *argv[]){ enum { OPT_THREAD_COUNT = 1, OPT_REAL_SDP, OPT_TRYING, OPT_RINGING }; struct pj_getopt_option long_options[] = { { "local-port", 1, 0, 'p' }, { "count", 1, 0, 'c' }, { "thread-count", 1, 0, OPT_THREAD_COUNT }, { "method", 1, 0, 'm' }, { "help", 0, 0, 'h' }, { "stateless", 0, 0, 's' }, { "timeout", 1, 0, 't' }, { "real-sdp", 0, 0, OPT_REAL_SDP }, { "verbose", 0, 0, 'v' }, { "use-tcp", 0, 0, 'T' }, { "window", 1, 0, 'w' }, { "delay", 1, 0, 'd' }, { "trying", 0, 0, OPT_TRYING}, { "ringing", 0, 0, OPT_RINGING}, { NULL, 0, 0, 0 }, }; int c; int option_index; /* Init default application configs */ app.local_port = 5060; app.thread_count = 1; app.client.job_count = DEFAULT_COUNT; app.client.method = pjsip_options_method; app.client.job_window = c = JOB_WINDOW; app.client.timeout = 60; app.log_level = 3; /* Parse options */ pj_optind = 0; while((c=pj_getopt_long(argc,argv, "p:c:m:t:w:d:hsv", long_options, &option_index))!=-1) { switch (c) { case 'p': app.local_port = my_atoi(pj_optarg); if (app.local_port < 0 || app.local_port > 65535) { PJ_LOG(3,(THIS_FILE, "Invalid --local-port %s", pj_optarg)); return -1; } break; case 'c': app.client.job_count = my_atoi(pj_optarg); if (app.client.job_count < 0) { PJ_LOG(3,(THIS_FILE, "Invalid --local-port %s", pj_optarg)); return -1; } if (app.client.job_count > PJSIP_MAX_TSX_COUNT) PJ_LOG(3,(THIS_FILE, "Warning: --count value (%d) exceeds maximum " "transaction count (%d)", app.client.job_count, PJSIP_MAX_TSX_COUNT)); break; case OPT_THREAD_COUNT: app.thread_count = my_atoi(pj_optarg); if (app.thread_count < 1 || app.thread_count > 16) { PJ_LOG(3,(THIS_FILE, "Invalid --thread-count %s", pj_optarg)); return -1; } break; case 'm': { pj_str_t temp = pj_str((char*)pj_optarg); pjsip_method_init_np(&app.client.method, &temp); } break; case 'h': usage(); return -1; case 's': app.client.stateless = PJ_TRUE; break; case OPT_REAL_SDP: app.real_sdp = 1; break; case 'v': app.log_level++; break; case 't': app.client.timeout = my_atoi(pj_optarg); if (app.client.timeout < 0 || app.client.timeout > 600) { PJ_LOG(3,(THIS_FILE, "Invalid --timeout %s", pj_optarg)); return -1; } break; case 'w': app.client.job_window = my_atoi(pj_optarg); if (app.client.job_window <= 0) { PJ_LOG(3,(THIS_FILE, "Invalid --window %s", pj_optarg)); return -1; } break; case 'T': app.use_tcp = PJ_TRUE; break; case 'd': app.server.delay = my_atoi(pj_optarg); if (app.server.delay > 3600) { PJ_LOG(3,(THIS_FILE, "I think --delay %s is too long", pj_optarg)); return -1; } break; case OPT_TRYING: app.server.send_trying = 1; break; case OPT_RINGING: app.server.send_ringing = 1; break; default: PJ_LOG(1,(THIS_FILE, "Invalid argument. Use --help to see help")); return -1; } } if (pj_optind != argc) { if (verify_sip_url(argv[pj_optind]) != PJ_SUCCESS) { PJ_LOG(1,(THIS_FILE, "Invalid SIP URI %s", argv[pj_optind])); return -1; } app.client.dst_uri = pj_str(argv[pj_optind]); pj_optind++; } if (pj_optind != argc) { PJ_LOG(1,(THIS_FILE, "Error: unknown options %s", argv[pj_optind])); return -1; } return 0;}/* Send one stateless request */static pj_status_t submit_stateless_job(void){ pjsip_tx_data *tdata; pj_status_t status; status = pjsip_endpt_create_request(app.sip_endpt, &app.client.method, &app.client.dst_uri, &app.local_uri, &app.client.dst_uri, &app.local_contact, NULL, -1, NULL, &tdata); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Error creating request", status); report_completion(701); return status; } status = pjsip_endpt_send_request_stateless(app.sip_endpt, tdata, NULL, NULL); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); app_perror(THIS_FILE, "Error sending stateless request", status); report_completion(701); return status; } return PJ_SUCCESS;}/* This callback is called when client transaction state has changed */static void tsx_completion_cb(void *token, pjsip_event *event){ pjsip_transaction *tsx; PJ_UNUSED_ARG(token); if (event->type != PJSIP_EVENT_TSX_STATE) return; tsx = event->body.tsx_state.tsx; if (tsx->mod_data[mod_test.id] != NULL) { /* This transaction has been calculated before */ return; } if (tsx->state==PJSIP_TSX_STATE_TERMINATED) { report_completion(tsx->status_code); tsx->mod_data[mod_test.id] = (void*)1; } else if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->state == PJSIP_TSX_STATE_CONFIRMED) { report_completion(tsx->status_code); tsx->mod_data[mod_test.id] = (void*)1; } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { report_completion(tsx->status_code); tsx->mod_data[mod_test.id] = (void*)1; TERMINATE_TSX(tsx, tsx->status_code); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -