⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pjsip-perf.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
#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 + -