[Pkg-voip-commits] [sngrep] 01/04: Imported Upstream version 1.1.0
Victor Seva Lopez
maniac-guest at moszumanska.debian.org
Tue Oct 27 22:15:44 UTC 2015
This is an automated email from the git hooks/post-receive script.
maniac-guest pushed a commit to branch pre_1.1.0
in repository sngrep.
commit 53e1c8dd07bd2b7924c335467b40d1ffc010901f
Author: Victor Seva <linuxmaniac at torreviejawireless.org>
Date: Tue Oct 27 22:21:24 2015 +0100
Imported Upstream version 1.1.0
---
README.md | 34 ++--
config/sngreprc | 2 +-
configure.ac | 55 +++++-
doc/sngrep.8 | 2 +-
src/Makefile.am | 12 +-
src/capture.c | 11 +-
src/capture.h | 1 +
src/{capture_tls.c => capture_gnutls.c} | 125 +++++++-----
src/{capture_tls.h => capture_gnutls.h} | 43 ++---
src/{capture_tls.c => capture_openssl.c} | 2 +-
src/{capture_tls.h => capture_openssl.h} | 0
src/capture_reasm.c | 10 +-
src/filter.c | 54 ++++--
src/filter.h | 10 +
src/keybinding.c | 242 +++++++++---------------
src/keybinding.h | 17 +-
src/main.c | 35 +++-
src/option.c | 3 -
src/rtp.c | 187 +++++++++++++-----
src/rtp.h | 218 ++++++++++++++++++++-
src/sip.c | 38 +++-
src/sip.h | 6 +
src/ui_call_flow.c | 313 ++++++++++++++++++++++++++++---
src/ui_call_flow.h | 28 ++-
src/ui_call_list.c | 10 +-
src/ui_filter.c | 53 +++---
src/ui_filter.h | 1 +
src/ui_manager.c | 3 +-
src/ui_manager.h | 3 +
src/ui_settings.c | 6 +-
src/ui_stats.c | 222 ++++++++++++++++++++++
src/ui_stats.h | 71 +++++++
src/vector.c | 6 +
src/vector.h | 6 +
34 files changed, 1427 insertions(+), 402 deletions(-)
diff --git a/README.md b/README.md
index f12b092..c189010 100644
--- a/README.md
+++ b/README.md
@@ -10,33 +10,19 @@ as PCAP viewer.
## Installing
### Binaries
-#### Debian / Ubuntu
-[Install sngrep Debian/Ubuntu package](https://github.com/irontec/sngrep/wiki/Installing-Binaries#debian--ubuntu)
-
-#### CentOS / RedHat / Fedora
-[Install sngrep CentOS/RedHat/Fedora package](https://github.com/irontec/sngrep/wiki/Installing-Binaries#centos--fedora--rhel)
-
-#### Gentoo
-You can find unofficial ebuilds for sngrep at [Gentoo Bugtracker System](https://bugs.gentoo.org/show_bug.cgi?id=534780) (thanks to Space Dream)
-
-Feel free to vote if you would like to see sngrep be part of Gentoo portage tree.
-
-#### Arch
-You can find an unofficial PKGBUILD for Arch at [ArchLinux User Repositories](https://aur.archlinux.org/packages/sngrep/) (thanks to w1ngnutt)
-
-Feel free to vote if you would like to see sngrep at official Arch repositories.
-
-#### OSX
-OSX users can install sngrep using [homebrew](https://github.com/Homebrew/homebrew)
-
- brew install sngrep
+* [Debian / Ubuntu] (https://github.com/irontec/sngrep/wiki/Installing-Binaries#debian--ubuntu)
+* [CentOS / RedHat / Fedora](https://github.com/irontec/sngrep/wiki/Installing-Binaries#centos--fedora--rhel)
+* [Gentoo](https://github.com/irontec/sngrep/wiki/Installing-Binaries#gentoo)
+* [Arch](https://github.com/irontec/sngrep/wiki/Installing-Binaries#arch)
+* [OSX] (https://github.com/irontec/sngrep/wiki/Installing-Binaries#osx)
### Building from sources
Prerequisites
- libncurse5 - for UI, windows, panels.
- libpcap - for capturing packets.
- - libssl - (optional) for TLS transport decrypt
+ - libssl - (optional) for TLS transport decrypt using OpenSSL and libcrypt
+ - gnutls - (optional) for TLS transport decrypt using GnuTLS and libgcrypt
- libncursesw5 - (optional) for UI, windows, panels (wide-character support)
- libpcre - (optional) for Perl Compatible regular expressions
@@ -52,9 +38,11 @@ You can pass following flags to ./configure to enable some features
| configure flag | Feature |
| ------------- | ------------- |
| `--with-openssl` | Adds OpenSSL support to parse TLS captured messages (req. libssl) |
+| `--with-gnutls` | Adds GnuTLS support to parse TLS captured messages (req. gnutls) |
| `--with-pcre`| Adds Perl Compatible regular expressions support in regexp fields |
| `--enable-unicode` | Adds Ncurses UTF-8/Unicode support (req. libncursesw5) |
-| `--enable-ipv6` | Enables IPv6 packet capture support. |
+| `--disable-ipv6` | Disable IPv6 packet capture support. (default: enabled) |
+| `--disable-eep` | Disable EEP packet send/receive support. (default: enabled) |
You can find [detailed instructions for some distributions] (https://github.com/irontec/sngrep/wiki/Building) on wiki.
@@ -76,6 +64,8 @@ or live capturing, saving packets to a new file
You can configure some options using [sngreprc] (https://github.com/irontec/sngrep/wiki/Configuration) file
## Frequent Asked Questions
+Any feedback, request or question are welcomed at [#sngrep](https://webchat.freenode.net/?channels=sngrep) channel at irc.freenode.net
+
See FAQ on [Github Wiki](https://github.com/irontec/sngrep/wiki#frequent-asked-questions)
## License
diff --git a/config/sngreprc b/config/sngreprc
index 630e8fe..b9304b2 100644
--- a/config/sngreprc
+++ b/config/sngreprc
@@ -99,4 +99,4 @@
##-----------------------------------------------------------------------------
## Uncomment to display dialogs that does not start with a request method
-# set sip.ignoreincomplete off
+# set sip.noincomplete off
diff --git a/configure.ac b/configure.ac
index 272bc50..5963d9a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ([2.59])
-AC_INIT([sngrep], [1.0.0], [kaian at irontec.com], [sngrep], [http://www.irontec.com/])
+AC_INIT([sngrep], [1.0.1], [kaian at irontec.com], [sngrep], [http://www.irontec.com/])
AM_INIT_AUTOMAKE([1.9])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_HEADERS([src/config.h])
@@ -97,6 +97,30 @@ AS_IF([test "x$enable_unicode" == "xyes"], [
])
####
+#### GnuTLS Support
+####
+AC_ARG_WITH([gnutls],
+ AS_HELP_STRING([--with-gnutls], [Enable SSL Support (TLS SIP Transport)]),
+ [AC_SUBST(WITH_GNUTLS, $withval)],
+ [AC_SUBST(WITH_GNUTLS, no)]
+)
+
+AS_IF([test "x$WITH_GNUTLS" == "xyes"], [
+ AC_CHECK_LIB([gnutls], [gnutls_init], [], [
+ AC_MSG_ERROR([ You need to have gnutls installed to compile sngrep])
+ ])
+
+ AC_CHECK_LIB([gnutls-openssl], [SSL_new], [], [
+ AC_MSG_ERROR([ You need to have gnutls installed to compile sngrep])
+ ])
+
+ AC_CHECK_LIB([gcrypt], [gcry_md_map_name], [], [
+ AC_MSG_ERROR([ You need to have libgcrypt installed to compile sngrep])
+ ])
+ AC_DEFINE([WITH_GNUTLS],[],[Compile With GnuTLS compatibility])
+], [])
+
+####
#### OpenSSL Support
####
AC_ARG_WITH([openssl],
@@ -106,16 +130,21 @@ AC_ARG_WITH([openssl],
)
AS_IF([test "x$WITH_OPENSSL" == "xyes"], [
+ AS_IF([test "x$WITH_GNUTLS" == "xyes"], [
+ AC_MSG_ERROR([ GnuTLS and OpenSSL can not be enabled at the same time ])
+ ], [])
+
AC_CHECK_LIB([ssl], [SSL_new], [], [
AC_MSG_ERROR([ You need to have libssl installed to compile sngrep])
])
-
+
AC_CHECK_LIB([crypto], [EVP_get_cipherbyname], [], [
AC_MSG_ERROR([ You need to have libcrypto installed to compile sngrep])
])
AC_DEFINE([WITH_OPENSSL],[],[Compile With Openssl compatibility])
], [])
+
####
#### PCRE Support
####
@@ -141,7 +170,7 @@ AS_IF([test "x$WITH_PCRE" == "xyes"], [
AC_ARG_ENABLE([ipv6],
AS_HELP_STRING([--enable-ipv6], [Enable IPv6 Support]),
[AC_SUBST(USE_IPV6, $enableval)],
- [AC_SUBST(USE_IPV6, no)]
+ [AC_SUBST(USE_IPV6, yes)]
)
AS_IF([test "x$USE_IPV6" == "xyes"], [
@@ -152,8 +181,24 @@ AS_IF([test "x$USE_IPV6" == "xyes"], [
], [])
+####
+#### EEP Support
+####
+AC_ARG_ENABLE([eep],
+ AS_HELP_STRING([--enable-eep], [Enable EEP/HEP Support]),
+ [AC_SUBST(USE_EEP, $enableval)],
+ [AC_SUBST(USE_EEP, yes)]
+)
+
+AS_IF([test "x$USE_EEP" == "xyes"], [
+ AC_DEFINE([USE_EEP],[],[Compile With EEP support])
+], [])
+
+
# Conditional Source inclusion
+AM_CONDITIONAL([WITH_GNUTLS], [test "x$WITH_GNUTLS" == "xyes"])
AM_CONDITIONAL([WITH_OPENSSL], [test "x$WITH_OPENSSL" == "xyes"])
+AM_CONDITIONAL([USE_EEP], [test "x$USE_EEP" == "xyes"])
######################################################################
@@ -177,10 +222,12 @@ AS_IF([test "x$enable_logo" == "xyes"], [
AC_MSG_NOTICE
AC_MSG_NOTICE( sngrep configure finished )
AC_MSG_NOTICE( ====================================================== )
+AC_MSG_NOTICE( GnuTLS Support : ${WITH_GNUTLS} )
AC_MSG_NOTICE( OpenSSL Support : ${WITH_OPENSSL} )
-AC_MSG_NOTICE( Unicode Support : ${UNICODE} )
+AC_MSG_NOTICE( Unicode Support : ${UNICODE} )
AC_MSG_NOTICE( Perl Expressions Support : ${WITH_PCRE} )
AC_MSG_NOTICE( IPv6 Support : ${USE_IPV6} )
+AC_MSG_NOTICE( EEP Support : ${USE_EEP} )
AC_MSG_NOTICE( ====================================================== )
AC_MSG_NOTICE
diff --git a/doc/sngrep.8 b/doc/sngrep.8
index f63a2bf..212a3fc 100644
--- a/doc/sngrep.8
+++ b/doc/sngrep.8
@@ -3,7 +3,7 @@
.\" Copyright (c) 2013-2015 Ivan Alonso <kaian at irontec.com>
.\" Copyright (c) 2013-2015 Irontec S.L.
-.TH SNGREP 8 "June 2015" "sngrep 1.0.0"
+.TH SNGREP 8 "June 2015" "sngrep 1.0.1"
.SH NAME
diff --git a/src/Makefile.am b/src/Makefile.am
index 96a7cd1..21ea3bc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,10 +1,16 @@
bin_PROGRAMS=sngrep
-sngrep_SOURCES=capture.c capture_eep.c capture_reasm.c capture_ws.c
+sngrep_SOURCES=capture.c capture_reasm.c capture_ws.c
+if USE_EEP
+sngrep_SOURCES+=capture_eep.c
+endif
+if WITH_GNUTLS
+sngrep_SOURCES+=capture_gnutls.c
+endif
if WITH_OPENSSL
-sngrep_SOURCES+=capture_tls.c
+sngrep_SOURCES+=capture_openssl.c
endif
sngrep_SOURCES+=sip.c sip_call.c sip_msg.c sip_attr.c main.c option.c
sngrep_SOURCES+=group.c filter.c keybinding.c media.c setting.c rtp.c util.c vector.c
-sngrep_SOURCES+=ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c
+sngrep_SOURCES+=ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c ui_stats.c
sngrep_SOURCES+=ui_filter.c ui_save.c ui_msg_diff.c ui_column_select.c ui_settings.c
diff --git a/src/capture.c b/src/capture.c
index e204d10..e5a1f59 100644
--- a/src/capture.c
+++ b/src/capture.c
@@ -35,9 +35,14 @@
#include "capture.h"
#include "capture_ws.h"
#include "capture_reasm.h"
+#ifdef USE_EEP
#include "capture_eep.h"
+#endif
+#ifdef WITH_GNUTLS
+#include "capture_gnutls.h"
+#endif
#ifdef WITH_OPENSSL
-#include "capture_tls.h"
+#include "capture_openssl.h"
#endif
#include "sip.h"
#include "rtp.h"
@@ -300,7 +305,7 @@ parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packe
if (!(pkt = capture_packet_reasm_tcp(pkt, tcp, payload, size_payload)))
return;
-#ifdef WITH_OPENSSL
+#if defined(WITH_GNUTLS) || defined(WITH_OPENSSL)
// Check if packet is TLS
if (capture_cfg.keyfile)
tls_process_segment(pkt, tcp);
@@ -319,8 +324,10 @@ parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packe
capture_lock();
// Check if we can handle this packet
if (capture_packet_parse(pkt) == 0) {
+#ifdef USE_EEP
// Send this packet through eep
capture_eep_send(pkt);
+#endif
// Store this packets in output file
dump_packet(capture_cfg.pd, pkt);
// If storage is disabled, delete frames payload
diff --git a/src/capture.h b/src/capture.h
index 86f9797..2ca77bc 100644
--- a/src/capture.h
+++ b/src/capture.h
@@ -108,6 +108,7 @@ enum capture_packet_type {
CAPTURE_PACKET_SIP_WS,
CAPTURE_PACKET_SIP_WSS,
CAPTURE_PACKET_RTP,
+ CAPTURE_PACKET_RTCP,
};
/**
diff --git a/src/capture_tls.c b/src/capture_gnutls.c
similarity index 79%
copy from src/capture_tls.c
copy to src/capture_gnutls.c
index 3ba3455..22345d5 100644
--- a/src/capture_tls.c
+++ b/src/capture_gnutls.c
@@ -32,7 +32,7 @@
#include <unistd.h>
#include "capture.h"
-#include "capture_tls.h"
+#include "capture_gnutls.h"
#include "option.h"
#include "util.h"
#include "sip.h"
@@ -48,14 +48,15 @@ int
P_hash(const char *digest, unsigned char *dest, int dlen, unsigned char *secret, int sslen,
unsigned char *seed, int slen)
{
- unsigned char hmac[20];
+ unsigned char hmac[48];
unsigned int hlen;
- HMAC_CTX hm;
- const EVP_MD *md = EVP_get_digestbyname(digest);
+ gcry_md_hd_t md;
unsigned int tmpslen;
unsigned char tmpseed[slen];
unsigned char *out = dest;
int pending = dlen;
+ int algo = gcry_md_map_name(digest);
+ int algolen = gcry_md_get_algo_dlen(algo);
// Copy initial seed
memcpy(tmpseed, seed, slen);
@@ -63,21 +64,25 @@ P_hash(const char *digest, unsigned char *dest, int dlen, unsigned char *secret,
// Calculate enough data to fill destination
while (pending > 0) {
- HMAC_Init(&hm, secret, sslen, md);
- HMAC_Update(&hm, tmpseed, tmpslen);
- HMAC_Final(&hm, tmpseed, &tmpslen);
-
- HMAC_Init(&hm, secret, sslen, md);
- HMAC_Update(&hm, tmpseed, tmpslen);
- HMAC_Update(&hm, seed, slen);
- HMAC_Final(&hm, hmac, &hlen);
+ gcry_md_open(&md, algo, GCRY_MD_FLAG_HMAC);
+ gcry_md_setkey(md, secret, sslen);
+ gcry_md_write(md, tmpseed, tmpslen);
+ memcpy(tmpseed, gcry_md_read(md, algo), algolen);
+ tmpslen = algolen;
+ gcry_md_close(md);
+
+ gcry_md_open(&md, algo, GCRY_MD_FLAG_HMAC);
+ gcry_md_setkey(md, secret, sslen);
+ gcry_md_write(md, tmpseed, tmpslen);
+ gcry_md_write(md, seed, slen);
+ memcpy(hmac, gcry_md_read(md, algo), algolen);
+ hlen = algolen;
hlen = (hlen > pending) ? pending : hlen;
memcpy(out, hmac, hlen);
out += hlen;
pending -= hlen;
}
- HMAC_cleanup(&hm);
return hlen;
}
@@ -119,6 +124,12 @@ PRF(unsigned char *dest, int dlen, unsigned char *pre_master_secret, int plen, u
struct SSLConnection *
tls_connection_create(struct in_addr caddr, u_short cport, struct in_addr saddr, u_short sport) {
struct SSLConnection *conn = NULL;
+ gnutls_datum_t keycontent = { NULL, 0 };
+ FILE *keyfp;
+ gnutls_x509_privkey_t spkey;
+ size_t br;
+
+ // Allocate memory for this connection
conn = sng_malloc(sizeof(struct SSLConnection));
memcpy(&conn->client_addr, &caddr, sizeof(struct in_addr));
@@ -127,18 +138,28 @@ tls_connection_create(struct in_addr caddr, u_short cport, struct in_addr saddr,
memcpy(&conn->server_port, &sport, sizeof(u_short));
SSL_library_init();
- ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
if (!(conn->ssl_ctx = SSL_CTX_new(SSLv23_server_method())))
return NULL;
- SSL_CTX_use_PrivateKey_file(conn->ssl_ctx, capture_get_keyfile(),
- SSL_FILETYPE_PEM);
if (!(conn->ssl = SSL_new(conn->ssl_ctx)))
return NULL;
- conn->server_private_key = SSL_get_privatekey(conn->ssl);
+ if (!(keyfp = fopen(capture_get_keyfile(), "rb")))
+ return NULL;
+ fseek(keyfp, 0, SEEK_END);
+ keycontent.size = ftell(keyfp);
+ fseek(keyfp, 0, SEEK_SET);
+ keycontent.data = sng_malloc(keycontent.size);
+ br = fread(keycontent.data, 1, keycontent.size, keyfp);
+ fclose(keyfp);
+
+ gnutls_x509_privkey_init(&spkey);
+ gnutls_x509_privkey_import(spkey, &keycontent, GNUTLS_X509_FMT_PEM);
+ sng_free(keycontent.data);
+ gnutls_privkey_init(&conn->server_private_key);
+ gnutls_privkey_import_x509(conn->server_private_key, spkey, 0);
// Add this connection to the list
conn->next = connections;
@@ -179,25 +200,31 @@ tls_connection_destroy(struct SSLConnection *conn)
int
tls_check_keyfile(const char *keyfile)
{
- SSL *ssl;
- SSL_CTX *ssl_ctx;
+ gnutls_x509_privkey_t key;
+ gnutls_datum_t keycontent = { NULL, 0 };
+ FILE *keyfp;
+ size_t br;
SSL_library_init();
- ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
if (access(capture_get_keyfile(), R_OK) != 0)
return 0;
- if (!(ssl_ctx = SSL_CTX_new(SSLv23_server_method())))
+ if (!(keyfp = fopen(capture_get_keyfile(), "rb")))
return 0;
- SSL_CTX_use_PrivateKey_file(ssl_ctx, capture_get_keyfile(), SSL_FILETYPE_PEM);
- if (!(ssl = SSL_new(ssl_ctx)))
- return 0;
+ fseek(keyfp, 0, SEEK_END);
+ keycontent.size = ftell(keyfp);
+ fseek(keyfp, 0, SEEK_SET);
+ keycontent.data = sng_malloc(keycontent.size);
+ br = fread(keycontent.data, 1, keycontent.size, keyfp);
+ fclose(keyfp);
- if (!SSL_get_privatekey(ssl))
+ gnutls_x509_privkey_init(&key);
+ if (gnutls_x509_privkey_import(key, &keycontent, GNUTLS_X509_FMT_PEM) < 0)
return 0;
+ sng_free(keycontent.data);
return 1;
}
@@ -358,7 +385,6 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment)
// Store client random
clienthello = (struct ClientHello *) body;
memcpy(&conn->client_random, &clienthello->random, sizeof(struct Random));
-
// Check we have a TLS handshake
if (!(clienthello->client_version.major == 0x03
&& clienthello->client_version.minor == 0x01)) {
@@ -389,16 +415,16 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment)
// Decrypt PreMasterKey
clientkeyex = (struct ClientKeyExchange *) body;
- RSA_private_decrypt(UINT16_INT(clientkeyex->length),
- (const unsigned char *) &clientkeyex->exchange_keys,
- (unsigned char *) &conn->pre_master_secret,
- conn->server_private_key->pkey.rsa, RSA_PKCS1_PADDING);
+ gnutls_datum_t exkeys, pms;
+ exkeys.size = UINT16_INT(clientkeyex->length);
+ exkeys.data = (unsigned char *)&clientkeyex->exchange_keys;
+ gnutls_privkey_decrypt_data(conn->server_private_key, 0, &exkeys, &pms);
+ memcpy(&conn->pre_master_secret, pms.data, pms.size);
+ // Get MasterSecret
unsigned char *seed = sng_malloc(sizeof(struct Random) * 2);
memcpy(seed, &conn->client_random, sizeof(struct Random));
memcpy(seed + sizeof(struct Random), &conn->server_random, sizeof(struct Random));
-
- // Get MasterSecret
PRF((unsigned char *) &conn->master_secret, sizeof(struct MasterSecret),
(unsigned char *) &conn->pre_master_secret, sizeof(struct PreMasterSecret),
(unsigned char *) "master secret", seed, sizeof(struct Random) * 2);
@@ -415,15 +441,22 @@ tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment)
sng_free(seed);
// Create Client decoder
- EVP_CIPHER_CTX_init(&conn->client_cipher_ctx);
- EVP_CipherInit(&conn->client_cipher_ctx, conn->ciph,
- conn->key_material.client_write_key, conn->key_material.client_write_IV,
- 0);
-
- EVP_CIPHER_CTX_init(&conn->server_cipher_ctx);
- EVP_CipherInit(&conn->server_cipher_ctx, conn->ciph,
- conn->key_material.server_write_key, conn->key_material.server_write_IV,
- 0);
+ gcry_cipher_open(&conn->client_cipher_ctx, conn->ciph, GCRY_CIPHER_MODE_CBC, 0);
+ gcry_cipher_setkey(conn->client_cipher_ctx,
+ conn->key_material.client_write_key,
+ gcry_cipher_get_algo_keylen(conn->ciph));
+ gcry_cipher_setiv(conn->client_cipher_ctx,
+ conn->key_material.client_write_IV,
+ gcry_cipher_get_algo_blklen(conn->ciph));
+
+ // Create Server decoder
+ gcry_cipher_open(&conn->server_cipher_ctx, conn->ciph, GCRY_CIPHER_MODE_CBC, 0);
+ gcry_cipher_setkey(conn->server_cipher_ctx,
+ conn->key_material.server_write_key,
+ gcry_cipher_get_algo_keylen(conn->ciph));
+ gcry_cipher_setiv(conn->server_cipher_ctx,
+ conn->key_material.server_write_IV,
+ gcry_cipher_get_algo_blklen(conn->ciph));
break;
case finished:
@@ -447,10 +480,10 @@ int
tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, const int len,
uint8 **out, uint32_t *outl)
{
- EVP_CIPHER_CTX *evp;
+ gcry_cipher_hd_t *evp;
unsigned char pad;
unsigned char *decoded;
- uint32_t dlen;
+ size_t dlen = len;
if (conn->direction == 0) {
evp = &conn->client_cipher_ctx;
@@ -459,7 +492,7 @@ tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, cons
}
decoded = sng_malloc(len);
- EVP_Cipher(evp, decoded, (unsigned char *) fragment, len);
+ gcry_cipher_decrypt(*evp, decoded, dlen, (unsigned char *) fragment, len);
// Get padding counter and remove from data
pad = decoded[len - 1];
@@ -482,9 +515,9 @@ tls_connection_load_cipher(struct SSLConnection *conn)
return 1;
if (conn->cipher_suite.cs2 == TLS_RSA_WITH_AES_256_CBC_SHA.cs2) {
- conn->ciph = EVP_get_cipherbyname("AES256");
+ conn->ciph = gcry_cipher_map_name("AES256");
} else if (conn->cipher_suite.cs2 == TLS_RSA_WITH_AES_128_CBC_SHA.cs2) {
- conn->ciph = EVP_get_cipherbyname("AES128");
+ conn->ciph = gcry_cipher_map_name("AES");
} else {
return 1;
}
diff --git a/src/capture_tls.h b/src/capture_gnutls.h
similarity index 92%
copy from src/capture_tls.h
copy to src/capture_gnutls.h
index 4208066..931cbce 100644
--- a/src/capture_tls.h
+++ b/src/capture_gnutls.h
@@ -47,10 +47,11 @@
#define __SNGREP_CAPTURE_TLS_
#include "config.h"
-#include <openssl/ssl.h>
-#include <openssl/tls1.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
+#include <gnutls/openssl.h>
+#include <gnutls/crypto.h>
+#include <gnutls/abstract.h>
+#include <gnutls/x509.h>
+#include <gcrypt.h>
#include "capture.h"
//! Cast two bytes into decimal (Big Endian)
@@ -97,23 +98,23 @@ enum SSLConnectionState {
//! ContentType values as defined in RFC5246
enum ContentType {
- change_cipher_spec = SSL3_RT_CHANGE_CIPHER_SPEC,
- alert = SSL3_RT_ALERT,
- handshake = SSL3_RT_HANDSHAKE,
- application_data = SSL3_RT_APPLICATION_DATA
+ change_cipher_spec = 20,
+ alert = 21,
+ handshake = 22,
+ application_data = 23
};
//! HanshakeType values as defined in RFC5246
enum HandshakeType {
- hello_request = SSL3_MT_HELLO_REQUEST,
- client_hello = SSL3_MT_CLIENT_HELLO,
- server_hello = SSL3_MT_SERVER_HELLO,
- certificate = SSL3_MT_CERTIFICATE,
- certificate_request = SSL3_MT_CERTIFICATE_REQUEST,
- server_hello_done = SSL3_MT_SERVER_DONE,
- certificate_verify = SSL3_MT_CERTIFICATE_VERIFY,
- client_key_exchange = SSL3_MT_CLIENT_KEY_EXCHANGE,
- finished = SSL3_MT_FINISHED
+ hello_request = GNUTLS_HANDSHAKE_HELLO_REQUEST,
+ client_hello = GNUTLS_HANDSHAKE_CLIENT_HELLO,
+ server_hello = GNUTLS_HANDSHAKE_SERVER_HELLO,
+ certificate = GNUTLS_HANDSHAKE_CERTIFICATE_PKT,
+ certificate_request = GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST,
+ server_hello_done = GNUTLS_HANDSHAKE_SERVER_HELLO_DONE,
+ certificate_verify = GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY,
+ client_key_exchange = GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE,
+ finished = GNUTLS_HANDSHAKE_FINISHED
};
//! ProtocolVersion header as defined in RFC5246
@@ -208,8 +209,8 @@ struct SSLConnection {
SSL *ssl;
SSL_CTX *ssl_ctx;
- EVP_PKEY *server_private_key;
- const EVP_CIPHER *ciph;
+ int ciph;
+ gnutls_privkey_t server_private_key;
struct Random client_random;
struct Random server_random;
struct CipherSuite cipher_suite;
@@ -225,8 +226,8 @@ struct SSLConnection {
uint8 server_write_IV[16];
} key_material;
- EVP_CIPHER_CTX client_cipher_ctx;
- EVP_CIPHER_CTX server_cipher_ctx;
+ gcry_cipher_hd_t client_cipher_ctx;
+ gcry_cipher_hd_t server_cipher_ctx;
struct SSLConnection *next;
};
diff --git a/src/capture_tls.c b/src/capture_openssl.c
similarity index 99%
rename from src/capture_tls.c
rename to src/capture_openssl.c
index 3ba3455..17f2c31 100644
--- a/src/capture_tls.c
+++ b/src/capture_openssl.c
@@ -32,7 +32,7 @@
#include <unistd.h>
#include "capture.h"
-#include "capture_tls.h"
+#include "capture_openssl.h"
#include "option.h"
#include "util.h"
#include "sip.h"
diff --git a/src/capture_tls.h b/src/capture_openssl.h
similarity index 100%
rename from src/capture_tls.h
rename to src/capture_openssl.h
diff --git a/src/capture_reasm.c b/src/capture_reasm.c
index ebc258e..3aea2fa 100644
--- a/src/capture_reasm.c
+++ b/src/capture_reasm.c
@@ -58,6 +58,8 @@ capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *heade
uint32_t ip_hl = 0;
// Fragment offset
uint16_t ip_off = 0;
+ // IP content len
+ uint16_t ip_len = 0;
// Fragmentation flag
uint16_t ip_frag = 0;
// Fragmentation identifier
@@ -92,6 +94,7 @@ capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *heade
ip_hl = ip4->ip_hl * 4;
ip_proto = ip4->ip_p;
ip_off = ntohs(ip4->ip_off);
+ ip_len = ntohs(ip4->ip_len);
ip_frag = ip_off & (IP_MF | IP_OFFMASK);
ip_frag_off = (ip_frag) ? (ip_off & IP_OFFMASK) * 8 : 0;
@@ -104,6 +107,7 @@ capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *heade
case 6:
ip_hl = sizeof(struct ip6_hdr);
ip_proto = ip6->ip6_nxt;
+ ip_len = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen) + ip_hl;
if (ip_proto == IPPROTO_FRAGMENT) {
struct ip6_frag *ip6f = (struct ip6_frag *) (ip6 + ip_hl);
@@ -120,7 +124,11 @@ capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *heade
}
// Remove IP Header length from payload
- *size = *caplen - capinfo->link_hl - ip_hl;
+ if (*caplen > capinfo->link_hl + ip_len) {
+ *size = ip_len - ip_hl;
+ } else {
+ *size = *caplen - capinfo->link_hl - ip_hl;
+ }
// If no fragmentation
if (ip_frag == 0) {
diff --git a/src/filter.c b/src/filter.c
index b460ebd..4dbae8b 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -45,7 +45,7 @@ filter_set(int type, const char *expr)
if (expr) {
const char *re_err = NULL;
int32_t err_offset;
- int32_t pcre_options = PCRE_UNGREEDY | PCRE_CASELESS;
+ int32_t pcre_options = PCRE_UNGREEDY | PCRE_CASELESS;
// Check if we have a valid expression
if (!(regex = pcre_compile(expr, pcre_options, &re_err, &err_offset, 0)))
@@ -95,8 +95,10 @@ int
filter_check_call(void *item)
{
int i;
- char data[256];
+ char data[MAX_SIP_PAYLOAD];
sip_call_t *call = (sip_call_t*) item;
+ sip_msg_t *msg;
+ vector_iter_t it;
// Dont filter calls without messages
if (call_msg_count(call) == 0)
@@ -135,6 +137,8 @@ filter_check_call(void *item)
case FILTER_METHOD:
call_get_attribute(call, SIP_ATTR_METHOD, data);
break;
+ case FILTER_PAYLOAD:
+ break;
case FILTER_CALL_LIST:
// FIXME Maybe call should know hot to calculate this line
call_list_line_text(ui_get_panel(ui_find_by_type(PANEL_CALL_LIST)), call, data);
@@ -144,26 +148,48 @@ filter_check_call(void *item)
return 0;
}
-#ifdef WITH_PCRE
- if (pcre_exec(filters[i].regex, 0, data, strlen(data), 0, 0, 0, 0)) {
- // Mak as filtered
+ // For payload filtering, check all messages payload
+ if (i == FILTER_PAYLOAD) {
+ // Assume this call doesn't match the filter
call->filtered = 1;
- break;
- }
-#else
- // Call doesn't match this filter
- if (regexec(&filters[i].regex, data, 0, NULL, 0)) {
- // Mak as filtered
- call->filtered = 1;
- break;
+ // Create an iterator for the call messages
+ it = vector_iterator(call->msgs);
+ while ((msg = vector_iterator_next(&it))) {
+ // Copy message payload
+ strcpy(data, msg_get_payload(msg));
+ // Check if this payload matches the filter
+ if (filter_check_expr(filters[i], data) == 0) {
+ call->filtered = 0;
+ break;
+ }
+ }
+ if (call->filtered == 1)
+ break;
+ } else {
+ // Check the filter against given data
+ if (filter_check_expr(filters[i], data) != 0) {
+ // The data didn't matched the filter
+ call->filtered = 1;
+ break;
+ }
}
-#endif
}
// Return the final filter status
return (call->filtered == 0);
}
+int
+filter_check_expr(filter_t filter, const char *data)
+{
+#ifdef WITH_PCRE
+ return pcre_exec(filter.regex, 0, data, strlen(data), 0, 0, 0, 0);
+#else
+ // Call doesn't match this filter
+ return regexec(&filter.regex, data, 0, NULL, 0);
+#endif
+}
+
void
filter_reset_calls()
{
diff --git a/src/filter.h b/src/filter.h
index 44cf630..e31b23c 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -65,6 +65,8 @@ enum filter_type {
FILTER_DESTINATION,
//! SIP Method in packet payload
FILTER_METHOD,
+ //! SIP Payload in any call packet
+ FILTER_PAYLOAD,
//! Displayed line in call list
FILTER_CALL_LIST,
//! Number of available filter types
@@ -119,6 +121,14 @@ int
filter_check_call(void *item);
/**
+ * @brief Check if data matches the filter regexp
+ *
+ * @return 0 if the given data matches the filter
+ */
+int
+filter_check_expr(filter_t filter, const char *data);
+
+/**
* @brief Reset filtered flag in all calls
*
* This function can be used to force reevaluation
diff --git a/src/keybinding.c b/src/keybinding.c
index 28732d8..c34fedf 100644
--- a/src/keybinding.c
+++ b/src/keybinding.c
@@ -36,145 +36,117 @@
#include "keybinding.h"
//! sngrep keybindings
-key_binding_t bindings[ACTION_SENTINEL];
-
-void
-key_bindings_init()
-{
- // Initialize bindings structure
- memset(bindings, 0, sizeof(key_binding_t) * ACTION_SENTINEL);
-
- // Set default keybindings
- key_bind_action(ACTION_UP, KEY_UP);
- key_bind_action(ACTION_UP, 'j');
- key_bind_action(ACTION_DOWN, KEY_DOWN);
- key_bind_action(ACTION_DOWN, 'k');
- key_bind_action(ACTION_LEFT, KEY_LEFT);
- key_bind_action(ACTION_LEFT, 'h');
- key_bind_action(ACTION_RIGHT, KEY_RIGHT);
- key_bind_action(ACTION_RIGHT, 'l');
- key_bind_action(ACTION_DELETE, KEY_DC);
- key_bind_action(ACTION_BACKSPACE, KEY_BACKSPACE);
- key_bind_action(ACTION_BACKSPACE, KEY_BACKSPACE2);
- key_bind_action(ACTION_BACKSPACE, KEY_BACKSPACE3);
- key_bind_action(ACTION_NPAGE, KEY_NPAGE);
- key_bind_action(ACTION_NPAGE, KEY_CTRL('F'));
- key_bind_action(ACTION_PPAGE, KEY_PPAGE);
- key_bind_action(ACTION_PPAGE, KEY_CTRL('B'));
- key_bind_action(ACTION_HNPAGE, KEY_CTRL('D'));
- key_bind_action(ACTION_HPPAGE, KEY_CTRL('U'));
- key_bind_action(ACTION_BEGIN, KEY_HOME);
- key_bind_action(ACTION_BEGIN, KEY_CTRL('A'));
- key_bind_action(ACTION_END, KEY_END);
- key_bind_action(ACTION_END, KEY_CTRL('E'));
- key_bind_action(ACTION_PREV_FIELD, KEY_UP);
- key_bind_action(ACTION_NEXT_FIELD, KEY_TAB);
- key_bind_action(ACTION_NEXT_FIELD, KEY_DOWN);
- key_bind_action(ACTION_RESIZE_SCREEN, KEY_RESIZE);
- key_bind_action(ACTION_CLEAR, KEY_CTRL('U'));
- key_bind_action(ACTION_CLEAR, KEY_CTRL('W'));
- key_bind_action(ACTION_CLEAR_CALLS, KEY_F(5));
- key_bind_action(ACTION_TOGGLE_SYNTAX, KEY_F(8));
- key_bind_action(ACTION_TOGGLE_SYNTAX, 'C');
- key_bind_action(ACTION_CYCLE_COLOR, KEY_F(7));
- key_bind_action(ACTION_CYCLE_COLOR, 'c');
- key_bind_action(ACTION_SHOW_HOSTNAMES, KEY_F(9));
- key_bind_action(ACTION_SHOW_ALIAS, 'a');
- key_bind_action(ACTION_TOGGLE_PAUSE, 'p');
- key_bind_action(ACTION_PREV_SCREEN, KEY_ESC);
- key_bind_action(ACTION_PREV_SCREEN, 'q');
- key_bind_action(ACTION_PREV_SCREEN, 'Q');
- key_bind_action(ACTION_SHOW_HELP, KEY_F(1));
- key_bind_action(ACTION_SHOW_HELP, 'h');
- key_bind_action(ACTION_SHOW_HELP, 'H');
- key_bind_action(ACTION_SHOW_HELP, '?');
- key_bind_action(ACTION_SHOW_RAW, KEY_F(6));
- key_bind_action(ACTION_SHOW_RAW, 'r');
- key_bind_action(ACTION_SHOW_RAW, 'R');
- key_bind_action(ACTION_SHOW_FLOW, KEY_INTRO);
- key_bind_action(ACTION_SHOW_FLOW_EX, KEY_F(4));
- key_bind_action(ACTION_SHOW_FLOW_EX, 'x');
- key_bind_action(ACTION_SHOW_FLOW_EX, 'X');
- key_bind_action(ACTION_SHOW_FILTERS, KEY_F(7));
- key_bind_action(ACTION_SHOW_FILTERS, 'f');
- key_bind_action(ACTION_SHOW_FILTERS, 'F');
- key_bind_action(ACTION_SHOW_COLUMNS, KEY_F(10));
- key_bind_action(ACTION_SHOW_COLUMNS, 't');
- key_bind_action(ACTION_SHOW_COLUMNS, 'T');
- key_bind_action(ACTION_SHOW_SETTINGS, KEY_F(8));
- key_bind_action(ACTION_SHOW_SETTINGS, 'o');
- key_bind_action(ACTION_SHOW_SETTINGS, 'O');
- key_bind_action(ACTION_COLUMN_MOVE_UP, '-');
- key_bind_action(ACTION_COLUMN_MOVE_DOWN, '+');
- key_bind_action(ACTION_DISP_FILTER, KEY_F(3));
- key_bind_action(ACTION_DISP_FILTER, '/');
- key_bind_action(ACTION_DISP_FILTER, KEY_TAB);
- key_bind_action(ACTION_DISP_INVITE, 'i');
- key_bind_action(ACTION_DISP_INVITE, 'I');
- key_bind_action(ACTION_SAVE, KEY_F(2));
- key_bind_action(ACTION_SAVE, 's');
- key_bind_action(ACTION_SAVE, 'S');
- key_bind_action(ACTION_SELECT, KEY_SPACE);
- key_bind_action(ACTION_CONFIRM, KEY_INTRO);
- key_bind_action(ACTION_TOGGLE_RAW, 't');
- key_bind_action(ACTION_TOGGLE_MEDIA, KEY_F(3));
- key_bind_action(ACTION_TOGGLE_MEDIA, 'm');
- key_bind_action(ACTION_INCREASE_RAW, '9');
- key_bind_action(ACTION_DECREASE_RAW, '0');
- key_bind_action(ACTION_RESET_RAW, 'T');
- key_bind_action(ACTION_ONLY_SDP, 'D');
- key_bind_action(ACTION_SDP_INFO, KEY_F(2));
- key_bind_action(ACTION_SDP_INFO, 'd');
- key_bind_action(ACTION_COMPRESS, KEY_F(5));
- key_bind_action(ACTION_COMPRESS, 's');
- key_bind_action(ACTION_TOGGLE_HINT, 'K');
-}
+key_binding_t bindings[ACTION_SENTINEL] = {
+ { ACTION_PRINTABLE, "", { }, 0 },
+ { ACTION_UP, "up", { KEY_UP, 'j' }, 2 },
+ { ACTION_DOWN, "down", { KEY_DOWN, 'k' }, 2 },
+ { ACTION_LEFT, "left", { KEY_LEFT, 'h' }, 2 },
+ { ACTION_RIGHT, "right", { KEY_RIGHT, 'l'}, 2 },
+ { ACTION_DELETE, "delete", { KEY_DC }, 1 },
+ { ACTION_BACKSPACE, "backspace", { KEY_BACKSPACE, KEY_BACKSPACE2, KEY_BACKSPACE3 }, 3 },
+ { ACTION_NPAGE, "npage", { KEY_NPAGE, KEY_CTRL('F') }, 2 },
+ { ACTION_PPAGE, "ppage", { KEY_PPAGE, KEY_CTRL('B') }, 2 },
+ { ACTION_HNPAGE, "hnpage", { KEY_CTRL('D') }, 1 },
+ { ACTION_HPPAGE, "hppage", { KEY_CTRL('U') }, 2 },
+ { ACTION_BEGIN, "begin", { KEY_HOME, KEY_CTRL('A') }, 2 },
+ { ACTION_END, "end", { KEY_END, KEY_CTRL('E') }, 2 },
+ { ACTION_PREV_FIELD, "pfield", { KEY_UP }, 1 },
+ { ACTION_NEXT_FIELD, "nfield", { KEY_DOWN, KEY_TAB }, 2 },
+ { ACTION_RESIZE_SCREEN, "", { KEY_RESIZE }, 1 },
+ { ACTION_CLEAR, "clear", { KEY_CTRL('U'), KEY_CTRL('W')}, 2 },
+ { ACTION_CLEAR_CALLS, "clearcalls", { KEY_F(5) }, 1 },
+ { ACTION_TOGGLE_SYNTAX, "togglesyntax", { KEY_F(8), 'C' }, 2 },
+ { ACTION_CYCLE_COLOR, "colormode", { 'c' }, 1 },
+ { ACTION_SHOW_HOSTNAMES, "togglehostname", { KEY_F(9) }, 1 },
+ { ACTION_SHOW_ALIAS, "togglealias", { 'a' }, 1 },
+ { ACTION_TOGGLE_PAUSE, "pause", { 'p' }, 1 },
+ { ACTION_PREV_SCREEN, "prevscreen", { KEY_ESC, 'q', 'Q' }, 3 },
+ { ACTION_SHOW_HELP, "help", { KEY_F(1), 'h', 'H', '?' }, 4 },
+ { ACTION_SHOW_RAW, "raw", { KEY_F(6), 'R', 'r' }, 3 },
+ { ACTION_SHOW_FLOW, "flow", { KEY_INTRO }, 1 },
+ { ACTION_SHOW_FLOW_EX, "flowex", { KEY_F(4), 'x', 'X' }, 3 },
+ { ACTION_SHOW_FILTERS, "filters", { KEY_F(7), 'f', 'F' }, 3 },
+ { ACTION_SHOW_COLUMNS, "columns", { KEY_F(10), 't', 'T' }, 3 },
+ { ACTION_SHOW_SETTINGS, "settings", { KEY_F(8), 'o', 'O' }, 3 },
+ { ACTION_SHOW_STATS, "stats", { 'i' }, 1 },
+ { ACTION_COLUMN_MOVE_UP, "columnup", { '-' }, 1 },
+ { ACTION_COLUMN_MOVE_DOWN, "columndown", { '+' }, 1 },
+ { ACTION_DISP_FILTER, "search", { KEY_F(3), '/', KEY_TAB }, 3 },
+ { ACTION_SAVE, "save", { KEY_F(2), 's', 'S'}, 3 },
+ { ACTION_SELECT, "select", { KEY_SPACE }, 1 },
+ { ACTION_CONFIRM, "confirm", { KEY_INTRO }, 1 },
+ { ACTION_TOGGLE_MEDIA, "togglemedia", { KEY_F(3), 'm' }, 2 },
+ { ACTION_TOGGLE_RAW, "rawpreview", { 't' }, 1 },
+ { ACTION_INCREASE_RAW, "morerawpreview", { '9' }, 1 },
+ { ACTION_DECREASE_RAW, "lessrawpreview", { '0' }, 1 },
+ { ACTION_RESET_RAW, "resetrawpreview", { 'T' }, 1 },
+ { ACTION_ONLY_SDP, "onlysdp", { 'D' }, 1 },
+ { ACTION_SDP_INFO, "sdpinfo", { KEY_F(2), 'd' }, 2 },
+ { ACTION_COMPRESS, "compress", { 's' }, 1 },
+ { ACTION_TOGGLE_HINT, "hintalt", { 'K' }, 1 },
+};
void
key_bindings_dump()
{
int i, j;
for (i = 1; i < ACTION_SENTINEL; i++) {
-
for (j = 0; j < bindings[i].bindcnt; j++) {
- printf("ActionID: %d\t Key: %d \t%s\n", i,
+ printf("ActionID: %d\t ActionName: %-21s Key: %d (%s)\n",
+ bindings[i].id,
+ bindings[i].name,
bindings[i].keys[j],
key_to_str(bindings[i].keys[j]));
}
}
}
+key_binding_t *
+key_binding_data(int action)
+{
+ int i;
+ for (i = 1; i < ACTION_SENTINEL; i++) {
+ if (bindings[i].id == action)
+ return &bindings[i];
+ }
+
+ return NULL;
+}
+
void
key_bind_action(int action, int key)
{
- if (action < 0)
+ key_binding_t *bind;
+
+ if (!(bind = key_binding_data(action)))
return;
- if (bindings[action].bindcnt == MAX_BINDINGS)
+ if (bind->bindcnt == MAX_BINDINGS)
return;
- bindings[action].keys[bindings[action].bindcnt++] = key;
+ bind->keys[bind->bindcnt++] = key;
}
void
key_unbind_action(int action, int key)
{
- key_binding_t bind;
+ key_binding_t tmp, *bind;
int i;
// Action is not valid
- if (action < 0)
+ if (!(bind = key_binding_data(action)))
return;
// Copy binding to temporal struct
- memcpy(&bind, &bindings[action], sizeof(key_binding_t));
+ memcpy(&tmp, bind, sizeof(key_binding_t));
+
// Reset bindings for this action
- memset(&bindings[action], 0, sizeof(key_binding_t));
+ memset(&bind->keys, 0, sizeof(int) * MAX_BINDINGS);
// Add all bindings but the unbinded
- for (i=0; i < bind.bindcnt; i++) {
- if (bind.keys[i] != key) {
- key_bind_action(action, bind.keys[i]);
+ for (i=0; i < tmp.bindcnt; i++) {
+ if (tmp.keys[i] != key) {
+ key_bind_action(action, tmp.keys[i]);
}
}
}
@@ -190,7 +162,7 @@ key_find_action(int key, int start)
for (j = 0; j < bindings[i].bindcnt; j++)
if (bindings[i].keys[j] == key)
- return i;
+ return bindings[i].id;
}
return -1;
}
@@ -198,49 +170,12 @@ key_find_action(int key, int start)
int
key_action_id(const char *action)
{
+ int i;
+ for (i = 1; i < ACTION_SENTINEL; i++) {
+ if (!strcasecmp(action, bindings[i].name))
+ return bindings[i].id;
- if (!strcmp(action, "up")) return ACTION_UP;
- if (!strcmp(action, "down")) return ACTION_DOWN;
- if (!strcmp(action, "left")) return ACTION_LEFT;
- if (!strcmp(action, "right")) return ACTION_RIGHT;
- if (!strcmp(action, "delete")) return ACTION_DELETE;
- if (!strcmp(action, "backspace")) return ACTION_BACKSPACE;
- if (!strcmp(action, "npage")) return ACTION_NPAGE;
- if (!strcmp(action, "ppage")) return ACTION_PPAGE;
- if (!strcmp(action, "hnpage")) return ACTION_HNPAGE;
- if (!strcmp(action, "hppage")) return ACTION_HPPAGE;
- if (!strcmp(action, "begin")) return ACTION_BEGIN;
- if (!strcmp(action, "end")) return ACTION_END;
- if (!strcmp(action, "pfield")) return ACTION_PREV_FIELD;
- if (!strcmp(action, "nfield")) return ACTION_NEXT_FIELD;
- if (!strcmp(action, "clear")) return ACTION_CLEAR;
- if (!strcmp(action, "clearcalls")) return ACTION_CLEAR_CALLS;
- if (!strcmp(action, "togglesyntax")) return ACTION_TOGGLE_SYNTAX;
- if (!strcmp(action, "colormode")) return ACTION_CYCLE_COLOR;
- if (!strcmp(action, "togglehostname")) return ACTION_SHOW_HOSTNAMES;
- if (!strcmp(action, "togglealias")) return ACTION_SHOW_ALIAS;
- if (!strcmp(action, "pause")) return ACTION_TOGGLE_PAUSE;
- if (!strcmp(action, "prevscreen")) return ACTION_PREV_SCREEN;
- if (!strcmp(action, "help")) return ACTION_SHOW_HELP;
- if (!strcmp(action, "raw")) return ACTION_SHOW_RAW;
- if (!strcmp(action, "flow")) return ACTION_SHOW_FLOW;
- if (!strcmp(action, "flowex")) return ACTION_SHOW_FLOW_EX;
- if (!strcmp(action, "filters")) return ACTION_SHOW_FILTERS;
- if (!strcmp(action, "columns")) return ACTION_SHOW_COLUMNS;
- if (!strcmp(action, "columnup")) return ACTION_COLUMN_MOVE_UP;
- if (!strcmp(action, "columndown")) return ACTION_COLUMN_MOVE_DOWN;
- if (!strcmp(action, "search")) return ACTION_DISP_FILTER;
- if (!strcmp(action, "save")) return ACTION_SAVE;
- if (!strcmp(action, "select")) return ACTION_SELECT;
- if (!strcmp(action, "confirm")) return ACTION_CONFIRM;
- if (!strcmp(action, "rawpreview")) return ACTION_TOGGLE_RAW;
- if (!strcmp(action, "morerawpreview")) return ACTION_INCREASE_RAW;
- if (!strcmp(action, "lessrawpreview")) return ACTION_DECREASE_RAW;
- if (!strcmp(action, "resetrawpreview")) return ACTION_RESET_RAW;
- if (!strcmp(action, "onlysdp")) return ACTION_ONLY_SDP;
- if (!strcmp(action, "sdpinfo")) return ACTION_SDP_INFO;
- if (!strcmp(action, "compress")) return ACTION_COMPRESS;
- if (!strcmp(action, "hintalt")) return ACTION_TOGGLE_HINT;
+ }
return -1;
}
@@ -323,11 +258,16 @@ key_from_str(const char *key)
const char *
key_action_key_str(int action)
{
- if (setting_enabled(SETTING_ALTKEY_HINT) && bindings[action].bindcnt > 1) {
+ key_binding_t *bind;
+
+ if (!(bind = key_binding_data(action)))
+ return NULL;
+
+ if (setting_enabled(SETTING_ALTKEY_HINT) && bind->bindcnt > 1) {
// First alt keybinding
- return key_to_str(bindings[action].keys[1]);
+ return key_to_str(bind->keys[1]);
} else {
// Default keybinding
- return key_to_str(bindings[action].keys[0]);
+ return key_to_str(bind->keys[0]);
}
}
diff --git a/src/keybinding.h b/src/keybinding.h
index ffd6c92..9057e7d 100644
--- a/src/keybinding.h
+++ b/src/keybinding.h
@@ -87,10 +87,10 @@ enum key_actions {
ACTION_SHOW_FILTERS,
ACTION_SHOW_COLUMNS,
ACTION_SHOW_SETTINGS,
+ ACTION_SHOW_STATS,
ACTION_COLUMN_MOVE_UP,
ACTION_COLUMN_MOVE_DOWN,
ACTION_DISP_FILTER,
- ACTION_DISP_INVITE,
ACTION_SAVE,
ACTION_SELECT,
ACTION_CONFIRM,
@@ -113,6 +113,10 @@ typedef struct key_binding key_binding_t;
* @brief Struct to hold a keybinding data
*/
struct key_binding {
+ //! Keybinding action id
+ int id;
+ //! Keybinding action name
+ const char *name;
//! keybindings for this action
int keys[MAX_BINDINGS];
//! How many keys are binded to this action
@@ -120,16 +124,17 @@ struct key_binding {
};
/**
- * @brief Initialize default keybindings
+ * @brief Print configured keybindigs
*/
void
-key_bindings_init();
+key_bindings_dump();
/**
- * @brief Print configured keybindigs
+ * @brief Return Keybinding data for a given action
+ * @return key_binding_t structure pointer or NULL if not found
*/
-void
-key_bindings_dump();
+key_binding_t *
+key_binding_data(int action);
/**
* @brief Bind a key to an action
diff --git a/src/main.c b/src/main.c
index ad10534..5120811 100644
--- a/src/main.c
+++ b/src/main.c
@@ -37,8 +37,11 @@
#include "ui_manager.h"
#include "capture.h"
#include "capture_eep.h"
+#ifdef WITH_GNUTLS
+#include "capture_gnutls.h"
+#endif
#ifdef WITH_OPENSSL
-#include "capture_tls.h"
+#include "capture_openssl.h"
#endif
/**
@@ -49,10 +52,13 @@
void
usage()
{
- printf("Usage: %s [-hVcivNq] [-IO pcap_dump] [-d dev] [-l limit]"
-#ifdef WITH_OPENSSL
+ printf("Usage: %s [-hVcivNqrD] [-IO pcap_dump] [-d dev] [-l limit]"
+#if defined(WITH_GNUTLS) || defined(WITH_OPENSSL)
" [-k keyfile]"
#endif
+#ifdef USE_EEP
+ " [-LH capture_url]"
+#endif
" [<match expression>] [<bpf filter>]\n\n"
" -h --help\t\t This usage\n"
" -V --version\t Version information\n"
@@ -60,16 +66,18 @@ usage()
" -I --input\t\t Read captured data from pcap file\n"
" -O --output\t\t Write captured data to pcap file\n"
" -c --calls\t\t Only display dialogs starting with INVITE\n"
- " -r --rtp\t\t Capture full RTP packets\n"
+ " -r --rtp\t\t Capture RTP packets payload\n"
" -l --limit\t\t Set capture limit to N dialogs\n"
" -i --icase\t\t Make <match expression> case insensitive\n"
" -v --invert\t\t Invert <match expression>\n"
" -N --no-interface\t Don't display sngrep interface, just capture\n"
+ " -q --quiet\t\t Don't print captured dialogs in no interface mode\n"
" -D --dump-config\t Print active configuration settings and exit\n"
+#ifdef USE_EEP
" -H --eep-send\t Homer sipcapture url (udp:X.X.X.X:XXXX)\n"
" -L --eep-listen\t Listen for encapsulated packets (udp:X.X.X.X:XXXX)\n"
- " -q --quiet\t\t Don't print captured dialogs in no interface mode\n"
-#ifdef WITH_OPENSSL
+#endif
+#if defined(WITH_GNUTLS) || defined(WITH_OPENSSL)
" -k --keyfile\t RSA private keyfile to decrypt captured packets\n"
#endif
"\n",PACKAGE);
@@ -84,6 +92,9 @@ version()
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n"
+#ifdef WITH_GNUTLS
+ " * Compiled with GnuTLS support.\n"
+#endif
#ifdef WITH_OPENSSL
" * Compiled with OpenSSL support.\n"
#endif
@@ -124,7 +135,9 @@ main(int argc, char* argv[])
{ "device", required_argument, 0, 'd' },
{ "input", required_argument, 0, 'I' },
{ "output", required_argument, 0, 'O' },
+#if defined(WITH_GNUTLS) || defined(WITH_OPENSSL)
{ "keyfile", required_argument, 0, 'k' },
+#endif
{ "calls", no_argument, 0, 'c' },
{ "rtp", no_argument, 0, 'r' },
{ "limit", no_argument, 0, 'l' },
@@ -132,8 +145,10 @@ main(int argc, char* argv[])
{ "invert", no_argument, 0, 'v' },
{ "no-interface", no_argument, 0, 'N' },
{ "dump-config", no_argument, 0, 'D' },
+#ifdef USE_EEP
{ "eep-listen", required_argument, 0, 'L' },
{ "eep-send", required_argument, 0, 'H' },
+#endif
{ "quiet", no_argument, 0, 'q' },
};
@@ -175,9 +190,11 @@ main(int argc, char* argv[])
return 0;
}
break;
+#if defined(WITH_GNUTLS) || defined(WITH_OPENSSL)
case 'k':
keyfile = optarg;
break;
+#endif
case 'c':
only_calls = 1;
setting_set_value(SETTING_SIP_CALLS, SETTING_ON);
@@ -208,12 +225,14 @@ main(int argc, char* argv[])
case 't':
case 'W':
break;
+#ifdef USE_EEP
case 'L':
capture_eep_set_server_url(optarg);
break;
case 'H':
capture_eep_set_client_url(optarg);
break;
+#endif
case '?':
if (strchr(options, optopt)) {
fprintf(stderr, "-%c option requires an argument.\n", optopt);
@@ -228,7 +247,7 @@ main(int argc, char* argv[])
}
}
-#ifdef WITH_OPENSSL
+#if defined(WITH_GNUTLS) || defined(WITH_OPENSSL)
// Set capture decrypt key file
capture_set_keyfile(keyfile);
// Check if we have a keyfile and is valid
@@ -251,8 +270,10 @@ main(int argc, char* argv[])
// Set capture options
capture_init(limit, rtp_capture);
+#ifdef USE_EEP
// Initialize EEP if enabled
capture_eep_init();
+#endif
// If we have an input file, load it
if (vector_count(infiles)) {
diff --git a/src/option.c b/src/option.c
index 99d563a..a6ff340 100644
--- a/src/option.c
+++ b/src/option.c
@@ -65,9 +65,6 @@ init_options()
set_option_value("cl.column6", "dst");
set_option_value("cl.column7", "state");
- // Initialize keybindings
- key_bindings_init();
-
// Read options from configuration files
read_options("/etc/sngreprc");
read_options("/usr/local/etc/sngreprc");
diff --git a/src/rtp.c b/src/rtp.c
index 0259a6a..3faa786 100644
--- a/src/rtp.c
+++ b/src/rtp.c
@@ -65,7 +65,7 @@ rtp_encoding_t encodings[] = {
};
rtp_stream_t *
-stream_create(sdp_media_t *media, const char *dst, u_short dport)
+stream_create(sdp_media_t *media, const char *dst, u_short dport, int type)
{
rtp_stream_t *stream;
@@ -74,6 +74,7 @@ stream_create(sdp_media_t *media, const char *dst, u_short dport)
return NULL;
// Initialize all fields
+ stream->type = type;
stream->media = media;
strcpy(stream->ip_dst, dst);
stream->dport = dport;
@@ -82,15 +83,20 @@ stream_create(sdp_media_t *media, const char *dst, u_short dport)
}
rtp_stream_t *
-stream_complete(rtp_stream_t *stream, const char *src, u_short sport, u_int format)
+stream_complete(rtp_stream_t *stream, const char *src, u_short sport)
{
strcpy(stream->ip_src, src);
stream->sport = sport;
- stream->fmtcode = format;
return stream;
}
void
+stream_set_format(rtp_stream_t *stream, uint32_t format)
+{
+ stream->rtpinfo.fmtcode = format;
+}
+
+void
stream_add_packet(rtp_stream_t *stream, capture_packet_t *packet)
{
if (stream->pktcnt == 0)
@@ -99,7 +105,7 @@ stream_add_packet(rtp_stream_t *stream, capture_packet_t *packet)
stream->pktcnt++;
}
-int
+uint32_t
stream_get_count(rtp_stream_t *stream)
{
return stream->pktcnt;
@@ -123,11 +129,11 @@ stream_get_format(rtp_stream_t *stream)
return NULL;
// Try to get standard format form code
- if ((fmt = rtp_get_standard_format(stream->fmtcode)))
+ if ((fmt = rtp_get_standard_format(stream->rtpinfo.fmtcode)))
return fmt;
// Try to get format form SDP payload
- if ((fmt = media_get_format(stream->media, stream->fmtcode)))
+ if ((fmt = media_get_format(stream->media, stream->rtpinfo.fmtcode)))
return fmt;
// Not found format for this code
@@ -155,9 +161,15 @@ rtp_check_packet(capture_packet_t *packet)
u_short sport, dport;
rtp_stream_t *stream;
rtp_stream_t *reverse;
- u_int format;
+ u_char format = 0;
u_char *payload;
- uint32_t size;
+ uint32_t size, bsize;
+ uint16_t len;
+ struct rtcp_hdr_generic hdr;
+ struct rtcp_hdr_sr hdr_sr;
+ struct rtcp_hdr_xr hdr_xr;
+ struct rtcp_blk_xr blk_xr;
+ struct rtcp_blk_xr_voip blk_xr_voip;
// Get packet data
payload = capture_packet_get_payload(packet);
@@ -170,42 +182,121 @@ rtp_check_packet(capture_packet_t *packet)
dport = packet->dport;
// Check if we have at least RTP type
- if (size < 2)
+ if ((int32_t) size < 2)
return NULL;
// Check RTP version
if (RTP_VERSION(*payload) != RTP_VERSION_RFC1889)
return NULL;
- // Get RTP payload type
- format = RTP_PAYLOAD_TYPE(*(++payload));
+ // RTP: even, RTCP: odd
+ if (((packet->dport % 2) == 0)) {
+
+ // Get RTP payload type
+ format = RTP_PAYLOAD_TYPE(*(payload + 1));
- // Find the matching stream
- stream = rtp_find_stream(src, sport, dst, dport, format);
+ // Find the matching stream
+ stream = rtp_find_stream(src, sport, dst, dport, format);
+
+ // Check if a valid stream has been found
+ if (!stream)
+ return NULL;
- // A valid stream has been found
- if (stream) {
// We have found a stream, but with different format
- if (stream->pktcnt && stream->fmtcode != format) {
+ if (stream_is_complete(stream) && stream->rtpinfo.fmtcode != format) {
// Create a new stream for this new format
- stream = stream_create(stream->media, dst, dport);
- stream_complete(stream, src, sport, format);
+ stream = stream_create(stream->media, dst, dport, CAPTURE_PACKET_RTP);
+ stream_complete(stream, src, sport);
+ stream_set_format(stream, format);
call_add_stream(msg_get_call(stream->media->msg), stream);
}
// First packet for this stream, set source data
- if (stream->pktcnt == 0) {
- stream_complete(stream, src, sport, format);
+ if (!(stream_is_complete(stream))) {
+ stream_complete(stream, src, sport);
+ stream_set_format(stream, format);
// Check if an stream in the opposite direction exists
- if (!(reverse = rtp_find_call_stream(stream->media->msg->call, stream->ip_dst, stream->dport, stream->ip_src, stream->sport, stream->fmtcode))) {
- reverse = stream_create(stream->media, stream->ip_src, stream->sport);
- stream_complete(reverse, stream->ip_dst, stream->dport, format);
+ if (!(reverse = rtp_find_call_stream(stream->media->msg->call, stream->ip_dst, stream->dport, stream->ip_src, stream->sport))) {
+ reverse = stream_create(stream->media, stream->ip_src, stream->sport, CAPTURE_PACKET_RTP);
+ stream_complete(reverse, stream->ip_dst, stream->dport);
+ stream_set_format(reverse, format);
call_add_stream(msg_get_call(stream->media->msg), reverse);
}
}
// Add packet to stream
stream_add_packet(stream, packet);
+ } else {
+ // Find the matching stream
+ if ((stream = rtp_find_stream(src, sport, dst, dport, format))) {
+
+ // Parse all packet payload headers
+ while ((int32_t) size > 0) {
+
+ // Check we have at least rtcp generic info
+ if (size < sizeof(struct rtcp_hdr_generic))
+ break;
+
+ memcpy(&hdr, payload, sizeof(hdr));
+
+ // Check RTP version
+ if (RTP_VERSION(hdr.version) != RTP_VERSION_RFC1889)
+ break;
+
+ // Header length
+ len = ntohs(hdr.len) * 4 + 4;
+
+ // Check RTCP packet header typ
+ switch (hdr.type) {
+ case RTCP_HDR_SR:
+ // Get Sender Report header
+ memcpy(&hdr_sr, payload, sizeof(hdr_sr));
+ stream->rtcpinfo.spc = ntohl(hdr_sr.spc);
+ break;
+ case RTCP_HDR_RR:
+ case RTCP_HDR_SDES:
+ case RTCP_HDR_BYE:
+ case RTCP_HDR_APP:
+ case RTCP_RTPFB:
+ case RTCP_PSFB:
+ break;
+ case RTCP_XR:
+ // Get Sender Report Extended header
+ memcpy(&hdr_xr, payload, sizeof(hdr_xr));
+ bsize = sizeof(hdr_xr);
+
+ // Read all report blocks
+ while (bsize < ntohs(hdr_xr.len) * 4 + 4) {
+ // Read block header
+ memcpy(&blk_xr, payload + bsize, sizeof(blk_xr));
+ // Check block type
+ switch (blk_xr.type) {
+ case RTCP_XR_VOIP_METRCS:
+ memcpy(&blk_xr_voip, payload + sizeof(hdr_xr), sizeof(blk_xr_voip));
+ stream->rtcpinfo.fdiscard = blk_xr_voip.drate;
+ stream->rtcpinfo.flost = blk_xr_voip.lrate;
+ stream->rtcpinfo.mosl = blk_xr_voip.moslq;
+ stream->rtcpinfo.mosc = blk_xr_voip.moscq;
+ break;
+ default: break;
+ }
+ bsize += ntohs(blk_xr.len) * 4 + 4;
+ }
+ break;
+ case RTCP_AVB:
+ case RTCP_RSI:
+ case RTCP_TOKEN:
+ default:
+ break;
+ }
+ payload += len;
+ size -= len;
+ }
+
+ // Add packet to stream
+ stream_complete(stream, src, sport);
+ stream_add_packet(stream, packet);
+ }
}
return stream;
@@ -222,11 +313,12 @@ rtp_find_stream(const char *src, u_short sport, const char *dst, u_short dport,
vector_iter_t calls;
// Get active calls (during conversation)
- calls = sip_active_calls_iterator();
+ calls = sip_calls_iterator();
+ //vector_iterator_set_current(&calls, vector_iterator_count(&calls) - 1);
while ((call = vector_iterator_next(&calls))) {
// Check if this call has an RTP stream for current packet data
- if ((stream = rtp_find_call_stream(call, src, sport, dst, dport, format))) {
+ if ((stream = rtp_find_call_stream(call, src, sport, dst, dport))) {
return stream;
}
}
@@ -235,44 +327,35 @@ rtp_find_stream(const char *src, u_short sport, const char *dst, u_short dport,
}
rtp_stream_t *
-rtp_find_call_stream(struct sip_call *call, const char *ip_src, u_short sport, const char *ip_dst, u_short dport, u_int format)
+rtp_find_call_stream(struct sip_call *call, const char *ip_src, u_short sport, const char *ip_dst, u_short dport)
{
- rtp_stream_t *stream, *ret = NULL;
+ rtp_stream_t *stream;
vector_iter_t it;
+ // Create an iterator for call streams
it = vector_iterator(call->streams);
- // Try to look for a complete stream with this format
- while ((stream = vector_iterator_next(&it))) {
- if (!strcmp(ip_src, stream->ip_src) && sport == stream->sport &&
- !strcmp(ip_dst, stream->ip_dst) && dport == stream->dport &&
- stream->fmtcode == format && stream->pktcnt) {
- ret = stream;
+ // Look for an incomplete stream with this destination
+ vector_iterator_set_last(&it);
+ while ((stream = vector_iterator_prev(&it))) {
+ if (!strcmp(ip_dst, stream->ip_dst) && dport == stream->dport && !stream->pktcnt) {
+ return stream;
}
}
- // Try to look for a complete stream with any format
- if (!ret) {
- vector_iterator_reset(&it);
- while ((stream = vector_iterator_next(&it))) {
+ // Try to look for an incomplete stream with this destination
+ if (ip_src && sport) {
+ vector_iterator_set_last(&it);
+ while ((stream = vector_iterator_prev(&it))) {
if (!strcmp(ip_src, stream->ip_src) && sport == stream->sport &&
!strcmp(ip_dst, stream->ip_dst) && dport == stream->dport) {
- ret = stream;
- }
- }
- }
-
- // Try to look for an incomplete stream with this destination
- if (!ret) {
- vector_iterator_reset(&it);
- while ((stream = vector_iterator_next(&it))) {
- if (!strcmp(ip_dst, stream->ip_dst) && dport == stream->dport && !stream->pktcnt) {
- ret = stream;
+ return stream;
}
}
}
- return ret;
+ // Nothing found
+ return NULL;
}
int
@@ -285,3 +368,9 @@ stream_is_older(rtp_stream_t *one, rtp_stream_t *two)
// Otherwise
return timeval_is_older(one->time, two->time);
}
+
+int
+stream_is_complete(rtp_stream_t *stream)
+{
+ return (stream->pktcnt != 0);
+}
diff --git a/src/rtp.h b/src/rtp.h
index 15be2e9..b4295fc 100644
--- a/src/rtp.h
+++ b/src/rtp.h
@@ -44,6 +44,40 @@
// Handled RTP versions
#define RTP_VERSION_RFC1889 2
+// RTCP header types
+//! http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml
+enum rtcp_header_types
+{
+ RTCP_HDR_SR = 200,
+ RTCP_HDR_RR,
+ RTCP_HDR_SDES,
+ RTCP_HDR_BYE,
+ RTCP_HDR_APP,
+ RTCP_RTPFB,
+ RTCP_PSFB,
+ RTCP_XR,
+ RTCP_AVB,
+ RTCP_RSI,
+ RTCP_TOKEN,
+};
+
+//! http://www.iana.org/assignments/rtcp-xr-block-types/rtcp-xr-block-types.xhtml
+enum rtcp_xr_block_types
+{
+ RTCP_XR_LOSS_RLE = 1,
+ RTCP_XR_DUP_RLE,
+ RTCP_XR_PKT_RXTIMES,
+ RTCP_XR_REF_TIME,
+ RTCP_XR_DLRR,
+ RTCP_XR_STATS_SUMRY,
+ RTCP_XR_VOIP_METRCS,
+ RTCP_XR_BT_XNQ,
+ RTCP_XR_TI_VOIP,
+ RTCP_XR_PR_LOSS_RLE,
+ RTCP_XR_MC_ACQ,
+ RTCP_XR_IDMS
+};
+
//! Shorter declaration of rtp_encoding structure
typedef struct rtp_encoding rtp_encoding_t;
//! Shorter declaration of rtp_stream structure
@@ -56,32 +90,193 @@ struct rtp_encoding {
};
struct rtp_stream {
+ //! Determine stream type
+ uint32_t type;
//! Source address and port
char ip_src[ADDRESSLEN];
u_short sport;
//! Destination address and port
char ip_dst[ADDRESSLEN];
u_short dport;
- //! Format of first received packet of stre
- u_int fmtcode;
- //! Time of first received packet of stream
- struct timeval time;
- //! Packet count for this stream
- int pktcnt;
//! SDP media that setup this stream
sdp_media_t *media;
+ //! Packet count for this stream
+ uint32_t pktcnt;
+ //! Time of first received packet of stream
+ struct timeval time;
+
+ // Stream information (depending on type)
+ union {
+ struct {
+ //! Format of first received packet of stre
+ uint32_t fmtcode;
+ } rtpinfo;
+ struct {
+ //! Sender packet count
+ uint32_t spc;
+ //! Fraction lost x/256
+ uint8_t flost;
+ //! uint8_t discarded x/256
+ uint8_t fdiscard;
+ //! MOS - listening Quality
+ uint8_t mosl;
+ //! MOS - Conversational Quality
+ uint8_t mosc;
+ } rtcpinfo;
+ };
+};
+
+struct rtcp_hdr_generic
+{
+ //! version (V): 2 bits
+ uint8_t version;
+ //! packet type (PT): 8 bits
+ uint8_t type;
+ //! length: 16 bits
+ uint16_t len;
+};
+
+struct rtcp_hdr_sr
+{
+ //! version (V): 2 bits
+ uint8_t version:2;
+ //! padding (P): 1 bit
+ uint8_t padding:1;
+ //! reception report count (RC): 5 bits
+ uint8_t rcount:5;
+ //! packet type (PT): 8 bits
+ uint8_t type;
+ //! length: 16 bits
+ uint16_t len;
+ //! SSRC: 32 bits
+ uint32_t ssrc;
+ //! NTP timestamp: 64 bits
+ uint64_t ntpts;
+ //! RTP timestamp: 32 bits
+ uint32_t rtpts;
+ //! sender's packet count: 32 bits
+ uint32_t spc;
+ //! sender's octet count: 32 bits
+ uint32_t soc;
+};
+
+struct rtcp_blk_sr
+{
+ //! SSRC_n (source identifier): 32 bits
+ uint32_t ssrc;
+ //! fraction lost: 8 bits
+ uint8_t flost;
+ //! cumulative number of packets lost: 24 bits
+ struct {
+ uint8_t pl1;
+ uint8_t pl2;
+ uint8_t pl3;
+ } plost;
+ //! extended highest sequence number received: 32 bits
+ uint32_t hseq;
+ //! interarrival jitter: 32 bits
+ uint32_t ijitter;
+};
+
+struct rtcp_hdr_xr
+{
+ //! version (V): 2 bits
+ uint8_t version:2;
+ //! padding (P): 1 bit
+ uint8_t padding:1;
+ //! reserved: 5 bits
+ uint8_t reserved:5;
+ //! packet type (PT): 8 bits
+ uint8_t type;
+ //! length: 16 bits
+ uint16_t len;
+ //! SSRC: 32 bits
+ uint32_t ssrc;
+};
+
+struct rtcp_blk_xr
+{
+ //! block type (BT): 8 bits
+ uint8_t type;
+ //! type-specific: 8 bits
+ uint8_t specific;
+ //! length: 16 bits
+ uint16_t len;
+};
+
+struct rtcp_blk_xr_voip
+{
+ //! block type (BT): 8 bits
+ uint8_t type;
+ //! type-specific: 8 bits
+ uint8_t reserved;
+ //! length: 16 bits
+ uint16_t len;
+ //! SSRC: 32 bits
+ uint32_t ssrc;
+ //! loss rate: 8 bits
+ uint8_t lrate;
+ //! discard rate: 8 bits
+ uint8_t drate;
+ //! burst density: 8 bits
+ uint8_t bdens;
+ //! gap density: 8 bits
+ uint8_t gdens;
+ //! burst duration: 16 bits
+ uint16_t bdur;
+ //! gap duration: 16 bits
+ uint16_t gdur;
+ //! round trip delay: 16 bits
+ uint16_t rtd;
+ //! end system delay: 16 bits
+ uint16_t esd;
+ //! signal level: 8 bits
+ uint8_t slevel;
+ //! noise level: 8 bits
+ uint8_t nlevel;
+ //! residual echo return loss (RERL): 8 bits
+ uint8_t rerl;
+ //! Gmin: 8 bits
+ uint8_t gmin;
+ //! R factor: 8 bits
+ uint8_t rfactor;
+ //! ext. R factor: 8 bits
+ uint8_t xrfactor;
+ //! MOS-LQ: 8 bits
+ uint8_t moslq;
+ //! MOS-CQ: 8 bits
+ uint8_t moscq;
+ //! receiver configuration byte (RX config): 8 bits
+ uint8_t rxc;
+ //! packet loss concealment (PLC): 2 bits
+ uint8_t plc:2;
+ //! jitter buffer adaptive (JBA): 2 bits
+ uint8_t jba:2;
+ //! jitter buffer rate (JB rate): 4 bits
+ uint8_t jbrate:4;
+ //! reserved: 8 bits
+ uint8_t reserved2;
+ //! jitter buffer nominal delay (JB nominal): 16 bits
+ uint16_t jbndelay;
+ //! jitter buffer maximum delay (JB maximum): 16 bits
+ uint16_t jbmdelay;
+ //! jitter buffer absolute maximum delay (JB abs max): 16 bits
+ uint16_t jbadelay;
};
rtp_stream_t *
-stream_create(sdp_media_t *media, const char *dst, u_short dport);
+stream_create(sdp_media_t *media, const char *dst, u_short dport, int type);
rtp_stream_t *
-stream_complete(rtp_stream_t *stream, const char *src, u_short sport, u_int format);
+stream_complete(rtp_stream_t *stream, const char *src, u_short sport);
+
+void
+stream_set_format(rtp_stream_t *stream, uint32_t format);
void
stream_add_packet(rtp_stream_t *stream, capture_packet_t *packet);
-int
+uint32_t
stream_get_count(rtp_stream_t *stream);
struct sip_call *
@@ -100,7 +295,7 @@ rtp_stream_t *
rtp_find_stream(const char *ip_src, u_short sport, const char *ip_dst, u_short dport, u_int format);
rtp_stream_t *
-rtp_find_call_stream(struct sip_call *call, const char *ip_src, u_short sport, const char *ip_dst, u_short dport, u_int format);
+rtp_find_call_stream(struct sip_call *call, const char *ip_src, u_short sport, const char *ip_dst, u_short dport);
/**
* @brief Check if a message is older than other
@@ -113,4 +308,7 @@ rtp_find_call_stream(struct sip_call *call, const char *ip_src, u_short sport, c
int
stream_is_older(rtp_stream_t *one, rtp_stream_t *two);
+int
+stream_is_complete(rtp_stream_t *stream);
+
#endif /* __SNGREP_RTP_H */
diff --git a/src/sip.c b/src/sip.c
index 6f75b8e..9a72153 100644
--- a/src/sip.c
+++ b/src/sip.c
@@ -524,6 +524,7 @@ sip_parse_msg_media(sip_msg_t *msg, const u_char *payload)
u_int media_fmt_code;
sdp_media_t *media = NULL;
char *payload2, *tofree, *line;
+ sip_call_t *call = msg_get_call(msg);
// Initialize variables
memset(address, 0, sizeof(address));
@@ -543,13 +544,18 @@ sip_parse_msg_media(sip_msg_t *msg, const u_char *payload)
msg_add_media(msg, media);
/**
- * From SDP we can only guess destination address port. RTP Capture process
+ * From SDP we can only guess destination address port. RTP Capture proccess
* will determine when the stream has been completed, getting source address
* and port of the stream.
*/
// Create a new stream with this destination address:port
if (!call_msg_is_retrans(msg)) {
- call_add_stream(msg_get_call(msg), stream_create(media, media_address, media_port));
+ if (!rtp_find_call_stream(call, 0, 0, media_address, media_port)) {
+ // Create RTP stream
+ call_add_stream(call, stream_create(media, media_address, media_port, CAPTURE_PACKET_RTP));
+ // Create early RTCP stream
+ call_add_stream(call, stream_create(media, media_address, media_port + 1, CAPTURE_PACKET_RTCP));
+ }
}
}
}
@@ -569,6 +575,17 @@ sip_parse_msg_media(sip_msg_t *msg, const u_char *payload)
}
}
+ // Check if we have attribute format RTCP port
+ if (!strncmp(line, "a=rtcp:", 7)) {
+ if (media && sscanf(line, "a=rtcp:%u", &media_port)) {
+ // Create early RTCP stream
+ if (!rtp_find_call_stream(call, 0, 0, media_address, media_port)) {
+ call_add_stream(call, stream_create(media, media_address, media_port, CAPTURE_PACKET_RTCP));
+ }
+ }
+ }
+
+
}
sng_free(tofree);
}
@@ -703,7 +720,7 @@ sip_address_format(const char *address)
// Return address formatted depending on active settings
if (setting_enabled(SETTING_DISPLAY_ALIAS)) {
return get_alias_value(address);
- } else if (setting_enabled(SETTING_DISPLAY_ALIAS)) {
+ } else if (setting_enabled(SETTING_DISPLAY_HOST)) {
return lookup_hostname(address);
} else {
return address;
@@ -724,3 +741,18 @@ sip_address_port_format(const char *addrport)
return aport;
}
+
+const char *
+sip_address_strip_port(char *addrport)
+{
+ char *colon;
+
+ if (!addrport)
+ return NULL;
+
+ // FIXME Make compatible with IPv6
+ if ((colon = strchr(addrport, ':')))
+ *colon = '\0';
+
+ return addrport;
+}
diff --git a/src/sip.h b/src/sip.h
index b11bade..ccfacdf 100644
--- a/src/sip.h
+++ b/src/sip.h
@@ -379,5 +379,11 @@ sip_address_format(const char *address);
const char *
sip_address_port_format(const char *address);
+/**
+ * @brief Remove port from an address
+ */
+const char *
+sip_address_strip_port(char *addrport);
+
#endif
diff --git a/src/ui_call_flow.c b/src/ui_call_flow.c
index a319065..794ce51 100644
--- a/src/ui_call_flow.c
+++ b/src/ui_call_flow.c
@@ -36,6 +36,7 @@
#include "ui_msg_diff.h"
#include "util.h"
#include "vector.h"
+#include "option.h"
/***
*
@@ -189,7 +190,10 @@ call_flow_draw(PANEL *panel)
if (!call_flow_draw_message(panel, arrow, cline))
break;
} else if (arrow->type == CF_ARROW_RTP) {
- if (!call_flow_draw_stream(panel, arrow, cline))
+ if (!call_flow_draw_rtp_stream(panel, arrow, cline))
+ break;
+ } else if (arrow->type == CF_ARROW_RTCP) {
+ if (!call_flow_draw_rtcp_stream(panel, arrow, cline))
break;
}
cline += arrow->height;
@@ -197,7 +201,18 @@ call_flow_draw(PANEL *panel)
// If there are only three columns, then draw the raw message on this panel
if (setting_enabled(SETTING_CF_FORCERAW)) {
- call_flow_draw_raw(panel, call_flow_arrow_message(info->cur_arrow));
+ switch (info->cur_arrow->type) {
+ case CF_ARROW_RTP:
+ call_flow_draw_raw(panel, info->cur_arrow->stream->media->msg);
+ break;
+ case CF_ARROW_SIP:
+ call_flow_draw_raw(panel, info->cur_arrow->msg);
+ break;
+ case CF_ARROW_RTCP:
+ call_flow_draw_raw_rtcp(panel, info->cur_arrow->stream);
+ break;
+ }
+
}
// Draw the scrollbar
@@ -498,16 +513,17 @@ call_flow_draw_message(PANEL *panel, call_flow_arrow_t *arrow, int cline)
call_flow_arrow_t *
-call_flow_draw_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline)
+call_flow_draw_rtp_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline)
{
call_flow_info_t *info;
WINDOW *win;
- char codec[50], time[20];
+ char text[50], time[20];
int height, width;
const char *callid;
char msg_dst[80], msg_src[80];
call_flow_column_t *column1, *column2;
rtp_stream_t *stream = arrow->stream;
+ int arrow_dir = 0; /* 0: right, 1: left */
// Get panel information
info = call_flow_info(panel);
@@ -530,7 +546,7 @@ call_flow_draw_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline)
mvwprintw(win, cline, 2, "%s", time);
// Get Message method (include extra info)
- sprintf(codec, "RTP (%s) %d", stream_get_format(stream), stream_get_count(stream));
+ sprintf(text, "RTP (%s) %d", stream_get_format(stream), stream_get_count(stream));
// Get message data
msg_get_attribute(stream->media->msg, SIP_ATTR_SRC, msg_src);
@@ -562,11 +578,12 @@ call_flow_draw_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline)
tmp = column1;
column1 = column2;
column2 = tmp;
+ arrow_dir = 1; /* swap arrow direction */
}
int startpos = 20 + 30 * column1->colpos;
int endpos = 20 + 30 * column2->colpos;
- int distance = abs(endpos - startpos) - 4;
+ int distance = abs(endpos - startpos) - 4 + 1;
// Highlight current message
if (arrow == info->cur_arrow) {
@@ -585,14 +602,154 @@ call_flow_draw_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline)
// Clear the line
mvwprintw(win, cline, startpos + 2, "%*s", distance, "");
// Draw method
- mvwprintw(win, cline++, startpos + (distance) / 2 - strlen(codec) / 2 + 2, "%s", codec);
+ mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, "%s", text);
+
+ if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed"))
+ cline++;
// Draw line between columns
mvwhline(win, cline, startpos + 2, ACS_HLINE, distance);
- // Write the arrow at the end of the message (two arros if this is a retrans)
- if (call_flow_column_get(panel, 0, stream->ip_src) == column1) {
- mvwprintw(win, cline, startpos - 5, "%d", stream->sport);
- mvwprintw(win, cline, endpos + 1, "%d", stream->dport);
+ // Write the arrow at the end of the message (two arrows if this is a retrans)
+ if (arrow_dir == 0 /* right */) {
+ if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) {
+ mvwprintw(win, cline, startpos - 5, "%d", stream->sport);
+ mvwprintw(win, cline, endpos + 1, "%d", stream->dport);
+ }
+ if (distance > 0)
+ mvwaddch(win, cline, endpos - 2, '>');
+ else
+ mvwaddch(win, cline, endpos, '>');
+ if (arrow->rtp_count != stream_get_count(stream)) {
+ arrow->rtp_count = stream_get_count(stream);
+ arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance;
+ mvwaddch(win, cline, startpos + arrow->rtp_ind_pos + 2, '>');
+ }
+ } else {
+ if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) {
+ mvwprintw(win, cline, endpos + 1, "%d", stream->sport);
+ mvwprintw(win, cline, startpos - 5, "%d", stream->dport);
+ }
+ if (distance > 0)
+ mvwaddch(win, cline, startpos + 2, '<');
+ else
+ mvwaddch(win, cline, startpos, '<');
+ if (arrow->rtp_count != stream_get_count(stream)) {
+ arrow->rtp_count = stream_get_count(stream);
+ arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance;
+ mvwaddch(win, cline, endpos - arrow->rtp_ind_pos - 2, '<');
+ }
+ }
+
+ if (setting_has_value(SETTING_CF_SDP_INFO, "compressed"))
+ mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, " %s ", text);
+
+ wattroff(win, A_BOLD | A_REVERSE);
+
+ return arrow;
+}
+
+call_flow_arrow_t *
+call_flow_draw_rtcp_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline)
+{
+ call_flow_info_t *info;
+ WINDOW *win;
+ char text[50], time[20];
+ int height, width;
+ const char *callid;
+ char msg_dst[80], msg_src[80];
+ call_flow_column_t *column1, *column2;
+ rtp_stream_t *stream = arrow->stream;
+ int arrow_dir = 0; /* 0: right, 1: left */
+
+ // Get panel information
+ info = call_flow_info(panel);
+ // Get the messages window
+ win = info->flow_win;
+ getmaxyx(win, height, width);
+
+ // Store arrow start line
+ arrow->line = cline;
+
+ // Calculate how many lines this message requires
+ arrow->height = call_flow_arrow_height(panel, arrow);
+
+ // Check this media fits on the panel
+ if (cline > height + arrow->height)
+ return NULL;
+
+ // Print timestamp
+ timeval_to_time(stream->time, time);
+ mvwprintw(win, cline, 2, "%s", time);
+
+ // Arrow text
+ sprintf(text, "RTCP (%.1f) %d", (float) stream->rtcpinfo.mosc / 10, stream_get_count(stream));
+
+ // Get message data
+ msg_get_attribute(stream->media->msg, SIP_ATTR_SRC, msg_src);
+ msg_get_attribute(stream->media->msg, SIP_ATTR_DST, msg_dst);
+ callid = stream->media->msg->call->callid;
+
+ // Get origin column for this stream.
+ // If we share the same Address from its setup SIP packet, use that column instead.
+ if (!strncmp(stream->ip_src, msg_src, strlen(stream->ip_src))) {
+ column1 = call_flow_column_get(panel, callid, msg_src);
+ } else if (!strncmp(stream->ip_src, msg_dst, strlen(stream->ip_src))) {
+ column1 = call_flow_column_get(panel, callid, msg_dst);
+ } else {
+ column1 = call_flow_column_get(panel, 0, stream->ip_src);
+ }
+
+ // Get destination column for this stream.
+ // If we share the same Address from its setup SIP packet, use that column instead.
+ if (!strncmp(stream->ip_dst, msg_dst, strlen(stream->ip_dst))) {
+ column2 = call_flow_column_get(panel, callid, msg_dst);
+ } else if (!strncmp(stream->ip_dst, msg_src, strlen(stream->ip_dst))) {
+ column2 = call_flow_column_get(panel, callid, msg_src);
+ } else {
+ column2 = call_flow_column_get(panel, 0, stream->ip_dst);
+ }
+
+ call_flow_column_t *tmp;
+ if (column1->colpos > column2->colpos) {
+ tmp = column1;
+ column1 = column2;
+ column2 = tmp;
+ arrow_dir = 1; /* swap arrow direction */
+ }
+
+ int startpos = 20 + 30 * column1->colpos;
+ int endpos = 20 + 30 * column2->colpos;
+ int distance = abs(endpos - startpos) - 4 + 1;
+
+ // Highlight current message
+ if (arrow == info->cur_arrow) {
+ if (setting_has_value(SETTING_CF_HIGHTLIGHT, "reverse")) {
+ wattron(win, A_REVERSE);
+ }
+ if (setting_has_value(SETTING_CF_HIGHTLIGHT, "bold")) {
+ wattron(win, A_BOLD);
+ }
+ if (setting_has_value(SETTING_CF_HIGHTLIGHT, "reversebold")) {
+ wattron(win, A_REVERSE);
+ wattron(win, A_BOLD);
+ }
+ }
+
+ // Clear the line
+ mvwprintw(win, cline, startpos + 2, "%*s", distance, "");
+ // Draw method
+ mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, "%s", text);
+ if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed"))
+ cline++;
+
+ // Draw line between columns
+ mvwhline(win, cline, startpos + 2, '-', distance);
+ // Write the arrow at the end of the message (two arrows if this is a retrans)
+ if (arrow_dir == 0 /* right */) {
+ if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) {
+ mvwprintw(win, cline, startpos - 5, "%d", stream->sport);
+ mvwprintw(win, cline, endpos + 1, "%d", stream->dport);
+ }
if (distance > 0)
mvwaddch(win, cline, endpos - 2, '>');
else
@@ -603,8 +760,10 @@ call_flow_draw_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline)
mvwaddch(win, cline, startpos + arrow->rtp_ind_pos + 2, '>');
}
} else {
- mvwprintw(win, cline, endpos + 1, "%d", stream->sport);
- mvwprintw(win, cline, startpos - 5, "%d", stream->dport);
+ if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) {
+ mvwprintw(win, cline, endpos + 1, "%d", stream->sport);
+ mvwprintw(win, cline, startpos - 5, "%d", stream->dport);
+ }
if (distance > 0)
mvwaddch(win, cline, startpos + 2, '<');
else
@@ -616,6 +775,9 @@ call_flow_draw_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline)
}
}
+ if (setting_has_value(SETTING_CF_SDP_INFO, "compressed"))
+ mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, " %s ", text);
+
wattroff(win, A_BOLD | A_REVERSE);
return arrow;
@@ -642,7 +804,7 @@ call_flow_next_arrow(PANEL *panel, const call_flow_arrow_t *cur)
memset(&cur_time, 0, sizeof(struct timeval));
} else if (cur->type == CF_ARROW_SIP) {
cur_time = msg_get_time(cur->msg);
- } else if (cur->type == CF_ARROW_RTP) {
+ } else if (cur->type == CF_ARROW_RTP || cur->type == CF_ARROW_RTCP) {
cur_time = cur->stream->time;
}
@@ -669,7 +831,7 @@ call_flow_next_arrow(PANEL *panel, const call_flow_arrow_t *cur)
if (!msg) {
// Create a new arrow to store next info
next = sng_malloc(sizeof(call_flow_arrow_t));
- next->type = CF_ARROW_RTP;
+ next->type = (stream->type == CAPTURE_PACKET_RTP) ? CF_ARROW_RTP : CF_ARROW_RTCP;
next->stream = stream;
} else if (!stream) {
/* a sip message goes next */
@@ -682,7 +844,7 @@ call_flow_next_arrow(PANEL *panel, const call_flow_arrow_t *cur)
if (timeval_is_older(msg_get_time(msg), stream->time)) {
// Create a new arrow to store next info
next = sng_malloc(sizeof(call_flow_arrow_t));
- next->type = CF_ARROW_RTP;
+ next->type = (stream->type == CAPTURE_PACKET_RTP) ? CF_ARROW_RTP : CF_ARROW_RTCP;
next->stream = stream;
} else {
// Create a new arrow to store next info
@@ -731,7 +893,9 @@ call_flow_arrow_height(PANEL *panel, const call_flow_arrow_t *arrow)
return 2;
if (setting_has_value(SETTING_CF_SDP_INFO, "full"))
return msg_media_count(arrow->msg) + 2;
- } else if (arrow->type == CF_ARROW_RTP) {
+ } else if (arrow->type == CF_ARROW_RTP || arrow->type == CF_ARROW_RTCP) {
+ if (setting_has_value(SETTING_CF_SDP_INFO, "compressed"))
+ return 1;
return 2;
}
@@ -766,7 +930,7 @@ call_flow_arrow_message(const call_flow_arrow_t *arrow)
return NULL;
if (arrow->type == CF_ARROW_SIP)
return arrow->msg;
- if (arrow->type == CF_ARROW_RTP)
+ if (arrow->type == CF_ARROW_RTP || arrow->type == CF_ARROW_RTCP)
return arrow->stream->media->msg;
return NULL;
}
@@ -836,6 +1000,78 @@ call_flow_draw_raw(PANEL *panel, sip_msg_t *msg)
return 0;
}
+
+int
+call_flow_draw_raw_rtcp(PANEL *panel, rtp_stream_t *stream)
+{
+ call_flow_info_t *info;
+ WINDOW *win, *raw_win;
+ int raw_width, raw_height, height, width;
+ int min_raw_width, fixed_raw_width;
+
+ // Get panel information
+ if (!(info = call_flow_info(panel)))
+ return 1;
+
+ // Get window of main panel
+ win = panel_window(panel);
+ getmaxyx(win, height, width);
+
+ // Get min raw width
+ min_raw_width = setting_get_intvalue(SETTING_CF_RAWMINWIDTH);
+ fixed_raw_width = setting_get_intvalue(SETTING_CF_RAWFIXEDWIDTH);
+
+ // Calculate the raw data width (width - used columns for flow - vertical lines)
+ raw_width = width - (30 * vector_count(info->columns)) - 2;
+ // We can define a mininum size for rawminwidth
+ if (raw_width < min_raw_width) {
+ raw_width = min_raw_width;
+ }
+ // We can configure an exact raw size
+ if (fixed_raw_width > 0) {
+ raw_width = fixed_raw_width;
+ }
+
+ // Height of raw window is always available size minus 6 lines for header/footer
+ raw_height = height - 3;
+
+ // If we already have a raw window
+ raw_win = info->raw_win;
+ if (raw_win) {
+ // Check it has the correct size
+ if (getmaxx(raw_win) != raw_width) {
+ // We need a new raw window
+ delwin(raw_win);
+ info->raw_win = raw_win = newwin(raw_height, raw_width, 0, 0);
+ } else {
+ // We have a valid raw win, clear its content
+ werase(raw_win);
+ }
+ } else {
+ // Create the raw window of required size
+ info->raw_win = raw_win = newwin(raw_height, raw_width, 0, 0);
+ }
+
+ // Draw raw box lines
+ wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF));
+ mvwvline(win, 1, width - raw_width - 2, ACS_VLINE, height - 2);
+ wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF));
+
+ mvwprintw(raw_win, 0, 0, "============ RTCP Information ============");
+ mvwprintw(raw_win, 2, 0, "Sender's packet count: %d", stream->rtcpinfo.spc);
+ mvwprintw(raw_win, 3, 0, "Fraction Lost: %d / 256", stream->rtcpinfo.flost);
+ mvwprintw(raw_win, 4, 0, "Fraction discarded: %d / 256", stream->rtcpinfo.fdiscard);
+ mvwprintw(raw_win, 6, 0, "MOS - Listening Quality: %.1f", (float) stream->rtcpinfo.mosl / 10);
+ mvwprintw(raw_win, 7, 0, "MOS - Conversational Quality: %.1f", (float) stream->rtcpinfo.mosc / 10);
+
+
+
+ // Copy the raw_win contents into the panel
+ copywin(raw_win, win, 0, 0, 1, width - raw_width - 1, raw_height, width - 2, 0);
+
+ return 0;
+}
+
int
call_flow_handle_key(PANEL *panel, int key)
{
@@ -1003,7 +1239,7 @@ call_flow_help(PANEL *panel)
int height, width;
// Create a new panel and show centered
- height = 26;
+ height = 27;
width = 65;
help_win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2);
@@ -1040,7 +1276,7 @@ call_flow_help(PANEL *panel)
mvwprintw(help_win, 10, 2, "Enter Show current message Raw");
mvwprintw(help_win, 11, 2, "F1/h Show this screen");
mvwprintw(help_win, 12, 2, "F2/d Toggle SDP Address:Port info");
- mvwprintw(help_win, 13, 2, "F3/t Toggle raw preview display");
+ mvwprintw(help_win, 13, 2, "F3/m Toggle RTP arrows display");
mvwprintw(help_win, 14, 2, "F4/X Show call-flow with X-CID/X-Call-ID dialog");
mvwprintw(help_win, 15, 2, "F5/s Toggle compressed view (One address <=> one column");
mvwprintw(help_win, 16, 2, "F6/R Show original call messages in raw mode");
@@ -1048,8 +1284,10 @@ call_flow_help(PANEL *panel)
mvwprintw(help_win, 18, 2, "F8/C Turn on/off message syntax highlighting");
mvwprintw(help_win, 19, 2, "F9/l Turn on/off resolved addresses");
mvwprintw(help_win, 20, 2, "9/0 Increase/Decrease raw preview size");
- mvwprintw(help_win, 21, 2, "T Restore raw preview size");
- mvwprintw(help_win, 22, 2, "D Only show SDP messages");
+ mvwprintw(help_win, 21, 2, "t Toggle raw preview display");
+ mvwprintw(help_win, 22, 2, "T Restore raw preview size");
+ mvwprintw(help_win, 23, 2, "D Only show SDP messages");
+
// Press any key to close
wgetch(help_win);
@@ -1082,18 +1320,30 @@ call_flow_set_group(sip_call_group_t *group)
}
void
-call_flow_column_add(PANEL *panel, const char *callid, const char *addr)
+call_flow_column_add(PANEL *panel, const char *callid, const char *address)
{
call_flow_info_t *info;
call_flow_column_t *column;
vector_iter_t columns;
+ char addr[ADDRESSLEN + 6];
if (!(info = call_flow_info(panel)))
return;
- if (!addr || !strlen(addr))
+ if (!address || !strlen(address))
return;
+ // Coppy address to local var
+ strcpy(addr, address);
+
+ // when compressed view is enabled
+ if (setting_enabled(SETTING_CF_SPLITCALLID)) {
+ // Remove the port from the address
+ sip_address_strip_port(addr);
+ // Display the alias value of the address
+ strcpy(addr, get_alias_value(addr));
+ }
+
if (call_flow_column_get(panel, callid, addr))
return;
@@ -1113,18 +1363,31 @@ call_flow_column_add(PANEL *panel, const char *callid, const char *addr)
}
call_flow_column_t *
-call_flow_column_get(PANEL *panel, const char *callid, const char *addr)
+call_flow_column_get(PANEL *panel, const char *callid, const char *address)
{
call_flow_info_t *info;
call_flow_column_t *column;
vector_iter_t columns;
int match_port;
char coladdr[ADDRESSLEN + 6];
+ char addr[ADDRESSLEN + 6];
char *dots;
if (!(info = call_flow_info(panel)))
return NULL;
+ // Coppy address to local var
+ strcpy(addr, address);
+
+ // when compressed view is enabled
+ if (setting_enabled(SETTING_CF_SPLITCALLID)) {
+ // Remove the port from the address
+ sip_address_strip_port(addr);
+ // Display the alias value of the address
+ strcpy(addr, get_alias_value(addr));
+ }
+
+
// Look for address or address:port ?
match_port = (strchr(addr, ':') != NULL);
diff --git a/src/ui_call_flow.h b/src/ui_call_flow.h
index 91e8d9c..7595484 100644
--- a/src/ui_call_flow.h
+++ b/src/ui_call_flow.h
@@ -71,6 +71,7 @@ typedef struct call_flow_arrow call_flow_arrow_t;
enum call_flow_arrow_type {
CF_ARROW_SIP,
CF_ARROW_RTP,
+ CF_ARROW_RTCP,
};
/**
@@ -227,7 +228,20 @@ call_flow_draw_message(PANEL *panel, call_flow_arrow_t *arrow, int cline);
* @return the arrow passed as parameter
*/
call_flow_arrow_t *
-call_flow_draw_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline);
+call_flow_draw_rtp_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline);
+
+/**
+ * @brief Draw the RTCP stream data in the given line
+ *
+ * Draw the given arrow of type stream in the given line.
+ *
+ * @param panel Ncurses panel pointer
+ * @param arrow Call flow arrow to be drawn
+ * @param cline Window line to draw the message
+ * @return the arrow passed as parameter
+ */
+call_flow_arrow_t *
+call_flow_draw_rtcp_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline);
/**
* @brief Get the next chronological arrow
@@ -306,6 +320,18 @@ int
call_flow_draw_raw(PANEL *panel, sip_msg_t *msg);
/**
+ * @brief Draw raw panel with RTCP data
+ *
+ * Draw the given stream data into the raw window.
+ *
+ * @param panel Ncurses panel pointer
+ * @param rtcp stream containing the RTCP conection data
+ * @return 0 in all cases
+ */
+int
+call_flow_draw_raw_rtcp(PANEL *panel, rtp_stream_t *rtcp);
+
+/**
* @brief Handle Call flow extended key strokes
*
* This function will manage the custom keybindings of the panel. If this
diff --git a/src/ui_call_list.c b/src/ui_call_list.c
index 1e5b2b4..7b17c96 100644
--- a/src/ui_call_list.c
+++ b/src/ui_call_list.c
@@ -582,17 +582,13 @@ call_list_handle_key(PANEL *panel, int key)
case ACTION_SHOW_COLUMNS:
ui_create_panel(PANEL_COLUMN_SELECT);
break;
+ case ACTION_SHOW_STATS:
+ ui_create_panel(PANEL_STATS);
+ break;
case ACTION_SAVE:
next_panel = ui_create_panel(PANEL_SAVE);
save_set_group(ui_get_panel(next_panel), info->group);
break;
- case ACTION_DISP_INVITE:
- // Set Display filter text
- set_field_buffer(info->fields[FLD_LIST_FILTER], 0, "invite");
- filter_set(FILTER_CALL_LIST, "invite");
- call_list_clear(panel);
- filter_reset_calls();
- break;
case ACTION_CLEAR:
// Clear group calls
vector_clear(info->group->calls);
diff --git a/src/ui_filter.c b/src/ui_filter.c
index 7ab1fe3..085ec3d 100644
--- a/src/ui_filter.c
+++ b/src/ui_filter.c
@@ -56,7 +56,7 @@ filter_create()
const char *method;
// Calculate window dimensions
- height = 15;
+ height = 16;
width = 50;
// Cerate a new indow for the panel and form
@@ -76,13 +76,14 @@ filter_create()
info->fields[FLD_FILTER_SIPTO] = new_field(1, 28, 4, 18, 0, 0);
info->fields[FLD_FILTER_SRC] = new_field(1, 18, 5, 18, 0, 0);
info->fields[FLD_FILTER_DST] = new_field(1, 18, 6, 18, 0, 0);
- info->fields[FLD_FILTER_REGISTER] = new_field(1, 1, 8, 15, 0, 0);
- info->fields[FLD_FILTER_INVITE] = new_field(1, 1, 9, 15, 0, 0);
- info->fields[FLD_FILTER_SUBSCRIBE] = new_field(1, 1, 10, 15, 0, 0);
- info->fields[FLD_FILTER_NOTIFY] = new_field(1, 1, 11, 15, 0, 0);
- info->fields[FLD_FILTER_OPTIONS] = new_field(1, 1, 8, 37, 0, 0);
- info->fields[FLD_FILTER_PUBLISH] = new_field(1, 1, 9, 37, 0, 0);
- info->fields[FLD_FILTER_MESSAGE] = new_field(1, 1, 10, 37, 0, 0);
+ info->fields[FLD_FILTER_PAYLOAD] = new_field(1, 28, 7, 18, 0, 0);
+ info->fields[FLD_FILTER_REGISTER] = new_field(1, 1, 9, 15, 0, 0);
+ info->fields[FLD_FILTER_INVITE] = new_field(1, 1, 10, 15, 0, 0);
+ info->fields[FLD_FILTER_SUBSCRIBE] = new_field(1, 1, 11, 15, 0, 0);
+ info->fields[FLD_FILTER_NOTIFY] = new_field(1, 1, 12, 15, 0, 0);
+ info->fields[FLD_FILTER_OPTIONS] = new_field(1, 1, 9, 37, 0, 0);
+ info->fields[FLD_FILTER_PUBLISH] = new_field(1, 1, 10, 37, 0, 0);
+ info->fields[FLD_FILTER_MESSAGE] = new_field(1, 1, 11, 37, 0, 0);
info->fields[FLD_FILTER_FILTER] = new_field(1, 10, height - 2, 11, 0, 0);
info->fields[FLD_FILTER_CANCEL] = new_field(1, 10, height - 2, 30, 0, 0);
info->fields[FLD_FILTER_COUNT] = NULL;
@@ -92,6 +93,7 @@ filter_create()
field_opts_off(info->fields[FLD_FILTER_SIPTO], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_SRC], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_DST], O_AUTOSKIP);
+ field_opts_off(info->fields[FLD_FILTER_PAYLOAD], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_REGISTER], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_INVITE], O_AUTOSKIP);
field_opts_off(info->fields[FLD_FILTER_SUBSCRIBE], O_AUTOSKIP);
@@ -107,6 +109,7 @@ filter_create()
set_field_back(info->fields[FLD_FILTER_SIPTO], A_UNDERLINE);
set_field_back(info->fields[FLD_FILTER_SRC], A_UNDERLINE);
set_field_back(info->fields[FLD_FILTER_DST], A_UNDERLINE);
+ set_field_back(info->fields[FLD_FILTER_PAYLOAD], A_UNDERLINE);
// Create the form and post it
info->form = new_form(info->fields);
@@ -118,13 +121,14 @@ filter_create()
mvwprintw(win, 4, 3, "SIP To:");
mvwprintw(win, 5, 3, "Source:");
mvwprintw(win, 6, 3, "Destination:");
- mvwprintw(win, 8, 3, "REGISTER [ ]");
- mvwprintw(win, 9, 3, "INVITE [ ]");
- mvwprintw(win, 10, 3, "SUBSCRIBE [ ]");
- mvwprintw(win, 11, 3, "NOTIFY [ ]");
- mvwprintw(win, 8, 25, "OPTIONS [ ]");
- mvwprintw(win, 9, 25, "PUBLISH [ ]");
- mvwprintw(win, 10, 25, "MESSAGE [ ]");
+ mvwprintw(win, 7, 3, "Payload:");
+ mvwprintw(win, 9, 3, "REGISTER [ ]");
+ mvwprintw(win, 10, 3, "INVITE [ ]");
+ mvwprintw(win, 11, 3, "SUBSCRIBE [ ]");
+ mvwprintw(win, 12, 3, "NOTIFY [ ]");
+ mvwprintw(win, 9, 25, "OPTIONS [ ]");
+ mvwprintw(win, 10, 25, "PUBLISH [ ]");
+ mvwprintw(win, 11, 25, "MESSAGE [ ]");
// Get Method filter
if (!(method = filter_get(FILTER_METHOD)))
@@ -135,6 +139,7 @@ filter_create()
set_field_buffer(info->fields[FLD_FILTER_SIPTO], 0, filter_get(FILTER_SIPTO));
set_field_buffer(info->fields[FLD_FILTER_SRC], 0, filter_get(FILTER_SOURCE));
set_field_buffer(info->fields[FLD_FILTER_DST], 0, filter_get(FILTER_DESTINATION));
+ set_field_buffer(info->fields[FLD_FILTER_PAYLOAD], 0, filter_get(FILTER_PAYLOAD));
set_field_buffer(info->fields[FLD_FILTER_REGISTER], 0,
strstr(method, sip_method_str(SIP_METHOD_REGISTER)) ? "*" : "");
set_field_buffer(info->fields[FLD_FILTER_INVITE], 0,
@@ -156,9 +161,9 @@ filter_create()
mvwprintw(win, 1, 18, "Filter options");
wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF));
title_foot_box(panel);
- mvwhline(win, 7, 1, ACS_HLINE, 49);
- mvwaddch(win, 7, 0, ACS_LTEE);
- mvwaddch(win, 7, 49, ACS_RTEE);
+ mvwhline(win, 8, 1, ACS_HLINE, 49);
+ mvwaddch(win, 8, 0, ACS_LTEE);
+ mvwaddch(win, 8, 49, ACS_RTEE);
wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF));
// Set default cursor position
@@ -199,7 +204,8 @@ filter_handle_key(PANEL *panel, int key)
// We trim spaces with sscanf because and empty field is stored as
// space characters
memset(field_value, 0, sizeof(field_value));
- sscanf(field_buffer(current_field(info->form), 0), "%[^ ]", field_value);
+ strcpy(field_value, field_buffer(current_field(info->form), 0));
+ strtrim(field_value);
// Check actions for this key
while ((action = key_find_action(key, action)) != ERR) {
@@ -208,7 +214,8 @@ filter_handle_key(PANEL *panel, int key)
case ACTION_PRINTABLE:
// If this is a normal character on input field, print it
if (field_idx == FLD_FILTER_SIPFROM || field_idx == FLD_FILTER_SIPTO
- || field_idx == FLD_FILTER_SRC || field_idx == FLD_FILTER_DST) {
+ || field_idx == FLD_FILTER_SRC || field_idx == FLD_FILTER_DST
+ || field_idx == FLD_FILTER_PAYLOAD) {
form_driver(info->form, key);
break;
}
@@ -319,7 +326,8 @@ filter_save_options(PANEL *panel)
// We trim spaces with sscanf because and empty field is stored as
// space characters
memset(field_value, 0, sizeof(field_value));
- sscanf(field_buffer(info->fields[field_id], 0), "%[^ ]", field_value);
+ strcpy(field_value, field_buffer(info->fields[field_id], 0));
+ strtrim(field_value);
// Set filter expression
expr = strlen(field_value) ? field_value : NULL;
@@ -337,6 +345,9 @@ filter_save_options(PANEL *panel)
case FLD_FILTER_DST:
filter_set(FILTER_DESTINATION, expr);
break;
+ case FLD_FILTER_PAYLOAD:
+ filter_set(FILTER_PAYLOAD, expr);
+ break;
case FLD_FILTER_REGISTER:
case FLD_FILTER_INVITE:
case FLD_FILTER_SUBSCRIBE:
diff --git a/src/ui_filter.h b/src/ui_filter.h
index 74c9382..8cd26a1 100644
--- a/src/ui_filter.h
+++ b/src/ui_filter.h
@@ -48,6 +48,7 @@ enum filter_field_list {
FLD_FILTER_SIPTO,
FLD_FILTER_SRC,
FLD_FILTER_DST,
+ FLD_FILTER_PAYLOAD,
FLD_FILTER_REGISTER,
FLD_FILTER_INVITE,
FLD_FILTER_SUBSCRIBE,
diff --git a/src/ui_manager.c b/src/ui_manager.c
index d315bc0..06afa26 100644
--- a/src/ui_manager.c
+++ b/src/ui_manager.c
@@ -59,7 +59,8 @@ static ui_t *panel_pool[] = {
&ui_save,
&ui_msg_diff,
&ui_column_select,
- &ui_settings
+ &ui_settings,
+ &ui_stats
};
int
diff --git a/src/ui_manager.h b/src/ui_manager.h
index 55ef1ae..49cc04a 100644
--- a/src/ui_manager.h
+++ b/src/ui_manager.h
@@ -136,6 +136,8 @@ enum panel_types {
PANEL_COLUMN_SELECT,
//! Settings panel
PANEL_SETTINGS,
+ //! Stats panel
+ PANEL_STATS,
//! Panel Counter
PANEL_COUNT,
};
@@ -151,6 +153,7 @@ extern ui_t ui_save;
extern ui_t ui_msg_diff;
extern ui_t ui_column_select;
extern ui_t ui_settings;
+extern ui_t ui_stats;
/**
* @brief Initialize ncurses mode
diff --git a/src/ui_settings.c b/src/ui_settings.c
index b503dbe..2938ca9 100644
--- a/src/ui_settings.c
+++ b/src/ui_settings.c
@@ -447,7 +447,8 @@ ui_settings_update_settings(PANEL *panel)
if ((entry = ui_settings_is_entry(info->fields[i]))) {
// Get field value.
memset(field_value, 0, sizeof(field_value));
- sscanf(field_buffer(info->fields[i], 0), "%[^ ]", field_value);
+ strcpy(field_value, field_buffer(info->fields[i], 0));
+ strtrim(field_value);
// Change setting value
setting_set_value(entry->setting_id, field_value);
}
@@ -508,7 +509,8 @@ ui_settings_save(PANEL *panel)
if ((entry = ui_settings_is_entry(info->fields[i]))) {
// Get field value.
memset(field_value, 0, sizeof(field_value));
- sscanf(field_buffer(info->fields[i], 0), "%[^ ]", field_value);
+ strcpy(field_value, field_buffer(info->fields[i], 0));
+ strtrim(field_value);
// Change setting value
fprintf(fo, "set %s %s\n", setting_name(entry->setting_id), field_value);
diff --git a/src/ui_stats.c b/src/ui_stats.c
new file mode 100644
index 0000000..4037eee
--- /dev/null
+++ b/src/ui_stats.c
@@ -0,0 +1,222 @@
+/**************************************************************************
+ **
+ ** sngrep - SIP Messages flow viewer
+ **
+ ** Copyright (C) 2014 Ivan Alonso (Kaian)
+ ** Copyright (C) 2014 Irontec SL. All rights reserved.
+ **
+ ** 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 3 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, see <http://www.gnu.org/licenses/>.
+ **
+ ****************************************************************************/
+/**
+ * @file ui_stats.c
+ * @author Ivan Alonso [aka Kaian] <kaian at irontec.com>
+ *
+ * @brief Source of functions defined in ui_stats.h
+ */
+/*
+ * +---------------------------------------------------------+
+ * | Stats Information |
+ * +---------------------------------------------------------+
+ * | Dialogs: 725 COMPLETED: 7 (22.1%) |
+ * | Calls: 10 CANCELLED: 2 (12.2%) |
+ * | Messages: 200 IN CALL: 10 (60.5%) |
+ * | REJECTED: 0 (0.0%) |
+ * | CALL SETUP: 0 (0.0%) |
+ * +---------------------------------------------------------+
+ * | INVITE: 10 (0.5%) 1XX: 123 (1.5%) |
+ * | REGISTER: 200 (5.1%) 2XX: 231 (3.1%) |
+ * | SUBSCRIBE: 20 (1.0%) 3XX: 0 (0.0%) |
+ * | UPDATE: 30 (1.3%) 4XX: 12 (1.5%) |
+ * | NOTIFY: 650 (22.7%) 5XX: 0 (0.0%) |
+ * | OPTIONS: 750 (27.4%) 6XX: 3 (0.5%) |
+ * | PUBLISH: 0 (0.0%) 7XX: 0 (0.0%) |
+ * | MESSAGE: 0 (0.0%) 8XX: 0 (0.0%) |
+ * | INFO: 0 (0.0%) |
+ * | ACK: 300 (7.2%) |
+ * | BYE: 10 (0.5%) |
+ * | CANCEL: 0 (0.0%) |
+ * +---------------------------------------------------------+
+ * | Press any key to continue |
+ * +---------------------------------------------------------+
+ *
+ */
+#include "config.h"
+#include "vector.h"
+#include "sip.h"
+#include "ui_manager.h"
+#include "ui_stats.h"
+
+/**
+ * Ui Structure definition for Stats panel
+ */
+ui_t ui_stats = {
+ .type = PANEL_STATS,
+ .panel = NULL,
+ .create = stats_create,
+ .destroy = stats_destroy,
+ .handle_key = stats_handle_key
+};
+
+PANEL *
+stats_create()
+{
+ PANEL *panel;
+ WINDOW *win;
+ int height, width;
+ vector_iter_t calls;
+ vector_iter_t msgs;
+ sip_call_t *call;
+ sip_msg_t *msg;
+
+ // Counters!
+ struct {
+ int dtotal, dcalls, completed, cancelled, incall, rejected, setup;
+ int mtotal, invite, regist, subscribe, update, notify, options;
+ int publish, message, info, ack, bye, cancel;
+ int r100, r200, r300, r400, r500, r600, r700, r800;
+ } stats;
+ memset(&stats, 0, sizeof(stats));
+
+ // Calculate window dimensions
+ height = 23;
+ width = 60;
+
+ // Cerate a new indow for the panel and form
+ win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2);
+
+ // Create a new panel
+ panel = new_panel(win);
+
+ // Set the window title and boxes
+ mvwprintw(win, 1, width / 2 - 9, "Stats Information");
+ wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF));
+ title_foot_box(panel);
+ mvwhline(win, 8, 1, ACS_HLINE, width - 1);
+ mvwaddch(win, 8, 0, ACS_LTEE);
+ mvwaddch(win, 8, width - 1, ACS_RTEE);
+ mvwprintw(win, height - 2, width / 2 - 12, "Press any key to continue");
+ wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF));
+
+ // Parse the data
+ calls = sip_calls_iterator();
+ stats.dtotal = vector_iterator_count(&calls);
+
+ // Ignore this screen when no dialog exists
+ if (!stats.dtotal) {
+ mvwprintw(win, 3, 3, "No information to display");
+ return panel;
+ }
+
+ while ((call = vector_iterator_next(&calls))) {
+ // If this dialog is a call
+ if (call->state) {
+ // Increase call counter
+ stats.dcalls++;
+ // Increase call status counter
+ switch (call->state) {
+ case SIP_CALLSTATE_CALLSETUP: stats.setup++; break;
+ case SIP_CALLSTATE_INCALL: stats.incall++; break;
+ case SIP_CALLSTATE_CANCELLED: stats.cancelled++; break;
+ case SIP_CALLSTATE_REJECTED: stats.rejected++; break;
+ case SIP_CALLSTATE_COMPLETED: stats.completed++; break;
+ }
+ }
+ // For each message in call
+ msgs = vector_iterator(call->msgs);
+ while ((msg = vector_iterator_next(&msgs))) {
+ // Increase message counter
+ stats.mtotal++;
+ // Check message type
+ switch (msg->reqresp) {
+ case SIP_METHOD_REGISTER: stats.regist++; break;
+ case SIP_METHOD_INVITE: stats.invite++; break;
+ case SIP_METHOD_SUBSCRIBE: stats.subscribe++; break;
+ case SIP_METHOD_NOTIFY: stats.notify++; break;
+ case SIP_METHOD_OPTIONS: stats.options++; break;
+ case SIP_METHOD_PUBLISH: stats.publish++; break;
+ case SIP_METHOD_MESSAGE: stats.message++; break;
+ case SIP_METHOD_CANCEL: stats.cancel++; break;
+ case SIP_METHOD_BYE: stats.bye++; break;
+ case SIP_METHOD_ACK: stats.ack++; break;
+ // case SIP_METHOD_PRACK:
+ case SIP_METHOD_INFO: stats.info++; break;
+ // case SIP_METHOD_REFER:
+ case SIP_METHOD_UPDATE: stats.update++; break;
+ default:
+ if (msg->reqresp >= 800) stats.r800++;
+ else if (msg->reqresp >= 700) stats.r700++;
+ else if (msg->reqresp >= 600) stats.r600++;
+ else if (msg->reqresp >= 500) stats.r500++;
+ else if (msg->reqresp >= 400) stats.r400++;
+ else if (msg->reqresp >= 300) stats.r300++;
+ else if (msg->reqresp >= 200) stats.r200++;
+ else if (msg->reqresp >= 100) stats.r100++;
+ }
+ }
+
+
+ }
+
+ // Print parses data
+ mvwprintw(win, 3, 3, "Dialogs: %d", stats.dtotal);
+ mvwprintw(win, 4, 3, "Calls: %d (%.1f\%)", stats.dcalls, (float) stats.dcalls * 100 / stats.dtotal);
+ mvwprintw(win, 5, 3, "Messages: %d", stats.mtotal);
+ // Print status of calls if any
+ if (stats.dcalls) {
+ mvwprintw(win, 3, 33, "COMPLETED: %d (%.1f\%)", stats.completed, (float) stats.completed * 100 / stats.dcalls);
+ mvwprintw(win, 4, 33, "CANCELLED: %d (%.1f\%)", stats.cancelled, (float) stats.cancelled * 100 / stats.dcalls);
+ mvwprintw(win, 5, 33, "IN CALL: %d (%.1f\%)", stats.incall, (float) stats.incall * 100 / stats.dcalls);
+ mvwprintw(win, 6, 33, "REJECTED: %d (%.1f\%)", stats.rejected, (float) stats.rejected * 100 / stats.dcalls);
+ mvwprintw(win, 7, 33, "CALL SETUP: %d (%.1f\%)", stats.setup, (float) stats.setup * 100 / stats.dcalls);
+ }
+
+ mvwprintw(win, 9, 3, "INVITE: %d (%.1f\%)", stats.invite, (float) stats.invite * 100 / stats.mtotal);
+ mvwprintw(win, 10, 3, "REGISTER: %d (%.1f\%)", stats.regist, (float) stats.regist * 100 / stats.mtotal);
+ mvwprintw(win, 11, 3, "SUBSCRIBE: %d (%.1f\%)", stats.subscribe, (float) stats.subscribe * 100 / stats.mtotal);
+ mvwprintw(win, 12, 3, "UPDATE: %d (%.1f\%)", stats.update, (float) stats.update * 100 / stats.mtotal);
+ mvwprintw(win, 13, 3, "NOTIFY: %d (%.1f\%)", stats.notify, (float) stats.notify * 100 / stats.mtotal);
+ mvwprintw(win, 14, 3, "OPTIONS: %d (%.1f\%)", stats.options, (float) stats.options * 100 / stats.mtotal);
+ mvwprintw(win, 15, 3, "PUBLISH: %d (%.1f\%)", stats.publish, (float) stats.publish * 100 / stats.mtotal);
+ mvwprintw(win, 16, 3, "MESSAGE: %d (%.1f\%)", stats.message, (float) stats.message * 100 / stats.mtotal);
+ mvwprintw(win, 17, 3, "INFO: %d (%.1f\%)", stats.info, (float) stats.info * 100 / stats.mtotal);
+ mvwprintw(win, 18, 3, "BYE: %d (%.1f\%)", stats.bye, (float) stats.bye * 100 / stats.mtotal);
+ mvwprintw(win, 19, 3, "CANCEL: %d (%.1f\%)", stats.cancel, (float) stats.cancel * 100 / stats.mtotal);
+
+ mvwprintw(win, 9, 33, "1XX: %d (%.1f\%)", stats.r100, (float) stats.r100 * 100 / stats.mtotal);
+ mvwprintw(win, 10, 33, "2XX: %d (%.1f\%)", stats.r200, (float) stats.r200 * 100 / stats.mtotal);
+ mvwprintw(win, 11, 33, "3XX: %d (%.1f\%)", stats.r300, (float) stats.r300 * 100 / stats.mtotal);
+ mvwprintw(win, 12, 33, "4XX: %d (%.1f\%)", stats.r400, (float) stats.r400 * 100 / stats.mtotal);
+ mvwprintw(win, 13, 33, "5XX: %d (%.1f\%)", stats.r500, (float) stats.r500 * 100 / stats.mtotal);
+ mvwprintw(win, 14, 33, "6XX: %d (%.1f\%)", stats.r600, (float) stats.r600 * 100 / stats.mtotal);
+ mvwprintw(win, 15, 33, "7XX: %d (%.1f\%)", stats.r700, (float) stats.r700 * 100 / stats.mtotal);
+ mvwprintw(win, 16, 33, "8XX: %d (%.1f\%)", stats.r800, (float) stats.r800 * 100 / stats.mtotal);
+
+ return panel;
+}
+
+void
+stats_destroy(PANEL *panel)
+{
+ // Deallocate panel window
+ delwin(panel_window(panel));
+ // Deallocate panel pointer
+ del_panel(panel);
+}
+
+int
+stats_handle_key(PANEL *panel, int key)
+{
+ return KEY_ESC;
+}
diff --git a/src/ui_stats.h b/src/ui_stats.h
new file mode 100644
index 0000000..6a34de5
--- /dev/null
+++ b/src/ui_stats.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+ **
+ ** sngrep - SIP Messages flow viewer
+ **
+ ** Copyright (C) 2013-2015 Ivan Alonso (Kaian)
+ ** Copyright (C) 2013-2015 Irontec SL. All rights reserved.
+ **
+ ** 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 3 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, see <http://www.gnu.org/licenses/>.
+ **
+ ****************************************************************************/
+/**
+ * @file ui_stats.h
+ * @author Ivan Alonso [aka Kaian] <kaian at irontec.com>
+ *
+ * @brief Functions to manage ui window for capture stats display
+ */
+#ifndef __UI_STATS_H
+#define __UI_STATS_H
+
+/**
+ * @brief Creates a new stats panel
+ *
+ * This function allocates all required memory for
+ * displaying the stats panel. It also draws all the
+ * static information of the panel that will never be
+ * redrawn.
+ *
+ * @return a panel pointer
+ */
+PANEL *
+stats_create();
+
+/**
+ * @brief Destroy stats panel
+ *
+ * This function do the final cleanups for this panel
+ */
+void
+stats_destroy();
+
+/**
+ * @brief Manage pressed keys for stats panel
+ *
+ * This function is called by UI manager every time a
+ * key is pressed. This allow the filter panel to manage
+ * its own keys.
+ * If this function return 0, the key will not be handled
+ * by ui manager. Otherwise the return will be considered
+ * a key code.
+ *
+ * @param panel Filter panel pointer
+ * @param key key code
+ * @return 0 if the key is handled, keycode otherwise
+ */
+int
+stats_handle_key(PANEL *panel, int key);
+
+
+
+#endif /* __UI_STATS_H */
diff --git a/src/vector.c b/src/vector.c
index 27bde49..a93c1ed 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -314,6 +314,12 @@ vector_iterator_set_current(vector_iter_t *it, int current)
it->current = current;
}
+void
+vector_iterator_set_last(vector_iter_t *it)
+{
+ it->current = vector_count(it->vector);
+}
+
int
vector_iterator_current(vector_iter_t *it)
{
diff --git a/src/vector.h b/src/vector.h
index ca7c23c..c33541e 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -250,6 +250,12 @@ void
vector_iterator_set_current(vector_iter_t *it, int current);
/**
+ * @brief Set iterator position to the last element
+ */
+void
+vector_iterator_set_last(vector_iter_t *it);
+
+/**
* @brief Return current iterator position
*/
int
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/sngrep.git
More information about the Pkg-voip-commits
mailing list