freeswitch/libs/sofia-sip/libsofia-sip-ua/sip/validator.c
Michael Jerris 5e81b98eba Sync to current darcs tree:
Mon Sep 17 14:50:04 EDT 2007  Pekka.Pessi@nokia.com
  * sofia-sip/sip_util.h: updated documentation

Mon Sep 17 14:50:18 EDT 2007  Pekka.Pessi@nokia.com
  * sofia-sip/tport_tag.h: updated documentation

Mon Sep 17 14:50:28 EDT 2007  Pekka.Pessi@nokia.com
  * soa_tag.c: updated documentation

Wed Sep 19 12:50:01 EDT 2007  Pekka.Pessi@nokia.com
  * msg: updated documentation

Wed Sep 19 13:29:50 EDT 2007  Pekka.Pessi@nokia.com
  * url: updated documentation

Wed Sep 19 13:32:14 EDT 2007  Pekka.Pessi@nokia.com
  * nth: updated documentation

Wed Sep 19 13:32:27 EDT 2007  Pekka.Pessi@nokia.com
  * nea: updated documentation

Wed Sep 19 13:33:36 EDT 2007  Pekka.Pessi@nokia.com
  * http: updated documentation

Wed Sep 19 13:36:58 EDT 2007  Pekka.Pessi@nokia.com
  * bnf: updated documentation

Wed Sep 19 13:38:58 EDT 2007  Pekka.Pessi@nokia.com
  * nua: updated nua_stack_init_handle() prototype

Wed Sep 19 18:45:56 EDT 2007  Pekka.Pessi@nokia.com
  * sip: added sip_name_addr_xtra(), sip_name_addr_dup()

Wed Sep 19 19:00:19 EDT 2007  Pekka.Pessi@nokia.com
  * sip_basic.c: cleaned old crud

Thu Sep 20 13:34:04 EDT 2007  Pekka.Pessi@nokia.com
  * iptsec: updated documentation

Thu Sep 20 13:36:22 EDT 2007  Pekka.Pessi@nokia.com
  * tport: updated documentation

Thu Sep 20 13:36:56 EDT 2007  Pekka.Pessi@nokia.com
  * su: updated documentation
  Removed internal files from doxygen-generated documentation.

Thu Sep 20 13:38:29 EDT 2007  Pekka.Pessi@nokia.com
  * soa: fixed documentation

Thu Sep 20 13:39:56 EDT 2007  Pekka.Pessi@nokia.com
  * sdp: updated documentation

Thu Sep 20 13:40:16 EDT 2007  Pekka.Pessi@nokia.com
  * ipt: updated documentation

Thu Sep 20 14:24:20 EDT 2007  Pekka.Pessi@nokia.com
  * nta: updated documentation

Thu Sep 20 14:41:04 EDT 2007  Pekka.Pessi@nokia.com
  * nua: updated documentation

  Updated tag documentation.

  Moved doxygen doc entries from sofia-sip/nua_tag.h to nua_tag.c.

  Removed internal datatypes and files from the generated documents.

Wed Sep 19 13:34:20 EDT 2007  Pekka.Pessi@nokia.com
  * docs: updated the generation of documentation. Updated links to header files.

Thu Sep 20 08:45:32 EDT 2007  Pekka.Pessi@nokia.com
  * sip/Makefile.am: added tags to <sofia-sip/sip_extra.h>

  Added check for extra tags in torture_sip.c.

Thu Sep 20 14:45:22 EDT 2007  Pekka.Pessi@nokia.com
  * stun: updated documentation

Wed Jul  4 18:55:20 EDT 2007  Pekka.Pessi@nokia.com
  * torture_heap.c: added tests for ##sort() and su_smoothsort()

Wed Jul  4 18:56:59 EDT 2007  Pekka.Pessi@nokia.com
  * Makefile.am: added smoothsort.c

Fri Jul 13 12:38:44 EDT 2007  Pekka.Pessi@nokia.com
  * sofia-sip/heap.h: heap_remove() now set()s index to 0 on removed item

