forked from Mirrors/sngrep
Refactoring: Move call and message functions
This commit is contained in:
parent
df175cc5ba
commit
b71138aeed
@ -1,5 +1,5 @@
|
||||
bin_PROGRAMS=sngrep
|
||||
sngrep_SOURCES=capture.c capture_ws.c sip.c sip_attr.c main.c option.c
|
||||
sngrep_SOURCES=capture.c capture_ws.c 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_filter.c ui_save.c ui_msg_diff.c ui_column_select.c ui_settings.c
|
||||
|
@ -20,7 +20,7 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
/**
|
||||
* @file capture_rtp.c
|
||||
* @file rtp.c
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Functions to manage RTP captured packets
|
||||
|
@ -20,7 +20,7 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
/**
|
||||
* @file capture_rtp.h
|
||||
* @file rtp.h
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Functions to manage rtp captured packets
|
||||
|
407
src/sip.c
407
src/sip.c
@ -61,7 +61,7 @@ sip_init(int limit, int only_calls, int no_incomplete)
|
||||
|
||||
// Create a vector to store calls
|
||||
calls.list = vector_create(200, 50);
|
||||
vector_set_destroyer(calls.list, sip_call_destroyer);
|
||||
vector_set_destroyer(calls.list, call_destroyer);
|
||||
|
||||
// Create hash table for callid search
|
||||
hcreate(calls.limit);
|
||||
@ -108,111 +108,6 @@ sip_deinit()
|
||||
pthread_mutex_destroy(&calls.lock);
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
sip_call_create(char *callid)
|
||||
{
|
||||
ENTRY entry;
|
||||
int index;
|
||||
sip_call_t *call;
|
||||
|
||||
// Initialize a new call structure
|
||||
if (!(call = malloc(sizeof(sip_call_t))))
|
||||
return NULL;
|
||||
memset(call, 0, sizeof(sip_call_t));
|
||||
|
||||
// Add this call to the call list
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
index = vector_append(calls.list, call);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
|
||||
// Store Call-Id
|
||||
call->callid = strdup(callid);
|
||||
|
||||
// Store this call in hash table
|
||||
entry.key = call->callid;
|
||||
entry.data = (void *) call;
|
||||
hsearch(entry, ENTER);
|
||||
|
||||
// Create a vector to store call messages
|
||||
call->msgs = vector_create(10, 5);
|
||||
vector_set_destroyer(call->msgs, sip_msg_destroyer);
|
||||
|
||||
// Create a vector to store call attributes
|
||||
call->attrs = vector_create(1, 1);
|
||||
vector_set_destroyer(call->attrs, sip_attr_destroyer);
|
||||
|
||||
// Create a vector to store RTP streams
|
||||
call->streams = vector_create(0, 2);
|
||||
vector_set_destroyer(call->streams, vector_generic_destroyer);
|
||||
|
||||
// Initialize call filter status
|
||||
call->filtered = -1;
|
||||
|
||||
// Store current call Index
|
||||
call_set_attribute(call, SIP_ATTR_CALLINDEX, "%d", index);
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
void
|
||||
sip_call_destroy(sip_call_t *call)
|
||||
{
|
||||
// Remove all call messages
|
||||
vector_destroy(call->msgs);
|
||||
// Remove all call streams
|
||||
vector_destroy(call->streams);
|
||||
// Remove all call attributes
|
||||
vector_destroy(call->attrs);
|
||||
// Free it!
|
||||
free(call->callid);
|
||||
free(call);
|
||||
}
|
||||
|
||||
void
|
||||
sip_call_destroyer(void *call)
|
||||
{
|
||||
sip_call_destroy((sip_call_t*)call);
|
||||
}
|
||||
|
||||
sip_msg_t *
|
||||
sip_msg_create(const char *payload)
|
||||
{
|
||||
sip_msg_t *msg;
|
||||
|
||||
if (!(msg = malloc(sizeof(sip_msg_t))))
|
||||
return NULL;
|
||||
memset(msg, 0, sizeof(sip_msg_t));
|
||||
msg->color = 0;
|
||||
// Create a vector to store attributes
|
||||
msg->attrs = vector_create(4, 10);
|
||||
vector_set_destroyer(msg->attrs, sip_attr_destroyer);
|
||||
// Create a vector to store sdp
|
||||
msg->medias = vector_create(0, 2);
|
||||
vector_set_destroyer(msg->medias, vector_generic_destroyer);
|
||||
// Create a vector to store packets
|
||||
msg->packets = vector_create(1, 1);
|
||||
vector_set_destroyer(msg->packets, capture_packet_destroyer);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void
|
||||
sip_msg_destroy(sip_msg_t *msg)
|
||||
{
|
||||
// Free message attribute list
|
||||
vector_destroy(msg->attrs);
|
||||
// Free message SDP media
|
||||
vector_destroy(msg->medias);
|
||||
// Free message packets
|
||||
vector_destroy(msg->packets);
|
||||
// Free all memory
|
||||
free(msg);
|
||||
}
|
||||
|
||||
void
|
||||
sip_msg_destroyer(void *msg)
|
||||
{
|
||||
sip_msg_destroy((sip_msg_t *)msg);
|
||||
}
|
||||
|
||||
char *
|
||||
sip_get_callid(const char* payload)
|
||||
@ -236,8 +131,10 @@ sip_get_callid(const char* payload)
|
||||
sip_msg_t *
|
||||
sip_load_message(capture_packet_t *packet, const char *src, u_short sport, const char* dst, u_short dport, u_char *payload)
|
||||
{
|
||||
ENTRY entry;
|
||||
sip_msg_t *msg;
|
||||
sip_call_t *call;
|
||||
int call_idx;
|
||||
char *callid;
|
||||
char msg_src[ADDRESSLEN];
|
||||
char msg_dst[ADDRESSLEN];
|
||||
@ -248,16 +145,16 @@ sip_load_message(capture_packet_t *packet, const char *src, u_short sport, const
|
||||
}
|
||||
|
||||
// Create a new message from this data
|
||||
if (!(msg = sip_msg_create((const char*) payload))) {
|
||||
if (!(msg = msg_create((const char*) payload))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get Method and request for the following checks
|
||||
// There is no need to parse all payload at this point
|
||||
// If no response or request code is found, this is not a SIP message
|
||||
if (!msg_get_reqresp(msg, payload)) {
|
||||
if (!sip_get_msg_reqresp(msg, payload)) {
|
||||
// Deallocate message memory
|
||||
sip_msg_destroy(msg);
|
||||
msg_destroy(msg);
|
||||
free(callid);
|
||||
return NULL;
|
||||
}
|
||||
@ -286,12 +183,12 @@ sip_load_message(capture_packet_t *packet, const char *src, u_short sport, const
|
||||
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
// Find the call for this msg
|
||||
if (!(call = call_find_by_callid(callid))) {
|
||||
if (!(call = sip_find_by_callid(callid))) {
|
||||
|
||||
// Check if payload matches expression
|
||||
if (!sip_check_match_expression((const char*) payload)) {
|
||||
// Deallocate message memory
|
||||
sip_msg_destroy(msg);
|
||||
msg_destroy(msg);
|
||||
free(callid);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return NULL;
|
||||
@ -301,7 +198,7 @@ sip_load_message(capture_packet_t *packet, const char *src, u_short sport, const
|
||||
if (calls.only_calls) {
|
||||
if (msg->reqresp != SIP_METHOD_INVITE) {
|
||||
// Deallocate message memory
|
||||
sip_msg_destroy(msg);
|
||||
msg_destroy(msg);
|
||||
free(callid);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return NULL;
|
||||
@ -313,7 +210,7 @@ sip_load_message(capture_packet_t *packet, const char *src, u_short sport, const
|
||||
if (calls.ignore_incomplete) {
|
||||
if (msg->reqresp > SIP_METHOD_MESSAGE) {
|
||||
// Deallocate message memory
|
||||
sip_msg_destroy(msg);
|
||||
msg_destroy(msg);
|
||||
free(callid);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return NULL;
|
||||
@ -323,20 +220,33 @@ sip_load_message(capture_packet_t *packet, const char *src, u_short sport, const
|
||||
// Check if this message is ignored by configuration directive
|
||||
if (sip_check_msg_ignore(msg)) {
|
||||
// Deallocate message memory
|
||||
sip_msg_destroy(msg);
|
||||
msg_destroy(msg);
|
||||
free(callid);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create the call if not found
|
||||
if (!(call = sip_call_create(callid))) {
|
||||
if (!(call = call_create(callid))) {
|
||||
// Deallocate message memory
|
||||
sip_msg_destroy(msg);
|
||||
msg_destroy(msg);
|
||||
free(callid);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Store this call in hash table
|
||||
entry.key = call->callid;
|
||||
entry.data = (void *) call;
|
||||
hsearch(entry, ENTER);
|
||||
|
||||
// Append this call to the call list
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
call_idx = vector_append(calls.list, call);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
|
||||
// Store current call Index
|
||||
call_set_attribute(call, SIP_ATTR_CALLINDEX, "%d", call_idx);
|
||||
}
|
||||
|
||||
// Set message callid
|
||||
@ -360,9 +270,9 @@ sip_load_message(capture_packet_t *packet, const char *src, u_short sport, const
|
||||
// Add the message to the call
|
||||
call_add_message(call, msg);
|
||||
// Parse SIP payload
|
||||
msg_parse_payload(msg, payload);
|
||||
sip_parse_msg_payload(msg, payload);
|
||||
// Parse media data
|
||||
msg_parse_media(msg, payload);
|
||||
sip_parse_msg_media(msg, payload);
|
||||
// Update Call State
|
||||
call_update_state(call, msg);
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
@ -397,19 +307,9 @@ sip_calls_stats(int *total, int *displayed)
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
}
|
||||
|
||||
void
|
||||
call_add_message(sip_call_t *call, sip_msg_t *msg)
|
||||
{
|
||||
// Set the message owner
|
||||
msg->call = call;
|
||||
// Put this msg at the end of the msg list
|
||||
vector_append(call->msgs, msg);
|
||||
// Store message count
|
||||
call_set_attribute(call, SIP_ATTR_MSGCNT, "%d", vector_count(call->msgs));
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_find_by_callid(const char *callid)
|
||||
sip_find_by_callid(const char *callid)
|
||||
{
|
||||
ENTRY entry, *eptr;
|
||||
|
||||
@ -421,7 +321,7 @@ call_find_by_callid(const char *callid)
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_find_by_xcallid(const char *xcallid)
|
||||
sip_find_by_xcallid(const char *xcallid)
|
||||
{
|
||||
const char *cur_xcallid;
|
||||
sip_call_t *cur;
|
||||
@ -437,17 +337,6 @@ call_find_by_xcallid(const char *xcallid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
call_msg_count(sip_call_t *call)
|
||||
{
|
||||
return vector_count(call->msgs);
|
||||
}
|
||||
|
||||
int
|
||||
msg_media_count(sip_msg_t *msg)
|
||||
{
|
||||
return vector_count(msg->medias);
|
||||
}
|
||||
|
||||
sip_call_t *
|
||||
call_get_xcall(sip_call_t *call)
|
||||
@ -455,103 +344,16 @@ call_get_xcall(sip_call_t *call)
|
||||
sip_call_t *xcall;
|
||||
pthread_mutex_lock(&calls.lock);
|
||||
if (call_get_attribute(call, SIP_ATTR_XCALLID)) {
|
||||
xcall = call_find_by_callid(call_get_attribute(call, SIP_ATTR_XCALLID));
|
||||
xcall = sip_find_by_callid(call_get_attribute(call, SIP_ATTR_XCALLID));
|
||||
} else {
|
||||
xcall = call_find_by_xcallid(call_get_attribute(call, SIP_ATTR_CALLID));
|
||||
xcall = sip_find_by_xcallid(call_get_attribute(call, SIP_ATTR_CALLID));
|
||||
}
|
||||
pthread_mutex_unlock(&calls.lock);
|
||||
return xcall;
|
||||
}
|
||||
|
||||
int
|
||||
call_is_active(void *item)
|
||||
{
|
||||
// TODO
|
||||
sip_call_t *call = (sip_call_t *)item;
|
||||
return call->active;
|
||||
}
|
||||
|
||||
int
|
||||
msg_has_sdp(void *item)
|
||||
{
|
||||
// TODO
|
||||
sip_msg_t *msg = (sip_msg_t *)item;
|
||||
return vector_count(msg->medias) ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
call_update_state(sip_call_t *call, sip_msg_t *msg)
|
||||
{
|
||||
const char *callstate;
|
||||
char dur[20];
|
||||
int reqresp;
|
||||
sip_msg_t *first;
|
||||
|
||||
// Sanity check
|
||||
if (!call || !call->msgs || !msg)
|
||||
return;
|
||||
|
||||
// Get the first message in the call
|
||||
first = vector_first(call->msgs);
|
||||
|
||||
// Check First message of Call has INVITE method
|
||||
if (first->reqresp != SIP_METHOD_INVITE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get current message Method / Response Code
|
||||
reqresp = msg->reqresp;
|
||||
|
||||
// If this message is actually a call, get its current state
|
||||
if ((callstate = call_get_attribute(call, SIP_ATTR_CALLSTATE))) {
|
||||
if (!strcmp(callstate, SIP_CALLSTATE_CALLSETUP)) {
|
||||
if (reqresp == 200) {
|
||||
// Alice and Bob are talking
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_INCALL);
|
||||
// Store the timestap where call has started
|
||||
call->active = 1;
|
||||
call->cstart_msg = msg;
|
||||
} else if (reqresp == SIP_METHOD_CANCEL) {
|
||||
// Alice is not in the mood
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CANCELLED);
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, timeval_to_duration(msg_get_time(first), msg_get_time(msg), dur));
|
||||
call->active = 0;
|
||||
} else if (reqresp > 400) {
|
||||
// Bob is not in the mood
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_REJECTED);
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, timeval_to_duration(msg_get_time(first), msg_get_time(msg), dur));
|
||||
call->active = 0;
|
||||
}
|
||||
} else if (!strcmp(callstate, SIP_CALLSTATE_INCALL)) {
|
||||
if (reqresp == SIP_METHOD_BYE) {
|
||||
// Thanks for all the fish!
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_COMPLETED);
|
||||
// Store Conversation duration
|
||||
call_set_attribute(call, SIP_ATTR_CONVDUR,
|
||||
timeval_to_duration(msg_get_time(call->cstart_msg), msg_get_time(msg), dur));
|
||||
call->active = 0;
|
||||
}
|
||||
} else if (reqresp == SIP_METHOD_INVITE && strcmp(callstate, SIP_CALLSTATE_INCALL)) {
|
||||
// Call is being setup (after proper authentication)
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CALLSETUP);
|
||||
call->active = 1;
|
||||
} else {
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, timeval_to_duration(msg_get_time(first), msg_get_time(msg), dur));
|
||||
}
|
||||
} else {
|
||||
// This is actually a call
|
||||
if (reqresp == SIP_METHOD_INVITE) {
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CALLSETUP);
|
||||
call->active = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
msg_get_reqresp(sip_msg_t *msg, const u_char *payload)
|
||||
sip_get_msg_reqresp(sip_msg_t *msg, const u_char *payload)
|
||||
{
|
||||
regmatch_t pmatch[3];
|
||||
char reqresp[20];
|
||||
@ -582,7 +384,7 @@ msg_get_reqresp(sip_msg_t *msg, const u_char *payload)
|
||||
}
|
||||
|
||||
int
|
||||
msg_parse_payload(sip_msg_t *msg, const u_char *payload)
|
||||
sip_parse_msg_payload(sip_msg_t *msg, const u_char *payload)
|
||||
{
|
||||
regmatch_t pmatch[4];
|
||||
char date[12], time[20], cseq[11];
|
||||
@ -623,7 +425,7 @@ msg_parse_payload(sip_msg_t *msg, const u_char *payload)
|
||||
}
|
||||
|
||||
void
|
||||
msg_parse_media(sip_msg_t *msg, const u_char *payload)
|
||||
sip_parse_msg_media(sip_msg_t *msg, const u_char *payload)
|
||||
{
|
||||
regmatch_t pmatch[4];
|
||||
char address[ADDRESSLEN];
|
||||
@ -693,73 +495,6 @@ msg_parse_media(sip_msg_t *msg, const u_char *payload)
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
msg_is_retrans(sip_msg_t *msg)
|
||||
{
|
||||
sip_msg_t *prev = NULL;
|
||||
vector_iter_t it;
|
||||
|
||||
// Get previous message in call
|
||||
it = vector_iterator(msg->call->msgs);
|
||||
vector_iterator_set_current(&it, vector_index(msg->call->msgs, msg));
|
||||
prev = vector_iterator_prev(&it);
|
||||
|
||||
return (prev && !strcasecmp(msg_get_payload(msg), msg_get_payload(prev)));
|
||||
}
|
||||
|
||||
int
|
||||
msg_is_request(sip_msg_t *msg)
|
||||
{
|
||||
return msg->reqresp < SIP_METHOD_SENTINEL;
|
||||
}
|
||||
|
||||
void
|
||||
msg_add_packet(sip_msg_t *msg, capture_packet_t *packet)
|
||||
{
|
||||
vector_append(msg->packets, packet);
|
||||
}
|
||||
|
||||
const char *
|
||||
msg_get_payload(sip_msg_t *msg)
|
||||
{
|
||||
// Return Message payload pointer
|
||||
if (msg->payload)
|
||||
return (const char *)msg->payload;
|
||||
|
||||
// Calculate message payload pointer
|
||||
// TODO Multi packet support
|
||||
capture_packet_t *packet = vector_first(msg->packets);
|
||||
packet->data[packet->size - 1] = '\0';
|
||||
msg->payload = packet->data + packet->payload_start;
|
||||
return (const char *) msg->payload;
|
||||
}
|
||||
|
||||
char *
|
||||
msg_get_header(sip_msg_t *msg, char *out)
|
||||
{
|
||||
// Source and Destination address
|
||||
char from_addr[80], to_addr[80];
|
||||
|
||||
// We dont use Message attributes here because it contains truncated data
|
||||
// This should not overload too much as all results should be already cached
|
||||
sprintf(from_addr, "%s", sip_address_port_format(SRC(msg)));
|
||||
sprintf(to_addr, "%s", sip_address_port_format(DST(msg)));
|
||||
|
||||
// Get msg header
|
||||
sprintf(out, "%s %s %s -> %s", DATE(msg), TIME(msg), from_addr, to_addr);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct timeval
|
||||
msg_get_time(sip_msg_t *msg)
|
||||
{
|
||||
struct timeval t = { };
|
||||
capture_packet_t *packet;
|
||||
|
||||
if (msg && (packet = vector_first(msg->packets)))
|
||||
return packet->header->ts;
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
sip_calls_clear()
|
||||
@ -824,62 +559,6 @@ sip_check_match_expression(const char *payload)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
call_set_attribute(sip_call_t *call, enum sip_attr_id id, const char *fmt, ...)
|
||||
{
|
||||
char value[512];
|
||||
|
||||
// Get the actual value for the attribute
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(value, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
sip_attr_set(call->attrs, id, value);
|
||||
}
|
||||
|
||||
const char *
|
||||
call_get_attribute(sip_call_t *call, enum sip_attr_id id)
|
||||
{
|
||||
if (!call)
|
||||
return NULL;
|
||||
|
||||
switch (id) {
|
||||
case SIP_ATTR_CALLINDEX:
|
||||
case SIP_ATTR_MSGCNT:
|
||||
case SIP_ATTR_CALLSTATE:
|
||||
case SIP_ATTR_CONVDUR:
|
||||
case SIP_ATTR_TOTALDUR:
|
||||
return sip_attr_get_value(call->attrs, id);
|
||||
default:
|
||||
return msg_get_attribute(vector_first(call->msgs), id);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
msg_set_attribute(sip_msg_t *msg, enum sip_attr_id id, const char *fmt, ...)
|
||||
{
|
||||
char value[512];
|
||||
|
||||
// Get the actual value for the attribute
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(value, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
sip_attr_set(msg->attrs, id, value);
|
||||
}
|
||||
|
||||
const char *
|
||||
msg_get_attribute(sip_msg_t *msg, enum sip_attr_id id)
|
||||
{
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
return sip_attr_get_value(msg->attrs, id);
|
||||
}
|
||||
|
||||
int
|
||||
sip_check_msg_ignore(sip_msg_t *msg)
|
||||
@ -945,6 +624,22 @@ sip_method_from_str(const char *method)
|
||||
return atoi(method);
|
||||
}
|
||||
|
||||
char *
|
||||
sip_get_msg_header(sip_msg_t *msg, char *out)
|
||||
{
|
||||
// Source and Destination address
|
||||
char from_addr[80], to_addr[80];
|
||||
|
||||
// We dont use Message attributes here because it contains truncated data
|
||||
// This should not overload too much as all results should be already cached
|
||||
sprintf(from_addr, "%s", sip_address_port_format(SRC(msg)));
|
||||
sprintf(to_addr, "%s", sip_address_port_format(DST(msg)));
|
||||
|
||||
// Get msg header
|
||||
sprintf(out, "%s %s %s -> %s", DATE(msg), TIME(msg), from_addr, to_addr);
|
||||
return out;
|
||||
}
|
||||
|
||||
const char *
|
||||
sip_address_format(const char *address)
|
||||
{
|
||||
|
367
src/sip.h
367
src/sip.h
@ -37,96 +37,12 @@
|
||||
#ifdef WITH_PCRE
|
||||
#include <pcre.h>
|
||||
#endif
|
||||
#include "util.h"
|
||||
#include "sip_attr.h"
|
||||
#include "rtp.h"
|
||||
#include "media.h"
|
||||
#include "sip_call.h"
|
||||
#include "vector.h"
|
||||
|
||||
//! SIP Methods
|
||||
enum sip_methods {
|
||||
SIP_METHOD_REGISTER = 1,
|
||||
SIP_METHOD_INVITE,
|
||||
SIP_METHOD_SUBSCRIBE,
|
||||
SIP_METHOD_NOTIFY,
|
||||
SIP_METHOD_OPTIONS,
|
||||
SIP_METHOD_PUBLISH,
|
||||
SIP_METHOD_MESSAGE,
|
||||
SIP_METHOD_CANCEL,
|
||||
SIP_METHOD_BYE,
|
||||
SIP_METHOD_ACK,
|
||||
SIP_METHOD_PRACK,
|
||||
SIP_METHOD_INFO,
|
||||
SIP_METHOD_REFER,
|
||||
SIP_METHOD_UPDATE,
|
||||
SIP_METHOD_SENTINEL,
|
||||
};
|
||||
|
||||
//! SIP Call State
|
||||
#define SIP_CALLSTATE_CALLSETUP "CALL SETUP"
|
||||
#define SIP_CALLSTATE_INCALL "IN CALL"
|
||||
#define SIP_CALLSTATE_CANCELLED "CANCELLED"
|
||||
#define SIP_CALLSTATE_REJECTED "REJECTED"
|
||||
#define SIP_CALLSTATE_COMPLETED "COMPLETED"
|
||||
|
||||
//! Shorter declaration of sip_call structure
|
||||
typedef struct sip_call sip_call_t;
|
||||
//! Shorter declaration of sip_msg structure
|
||||
typedef struct sip_msg sip_msg_t;
|
||||
//! Shorter declaration of sip_call_list structure
|
||||
typedef struct sip_call_list sip_call_list_t;
|
||||
|
||||
/**
|
||||
* @brief Information of a single message withing a dialog.
|
||||
*
|
||||
* Most of the data is just stored to be displayed in the UI so
|
||||
* the formats may be no the best, but the simplest for this
|
||||
* purpose. It also works as a linked lists of messages in a
|
||||
* call.
|
||||
*/
|
||||
struct sip_msg {
|
||||
//! Temporal payload data before being parsed
|
||||
u_char *payload;
|
||||
//! Color for this message (in color.cseq mode)
|
||||
int color;
|
||||
//! Request Method or Response Code @see sip_methods
|
||||
int reqresp;
|
||||
//! Message Cseq
|
||||
int cseq;
|
||||
//! Message attribute list
|
||||
vector_t *attrs;
|
||||
//! SDP payload information (sdp_media_t *)
|
||||
vector_t *medias;
|
||||
//! Captured packets for this message (capture_packet_t *)
|
||||
vector_t *packets;
|
||||
//! Message owner
|
||||
sip_call_t *call;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Contains all information of a call and its messages
|
||||
*
|
||||
* This structure acts as header of messages list of the same
|
||||
* callid (considered a dialog). It contains some replicated
|
||||
* data from its messages to speed up searches.
|
||||
*/
|
||||
struct sip_call {
|
||||
//! Call Call-Id
|
||||
char *callid;
|
||||
//! Flag this call as filtered so won't be displayed
|
||||
int filtered;
|
||||
//! For call dialogs, mark if call has not yet finished
|
||||
int active;
|
||||
//! List of messages of this call (sip_msg_t*)
|
||||
vector_t *msgs;
|
||||
//! Message when conversation started
|
||||
sip_msg_t *cstart_msg;
|
||||
//! Call attribute list
|
||||
vector_t *attrs;
|
||||
//! RTP streams for this call (rtp_stream_t *)
|
||||
vector_t *streams;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief call structures head list
|
||||
*
|
||||
@ -183,68 +99,6 @@ sip_init(int limit, int only_calls, int no_incomplete);
|
||||
void
|
||||
sip_deinit();
|
||||
|
||||
/**
|
||||
* @brief Create a new call with the given callid (Minimum required data)
|
||||
*
|
||||
* Allocated required memory for a new SIP Call. The call acts as
|
||||
* header structure to all the messages with the same callid.
|
||||
*
|
||||
* @param callid Call-ID Header value
|
||||
* @return pointer to the sip_call created
|
||||
*/
|
||||
sip_call_t *
|
||||
sip_call_create(char *callid);
|
||||
|
||||
/**
|
||||
* @brief Free all related memory from a call and remove from call list
|
||||
*
|
||||
* Deallocate memory of an existing SIP Call.
|
||||
* This will also remove all messages, calling sip_msg_destroy for each
|
||||
* one.
|
||||
*
|
||||
* @param call Call to be destroyed
|
||||
*/
|
||||
void
|
||||
sip_call_destroy(sip_call_t *call);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Wrapper around Message destroyer to clear call vectors
|
||||
*/
|
||||
void
|
||||
sip_call_destroyer(void *call);
|
||||
|
||||
/**
|
||||
* @brief Create a new message from the readed header and payload
|
||||
*
|
||||
* Allocate required memory for a new SIP message. This function
|
||||
* will only store the given information, but wont parse it until
|
||||
* needed.
|
||||
*
|
||||
* @param payload Raw payload content
|
||||
* @return a new allocated message
|
||||
*/
|
||||
sip_msg_t *
|
||||
sip_msg_create(const char *payload);
|
||||
|
||||
/**
|
||||
* @brief Destroy a SIP message and free its memory
|
||||
*
|
||||
* Deallocate memory of an existing SIP Message.
|
||||
* This function will remove the message from the call and the
|
||||
* passed pointer will be NULL.
|
||||
*
|
||||
* @param nsg SIP message to be deleted
|
||||
*/
|
||||
void
|
||||
sip_msg_destroy(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Wrapper around Message destroyer to clear msg vectors
|
||||
*/
|
||||
void
|
||||
sip_msg_destroyer(void *msg);
|
||||
|
||||
/**
|
||||
* @brief Parses Call-ID header of a SIP message payload
|
||||
*
|
||||
@ -294,28 +148,14 @@ sip_calls_iterator();
|
||||
void
|
||||
sip_calls_stats(int *total, int *displayed);
|
||||
|
||||
/**
|
||||
* @brief Append message to the call's message list
|
||||
*
|
||||
* Creates a relation between this call and the message, appending it
|
||||
* to the end of the message list and setting the message owner.
|
||||
*
|
||||
* @param call pointer to the call owner of the message
|
||||
* @param msg SIP message structure
|
||||
*/
|
||||
void
|
||||
call_add_message(sip_call_t *call, sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Find a call structure in calls linked list given an callid
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param callid Call-ID Header value
|
||||
* @return pointer to the sip_call structure found or NULL
|
||||
*/
|
||||
sip_call_t *
|
||||
call_find_by_callid(const char *callid);
|
||||
sip_find_by_callid(const char *callid);
|
||||
|
||||
/**
|
||||
* @brief Find a call structure in calls linked list given an xcallid
|
||||
@ -327,69 +167,16 @@ call_find_by_callid(const char *callid);
|
||||
* @return pointer to the sip_call structure found or NULL
|
||||
*/
|
||||
sip_call_t *
|
||||
call_find_by_xcallid(const char *xcallid);
|
||||
sip_find_by_xcallid(const char *xcallid);
|
||||
|
||||
/**
|
||||
* @brief Getter for call messages linked list size
|
||||
* @brief Remove al calls
|
||||
*
|
||||
* Return the number of messages stored in this call. All messages
|
||||
* share the same Call-ID
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @return how many messages are in the call
|
||||
*/
|
||||
int
|
||||
call_msg_count(sip_call_t *call);
|
||||
|
||||
/**
|
||||
* @brief Getter for media of given messages
|
||||
*
|
||||
* Return the number of media structures of given msg
|
||||
* stored in this call.
|
||||
*
|
||||
* @param msg SIP message structure
|
||||
* @return how many media structures are in the msg
|
||||
*/
|
||||
int
|
||||
msg_media_count(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Finds the other leg of this call.
|
||||
*
|
||||
* If this call has a X-CID or X-Call-ID header, that call will be
|
||||
* find and returned. Otherwise, a call with X-CID or X-Call-ID header
|
||||
* matching the given call's Call-ID will be find or returned.
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @return The other call structure or NULL if none found
|
||||
*/
|
||||
sip_call_t *
|
||||
call_get_xcall(sip_call_t *call);
|
||||
|
||||
|
||||
int
|
||||
call_is_active(void *item);
|
||||
|
||||
int
|
||||
msg_has_sdp(void *item);
|
||||
|
||||
/**
|
||||
* @brief Update Call State attribute with its last parsed message
|
||||
*
|
||||
* @param call Call structure to be updated
|
||||
* @param msg Last received message of this call
|
||||
* This funtion will clear the call list invoking the destroy
|
||||
* function for each one.
|
||||
*/
|
||||
void
|
||||
call_update_state(sip_call_t *call, sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Add a media structure to a msg
|
||||
*
|
||||
* @param cmsg SIP Message to be updated
|
||||
* @param media Media structure to be added
|
||||
*/
|
||||
void
|
||||
msg_add_media(sip_msg_t *msg, sdp_media_t *media);
|
||||
sip_calls_clear();
|
||||
|
||||
/**
|
||||
* @brief Get message Request/Response code
|
||||
@ -400,7 +187,7 @@ msg_add_media(sip_msg_t *msg, sdp_media_t *media);
|
||||
* @return numeric representation of Request/ResponseCode
|
||||
*/
|
||||
int
|
||||
msg_get_reqresp(sip_msg_t *msg, const u_char *payload);
|
||||
sip_get_msg_reqresp(sip_msg_t *msg, const u_char *payload);
|
||||
|
||||
/**
|
||||
* @brief Parse SIP Message payload to fill sip_msg structe
|
||||
@ -412,7 +199,7 @@ msg_get_reqresp(sip_msg_t *msg, const u_char *payload);
|
||||
* @return 0 in all cases
|
||||
*/
|
||||
int
|
||||
msg_parse_payload(sip_msg_t *msg, const u_char *payload);
|
||||
sip_parse_msg_payload(sip_msg_t *msg, const u_char *payload);
|
||||
|
||||
/**
|
||||
* @brief Parse SIP Message payload for SDP media streams
|
||||
@ -423,77 +210,7 @@ msg_parse_payload(sip_msg_t *msg, const u_char *payload);
|
||||
* @return 0 in all cases
|
||||
*/
|
||||
void
|
||||
msg_parse_media(sip_msg_t *msg, const u_char *payload);
|
||||
|
||||
/**
|
||||
* @brief Check if a package is a retransmission
|
||||
*
|
||||
* This function will compare its payload with the previous message
|
||||
* in the dialog, to check if it has the same content.
|
||||
*
|
||||
* @param msg SIP message that will be checked
|
||||
* @return 1 if the previous message is equal to msg, 0 otherwise
|
||||
*/
|
||||
int
|
||||
msg_is_retrans(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Check if a message is a Request or response
|
||||
*
|
||||
* @param msg SIP message that will be checked
|
||||
* @return 1 if the message is a request, 0 if a response
|
||||
*/
|
||||
int
|
||||
msg_is_request(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Add a new packet for given message
|
||||
*
|
||||
* A SIP message can have multiple fragmented packets to
|
||||
* store its payload;
|
||||
*
|
||||
* @param msg SIP message that will store this packet
|
||||
* @param packet Captured packet information
|
||||
*/
|
||||
void
|
||||
msg_add_packet(sip_msg_t *msg, capture_packet_t *packet);
|
||||
|
||||
/**
|
||||
* @brief Get SIP Message payload
|
||||
*/
|
||||
const char *
|
||||
msg_get_payload(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Get summary of message header data
|
||||
*
|
||||
* For raw prints, it's handy to have the ngrep header style message
|
||||
* data.
|
||||
*
|
||||
* @param msg SIP message
|
||||
* @param out pointer to allocated memory to contain the header output
|
||||
* @returns pointer to out
|
||||
*/
|
||||
char *
|
||||
msg_get_header(sip_msg_t *msg, char *out);
|
||||
|
||||
/**
|
||||
* @brief Get Time of message from packet header
|
||||
*
|
||||
* @param msg SIP message
|
||||
* @return timeval structure with message first packet time
|
||||
*/
|
||||
struct timeval
|
||||
msg_get_time(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Remove al calls
|
||||
*
|
||||
* This funtion will clear the call list invoking the destroy
|
||||
* function for each one.
|
||||
*/
|
||||
void
|
||||
sip_calls_clear();
|
||||
sip_parse_msg_media(sip_msg_t *msg, const u_char *payload);
|
||||
|
||||
/**
|
||||
* @brief Set Capture Matching expression
|
||||
@ -515,57 +232,6 @@ sip_set_match_expression(const char *expr, int insensitive, int invert);
|
||||
int
|
||||
sip_check_match_expression(const char *payload);
|
||||
|
||||
/**
|
||||
* @brief Sets the attribute value for a given call
|
||||
*
|
||||
* This function acts as wrapper of sip call attributes
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @param id Attribute id
|
||||
* @param value Attribute value
|
||||
*/
|
||||
void
|
||||
call_set_attribute(struct sip_call *call, enum sip_attr_id id, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Return a call attribute value
|
||||
*
|
||||
* This function will be used to avoid accessing call structure
|
||||
* fields directly.
|
||||
* @todo Code a proper way to store this information
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @param id Attribute id
|
||||
* @return Attribute value or NULL if not found
|
||||
*/
|
||||
const char *
|
||||
call_get_attribute(struct sip_call *call, enum sip_attr_id id);
|
||||
|
||||
/**
|
||||
* @brief Sets the attribute value for a given message
|
||||
*
|
||||
* This function acts as wrapper of sip message attributes
|
||||
*
|
||||
* @param msg SIP message structure
|
||||
* @param id Attribute id
|
||||
* @param value Attribute value
|
||||
*/
|
||||
void
|
||||
msg_set_attribute(struct sip_msg *msg, enum sip_attr_id id, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Return a message attribute value
|
||||
*
|
||||
* This function will be used to avoid accessing call structure
|
||||
* fields directly.
|
||||
*
|
||||
* @param msg SIP message structure
|
||||
* @param id Attribute id
|
||||
* @return Attribute value or NULL if not found
|
||||
*/
|
||||
const char *
|
||||
msg_get_attribute(struct sip_msg *msg, enum sip_attr_id id);
|
||||
|
||||
/**
|
||||
* @brief Check if this msg is affected by filters
|
||||
*
|
||||
@ -597,6 +263,19 @@ sip_method_str(enum sip_methods method);
|
||||
int
|
||||
sip_method_from_str(const char *method);
|
||||
|
||||
/**
|
||||
* @brief Get summary of message header data
|
||||
*
|
||||
* For raw prints, it's handy to have the ngrep header style message
|
||||
* data.
|
||||
*
|
||||
* @param msg SIP message
|
||||
* @param out pointer to allocated memory to contain the header output
|
||||
* @returns pointer to out
|
||||
*/
|
||||
char *
|
||||
sip_get_msg_header(sip_msg_t *msg, char *out);
|
||||
|
||||
/**
|
||||
* @brief Return address formatted depending on active settings
|
||||
*
|
||||
|
213
src/sip_call.c
Normal file
213
src/sip_call.c
Normal file
@ -0,0 +1,213 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP Messages flow viewer
|
||||
**
|
||||
** Copyright (C) 2015 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 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 sip_call.c
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Functions to manage SIP call data
|
||||
*
|
||||
* This file contains the functions and structure to manage SIP call data
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sip_call.h"
|
||||
|
||||
sip_call_t *
|
||||
call_create(char *callid)
|
||||
{
|
||||
int index;
|
||||
sip_call_t *call;
|
||||
|
||||
// Initialize a new call structure
|
||||
if (!(call = malloc(sizeof(sip_call_t))))
|
||||
return NULL;
|
||||
memset(call, 0, sizeof(sip_call_t));
|
||||
|
||||
// Store Call-Id
|
||||
call->callid = strdup(callid);
|
||||
|
||||
// Create a vector to store call messages
|
||||
call->msgs = vector_create(10, 5);
|
||||
vector_set_destroyer(call->msgs, msg_destroyer);
|
||||
|
||||
// Create a vector to store call attributes
|
||||
call->attrs = vector_create(1, 1);
|
||||
vector_set_destroyer(call->attrs, sip_attr_destroyer);
|
||||
|
||||
// Create a vector to store RTP streams
|
||||
call->streams = vector_create(0, 2);
|
||||
vector_set_destroyer(call->streams, vector_generic_destroyer);
|
||||
|
||||
// Initialize call filter status
|
||||
call->filtered = -1;
|
||||
return call;
|
||||
}
|
||||
|
||||
void
|
||||
call_destroy(sip_call_t *call)
|
||||
{
|
||||
// Remove all call messages
|
||||
vector_destroy(call->msgs);
|
||||
// Remove all call streams
|
||||
vector_destroy(call->streams);
|
||||
// Remove all call attributes
|
||||
vector_destroy(call->attrs);
|
||||
// Free it!
|
||||
free(call->callid);
|
||||
free(call);
|
||||
}
|
||||
|
||||
void
|
||||
call_destroyer(void *call)
|
||||
{
|
||||
call_destroy((sip_call_t*)call);
|
||||
}
|
||||
|
||||
void
|
||||
call_add_message(sip_call_t *call, sip_msg_t *msg)
|
||||
{
|
||||
// Set the message owner
|
||||
msg->call = call;
|
||||
// Put this msg at the end of the msg list
|
||||
vector_append(call->msgs, msg);
|
||||
// Store message count
|
||||
call_set_attribute(call, SIP_ATTR_MSGCNT, "%d", vector_count(call->msgs));
|
||||
}
|
||||
|
||||
int
|
||||
call_msg_count(sip_call_t *call)
|
||||
{
|
||||
return vector_count(call->msgs);
|
||||
}
|
||||
|
||||
int
|
||||
call_is_active(void *item)
|
||||
{
|
||||
// TODO
|
||||
sip_call_t *call = (sip_call_t *)item;
|
||||
return call->active;
|
||||
}
|
||||
|
||||
void
|
||||
call_update_state(sip_call_t *call, sip_msg_t *msg)
|
||||
{
|
||||
const char *callstate;
|
||||
char dur[20];
|
||||
int reqresp;
|
||||
sip_msg_t *first;
|
||||
|
||||
// Sanity check
|
||||
if (!call || !call->msgs || !msg)
|
||||
return;
|
||||
|
||||
// Get the first message in the call
|
||||
first = vector_first(call->msgs);
|
||||
|
||||
// Check First message of Call has INVITE method
|
||||
if (first->reqresp != SIP_METHOD_INVITE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get current message Method / Response Code
|
||||
reqresp = msg->reqresp;
|
||||
|
||||
// If this message is actually a call, get its current state
|
||||
if ((callstate = call_get_attribute(call, SIP_ATTR_CALLSTATE))) {
|
||||
if (!strcmp(callstate, SIP_CALLSTATE_CALLSETUP)) {
|
||||
if (reqresp == 200) {
|
||||
// Alice and Bob are talking
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_INCALL);
|
||||
// Store the timestap where call has started
|
||||
call->active = 1;
|
||||
call->cstart_msg = msg;
|
||||
} else if (reqresp == SIP_METHOD_CANCEL) {
|
||||
// Alice is not in the mood
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CANCELLED);
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, timeval_to_duration(msg_get_time(first), msg_get_time(msg), dur));
|
||||
call->active = 0;
|
||||
} else if (reqresp > 400) {
|
||||
// Bob is not in the mood
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_REJECTED);
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, timeval_to_duration(msg_get_time(first), msg_get_time(msg), dur));
|
||||
call->active = 0;
|
||||
}
|
||||
} else if (!strcmp(callstate, SIP_CALLSTATE_INCALL)) {
|
||||
if (reqresp == SIP_METHOD_BYE) {
|
||||
// Thanks for all the fish!
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_COMPLETED);
|
||||
// Store Conversation duration
|
||||
call_set_attribute(call, SIP_ATTR_CONVDUR,
|
||||
timeval_to_duration(msg_get_time(call->cstart_msg), msg_get_time(msg), dur));
|
||||
call->active = 0;
|
||||
}
|
||||
} else if (reqresp == SIP_METHOD_INVITE && strcmp(callstate, SIP_CALLSTATE_INCALL)) {
|
||||
// Call is being setup (after proper authentication)
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CALLSETUP);
|
||||
call->active = 1;
|
||||
} else {
|
||||
// Store total call duration
|
||||
call_set_attribute(call, SIP_ATTR_TOTALDUR, timeval_to_duration(msg_get_time(first), msg_get_time(msg), dur));
|
||||
}
|
||||
} else {
|
||||
// This is actually a call
|
||||
if (reqresp == SIP_METHOD_INVITE) {
|
||||
call_set_attribute(call, SIP_ATTR_CALLSTATE, SIP_CALLSTATE_CALLSETUP);
|
||||
call->active = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
call_set_attribute(sip_call_t *call, enum sip_attr_id id, const char *fmt, ...)
|
||||
{
|
||||
char value[512];
|
||||
|
||||
// Get the actual value for the attribute
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(value, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
sip_attr_set(call->attrs, id, value);
|
||||
}
|
||||
|
||||
const char *
|
||||
call_get_attribute(sip_call_t *call, enum sip_attr_id id)
|
||||
{
|
||||
if (!call)
|
||||
return NULL;
|
||||
|
||||
switch (id) {
|
||||
case SIP_ATTR_CALLINDEX:
|
||||
case SIP_ATTR_MSGCNT:
|
||||
case SIP_ATTR_CALLSTATE:
|
||||
case SIP_ATTR_CONVDUR:
|
||||
case SIP_ATTR_TOTALDUR:
|
||||
return sip_attr_get_value(call->attrs, id);
|
||||
default:
|
||||
return msg_get_attribute(vector_first(call->msgs), id);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
180
src/sip_call.h
Normal file
180
src/sip_call.h
Normal file
@ -0,0 +1,180 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP Messages flow viewer
|
||||
**
|
||||
** Copyright (C) 2015 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 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 sip_call.h
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Functions to manage sip calls
|
||||
*
|
||||
*/
|
||||
#ifndef __SNGREP_SIP_CALL_H
|
||||
#define __SNGREP_SIP_CALL_H
|
||||
|
||||
#include "config.h"
|
||||
#include "vector.h"
|
||||
#include "sip_msg.h"
|
||||
#include "sip_attr.h"
|
||||
|
||||
//! SIP Call State
|
||||
#define SIP_CALLSTATE_CALLSETUP "CALL SETUP"
|
||||
#define SIP_CALLSTATE_INCALL "IN CALL"
|
||||
#define SIP_CALLSTATE_CANCELLED "CANCELLED"
|
||||
#define SIP_CALLSTATE_REJECTED "REJECTED"
|
||||
#define SIP_CALLSTATE_COMPLETED "COMPLETED"
|
||||
|
||||
//! Shorter declaration of sip_call structure
|
||||
typedef struct sip_call sip_call_t;
|
||||
|
||||
/**
|
||||
* @brief Contains all information of a call and its messages
|
||||
*
|
||||
* This structure acts as header of messages list of the same
|
||||
* callid (considered a dialog). It contains some replicated
|
||||
* data from its messages to speed up searches.
|
||||
*/
|
||||
struct sip_call {
|
||||
//! Call Call-Id
|
||||
char *callid;
|
||||
//! Flag this call as filtered so won't be displayed
|
||||
int filtered;
|
||||
//! For call dialogs, mark if call has not yet finished
|
||||
int active;
|
||||
//! List of messages of this call (sip_msg_t*)
|
||||
vector_t *msgs;
|
||||
//! Message when conversation started
|
||||
sip_msg_t *cstart_msg;
|
||||
//! Call attribute list
|
||||
vector_t *attrs;
|
||||
//! RTP streams for this call (rtp_stream_t *)
|
||||
vector_t *streams;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new call with the given callid (Minimum required data)
|
||||
*
|
||||
* Allocated required memory for a new SIP Call. The call acts as
|
||||
* header structure to all the messages with the same callid.
|
||||
*
|
||||
* @param callid Call-ID Header value
|
||||
* @return pointer to the sip_call created
|
||||
*/
|
||||
sip_call_t *
|
||||
call_create(char *callid);
|
||||
|
||||
/**
|
||||
* @brief Free all related memory from a call and remove from call list
|
||||
*
|
||||
* Deallocate memory of an existing SIP Call.
|
||||
* This will also remove all messages, calling sip_msg_destroy for each
|
||||
* one.
|
||||
*
|
||||
* @param call Call to be destroyed
|
||||
*/
|
||||
void
|
||||
call_destroy(sip_call_t *call);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Wrapper around Message destroyer to clear call vectors
|
||||
*/
|
||||
void
|
||||
call_destroyer(void *call);
|
||||
|
||||
/**
|
||||
* @brief Append message to the call's message list
|
||||
*
|
||||
* Creates a relation between this call and the message, appending it
|
||||
* to the end of the message list and setting the message owner.
|
||||
*
|
||||
* @param call pointer to the call owner of the message
|
||||
* @param msg SIP message structure
|
||||
*/
|
||||
void
|
||||
call_add_message(sip_call_t *call, sip_msg_t *msg);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Getter for call messages linked list size
|
||||
*
|
||||
* Return the number of messages stored in this call. All messages
|
||||
* share the same Call-ID
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @return how many messages are in the call
|
||||
*/
|
||||
int
|
||||
call_msg_count(sip_call_t *call);
|
||||
|
||||
/**
|
||||
* @brief Finds the other leg of this call.
|
||||
*
|
||||
* If this call has a X-CID or X-Call-ID header, that call will be
|
||||
* find and returned. Otherwise, a call with X-CID or X-Call-ID header
|
||||
* matching the given call's Call-ID will be find or returned.
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @return The other call structure or NULL if none found
|
||||
*/
|
||||
sip_call_t *
|
||||
call_get_xcall(sip_call_t *call);
|
||||
|
||||
|
||||
int
|
||||
call_is_active(void *item);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Update Call State attribute with its last parsed message
|
||||
*
|
||||
* @param call Call structure to be updated
|
||||
* @param msg Last received message of this call
|
||||
*/
|
||||
void
|
||||
call_update_state(sip_call_t *call, sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Sets the attribute value for a given call
|
||||
*
|
||||
* This function acts as wrapper of sip call attributes
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @param id Attribute id
|
||||
* @param value Attribute value
|
||||
*/
|
||||
void
|
||||
call_set_attribute(struct sip_call *call, enum sip_attr_id id, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Return a call attribute value
|
||||
*
|
||||
* This function will be used to avoid accessing call structure
|
||||
* fields directly.
|
||||
* @todo Code a proper way to store this information
|
||||
*
|
||||
* @param call SIP call structure
|
||||
* @param id Attribute id
|
||||
* @return Attribute value or NULL if not found
|
||||
*/
|
||||
const char *
|
||||
call_get_attribute(struct sip_call *call, enum sip_attr_id id);
|
||||
|
||||
#endif /* __SNGREP_SIP_CALL_H */
|
160
src/sip_msg.c
Normal file
160
src/sip_msg.c
Normal file
@ -0,0 +1,160 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP Messages flow viewer
|
||||
**
|
||||
** Copyright (C) 2015 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 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 sip_msg.c
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Functions to manage SIP call data
|
||||
*
|
||||
* This file contains the functions and structure to manage SIP message data
|
||||
*
|
||||
*/
|
||||
#include "sip_msg.h"
|
||||
|
||||
sip_msg_t *
|
||||
msg_create(const char *payload)
|
||||
{
|
||||
sip_msg_t *msg;
|
||||
|
||||
if (!(msg = malloc(sizeof(sip_msg_t))))
|
||||
return NULL;
|
||||
memset(msg, 0, sizeof(sip_msg_t));
|
||||
msg->color = 0;
|
||||
// Create a vector to store attributes
|
||||
msg->attrs = vector_create(4, 10);
|
||||
vector_set_destroyer(msg->attrs, sip_attr_destroyer);
|
||||
// Create a vector to store sdp
|
||||
msg->medias = vector_create(0, 2);
|
||||
vector_set_destroyer(msg->medias, vector_generic_destroyer);
|
||||
// Create a vector to store packets
|
||||
msg->packets = vector_create(1, 1);
|
||||
vector_set_destroyer(msg->packets, capture_packet_destroyer);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void
|
||||
msg_destroy(sip_msg_t *msg)
|
||||
{
|
||||
// Free message attribute list
|
||||
vector_destroy(msg->attrs);
|
||||
// Free message SDP media
|
||||
vector_destroy(msg->medias);
|
||||
// Free message packets
|
||||
vector_destroy(msg->packets);
|
||||
// Free all memory
|
||||
free(msg);
|
||||
}
|
||||
|
||||
void
|
||||
msg_destroyer(void *msg)
|
||||
{
|
||||
msg_destroy((sip_msg_t *)msg);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
msg_media_count(sip_msg_t *msg)
|
||||
{
|
||||
return vector_count(msg->medias);
|
||||
}
|
||||
|
||||
int
|
||||
msg_has_sdp(void *item)
|
||||
{
|
||||
// TODO
|
||||
sip_msg_t *msg = (sip_msg_t *)item;
|
||||
return vector_count(msg->medias) ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
msg_is_retrans(sip_msg_t *msg)
|
||||
{
|
||||
return 0;
|
||||
// sip_msg_t *prev = NULL;
|
||||
// vector_iter_t it;
|
||||
//
|
||||
// // Get previous message in call
|
||||
// it = vector_iterator(msg->call->msgs);
|
||||
// vector_iterator_set_current(&it, vector_index(msg->call->msgs, msg));
|
||||
// prev = vector_iterator_prev(&it);
|
||||
//
|
||||
// return (prev && !strcasecmp(msg_get_payload(msg), msg_get_payload(prev)));
|
||||
}
|
||||
|
||||
int
|
||||
msg_is_request(sip_msg_t *msg)
|
||||
{
|
||||
return msg->reqresp < SIP_METHOD_SENTINEL;
|
||||
}
|
||||
|
||||
void
|
||||
msg_add_packet(sip_msg_t *msg, capture_packet_t *packet)
|
||||
{
|
||||
vector_append(msg->packets, packet);
|
||||
}
|
||||
|
||||
const char *
|
||||
msg_get_payload(sip_msg_t *msg)
|
||||
{
|
||||
// Return Message payload pointer
|
||||
if (msg->payload)
|
||||
return (const char *)msg->payload;
|
||||
|
||||
// Calculate message payload pointer
|
||||
// TODO Multi packet support
|
||||
capture_packet_t *packet = vector_first(msg->packets);
|
||||
packet->data[packet->size - 1] = '\0';
|
||||
msg->payload = packet->data + packet->payload_start;
|
||||
return (const char *) msg->payload;
|
||||
}
|
||||
|
||||
struct timeval
|
||||
msg_get_time(sip_msg_t *msg)
|
||||
{
|
||||
struct timeval t = { };
|
||||
capture_packet_t *packet;
|
||||
|
||||
if (msg && (packet = vector_first(msg->packets)))
|
||||
return packet->header->ts;
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
msg_set_attribute(sip_msg_t *msg, enum sip_attr_id id, const char *fmt, ...)
|
||||
{
|
||||
char value[512];
|
||||
|
||||
// Get the actual value for the attribute
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf(value, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
sip_attr_set(msg->attrs, id, value);
|
||||
}
|
||||
|
||||
const char *
|
||||
msg_get_attribute(sip_msg_t *msg, enum sip_attr_id id)
|
||||
{
|
||||
return sip_attr_get_value(msg->attrs, id);
|
||||
}
|
||||
|
223
src/sip_msg.h
Normal file
223
src/sip_msg.h
Normal file
@ -0,0 +1,223 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** sngrep - SIP Messages flow viewer
|
||||
**
|
||||
** Copyright (C) 2015 Ivan Alonso (Kaian)
|
||||
** Copyright (C) 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 sip_msg.h
|
||||
* @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
|
||||
*
|
||||
* @brief Functions to manage sip messages
|
||||
*
|
||||
*/
|
||||
#ifndef __SNGREP_SIP_MSG_H
|
||||
#define __SNGREP_SIP_MSG_H
|
||||
|
||||
#include "config.h"
|
||||
#include "vector.h"
|
||||
#include "media.h"
|
||||
#include "rtp.h"
|
||||
#include "sip_attr.h"
|
||||
#include "util.h"
|
||||
|
||||
//! Shorter declaration of sip_msg structure
|
||||
typedef struct sip_msg sip_msg_t;
|
||||
|
||||
//! SIP Methods
|
||||
enum sip_methods {
|
||||
SIP_METHOD_REGISTER = 1,
|
||||
SIP_METHOD_INVITE,
|
||||
SIP_METHOD_SUBSCRIBE,
|
||||
SIP_METHOD_NOTIFY,
|
||||
SIP_METHOD_OPTIONS,
|
||||
SIP_METHOD_PUBLISH,
|
||||
SIP_METHOD_MESSAGE,
|
||||
SIP_METHOD_CANCEL,
|
||||
SIP_METHOD_BYE,
|
||||
SIP_METHOD_ACK,
|
||||
SIP_METHOD_PRACK,
|
||||
SIP_METHOD_INFO,
|
||||
SIP_METHOD_REFER,
|
||||
SIP_METHOD_UPDATE,
|
||||
SIP_METHOD_SENTINEL,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Information of a single message withing a dialog.
|
||||
*
|
||||
* Most of the data is just stored to be displayed in the UI so
|
||||
* the formats may be no the best, but the simplest for this
|
||||
* purpose. It also works as a linked lists of messages in a
|
||||
* call.
|
||||
*/
|
||||
struct sip_call;
|
||||
struct sip_msg {
|
||||
//! Temporal payload data before being parsed
|
||||
u_char *payload;
|
||||
//! Color for this message (in color.cseq mode)
|
||||
int color;
|
||||
//! Request Method or Response Code @see sip_methods
|
||||
int reqresp;
|
||||
//! Message Cseq
|
||||
int cseq;
|
||||
//! Message attribute list
|
||||
vector_t *attrs;
|
||||
//! SDP payload information (sdp_media_t *)
|
||||
vector_t *medias;
|
||||
//! Captured packets for this message (capture_packet_t *)
|
||||
vector_t *packets;
|
||||
//! Message owner
|
||||
struct sip_call *call;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new message from the readed header and payload
|
||||
*
|
||||
* Allocate required memory for a new SIP message. This function
|
||||
* will only store the given information, but wont parse it until
|
||||
* needed.
|
||||
*
|
||||
* @param payload Raw payload content
|
||||
* @return a new allocated message
|
||||
*/
|
||||
sip_msg_t *
|
||||
msg_create(const char *payload);
|
||||
|
||||
/**
|
||||
* @brief Destroy a SIP message and free its memory
|
||||
*
|
||||
* Deallocate memory of an existing SIP Message.
|
||||
* This function will remove the message from the call and the
|
||||
* passed pointer will be NULL.
|
||||
*
|
||||
* @param nsg SIP message to be deleted
|
||||
*/
|
||||
void
|
||||
msg_destroy(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Wrapper around Message destroyer to clear msg vectors
|
||||
*/
|
||||
void
|
||||
msg_destroyer(void *msg);
|
||||
|
||||
/**
|
||||
* @brief Getter for media of given messages
|
||||
*
|
||||
* Return the number of media structures of given msg
|
||||
* stored in this call.
|
||||
*
|
||||
* @param msg SIP message structure
|
||||
* @return how many media structures are in the msg
|
||||
*/
|
||||
int
|
||||
msg_media_count(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Check if given message has spd content
|
||||
*/
|
||||
int
|
||||
msg_has_sdp(void *item);
|
||||
|
||||
/**
|
||||
* @brief Add a media structure to a msg
|
||||
*
|
||||
* @param cmsg SIP Message to be updated
|
||||
* @param media Media structure to be added
|
||||
*/
|
||||
void
|
||||
msg_add_media(sip_msg_t *msg, sdp_media_t *media);
|
||||
|
||||
/**
|
||||
* @brief Check if a package is a retransmission
|
||||
*
|
||||
* This function will compare its payload with the previous message
|
||||
* in the dialog, to check if it has the same content.
|
||||
*
|
||||
* @param msg SIP message that will be checked
|
||||
* @return 1 if the previous message is equal to msg, 0 otherwise
|
||||
*/
|
||||
int
|
||||
msg_is_retrans(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Check if a message is a Request or response
|
||||
*
|
||||
* @param msg SIP message that will be checked
|
||||
* @return 1 if the message is a request, 0 if a response
|
||||
*/
|
||||
int
|
||||
msg_is_request(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Add a new packet for given message
|
||||
*
|
||||
* A SIP message can have multiple fragmented packets to
|
||||
* store its payload;
|
||||
*
|
||||
* @param msg SIP message that will store this packet
|
||||
* @param packet Captured packet information
|
||||
*/
|
||||
void
|
||||
msg_add_packet(sip_msg_t *msg, capture_packet_t *packet);
|
||||
|
||||
/**
|
||||
* @brief Get SIP Message payload
|
||||
*/
|
||||
const char *
|
||||
msg_get_payload(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Get Time of message from packet header
|
||||
*
|
||||
* @param msg SIP message
|
||||
* @return timeval structure with message first packet time
|
||||
*/
|
||||
struct timeval
|
||||
msg_get_time(sip_msg_t *msg);
|
||||
|
||||
/**
|
||||
* @brief Sets the attribute value for a given message
|
||||
*
|
||||
* This function acts as wrapper of sip message attributes
|
||||
*
|
||||
* @param msg SIP message structure
|
||||
* @param id Attribute id
|
||||
* @param value Attribute value
|
||||
*/
|
||||
void
|
||||
msg_set_attribute(struct sip_msg *msg, enum sip_attr_id id, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Return a message attribute value
|
||||
*
|
||||
* This function will be used to avoid accessing call structure
|
||||
* fields directly.
|
||||
*
|
||||
* @param msg SIP message structure
|
||||
* @param id Attribute id
|
||||
* @return Attribute value or NULL if not found
|
||||
*/
|
||||
const char *
|
||||
msg_get_attribute(struct sip_msg *msg, enum sip_attr_id id);
|
||||
|
||||
|
||||
#endif /* __SNGREP_SIP_MSG_H */
|
@ -187,7 +187,7 @@ call_raw_print_msg(PANEL *panel, sip_msg_t *msg)
|
||||
|
||||
// Print msg header
|
||||
wattron(pad, A_BOLD);
|
||||
mvwprintw(pad, info->padline++, 0, "%s", msg_get_header(msg, header));
|
||||
mvwprintw(pad, info->padline++, 0, "%s", sip_get_msg_header(msg, header));
|
||||
wattroff(pad, A_BOLD);
|
||||
|
||||
// Print msg payload
|
||||
|
@ -196,7 +196,7 @@ msg_diff_draw_message(WINDOW *win, sip_msg_t *msg, char *highlight)
|
||||
getmaxyx(win, height, width);
|
||||
|
||||
wattron(win, A_BOLD);
|
||||
mvwprintw(win, 0, 0, msg_get_header(msg, header));
|
||||
mvwprintw(win, 0, 0, sip_get_msg_header(msg, header));
|
||||
wattroff(win, A_BOLD);
|
||||
|
||||
// Print msg payload
|
||||
|
Loading…
Reference in New Issue
Block a user