You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules/sca/sca_util.c

380 lines
8.0 KiB

/*
* $Id$
*
* Copyright (C) 2012 Andrew Mortensen
*
* This file is part of the sca module for sip-router, a free SIP server.
*
* The sca module 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 2 of the License, or
* (at your option) any later version
*
* The sca module 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*/
#include "sca_common.h"
#include <assert.h>
#include "sca_util.h"
#include "../../parser/sdp/sdp.h"
int
sca_get_msg_method( sip_msg_t *msg )
{
assert( msg != NULL );
if ( msg->first_line.type == SIP_REQUEST ) {
return( msg->REQ_METHOD );
}
return( sca_get_msg_cseq_method( msg ));
}
int
sca_get_msg_contact_uri( sip_msg_t *msg, str *contact_uri )
{
contact_body_t *contact_body;
assert( msg != NULL );
assert( contact_uri != NULL );
if ( SCA_HEADER_EMPTY( msg->contact )) {
LM_DBG( "Empty Contact header" );
contact_uri->s = NULL;
contact_uri->len = 0;
return( 0 );
}
if ( parse_contact( msg->contact ) < 0 ) {
LM_ERR( "Failed to parse Contact header: %.*s",
STR_FMT( &msg->contact->body ));
return( -1 );
}
if (( contact_body = (contact_body_t *)msg->contact->parsed ) == NULL ) {
LM_ERR( "Invalid Contact header: %.*s", STR_FMT( &msg->contact->body ));
return( -1 );
}
if ( contact_body->star ) {
LM_ERR( "Invalid Contact header: SCA Contact must not be \"*\"" );
return( -1 );
}
if ( contact_body->contacts == NULL ) {
LM_ERR( "Invalid Contact header: parser found no contacts" );
return( -1 );
}
if ( contact_body->contacts->next ) {
LM_ERR( "Invalid Contact header: Contact may only contain one URI" );
return( -1 );
}
contact_uri->s = contact_body->contacts->uri.s;
contact_uri->len = contact_body->contacts->uri.len;
return( 1 );
}
int
sca_get_msg_cseq_number( sip_msg_t *msg )
{
int cseq;
assert( msg != NULL );
if ( SCA_HEADER_EMPTY( msg->cseq )) {
LM_ERR( "Empty Cseq header" );
return( -1 );
}
if ( str2int( &(get_cseq( msg )->number), (unsigned int *)&cseq ) != 0 ) {
LM_ERR( "Bad Cseq header: %.*s", STR_FMT( &msg->cseq->body ));
return( -1 );
}
return( cseq );
}
/* assumes cseq header in msg is already parsed */
int
sca_get_msg_cseq_method( sip_msg_t *msg )
{
assert( msg != NULL );
if ( SCA_HEADER_EMPTY( msg->cseq )) {
LM_ERR( "Empty Cseq header" );
return( -1 );
}
return( get_cseq( msg )->method_id );
}
int
sca_get_msg_from_header( sip_msg_t *msg, struct to_body **from )
{
struct to_body *f;
assert( msg != NULL );
assert( from != NULL );
if ( SCA_HEADER_EMPTY( msg->from )) {
LM_ERR( "Empty From header" );
return( -1 );
}
if ( parse_from_header( msg ) < 0 ) {
LM_ERR( "Bad From header" );
return( -1 );
}
f = get_from( msg );
if ( SCA_STR_EMPTY( &f->tag_value )) {
LM_ERR( "Bad From header: no tag parameter" );
return( -1 );
}
/* ensure the URI is parsed for future use */
if ( parse_uri( f->uri.s, f->uri.len, GET_FROM_PURI( msg )) < 0 ) {
LM_ERR( "Failed to parse From URI %.*s", STR_FMT( &f->uri ));
return( -1 );
}
*from = f;
return( 0 );
}
int
sca_get_msg_to_header( sip_msg_t *msg, struct to_body **to )
{
struct to_body parsed_to;
struct to_body *t = NULL;
assert( msg != NULL );
assert( to != NULL );
if ( SCA_HEADER_EMPTY( msg->to )) {
LM_ERR( "Empty To header" );
return( -1 );
}
t = get_to( msg );
if ( t == NULL ) {
parse_to( msg->to->body.s,
msg->to->body.s + msg->to->body.len + 1, /* end of buffer */
&parsed_to );
if ( parsed_to.error != PARSE_OK ) {
LM_ERR( "Bad To header" );
return( -1 );
}
t = &parsed_to;
}
/* ensure the URI is parsed for future use */
if ( parse_uri( t->uri.s, t->uri.len, GET_TO_PURI( msg )) < 0 ) {
LM_ERR( "Failed to parse To URI %.*s", STR_FMT( &t->uri ));
return( -1 );
}
*to = t;
return( 0 );
}
/* count characters requiring escape as defined by escape_common */
int
sca_uri_display_escapes_count( str *display )
{
int c = 0;
int i;
if ( SCA_STR_EMPTY( display )) {
return( 0 );
}
for ( i = 0; i < display->len; i++ ) {
switch ( display->s[ i ] ) {
case '\'':
case '"':
case '\\':
case '\0':
c++;
default:
break;
}
}
return( c );
}
int
sca_uri_extract_aor( str *uri, str *aor )
{
char *semi;
assert( aor != NULL );
if ( uri == NULL ) {
aor->s = NULL;
aor->len = 0;
return( -1 );
}
aor->s = uri->s;
semi = memchr( uri->s, ';', uri->len );
if ( semi != NULL ) {
aor->len = semi - uri->s;
} else {
aor->len = uri->len;
}
return( 0 );
}
int
sca_uri_build_aor( str *aor, int maxlen, str *contact_uri, str *domain_uri )
{
char *p;
char *dp;
int len;
assert( aor != NULL );
assert( contact_uri != NULL );
assert( domain_uri != NULL );
if ( contact_uri->len + domain_uri->len >= maxlen ) {
return( -1 );
}
p = memchr( contact_uri->s, '@', contact_uri->len );
if ( p == NULL ) {
/* no username, by definition can't be an SCA line */
aor->s = NULL;
aor->len = 0;
return( 0 );
}
dp = memchr( domain_uri->s, '@', domain_uri->len );
if ( dp == NULL ) {
/* may be nameless URI */
dp = memchr( domain_uri->s, ':', domain_uri->len );
if ( dp == NULL ) {
/* bad domain URI */
return( -1 );
}
}
dp++;
len = p - contact_uri->s;
memcpy( aor->s, contact_uri->s, len );
aor->s[ len ] = '@';
len += 1;
aor->len = len;
len = domain_uri->len - ( dp - domain_uri->s );
memcpy( aor->s + aor->len, dp, len );
aor->len += len;
return( aor->len );
}
int
sca_aor_create_from_info( str *aor, uri_type type, str *user, str *domain,
str *port )
{
str scheme = STR_NULL;
int len = 0;
assert( aor != NULL );
uri_type_to_str( type, &scheme );
/* +1 for ':', +1 for '@' */
len = scheme.len + 1 + user->len + 1 + domain->len;
if ( !SCA_STR_EMPTY( port )) {
/* +1 for ':' */
len += 1 + port->len;
}
aor->s = (char *)pkg_malloc( len );
if ( aor->s == NULL ) {
LM_ERR( "sca_aor_create_from_info: pkg_malloc %d bytes failed", len );
return( -1 );
}
len = 0;
SCA_STR_COPY( aor, &scheme );
len += scheme.len;
*(aor->s + len) = ':';
aor->len++;
len++;
SCA_STR_APPEND( aor, user );
len += user->len;
*(aor->s + len) = '@';
aor->len++;
len++;
SCA_STR_APPEND( aor, domain );
len += domain->len;
if ( !SCA_STR_EMPTY( port )) {
*(aor->s + len) = ':';
len += 1;
SCA_STR_APPEND( aor, port );
len += port->len;
}
return( aor->len );
}
/* XXX this considers any held stream to mean the call is on hold. correct? */
int
sca_call_is_held( sip_msg_t *msg )
{
sdp_session_cell_t *session;
sdp_stream_cell_t *stream;
int n_sess;
int n_str;
int is_held = 0;
int rc;
rc = parse_sdp( msg );
if ( rc < 0 ) {
LM_ERR( "sca_call_is_held: parse_sdp body failed" );
return( 0 );
} else if ( rc > 0 ) {
LM_DBG( "sca_call_is_held: parse_sdp returned %d, no SDP body", rc );
return( 0 );
}
/* Cf. modules_k/textops's exported is_audio_on_hold */
for ( n_sess = 0, session = get_sdp_session( msg, n_sess );
session != NULL;
n_sess++, session = get_sdp_session( msg, n_sess )) {
for ( n_str = 0, stream = get_sdp_stream( msg, n_sess, n_str );
stream != NULL;
n_str++, stream = get_sdp_stream( msg, n_sess, n_str )) {
if ( stream->is_on_hold ) {
is_held = 1;
goto done;
}
}
}
done:
return( is_held );
}