📄 pjsip-perf.c
字号:
/* $Id: pjsip-perf.c 1158 2007-04-06 10:25:23Z bennylp $ */
/*
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* \page page_pjsip_perf_c Samples: SIP Performance Benchmark
*
* <b>pjsip-perf</b> is a complete program to measure the
* performance of PJSIP or other SIP endpoints. It consists of two
* parts:
* - the server, to respond incoming requests, and
* - the client, who actively submits requests and measure the
* performance of the server.
*
* Both server and client part can run simultaneously, to measure the
* performance when both endpoints are co-located in a single program.
*
* The server accepts both INVITE and non-INVITE requests.
* The server exports several different types of URL, which would
* control how the request would be handled by the server:
* - URL with "0" as the user part will be handled statelessly.
* It should not be used with INVITE method.
* - URL with "1" as the user part will be handled statefully.
* If the request is an INVITE request, INVITE transaction will
* be created and 200/OK response will be sent, along with a valid
* SDP body. However, the SDP is just a static text body, and
* is not a proper SDP generated by PJMEDIA.
* - URL with "2" as the user part is only meaningful for INVITE
* requests, as it would be handled <b>call-statefully</b> by the
* server. For this URL, the server also would generate SDP dynamically
* and perform a proper SDP negotiation for the incoming call.
* Also for every call, server will limit the call duration to
* 10 seconds, on which the call will be terminated if the client
* doesn't hangup the call.
*
*
*
* This file is pjsip-apps/src/samples/pjsip-perf.c
*
* \includelineno pjsip-perf.c
*/
/* Include all headers. */
#include <pjsip.h>
#include <pjmedia.h>
#include <pjmedia-codec.h>
#include <pjsip_ua.h>
#include <pjsip_simple.h>
#include <pjlib-util.h>
#include <pjlib.h>
#include <stdio.h>
#if defined(PJ_WIN32) && PJ_WIN32!=0
# include <windows.h>
#endif
#define THIS_FILE "pjsip-perf.c"
#define DEFAULT_COUNT (PJSIP_MAX_TSX_COUNT/2>10000?10000:PJSIP_MAX_TSX_COUNT/2)
#define JOB_WINDOW 1000
#define TERMINATE_TSX(x,c)
#ifndef CACHING_POOL_SIZE
# define CACHING_POOL_SIZE (256*1024*1024)
#endif
/* Static message body for INVITE, when stateful processing is
* invoked (instead of call-stateful, where SDP is generated
* dynamically.
*/
static pj_str_t dummy_sdp_str =
{
"v=0\r\n"
"o=- 3360842071 3360842071 IN IP4 192.168.0.68\r\n"
"s=pjmedia\r\n"
"c=IN IP4 192.168.0.68\r\n"
"t=0 0\r\n"
"m=audio 4000 RTP/AVP 0 8 3 103 102 101\r\n"
"a=rtcp:4001 IN IP4 192.168.0.68\r\n"
"a=rtpmap:103 speex/16000\r\n"
"a=rtpmap:102 speex/8000\r\n"
"a=rtpmap:3 GSM/8000\r\n"
"a=rtpmap:0 PCMU/8000\r\n"
"a=rtpmap:8 PCMA/8000\r\n"
"a=sendrecv\r\n"
"a=rtpmap:101 telephone-event/8000\r\n"
"a=fmtp:101 0-15\r\n",
0
};
static pj_str_t mime_application = { "application", 11};
static pj_str_t mime_sdp = {"sdp", 3};
struct srv_state
{
unsigned stateless_cnt;
unsigned stateful_cnt;
unsigned call_cnt;
};
struct app
{
pj_caching_pool cp;
pj_pool_t *pool;
pj_bool_t use_tcp;
pj_str_t local_addr;
int local_port;
pjsip_endpoint *sip_endpt;
pjmedia_endpt *med_endpt;
pj_str_t local_uri;
pj_str_t local_contact;
unsigned skinfo_cnt;
pjmedia_sock_info skinfo[8];
pj_bool_t thread_quit;
unsigned thread_count;
pj_thread_t *thread[16];
pj_bool_t real_sdp;
pjmedia_sdp_session *dummy_sdp;
int log_level;
struct {
pjsip_method method;
pj_str_t dst_uri;
pj_bool_t stateless;
unsigned timeout;
unsigned job_count,
job_submitted,
job_finished,
job_window;
unsigned stat_max_window;
pj_time_val first_request;
pj_time_val requests_sent;
pj_time_val last_completion;
unsigned total_responses;
unsigned response_codes[800];
} client;
struct {
pj_bool_t send_trying;
pj_bool_t send_ringing;
unsigned delay;
struct srv_state prev_state;
struct srv_state cur_state;
} server;
} app;
struct call
{
pjsip_inv_session *inv;
pj_timer_entry ans_timer;
};
static void app_perror(const char *sender, const char *title,
pj_status_t status)
{
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status));
}
/**************************************************************************
* STATELESS SERVER
*/
static pj_bool_t mod_stateless_on_rx_request(pjsip_rx_data *rdata);
/* Module to handle incoming requests statelessly.
*/
static pjsip_module mod_stateless_server =
{
NULL, NULL, /* prev, next. */
{ "mod-stateless-server", 20 }, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
&mod_stateless_on_rx_request, /* on_rx_request() */
NULL, /* on_rx_response() */
NULL, /* on_tx_request. */
NULL, /* on_tx_response() */
NULL, /* on_tsx_state() */
};
static pj_bool_t mod_stateless_on_rx_request(pjsip_rx_data *rdata)
{
const pj_str_t stateless_user = { "0", 1 };
pjsip_uri *uri;
pjsip_sip_uri *sip_uri;
uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
/* Only want to receive SIP scheme */
if (!PJSIP_URI_SCHEME_IS_SIP(uri))
return PJ_FALSE;
sip_uri = (pjsip_sip_uri*) uri;
/* Check for matching user part */
if (pj_strcmp(&sip_uri->user, &stateless_user)!=0)
return PJ_FALSE;
/*
* Yes, this is for us.
*/
/* Ignore ACK request */
if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD)
return PJ_TRUE;
/*
* Respond statelessly with 200/OK.
*/
pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 200, NULL,
NULL, NULL);
app.server.cur_state.stateless_cnt++;
return PJ_TRUE;
}
/**************************************************************************
* STATEFUL SERVER
*/
static pj_bool_t mod_stateful_on_rx_request(pjsip_rx_data *rdata);
/* Module to handle incoming requests statefully.
*/
static pjsip_module mod_stateful_server =
{
NULL, NULL, /* prev, next. */
{ "mod-stateful-server", 19 }, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
&mod_stateful_on_rx_request, /* on_rx_request() */
NULL, /* on_rx_response() */
NULL, /* on_tx_request. */
NULL, /* on_tx_response() */
NULL, /* on_tsx_state() */
};
static pj_bool_t mod_stateful_on_rx_request(pjsip_rx_data *rdata)
{
const pj_str_t stateful_user = { "1", 1 };
pjsip_uri *uri;
pjsip_sip_uri *sip_uri;
uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
/* Only want to receive SIP scheme */
if (!PJSIP_URI_SCHEME_IS_SIP(uri))
return PJ_FALSE;
sip_uri = (pjsip_sip_uri*) uri;
/* Check for matching user part */
if (pj_strcmp(&sip_uri->user, &stateful_user)!=0)
return PJ_FALSE;
/*
* Yes, this is for us.
* Respond statefully with 200/OK.
*/
switch (rdata->msg_info.msg->line.req.method.id) {
case PJSIP_INVITE_METHOD:
{
pjsip_msg_body *body;
if (dummy_sdp_str.slen == 0)
dummy_sdp_str.slen = pj_ansi_strlen(dummy_sdp_str.ptr);
body = pjsip_msg_body_create(rdata->tp_info.pool,
&mime_application, &mime_sdp,
&dummy_sdp_str);
pjsip_endpt_respond(app.sip_endpt, &mod_stateful_server, rdata,
200, NULL, NULL, body, NULL);
}
break;
case PJSIP_ACK_METHOD:
return PJ_TRUE;
default:
pjsip_endpt_respond(app.sip_endpt, &mod_stateful_server, rdata,
200, NULL, NULL, NULL, NULL);
break;
}
app.server.cur_state.stateful_cnt++;
return PJ_TRUE;
}
/**************************************************************************
* CALL SERVER
*/
static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata);
/* Module to handle incoming requests callly.
*/
static pjsip_module mod_call_server =
{
NULL, NULL, /* prev, next. */
{ "mod-call-server", 15 }, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
&mod_call_on_rx_request, /* on_rx_request() */
NULL, /* on_rx_response() */
NULL, /* on_tx_request. */
NULL, /* on_tx_response() */
NULL, /* on_tsx_state() */
};
static pj_status_t send_response(pjsip_inv_session *inv,
pjsip_rx_data *rdata,
int code,
pj_bool_t *has_initial)
{
pjsip_tx_data *tdata;
pj_status_t status;
if (*has_initial) {
status = pjsip_inv_answer(inv, code, NULL, NULL, &tdata);
} else {
status = pjsip_inv_initial_answer(inv, rdata, code,
NULL, NULL, &tdata);
}
if (status != PJ_SUCCESS) {
if (*has_initial) {
status = pjsip_inv_answer(inv, PJSIP_SC_NOT_ACCEPTABLE,
NULL, NULL, &tdata);
} else {
status = pjsip_inv_initial_answer(inv, rdata,
PJSIP_SC_NOT_ACCEPTABLE,
NULL, NULL, &tdata);
}
if (status == PJ_SUCCESS) {
*has_initial = PJ_TRUE;
pjsip_inv_send_msg(inv, tdata);
} else {
pjsip_inv_terminate(inv, 500, PJ_FALSE);
return -1;
}
} else {
*has_initial = PJ_TRUE;
status = pjsip_inv_send_msg(inv, tdata);
if (status != PJ_SUCCESS) {
pjsip_tx_data_dec_ref(tdata);
return status;
}
}
return status;
}
static void answer_timer_cb(pj_timer_heap_t *h, pj_timer_entry *entry)
{
struct call *call = entry->user_data;
pj_bool_t has_initial = PJ_TRUE;
PJ_UNUSED_ARG(h);
entry->id = 0;
send_response(call->inv, NULL, 200, &has_initial);
}
static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata)
{
const pj_str_t call_user = { "2", 1 };
pjsip_uri *uri;
pjsip_sip_uri *sip_uri;
struct call *call;
pjsip_dialog *dlg;
pjmedia_sdp_session *sdp;
pjsip_tx_data *tdata;
pj_bool_t has_initial = PJ_FALSE;
pj_status_t status;
uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
/* Only want to receive SIP scheme */
if (!PJSIP_URI_SCHEME_IS_SIP(uri))
return PJ_FALSE;
sip_uri = (pjsip_sip_uri*) uri;
/* Only want to handle INVITE requests. */
if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
return PJ_FALSE;
}
/* Check for matching user part. Incoming requests will be handled
* call-statefully if:
* - user part is "2", or
* - user part is not "0" nor "1" and method is INVITE.
*/
if (pj_strcmp(&sip_uri->user, &call_user) == 0 ||
sip_uri->user.slen != 1 ||
(*sip_uri->user.ptr != '0' && *sip_uri->user.ptr != '1'))
{
/* Match */
} else {
return PJ_FALSE;
}
/* Verify that we can handle the request. */
if (app.real_sdp) {
unsigned options = 0;
status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
app.sip_endpt, &tdata);
if (status != PJ_SUCCESS) {
/*
* No we can't handle the incoming INVITE request.
*/
if (tdata) {
pjsip_response_addr res_addr;
pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
pjsip_endpt_send_response(app.sip_endpt, &res_addr, tdata,
NULL, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -