mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-11 04:18:21 +00:00
Add outgoing OSP support (SIP only at this point)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3296 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -40,6 +40,7 @@ endif
|
|||||||
|
|
||||||
APPS+=$(shell if [ -f /usr/include/linux/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
|
APPS+=$(shell if [ -f /usr/include/linux/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
|
||||||
APPS+=$(shell if [ -f /usr/local/include/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
|
APPS+=$(shell if [ -f /usr/local/include/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
|
||||||
|
APPS+=$(shell if [ -f /usr/include/osp/osp.h ]; then echo "app_osplookup.so" ; fi)
|
||||||
|
|
||||||
CFLAGS+=-fPIC
|
CFLAGS+=-fPIC
|
||||||
|
|
||||||
|
|||||||
@@ -362,6 +362,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
|
|||||||
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
|
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
|
||||||
/* Got hung up */
|
/* Got hung up */
|
||||||
*to=-1;
|
*to=-1;
|
||||||
|
strcpy(status, "CANCEL");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (f && (f->frametype == AST_FRAME_DTMF) && *allowdisconnect &&
|
if (f && (f->frametype == AST_FRAME_DTMF) && *allowdisconnect &&
|
||||||
@@ -722,36 +723,21 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
|||||||
/* If creating a SIP channel, look for a variable called */
|
/* If creating a SIP channel, look for a variable called */
|
||||||
/* VXML_URL in the calling channel and copy it to the */
|
/* VXML_URL in the calling channel and copy it to the */
|
||||||
/* new channel. */
|
/* new channel. */
|
||||||
if (strcasecmp(tech,"SIP")==0)
|
|
||||||
{
|
|
||||||
headp=&chan->varshead;
|
|
||||||
AST_LIST_TRAVERSE(headp,current,entries) {
|
|
||||||
if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
|
|
||||||
{
|
|
||||||
newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
|
|
||||||
newheadp=&tmp->chan->varshead;
|
|
||||||
AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Check for ALERT_INFO in the SetVar list. This is for */
|
/* Check for ALERT_INFO in the SetVar list. This is for */
|
||||||
/* SIP distinctive ring as per the RFC. For Cisco 7960s, */
|
/* SIP distinctive ring as per the RFC. For Cisco 7960s, */
|
||||||
/* SetVar(ALERT_INFO=<x>) where x is an integer value 1-5. */
|
/* SetVar(ALERT_INFO=<x>) where x is an integer value 1-5. */
|
||||||
/* However, the RFC says it should be a URL. -km- */
|
/* However, the RFC says it should be a URL. -km- */
|
||||||
|
|
||||||
if (strcasecmp(tech,"SIP")==0)
|
|
||||||
{
|
|
||||||
headp=&chan->varshead;
|
headp=&chan->varshead;
|
||||||
AST_LIST_TRAVERSE(headp,current,entries) {
|
AST_LIST_TRAVERSE(headp,current,entries) {
|
||||||
/* Search for ALERT_INFO */
|
if (!strcasecmp(ast_var_name(current),"VXML_URL") ||
|
||||||
if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
|
!strcasecmp(ast_var_name(current), "ALERT_INFO") ||
|
||||||
|
!strcasecmp(ast_var_name(current), "OSPTOKEN") ||
|
||||||
|
!strcasecmp(ast_var_name(current), "OSPHANDLE"))
|
||||||
{
|
{
|
||||||
newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
|
newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
|
||||||
newheadp=&tmp->chan->varshead;
|
newheadp=&tmp->chan->varshead;
|
||||||
AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
|
AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,6 +836,10 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (peer) {
|
if (peer) {
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
/* Once call is answered, ditch the OSP Handle */
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPHANDLE", "");
|
||||||
|
#endif
|
||||||
strcpy(status, "ANSWER");
|
strcpy(status, "ANSWER");
|
||||||
/* Ah ha! Someone answered within the desired timeframe. Of course after this
|
/* Ah ha! Someone answered within the desired timeframe. Of course after this
|
||||||
we will always return with -1 so that it is hung up properly after the
|
we will always return with -1 so that it is hung up properly after the
|
||||||
|
|||||||
274
apps/app_osplookup.c
Executable file
274
apps/app_osplookup.c
Executable file
@@ -0,0 +1,274 @@
|
|||||||
|
/*
|
||||||
|
* Asterisk -- A telephony toolkit for Linux.
|
||||||
|
*
|
||||||
|
* Time of day - Report the time of day
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999, Mark Spencer
|
||||||
|
*
|
||||||
|
* Mark Spencer <markster@linux-support.net>
|
||||||
|
*
|
||||||
|
* This program is free software, distributed under the terms of
|
||||||
|
* the GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asterisk/lock.h>
|
||||||
|
#include <asterisk/file.h>
|
||||||
|
#include <asterisk/logger.h>
|
||||||
|
#include <asterisk/channel.h>
|
||||||
|
#include <asterisk/pbx.h>
|
||||||
|
#include <asterisk/options.h>
|
||||||
|
#include <asterisk/config.h>
|
||||||
|
#include <asterisk/module.h>
|
||||||
|
#include <asterisk/utils.h>
|
||||||
|
#include <asterisk/causes.h>
|
||||||
|
#include <asterisk/astosp.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
static char *tdesc = "OSP Lookup";
|
||||||
|
|
||||||
|
static char *app = "OSPLookup";
|
||||||
|
static char *app2 = "OSPNext";
|
||||||
|
static char *app3 = "OSPFinish";
|
||||||
|
|
||||||
|
static char *synopsis = "Lookup number in OSP";
|
||||||
|
static char *synopsis2 = "Lookup next OSP entry";
|
||||||
|
static char *synopsis3 = "Record OSP entry";
|
||||||
|
|
||||||
|
static char *descrip =
|
||||||
|
" OSPLookup(exten[|provider[|options]]): Looks up an extension via OSP and sets\n"
|
||||||
|
"the variables, where 'n' is the number of the result beginning with 1:\n"
|
||||||
|
" ${OSPTECH}: The technology to use for the call\n"
|
||||||
|
" ${OSPDEST}: The destination to use for the call\n"
|
||||||
|
" ${OSPTOKEN}: The actual OSP token as a string\n"
|
||||||
|
" ${OSPHANDLE}: The OSP Handle for anything remaining\n"
|
||||||
|
" ${OSPRESULTS}: The number of OSP results total remaining\n"
|
||||||
|
"\n"
|
||||||
|
"If the lookup was *not* successful and there exists a priority n + 101,\n"
|
||||||
|
"then that priority will be taken next.\n" ;
|
||||||
|
|
||||||
|
static char *descrip2 =
|
||||||
|
" OSPNext: Looks up the next OSP Destination for ${OSPHANDLE}\n"
|
||||||
|
"See OSPLookup for more information\n"
|
||||||
|
"\n"
|
||||||
|
"If the lookup was *not* successful and there exists a priority n + 101,\n"
|
||||||
|
"then that priority will be taken next.\n" ;
|
||||||
|
|
||||||
|
static char *descrip3 =
|
||||||
|
" OSPFinish(status): Records call state for ${OSPHANDLE}, according to\n"
|
||||||
|
"status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or NOCHANAVAIL\n"
|
||||||
|
"or coincidentally, just what the Dial application stores in its ${DIALSTATUS}\n"
|
||||||
|
"\n"
|
||||||
|
"If the finishing was *not* successful and there exists a priority n + 101,\n"
|
||||||
|
"then that priority will be taken next.\n" ;
|
||||||
|
|
||||||
|
STANDARD_LOCAL_USER;
|
||||||
|
|
||||||
|
LOCAL_USER_DECL;
|
||||||
|
|
||||||
|
static int str2cause(char *cause)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(cause, "BUSY"))
|
||||||
|
return AST_CAUSE_BUSY;
|
||||||
|
if (!strcasecmp(cause, "CONGESTION"))
|
||||||
|
return AST_CAUSE_CONGESTION;
|
||||||
|
if (!strcasecmp(cause, "ANSWER"))
|
||||||
|
return AST_CAUSE_NORMAL;
|
||||||
|
if (!strcasecmp(cause, "CANCEL"))
|
||||||
|
return AST_CAUSE_NORMAL;
|
||||||
|
if (!strcasecmp(cause, "NOANSWER"))
|
||||||
|
return AST_CAUSE_NOANSWER;
|
||||||
|
if (!strcasecmp(cause, "NOCHANAVAIL"))
|
||||||
|
return AST_CAUSE_CONGESTION;
|
||||||
|
ast_log(LOG_WARNING, "Unknown cause '%s', using NORMAL\n", cause);
|
||||||
|
return AST_CAUSE_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int osplookup_exec(struct ast_channel *chan, void *data)
|
||||||
|
{
|
||||||
|
int res=0;
|
||||||
|
struct localuser *u;
|
||||||
|
char *temp;
|
||||||
|
char *provider, *opts=NULL;
|
||||||
|
struct ast_osp_result result;
|
||||||
|
if (!data || ast_strlen_zero(data) || !(temp = ast_strdupa(data))) {
|
||||||
|
ast_log(LOG_WARNING, "OSPLookup requires an argument (extension)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
provider = strchr(temp, '|');
|
||||||
|
if (provider) {
|
||||||
|
*provider = '\0';
|
||||||
|
provider++;
|
||||||
|
opts = strchr(provider, '|');
|
||||||
|
if (opts) {
|
||||||
|
*opts = '\0';
|
||||||
|
opts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOCAL_USER_ADD(u);
|
||||||
|
ast_log(LOG_DEBUG, "Whoo hoo, looking up OSP on '%s' via '%s'\n", temp, provider ? provider : "<default>");
|
||||||
|
if ((res = ast_osp_lookup(chan, provider, temp, chan->callerid, &result)) > 0) {
|
||||||
|
char tmp[80];
|
||||||
|
snprintf(tmp, sizeof(tmp), "%d", result.handle);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPHANDLE", tmp);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPTOKEN", result.token);
|
||||||
|
snprintf(tmp, sizeof(tmp), "%d", result.numresults);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPRESULTS", tmp);
|
||||||
|
} else {
|
||||||
|
if (!res)
|
||||||
|
ast_log(LOG_NOTICE, "OSP Lookup failed for '%s' (provider '%s')\n", temp, provider ? provider : "<default>");
|
||||||
|
else
|
||||||
|
ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Lookup for '%s' (provider '%s')!\n", chan->name, temp, provider ? provider : "<default>" );
|
||||||
|
}
|
||||||
|
if (!res) {
|
||||||
|
/* Look for a "busy" place */
|
||||||
|
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||||
|
chan->priority += 100;
|
||||||
|
} else if (res > 0)
|
||||||
|
res = 0;
|
||||||
|
LOCAL_USER_REMOVE(u);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospnext_exec(struct ast_channel *chan, void *data)
|
||||||
|
{
|
||||||
|
int res=0;
|
||||||
|
struct localuser *u;
|
||||||
|
char *temp;
|
||||||
|
int cause;
|
||||||
|
struct ast_osp_result result;
|
||||||
|
if (!data || ast_strlen_zero(data)) {
|
||||||
|
ast_log(LOG_WARNING, "OSPNext should have an argument (cause)\n");
|
||||||
|
}
|
||||||
|
LOCAL_USER_ADD(u);
|
||||||
|
cause = str2cause((char *)data);
|
||||||
|
temp = pbx_builtin_getvar_helper(chan, "OSPHANDLE");
|
||||||
|
result.handle = -1;
|
||||||
|
if (temp && strlen(temp) && (sscanf(temp, "%i", &result.handle) == 1) && (result.handle > -1)) {
|
||||||
|
if ((res = ast_osp_next(&result, cause)) > 0) {
|
||||||
|
char tmp[80];
|
||||||
|
snprintf(tmp, sizeof(tmp), "%d", result.handle);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPHANDLE", tmp);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPTOKEN", result.token);
|
||||||
|
snprintf(tmp, sizeof(tmp), "%d", result.numresults);
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPRESULTS", tmp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!res) {
|
||||||
|
if (result.handle < 0)
|
||||||
|
ast_log(LOG_NOTICE, "OSP Lookup Next failed for handle '%d'\n", result.handle);
|
||||||
|
else
|
||||||
|
ast_log(LOG_DEBUG, "No OSP handle specified\n");
|
||||||
|
} else
|
||||||
|
ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Next!\n", chan->name);
|
||||||
|
}
|
||||||
|
if (!res) {
|
||||||
|
/* Look for a "busy" place */
|
||||||
|
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||||
|
chan->priority += 100;
|
||||||
|
} else if (res > 0)
|
||||||
|
res = 0;
|
||||||
|
LOCAL_USER_REMOVE(u);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ospfinished_exec(struct ast_channel *chan, void *data)
|
||||||
|
{
|
||||||
|
int res=0;
|
||||||
|
struct localuser *u;
|
||||||
|
char *temp;
|
||||||
|
int cause;
|
||||||
|
time_t start=0, duration=0;
|
||||||
|
struct ast_osp_result result;
|
||||||
|
if (!data || ast_strlen_zero(data)) {
|
||||||
|
ast_log(LOG_WARNING, "OSPFinish should have an argument (cause)\n");
|
||||||
|
}
|
||||||
|
if (chan->cdr) {
|
||||||
|
start = chan->cdr->answer.tv_sec;
|
||||||
|
duration = time(NULL) - start;
|
||||||
|
} else
|
||||||
|
ast_log(LOG_WARNING, "OSPFinish called on channel '%s' with no CDR!\n", chan->name);
|
||||||
|
LOCAL_USER_ADD(u);
|
||||||
|
cause = str2cause((char *)data);
|
||||||
|
temp = pbx_builtin_getvar_helper(chan, "OSPHANDLE");
|
||||||
|
result.handle = -1;
|
||||||
|
if (temp && strlen(temp) && (sscanf(temp, "%i", &result.handle) == 1) && (result.handle > -1)) {
|
||||||
|
if (!ast_osp_terminate(result.handle, cause, start, duration)) {
|
||||||
|
pbx_builtin_setvar_helper(chan, "OSPHANDLE", "");
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!res) {
|
||||||
|
if (result.handle > -1)
|
||||||
|
ast_log(LOG_NOTICE, "OSP Finish failed for handle '%d'\n", result.handle);
|
||||||
|
else
|
||||||
|
ast_log(LOG_DEBUG, "No OSP handle specified\n");
|
||||||
|
} else
|
||||||
|
ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Terminate!\n", chan->name);
|
||||||
|
}
|
||||||
|
if (!res) {
|
||||||
|
/* Look for a "busy" place */
|
||||||
|
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||||
|
chan->priority += 100;
|
||||||
|
} else if (res > 0)
|
||||||
|
res = 0;
|
||||||
|
LOCAL_USER_REMOVE(u);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int unload_module(void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
STANDARD_HANGUP_LOCALUSERS;
|
||||||
|
res = ast_unregister_application(app3);
|
||||||
|
res |= ast_unregister_application(app2);
|
||||||
|
res |= ast_unregister_application(app);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_module(void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
res = ast_register_application(app, osplookup_exec, synopsis, descrip);
|
||||||
|
if (res)
|
||||||
|
return(res);
|
||||||
|
res = ast_register_application(app2, ospnext_exec, synopsis2, descrip2);
|
||||||
|
if (res)
|
||||||
|
return(res);
|
||||||
|
res = ast_register_application(app3, ospfinished_exec, synopsis3, descrip3);
|
||||||
|
if (res)
|
||||||
|
return(res);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int reload(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *description(void)
|
||||||
|
{
|
||||||
|
return tdesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usecount(void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
STANDARD_USECOUNT(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *key()
|
||||||
|
{
|
||||||
|
return ASTERISK_GPL_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -40,6 +40,9 @@
|
|||||||
#include <asterisk/astdb.h>
|
#include <asterisk/astdb.h>
|
||||||
#include <asterisk/causes.h>
|
#include <asterisk/causes.h>
|
||||||
#include <asterisk/utils.h>
|
#include <asterisk/utils.h>
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
#include <asterisk/astosp.h>
|
||||||
|
#endif
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
@@ -314,6 +317,10 @@ static struct sip_pvt {
|
|||||||
int needreinvite; /* Do we need to send another reinvite? */
|
int needreinvite; /* Do we need to send another reinvite? */
|
||||||
int pendingbye; /* Need to send bye after we ack? */
|
int pendingbye; /* Need to send bye after we ack? */
|
||||||
int gotrefer; /* Got a refer? */
|
int gotrefer; /* Got a refer? */
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
int osphandle; /* OSP Handle for call */
|
||||||
|
time_t ospstart; /* OSP Start time */
|
||||||
|
#endif
|
||||||
struct sip_request initreq; /* Initial request */
|
struct sip_request initreq; /* Initial request */
|
||||||
|
|
||||||
int maxtime; /* Max time for first response */
|
int maxtime; /* Max time for first response */
|
||||||
@@ -514,7 +521,7 @@ static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_r
|
|||||||
static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *rand, int reliable, char *header);
|
static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *rand, int reliable, char *header);
|
||||||
static int transmit_request(struct sip_pvt *p, char *msg, int inc, int reliable, int newbranch);
|
static int transmit_request(struct sip_pvt *p, char *msg, int inc, int reliable, int newbranch);
|
||||||
static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int inc, int reliable, int newbranch);
|
static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int inc, int reliable, int newbranch);
|
||||||
static int transmit_invite(struct sip_pvt *p, char *msg, int sendsdp, char *auth, char *authheader, char *vxml_url,char *distinctive_ring, int init);
|
static int transmit_invite(struct sip_pvt *p, char *msg, int sendsdp, char *auth, char *authheader, char *vxml_url,char *distinctive_ring, char *osptoken,int init);
|
||||||
static int transmit_reinvite_with_sdp(struct sip_pvt *p);
|
static int transmit_reinvite_with_sdp(struct sip_pvt *p);
|
||||||
static int transmit_info_with_digit(struct sip_pvt *p, char digit);
|
static int transmit_info_with_digit(struct sip_pvt *p, char digit);
|
||||||
static int transmit_message_with_text(struct sip_pvt *p, char *text);
|
static int transmit_message_with_text(struct sip_pvt *p, char *text);
|
||||||
@@ -1355,6 +1362,10 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
|
|||||||
struct sip_pvt *p;
|
struct sip_pvt *p;
|
||||||
char *vxml_url = NULL;
|
char *vxml_url = NULL;
|
||||||
char *distinctive_ring = NULL;
|
char *distinctive_ring = NULL;
|
||||||
|
char *osptoken = NULL;
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
char *osphandle = NULL;
|
||||||
|
#endif
|
||||||
struct varshead *headp;
|
struct varshead *headp;
|
||||||
struct ast_var_t *current;
|
struct ast_var_t *current;
|
||||||
|
|
||||||
@@ -1371,24 +1382,37 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
|
|||||||
if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
|
if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
|
||||||
{
|
{
|
||||||
vxml_url = ast_var_value(current);
|
vxml_url = ast_var_value(current);
|
||||||
break;
|
} else
|
||||||
}
|
|
||||||
/* Check whether there is a ALERT_INFO variable */
|
/* Check whether there is a ALERT_INFO variable */
|
||||||
if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
|
if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
|
||||||
{
|
{
|
||||||
distinctive_ring = ast_var_value(current);
|
distinctive_ring = ast_var_value(current);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
else if (!strcasecmp(ast_var_name(current), "OSPTOKEN")) {
|
||||||
|
osptoken = ast_var_value(current);
|
||||||
|
} else if (!strcasecmp(ast_var_name(current), "OSPHANDLE")) {
|
||||||
|
osphandle = ast_var_value(current);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
p->outgoing = 1;
|
p->outgoing = 1;
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
if (!osptoken || !osphandle || (sscanf(osphandle, "%i", &p->osphandle) != 1)) {
|
||||||
|
/* Force Disable OSP support */
|
||||||
|
osptoken = NULL;
|
||||||
|
osphandle = NULL;
|
||||||
|
p->osphandle = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ast_log(LOG_DEBUG, "Outgoing Call for %s\n", p->username);
|
ast_log(LOG_DEBUG, "Outgoing Call for %s\n", p->username);
|
||||||
res = update_user_counter(p,INC_OUT_USE);
|
res = update_user_counter(p,INC_OUT_USE);
|
||||||
if ( res != -1 ) {
|
if ( res != -1 ) {
|
||||||
p->restrictcid = ast->restrictcid;
|
p->restrictcid = ast->restrictcid;
|
||||||
p->jointcapability = p->capability;
|
p->jointcapability = p->capability;
|
||||||
transmit_invite(p, "INVITE", 1, NULL, NULL, vxml_url,distinctive_ring, 1);
|
transmit_invite(p, "INVITE", 1, NULL, NULL, vxml_url,distinctive_ring, osptoken, 1);
|
||||||
if (p->maxtime) {
|
if (p->maxtime) {
|
||||||
/* Initialize auto-congest time */
|
/* Initialize auto-congest time */
|
||||||
p->initid = ast_sched_add(sched, p->maxtime * 4, auto_congest, p);
|
p->initid = ast_sched_add(sched, p->maxtime * 4, auto_congest, p);
|
||||||
@@ -1606,6 +1630,11 @@ static int sip_hangup(struct ast_channel *ast)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ast_mutex_lock(&p->lock);
|
ast_mutex_lock(&p->lock);
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
if ((p->osphandle > -1) && (ast->_state == AST_STATE_UP)) {
|
||||||
|
ast_osp_terminate(p->osphandle, AST_CAUSE_NORMAL, p->ospstart, time(NULL) - p->ospstart);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if ( p->outgoing ) {
|
if ( p->outgoing ) {
|
||||||
ast_log(LOG_DEBUG, "update_user_counter(%s) - decrement outUse counter\n", p->username);
|
ast_log(LOG_DEBUG, "update_user_counter(%s) - decrement outUse counter\n", p->username);
|
||||||
update_user_counter(p, DEC_OUT_USE);
|
update_user_counter(p, DEC_OUT_USE);
|
||||||
@@ -1687,8 +1716,9 @@ static int sip_answer(struct ast_channel *ast)
|
|||||||
|
|
||||||
ast_mutex_lock(&p->lock);
|
ast_mutex_lock(&p->lock);
|
||||||
if (ast->_state != AST_STATE_UP) {
|
if (ast->_state != AST_STATE_UP) {
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
time(&p->ospstart);
|
||||||
|
#endif
|
||||||
|
|
||||||
codec=pbx_builtin_getvar_helper(p->owner,"SIP_CODEC");
|
codec=pbx_builtin_getvar_helper(p->owner,"SIP_CODEC");
|
||||||
if (codec) {
|
if (codec) {
|
||||||
@@ -2137,6 +2167,9 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
|
|||||||
p->initid = -1;
|
p->initid = -1;
|
||||||
p->autokillid = -1;
|
p->autokillid = -1;
|
||||||
p->stateid = -1;
|
p->stateid = -1;
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
p->osphandle = -1;
|
||||||
|
#endif
|
||||||
p->rtp = ast_rtp_new(sched, io, 1, 0);
|
p->rtp = ast_rtp_new(sched, io, 1, 0);
|
||||||
if (videosupport)
|
if (videosupport)
|
||||||
p->vrtp = ast_rtp_new(sched, io, 1, 0);
|
p->vrtp = ast_rtp_new(sched, io, 1, 0);
|
||||||
@@ -3543,7 +3576,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, char *cmd, c
|
|||||||
|
|
||||||
|
|
||||||
/*--- transmit_invite: Build REFER/INVITE/OPTIONS message and trasmit it ---*/
|
/*--- transmit_invite: Build REFER/INVITE/OPTIONS message and trasmit it ---*/
|
||||||
static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, char *authheader, char *vxml_url, char *distinctive_ring, int init)
|
static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, char *authheader, char *vxml_url, char *distinctive_ring, char *osptoken, int init)
|
||||||
{
|
{
|
||||||
struct sip_request req;
|
struct sip_request req;
|
||||||
|
|
||||||
@@ -3564,7 +3597,11 @@ static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, ch
|
|||||||
if (!ast_strlen_zero(p->referred_by))
|
if (!ast_strlen_zero(p->referred_by))
|
||||||
add_header(&req, "Referred-By", p->referred_by);
|
add_header(&req, "Referred-By", p->referred_by);
|
||||||
}
|
}
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
if (osptoken && !ast_strlen_zero(osptoken)) {
|
||||||
|
add_header(&req, "P-OSP-Auth-Token", osptoken);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (distinctive_ring && !ast_strlen_zero(distinctive_ring))
|
if (distinctive_ring && !ast_strlen_zero(distinctive_ring))
|
||||||
{
|
{
|
||||||
add_header(&req, "Alert-info",distinctive_ring);
|
add_header(&req, "Alert-info",distinctive_ring);
|
||||||
@@ -5792,7 +5829,7 @@ static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *heade
|
|||||||
/* No way to authenticate */
|
/* No way to authenticate */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return transmit_invite(p,msg,!strcasecmp(msg, "INVITE"),digest, respheader, NULL,NULL, init);
|
return transmit_invite(p,msg,!strcasecmp(msg, "INVITE"),digest, respheader, NULL,NULL,NULL, init);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--- reply_digest: reply to authentication for outbound registrations ---*/
|
/*--- reply_digest: reply to authentication for outbound registrations ---*/
|
||||||
@@ -6222,6 +6259,9 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
|
|||||||
build_route(p, req, 1);
|
build_route(p, req, 1);
|
||||||
if (p->owner) {
|
if (p->owner) {
|
||||||
if (p->owner->_state != AST_STATE_UP) {
|
if (p->owner->_state != AST_STATE_UP) {
|
||||||
|
#ifdef OSP_SUPPORT
|
||||||
|
time(&p->ospstart);
|
||||||
|
#endif
|
||||||
ast_setstate(p->owner, AST_STATE_UP);
|
ast_setstate(p->owner, AST_STATE_UP);
|
||||||
ast_queue_control(p->owner, AST_CONTROL_ANSWER);
|
ast_queue_control(p->owner, AST_CONTROL_ANSWER);
|
||||||
} else {
|
} else {
|
||||||
@@ -7303,9 +7343,9 @@ static int sip_poke_peer(struct sip_peer *peer)
|
|||||||
p->outgoing = 1;
|
p->outgoing = 1;
|
||||||
#ifdef VOCAL_DATA_HACK
|
#ifdef VOCAL_DATA_HACK
|
||||||
strncpy(p->username, "__VOCAL_DATA_SHOULD_READ_THE_SIP_SPEC__", sizeof(p->username));
|
strncpy(p->username, "__VOCAL_DATA_SHOULD_READ_THE_SIP_SPEC__", sizeof(p->username));
|
||||||
transmit_invite(p, "INVITE", 0, NULL, NULL, NULL,NULL, 1);
|
transmit_invite(p, "INVITE", 0, NULL, NULL, NULL,NULL,NULL, 1);
|
||||||
#else
|
#else
|
||||||
transmit_invite(p, "OPTIONS", 0, NULL, NULL, NULL,NULL, 1);
|
transmit_invite(p, "OPTIONS", 0, NULL, NULL, NULL,NULL,NULL, 1);
|
||||||
#endif
|
#endif
|
||||||
gettimeofday(&peer->ps, NULL);
|
gettimeofday(&peer->ps, NULL);
|
||||||
peer->pokeexpire = ast_sched_add(sched, DEFAULT_MAXMS * 2, sip_poke_noanswer, peer);
|
peer->pokeexpire = ast_sched_add(sched, DEFAULT_MAXMS * 2, sip_poke_noanswer, peer);
|
||||||
|
|||||||
35
include/asterisk/astosp.h
Executable file
35
include/asterisk/astosp.h
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Asterisk -- A telephony toolkit for Linux.
|
||||||
|
*
|
||||||
|
* OSP support
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999, Mark Spencer
|
||||||
|
*
|
||||||
|
* Mark Spencer <markster@linux-support.net>
|
||||||
|
*
|
||||||
|
* This program is free software, distributed under the terms of
|
||||||
|
* the GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ASTERISK_OSP_H
|
||||||
|
#define _ASTERISK_OSP_H
|
||||||
|
#include <asterisk/channel.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
struct ast_osp_result {
|
||||||
|
int handle;
|
||||||
|
int numresults;
|
||||||
|
char tech[20];
|
||||||
|
char dest[256];
|
||||||
|
char token[4096];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Note: Channel will be auto-serviced if specified. Returns -1 on hangup,
|
||||||
|
0 if nothing found, or 1 if something is found */
|
||||||
|
int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result);
|
||||||
|
|
||||||
|
int ast_osp_next(struct ast_osp_result *result, int cause);
|
||||||
|
|
||||||
|
int ast_osp_terminate(int handle, int cause, time_t start, time_t duration);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,5 +20,6 @@
|
|||||||
#define AST_CAUSE_FAILURE 3
|
#define AST_CAUSE_FAILURE 3
|
||||||
#define AST_CAUSE_CONGESTION 4
|
#define AST_CAUSE_CONGESTION 4
|
||||||
#define AST_CAUSE_UNALLOCATED 5
|
#define AST_CAUSE_UNALLOCATED 5
|
||||||
|
#define AST_CAUSE_NOANSWER 6
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ struct ast_hostent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp);
|
extern struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp);
|
||||||
|
extern int ast_base64encode(char *dst, unsigned char *src, int srclen, int max);
|
||||||
|
extern int ast_base64decode(unsigned char *dst, char *src, int max);
|
||||||
|
|
||||||
extern int test_for_thread_safety(void);
|
extern int test_for_thread_safety(void);
|
||||||
|
extern int ast_utils_init(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
MODS=res_adsi.so res_parking.so res_crypto.so res_musiconhold.so res_indications.so res_monitor.so
|
MODS=res_adsi.so res_parking.so res_crypto.so res_musiconhold.so res_indications.so res_monitor.so
|
||||||
MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
|
MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
|
||||||
MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
|
MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi)
|
||||||
|
MODS+=$(shell if [ -f "/usr/include/osp/osp.h" ]; then echo "res_osp.so"; fi)
|
||||||
|
|
||||||
CRYPTO_LIBS=-lssl -lcrypto
|
CRYPTO_LIBS=-lssl -lcrypto
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ CFLAGS+=$(shell [ -f /usr/local/include/zaptel.h ] && echo " -DZAPATA_MOH")
|
|||||||
# Work around buggy RedHat 9.0
|
# Work around buggy RedHat 9.0
|
||||||
#
|
#
|
||||||
CFLAGS+=-DOPENSSL_NO_KRB5 -fPIC
|
CFLAGS+=-DOPENSSL_NO_KRB5 -fPIC
|
||||||
|
OSPLIB=/usr/lib/libosp.a
|
||||||
|
|
||||||
all: depend $(MODS)
|
all: depend $(MODS)
|
||||||
|
|
||||||
@@ -39,6 +41,9 @@ clean:
|
|||||||
res_odbc.so: res_odbc.o
|
res_odbc.so: res_odbc.o
|
||||||
$(CC) $(SOLINK) -o $@ $< -lodbc
|
$(CC) $(SOLINK) -o $@ $< -lodbc
|
||||||
|
|
||||||
|
res_osp.so: res_osp.o $(OSPLIB)
|
||||||
|
$(CC) $(SOLINK) -o $@ $< $(OSPLIB)
|
||||||
|
|
||||||
%.so : %.o
|
%.so : %.o
|
||||||
$(CC) $(SOLINK) -o $@ $<
|
$(CC) $(SOLINK) -o $@ $<
|
||||||
|
|
||||||
|
|||||||
124
res/res_crypto.c
124
res/res_crypto.c
@@ -23,6 +23,7 @@
|
|||||||
#include <asterisk/cli.h>
|
#include <asterisk/cli.h>
|
||||||
#include <asterisk/io.h>
|
#include <asterisk/io.h>
|
||||||
#include <asterisk/lock.h>
|
#include <asterisk/lock.h>
|
||||||
|
#include <asterisk/utils.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -56,9 +57,6 @@
|
|||||||
* XXXX
|
* XXXX
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char base64[64];
|
|
||||||
static char b2a[256];
|
|
||||||
|
|
||||||
AST_MUTEX_DEFINE_STATIC(keylock);
|
AST_MUTEX_DEFINE_STATIC(keylock);
|
||||||
|
|
||||||
#define KEY_NEEDS_PASSCODE (1 << 16)
|
#define KEY_NEEDS_PASSCODE (1 << 16)
|
||||||
@@ -298,89 +296,6 @@ static char *binary(int y, int len)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int base64decode(unsigned char *dst, char *src, int max)
|
|
||||||
{
|
|
||||||
int cnt = 0;
|
|
||||||
unsigned int byte = 0;
|
|
||||||
unsigned int bits = 0;
|
|
||||||
int incnt = 0;
|
|
||||||
#if 0
|
|
||||||
unsigned char *odst = dst;
|
|
||||||
#endif
|
|
||||||
while(*src && (cnt < max)) {
|
|
||||||
/* Shift in 6 bits of input */
|
|
||||||
byte <<= 6;
|
|
||||||
byte |= (b2a[(int)(*src)]) & 0x3f;
|
|
||||||
bits += 6;
|
|
||||||
#if 0
|
|
||||||
printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6));
|
|
||||||
#endif
|
|
||||||
src++;
|
|
||||||
incnt++;
|
|
||||||
/* If we have at least 8 bits left over, take that character
|
|
||||||
off the top */
|
|
||||||
if (bits >= 8) {
|
|
||||||
bits -= 8;
|
|
||||||
*dst = (byte >> bits) & 0xff;
|
|
||||||
#if 0
|
|
||||||
printf("Remove: %02x %s\n", *dst, binary(*dst, 8));
|
|
||||||
#endif
|
|
||||||
dst++;
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
dump(odst, cnt);
|
|
||||||
#endif
|
|
||||||
/* Dont worry about left over bits, they're extra anyway */
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int base64encode(char *dst, unsigned char *src, int srclen, int max)
|
|
||||||
{
|
|
||||||
int cnt = 0;
|
|
||||||
unsigned int byte = 0;
|
|
||||||
int bits = 0;
|
|
||||||
int index;
|
|
||||||
int cntin = 0;
|
|
||||||
#if 0
|
|
||||||
char *odst = dst;
|
|
||||||
dump(src, srclen);
|
|
||||||
#endif
|
|
||||||
/* Reserve one bit for end */
|
|
||||||
max--;
|
|
||||||
while((cntin < srclen) && (cnt < max)) {
|
|
||||||
byte <<= 8;
|
|
||||||
#if 0
|
|
||||||
printf("Add: %02x %s\n", *src, binary(*src, 8));
|
|
||||||
#endif
|
|
||||||
byte |= *(src++);
|
|
||||||
bits += 8;
|
|
||||||
cntin++;
|
|
||||||
while((bits >= 6) && (cnt < max)) {
|
|
||||||
bits -= 6;
|
|
||||||
/* We want only the top */
|
|
||||||
index = (byte >> bits) & 0x3f;
|
|
||||||
*dst = base64[index];
|
|
||||||
#if 0
|
|
||||||
printf("Remove: %c %s\n", *dst, binary(index, 6));
|
|
||||||
#endif
|
|
||||||
dst++;
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (bits && (cnt < max)) {
|
|
||||||
/* Add one last character for the remaining bits,
|
|
||||||
padding the rest with 0 */
|
|
||||||
byte <<= (6 - bits);
|
|
||||||
index = (byte) & 0x3f;
|
|
||||||
*(dst++) = base64[index];
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
*dst = '\0';
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ast_sign(struct ast_key *key, char *msg, char *sig)
|
int ast_sign(struct ast_key *key, char *msg, char *sig)
|
||||||
{
|
{
|
||||||
unsigned char digest[20];
|
unsigned char digest[20];
|
||||||
@@ -410,7 +325,7 @@ int ast_sign(struct ast_key *key, char *msg, char *sig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Success -- encode (256 bytes max as documented) */
|
/* Success -- encode (256 bytes max as documented) */
|
||||||
base64encode(sig, dsig, siglen, 256);
|
ast_base64encode(sig, dsig, siglen, 256);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -429,7 +344,7 @@ int ast_check_signature(struct ast_key *key, char *msg, char *sig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Decode signature */
|
/* Decode signature */
|
||||||
res = base64decode(dsig, sig, sizeof(dsig));
|
res = ast_base64decode(dsig, sig, sizeof(dsig));
|
||||||
if (res != sizeof(dsig)) {
|
if (res != sizeof(dsig)) {
|
||||||
ast_log(LOG_WARNING, "Signature improper length (expect %d, got %d)\n", (int)sizeof(dsig), (int)res);
|
ast_log(LOG_WARNING, "Signature improper length (expect %d, got %d)\n", (int)sizeof(dsig), (int)res);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -558,41 +473,8 @@ static struct ast_cli_entry cli_show_keys =
|
|||||||
static struct ast_cli_entry cli_init_keys =
|
static struct ast_cli_entry cli_init_keys =
|
||||||
{ { "init", "keys", NULL }, init_keys, "Initialize RSA key passcodes", init_keys_usage };
|
{ { "init", "keys", NULL }, init_keys, "Initialize RSA key passcodes", init_keys_usage };
|
||||||
|
|
||||||
static void base64_init(void)
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
memset(b2a, -1, sizeof(b2a));
|
|
||||||
/* Initialize base-64 Conversion table */
|
|
||||||
for (x=0;x<26;x++) {
|
|
||||||
/* A-Z */
|
|
||||||
base64[x] = 'A' + x;
|
|
||||||
b2a['A' + x] = x;
|
|
||||||
/* a-z */
|
|
||||||
base64[x + 26] = 'a' + x;
|
|
||||||
b2a['a' + x] = x + 26;
|
|
||||||
/* 0-9 */
|
|
||||||
if (x < 10) {
|
|
||||||
base64[x + 52] = '0' + x;
|
|
||||||
b2a['0' + x] = x + 52;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
base64[62] = '+';
|
|
||||||
base64[63] = '/';
|
|
||||||
b2a[(int)'+'] = 62;
|
|
||||||
b2a[(int)'/'] = 63;
|
|
||||||
#if 0
|
|
||||||
for (x=0;x<64;x++) {
|
|
||||||
if (b2a[(int)base64[x]] != x) {
|
|
||||||
fprintf(stderr, "!!! %d failed\n", x);
|
|
||||||
} else
|
|
||||||
fprintf(stderr, "--- %d passed\n", x);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int crypto_init(void)
|
static int crypto_init(void)
|
||||||
{
|
{
|
||||||
base64_init();
|
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
ERR_load_crypto_strings();
|
ERR_load_crypto_strings();
|
||||||
ast_cli_register(&cli_show_keys);
|
ast_cli_register(&cli_show_keys);
|
||||||
|
|||||||
736
res/res_osp.c
Executable file
736
res/res_osp.c
Executable file
@@ -0,0 +1,736 @@
|
|||||||
|
/*
|
||||||
|
* Asterisk -- A telephony toolkit for Linux.
|
||||||
|
*
|
||||||
|
* Provide Open Settlement Protocol capability
|
||||||
|
*
|
||||||
|
* Copyright (C) 2004, Digium, Inc.
|
||||||
|
*
|
||||||
|
* Mark Spencer <markster@digium.com>
|
||||||
|
*
|
||||||
|
* This program is free software, distributed under the terms of
|
||||||
|
* the GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <asterisk/file.h>
|
||||||
|
#include <asterisk/channel.h>
|
||||||
|
#include <asterisk/logger.h>
|
||||||
|
#include <asterisk/say.h>
|
||||||
|
#include <asterisk/module.h>
|
||||||
|
#include <asterisk/options.h>
|
||||||
|
#include <asterisk/crypto.h>
|
||||||
|
#include <asterisk/md5.h>
|
||||||
|
#include <asterisk/cli.h>
|
||||||
|
#include <asterisk/io.h>
|
||||||
|
#include <asterisk/lock.h>
|
||||||
|
#include <asterisk/astosp.h>
|
||||||
|
#include <asterisk/config.h>
|
||||||
|
#include <asterisk/utils.h>
|
||||||
|
#include <asterisk/lock.h>
|
||||||
|
#include <asterisk/causes.h>
|
||||||
|
#include <osp.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "../asterisk.h"
|
||||||
|
#include "../astconf.h"
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_CERTS 10
|
||||||
|
#define MAX_SERVICEPOINTS 10
|
||||||
|
#define OSP_MAX 256
|
||||||
|
|
||||||
|
#define OSP_DEFAULT_MAX_CONNECTIONS 20
|
||||||
|
#define OSP_DEFAULT_RETRY_DELAY 0
|
||||||
|
#define OSP_DEFAULT_RETRY_LIMIT 2
|
||||||
|
#define OSP_DEFAULT_TIMEOUT 500
|
||||||
|
|
||||||
|
static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len);
|
||||||
|
static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len);
|
||||||
|
|
||||||
|
AST_MUTEX_DEFINE_STATIC(osplock);
|
||||||
|
|
||||||
|
static int initialized = 0;
|
||||||
|
static int hardware = 0;
|
||||||
|
|
||||||
|
struct osp_provider {
|
||||||
|
char name[OSP_MAX];
|
||||||
|
char localpvtkey[OSP_MAX];
|
||||||
|
char localcert[OSP_MAX];
|
||||||
|
char cacerts[MAX_CERTS][OSP_MAX];
|
||||||
|
int cacount;
|
||||||
|
char servicepoints[MAX_SERVICEPOINTS][OSP_MAX];
|
||||||
|
char source[OSP_MAX];
|
||||||
|
int spcount;
|
||||||
|
int dead;
|
||||||
|
int maxconnections;
|
||||||
|
int retrydelay;
|
||||||
|
int retrylimit;
|
||||||
|
int timeout;
|
||||||
|
OSPTPROVHANDLE handle;
|
||||||
|
struct osp_provider *next;
|
||||||
|
};
|
||||||
|
static struct osp_provider *providers;
|
||||||
|
|
||||||
|
static int osp_build(struct ast_config *cfg, char *cat)
|
||||||
|
{
|
||||||
|
OSPTCERT TheAuthCert[MAX_CERTS];
|
||||||
|
unsigned char Reqbuf[4096],LocalBuf[4096],AuthBuf[MAX_CERTS][4096];
|
||||||
|
struct ast_variable *v;
|
||||||
|
struct osp_provider *osp;
|
||||||
|
int x,length,errorcode=0;
|
||||||
|
int mallocd=0,i;
|
||||||
|
char *cacerts[MAX_CERTS];
|
||||||
|
const char *servicepoints[MAX_SERVICEPOINTS];
|
||||||
|
OSPTPRIVATEKEY privatekey;
|
||||||
|
OSPTCERT localcert;
|
||||||
|
OSPTCERT *authCerts[MAX_CERTS];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ast_mutex_lock(&osplock);
|
||||||
|
osp = providers;
|
||||||
|
while(osp) {
|
||||||
|
if (!strcasecmp(osp->name, cat))
|
||||||
|
break;
|
||||||
|
osp = osp->next;
|
||||||
|
}
|
||||||
|
ast_mutex_unlock(&osplock);
|
||||||
|
if (!osp) {
|
||||||
|
mallocd = 1;
|
||||||
|
osp = malloc(sizeof(struct osp_provider));
|
||||||
|
if (!osp) {
|
||||||
|
ast_log(LOG_WARNING, "Out of memory!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(osp, 0, sizeof(struct osp_provider));
|
||||||
|
osp->handle = -1;
|
||||||
|
}
|
||||||
|
strncpy(osp->name, cat, sizeof(osp->name) - 1);
|
||||||
|
snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s-privatekey.pem", cat);
|
||||||
|
snprintf(osp->localcert, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s-localcert.pem", cat);
|
||||||
|
osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS;
|
||||||
|
osp->retrydelay = OSP_DEFAULT_RETRY_DELAY;
|
||||||
|
osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT;
|
||||||
|
osp->timeout = OSP_DEFAULT_TIMEOUT;
|
||||||
|
strcpy(osp->source, "");
|
||||||
|
ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat);
|
||||||
|
v = ast_variable_browse(cfg, cat);
|
||||||
|
while(v) {
|
||||||
|
if (!strcasecmp(v->name, "privatekey")) {
|
||||||
|
if (v->value[0] == '/')
|
||||||
|
strncpy(osp->localpvtkey, v->value, sizeof(osp->localpvtkey) - 1);
|
||||||
|
else
|
||||||
|
snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s", v->value);
|
||||||
|
} else if (!strcasecmp(v->name, "localcert")) {
|
||||||
|
if (v->value[0] == '/')
|
||||||
|
strncpy(osp->localcert, v->value, sizeof(osp->localcert) - 1);
|
||||||
|
else
|
||||||
|
snprintf(osp->localcert, sizeof(osp->localcert), AST_KEY_DIR "/%s", v->value);
|
||||||
|
} else if (!strcasecmp(v->name, "cacert")) {
|
||||||
|
if (osp->cacount < MAX_CERTS) {
|
||||||
|
if (v->value[0] == '/')
|
||||||
|
strncpy(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0]));
|
||||||
|
else
|
||||||
|
snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), AST_KEY_DIR "/%s", v->value);
|
||||||
|
osp->cacount++;
|
||||||
|
} else
|
||||||
|
ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno);
|
||||||
|
} else if (!strcasecmp(v->name, "servicepoint")) {
|
||||||
|
if (osp->spcount < MAX_SERVICEPOINTS) {
|
||||||
|
strncpy(osp->servicepoints[osp->spcount], v->value, sizeof(osp->servicepoints[0]));
|
||||||
|
osp->spcount++;
|
||||||
|
} else
|
||||||
|
ast_log(LOG_WARNING, "Too many Service points at line %d\n", v->lineno);
|
||||||
|
} else if (!strcasecmp(v->name, "maxconnections")) {
|
||||||
|
if ((sscanf(v->value, "%i", &x) == 1) && (x > 0) && (x <= 1000)) {
|
||||||
|
osp->maxconnections = x;
|
||||||
|
} else
|
||||||
|
ast_log(LOG_WARNING, "maxconnections should be an integer from 1 to 1000, not '%s' at line %d\n", v->value, v->lineno);
|
||||||
|
} else if (!strcasecmp(v->name, "retrydelay")) {
|
||||||
|
if ((sscanf(v->value, "%i", &x) == 1) && (x >= 0) && (x <= 10)) {
|
||||||
|
osp->retrydelay = x;
|
||||||
|
} else
|
||||||
|
ast_log(LOG_WARNING, "retrydelay should be an integer from 0 to 10, not '%s' at line %d\n", v->value, v->lineno);
|
||||||
|
} else if (!strcasecmp(v->name, "retrylimit")) {
|
||||||
|
if ((sscanf(v->value, "%i", &x) == 1) && (x >= 0) && (x <= 100)) {
|
||||||
|
osp->retrylimit = x;
|
||||||
|
} else
|
||||||
|
ast_log(LOG_WARNING, "retrylimit should be an integer from 0 to 100, not '%s' at line %d\n", v->value, v->lineno);
|
||||||
|
} else if (!strcasecmp(v->name, "timeout")) {
|
||||||
|
if ((sscanf(v->value, "%i", &x) == 1) && (x >= 200) && (x <= 10000)) {
|
||||||
|
osp->timeout = x;
|
||||||
|
} else
|
||||||
|
ast_log(LOG_WARNING, "timeout should be an integer from 200 to 10000, not '%s' at line %d\n", v->value, v->lineno);
|
||||||
|
}
|
||||||
|
v = v->next;
|
||||||
|
}
|
||||||
|
if (osp->cacount < 1) {
|
||||||
|
snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), AST_KEY_DIR "/%s-cacert.pem", cat);
|
||||||
|
osp->cacount++;
|
||||||
|
}
|
||||||
|
for (x=0;x<osp->cacount;x++)
|
||||||
|
cacerts[x] = osp->cacerts[x];
|
||||||
|
for (x=0;x<osp->spcount;x++)
|
||||||
|
servicepoints[x] = osp->servicepoints[x];
|
||||||
|
|
||||||
|
ast_mutex_lock(&osplock);
|
||||||
|
osp->dead = 0;
|
||||||
|
if (osp->handle > -1) {
|
||||||
|
ast_log(LOG_DEBUG, "Deleting old handle for '%s'\n", osp->name);
|
||||||
|
OSPPProviderDelete(osp->handle, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
length = 0;
|
||||||
|
ast_log(LOG_DEBUG, "Loading private key for '%s' (%s)\n", osp->name, osp->localpvtkey);
|
||||||
|
errorcode = loadPemPrivateKey(osp->localpvtkey,Reqbuf,&length);
|
||||||
|
if (errorcode == 0)
|
||||||
|
{
|
||||||
|
privatekey.PrivateKeyData = Reqbuf;
|
||||||
|
privatekey.PrivateKeyLength = length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = 0;
|
||||||
|
ast_log(LOG_DEBUG, "Loading local cert for '%s' (%s)\n", osp->name, osp->localcert);
|
||||||
|
errorcode = loadPemCert(osp->localcert,LocalBuf,&length);
|
||||||
|
if (errorcode == 0)
|
||||||
|
{
|
||||||
|
localcert.CertData = LocalBuf;
|
||||||
|
localcert.CertDataLength = length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0;i<osp->cacount;i++)
|
||||||
|
{
|
||||||
|
length = 0;
|
||||||
|
ast_log(LOG_DEBUG, "Loading CA cert %d for '%s' (%s)\n", i + 1, osp->name, osp->cacerts[i]);
|
||||||
|
errorcode = loadPemCert(osp->cacerts[i],AuthBuf[i],&length);
|
||||||
|
if (errorcode == 0)
|
||||||
|
{
|
||||||
|
TheAuthCert[i].CertData = AuthBuf[i];
|
||||||
|
TheAuthCert[i].CertDataLength = length;
|
||||||
|
authCerts[i] = &(TheAuthCert[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_log(LOG_DEBUG, "Creating provider handle for '%s'\n", osp->name);
|
||||||
|
|
||||||
|
ast_log(LOG_DEBUG, "Service point '%s %d'\n", servicepoints[0], osp->spcount);
|
||||||
|
|
||||||
|
if (OSPPProviderNew(osp->spcount,
|
||||||
|
servicepoints,
|
||||||
|
NULL,
|
||||||
|
"localhost",
|
||||||
|
&privatekey,
|
||||||
|
&localcert,
|
||||||
|
osp->cacount,
|
||||||
|
(const OSPTCERT **)authCerts,
|
||||||
|
1,
|
||||||
|
300,
|
||||||
|
osp->maxconnections,
|
||||||
|
60000,
|
||||||
|
osp->retrydelay,
|
||||||
|
osp->retrylimit,
|
||||||
|
osp->timeout,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
&osp->handle)) {
|
||||||
|
ast_log(LOG_WARNING, "Unable to initialize provider '%s'\n", cat);
|
||||||
|
osp->dead = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mallocd) {
|
||||||
|
osp->next = providers;
|
||||||
|
providers = osp;
|
||||||
|
}
|
||||||
|
ast_mutex_unlock(&osplock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_osp(int fd, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct osp_provider *osp;
|
||||||
|
char *search = NULL;
|
||||||
|
int x;
|
||||||
|
int found = 0;
|
||||||
|
if ((argc < 2) || (argc > 3))
|
||||||
|
return RESULT_SHOWUSAGE;
|
||||||
|
if (argc > 2)
|
||||||
|
search = argv[2];
|
||||||
|
if (!search)
|
||||||
|
ast_cli(fd, "OSP: %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal");
|
||||||
|
|
||||||
|
ast_mutex_lock(&osplock);
|
||||||
|
osp = providers;
|
||||||
|
while(osp) {
|
||||||
|
if (!search || !strcasecmp(osp->name, search)) {
|
||||||
|
if (found)
|
||||||
|
ast_cli(fd, "\n");
|
||||||
|
ast_cli(fd, " == OSP Provider '%s' ==\n", osp->name);
|
||||||
|
ast_cli(fd, "Local Private Key: %s\n", osp->localpvtkey);
|
||||||
|
ast_cli(fd, "Local Certificate: %s\n", osp->localcert);
|
||||||
|
for (x=0;x<osp->cacount;x++)
|
||||||
|
ast_cli(fd, "CA Certificate %d: %s\n", x + 1, osp->cacerts[x]);
|
||||||
|
for (x=0;x<osp->spcount;x++)
|
||||||
|
ast_cli(fd, "Service Point %d: %s\n", x + 1, osp->servicepoints[x]);
|
||||||
|
ast_cli(fd, "Max Connections: %d\n", osp->maxconnections);
|
||||||
|
ast_cli(fd, "Retry Delay: %d seconds\n", osp->retrydelay);
|
||||||
|
ast_cli(fd, "Retry Limit: %d\n", osp->retrylimit);
|
||||||
|
ast_cli(fd, "Timeout: %d milliseconds\n", osp->timeout);
|
||||||
|
ast_cli(fd, "Source: %s\n", strlen(osp->source) ? osp->source : "<unspecified>");
|
||||||
|
ast_cli(fd, "OSP Handle: %d\n", osp->handle);
|
||||||
|
found++;
|
||||||
|
}
|
||||||
|
osp = osp->next;
|
||||||
|
}
|
||||||
|
ast_mutex_unlock(&osplock);
|
||||||
|
if (!found) {
|
||||||
|
if (search)
|
||||||
|
ast_cli(fd, "Unable to find OSP provider '%s'\n", search);
|
||||||
|
else
|
||||||
|
ast_cli(fd, "No OSP providers configured\n");
|
||||||
|
}
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------------*
|
||||||
|
* Loads the Certificate *
|
||||||
|
*----------------------------------------------*/
|
||||||
|
static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len)
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
unsigned char *temp;
|
||||||
|
BIO *bioIn = NULL;
|
||||||
|
X509 *cert=NULL;
|
||||||
|
int retVal = OSPC_ERR_NO_ERROR;
|
||||||
|
|
||||||
|
temp = buffer;
|
||||||
|
bioIn = BIO_new_file((const char*)FileName,"r");
|
||||||
|
if (bioIn == NULL)
|
||||||
|
{
|
||||||
|
ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cert = PEM_read_bio_X509(bioIn,NULL,NULL,NULL);
|
||||||
|
if (cert == NULL)
|
||||||
|
{
|
||||||
|
ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s \n",FileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
length = i2d_X509(cert,&temp);
|
||||||
|
if (cert == 0)
|
||||||
|
{
|
||||||
|
ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s, Length=0 \n",FileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*len = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bioIn != NULL)
|
||||||
|
{
|
||||||
|
BIO_free(bioIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cert != NULL)
|
||||||
|
{
|
||||||
|
X509_free(cert);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------*
|
||||||
|
* Loads the Private Key *
|
||||||
|
*----------------------------------------------*/
|
||||||
|
static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len)
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
unsigned char *temp;
|
||||||
|
BIO *bioIn = NULL;
|
||||||
|
RSA *pKey = NULL;
|
||||||
|
int retVal = OSPC_ERR_NO_ERROR;
|
||||||
|
|
||||||
|
temp = buffer;
|
||||||
|
|
||||||
|
bioIn = BIO_new_file((const char*)FileName,"r");
|
||||||
|
if (bioIn == NULL)
|
||||||
|
{
|
||||||
|
ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pKey = PEM_read_bio_RSAPrivateKey(bioIn,NULL,NULL,NULL);
|
||||||
|
if (pKey == NULL)
|
||||||
|
{
|
||||||
|
ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s \n",FileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
length = i2d_RSAPrivateKey(pKey,&temp);
|
||||||
|
if (length == 0)
|
||||||
|
{
|
||||||
|
ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s, Length=0 \n",FileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*len = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bioIn != NULL)
|
||||||
|
{
|
||||||
|
BIO_free(bioIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pKey != NULL)
|
||||||
|
{
|
||||||
|
RSA_free(pKey);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result)
|
||||||
|
{
|
||||||
|
int cres;
|
||||||
|
int res = 0;
|
||||||
|
int counts;
|
||||||
|
int tokenlen;
|
||||||
|
unsigned int dummy=0;
|
||||||
|
unsigned int timelimit;
|
||||||
|
unsigned int callidlen;
|
||||||
|
struct osp_provider *osp;
|
||||||
|
char source[OSP_MAX]; /* Same length as osp->source */
|
||||||
|
char uniqueid[32] = "";
|
||||||
|
char callednum[2048]="";
|
||||||
|
char destination[2048]="";
|
||||||
|
char token[2000];
|
||||||
|
OSPTCALLID *callid;
|
||||||
|
OSPE_DEST_PROT prot;
|
||||||
|
|
||||||
|
result->handle = -1;
|
||||||
|
result->numresults = 0;
|
||||||
|
strcpy(result->tech, "");
|
||||||
|
strcpy(result->dest, "");
|
||||||
|
strcpy(result->token, "");
|
||||||
|
|
||||||
|
if (!provider || !strlen(provider))
|
||||||
|
provider = "default";
|
||||||
|
|
||||||
|
if (!callerid)
|
||||||
|
callerid = "";
|
||||||
|
|
||||||
|
if (chan) {
|
||||||
|
strncpy(uniqueid, chan->uniqueid, sizeof(uniqueid) - 1);
|
||||||
|
cres = ast_autoservice_start(chan);
|
||||||
|
if (cres < 0)
|
||||||
|
return cres;
|
||||||
|
}
|
||||||
|
ast_mutex_lock(&osplock);
|
||||||
|
osp = providers;
|
||||||
|
while(osp) {
|
||||||
|
if (!strcasecmp(osp->name, provider)) {
|
||||||
|
if (OSPPTransactionNew(osp->handle, &result->handle)) {
|
||||||
|
ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
|
||||||
|
} else {
|
||||||
|
strcpy(source, osp->source);
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
osp = osp->next;
|
||||||
|
}
|
||||||
|
ast_mutex_unlock(&osplock);
|
||||||
|
if (res) {
|
||||||
|
res = 0;
|
||||||
|
callid = OSPPCallIdNew(strlen(uniqueid), uniqueid);
|
||||||
|
if (callid) {
|
||||||
|
/* No more than 10 back */
|
||||||
|
counts = 10;
|
||||||
|
dummy = 0;
|
||||||
|
callidlen = sizeof(uniqueid);
|
||||||
|
if (!OSPPTransactionRequestAuthorisation(result->handle, source, "",
|
||||||
|
callerid,OSPC_E164, extension, OSPC_E164, NULL, 1, &callid, NULL, &counts, &dummy, NULL)) {
|
||||||
|
if (counts) {
|
||||||
|
tokenlen = sizeof(token);
|
||||||
|
result->numresults = counts - 1;
|
||||||
|
if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
|
||||||
|
sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
|
||||||
|
ast_log(LOG_DEBUG, "Got destination '%s' and '%s' for '%s' (provider '%s')\n",
|
||||||
|
destination, callednum, extension, provider);
|
||||||
|
do {
|
||||||
|
ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
|
||||||
|
if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
|
||||||
|
res = 1;
|
||||||
|
/* Strip leading and trailing brackets */
|
||||||
|
destination[strlen(destination) - 1] = '\0';
|
||||||
|
switch(prot) {
|
||||||
|
case OSPE_DEST_PROT_H323_SETUP:
|
||||||
|
strcpy(result->tech, "H323");
|
||||||
|
snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
|
||||||
|
break;
|
||||||
|
case OSPE_DEST_PROT_SIP:
|
||||||
|
strcpy(result->tech, "SIP");
|
||||||
|
snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
if (!res && result->numresults) {
|
||||||
|
result->numresults--;
|
||||||
|
if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
|
||||||
|
sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_DEBUG, "Missing destination protocol\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(!res && result->numresults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
OSPPCallIdDelete(&callid);
|
||||||
|
}
|
||||||
|
if (!res) {
|
||||||
|
OSPPTransactionDelete(result->handle);
|
||||||
|
result->handle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!osp)
|
||||||
|
ast_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider);
|
||||||
|
if (chan) {
|
||||||
|
cres = ast_autoservice_stop(chan);
|
||||||
|
if (cres < 0)
|
||||||
|
return cres;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ast_osp_next(struct ast_osp_result *result, int cause)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
int tokenlen;
|
||||||
|
unsigned int dummy=0;
|
||||||
|
unsigned int timelimit;
|
||||||
|
unsigned int callidlen;
|
||||||
|
char uniqueid[32] = "";
|
||||||
|
char callednum[2048]="";
|
||||||
|
char destination[2048]="";
|
||||||
|
char token[2000];
|
||||||
|
OSPE_DEST_PROT prot;
|
||||||
|
|
||||||
|
strcpy(result->tech, "");
|
||||||
|
strcpy(result->dest, "");
|
||||||
|
strcpy(result->token, "");
|
||||||
|
|
||||||
|
if (result->handle > -1) {
|
||||||
|
dummy = 0;
|
||||||
|
callidlen = sizeof(uniqueid);
|
||||||
|
if (result->numresults) {
|
||||||
|
tokenlen = sizeof(token);
|
||||||
|
while(!res && result->numresults) {
|
||||||
|
result->numresults--;
|
||||||
|
if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
|
||||||
|
sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
|
||||||
|
ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
|
||||||
|
if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
|
||||||
|
res = 1;
|
||||||
|
/* Strip leading and trailing brackets */
|
||||||
|
destination[strlen(destination) - 1] = '\0';
|
||||||
|
switch(prot) {
|
||||||
|
case OSPE_DEST_PROT_H323_SETUP:
|
||||||
|
strcpy(result->tech, "H323");
|
||||||
|
snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
|
||||||
|
break;
|
||||||
|
case OSPE_DEST_PROT_SIP:
|
||||||
|
strcpy(result->tech, "SIP");
|
||||||
|
snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_DEBUG, "Missing destination protocol\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!res) {
|
||||||
|
OSPPTransactionDelete(result->handle);
|
||||||
|
result->handle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum OSPEFAILREASON cause2reason(int cause)
|
||||||
|
{
|
||||||
|
switch(cause) {
|
||||||
|
case AST_CAUSE_BUSY:
|
||||||
|
return OSPC_FAIL_USER_BUSY;
|
||||||
|
case AST_CAUSE_CONGESTION:
|
||||||
|
return OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION;
|
||||||
|
case AST_CAUSE_UNALLOCATED:
|
||||||
|
return OSPC_FAIL_UNALLOC_NUMBER;
|
||||||
|
case AST_CAUSE_NOTDEFINED:
|
||||||
|
return OSPC_FAIL_NORMAL_UNSPECIFIED;
|
||||||
|
case AST_CAUSE_NOANSWER:
|
||||||
|
return OSPC_FAIL_NO_ANSWER_FROM_USER;
|
||||||
|
case AST_CAUSE_NORMAL:
|
||||||
|
default:
|
||||||
|
return OSPC_FAIL_NORMAL_CALL_CLEARING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ast_osp_terminate(int handle, int cause, time_t start, time_t duration)
|
||||||
|
{
|
||||||
|
unsigned int dummy = 0;
|
||||||
|
int res = -1;
|
||||||
|
enum OSPEFAILREASON reason;
|
||||||
|
reason = cause2reason(cause);
|
||||||
|
if (OSPPTransactionRecordFailure(handle, reason))
|
||||||
|
ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle);
|
||||||
|
else if (OSPPTransactionReportUsage(handle, duration, start, 0, 0, 0, 0, &dummy, NULL))
|
||||||
|
ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle);
|
||||||
|
else {
|
||||||
|
ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle);
|
||||||
|
OSPPTransactionDelete(handle);
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_load(void)
|
||||||
|
{
|
||||||
|
struct ast_config *cfg;
|
||||||
|
char *cat;
|
||||||
|
struct osp_provider *osp, *prev = NULL, *next;
|
||||||
|
ast_mutex_lock(&osplock);
|
||||||
|
osp = providers;
|
||||||
|
while(osp) {
|
||||||
|
osp->dead = 1;
|
||||||
|
osp = osp->next;
|
||||||
|
}
|
||||||
|
ast_mutex_unlock(&osplock);
|
||||||
|
cfg = ast_load("osp.conf");
|
||||||
|
if (cfg) {
|
||||||
|
if (!initialized) {
|
||||||
|
cat = ast_variable_retrieve(cfg, "general", "accelerate");
|
||||||
|
if (cat && ast_true(cat))
|
||||||
|
if (OSPPInit(1)) {
|
||||||
|
ast_log(LOG_WARNING, "Failed to enable hardware accelleration, falling back to software mode\n");
|
||||||
|
OSPPInit(0);
|
||||||
|
} else
|
||||||
|
hardware = 1;
|
||||||
|
else
|
||||||
|
OSPPInit(0);
|
||||||
|
initialized = 1;
|
||||||
|
}
|
||||||
|
cat = ast_category_browse(cfg, NULL);
|
||||||
|
while(cat) {
|
||||||
|
if (strcasecmp(cat, "general"))
|
||||||
|
osp_build(cfg, cat);
|
||||||
|
cat = ast_category_browse(cfg, cat);
|
||||||
|
}
|
||||||
|
ast_destroy(cfg);
|
||||||
|
} else
|
||||||
|
ast_log(LOG_NOTICE, "No OSP configuration found. OSP support disabled\n");
|
||||||
|
ast_mutex_lock(&osplock);
|
||||||
|
osp = providers;
|
||||||
|
while(osp) {
|
||||||
|
next = osp->next;
|
||||||
|
if (osp->dead) {
|
||||||
|
if (prev)
|
||||||
|
prev->next = next;
|
||||||
|
else
|
||||||
|
providers = next;
|
||||||
|
/* XXX Cleanup OSP structure first XXX */
|
||||||
|
free(osp);
|
||||||
|
} else
|
||||||
|
prev = osp;
|
||||||
|
osp = next;
|
||||||
|
}
|
||||||
|
ast_mutex_unlock(&osplock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char show_osp_usage[] =
|
||||||
|
"Usage: show osp\n"
|
||||||
|
" Displays information on Open Settlement Protocol\n";
|
||||||
|
|
||||||
|
static struct ast_cli_entry cli_show_osp =
|
||||||
|
{ { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage };
|
||||||
|
|
||||||
|
int reload(void)
|
||||||
|
{
|
||||||
|
config_load();
|
||||||
|
ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_module(void)
|
||||||
|
{
|
||||||
|
config_load();
|
||||||
|
ast_cli_register(&cli_show_osp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unload_module(void)
|
||||||
|
{
|
||||||
|
/* Can't unload this once we're loaded */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *description(void)
|
||||||
|
{
|
||||||
|
return "Open Settlement Protocol Support";
|
||||||
|
}
|
||||||
|
|
||||||
|
int usecount(void)
|
||||||
|
{
|
||||||
|
/* We should never be unloaded */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *key()
|
||||||
|
{
|
||||||
|
return ASTERISK_GPL_KEY;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user