Mon Jul 23 11:14:22 EDT 2007  Pekka.Pessi@nokia.com
  * sofia-sip/heap.h: fixed bug in heap##remove()

  If left kid was in heap but right was not, left kid was ignored.

Wed Jul  4 18:51:08 EDT 2007  Pekka.Pessi@nokia.com
  * smoothsort.c: added

Wed Jul  4 18:51:34 EDT 2007  Pekka.Pessi@nokia.com
  * heap.h: using su_smoothsort()

Fri Jul  6 10:20:27 EDT 2007  Pekka.Pessi@nokia.com
  * smoothsort.c: added

Wed Sep 19 17:40:30 EDT 2007  Pekka.Pessi@nokia.com
  * msg_parser.awk: generate two parser tables, default and extended

Wed Sep 19 18:39:45 EDT 2007  Pekka.Pessi@nokia.com
  * msg_parser.awk: just generate list of extra headers

  Allocate extended parser dynamically.

Wed Sep 19 18:59:59 EDT 2007  Pekka.Pessi@nokia.com
  * sip: added Remote-Party-ID, P-Asserted-Identity, P-Preferred-Identity

  Added functions sip_update_default_mclass() and sip_extend_mclass()
  for handling the extended parser. Note that Reply-To and Alert-Info are only
  available with the extended parser.

Wed Sep 19 19:05:44 EDT 2007  Pekka.Pessi@nokia.com
  * RELEASE: updated

Thu Sep 20 13:38:59 EDT 2007  Pekka.Pessi@nokia.com
  * sip: updated documentation

Thu Sep 20 14:17:28 EDT 2007  Pekka.Pessi@nokia.com
  * docs/conformance.docs: updated

Mon Oct  1 10:11:14 EDT 2007  Pekka.Pessi@nokia.com
  * tport_tag.c: re-enabled tptag_trusted

Thu Oct  4 09:21:07 EDT 2007  Pekka.Pessi@nokia.com
  * su_osx_runloop.c: moved virtual function table after struct definition

  Preparing for su_port_vtable_t refactoring.

Thu Oct  4 10:22:03 EDT 2007  Pekka.Pessi@nokia.com
  * su_source.c: refactored initialization/deinitialization

Fri Oct  5 04:58:18 EDT 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * sip_extra.c: fixed prototypes with isize_t

Fri Oct  5 04:58:45 EDT 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * test_nta_api.c: removed warnings about signedness

Fri Oct  5 04:59:02 EDT 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * test_nua_params.c: removed warnings about constness

Fri Oct  5 07:20:26 EDT 2007  Pekka Pessi <first.lastname@nokia.com>
  * su_port.h, su_root.c: cleaned argument checking

  The su_root_*() and su_port_*() functions now check their arguments once
  and do not assert() with NULL arguments. The sur_task->sut_port should
  always be valid while su_root_t is alive.

Fri Oct  5 07:22:09 EDT 2007  Pekka Pessi <first.lastname@nokia.com>
  * su: added su_root_obtain(), su_root_release() and su_root_has_thread()

  When root is created with su_root_create() or cloned with su_clone_start(),
  the resulting root is obtained by the calling or created thread,
  respectively.

  The root can be released with su_root_release() and another thread can
  obtain it.

  The function su_root_has_thread() can be used to check if a thread has
  obtained or released the root.

  Implementation upgraded the su_port_own_thread() method as su_port_thread().

Fri Oct  5 07:28:10 EDT 2007  Pekka Pessi <first.lastname@nokia.com>
  * su_port.h: removed su_port_threadsafe() and su_port_yield() methods

  su_port_wait_events() replaces su_port_yield().

Fri Oct  5 13:26:04 EDT 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * msg_parser.awk: not extending header structure unless needed.

  Removed gawk-ish /* comments */.

Fri Oct  5 14:32:25 EDT 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * run_test_su: removed GNUisms

