added plugin_codecfilter.c

This commit is contained in:
Thomas Ries 2015-01-21 22:19:56 +00:00
parent 9282ca41cb
commit b871356854
2 changed files with 319 additions and 0 deletions

View File

@ -37,6 +37,7 @@ pkglib_LTLIBRARIES = plugin_demo.la \
plugin_stun.la \
plugin_prefix.la \
plugin_regex.la \
plugin_codecfilter.la \
plugin_stripheader.la
DLOPENPLUGINS = -dlopen plugin_demo.la \
-dlopen plugin_shortdial.la \
@ -46,6 +47,7 @@ DLOPENPLUGINS = -dlopen plugin_demo.la \
-dlopen plugin_stun.la \
-dlopen plugin_prefix.la \
-dlopen plugin_regex.la \
-dlopen plugin_codecfilter.la \
-dlopen plugin_stripheader.la
#
plugin_demo_la_SOURCES = plugin_demo.c
@ -72,6 +74,9 @@ plugin_prefix_la_LDFLAGS = -module -avoid-version -shrext '.so'
plugin_regex_la_SOURCES = plugin_regex.c
plugin_regex_la_LDFLAGS = -module -avoid-version -shrext '.so'
#
plugin_codecfilter_la_SOURCES = plugin_codecfilter.c
plugin_codecfilter_la_LDFLAGS = -module -avoid-version -shrext '.so'
#
plugin_stripheader_la_SOURCES = plugin_stripheader.c
plugin_stripheader_la_LDFLAGS = -module -avoid-version -shrext '.so'

314
src/plugin_codecfilter.c Normal file
View File

