Refactoring: Move call and message functions

This commit is contained in:
Kaian 2015-07-02 14:39:40 +02:00
parent df175cc5ba
commit b71138aeed
11 changed files with 855 additions and 705 deletions

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -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
View 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
View 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
View 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
View 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 */

View File

@ -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

View File

@ -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