Fri Oct  5 14:32:47 EDT 2007  Pekka Pessi <Pekka.Pessi@nokia.com>
  * Makefile.am: removed implicit check target test_urlmap

Fri Oct  5 14:22:32 EDT 2007  Pekka Pessi <first.lastname@nokia.com>
  * torture_sresolv.c: use CLOCK_REALTIME if no CLOCK_PROCESS_CPUTIME_ID available

  Casting timespec tv_sec to unsigned long.

Fri Oct * nua_s added handling nua_prack()

  Thanks to Fabio Margarido for the patch.

Mon Oct  8 10:24:35 EDT 2007  Pekka.Pessi@nokia.com
  * test_nua: added test for sf.net bug #1803686

Mon Oct  8 08:15:23 EDT 2007  Pekka.Pessi@nokia.com
  * RELEASE: updated.

Mon Oct  8 09:30:36 EDT 2007  Pekka.Pessi@nokia.com
  * nua_stack: added handling nua_prack()

  Thanks to Fabio Margarido for the patch.

Mon Oct  8 10:24:35 EDT 2007  Pekka.Pessi@nokia.com
  * test_nua: added test for sf.net bug #1803686

Mon Oct  8 10:26:31 EDT 2007  Pekka.Pessi@nokia.com
  * nua: added test for nua_prack() (sf.net bug #1804248)

  Avoid sending nua_i_state after nua_prack() if no SDP O/A is happening, too.

Mon Oct  8 10:32:04 EDT 2007  Mikhail Zabaluev <mikhail.zabaluev@nokia.com>
  * su_source.c: don t leak the wait arrays

Mon Oct  8 10:37:11 EDT 2007  Pekka.Pessi@nokia.com
  * RELEASE: updated

Wed Oct 10 11:55:21 EDT 2007  Pekka.Pessi@nokia.com
  * sip_parser.c: silenced warning about extra const in sip_extend_mclass()

Wed Oct 10 11:57:08 EDT 2007  Pekka.Pessi@nokia.com
  * nta_tag.c: updated tag documentation

Wed Oct 10 13:16:40 EDT 2007  Pekka.Pessi@nokia.com
  * nua: fix logging crash if outbound used with application contact

  Silenced warnings.

Wed Oct 10 13:30:45 EDT 2007  Pekka.Pessi@nokia.com
  * msg_parser.awk: removed extra "const"

Wed Oct 10 13:31:45 EDT 2007  Pekka.Pessi@nokia.com
  * Makefile.am's: fixed distclean of documentation



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5840 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-10-11 14:16:59 +00:00

647 lines
15 KiB
C

/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
/**@internal @IFILE validator.c
*
* SIP parser tester. This uses output from tport dump where messages are
* separated with Control-K ('\v') from each other.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>.
*
* @date Wed Mar 21 19:12:13 2001 ppessi
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <sys/mman.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sofia-sip/su_types.h>
#include <sofia-sip/su_alloc_stat.h>
#include <sofia-sip/su_time.h>
#include <sofia-sip/su_tag.h>
#include <sofia-sip/su_tag_class.h>
#include <sofia-sip/su_tag_io.h>
#include <sofia-sip/sip_tag.h>
#include <sofia-sip/url_tag.h>
#include <sofia-sip/sip.h>
#include <sofia-sip/sip_header.h>
#include <sofia-sip/msg_buffer.h>
char const *name = "validator";
typedef struct {
unsigned o_verbose : 1; /**< Be verbose */
unsigned o_very_verbose : 1; /**< Be very verbose */
unsigned o_requests : 1; /**< Only requests */
unsigned o_responses : 1; /**< Only responses */
unsigned o_decode : 1; /**< Only try to decode,
print error if unknown headers */
unsigned o_print : 1; /**< Print whole message */
unsigned o_times : 1; /**< Generate timing information */
unsigned o_memstats : 1; /**< Generate memory statistics */
unsigned o_histogram : 1; /**< Generate histograms */
unsigned o_sipstats : 1; /**< Generate header statistics */
unsigned o_vsipstats : 1; /**< Generate verbatim header statistics */
unsigned : 0;
unsigned o_flags; /**< Message flags */
} options_t;
typedef struct {
size_t N;
uint32_t bsize;
double buckets[32768];
} histogram_t;
static
histogram_t *histogram_create(uint64_t max, uint32_t bsize)
{
size_t N = (max + bsize - 1) / bsize;
histogram_t *h = calloc(1, offsetof(histogram_t, buckets[N + 1]));
if (!h) { perror("calloc"); exit(1); }
h->N = N, h->bsize = bsize;
return h;
}
static
double *histogram_update(histogram_t *h, uint32_t n)
{
if (h->bsize > 1)
n /= h->bsize;
if (n < h->N)
return &h->buckets[n];
else
return &h->buckets[h->N];
}
static void
histogram_div(histogram_t *h, histogram_t const *n)
{
size_t i;
assert(h->N == n->N); assert(h->bsize == n->bsize);
for (i = 0; i <= h->N; i++) {
if (n->buckets[i]) {
h->buckets[i] /= n->buckets[i];
}
else {
assert(h->buckets[i] == 0);
}
}
}
typedef struct {
uint64_t number;
uint64_t headers;
uint64_t payloads;
uint64_t pl_bytes;
} sipstat_t;
typedef struct {
sipstat_t req, resp;
histogram_t *hist_headers;
} sipstats_t;
typedef struct {
char const *name;
char const *sep;
uint64_t messages;
uint64_t bytes;
uint64_t errors;
uint32_t files;
double time;
options_t options[1];
/* Statistics */
histogram_t *hist_msgsize;
histogram_t *hist_mallocs;
histogram_t *hist_memsize;
histogram_t *hist_nheaders;
sipstats_t sipstats[1];
su_home_stat_t hs[1];
uint64_t est_fail, est_succ, est_slack;
} context_t;
void usage(void)
{
fprintf(stderr,
"usage: %s [-vdp]\n",
name);
exit(2);
}
char *lastpart(char *path)
{
char *p = strrchr(path, '/');
if (p)
return p + 1;
else
return path;
}
msg_mclass_t const *mclass = NULL;
int validate_file(int fd, char const *name, context_t *ctx);
int validate_dump(char *, off_t, context_t *ctx);
int report(context_t const *ctx);
static void memstats(msg_t *, uint32_t msize, context_t *ctx);
static void sipstats(msg_t *, uint32_t msize, sipstats_t *ss, context_t *ctx);
int main(int argc, char *argv[])
{
context_t ctx[1] = {{ 0 }};
options_t *o = ctx->options;
name = lastpart(argv[0]); /* Set our name */
for (; argv[1]; argv++) {
if (argv[1][0] == 0)
usage();
else if (argv[1][0] != '-')
break;
else if (argv[1][1] == 0) {
argv++; break;
}
else if (strcmp(argv[1], "-v") == 0)
o->o_very_verbose = o->o_verbose, o->o_verbose = 1;
else if (strcmp(argv[1], "-d") == 0)
o->o_decode = 1; /* Decode only */
else if (strcmp(argv[1], "-p") == 0)
o->o_print = 1;
else if (strcmp(argv[1], "-q") == 0)
o->o_requests = 1;
else if (strcmp(argv[1], "-Q") == 0)
o->o_responses = 1;
else if (strcmp(argv[1], "-t") == 0)
o->o_times = 1;
else if (strcmp(argv[1], "-m") == 0)
o->o_memstats = 1;
else if (strcmp(argv[1], "-s") == 0)
o->o_vsipstats = o->o_sipstats, o->o_sipstats = 1;
else if (strcmp(argv[1], "-h") == 0)
o->o_histogram = 1;
else
usage();
}
if (o->o_requests && o->o_responses)
usage();
if (!mclass)
mclass = sip_default_mclass();
if (argv[1]) {
for (; argv[1]; argv++) {
int fd = open(argv[1], O_RDONLY, 000);
if (fd == -1)
perror(argv[1]), exit(1);
if (validate_file(fd, argv[1], ctx))
exit(1);
close(fd);
}
}
else
validate_file(0, "", ctx);
report(ctx);
exit(0);
}
int validate_file(int fd, char const *name, context_t *ctx)
{
void *p;
off_t size;
int retval;
ctx->name = name;
if (strlen(name))
ctx->sep = ": ";
else
ctx->sep = "";
ctx->files++;
size = lseek(fd, 0, SEEK_END);
if (size < 1)
return 0;
if (size > INT_MAX) {
fprintf(stderr, "%s%stoo large file to map\n", ctx->name, ctx->sep);
return -1;
}
#ifndef _WIN32
p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0L);
if (p == NULL) {
perror("mmap");
return -1;
}
retval = validate_dump(p, size, ctx);
munmap(p, size);
return retval;
#else
errno = EINVAL;
perror("mmap not implemented");
return -1;
#endif
}
su_inline
void nul_terminate(char *b, off_t size)
{
char *end;
/* NUL-terminate */
for (end = b + size - 1; end != b; end--)
if (*end == '\v')
break;
*end = '\0';
}
su_inline
int search_msg(char **bb, char const *protocol)
{
int linelen, plen = strlen(protocol);
char *b = *bb;
for (;;) {
if (!b[0])
return 0;
if (strncmp(b, protocol, plen) == 0 && b[plen] == ' ')
return 1; /* status */
linelen = strcspn(b, "\r\n");
if (linelen > plen + 1 &&
b[linelen - plen - 1] == ' ' &&
strncmp(b + linelen - plen, protocol, plen) == 0)
return 1; /* request */
b += linelen + strspn(b + linelen, "\r\n");
*bb = b;
}
}
int validate_dump(char *b, off_t size, context_t *ctx)
{
size_t n = 0, N = 0;
struct message {
char *b;
int size;
} *msgs = NULL;
uint64_t time0, time1;
options_t *o = ctx->options;
int maxsize = 0;
nul_terminate(b, size);
/* Split dump file to messages */
while (search_msg(&b, SIP_VERSION_CURRENT)) {
int msize = strcspn(b, "\v");
int linelen = strcspn(b, "\r\n");
if (o->o_responses &&
memcmp(b, SIP_VERSION_CURRENT, strlen(SIP_VERSION_CURRENT)) != 0)
;
else if (o->o_requests &&
memcmp(b, SIP_VERSION_CURRENT, strlen(SIP_VERSION_CURRENT)) == 0)
;
else {
if (o->o_very_verbose)
printf("message "MOD_ZU": %.*s\n", n, linelen, b);
if (n == N) {
N *= 2; if (n == N) N = 16;
msgs = realloc(msgs, sizeof(*msgs) * N);
if (msgs == NULL) {
perror("realloc");
exit(1);
}
}
msgs[n].b = b; msgs[n].size = msize;
n++;
ctx->bytes += msize;
if (msize > maxsize)
maxsize = msize;
}
b += msize; if (*b) *b++ = '\0';
}
ctx->messages += N = n;
if (o->o_histogram) {
ctx->hist_msgsize = histogram_create(maxsize, 64);
if (o->o_memstats) {
ctx->hist_mallocs = histogram_create(maxsize, 64);
ctx->hist_memsize = histogram_create(maxsize, 64);
}
if (o->o_sipstats) {
ctx->sipstats->hist_headers = histogram_create(64, 1);
ctx->hist_nheaders = histogram_create(maxsize, 64);
}
}
time0 = su_nanocounter();
for (n = 0; n < N; n++) {
msg_t *msg = msg_create(mclass, o->o_flags);
int m;
if (msg == NULL) {
perror("msg_create"); exit(1);
}
if (o->o_memstats)
su_home_init_stats(msg_home(msg));
msg_buf_set(msg, msgs[n].b, msgs[n].size + 1);
msg_buf_commit(msg, msgs[n].size, 1);
su_home_preload(msg_home(msg), 1, msgs[n].size + 384);
m = msg_extract(msg);
if (m < 0) {
fprintf(stderr, "%s%sparsing error in message "MOD_ZU"\n",
ctx->name, ctx->sep, n);
ctx->errors++;
}
else {
if (ctx->hist_msgsize)
*histogram_update(ctx->hist_msgsize, msgs[n].size) += 1;
if (o->o_sipstats)
sipstats(msg, msgs[n].size, ctx->sipstats, ctx);
if (o->o_memstats)
memstats(msg, msgs[n].size, ctx);
}
msg_destroy(msg);
}
time1 = su_nanocounter();
if (o->o_times) {
double dur = (time1 - time0) * 1E-9;
ctx->time += dur;
printf("%s%s"MOD_ZU" messages in %g seconds (%g msg/sec)\n"
" parse speed %.1f Mb/s (on Ethernet wire %.1f Mb/s)\n",
ctx->name, ctx->sep, N, dur, (double)N / dur,
(double)ctx->bytes * 8 / ctx->time / 1e6,
((double)ctx->bytes + N * (16 + 20 + 8)) * 8 / ctx->time / 1e6);
}
free(msgs);
return 0;
}
typedef unsigned longlong ull;
static
void report_memstats(char const *title, su_home_stat_t const hs[1])
{
printf("%s%smemory statistics\n", title, strlen(title) ? " " : "");
if (hs->hs_allocs.hsa_number)
printf("\t"LLU" allocs, "LLU" bytes, "LLU" rounded,"
" "LLU" max\n",
(ull)hs->hs_allocs.hsa_number, (ull)hs->hs_allocs.hsa_bytes,
(ull)hs->hs_allocs.hsa_rbytes, (ull)hs->hs_allocs.hsa_maxrbytes);
if (hs->hs_frees.hsf_number)
printf("\t"LLU" frees, "LLU" bytes, rounded to "LLU" bytes\n",
(ull)hs->hs_frees.hsf_number, (ull)hs->hs_frees.hsf_bytes,
(ull)hs->hs_frees.hsf_rbytes);
if (hs->hs_rehash || hs->hs_clones)
printf("\t"LLU" rehashes, "LLU" clones\n",
(ull)hs->hs_rehash, (ull)hs->hs_clones);
}
void memstats(msg_t *msg, uint32_t msize, context_t *ctx)
{
options_t *o = ctx->options;
su_home_stat_t hs[1];
su_home_get_stats(msg_home(msg), 1, hs, sizeof(hs));
su_home_stat_add(ctx->hs, hs);
if (o->o_histogram) {
*histogram_update(ctx->hist_mallocs, msize) += hs->hs_allocs.hsa_number;
*histogram_update(ctx->hist_memsize, msize) += hs->hs_allocs.hsa_maxrbytes;
}
{
int estimate = msize + 384;
int slack = estimate - hs->hs_allocs.hsa_maxrbytes;
if (slack < 0)
ctx->est_fail++;
else {
ctx->est_succ++;
ctx->est_slack += slack;
}
}
if (o->o_very_verbose)
report_memstats(ctx->name, hs);
}
void report_sipstat(char const *what, sipstat_t const *sss)
{
printf("%s: "LLU" with %.1f headers (total "LLU")\n",
what, (ull)sss->number, (double)sss->headers / sss->number,
(ull)sss->headers);
if (sss->payloads)
printf("\t"LLU" with body of %.1f bytes (total "LLU")\n",
(ull)sss->payloads, (double)sss->pl_bytes / sss->payloads,
(ull)sss->payloads);
}
void sipstats(msg_t *msg, uint32_t msize, sipstats_t *ss, context_t *ctx)
{
options_t *o = ctx->options;
msg_pub_t *m = msg_object(msg);
sip_t const *sip = sip_object(msg);
msg_header_t *h;
sipstat_t *sss;
size_t n, bytes;
if (!sip)
return;
if (m->msg_request) {
sss = &ss->req;
h = m->msg_request;
}
else if (m->msg_status) {
sss = &ss->resp;
h = m->msg_status;
}
else {
return;
}
sss->number++;
/* Count headers */
for (n = 0, h = h->sh_succ; h && !sip_is_separator((sip_header_t *)h); h = h->sh_succ)
n++;
sss->headers += n;
bytes = sip->sip_payload ? (size_t)sip->sip_payload->pl_len : 0;
if (bytes) {
sss->payloads++;
sss->pl_bytes += bytes;
}
if (ctx->hist_nheaders) {
*histogram_update(ctx->hist_nheaders, msize) += n;
*histogram_update(ss->hist_headers, n) += 1;
}
if (o->o_very_verbose)
printf("%s%s"MOD_ZU" headers, "MOD_ZU" bytes in payload\n",
ctx->name, ctx->sep, n, bytes);
}
void report_histogram(char const *title, histogram_t const *h)
{
size_t i, min_i, max_i;
for (i = 0; i < h->N && h->buckets[i] == 0.0; i++)
;
min_i = i;
for (i = h->N - 1; i >= 0 && h->buckets[i] == 0.0; i--)
;
max_i = i;
if (min_i >= max_i)
return;
printf("%s histogram\n", title);
for (i = min_i; i < max_i; i++)
printf("\t"MOD_ZU".."MOD_ZU": %.1f\n", i * h->bsize, (i + 1) * h->bsize, h->buckets[i]);
if (h->buckets[h->N])
printf("\t"MOD_ZU"..: %.1f\n", h->N * h->bsize, h->buckets[h->N]);
}
int report(context_t const *ctx)
{
const options_t *o = ctx->options;
uint64_t n = ctx->messages;
if (!n)
return -1;
printf("total "LLU" messages with "LLU" bytes (mean size "LLU")\n",
(ull)n, (ull)ctx->bytes, (ull)(ctx->bytes / n));
if (ctx->hist_msgsize)
report_histogram("Message size", ctx->hist_msgsize);
if (o->o_times && ctx->files > 1)
printf("total "LLU" messages in %g seconds (%g msg/sec)\n",
(ull)n, ctx->time, (double)n / ctx->time);
if (o->o_sipstats) {
const sipstats_t *ss = ctx->sipstats;
report_sipstat("requests", &ss->req);
report_sipstat("responses", &ss->resp);
if (ctx->hist_nheaders) {
histogram_div(ctx->hist_nheaders, ctx->hist_msgsize);
report_histogram("Number of headers", ctx->hist_nheaders);
}
}
if (o->o_memstats) {
su_home_stat_t hs[1];
*hs = *ctx->hs;
report_memstats("total", hs);
/* Calculate mean */
hs->hs_clones /= n; hs->hs_rehash /= n;
hs->hs_allocs.hsa_number /= n; hs->hs_allocs.hsa_bytes /= n;
hs->hs_allocs.hsa_rbytes /= n; hs->hs_allocs.hsa_maxrbytes /= n;
hs->hs_frees.hsf_number /= n; hs->hs_frees.hsf_bytes /= n;
hs->hs_frees.hsf_rbytes /= n;
hs->hs_blocks.hsb_number /= n; hs->hs_blocks.hsb_bytes /= n;
hs->hs_blocks.hsb_rbytes /= n;
report_memstats("mean", hs);
printf("\testimator fails %.1f%% times (mean slack %.0f bytes)\n",
100 * (double)ctx->est_fail / (ctx->est_fail + ctx->est_succ),
(double)ctx->est_slack / ctx->est_succ);
if (ctx->hist_memsize) {
histogram_div(ctx->hist_memsize, ctx->hist_msgsize);
report_histogram("Allocated memory", ctx->hist_memsize);
}
}
return 0;
}