@ -0,0 +1,314 @@
/*
Copyright (C) 2015 Thomas Ries <tries@gmx.net>
This file is part of Siproxd.
Siproxd 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.
Siproxd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warrantry 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 Siproxd; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* must be defined before including <plugin.h> */
#define PLUGIN_NAME plugin_codecfilter
#include "config.h"
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <osipparser2/osip_parser.h>
#include <osipparser2/sdp_message.h>
#include "siproxd.h"
#include "plugins.h"
#include "log.h"
static char const ident[]="$Id$";
/* Plug-in identification */
static char name[]="plugin_codecfilter";
static char desc[]="Allows filtering the codec list in SDP";
/* global configuration storage - required for config file location */
extern struct siproxd_config configuration;
/* plugin configuration storage */
static struct plugin_config {
char *codec;
stringa_t codec_whitelist;
stringa_t codec_blacklist;
} plugin_cfg;
/* Instructions for config parser */
static cfgopts_t plugin_cfg_opts[] = {
{ "plugin_codecfilter_whitelist", TYP_STRINGA, &plugin_cfg.codec_whitelist, {0, NULL} },
{ "plugin_codecfilter_blacklist", TYP_STRINGA, &plugin_cfg.codec_blacklist, {0, NULL} },
{0, 0, 0}
};
#if 0
/* Prototypes */
static int sip_filter_sdp(sip_ticket_t *ticket);
#endif
/*
* Initialization.
* Called once suring siproxd startup.
*/
int PLUGIN_INIT(plugin_def_t *plugin_def) {
/* API version number of siproxd that this plugin is built against.
* This constant will change whenever changes to the API are made
* that require adaptions in the plugin. */
plugin_def->api_version=SIPROXD_API_VERSION;
/* Name and descriptive text of the plugin */
plugin_def->name=name;
plugin_def->desc=desc;
/* Execution mask - during what stages of SIP processing shall
* the plugin be called. */
plugin_def->exe_mask=PLUGIN_PRE_PROXY;
/* read the config file */
if (read_config(configuration.configfile,
configuration.config_search,
plugin_cfg_opts, name) == STS_FAILURE) {
ERROR("Plugin '%s': could not load config file", name);
return STS_FAILURE;
}
INFO("%s is initialized", name);
return STS_SUCCESS;
}
/*
* Processing.
*
*/
int PLUGIN_PROCESS(int stage, sip_ticket_t *ticket){
/* stage contains the PLUGIN_* value - the stage of SIP processing. */
int sts;
char *buff;
size_t buflen;
char clen[8]; /* content length: probably never more than 7 digits !*/
int i;
osip_body_t *body;
sdp_message_t *sdp;
char *sdp_media;
int media_stream_no;
char *payload;
int payload_mediatype;
int payload_no;
sdp_attribute_t *sdp_attr;
int attr_mediatype;
int media_attr_no;
int skip_media_attr_inc;
DEBUGC(DBCLASS_PLUGIN, "%s: entered", name);
sts = osip_message_get_body(ticket->sipmsg, 0, &body);
if (sts != 0) {
DEBUGC(DBCLASS_PLUGIN, "%s: rewrite_invitation_body: "
"no body found in message", name);
return STS_SUCCESS;
}
sts = sip_body_to_str(body, &buff, &buflen);
if (sts != 0) {
ERROR("%s: unable to sip_body_to_str", name);
return STS_FAILURE;
}
sts = sdp_message_init(&sdp);
sts = sdp_message_parse (sdp, buff);
if (sts != 0) {
ERROR("%s: unable to sdp_message_parse body", name);
DUMP_BUFFER(-1, buff, buflen);
osip_free(buff);
sdp_message_free(sdp);
return STS_SUCCESS;
}
osip_free(buff);
buff=NULL;
media_stream_no=0;
while ((sdp_media=sdp_message_m_media_get(sdp, media_stream_no))) {
DEBUGC(DBCLASS_PLUGIN, "%s: m:%i", name, media_stream_no);
payload_no=0;
while ((payload=sdp_message_m_payload_get(sdp, media_stream_no, payload_no))) {
DEBUGC(DBCLASS_PLUGIN, " +-- p:%s", payload);
payload_no++;
}
media_attr_no=0;
while ((sdp_attr=sdp_message_attribute_get(sdp, media_stream_no, media_attr_no))) {
DEBUGC(DBCLASS_PLUGIN, " Attr m:%i, a=%i", media_stream_no, media_attr_no);
if (sdp_attr->a_att_field && sdp_attr->a_att_value) {
attr_mediatype=0;
sts=sscanf(sdp_attr->a_att_value, "%i", &attr_mediatype);
DEBUGC(DBCLASS_PLUGIN, " Attr field=%s, val=%s [MT=%i]",
sdp_attr->a_att_field, sdp_attr->a_att_value, attr_mediatype);
/* search for match */
for (i=0; i<plugin_cfg.codec_blacklist.used; i++) {
if (strcasestr(sdp_attr->a_att_value, plugin_cfg.codec_blacklist.string[i])) {
/* match, need to remove this codec */
DEBUGC(DBCLASS_PLUGIN, "%s: *** REMOVE media attr [%s] at attrpos=%i", name,
sdp_attr->a_att_value, media_attr_no);
// remove media attribute (a)
// libosip bug?? -> loops Do it manually then...
//if (sdp_message_a_attribute_del_at_index(sdp, media_stream_no, sdp_attr->a_att_field, media_attr_no) != OSIP_SUCCESS) {
// ERROR("%s: sdp_message_a_attribute_del() failed", name);
//}
{
sdp_media_t *med;
sdp_attribute_t *attr;
med = (sdp_media_t *) osip_list_get(&sdp->m_medias, media_stream_no);
if ((attr = osip_list_get(&med->a_attributes, media_attr_no)) != NULL) {
osip_list_remove(&med->a_attributes, media_attr_no);
sdp_attribute_free(attr);
attr=NULL;
skip_media_attr_inc=1;
}
}
// find corresponding (m) payload
payload_no=0;
while ((payload=sdp_message_m_payload_get(sdp, media_stream_no, payload_no))) {
payload_mediatype=0;
sts=sscanf(payload, "%i", &payload_mediatype);
DEBUGC(DBCLASS_PLUGIN, " +-- p:%s [%i]", payload, payload_mediatype);
if (payload_mediatype == attr_mediatype) {
DEBUGC(DBCLASS_PLUGIN, "%s: *** REMOVE media format %i at stream=%i, pos=%i", name,
payload_mediatype, media_stream_no, payload_no);
// remove (m) playload in media description
if (sdp_message_m_payload_del(sdp, media_stream_no, payload_no) != OSIP_SUCCESS) {
ERROR("%s: sdp_message_a_attribute_del() failed", name);
}
} else {
payload_no++;
}
} /* while playload */
} /* if match with config blacklist */
} /* for codec_blacklist */
}
if (skip_media_attr_inc == 0) {media_attr_no++;}
skip_media_attr_inc=0;
} /* while sdp_message_attribute_get */
media_stream_no++;
} /* while sdp_message_m_media_get */
//better:
//&&&
// while (next media_attribute) {
// if match with exclusion config
// get media type
// remove media attribute
// while (next media description)
// if match on removed media type
// remove media type from media description
/* remove old body */
sts = osip_list_remove(&(ticket->sipmsg->bodies), 0);
osip_body_free(body);
body=NULL;
/* dump new body */
sdp_message_to_str(sdp, &buff);
buflen=strlen(buff);
/* free sdp structure */
sdp_message_free(sdp);
/* include new body */
sip_message_set_body(ticket->sipmsg, buff, buflen);
if (sts != 0) {
ERROR("%s: unable to sip_message_set_body body", name);
}
/* free content length resource and include new one*/
osip_content_length_free(ticket->sipmsg->content_length);
ticket->sipmsg->content_length=NULL;
sprintf(clen,"%ld",(long)buflen);
sts = osip_message_set_content_length(ticket->sipmsg, clen);
/* free new body string*/
osip_free(buff);
DEBUGC(DBCLASS_PLUGIN, "%s: exit", name);
return STS_SUCCESS;
}
/*
* De-Initialization.
* Called during shutdown of siproxd. Gives the plugin the chance
* to clean up its mess (e.g. dynamic memory allocation, database
* connections, whatever the plugin messes around with)
*/
int PLUGIN_END(plugin_def_t *plugin_def){
INFO("%s ends here", name);
return STS_SUCCESS;
}
#if 0
/*--------------------------------------------------------------------*/
static int sip_filter_sdp(sip_ticket_t *ticket) {
sdp_media_t *sdp_media;
osip_via_t *via;
if((via = osip_list_get(&(ticket->sipmsg->vias), 0)) != NULL) {
/* clone Via header */
/* set new IP (from IP) */
osip_free(via->host);
via->host=osip_malloc(IPSTRING_SIZE);
snprintf(via->host, IPSTRING_SIZE, "%s",
utils_inet_ntoa(ticket->from.sin_addr));
via->host[IPSTRING_SIZE-1] ='\0';
/* set new port number */
osip_free(via->port);
via->port=osip_malloc(6); /* 5 digits + \0 */
snprintf(via->port, 5, "%u", ntohs(ticket->from.sin_port));
via->port[5-1] ='\0';
DEBUGC(DBCLASS_PLUGIN, "%s: -> %s:%s", name,
via->host, via->port);
}
return STS_SUCCESS;
}
#endif