forked from Mirrors/freeswitch
5e81b98eba
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
647 lines
15 KiB
C
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;
|
|
}
|