diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-07-03 14:18:17 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-07-03 14:18:17 +0000 |
commit | 63147d55f091ec8ba1a5b57cb04b421938ec9fde (patch) | |
tree | 472a6675304f57a815f6f0380ab631373be766a6 /pjsip-apps | |
parent | 589260d10d6915e1f55724099508fc742012b838 (diff) |
Fixed minor bug in pool_caching.c that prevent pool from being reused if the capacity has changed when the pool is released
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@581 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip-apps')
-rw-r--r-- | pjsip-apps/build/Makefile | 20 | ||||
-rw-r--r-- | pjsip-apps/build/pjsip_apps.dsw | 33 | ||||
-rw-r--r-- | pjsip-apps/build/pjsip_perf.dsp | 114 | ||||
-rw-r--r-- | pjsip-apps/build/sample_debug.dsp | 3 | ||||
-rw-r--r-- | pjsip-apps/src/pjsip-perf/handler_call.c | 417 | ||||
-rw-r--r-- | pjsip-apps/src/pjsip-perf/handler_options.c | 154 | ||||
-rw-r--r-- | pjsip-apps/src/pjsip-perf/main.c | 880 | ||||
-rw-r--r-- | pjsip-apps/src/pjsip-perf/pjsip_perf.h | 178 | ||||
-rw-r--r-- | pjsip-apps/src/samples/pjsip-perf.c | 129 |
9 files changed, 94 insertions, 1834 deletions
diff --git a/pjsip-apps/build/Makefile b/pjsip-apps/build/Makefile index 16c916e2..e2fe85a3 100644 --- a/pjsip-apps/build/Makefile +++ b/pjsip-apps/build/Makefile @@ -43,25 +43,12 @@ export PJSUA_LDFLAGS += $(_LDFLAGS) export PJSUA_EXE:=../bin/pjsua-$(TARGET_NAME)$(HOST_EXE) - -############################################################################### -# Defines for building PJSIP-PERF -# -export PJSIPPERF_SRCDIR = ../src/pjsip-perf -export PJSIPPERF_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ - handler_call.o handler_options.o main.o -export PJSIPPERF_CFLAGS += $(_CFLAGS) -export PJSIPPERF_LDFLAGS += $(_LDFLAGS) -export PJSIPPERF_EXE:=../bin/pjsip-perf-$(TARGET_NAME)$(HOST_EXE) - - - export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT ############################################################################### # Main entry # # -TARGETS := pjsua pjsip-perf samples +TARGETS := pjsua samples .PHONY: $(TARGETS) @@ -78,9 +65,6 @@ distclean: realclean pjsua: $(MAKE) -f $(RULES_MAK) APP=PJSUA app=pjsua $(PJSUA_EXE) -pjsip-perf: - $(MAKE) -f $(RULES_MAK) APP=PJSIPPERF app=pjsip-perf $(PJSUA_EXE) - samples: $(MAKE) -f Samples.mak @@ -90,11 +74,9 @@ samples: clean depend realclean: $(MAKE) -f $(RULES_MAK) APP=PJSUA app=pjsua $@ - $(MAKE) -f $(RULES_MAK) APP=PJSIPPERF app=pjsip-perf $@ $(MAKE) -f Samples.mak $@ @if test "$@" = "depend"; then \ echo '$(PJSUA_EXE): $(PJSIP_LIB) $(PJSIP_UA_LIB) $(PJSIP_SIMPLE) $(PJSUA_LIB_LIB) $(PJLIB_LIB) $(PJLIB_UTIL_LIB) $(PJMEDIA_LIB) $(PJMEDIA_CODEC_LIB) Makefile' >> .pjsua-$(TARGET_NAME).depend; \ - echo '$(PJSIPPERF_EXE): $(PJSIP_LIB) $(PJSIP_UA_LIB) $(PJSIP_SIMPLE) $(PJSUA_LIB_LIB) $(PJLIB_LIB) $(PJLIB_UTIL_LIB) $(PJMEDIA_LIB) $(PJMEDIA_CODEC_LIB)' >> .pjsip-perf-$(TARGET_NAME).depend; \ fi diff --git a/pjsip-apps/build/pjsip_apps.dsw b/pjsip-apps/build/pjsip_apps.dsw index 240e30a5..72cf939e 100644 --- a/pjsip-apps/build/pjsip_apps.dsw +++ b/pjsip-apps/build/pjsip_apps.dsw @@ -63,39 +63,6 @@ Package=<4> ############################################################################### -Project: "pjsip_perf"=".\pjsip_perf.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name pjlib - End Project Dependency - Begin Project Dependency - Project_Dep_Name pjlib_util - End Project Dependency - Begin Project Dependency - Project_Dep_Name pjsip_core - End Project Dependency - Begin Project Dependency - Project_Dep_Name pjsip_simple - End Project Dependency - Begin Project Dependency - Project_Dep_Name pjsip_ua - End Project Dependency - Begin Project Dependency - Project_Dep_Name pjsua_lib - End Project Dependency - Begin Project Dependency - Project_Dep_Name pjmedia - End Project Dependency -}}} - -############################################################################### - Project: "pjsip_simple"="..\..\pjsip\build\pjsip_simple.dsp" - Package Owner=<4> Package=<5> diff --git a/pjsip-apps/build/pjsip_perf.dsp b/pjsip-apps/build/pjsip_perf.dsp deleted file mode 100644 index c6402062..00000000 --- a/pjsip-apps/build/pjsip_perf.dsp +++ /dev/null @@ -1,114 +0,0 @@ -# Microsoft Developer Studio Project File - Name="pjsip_perf" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=pjsip_perf - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "pjsip_perf.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "pjsip_perf.mak" CFG="pjsip_perf - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "pjsip_perf - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "pjsip_perf - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "pjsip_perf - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\output\pjsip-perf-i386-win32-vc6-release" -# PROP BASE Intermediate_Dir ".\output\pjsip-perf-i386-win32-vc6-release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".\output\pjsip-perf-i386-win32-vc6-release" -# PROP Intermediate_Dir ".\output\pjsip-perf-i386-win32-vc6-release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W4 /GX /O2 /I "../../pjsip/include" /I "../../pjmedia/include" /I "../../pjlib-util/include" /I "../../pjlib/include" /D "NDEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ole32.lib user32.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\pjsip-perf-i386-win32-vc6.exe" - -!ELSEIF "$(CFG)" == "pjsip_perf - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir ".\output\pjsip-perf-i386-win32-vc6-debug" -# PROP BASE Intermediate_Dir ".\output\pjsip-perf-i386-win32-vc6-debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".\output\pjsip-perf-i386-win32-vc6-debug" -# PROP Intermediate_Dir ".\output\pjsip-perf-i386-win32-vc6-debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../../pjsip/include" /I "../../pjmedia/include" /I "../../pjlib-util/include" /I "../../pjlib/include" /D "_DEBUG" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ole32.lib user32.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /debug /machine:I386 /out:"..\bin\pjsip-perf-i386-win32-vc6d.exe" - -!ENDIF - -# Begin Target - -# Name "pjsip_perf - Win32 Release" -# Name "pjsip_perf - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE="..\src\pjsip-perf\handler_call.c" -# End Source File -# Begin Source File - -SOURCE="..\src\pjsip-perf\handler_options.c" -# End Source File -# Begin Source File - -SOURCE="..\src\pjsip-perf\main.c" -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE="..\src\pjsip-perf\pjsip_perf.h" -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/pjsip-apps/build/sample_debug.dsp b/pjsip-apps/build/sample_debug.dsp index a6af92cb..1cf451c4 100644 --- a/pjsip-apps/build/sample_debug.dsp +++ b/pjsip-apps/build/sample_debug.dsp @@ -42,7 +42,8 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../pjsip/include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjmedia/include" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /I "../../pjsip/include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjmedia/include" /D PJ_WIN32=1 /D PJ_M_I386=1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe diff --git a/pjsip-apps/src/pjsip-perf/handler_call.c b/pjsip-apps/src/pjsip-perf/handler_call.c deleted file mode 100644 index bc7ae339..00000000 --- a/pjsip-apps/src/pjsip-perf/handler_call.c +++ /dev/null @@ -1,417 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2006 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 - */ -#include "pjsip_perf.h" - -/* - * This file handles call generation and incoming calls. - */ -#define THIS_FILE "handler_call.c" - -/* - * Dummy SDP. - */ -static pjmedia_sdp_session *local_sdp; - - -#define TIMER_ID 1234 - -/* Call data, to be attached to invite session. */ -struct call_data -{ - pjsip_inv_session *inv; - pj_bool_t confirmed; - pj_timer_entry bye_timer; - void *test_data; - void (*completion_cb)(void*,pj_bool_t); -}; - - -/**************************************************************************** - * - * INCOMING CALL HANDLER - * - **************************************************************************** - */ - - -static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata); - -/* The module instance. */ -static pjsip_module mod_call = -{ - NULL, NULL, /* prev, next. */ - { "mod-perf-call", 13 }, /* 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() */ -}; - - - -/* - * Handle incoming requests. - * Because this module is registered to the INVITE module too, this - * callback may be called for requests inside a dialog. - */ -static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata) -{ - pjsip_msg *msg = rdata->msg_info.msg; - pjsip_dialog *dlg; - pjsip_inv_session *inv; - pjsip_tx_data *response; - struct call_data *call_data; - unsigned options; - pj_status_t status; - - - /* Don't want to handle anything but INVITE */ - if (msg->line.req.method.id != PJSIP_INVITE_METHOD) - return PJ_FALSE; - - /* Don't want to handle request that's already associated with - * existing dialog or transaction. - */ - if (pjsip_rdata_get_dlg(rdata) || pjsip_rdata_get_tsx(rdata)) - return PJ_FALSE; - - - /* Verify that we can handle the request. */ - options = 0; - status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, - settings.endpt, &response); - if (status != PJ_SUCCESS) { - - /* - * No we can't handle the incoming INVITE request. - */ - - if (response) { - pjsip_response_addr res_addr; - - pjsip_get_response_addr(response->pool, rdata, &res_addr); - pjsip_endpt_send_response(settings.endpt, &res_addr, response, - NULL, NULL); - - } else { - - /* Respond with 500 (Internal Server Error) */ - pjsip_endpt_respond_stateless(settings.endpt, rdata, 500, NULL, - NULL, NULL); - } - - return PJ_TRUE; - } - - /* - * Yes we can handle the incoming INVITE request. - */ - - /* Create dialog. */ - status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dlg); - if (status != PJ_SUCCESS) { - pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL); - return PJ_TRUE; - } - - /* Create invite session: */ - status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &inv); - if (status != PJ_SUCCESS) { - - pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL); - - // TODO: Need to delete dialog - return PJ_TRUE; - } - - /* Create and associate call data. */ - call_data = pj_pool_zalloc(inv->pool, sizeof(struct call_data)); - call_data->inv = inv; - call_data->bye_timer.user_data = call_data; - inv->mod_data[mod_call.id] = call_data; - - /* Answer with 200 straight away. */ - status = pjsip_inv_initial_answer(inv, rdata, 200, - NULL, NULL, &response); - if (status != PJ_SUCCESS) { - - app_perror(THIS_FILE, "Unable to create 200 response", status); - - pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL); - - // TODO: Need to delete dialog - - } else { - status = pjsip_inv_send_msg(inv, response); - if (status != PJ_SUCCESS) - app_perror(THIS_FILE, "Unable to send 100 response", status); - } - - - return PJ_TRUE; -} - - -/**************************************************************************** - * - * OUTGOING CALL GENERATOR - * - **************************************************************************** - */ - -/** - * Make outgoing call. - */ -pj_status_t call_spawn_test( const pj_str_t *target, - const pj_str_t *from, - const pj_str_t *to, - unsigned cred_cnt, - const pjsip_cred_info cred[], - const pjsip_route_hdr *route_set, - void *test_data, - void (*completion_cb)(void*,pj_bool_t)) -{ - pjsip_dialog *dlg; - pjsip_inv_session *inv; - pjsip_tx_data *tdata; - struct call_data *call_data; - pj_status_t status; - - /* Create outgoing dialog: */ - status = pjsip_dlg_create_uac( pjsip_ua_instance(), - from, NULL, - to, target, - &dlg); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Dialog creation failed", status); - return status; - } - - /* Create the INVITE session: */ - status = pjsip_inv_create_uac( dlg, local_sdp, 0, &inv); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Invite session creation failed", status); - goto on_error; - } - - - /* Set dialog Route-Set: */ - if (route_set) - pjsip_dlg_set_route_set(dlg, route_set); - - - /* Set credentials: */ - pjsip_auth_clt_set_credentials( &dlg->auth_sess, cred_cnt, cred); - - - /* Create initial INVITE: */ - status = pjsip_inv_invite(inv, &tdata); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to create initial INVITE request", - status); - goto on_error; - } - - - /* Create and associate our call data */ - call_data = pj_pool_zalloc(inv->pool, sizeof(struct call_data)); - call_data->inv = inv; - call_data->test_data = test_data; - call_data->bye_timer.user_data = call_data; - call_data->completion_cb = completion_cb; - - inv->mod_data[mod_call.id] = call_data; - - - /* Send initial INVITE: */ - status = pjsip_inv_send_msg(inv, tdata); - if (status != PJ_SUCCESS) { - app_perror( THIS_FILE, "Unable to send initial INVITE request", - status); - goto on_error; - } - - - return PJ_SUCCESS; - - -on_error: - PJ_TODO(DESTROY_DIALOG_ON_FAIL); - return status; -} - - -/* Timer callback to send BYE. */ -static void bye_callback( pj_timer_heap_t *ht, pj_timer_entry *e) -{ - struct call_data *call_data = e->user_data; - pjsip_tx_data *tdata; - pj_status_t status; - - PJ_UNUSED_ARG(ht); - PJ_UNUSED_ARG(e); - - e->id = 0; - - status = pjsip_inv_end_session(call_data->inv, PJSIP_SC_REQUEST_TIMEOUT, - NULL, &tdata); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to create BYE", status); - return; - } - - status = pjsip_inv_send_msg(call_data->inv, tdata); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to send BYE", status); - return; - } - -} - -/* - * This callback receives notification from invite session when the - * session state has changed. - */ -static void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e) -{ - struct call_data *call_data; - - PJ_UNUSED_ARG(e); - - call_data = inv->mod_data[mod_call.id]; - if (call_data == NULL) - return; - - /* Once call has been confirmed, schedule timer to terminate the call. */ - if (inv->state == PJSIP_INV_STATE_CONFIRMED) { - - pj_time_val interval; - - call_data->confirmed = PJ_TRUE; - - /* For UAC, schedule time to send BYE. - * For UAS, schedule time to disconnect INVITE, just in case BYE - * is not received. - */ - if (inv->role == PJSIP_ROLE_UAC) - interval.sec = settings.duration, interval.msec = 0; - else - interval.sec = settings.duration+5, interval.msec = 0; - - call_data->bye_timer.id = TIMER_ID; - call_data->bye_timer.cb = &bye_callback; - pjsip_endpt_schedule_timer(settings.endpt, &call_data->bye_timer, - &interval); - - } - /* If call has been terminated, cancel our timer, if any. - * And call tester's callback. - */ - else if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { - - /* Cancel timer, if any. */ - if (call_data->bye_timer.id == TIMER_ID) { - call_data->bye_timer.id = 0; - pjsip_endpt_cancel_timer(settings.endpt, &call_data->bye_timer); - } - - /* Detach call data from the invite session. */ - inv->mod_data[mod_call.id] = NULL; - - /* Call tester callback. */ - if (call_data->completion_cb) { - (*call_data->completion_cb)(call_data->test_data, - call_data->confirmed); - } - } -} - - -/* - * This callback is called by invite session framework when UAC session - * has forked. - */ -static void call_on_forked( pjsip_inv_session *inv, pjsip_event *e) -{ - PJ_UNUSED_ARG(inv); - PJ_UNUSED_ARG(e); - - PJ_TODO(HANDLE_FORKED_DIALOG); -} - - - -/**************************************************************************** - * - * INITIALIZATION - * - **************************************************************************** - */ - -pj_status_t call_handler_init(void) -{ - pjsip_inv_callback inv_cb; - pjmedia_sock_info skinfo; - pj_status_t status; - - /* Register incoming call handler. */ - status = pjsip_endpt_register_module(settings.endpt, &mod_call); - if (status != PJ_SUCCESS) { - app_perror( THIS_FILE, "Unable to register call handler", - status); - return status; - } - - /* Invite session callback: */ - pj_memset(&inv_cb, 0, sizeof(inv_cb)); - inv_cb.on_state_changed = &call_on_state_changed; - inv_cb.on_new_session = &call_on_forked; - - /* Initialize invite session module: */ - status = pjsip_inv_usage_init(settings.endpt, &inv_cb); - if (status != PJ_SUCCESS) { - app_perror( THIS_FILE, "Unable to initialize INVITE session module", - status); - return status; - } - - /* Create dummy SDP. */ - pj_memset(&skinfo, 0, sizeof(skinfo)); - pj_sockaddr_in_init(&skinfo.rtp_addr_name, pj_gethostname(), 4000); - pj_sockaddr_in_init(&skinfo.rtcp_addr_name, pj_gethostname(), 4001); - - status = pjmedia_endpt_create_sdp( settings.med_endpt, settings.pool, - 1, &skinfo, &local_sdp); - if (status != PJ_SUCCESS) { - app_perror( THIS_FILE, "Unable to generate local SDP", - status); - return status; - } - - return PJ_SUCCESS; -} - - diff --git a/pjsip-apps/src/pjsip-perf/handler_options.c b/pjsip-apps/src/pjsip-perf/handler_options.c deleted file mode 100644 index bd14a724..00000000 --- a/pjsip-apps/src/pjsip-perf/handler_options.c +++ /dev/null @@ -1,154 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2006 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 - */ -#include "pjsip_perf.h" - - -/* - * This file handles OPTIONS generator and incoming OPTIONS requests. - */ -#define THIS_FILE "handler_options.c" - - -/**************************************************************************** - * - * INCOMING OPTIONS HANDLER - * - **************************************************************************** - */ - - -static pj_bool_t mod_options_on_rx_request(pjsip_rx_data *rdata); - - -/* The module instance. */ -static pjsip_module mod_perf_options = -{ - NULL, NULL, /* prev, next. */ - { "mod-perf-options", 16 }, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &mod_options_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_options_on_rx_request(pjsip_rx_data *rdata) -{ - pjsip_msg *msg = rdata->msg_info.msg; - - if (msg->line.req.method.id == PJSIP_OPTIONS_METHOD) { - - if (settings.stateless) { - pjsip_endpt_respond_stateless( settings.endpt, rdata, 200, NULL, - NULL, NULL); - } else { - - pjsip_endpt_respond( settings.endpt, NULL, rdata, 200, NULL, - NULL, NULL, NULL); - } - - return PJ_TRUE; - } - - return PJ_FALSE; -} - - -/**************************************************************************** - * - * OUTGOING OPTIONS GENERATOR. - * - **************************************************************************** - */ - -struct callback_data -{ - void *test_data; - void (*completion_cb)(void*,pj_bool_t); -}; - -static void options_callback(void *token, const pjsip_event *e) -{ - struct callback_data *cb_data = token; - - if (e->type == PJSIP_EVENT_TSX_STATE) { - (*cb_data->completion_cb)(cb_data->test_data, - e->body.tsx_state.tsx->status_code/100==2); - } -} - -pj_status_t options_spawn_test(const pj_str_t *target, - const pj_str_t *from, - const pj_str_t *to, - unsigned cred_cnt, - const pjsip_cred_info cred[], - const pjsip_route_hdr *route_set, - void *test_data, - void (*completion_cb)(void*,pj_bool_t)) -{ - pj_status_t status; - struct callback_data *cb_data; - pjsip_tx_data *tdata; - - PJ_LOG(5,(THIS_FILE,"Sending OPTIONS request..")); - - PJ_UNUSED_ARG(route_set); - PJ_UNUSED_ARG(cred_cnt); - PJ_UNUSED_ARG(cred); - - status = pjsip_endpt_create_request( settings.endpt, - &pjsip_options_method, - target, - from, - to, - NULL, NULL, -1, NULL, - &tdata); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to create request", status); - return status; - } - - cb_data = pj_pool_alloc(tdata->pool, sizeof(struct callback_data)); - cb_data->test_data = test_data; - cb_data->completion_cb = completion_cb; - - status = pjsip_endpt_send_request( settings.endpt, tdata, -1, - cb_data, &options_callback); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to send request", status); - return status; - } - - return PJ_SUCCESS; -} - - -pj_status_t options_handler_init(void) -{ - return pjsip_endpt_register_module(settings.endpt, &mod_perf_options); -} - - diff --git a/pjsip-apps/src/pjsip-perf/main.c b/pjsip-apps/src/pjsip-perf/main.c deleted file mode 100644 index da590248..00000000 --- a/pjsip-apps/src/pjsip-perf/main.c +++ /dev/null @@ -1,880 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2006 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 - */ -#include "pjsip_perf.h" -#include <stdlib.h> /* atoi */ - -#define THIS_FILE "main.c" - -pjsip_perf_settings settings; - -/* Show error message. */ -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(3,(sender, "%s: %s [code=%d]", title, errmsg, status)); -} - - -/* Init default settings. */ -static void init_settings(void) -{ - pj_status_t status; - - settings.stateless = 0; - settings.start_rate = 10; - settings.max_capacity = 64; - settings.duration = 0; - settings.thread_cnt = 1; - settings.local_port = 5060; - settings.log_level = 3; - settings.app_log_level = 3; - - pjsip_method_set(&settings.method, PJSIP_OPTIONS_METHOD); - - pj_init(); - - /* Create caching pool. */ - pj_caching_pool_init(&settings.cp, &pj_pool_factory_default_policy, - 4 * 1024 * 1024); - - /* Create application pool. */ - settings.pool = pj_pool_create(&settings.cp.factory, "pjsip-perf", 1024, - 1024, NULL); - - /* Create endpoint. */ - status = pjsip_endpt_create(&settings.cp.factory, NULL, &settings.endpt); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to create endpoint", status); - return; - } - -} - -/* Poll function. */ -static int PJ_THREAD_FUNC poll_pjsip(void *arg) -{ - pj_status_t last_err = 0; - - PJ_UNUSED_ARG(arg); - - do { - pj_time_val timeout = { 0, 10 }; - pj_status_t status; - - status = pjsip_endpt_handle_events (settings.endpt, &timeout); - if (status != last_err) { - last_err = status; - app_perror(THIS_FILE, "handle_events() returned error", status); - } - } while (!settings.quit_flag); - - return 0; -} - -/***************************************************************************** - * This is a simple module to count and log messages - */ -static void on_rx_msg(pjsip_rx_data *rdata) -{ - PJ_LOG(5,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" - "%s\n" - "--end msg--", - rdata->msg_info.len, - pjsip_rx_data_get_info(rdata), - rdata->pkt_info.src_name, - rdata->pkt_info.src_port, - rdata->msg_info.msg_buf)); -} - -static void on_tx_msg(pjsip_tx_data *tdata) -{ - PJ_LOG(5,(THIS_FILE, "TX %d bytes %s to %s:%d:\n" - "%s\n" - "--end msg--", - (tdata->buf.cur - tdata->buf.start), - pjsip_tx_data_get_info(tdata), - tdata->tp_info.dst_name, - tdata->tp_info.dst_port, - tdata->buf.start)); -} - -static pj_bool_t mod_counter_on_rx_request(pjsip_rx_data *rdata) -{ - settings.rx_req++; - on_rx_msg(rdata); - return PJ_FALSE; -} - -static pj_bool_t mod_counter_on_rx_response(pjsip_rx_data *rdata) -{ - settings.rx_res++; - on_rx_msg(rdata); - return PJ_FALSE; -} - -static pj_status_t mod_counter_on_tx_request(pjsip_tx_data *tdata) -{ - settings.tx_req++; - on_tx_msg(tdata); - return PJ_SUCCESS; -} - -static pj_status_t mod_counter_on_tx_response(pjsip_tx_data *tdata) -{ - settings.tx_res++; - on_tx_msg(tdata); - return PJ_SUCCESS; -} - -static pjsip_module mod_counter = -{ - NULL, NULL, /* prev, next. */ - { "mod-counter", 11 }, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &mod_counter_on_rx_request, /* on_rx_request() */ - &mod_counter_on_rx_response, /* on_rx_response() */ - &mod_counter_on_tx_request, /* on_tx_request. */ - &mod_counter_on_tx_response, /* on_tx_response() */ - NULL, /* on_tsx_state() */ - -}; - - -/***************************************************************************** - * Console application custom logging: - */ - - -static FILE *log_file; -static void app_log_writer(int level, const char *buffer, int len) -{ - /* Write to both stdout and file. */ - if (level <= settings.app_log_level) - pj_log_write(level, buffer, len); - - if (log_file) { - fwrite(buffer, len, 1, log_file); - fflush(log_file); - } -} - - -static pj_status_t app_logging_init(void) -{ - /* Redirect log function to ours */ - - pj_log_set_log_func( &app_log_writer ); - - /* If output log file is desired, create the file: */ - - if (settings.log_file) { - log_file = fopen(settings.log_file, "wt"); - if (log_file == NULL) { - PJ_LOG(1,(THIS_FILE, "Unable to open log file %s", - settings.log_file)); - return -1; - } - } - - return PJ_SUCCESS; -} - - -void app_logging_shutdown(void) -{ - /* Close logging file, if any: */ - if (log_file) { - fclose(log_file); - log_file = NULL; - } -} - - -/* Initialize */ -static pj_status_t initialize(void) -{ - pj_sockaddr_in addr; - int i; - pj_status_t status; - - /* Init logging */ - if (app_logging_init() != PJ_SUCCESS) - return -1; - - /* Create UDP transport. */ - pj_memset(&addr, 0, sizeof(addr)); - addr.sin_family = PJ_AF_INET; - addr.sin_port = pj_htons((pj_uint16_t)settings.local_port); - status = pjsip_udp_transport_start(settings.endpt, &addr, NULL, - settings.thread_cnt, NULL); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to start UDP transport", status); - return status; - } - - - /* Initialize transaction layer: */ - status = pjsip_tsx_layer_init_module(settings.endpt); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Transaction layer initialization error", - status); - return status; - } - - /* Initialize UA layer module: */ - pjsip_ua_init_module( settings.endpt, NULL ); - - /* Init core SIMPLE module : */ - pjsip_evsub_init_module(settings.endpt); - - /* Init presence module: */ - pjsip_pres_init_module( settings.endpt, pjsip_evsub_instance()); - - /* Init xfer/REFER module */ - pjsip_xfer_init_module( settings.endpt ); - - /* Init multimedia endpoint. */ - status = pjmedia_endpt_create(&settings.cp.factory, - pjsip_endpt_get_ioqueue(settings.endpt), 0, - &settings.med_endpt); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to create media endpoint", - status); - return status; - } - - /* Init OPTIONS test handler */ - status = options_handler_init(); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to create OPTIONS handler", status); - return status; - } - - /* Init call test handler */ - status = call_handler_init(); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to initialize call handler", status); - return status; - } - - - /* Register message counter module. */ - status = pjsip_endpt_register_module(settings.endpt, &mod_counter); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to register module", status); - return status; - } - - /* Start worker thread. */ - for (i=0; i<settings.thread_cnt; ++i) { - status = pj_thread_create(settings.pool, "pjsip-perf", &poll_pjsip, - NULL, 0, 0, &settings.thread[i]); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Unable to create thread", status); - return status; - } - } - - pj_log_set_level(settings.log_level); - return PJ_SUCCESS; -} - - -/* Shutdown */ -static void shutdown(void) -{ - int i; - - /* Signal and wait worker thread to quit. */ - settings.quit_flag = 1; - - for (i=0; i<settings.thread_cnt; ++i) { - pj_thread_join(settings.thread[i]); - pj_thread_destroy(settings.thread[i]); - } - - pjsip_endpt_destroy(settings.endpt); - pj_caching_pool_destroy(&settings.cp); -} - - -/* Verify that valid SIP url is given. */ -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(&settings.cp.factory, "check%p", 1024, 0, NULL); - if (!pool) return -1; - - url = pj_pool_alloc(pool, len+1); - pj_ansi_strcpy(url, c_url); - - 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; -} - - - -/* Usage */ -static void usage(void) -{ - puts("Usage:"); - puts(" pjsip-perf [options] [target]"); - puts("where"); - puts(" target Optional default target URL"); - puts(""); - puts("General options:"); - puts(" --help Display this help screen"); - puts(" --version Display version info"); - puts(""); - puts("Logging options:"); - puts(" --log-level=N Set log verbosity (default=3)"); - puts(" --app-log-level=N Set screen log verbosity (default=3)"); - puts(" --log-file=FILE Save log to FILE"); - puts(""); - puts("SIP options:"); - puts(" --local-port=N SIP local port"); - puts(" --stateless Handle incoming request statelessly if possible"); - puts(" --thread-cnt=N Number of worker threads (default=1)"); - puts(""); - puts("Rate control:"); - puts(" --start-rate=N Start rate in tasks per seconds (default=1)"); - puts(""); - puts("Capacity control:"); - puts(" --max-capacity=N Maximum outstanding sessions (default=64)"); - puts(""); - puts("Duration control:"); - puts(" --duration=secs Sessions duration (default=0)"); - puts(""); -} - - -/* Read options. */ -static pj_status_t parse_options(int argc, char *argv[]) -{ - enum { - OPT_HELP, - OPT_VERSION, - OPT_LOG_LEVEL, - OPT_APP_LOG_LEVEL, - OPT_LOG_FILE, - OPT_LOCAL_PORT, - OPT_STATELESS, - OPT_THREAD_CNT, - OPT_START_RATE, - OPT_MAX_CAPACITY, - OPT_DURATION - }; - struct pj_getopt_option long_opts[] = { - { "help", 0, 0, OPT_HELP}, - { "version", 0, 0, OPT_VERSION}, - { "log-level", 1, 0, OPT_LOG_LEVEL}, - { "app-log-level", 1, 0, OPT_APP_LOG_LEVEL}, - { "log-file", 1, 0, OPT_LOG_FILE}, - { "local-port", 1, 0, OPT_LOCAL_PORT}, - { "stateless", 0, 0, OPT_STATELESS}, - { "thread-cnt", 1, 0, OPT_THREAD_CNT}, - { "start-rate", 1, 0, OPT_START_RATE}, - { "max-capacity", 1, 0, OPT_MAX_CAPACITY}, - { "duration", 1, 0, OPT_DURATION}, - { NULL, 0, 0, 0} - }; - int c, option_index; - - pj_optind = 0; - while ((c=pj_getopt_long(argc, argv, "", long_opts, &option_index)) != -1) { - switch (c) { - - case OPT_HELP: - usage(); - return PJ_EINVAL; - - case OPT_VERSION: - pj_dump_config(); - return PJ_EINVAL; - - case OPT_LOG_LEVEL: - settings.log_level = atoi(pj_optarg); - break; - - case OPT_APP_LOG_LEVEL: - settings.app_log_level = atoi(pj_optarg); - break; - - case OPT_LOG_FILE: - settings.log_file = pj_optarg; - break; - - case OPT_LOCAL_PORT: - settings.local_port = atoi(pj_optarg); - if (settings.local_port < 1 || settings.local_port > 65535) { - PJ_LOG(1,(THIS_FILE,"Invalid --local-port %s", pj_optarg)); - return PJ_EINVAL; - } - break; - - case OPT_STATELESS: - settings.stateless = 1; - break; - - case OPT_THREAD_CNT: - settings.thread_cnt = atoi(pj_optarg); - if (settings.thread_cnt < 1 || - settings.thread_cnt > PJ_ARRAY_SIZE(settings.thread)) - { - PJ_LOG(1,(THIS_FILE,"Invalid --thread-cnt %s", pj_optarg)); - return PJ_EINVAL; - } - break; - - case OPT_START_RATE: - settings.start_rate = atoi(pj_optarg); - if (settings.start_rate < 1 || settings.start_rate > 1000000) { - PJ_LOG(1,(THIS_FILE,"Invalid --start-rate %s", pj_optarg)); - return PJ_EINVAL; - } - break; - - case OPT_MAX_CAPACITY: - settings.max_capacity = atoi(pj_optarg); - if (settings.max_capacity < 1 || settings.max_capacity > 65000) { - PJ_LOG(1,(THIS_FILE, - "Invalid --max-capacity %s (range=1-65000)", - pj_optarg)); - return PJ_EINVAL; - } - break; - - case OPT_DURATION: - settings.duration = atoi(pj_optarg); - if (settings.duration < 0 || settings.duration > 1000000) { - PJ_LOG(1,(THIS_FILE,"Invalid --duration %s", pj_optarg)); - return PJ_EINVAL; - } - break; - - } - } - - if (pj_optind != argc) { - if (verify_sip_url(argv[pj_optind]) != PJ_SUCCESS) { - PJ_LOG(3,(THIS_FILE, "Invalid SIP URL %s", argv[pj_optind])); - return PJ_EINVAL; - } - - settings.target = pj_str(argv[pj_optind]); - ++pj_optind; - } - - if (pj_optind != argc) { - printf("Error: unknown options %s\n", argv[pj_optind]); - return PJ_EINVAL; - } - - return PJ_SUCCESS; -} - - -static void spawn_batch( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry ); - -/* Completion callback. */ -static void completion_cb(void *token, pj_bool_t success) -{ - batch *batch = token; - - if (success) - batch->success++; - else - batch->failed++; - - if (batch->success+batch->failed == batch->rate) { - pj_time_val elapsed, sess_elapsed; - unsigned msec; - - pj_gettimeofday(&batch->end_time); - elapsed = sess_elapsed = batch->end_time; - - /* Batch time. */ - PJ_TIME_VAL_SUB(elapsed, batch->start_time); - msec = PJ_TIME_VAL_MSEC(elapsed); - if (msec == 0) msec = 1; - - /* Session time */ - PJ_TIME_VAL_SUB(sess_elapsed, settings.session->start_time); - - /* Spawn time */ - PJ_TIME_VAL_SUB(batch->spawned_time, batch->start_time); - - if (batch->failed) { - PJ_LOG(2,(THIS_FILE, - "%02d:%02d:%02d: %d tasks in %d.%ds (%d tasks/sec), " - "spawn=time=%d.%d, FAILED=%d", - (sess_elapsed.sec / 3600), - (sess_elapsed.sec % 3600) / 60, - (sess_elapsed.sec % 60), - batch->rate, - elapsed.sec, elapsed.msec, - batch->rate * 1000 / msec, - batch->spawned_time.sec, - batch->spawned_time.msec, - batch->failed)); - } else { - PJ_LOG(3,(THIS_FILE, - "%02d:%02d:%02d: %d tasks in %d.%ds (%d tasks/sec), " - "spawn=time=%d.%d", - (sess_elapsed.sec / 3600), - (sess_elapsed.sec % 3600) / 60, - (sess_elapsed.sec % 60), - batch->rate, - elapsed.sec, elapsed.msec, - batch->rate * 1000 / msec, - batch->spawned_time.sec, - batch->spawned_time.msec)); - } - - if (!settings.session->stopping) { - pj_time_val interval; - - if (msec >= 1000) - interval.sec = interval.msec = 0; - else - interval.sec = 0, interval.msec = 1000-msec; - - settings.timer.cb = &spawn_batch; - pjsip_endpt_schedule_timer( settings.endpt, &settings.timer, &interval); - } else { - PJ_LOG(3,(THIS_FILE, "%.*s test session completed", - (int)settings.session->method.name.slen, - settings.session->method.name.ptr)); - pj_pool_release(settings.session->pool); - settings.session = NULL; - } - } -} - -/* Spawn new batch. */ -static void spawn_batch( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry ) -{ - session *sess = settings.session; - batch *batch; - pj_status_t status = PJ_SUCCESS; - pjsip_cred_info cred_info[1]; - pj_time_val elapsed; - - unsigned i; - - PJ_UNUSED_ARG(timer_heap); - PJ_UNUSED_ARG(entry); - - if (!pj_list_empty(&sess->free_list)) { - batch = sess->free_list.next; - pj_list_erase(batch); - } else { - batch = pj_pool_alloc(sess->pool, sizeof(struct batch)); - } - - pj_gettimeofday(&batch->start_time); - batch->rate = settings.cur_rate; - batch->started = 0; - batch->success = 0; - batch->failed = 0; - pj_gettimeofday(&batch->start_time); - batch->spawned_time = batch->start_time; - - pj_list_push_back(&sess->active_list, batch); - - for (i=0; i<batch->rate; ++i) { - pj_str_t from = { "sip:user@127.0.0.1", 18}; - - if (sess->method.id == PJSIP_OPTIONS_METHOD) { - status = options_spawn_test(&settings.target, &from, - &settings.target, - 0, cred_info, NULL, batch, - &completion_cb); - } else if (sess->method.id == PJSIP_INVITE_METHOD) { - status = call_spawn_test( &settings.target, &from, - &settings.target, - 0, cred_info, NULL, batch, - &completion_cb); - } - if (status != PJ_SUCCESS) - break; - - batch->started++; - - elapsed.sec = elapsed.msec = 0; - pjsip_endpt_handle_events(settings.endpt, &elapsed); - } - - pj_gettimeofday(&batch->spawned_time); - - /// -#if 0 - elapsed = batch->spawned_time; - PJ_TIME_VAL_SUB(elapsed, batch->start_time); - PJ_LOG(2,(THIS_FILE, "%d requests sent in %d ms", batch->started, - PJ_TIME_VAL_MSEC(elapsed))); -#endif - - sess->total_created += batch->started; - - batch = sess->active_list.next; - sess->outstanding = 0; - while (batch != &sess->active_list) { - sess->outstanding += (batch->started - batch->success - batch->failed); - - if (batch->started == batch->success + batch->failed) { - struct batch *next = batch->next; - pj_list_erase(batch); - pj_list_push_back(&sess->free_list, batch); - batch = next; - } else { - batch = batch->next; - } - } -} - - -/* Start new session */ -static void start_session(pj_bool_t auto_repeat) -{ - pj_time_val interval = { 0, 0 }; - pj_pool_t *pool; - session *sess; - - pool = pjsip_endpt_create_pool(settings.endpt, "session", 4000, 4000); - if (!pool) { - app_perror(THIS_FILE, "Unable to create pool", PJ_ENOMEM); - return; - } - - sess = pj_pool_zalloc(pool, sizeof(session)); - sess->pool = pool; - sess->stopping = auto_repeat ? 0 : 1; - sess->method = settings.method; - - pj_list_init(&sess->active_list); - pj_list_init(&sess->free_list); - pj_gettimeofday(&sess->start_time); - - settings.session = sess; - - settings.timer.cb = &spawn_batch; - pjsip_endpt_schedule_timer( settings.endpt, &settings.timer, &interval); -} - - -/* Dump state */ -static void dump(pj_bool_t detail) -{ - pjsip_endpt_dump(settings.endpt, detail); - pjsip_tsx_layer_dump(detail); - pjsip_ua_dump(detail); -} - - -/* help screen */ -static void help_screen(void) -{ - puts ("+============================================================================+"); - printf("| Current mode: %-10s Current rate: %-5d Call Capacity: %-7d |\n", - settings.method.name.ptr, settings.cur_rate, settings.max_capacity); - printf("| Call Duration: %-7d |\n", - settings.duration); - - printf("| Total tx requests: %-7u rx requests: %-7u |\n", - settings.tx_req, settings.rx_req); - printf("| tx responses: %-7u rx responses: %-7u |\n", - settings.tx_res, settings.rx_res); - puts ("+--------------------------------------+-------------------------------------+"); - puts ("| Test Settings | Misc Commands: |"); - puts ("| | |"); - puts ("| m Change mode | |"); - puts ("| + - Increment/decrement rate by 10 | d Dump status |"); - puts ("| * / Increment/decrement rate by 100 | dd Dump detailed (e.g. tables) |"); - puts ("+--------------------------------------+-------------------------------------+"); - puts ("| Test Commands |"); - puts ("| |"); - puts ("| s Start single test batch c Clear counters |"); - puts ("| sc Start continuous test x Stop continuous tests |"); - puts ("+----------------------------------------------------------------------------+"); - puts ("| q: Quit |"); - puts ("+============================================================================+"); - puts (""); - -} - -/* - * Input simple string - */ -static pj_bool_t simple_input(const char *title, char *buf, pj_size_t len) -{ - char *p; - - printf("%s (empty to cancel): ", title); fflush(stdout); - fgets(buf, len, stdin); - - /* Remove trailing newlines. */ - for (p=buf; ; ++p) { - if (*p=='\r' || *p=='\n') *p='\0'; - else if (!*p) break; - } - - if (!*buf) - return PJ_FALSE; - - return PJ_TRUE; -} - -/* Main input loop */ -static void test_main(void) -{ - char menuin[10]; - char input[80]; - - settings.cur_rate = settings.start_rate; - - help_screen(); - - for (;;) { - printf(">>>> "); fflush(stdout); - - fgets(menuin, sizeof(menuin), stdin); - - switch (menuin[0]) { - case 's': - if (settings.session != NULL) { - PJ_LOG(3,(THIS_FILE,"Error: another session is in progress")); - } else if (settings.target.slen == 0) { - PJ_LOG(3,(THIS_FILE,"Error: target URL is not configured")); - } else { - start_session(menuin[1]=='c'); - } - break; - - case 'x': - if (settings.session) { - settings.session->stopping = 1; - puts("Stopping sessions..."); - } else { - PJ_LOG(3,(THIS_FILE,"Error: no sessions")); - } - break; - - case 'c': - /* Clear counters */ - settings.rx_req = settings.rx_res = settings.tx_req = - settings.tx_res = 0; - puts("Counters cleared"); - break; - - case 'm': - if (!simple_input("Change method [OPTIONS,INVITE]", input, sizeof(input))) - continue; - - if (pj_ansi_stricmp(input, "OPTIONS")==0) - pjsip_method_set(&settings.method, PJSIP_OPTIONS_METHOD); - else if (pj_ansi_stricmp(input, "INVITE")==0) - pjsip_method_set(&settings.method, PJSIP_INVITE_METHOD); - else { - puts("Error: invalid method"); - } - break; - - case 'd': - dump(menuin[1]=='d'); - break; - - case '+': - settings.cur_rate += 10; - PJ_LOG(3,(THIS_FILE, "Rate is now %d", settings.cur_rate)); - break; - - case '-': - if (settings.cur_rate > 10) { - settings.cur_rate -= 10; - PJ_LOG(3,(THIS_FILE, "Rate is now %d", settings.cur_rate)); - } - break; - - case '*': - settings.cur_rate += 100; - PJ_LOG(3,(THIS_FILE, "Rate is now %d", settings.cur_rate)); - break; - - case '/': - if (settings.cur_rate > 100) { - settings.cur_rate -= 100; - PJ_LOG(3,(THIS_FILE, "Rate is now %d", settings.cur_rate)); - } - break; - - case 'q': - return; - - default: - help_screen(); - break; - - } - } -} - - -/* main() */ -int main(int argc, char *argv[]) -{ - pj_status_t status; - - init_settings(); - - status = parse_options(argc, argv); - if (status != PJ_SUCCESS) - return 1; - - status = initialize(); - if (status != PJ_SUCCESS) - return 1; - - - test_main(); - - shutdown(); - - return 0; -} - diff --git a/pjsip-apps/src/pjsip-perf/pjsip_perf.h b/pjsip-apps/src/pjsip-perf/pjsip_perf.h deleted file mode 100644 index 6c5372e3..00000000 --- a/pjsip-apps/src/pjsip-perf/pjsip_perf.h +++ /dev/null @@ -1,178 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2006 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 - */ -#ifndef __PJSIP_PERF_H__ -#define __PJSIP_PERF_H__ - -#include <pjsua-lib/pjsua.h> - - -PJ_BEGIN_DECL - - -typedef struct batch batch; -typedef struct session session; - -/** - * A test batch. - */ -struct batch -{ - PJ_DECL_LIST_MEMBER(struct batch); - - unsigned rate; /**< How many tasks to perform */ - - unsigned started; /**< # of tasks started. */ - unsigned success; /**< # of tasks completed successfully. */ - unsigned failed; /**< # of failed tasks. */ - - pj_time_val start_time; /**< Start time of the tests. */ - pj_time_val spawned_time; /**< Time when all tasks has been started. */ - pj_time_val end_time; /**< Time when all tasks has completed. */ -}; - -/** - * Test session. - */ -struct session -{ - pj_pool_t *pool; - pj_time_val start_time; - pj_bool_t stopping; - pjsip_method method; - struct batch active_list; - struct batch free_list; - - unsigned outstanding; - unsigned total_created; -}; - - -/** - * Request parameter. - */ -struct request_param -{ - pj_str_t dst; - pj_str_t src; - pjsip_cred_info cred; -}; - - -typedef struct request_param request_param; - - -void app_perror(const char *sender, const char *title, pj_status_t status); - -/* OPTIONS test */ -pj_status_t options_handler_init(void); -pj_status_t options_spawn_test(const pj_str_t *target, - const pj_str_t *from, - const pj_str_t *to, - unsigned cred_cnt, - const pjsip_cred_info cred[], - const pjsip_route_hdr *route_set, - void *test_data, - void (*completion_cb)(void*,pj_bool_t)); - -/* CALL test */ -pj_status_t call_handler_init(void); -pj_status_t call_spawn_test( const pj_str_t *target, - const pj_str_t *from, - const pj_str_t *to, - unsigned cred_cnt, - const pjsip_cred_info cred[], - const pjsip_route_hdr *route_set, - void *test_data, - void (*completion_cb)(void*,pj_bool_t)); - - - -/** - * Global settings - */ -struct pjsip_perf_settings -{ - /* Global */ - pj_caching_pool cp; - pj_pool_t *pool; - pjsip_endpoint *endpt; - pj_mutex_t *mutex; - - /* Misc: */ - int log_level; - int app_log_level; - char *log_file; - - /* Network: */ - int local_port; - - /* Threads. */ - pj_bool_t quit_flag; - int thread_cnt; - pj_thread_t *thread[16]; - - /* Outgoing request method: */ - pjsip_method method; - - /* Default target: */ - pj_str_t target; - - /* Media: */ - pjmedia_endpt *med_endpt; - pjmedia_conf *mconf; - - /* Handling incoming requests: */ - pj_bool_t stateless; - - /* Rate control. */ - pj_uint32_t start_rate; - pj_uint32_t cur_rate; - - /* Capacity control. */ - pj_uint32_t max_capacity; - - /* Duration control: */ - pj_uint32_t duration; - - /* Test control: */ - session *session; - pj_timer_entry timer; - - /* Counters: */ - pj_uint32_t tx_req; - pj_uint32_t tx_res; - pj_uint32_t rx_req; - pj_uint32_t rx_res; -}; - - -typedef struct pjsip_perf_settings pjsip_perf_settings; - -extern pjsip_perf_settings settings; - - - -PJ_END_DECL - - -#endif /* __PJSIP_PERF_H__ */ - - - - diff --git a/pjsip-apps/src/samples/pjsip-perf.c b/pjsip-apps/src/samples/pjsip-perf.c index dbc6fb21..7f41668c 100644 --- a/pjsip-apps/src/samples/pjsip-perf.c +++ b/pjsip-apps/src/samples/pjsip-perf.c @@ -66,9 +66,19 @@ #include <pjlib.h> #include <stdio.h> -#define THIS_FILE "pjsip-perf.c" -#define DEFAULT_COUNT (PJSIP_MAX_TSX_COUNT/2>10000?10000:PJSIP_MAX_TSX_COUNT/2) -#define JOB_WINDOW DEFAULT_COUNT +#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 DEFAULT_COUNT +#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 @@ -138,6 +148,7 @@ struct app job_submitted, job_finished, job_window; + unsigned stat_max_window; pj_time_val first_request; pj_time_val last_completion; unsigned total_responses; @@ -587,7 +598,8 @@ static pj_status_t create_app(void) PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Must create a pool factory before we can allocate any memory. */ - pj_caching_pool_init(&app.cp, &pj_pool_factory_default_policy, 0); + pj_caching_pool_init(&app.cp, &pj_pool_factory_default_policy, + CACHING_POOL_SIZE); /* Create application pool for misc. */ app.pool = pj_pool_create(&app.cp.factory, "app", 1000, 1000, NULL); @@ -632,7 +644,7 @@ static pj_status_t init_sip() pjsip_tpfactory *tpfactory; transport_type = "tcp"; - pj_sockaddr_in_init(&local_addr, 0, app.local_port); + pj_sockaddr_in_init(&local_addr, 0, (pj_uint16_t)app.local_port); status = pjsip_tcp_transport_start(app.sip_endpt, &local_addr, app.thread_count, &tpfactory); if (status == PJ_SUCCESS) { @@ -975,6 +987,7 @@ static void usage(void) " --thread-count=N Set number of worker threads (default=1)\n" " --stateless, -s Set client to operate in stateless mode\n" " (default: stateful)\n" + " --window=COUNT, -w Set maximum outstanding job in client (default: %d)\n" " --real-sdp Generate real SDP from pjmedia, and also perform\n" " proper SDP negotiation (default: dummy)\n" " --timeout=SEC, -t Set client timeout (default=60 sec)\n" @@ -985,7 +998,7 @@ static void usage(void) " - sip:0@server-addr To handle requests statelessly (non-INVITE only)\n" " - sip:1@server-addr To handle requests statefully (INVITE and non-INVITE)\n" " - sip:2@server-addr To handle INVITE call (INVITE only)\n", - DEFAULT_COUNT); + DEFAULT_COUNT, JOB_WINDOW); } @@ -1010,6 +1023,7 @@ static pj_status_t init_options(int argc, char *argv[]) { "real-sdp", 0, 0, OPT_REAL_SDP }, { "verbose", 0, 0, 'v' }, { "use-tcp", 0, 0, 'T' }, + { "window", 1, 0, 'w' }, { NULL, 0, 0, 0 }, }; int c; @@ -1026,7 +1040,7 @@ static pj_status_t init_options(int argc, char *argv[]) /* Parse options */ pj_optind = 0; - while((c=pj_getopt_long(argc,argv, "p:c:m:t:hsv", + while((c=pj_getopt_long(argc,argv, "p:c:m:t:w:hsv", long_options, &option_index))!=-1) { switch (c) { @@ -1090,6 +1104,14 @@ static pj_status_t init_options(int argc, char *argv[]) } 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; @@ -1183,7 +1205,7 @@ static void tsx_completion_cb(void *token, pjsip_event *event) report_completion(tsx->status_code); tsx->mod_data[mod_test.id] = (void*)1; - pjsip_tsx_terminate(tsx, tsx->status_code); + TERMINATE_TSX(tsx, tsx->status_code); } } @@ -1219,6 +1241,7 @@ static pj_status_t submit_job(void) /* Client worker thread */ static int client_thread(void *arg) { + unsigned last_timeout_check = 0; pj_time_val end_time, now; PJ_UNUSED_ARG(arg); @@ -1239,15 +1262,23 @@ static int client_thread(void *arg) int outstanding; pj_status_t status; + /* Calculate current outstanding job */ + outstanding = app.client.job_submitted - app.client.job_finished; + + /* Update stats on max outstanding jobs */ + if (outstanding > (int)app.client.stat_max_window) + app.client.stat_max_window = outstanding; + /* Wait if there are more pending jobs than allowed in the * window. */ - outstanding = app.client.job_submitted - app.client.job_finished; - while (outstanding >= (int)app.client.job_window) { + for (i=0; outstanding > (int)app.client.job_window && i<100; ++i) { pjsip_endpt_handle_events(app.sip_endpt, &timeout); outstanding = app.client.job_submitted - app.client.job_finished; } + + /* Submit one job */ if (app.client.method.id == PJSIP_INVITE_METHOD) { status = make_call(&app.client.dst_uri); } else if (app.client.stateless) { @@ -1258,11 +1289,15 @@ static int client_thread(void *arg) ++app.client.job_submitted; - for (i=0; i<2; ++i) { - unsigned cnt=0; - pjsip_endpt_handle_events2(app.sip_endpt, &timeout, &cnt); - if (cnt==0) + /* Handle event */ + pjsip_endpt_handle_events2(app.sip_endpt, &timeout, NULL); + + /* Check for time out */ + if (app.client.job_submitted - last_timeout_check >= 2000) { + pj_gettimeofday(&now); + if (PJ_TIME_VAL_GTE(now, end_time)) break; + last_timeout_check = app.client.job_submitted; } } @@ -1271,11 +1306,8 @@ static int client_thread(void *arg) pj_time_val timeout = { 0, 0 }; unsigned i; - for (i=0; i<2; ++i) { - unsigned cnt=0; - pjsip_endpt_handle_events2(app.sip_endpt, &timeout, &cnt); - if (cnt==0) - break; + for (i=0; i<2000; ++i) { + pjsip_endpt_handle_events2(app.sip_endpt, &timeout, NULL); } pj_gettimeofday(&now); @@ -1352,7 +1384,7 @@ static int server_thread(void *arg) good_number(str_stateful, app.server.cur_state.stateful_cnt); good_number(str_call, app.server.cur_state.call_cnt); - printf("Total(rate): stateless:%s (%d/s), statefull:%s (%d/s), call:%s (%d/s)\r", + printf("Total(rate): stateless:%s (%d/s), statefull:%s (%d/s), call:%s (%d/s) \r", str_stateless, stateless*1000/msec, str_stateful, stateful*1000/msec, str_call, call*1000/msec); @@ -1366,8 +1398,20 @@ static int server_thread(void *arg) return 0; } +static void write_report(const char *msg) +{ + puts(msg); + +#if defined(PJ_WIN32) && PJ_WIN32!=0 + OutputDebugString(msg); + OutputDebugString("\n"); +#endif +} + + int main(int argc, char *argv[]) { + static char report[1024]; if (create_app() != 0) return 1; @@ -1458,24 +1502,33 @@ int main(int argc, char *argv[]) if (msec == 0) msec = 1; - printf("Total %d %s sent, %d responses received in %d msec:\n" - " - 2xx responses: %7d (rate=%d/sec)\n" - " - 3xx responses: %7d (rate=%d/sec)\n" - " - 4xx responses: %7d (rate=%d/sec)\n" - " - 5xx responses: %7d (rate=%d/sec)\n" - " - 6xx responses: %7d (rate=%d/sec)\n" - " - 7xx responses: %7d (rate=%d/sec)\n" - " ----------------\n" - " TOTAL responses: %7d (rate=%d/sec)\n", - app.client.job_submitted, test_type, - app.client.total_responses, msec, - app.client.status_class[2], app.client.status_class[2]*1000/msec, - app.client.status_class[3], app.client.status_class[3]*1000/msec, - app.client.status_class[4], app.client.status_class[4]*1000/msec, - app.client.status_class[5], app.client.status_class[5]*1000/msec, - app.client.status_class[6], app.client.status_class[6]*1000/msec, - app.client.status_class[7], app.client.status_class[7]*1000/msec, - app.client.total_responses, app.client.total_responses*1000/msec); + pj_ansi_snprintf( + report, sizeof(report), + "Total %d %s sent, %d responses received in %d ms:\n" + " - 2xx responses: %7d (rate=%d/sec)\n" + " - 3xx responses: %7d (rate=%d/sec)\n" + " - 4xx responses: %7d (rate=%d/sec)\n" + " - 5xx responses: %7d (rate=%d/sec)\n" + " - 6xx responses: %7d (rate=%d/sec)\n" + " - 7xx responses: %7d (rate=%d/sec)\n" + " ----------------\n" + " TOTAL responses: %7d (rate=%d/sec)\n", + app.client.job_submitted, test_type, + app.client.total_responses, msec, + app.client.status_class[2], app.client.status_class[2]*1000/msec, + app.client.status_class[3], app.client.status_class[3]*1000/msec, + app.client.status_class[4], app.client.status_class[4]*1000/msec, + app.client.status_class[5], app.client.status_class[5]*1000/msec, + app.client.status_class[6], app.client.status_class[6]*1000/msec, + app.client.status_class[7], app.client.status_class[7]*1000/msec, + app.client.total_responses, app.client.total_responses*1000/msec); + + write_report(report); + + pj_ansi_sprintf(report, "Maximum outstanding job: %d", + app.client.stat_max_window); + write_report(report); + } else { /* Server mode */ |