Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Welcome to SIPp reference documentation!
3PCC_extended
controlling
transport
multi_instance
media
statistics
error
Expand Down
74 changes: 74 additions & 0 deletions docs/multi_instance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Multi-instance launcher
=======================

SIPp can launch several SIPp processes from one CSV configuration file. This
is useful when a test needs matching groups of UAC and UAS instances.

Use ``-multi`` with a CSV file:

.. code-block:: bash

./sipp -multi multi.csv -multi_base_port 5060

``-multi`` is a launcher mode. When it is present, the launcher accepts only
``-multi`` and ``-multi_base_port``; put normal SIPp options in the CSV
``args`` field instead. ``-multi_base_port`` cannot be used without
``-multi``.

The CSV format is:

.. code-block:: text

role,count,args
uas,2,"-sn uas -p {instance_port} -nostdin"
uac,2,"-sn uac 127.0.0.1:{instance_port} -m 100 -nostdin"

Blank lines and lines whose first non-whitespace character is ``#`` are
ignored. The header is optional and, when present, may use any letter case.
A configuration may launch at most 256 child processes in total.

Each row creates ``count`` child processes. The ``args`` field is split once
into command-line arguments before placeholders are expanded. This keeps
placeholder values containing spaces or quote characters as a single
argument instead of re-parsing them as shell syntax.

The launcher-only options ``-multi`` and ``-multi_base_port`` (including their
``--`` forms) are forbidden in child arguments. Validation is performed after
placeholder expansion, so placeholders cannot be used to create a nested
launcher. This prevents recursive configurations from bypassing the per-file
child-process limit.

The following placeholders are expanded in the ``args`` field:

* ``{role}``: the role column value.
* ``{instance}``: the zero-based instance number within that role. If a role
appears in more than one CSV row, numbering continues across those rows.
* ``{base_port}``: the value passed with ``-multi_base_port``.
* ``{instance_port}``: ``base_port + instance``. Use this to pair UAC and UAS
rows by instance number.
* ``{port}``: a globally increasing port number for every child process.

The launcher validates that all generated ports stay in the range 1 through
65535. It waits until all children exit and returns the first non-zero child
exit code. If a child cannot be forked, children already started by the
launcher are terminated and reaped before the launcher exits with failure.
If all children exit successfully, the launcher exits with zero.

When the launcher receives ``SIGINT``, ``SIGTERM``, or ``SIGHUP``, it forwards
a graceful termination to children, waits briefly, force-terminates any child
that remains, reaps them, and exits with ``128 + signal``. This also prevents
children from being orphaned when the launcher is stopped by a service manager
or CI timeout.

All children inherit the launcher's standard input, output, and error streams.
Multiple interactive SIPp screens will therefore interleave on one terminal.
Use ``-nostdin`` for children and redirect the launcher's output when a clean
terminal is needed, for example:

.. code-block:: bash

./sipp -multi multi.csv >multi.log 2>&1

A child may also use SIPp's ``-bg`` option when independent backgrounding is
desired; in that case the launcher only supervises the process until that
child backgrounds itself.
74 changes: 74 additions & 0 deletions include/multi_instance.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Multi-instance launcher support for SIPp.
*/

#ifndef __SIPP_MULTI_INSTANCE_H__
#define __SIPP_MULTI_INSTANCE_H__

#include <iosfwd>
#include <string>
#include <vector>

constexpr int MAX_MULTI_INSTANCE_CHILDREN = 256;

enum class MultiInstanceArgParseResult {
NOT_REQUESTED,
READY,
INVALID
};

struct MultiInstanceOptions {
std::string config_path;
int base_port;
};

struct MultiInstanceSpec {
std::string role;
int count;
std::vector<std::string> args;
};

struct MultiInstanceCommand {
std::string role;
int instance;
int port;
bool uses_port = false;
std::string executable_path;
std::vector<std::string> argv;
};

std::string trim_copy(const std::string &value);

bool split_command_args(const std::string &args,
std::vector<std::string> *words,
std::string *error);

MultiInstanceArgParseResult
parse_multi_instance_launcher_args(int argc,
char *argv[],
int default_base_port,
MultiInstanceOptions *options,
std::string *error);

std::string resolve_current_executable_path(const char *argv0);

bool parse_multi_instance_csv(const std::string &csv,
const std::string &source_name,
std::vector<MultiInstanceSpec> *specs,
std::string *error);

bool parse_multi_instance_csv_file(const std::string &path,
std::vector<MultiInstanceSpec> *specs,
std::string *error);

bool build_multi_instance_commands(const std::string &program_path,
const std::vector<MultiInstanceSpec> &specs,
int base_port,
std::vector<MultiInstanceCommand> *commands,
std::string *error);

int run_multi_instance_commands(const std::vector<MultiInstanceCommand> &commands,
std::ostream &out,
std::ostream &err);

#endif
Loading
Loading