Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 17735) +++ channels/chan_sip.c (working copy) @@ -82,10 +82,6 @@ #include "asterisk/devicestate.h" #include "asterisk/linkedlists.h" -#ifdef OSP_SUPPORT -#include "asterisk/astosp.h" -#endif - #ifndef DEFAULT_USERAGENT #define DEFAULT_USERAGENT "Asterisk PBX" #endif @@ -464,7 +460,6 @@ /*! \brief Parameters to the transmit_invite function */ struct sip_invite_param { char *distinctive_ring; /*!< Distinctive ring header */ - char *osptoken; /*!< OSP token for this call */ int addsipheaders; /*!< Add extra SIP headers */ char *uri_options; /*!< URI options to add to the URI */ char *vxml_url; /*!< VXML url for Cisco phones */ @@ -549,23 +544,17 @@ #define SIP_PROG_INBAND_NEVER (0 << 24) #define SIP_PROG_INBAND_NO (1 << 24) #define SIP_PROG_INBAND_YES (2 << 24) -/* Open Settlement Protocol authentication */ -#define SIP_OSPAUTH (3 << 26) /*!< four settings, uses two bits */ -#define SIP_OSPAUTH_NO (0 << 26) -#define SIP_OSPAUTH_GATEWAY (1 << 26) -#define SIP_OSPAUTH_PROXY (2 << 26) -#define SIP_OSPAUTH_EXCLUSIVE (3 << 26) /* Call states */ -#define SIP_CALL_ONHOLD (1 << 28) -#define SIP_CALL_LIMIT (1 << 29) +#define SIP_CALL_ONHOLD (1 << 26) +#define SIP_CALL_LIMIT (1 << 27) /* Remote Party-ID Support */ -#define SIP_SENDRPID (1 << 30) +#define SIP_SENDRPID (1 << 28) /* Did this connection increment the counter of in-use calls? */ -#define SIP_INC_COUNT (1 << 31) +#define SIP_INC_COUNT (1 << 29) #define SIP_FLAGS_TO_COPY \ (SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_SENDRPID | SIP_DTMF | SIP_REINVITE | \ - SIP_PROG_INBAND | SIP_OSPAUTH | SIP_USECLIENTCODE | SIP_NAT | \ + SIP_PROG_INBAND | SIP_USECLIENTCODE | SIP_NAT | \ SIP_USEREQPHONE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE) /* a new page of flags for peer */ @@ -659,11 +648,6 @@ char lastmsg[256]; /*!< Last Message sent/received */ int amaflags; /*!< AMA Flags */ int pendinginvite; /*!< Any pending invite */ -#ifdef OSP_SUPPORT - int osphandle; /*!< OSP Handle for call */ - time_t ospstart; /*!< OSP Start time */ - unsigned int osptimelimit; /*!< OSP call duration limit */ -#endif struct sip_request initreq; /*!< Initial request */ int maxtime; /*!< Max time for first response */ @@ -2005,9 +1989,6 @@ { int res; struct sip_pvt *p; -#ifdef OSP_SUPPORT - char *osphandle = NULL; -#endif struct varshead *headp; struct ast_var_t *current; @@ -2036,28 +2017,10 @@ /* Check whether there is a variable with a name starting with SIPADDHEADER */ p->options->addsipheaders = 1; } - - -#ifdef OSP_SUPPORT - else if (!p->options->osptoken && !strcasecmp(ast_var_name(current), "OSPTOKEN")) { - p->options->osptoken = ast_var_value(current); - } else if (!osphandle && !strcasecmp(ast_var_name(current), "OSPHANDLE")) { - osphandle = ast_var_value(current); - } -#endif } res = 0; ast_set_flag(p, SIP_OUTGOING); -#ifdef OSP_SUPPORT - if (!p->options->osptoken || !osphandle || (sscanf(osphandle, "%d", &p->osphandle) != 1)) { - /* Force Disable OSP support */ - ast_log(LOG_DEBUG, "Disabling OSP support for this call. osptoken = %s, osphandle = %s\n", p->options->osptoken, osphandle); - p->options->osptoken = NULL; - osphandle = NULL; - p->osphandle = -1; - } -#endif ast_log(LOG_DEBUG, "Outgoing Call for %s\n", p->username); res = update_call_counter(p, INC_CALL_LIMIT); if ( res != -1 ) { @@ -2411,11 +2374,6 @@ ast_log(LOG_DEBUG, "Hangup call %s, SIP callid %s)\n", ast->name, p->callid); 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 ast_log(LOG_DEBUG, "update_call_counter(%s) - decrement call limit counter\n", p->username); update_call_counter(p, DEC_CALL_LIMIT); /* Determine how to disconnect */ @@ -2517,9 +2475,6 @@ ast_mutex_lock(&p->lock); if (ast->_state != AST_STATE_UP) { -#ifdef OSP_SUPPORT - time(&p->ospstart); -#endif try_suggested_sip_codec(p); ast_setstate(ast, AST_STATE_UP); @@ -2735,10 +2690,6 @@ struct ast_channel *tmp; struct ast_variable *v = NULL; int fmt; -#ifdef OSP_SUPPORT - char iabuf[INET_ADDRSTRLEN]; - char peer[MAXHOSTNAMELEN]; -#endif ast_mutex_unlock(&i->lock); /* Don't hold a sip pvt lock while we allocate a channel */ @@ -2828,10 +2779,6 @@ if (!ast_strlen_zero(i->callid)) { pbx_builtin_setvar_helper(tmp, "SIPCALLID", i->callid); } -#ifdef OSP_SUPPORT - snprintf(peer, sizeof(peer), "[%s]:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), i->sa.sin_addr), ntohs(i->sa.sin_port)); - pbx_builtin_setvar_helper(tmp, "OSPPEER", peer); -#endif ast_setstate(tmp, state); if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { @@ -3048,10 +2995,6 @@ p->prefs = prefs; if (intended_method != SIP_OPTIONS) /* Peerpoke has it's own system */ p->timer_t1 = 500; /* Default SIP retransmission timer T1 (RFC 3261) */ -#ifdef OSP_SUPPORT - p->osphandle = -1; - p->osptimelimit = 0; -#endif if (sin) { memcpy(&p->sa, sin, sizeof(p->sa)); if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip)) @@ -4887,12 +4830,6 @@ if (!ast_strlen_zero(p->referred_by)) add_header(&req, "Referred-By", p->referred_by); } -#ifdef OSP_SUPPORT - if ((req.method != SIP_OPTIONS) && p->options && !ast_strlen_zero(p->options->osptoken)) { - ast_log(LOG_DEBUG,"Adding OSP Token: %s\n", p->options->osptoken); - add_header(&req, "P-OSP-Auth-Token", p->options->osptoken); - } -#endif if (p->options && !ast_strlen_zero(p->options->distinctive_ring)) { add_header(&req, "Alert-Info", p->options->distinctive_ring); @@ -6077,22 +6014,6 @@ list_route(p->route); } -#ifdef OSP_SUPPORT -/*! \brief check_osptoken: Validate OSP token for user authrroization ---*/ -static int check_osptoken (struct sip_pvt *p, char *token) -{ - char tmp[80]; - - if (ast_osp_validate (NULL, token, &p->osphandle, &p->osptimelimit, p->cid_num, p->sa.sin_addr, p->exten) < 1) { - return (-1); - } else { - snprintf (tmp, sizeof (tmp), "%d", p->osphandle); - pbx_builtin_setvar_helper (p->owner, "_OSPHANDLE", tmp); - return (0); - } -} -#endif - /*! \brief check_auth: Check user authorization from peer definition ---*/ /* Some actions, like REGISTER and INVITEs from peers require authentication (if peer have secret set) */ @@ -6103,16 +6024,8 @@ char *reqheader = "Proxy-Authorization"; char *respheader = "Proxy-Authenticate"; char *authtoken; -#ifdef OSP_SUPPORT - char *osptoken; -#endif /* Always OK if no secret */ - if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret) -#ifdef OSP_SUPPORT - && !ast_test_flag(p, SIP_OSPAUTH) - && global_allowguest != 2 -#endif - ) + if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret)) return 0; if (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) { /* On a REGISTER, we have to use 401 and its family of headers instead of 407 and its family @@ -6122,44 +6035,6 @@ reqheader = "Authorization"; respheader = "WWW-Authenticate"; } -#ifdef OSP_SUPPORT - else { - ast_log (LOG_DEBUG, "Checking OSP Authentication!\n"); - osptoken = get_header (req, "P-OSP-Auth-Token"); - switch (ast_test_flag (p, SIP_OSPAUTH)) { - case SIP_OSPAUTH_NO: - break; - case SIP_OSPAUTH_GATEWAY: - if (ast_strlen_zero (osptoken)) { - if (ast_strlen_zero (secret) && ast_strlen_zero (md5secret)) { - return (0); - } - } - else { - return (check_osptoken (p, osptoken)); - } - break; - case SIP_OSPAUTH_PROXY: - if (ast_strlen_zero (osptoken)) { - return (0); - } - else { - return (check_osptoken (p, osptoken)); - } - break; - case SIP_OSPAUTH_EXCLUSIVE: - if (ast_strlen_zero (osptoken)) { - return (-1); - } - else { - return (check_osptoken (p, osptoken)); - } - break; - default: - return (-1); - } - } -#endif authtoken = get_header(req, reqheader); if (ignore && !ast_strlen_zero(randdata) && ast_strlen_zero(authtoken)) { /* This is a retransmitted invite/register/etc, don't reconstruct authentication @@ -7200,12 +7075,6 @@ /* do we allow guests? */ if (!global_allowguest) res = -1; /* we don't want any guests, authentication will fail */ -#ifdef OSP_SUPPORT - else if (global_allowguest == 2) { - ast_copy_flags(p, &global_flags, SIP_OSPAUTH); - res = check_auth(p, req, p->randdata, sizeof(p->randdata), "", "", "", sipmethod, uri, reliable, ignore); - } -#endif } } @@ -8182,11 +8051,6 @@ ast_cli(fd, " Record SIP history: %s\n", recordhistory ? "On" : "Off"); ast_cli(fd, " Call Events: %s\n", callevents ? "On" : "Off"); ast_cli(fd, " IP ToS: 0x%x\n", tos); -#ifdef OSP_SUPPORT - ast_cli(fd, " OSP Support: Yes\n"); -#else - ast_cli(fd, " OSP Support: No\n"); -#endif if (!realtimepeers && !realtimeusers) ast_cli(fd, " SIP realtime: Disabled\n" ); else @@ -9513,9 +9377,6 @@ if (!ignore && p->owner) { if (p->owner->_state != AST_STATE_UP) { -#ifdef OSP_SUPPORT - time(&p->ospstart); -#endif ast_queue_control(p->owner, AST_CONTROL_ANSWER); } else { /* RE-invite */ struct ast_frame af = { AST_FRAME_NULL, }; @@ -10260,6 +10121,9 @@ char *supported; char *required; unsigned int required_profile = 0; + char *token; + char buffer[256]; + char iabuf[INET_ADDRSTRLEN]; /* Find out what they support */ if (!p->sipoptions) { @@ -10411,9 +10275,12 @@ if (!ignore && p) p->lastinvite = seqno; if (c) { -#ifdef OSP_SUPPORT - ast_channel_setwhentohangup (c, p->osptimelimit); -#endif + token = get_header(req, "P-OSP-Auth-Token"); + if (!ast_strlen_zero(token)) { + pbx_builtin_setvar_helper(c, "SIPTOKEN", token); + } + snprintf(buffer, sizeof(buffer), "[%s]", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr)); + pbx_builtin_setvar_helper(c, "SIPPEERIP", buffer); switch(c->_state) { case AST_STATE_DOWN: transmit_response(p, "100 Trying", req); @@ -11695,26 +11562,10 @@ else if (strcasecmp(v->value, "never")) ast_set_flag(flags, SIP_PROG_INBAND_NO); } else if (!strcasecmp(v->name, "allowguest")) { -#ifdef OSP_SUPPORT - if (!strcasecmp(v->value, "osp")) - global_allowguest = 2; - else -#endif if (ast_true(v->value)) global_allowguest = 1; else global_allowguest = 0; -#ifdef OSP_SUPPORT - } else if (!strcasecmp(v->name, "ospauth")) { - ast_set_flag(mask, SIP_OSPAUTH); - ast_clear_flag(flags, SIP_OSPAUTH); - if (!strcasecmp(v->value, "proxy")) - ast_set_flag(flags, SIP_OSPAUTH_PROXY); - else if (!strcasecmp(v->value, "gateway")) - ast_set_flag(flags, SIP_OSPAUTH_GATEWAY); - else if(!strcasecmp (v->value, "exclusive")) - ast_set_flag(flags, SIP_OSPAUTH_EXCLUSIVE); -#endif } else if (!strcasecmp(v->name, "promiscredir")) { ast_set_flag(mask, SIP_PROMISCREDIR); ast_set2_flag(flags, ast_true(v->value), SIP_PROMISCREDIR); Index: apps/app_dial.c =================================================================== --- apps/app_dial.c (revision 17735) +++ apps/app_dial.c (working copy) @@ -1176,10 +1176,6 @@ } if (peer) { time(&answer_time); -#ifdef OSP_SUPPORT - /* Once call is answered, ditch the OSP Handle */ - pbx_builtin_setvar_helper(chan, "_OSPHANDLE", ""); -#endif strcpy(status, "ANSWER"); /* 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 Index: apps/app_osplookup.c =================================================================== --- apps/app_osplookup.c (revision 17735) +++ apps/app_osplookup.c (working copy) @@ -16,10 +16,9 @@ * at the top of the source tree. */ -/*! \file - * - * \brief Open Settlement Protocol Lookup - * +/*! + * \file + * \brief Open Settlement Protocol Applications * \ingroup applications */ @@ -47,44 +46,55 @@ #include "asterisk/app.h" #include "asterisk/options.h" -static char *tdesc = "OSP Lookup"; +static char *app1= "OSPAuth"; +static char *synopsis1 = "OSP authentication"; +static char *descrip1 = +" OSPAuth([provider[|options]]): Authenticate a SIP INVITE by OSP and sets\n" +"the variables:\n" +" ${OSPINHANDLE}: The in_bound call transaction handle\n" +" ${OSPINTIMELIMIT}: The in_bound call duration limit in seconds\n" +"\n" +"The option string may contain the following character:\n" +" 'j' -- jump to n+101 priority if the authentication was NOT successful\n" +"This application sets the following channel variable upon completion:\n" +" OSPAUTHSTATUS The status of the OSP Auth attempt as a text string, one of\n" +" SUCCESS | FAILED | ERROR\n"; -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 = +static char *app2= "OSPLookup"; +static char *synopsis2 = "Lookup destination by OSP"; +static char *descrip2 = " 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" +" ${OSPOUTHANDLE}: The OSP Handle for anything remaining\n" +" ${OSPTECH}: The technology to use for the call\n" +" ${OSPDEST}: The destination to use for the call\n" +" ${OSPCALLING}: The calling number to use for the call\n" +" ${OSPOUTTOKEN}: The actual OSP token as a string\n" +" ${OSPOUTTIMELIMIT}: The out_bound call duration limit in seconds\n" +" ${OSPRESULTS}: The number of OSP results total remaining\n" "\n" "The option string may contain the following character:\n" " 'j' -- jump to n+101 priority if the lookup was NOT successful\n" "This application sets the following channel variable upon completion:\n" " OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n" -" SUCCESS | FAILED \n"; +" SUCCESS | FAILED | ERROR\n"; - -static char *descrip2 = -" OSPNext(cause[|options]): Looks up the next OSP Destination for ${OSPHANDLE}\n" +static char *app3 = "OSPNext"; +static char *synopsis3 = "Lookup next destination by OSP"; +static char *descrip3 = +" OSPNext(cause[|options]): Looks up the next OSP Destination for ${OSPOUTHANDLE}\n" "See OSPLookup for more information\n" "\n" "The option string may contain the following character:\n" " 'j' -- jump to n+101 priority if the lookup was NOT successful\n" "This application sets the following channel variable upon completion:\n" " OSPNEXTSTATUS The status of the OSP Next attempt as a text string, one of\n" -" SUCCESS | FAILED \n"; +" SUCCESS | FAILED |ERROR\n"; -static char *descrip3 = -" OSPFinish(status[|options]): Records call state for ${OSPHANDLE}, according to\n" +static char *app4 = "OSPFinish"; +static char *synopsis4 = "Record OSP entry"; +static char *descrip4 = +" OSPFinish([status[|options]]): Records call state for ${OSPINHANDLE}, according to\n" "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n" "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n" "\n" @@ -92,284 +102,551 @@ " 'j' -- jump to n+101 priority if the finish attempt was NOT successful\n" "This application sets the following channel variable upon completion:\n" " OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n" -" SUCCESS | FAILED \n"; +" SUCCESS | FAILED |ERROR \n"; STANDARD_LOCAL_USER; LOCAL_USER_DECL; -static int str2cause(char *cause) +static int ospauth_exec(struct ast_channel *chan, void *data) { - 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; + int res = 0; + struct localuser* u; + char* provider = OSP_DEF_PROVIDER; + int priority_jump = 0; + struct varshead* headp; + struct ast_var_t* current; + char* source = ""; + char* token = ""; + int handle; + unsigned int timelimit; + char* tmp; + char buffer[OSP_INTSTR_SIZE]; + char* status; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(provider); + AST_APP_ARG(options); + ); + + LOCAL_USER_ADD(u); + + if (!(tmp = ast_strdupa(data))) { + ast_log(LOG_ERROR, "Out of memory\n"); + LOCAL_USER_REMOVE(u); + return(-1); + } + + AST_STANDARD_APP_ARGS(args, tmp); + + if (!ast_strlen_zero(args.provider)) { + provider = args.provider; + } + ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider); + + if (args.options) { + if (strchr(args.options, 'j')) { + priority_jump = 1; + } + } + ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump); + + headp = &chan->varshead; + AST_LIST_TRAVERSE(headp, current, entries) { + if (!strcasecmp(ast_var_name(current), "SIPPEERIP")) { + source = ast_var_value(current); + } else if (!strcasecmp(ast_var_name(current), "SIPTOKEN")) { + token = ast_var_value(current); + } + } + ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source); + ast_log(LOG_DEBUG, "OSPAuth: token size '%d'\n", strlen(token)); + + res = ast_osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit); + if (res > 0) { + status = OSP_APP_SUCCESS; + } else { + timelimit = OSP_DEF_TIMELIMIT; + if (!res) { + status = OSP_APP_FAILED; + } else { + handle = OSP_INVALID_HANDLE; + status = OSP_APP_ERROR; + } + } + + snprintf(buffer, sizeof(buffer), "%d", handle); + pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer); + ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer); + snprintf(buffer, sizeof(buffer), "%d", timelimit); + pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer); + ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer); + pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status); + ast_log(LOG_DEBUG, "OSPAuth: %s\n", status); + + if(!res) { + if (priority_jump || option_priority_jumping) { + ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); + } else { + res = -1; + } + } else if (res > 0) { + res = 0; + } + + LOCAL_USER_REMOVE(u); + + return(res); } static int osplookup_exec(struct ast_channel *chan, void *data) { - int res=0; - struct localuser *u; - char *temp; + int res = 0; + struct localuser* u; + char* provider = OSP_DEF_PROVIDER; + int priority_jump = 0; + struct varshead* headp; + struct ast_var_t* current; + char* srcdev = ""; + char* tmp; + char buffer[OSP_TOKSTR_SIZE]; struct ast_osp_result result; - int priority_jump = 0; + char* status; + AST_DECLARE_APP_ARGS(args, - AST_APP_ARG(extension); + AST_APP_ARG(exten); AST_APP_ARG(provider); AST_APP_ARG(options); ); if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "OSPLookup requires an argument OSPLookup(exten[|provider[|options]])\n"); - return -1; + ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n"); + return(-1); } LOCAL_USER_ADD(u); - temp = ast_strdupa(data); - if (!temp) { - ast_log(LOG_ERROR, "Out of memory!\n"); + tmp = ast_strdupa(data); + if (!tmp) { + ast_log(LOG_ERROR, "Out of memory\n"); LOCAL_USER_REMOVE(u); - return -1; + return(-1); } - AST_STANDARD_APP_ARGS(args, temp); + AST_STANDARD_APP_ARGS(args, tmp); + ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten); + + if (!ast_strlen_zero(args.provider)) { + provider = args.provider; + } + ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider); + if (args.options) { - if (strchr(args.options, 'j')) + if (strchr(args.options, 'j')) { priority_jump = 1; + } } + ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump); - ast_log(LOG_DEBUG, "Whoo hoo, looking up OSP on '%s' via '%s'\n", args.extension, args.provider ? args.provider : ""); - if ((res = ast_osp_lookup(chan, args.provider, args.extension, chan->cid.cid_num, &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); - pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", "SUCCESS"); + result.inhandle = OSP_INVALID_HANDLE; + headp = &chan->varshead; + AST_LIST_TRAVERSE(headp, current, entries) { + if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) { + if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) { + result.inhandle = OSP_INVALID_HANDLE; + } + } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) { + if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) { + result.intimelimit = OSP_DEF_TIMELIMIT; + } + } else if (!strcasecmp(ast_var_name(current), "SIPPEERIP")) { + srcdev = ast_var_value(current); + } + } + ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle); + ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit); + ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev); + + res = ast_osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, &result); + if (res > 0) { + status = OSP_APP_SUCCESS; } else { + result.tech[0] = '\0'; + result.dest[0] = '\0'; + result.calling[0] = '\0'; + result.token[0] = '\0'; + result.numresults = 0; + result.outtimelimit = OSP_DEF_TIMELIMIT; if (!res) { - ast_log(LOG_NOTICE, "OSP Lookup failed for '%s' (provider '%s')\n", args.extension, args.provider ? args.provider : ""); - pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", "FAILED"); - } else - ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Lookup for '%s' (provider '%s')!\n", chan->name, args.extension, args.provider ? args.provider : "" ); + status = OSP_APP_FAILED; + } else { + result.outhandle = OSP_INVALID_HANDLE; + status = OSP_APP_ERROR; + } } - if (!res) { - /* Look for a "busy" place */ - if (priority_jump || option_priority_jumping) + + snprintf(buffer, sizeof(buffer), "%d", result.outhandle); + pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer); + ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer); + pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech); + ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech); + pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest); + ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest); + pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling); + ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling); + pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token); + ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%d'\n", strlen(result.token)); + if (!ast_strlen_zero(result.token)) { + snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token); + pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer); + ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%d'\n", strlen(buffer)); + } + snprintf(buffer, sizeof(buffer), "%d", result.numresults); + pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer); + ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer); + snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit); + pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer); + ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer); + pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status); + ast_log(LOG_DEBUG, "OSPLookup: %s\n", status); + + if(!res) { + if (priority_jump || option_priority_jumping) { ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); - } else if (res > 0) + } else { + res = -1; + } + } else if (res > 0) { res = 0; + } + LOCAL_USER_REMOVE(u); - return res; + + return(res); } +static int str2cause(char *str) +{ + int cause = AST_CAUSE_NORMAL; + + if (ast_strlen_zero(str)) { + cause = AST_CAUSE_NOTDEFINED; + } else if (!strcasecmp(str, "BUSY")) { + cause = AST_CAUSE_BUSY; + } else if (!strcasecmp(str, "CONGESTION")) { + cause = AST_CAUSE_CONGESTION; + } else if (!strcasecmp(str, "ANSWER")) { + cause = AST_CAUSE_NORMAL; + } else if (!strcasecmp(str, "CANCEL")) { + cause = AST_CAUSE_NORMAL; + } else if (!strcasecmp(str, "NOANSWER")) { + cause = AST_CAUSE_NOANSWER; + } else if (!strcasecmp(str, "NOCHANAVAIL")) { + cause = AST_CAUSE_CONGESTION; + } else { + ast_log(LOG_WARNING, "OSP: Unknown cause '%s', using NORMAL\n", str); + } + + return(cause); +} + static int ospnext_exec(struct ast_channel *chan, void *data) { int res=0; struct localuser *u; - char *temp; + int priority_jump = 0; int cause; + struct varshead* headp; + struct ast_var_t* current; struct ast_osp_result result; - int priority_jump = 0; + char *tmp; + char buffer[OSP_TOKSTR_SIZE]; + char* status; + AST_DECLARE_APP_ARGS(args, AST_APP_ARG(cause); AST_APP_ARG(options); ); if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "OSPNext should have an argument (cause[|options])\n"); - return -1; + ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|options])\n"); + return(-1); } LOCAL_USER_ADD(u); - temp = ast_strdupa(data); - if (!temp) { - ast_log(LOG_ERROR, "Out of memory!\n"); + tmp = ast_strdupa(data); + if (!tmp) { + ast_log(LOG_ERROR, "Out of memory\n"); LOCAL_USER_REMOVE(u); - return -1; + return(-1); } - AST_STANDARD_APP_ARGS(args, temp); + AST_STANDARD_APP_ARGS(args, tmp); + cause = str2cause(args.cause); + ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause); + if (args.options) { if (strchr(args.options, 'j')) priority_jump = 1; } + ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump); - cause = str2cause(args.cause); - temp = pbx_builtin_getvar_helper(chan, "OSPHANDLE"); - result.handle = -1; - if (!ast_strlen_zero(temp) && (sscanf(temp, "%d", &result.handle) == 1) && (result.handle > -1)) { - temp = pbx_builtin_getvar_helper(chan, "OSPRESULTS"); - if (ast_strlen_zero(temp) || (sscanf(temp, "%d", &result.numresults) != 1)) { - result.numresults = 0; + result.inhandle = OSP_INVALID_HANDLE; + result.outhandle = OSP_INVALID_HANDLE; + result.numresults = 0; + + headp = &chan->varshead; + AST_LIST_TRAVERSE(headp, current, entries) { + if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) { + if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) { + result.inhandle = OSP_INVALID_HANDLE; + } + } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) { + if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) { + result.outhandle = OSP_INVALID_HANDLE; + } + } else if (!strcasecmp(ast_var_name(current), "OSPINTIMEOUT")) { + if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) { + result.intimelimit = OSP_DEF_TIMELIMIT; + } + } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) { + if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) { + result.numresults = 0; + } } - 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); - pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", "SUCCESS"); - } + } + ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle); + ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle); + ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit); + ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults); + + if ((res = ast_osp_next(cause, &result)) > 0) { + status = OSP_APP_SUCCESS; } else { + result.tech[0] = '\0'; + result.dest[0] = '\0'; + result.calling[0] = '\0'; + result.token[0] = '\0'; + result.numresults = 0; + result.outtimelimit = OSP_DEF_TIMELIMIT; 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"); - pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", "FAILED"); - } else - ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Next!\n", chan->name); + status = OSP_APP_FAILED; + } else { + result.outhandle = OSP_INVALID_HANDLE; + status = OSP_APP_ERROR; + } } - if (!res) { - /* Look for a "busy" place */ - if (priority_jump || option_priority_jumping) + + pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech); + ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech); + pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest); + ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest); + pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling); + ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling); + pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token); + ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%d'\n", strlen(result.token)); + if (!ast_strlen_zero(result.token)) { + snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token); + pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer); + ast_log(LOG_DEBUG, "OSPNext: SIPADDHEADER size '%d'\n", strlen(buffer)); + } + snprintf(buffer, sizeof(buffer), "%d", result.numresults); + pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer); + ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer); + snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit); + pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer); + ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer); + pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status); + ast_log(LOG_DEBUG, "OSPNext: %s\n", status); + + if(!res) { + if (priority_jump || option_priority_jumping) { ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); - } else if (res > 0) + } else { + res = -1; + } + } else if (res > 0) { res = 0; + } + LOCAL_USER_REMOVE(u); - return res; + + return(res); } static int ospfinished_exec(struct ast_channel *chan, void *data) { - int res=0; - struct localuser *u; - char *temp; + int res = 1; + struct localuser* u; + int priority_jump = 0; int cause; - time_t start=0, duration=0; - struct ast_osp_result result; - int priority_jump = 0; + struct varshead* headp; + struct ast_var_t* current; + int inhandle = OSP_INVALID_HANDLE; + int outhandle = OSP_INVALID_HANDLE; + int recorded = 0; + time_t start, connect, end; + char* tmp; + char* str = ""; + char buffer[OSP_INTSTR_SIZE]; + char* status; + AST_DECLARE_APP_ARGS(args, AST_APP_ARG(status); AST_APP_ARG(options); ); - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "OSPFinish should have an argument (status[|options])\n"); - return -1; - } - LOCAL_USER_ADD(u); - temp = ast_strdupa(data); - if (!temp) { - ast_log(LOG_ERROR, "Out of memory!\n"); + tmp = ast_strdupa(data); + if (!tmp) { + ast_log(LOG_ERROR, "Out of memory\n"); LOCAL_USER_REMOVE(u); - return -1; + return(-1); } - AST_STANDARD_APP_ARGS(args, temp); + AST_STANDARD_APP_ARGS(args, tmp); if (args.options) { if (strchr(args.options, 'j')) priority_jump = 1; } + ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump); + headp = &chan->varshead; + AST_LIST_TRAVERSE(headp, current, entries) { + if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) { + if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) { + inhandle = OSP_INVALID_HANDLE; + } + } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) { + if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) { + outhandle = OSP_INVALID_HANDLE; + } + } else if (!recorded && + (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") || + !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") || + !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS"))) + { + if (strcasecmp(ast_var_value(current), OSP_APP_SUCCESS)) { + recorded = 1; + } + } + } + ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle); + ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle); + ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded); + + if (!recorded) { + str = args.status; + } + cause = str2cause(str); + ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause); + if (chan->cdr) { - start = chan->cdr->answer.tv_sec; - if (start) - duration = time(NULL) - start; - else - duration = 0; - } else - ast_log(LOG_WARNING, "OSPFinish called on channel '%s' with no CDR!\n", chan->name); - - cause = str2cause(args.status); - temp = pbx_builtin_getvar_helper(chan, "OSPHANDLE"); - result.handle = -1; - if (!ast_strlen_zero(temp) && (sscanf(temp, "%d", &result.handle) == 1) && (result.handle > -1)) { - if (!ast_osp_terminate(result.handle, cause, start, duration)) { - pbx_builtin_setvar_helper(chan, "_OSPHANDLE", ""); - pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", "SUCCESS"); - res = 1; + start = chan->cdr->start.tv_sec; + connect = chan->cdr->answer.tv_sec; + if (connect) { + end = time(NULL); + } else { + end = connect; } } 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"); - pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", "FAILED"); - } else - ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Terminate!\n", chan->name); + start = 0; + connect = 0; + end = 0; } - if (!res) { - /* Look for a "busy" place */ - if (priority_jump || option_priority_jumping) + ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start); + ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect); + ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end); + + if (ast_osp_finish(outhandle, cause, start, connect, end) <= 0) { + ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for out_bound call\n"); + } + if (ast_osp_finish(inhandle, cause, start, connect, end) <= 0) { + ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for in_bound call\n"); + } + snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE); + pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer); + pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer); + + if (res > 0) { + status = OSP_APP_SUCCESS; + } else if (!res) { + status = OSP_APP_FAILED; + } else { + status = OSP_APP_ERROR; + } + pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status); + + if(!res) { + if (priority_jump || option_priority_jumping) { ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); - } else if (res > 0) + } else { + res = -1; + } + } else if (res > 0) { res = 0; + } + LOCAL_USER_REMOVE(u); - return res; + + return(res); } +int load_module(void) +{ + int res; + + ast_osp_adduse(); + res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1); + res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2); + res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3); + res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4); + + return(res); +} + int unload_module(void) { int res; - res = ast_unregister_application(app3); + res = ast_unregister_application(app4); + res |= ast_unregister_application(app3); res |= ast_unregister_application(app2); - res |= ast_unregister_application(app); + res |= ast_unregister_application(app1); STANDARD_HANGUP_LOCALUSERS; - return res; -} + ast_osp_deluse(); -int load_module(void) -{ - int res; - - res = ast_register_application(app, osplookup_exec, synopsis, descrip); - res |= ast_register_application(app2, ospnext_exec, synopsis2, descrip2); - res |= ast_register_application(app3, ospfinished_exec, synopsis3, descrip3); - - return res; + return(res); } int reload(void) { - return 0; + return(0); } - char *description(void) { - return tdesc; + return("Open Settlement Protocol Applications"); } int usecount(void) { int res; STANDARD_USECOUNT(res); - return res; + return(res); } char *key() { - return ASTERISK_GPL_KEY; + return(ASTERISK_GPL_KEY); } Index: doc/README.variables =================================================================== --- doc/README.variables (revision 17735) +++ doc/README.variables (working copy) @@ -610,6 +610,7 @@ ${ENUMSTATUS} * enumlookup() ${HASVMSTATUS} * hasnewvoicemail() ${LOOKUPBLSTATUS} * lookupblacklist() +${OSPAUTHSTATUS} * ospauth() ${OSPLOOKUPSTATUS} * osplookup() ${OSPNEXTSTATUS} * ospnext() ${OSPFINISHSTATUS} * ospfinish() @@ -747,14 +748,17 @@ ${MACRO_PRIORITY} * The calling priority ${MACRO_OFFSET} Offset to add to priority at return from macro -If you compile with OSP support in the SIP channel, these -variables are used: +If you compile with OSP support, these variables are used: --------------------------------------------------------- -${OSPHANDLE} Handle from the OSP Library -${OSPTECH} OSP Technology from Library -${OSPDEST} OSP Destination from Library -${OSPTOKEN} OSP Token to use for call from Library -${OSPRESULTS} Number of OSP results +${OSPINHANDLE} OSP handle of in_bound call +${OSPINTIMELIMIT} Duration limit for in_bound call +${OSPOUTHANDLE} OSP handle of out_bound call +${OSPTECH} OSP technology +${OSPDEST} OSP destination +${OSPCALLING} OSP calling number +${OSPOUTTOKEN} OSP token to use for out_bound call +${OSPOUTTIMELIMIT} Duration limit for out_bound call +${OSPRESULTS} Number of remained destinations ____________________________________ CDR Variables Index: include/asterisk/astosp.h =================================================================== --- include/asterisk/astosp.h (revision 17735) +++ include/asterisk/astosp.h (working copy) @@ -16,33 +16,111 @@ * at the top of the source tree. */ -/*! \file +/*! + * \file * \brief OSP support (Open Settlement Protocol) */ #ifndef _ASTERISK_OSP_H #define _ASTERISK_OSP_H -#include "asterisk/channel.h" +#include #include -#include +#include "asterisk/channel.h" + +#define OSP_DEF_PROVIDER ((char*)"default") /* Default provider context name */ +#define OSP_INVALID_HANDLE ((int)-1) /* Invalid OSP handle, provider, transaction etc. */ +#define OSP_DEF_TIMELIMIT ((unsigned int)0) /* Default duration limit, no limit */ + +#define OSP_INTSTR_SIZE ((unsigned int)16) /* Signed/unsigned int string buffer size */ +#define OSP_NORSTR_SIZE ((unsigned int)256) /* Normal string buffer size */ +#define OSP_TOKSTR_SIZE ((unsigned int)4096) /* Token string buffer size */ + +#define OSP_APP_SUCCESS ((char*)"SUCCESS") /* Return status, success */ +#define OSP_APP_FAILED ((char*)"FAILED") /* Return status, failed */ +#define OSP_APP_ERROR ((char*)"ERROR") /* Return status, error */ + struct ast_osp_result { - int handle; + int inhandle; + int outhandle; + unsigned int intimelimit; + unsigned int outtimelimit; + char tech[20]; + char dest[OSP_NORSTR_SIZE]; + char calling[OSP_NORSTR_SIZE]; + char token[OSP_TOKSTR_SIZE]; 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); +/*! + * \brief OSP Increase Use Count function + */ +void ast_osp_adduse(void); +/*! + * \brief OSP Decrease Use Count function + */ +void ast_osp_deluse(void); +/*! + * \brief OSP Authentication function + * \param provider OSP provider context name + * \param transaction OSP transaction handle, output + * \param source Source of in_bound call + * \param calling Calling number + * \param called Called number + * \param token OSP token, may be empty + * \param timelimit Call duration limit, output + * \return 1 Authenricated, 0 Unauthenticated, -1 Error + */ +int ast_osp_auth( + const char* provider, /* OSP provider context name */ + int* transaction, /* OSP transaction handle, output */ + const char* source, /* Source of in_bound call */ + const char* calling, /* Calling number */ + const char* called, /* Called number */ + const char* token, /* OSP token, may be empty */ + unsigned int* timelimit /* Call duration limit, output */ +); +/*! + * \brief OSP Lookup function + * \param provider OSP provider context name + * \param srcdev Source device of out_bound call + * \param calling Calling number + * \param called Called number + * \param result Lookup results + * \return 1 Found , 0 No route, -1 Error + */ +int ast_osp_lookup( + const char* provider, /* OSP provider conttext name */ + const char* srcdev, /* Source device of out_bound call */ + const char* calling, /* Calling number */ + const char* called, /* Called number */ + struct ast_osp_result* result /* OSP lookup results, output */ +); +/*! + * \brief OSP Next function + * \param reason Last destination failure reason + * \param result Lookup results, in/output + * \return 1 Found , 0 No route, -1 Error + */ +int ast_osp_next( + int reason, /* Last destination failure reason */ + struct ast_osp_result *result /* OSP lookup results, in/output */ +); +/*! + * \brief OSP Finish function + * \param handle OSP in/out_bound transaction handle + * \param reason Last destination failure reason + * \param start Call start time + * \param duration Call duration + * \return 1 Success, 0 Failed, -1 Error + */ +int ast_osp_finish( + int handle, /* OSP in/out_bound transaction handle */ + int reason, /* Last destination failure reason */ + time_t start, /* Call start time */ + time_t connect, /* Call connect time */ + time_t end /* Call end time */ +); -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); - -int ast_osp_validate(char *provider, char *token, int *handle, unsigned int *timeout, char *callerid, struct in_addr addr, char *extension); - #endif /* _ASTERISK_OSP_H */ Index: configs/osp.conf.sample =================================================================== --- configs/osp.conf.sample (revision 17735) +++ configs/osp.conf.sample (working copy) @@ -62,3 +62,11 @@ ; Set the "source" for requesting authorization ; ;source=foo +; +; Set the authentication policy. +; 0 - NO +; 1 - YES +; 2 - EXCLUSIVE +; Default is 1, validate token but allow no token. +; +;authpolicy=1 Index: res/res_osp.c =================================================================== --- res/res_osp.c (revision 17735) +++ res/res_osp.c (working copy) @@ -16,15 +16,15 @@ * at the top of the source tree. */ -/*! \file - * +/*! + * \file * \brief Provide Open Settlement Protocol capability - * - * \arg See also: \ref chan_sip.c + * \arg See also: \ref app_osplookup.c */ #include #include +#include #include #include #include @@ -59,828 +59,1069 @@ #include "asterisk/callerid.h" #include "asterisk/pbx.h" -#define MAX_CERTS 10 -#define MAX_SERVICEPOINTS 10 -#define OSP_MAX 256 +/* OSP Authentication Policy */ +enum osp_authpolicy { + OSP_AUTH_NO, + OSP_AUTH_YES, + OSP_AUTH_EXCLUSIVE +}; -#define OSP_DEFAULT_MAX_CONNECTIONS 20 -#define OSP_DEFAULT_RETRY_DELAY 0 -#define OSP_DEFAULT_RETRY_LIMIT 2 -#define OSP_DEFAULT_TIMEOUT 500 +#define OSP_CONFIG_FILE ((char*)"osp.conf") +#define OSP_GENERAL_CAT ((char*)"general") +#define OSP_MAX_CERTS ((unsigned int)10) +#define OSP_MAX_SRVS ((unsigned int)10) +#define OSP_DEF_MAXCONNECTIONS ((unsigned int)20) +#define OSP_MIN_MAXCONNECTIONS ((unsigned int)1) +#define OSP_MAX_MAXCONNECTIONS ((unsigned int)1000) +#define OSP_DEF_RETRYDELAY ((unsigned int)0) +#define OSP_MIN_RETRYDELAY ((unsigned int)0) +#define OSP_MAX_RETRYDELAY ((unsigned int)10) +#define OSP_DEF_RETRYLIMIT ((unsigned int)2) +#define OSP_MIN_RETRYLIMIT ((unsigned int)0) +#define OSP_MAX_RETRYLIMIT ((unsigned int)100) +#define OSP_DEF_TIMEOUT ((unsigned int)500) +#define OSP_MIN_TIMEOUT ((unsigned int)200) +#define OSP_MAX_TIMEOUT ((unsigned int)10000) +#define OSP_DEF_AUTHPOLICY ((enum osp_authpolicy)OSP_AUTH_YES) +#define OSP_AUDIT_URL ((char*)"localhost") +#define OSP_LOCAL_VALIDATION ((int)1) +#define OSP_SSL_LIFETIME ((unsigned int)300) +#define OSP_HTTP_PERSISTENCE ((int)1) +#define OSP_CUSTOMER_ID ((char*)"") +#define OSP_DEVICE_ID ((char*)"") +#define OSP_DEF_DESTINATIONS ((unsigned int)5) -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; -static unsigned tokenformat = TOKEN_ALGO_SIGNED; - 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; + char name[OSP_NORSTR_SIZE]; + char privatekey[OSP_NORSTR_SIZE]; + char localcert[OSP_NORSTR_SIZE]; + unsigned int cacount; + char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE]; + unsigned int spcount; + char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE]; int maxconnections; int retrydelay; int retrylimit; int timeout; + char source[OSP_NORSTR_SIZE]; + enum osp_authpolicy authpolicy; OSPTPROVHANDLE handle; struct osp_provider *next; }; -static struct osp_provider *providers; -static int osp_build(struct ast_config *cfg, char *cat) +AST_MUTEX_DEFINE_STATIC(osplock); +static unsigned int osp_usecount = 0; +static int osp_initialized = 0; +static int osp_hardware = 0; +static struct osp_provider* ospproviders = NULL; +static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED; + +static int osp_buildProvider( + struct ast_config* cfg, /* OSP configuration */ + char* provider); /* OSP provider context name */ +static int osp_getPolicy( + const char* provider, /* OSP provider context name */ + int* policy); /* OSP authentication policy, output */ +static int osp_genTransaction( + const char* provider, /* OSP provider context name */ + int* transaction, /* OSP transaction handle, output */ + unsigned int sourcesize, /* Size of source buffer, in/output */ + char* source); /* Source of provider context, output */ +static int osp_valToken( + int transaction, /* OSP transaction handle */ + const char* source, /* Source of in_bound call */ + const char* dest, /* Destination of in_bound call */ + const char* calling, /* Calling number */ + const char* called, /* Called number */ + const char* token, /* OSP token, may be empty */ + unsigned int* timelimit); /* Call duration limit, output */ +static unsigned int osp_choTimelimit( + unsigned int in, /* In_bound OSP timelimit */ + unsigned int out); /* Out_bound OSP timelimit */ +static enum OSPEFAILREASON reason2cause( + int reason); /* Last call failure reason */ + +static int osp_load(void); +static int osp_unload(void); +static int osp_show(int fd, int argc, char *argv[]); + +static int osp_buildProvider( + struct ast_config *cfg, /* OSP configuration */ + char* provider) /* OSP provider context name */ { - 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]; + int res; + unsigned int t, i, j; + struct osp_provider* p; + struct ast_variable* v; OSPTPRIVATEKEY privatekey; OSPTCERT localcert; - OSPTCERT *authCerts[MAX_CERTS]; + const char* psrvpoints[OSP_MAX_SRVS]; + OSPTCERT cacerts[OSP_MAX_CERTS]; + const OSPTCERT* pcacerts[OSP_MAX_CERTS]; + int error = OSPC_ERR_NO_ERROR; - - - ast_mutex_lock(&osplock); - osp = providers; - while(osp) { - if (!strcasecmp(osp->name, cat)) - break; - osp = osp->next; + p = malloc(sizeof(struct osp_provider)); + if (!p) { + ast_log(LOG_ERROR, "Out of memory\n"); + return(-1); } - 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; - } - ast_copy_string(osp->name, cat, sizeof(osp->name)); - snprintf(osp->localpvtkey, sizeof(osp->localpvtkey) ,"%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, cat); - snprintf(osp->localcert, sizeof(osp->localpvtkey), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, cat); - osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS; - osp->retrydelay = OSP_DEFAULT_RETRY_DELAY; - osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT; - osp->timeout = OSP_DEFAULT_TIMEOUT; - osp->source[0] = '\0'; - ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat); - v = ast_variable_browse(cfg, cat); + + memset(p, 0, sizeof(struct osp_provider)); + ast_copy_string(p->name, provider, sizeof(p->name)); + p->handle = OSP_INVALID_HANDLE; + snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider); + snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider); + p->maxconnections = OSP_DEF_MAXCONNECTIONS; + p->retrydelay = OSP_DEF_RETRYDELAY; + p->retrylimit = OSP_DEF_RETRYLIMIT; + p->timeout = OSP_DEF_TIMEOUT; + p->authpolicy = OSP_DEF_AUTHPOLICY; + + v = ast_variable_browse(cfg, provider); while(v) { if (!strcasecmp(v->name, "privatekey")) { - if (v->value[0] == '/') - ast_copy_string(osp->localpvtkey, v->value, sizeof(osp->localpvtkey)); - else - snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), "%s/%s", ast_config_AST_KEY_DIR , v->value); + if (v->value[0] == '/') { + ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey)); + } else { + snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value); + } + ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey); } else if (!strcasecmp(v->name, "localcert")) { - if (v->value[0] == '/') - ast_copy_string(osp->localcert, v->value, sizeof(osp->localcert)); - else - snprintf(osp->localcert, sizeof(osp->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value); + if (v->value[0] == '/') { + ast_copy_string(p->localcert, v->value, sizeof(p->localcert)); + } else { + snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value); + } + ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert); } else if (!strcasecmp(v->name, "cacert")) { - if (osp->cacount < MAX_CERTS) { - if (v->value[0] == '/') - ast_copy_string(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0])); - else - snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value); - osp->cacount++; - } else - ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno); + if (p->cacount < OSP_MAX_CERTS) { + if (v->value[0] == '/') { + ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0])); + } else { + snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value); + } + ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]); + p->cacount++; + } else { + ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno); + } } else if (!strcasecmp(v->name, "servicepoint")) { - if (osp->spcount < MAX_SERVICEPOINTS) { - ast_copy_string(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); + if (p->spcount < OSP_MAX_SRVS) { + ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0])); + ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]); + p->spcount++; + } else { + ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno); + } } else if (!strcasecmp(v->name, "maxconnections")) { - if ((sscanf(v->value, "%d", &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); + if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) { + p->maxconnections = t; + ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t); + } else { + ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n", + OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno); + } } else if (!strcasecmp(v->name, "retrydelay")) { - if ((sscanf(v->value, "%d", &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); + if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) { + p->retrydelay = t; + ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t); + } else { + ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n", + OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno); + } } else if (!strcasecmp(v->name, "retrylimit")) { - if ((sscanf(v->value, "%d", &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); + if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) { + p->retrylimit = t; + ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t); + } else { + ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n", + OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno); + } } else if (!strcasecmp(v->name, "timeout")) { - if ((sscanf(v->value, "%d", &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); + if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) { + p->timeout = t; + ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t); + } else { + ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n", + OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno); + } } else if (!strcasecmp(v->name, "source")) { - ast_copy_string(osp->source, v->value, sizeof(osp->source)); + ast_copy_string(p->source, v->value, sizeof(p->source)); + ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source); + } else if (!strcasecmp(v->name, "authpolicy")) { + if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) { + p->authpolicy = t; + ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t); + } else { + ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n", + OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno); + } } v = v->next; } - if (osp->cacount < 1) { - snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, cat); - osp->cacount++; + + error = OSPPUtilLoadPEMPrivateKey(p->privatekey, &privatekey); + if (error != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s'\n", p->privatekey); + free(p); + return(-1); } - for (x=0;xcacount;x++) - cacerts[x] = osp->cacerts[x]; - for (x=0;xspcount;x++) - servicepoints[x] = osp->servicepoints[x]; + + error = OSPPUtilLoadPEMCert(p->localcert, &localcert); + if (error != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s'\n", p->localcert); + if (privatekey.PrivateKeyData) { + free(privatekey.PrivateKeyData); + } + free(p); + return(-1); + } + + if (p->cacount < 1) { + snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider); + ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]); + p->cacount++; + } + for (i = 0; i < p->cacount; i++) { + error = OSPPUtilLoadPEMCert(p->cacerts[i], &cacerts[i]); + if (error != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s'\n", p->cacerts[i]); + for (j = 0; j < i; j++) { + if (cacerts[j].CertData) { + free(cacerts[j].CertData); + } + } + if (localcert.CertData) { + free(localcert.CertData); + } + if (privatekey.PrivateKeyData) { + free(privatekey.PrivateKeyData); + } + free(p); + return(-1); + } + pcacerts[i] = &cacerts[i]; + } - 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); + for (i = 0; i < p->spcount; i++) { + psrvpoints[i] = p->srvpoints[i]; } - - 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; - } + error = OSPPProviderNew( + p->spcount, psrvpoints, + NULL, + OSP_AUDIT_URL, + &privatekey, + &localcert, + p->cacount, pcacerts, + OSP_LOCAL_VALIDATION, + OSP_SSL_LIFETIME, + p->maxconnections, + OSP_HTTP_PERSISTENCE, + p->retrydelay, + p->retrylimit, + p->timeout, + OSP_CUSTOMER_ID, + OSP_DEVICE_ID, + &p->handle); + if (error != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to initialize provider '%s'\n", provider); + free(p); + res = -1; + } else { + ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider); + ast_mutex_lock(&osplock); + p->next = ospproviders; + ospproviders = p; + ast_mutex_unlock(&osplock); + res = 0; + } - 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;icacount;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; + for (i = 0; i < p->cacount; i++) { + if (cacerts[i].CertData) { + free(cacerts[i].CertData); } - } - - 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, - 1, - 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; + if (localcert.CertData) { + free(localcert.CertData); } - ast_mutex_unlock(&osplock); - return 0; + if (privatekey.PrivateKeyData) { + free(privatekey.PrivateKeyData); + } + + return(res); } -static int show_osp(int fd, int argc, char *argv[]) +static int osp_getPolicy( + const char* provider, /* OSP provider context name */ + int* policy) /* OSP authentication policy, output */ { - struct osp_provider *osp; - char *search = NULL; - int x; - int found = 0; - char *tokenalgo; + int res = 0; + struct osp_provider* p; - if ((argc < 2) || (argc > 3)) - return RESULT_SHOWUSAGE; - if (argc > 2) - search = argv[2]; - if (!search) { - switch (tokenformat) { - case TOKEN_ALGO_BOTH: - tokenalgo = "Both"; - break; - case TOKEN_ALGO_UNSIGNED: - tokenalgo = "Unsigned"; - break; - case TOKEN_ALGO_SIGNED: - default: - tokenalgo = "Signed"; - break; - } - ast_cli(fd, "OSP: %s %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal", tokenalgo); - } - 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;xcacount;x++) - ast_cli(fd, "CA Certificate %d: %s\n", x + 1, osp->cacerts[x]); - for (x=0;xspcount;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 : ""); - ast_cli(fd, "OSP Handle: %d\n", osp->handle); - found++; + p = ospproviders; + while(p) { + if (!strcasecmp(p->name, provider)) { + *policy = p->authpolicy; + ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", *policy); + res = 1; + break; } - osp = osp->next; + p = p->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; + + return(res); } - -/*----------------------------------------------* - * Loads the Certificate * - *----------------------------------------------*/ -static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len) +static int osp_genTransaction( + const char* provider, /* OSP provider context name */ + int* transaction, /* OSP transaction handle, output */ + unsigned int sourcesize, /* Size of source buffer, in/output */ + char* source) /* Source of provider context, output */ { - int length = 0; - unsigned char *temp; - BIO *bioIn = NULL; - X509 *cert=NULL; - int retVal = OSPC_ERR_NO_ERROR; + int res = 0; + struct osp_provider *p; + int 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; - } - } - } + ast_mutex_lock(&osplock); + p = ospproviders; + while(p) { + if (!strcasecmp(p->name, provider)) { + error = OSPPTransactionNew(p->handle, transaction); + if (error == OSPC_ERR_NO_ERROR) { + ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction); + ast_copy_string(source, p->source, sourcesize); + ast_log(LOG_DEBUG, "OSP: source '%s'\n", source); + res = 1; + } else { + *transaction = OSP_INVALID_HANDLE; + ast_log(LOG_WARNING, "OSP: Unable to create transaction handle\n"); + res = -1; + } + break; + } + p = p->next; + } + ast_mutex_unlock(&osplock); - if (bioIn != NULL) - { - BIO_free(bioIn); - } - - if (cert != NULL) - { - X509_free(cert); - } - return retVal; + return(res); } -/*----------------------------------------------* - * Loads the Private Key * - *----------------------------------------------*/ -static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len) +static int osp_valToken( + int transaction, /* OSP transaction handle */ + const char* source, /* Source of in_bound call */ + const char* dest, /* Destination of in_bound call */ + const char* calling, /* Calling number */ + const char* called, /* Called number */ + const char* token, /* OSP token, may be empty */ + unsigned int* timelimit) /* Call duration limit, output */ { - int length = 0; - unsigned char *temp; - BIO *bioIn = NULL; - RSA *pKey = NULL; - int retVal = OSPC_ERR_NO_ERROR; + int res = 0; + char* tokenstr; + int tokenlen; + unsigned int authorised; + unsigned int dummy = 0; + int error; - temp = buffer; + tokenstr = ast_strdupa(token); + if (!tokenstr) { + ast_log(LOG_WARNING, "OSP: Unable to duplicate token\n"); + return(res); + } + tokenlen = ast_base64decode(tokenstr, token, strlen(token)); - 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; + error = OSPPTransactionValidateAuthorisation( + transaction, + source, dest, NULL, NULL, + calling ? calling : "", OSPC_E164, + called, OSPC_E164, + 0, NULL, + tokenlen, tokenstr, + &authorised, + timelimit, + &dummy, NULL, + osp_tokenformat); + if (error == OSPC_ERR_NO_ERROR) { + if (authorised) { + ast_log(LOG_DEBUG, "OSP: Authorised\n"); + res = 1; + } + } + return(res); } -int ast_osp_validate(char *provider, char *token, int *handle, unsigned int *timelimit, char *callerid, struct in_addr addr, char *extension) +int ast_osp_auth( + const char* provider, /* OSP provider context name */ + int* transaction, /* OSP transaction handle, output */ + const char* source, /* Source of in_bound call */ + const char* calling, /* Calling number */ + const char* called, /* Called number */ + const char* token, /* OSP token, may be empty */ + unsigned int* timelimit) /* Call duration limit, output */ { - char tmp[256]="", *l, *n; - char iabuf[INET_ADDRSTRLEN]; - char source[OSP_MAX] = ""; /* Same length as osp->source */ - char *token2; - int tokenlen; - struct osp_provider *osp; - int res = 0; - unsigned int authorised, dummy; + int res; + char dest[OSP_NORSTR_SIZE]; + int policy = OSP_AUTH_YES; - if (!provider || !strlen(provider)) - provider = "default"; + *transaction = OSP_INVALID_HANDLE; + *timelimit = OSP_DEF_TIMELIMIT; - token2 = ast_strdupa(token); - if (!token2) - return -1; - tokenlen = ast_base64decode(token2, token, strlen(token)); - *handle = -1; - if (!callerid) - callerid = ""; - ast_copy_string(tmp, callerid, sizeof(tmp)); - ast_callerid_parse(tmp, &n, &l); - if (!l) - l = ""; - else { - ast_shrink_phone_number(l); - if (!ast_isphonenumber(l)) - l = ""; + res = osp_getPolicy(provider, &policy); + if (!res) { + ast_log(LOG_WARNING, "OSP: Unabe to find authentication policy\n"); + return(-1); } - callerid = l; - ast_mutex_lock(&osplock); - ast_inet_ntoa(iabuf, sizeof(iabuf), addr); - osp = providers; - while(osp) { - if (!strcasecmp(osp->name, provider)) { - if (OSPPTransactionNew(osp->handle, handle)) { - ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n"); + + switch (policy) { + case OSP_AUTH_NO: + res = 1; + break; + case OSP_AUTH_EXCLUSIVE: + if (ast_strlen_zero(token)) { + res = 0; + } else if ((res = osp_genTransaction(provider, transaction, sizeof(dest), dest)) <= 0) { + *transaction = OSP_INVALID_HANDLE; + ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n"); + res = -1; } else { - ast_copy_string(source, osp->source, sizeof(source)); - res = 1; + res = osp_valToken(*transaction, source, dest, calling, called, token, timelimit); } break; - } - osp = osp->next; - } - ast_mutex_unlock(&osplock); - if (res) { - res = 0; - dummy = 0; - if (!OSPPTransactionValidateAuthorisation(*handle, iabuf, source, NULL, NULL, - callerid, OSPC_E164, extension, OSPC_E164, 0, "", tokenlen, token2, &authorised, timelimit, &dummy, NULL, tokenformat)) { - if (authorised) { - ast_log(LOG_DEBUG, "Validated token for '%s' from '%s@%s'\n", extension, callerid, iabuf); + case OSP_AUTH_YES: + default: + if (ast_strlen_zero(token)) { res = 1; + } else if ((res = osp_genTransaction(provider, transaction, sizeof(dest), dest)) <= 0) { + *transaction = OSP_INVALID_HANDLE; + ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n"); + res = -1; + } else { + res = osp_valToken(*transaction, source, dest, calling, called, token, timelimit); } - } + break; } - return res; + + if (!res) { + OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED); + } + + return(res); } -int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result) +static unsigned int osp_choTimelimit( + unsigned int in, /* In_bound OSP timelimit */ + unsigned int out) /* Out_bound OSP timelimit */ { - int cres; - int res = 0; - int counts; - int tokenlen; - unsigned int dummy=0; - unsigned int timelimit; + if (in == OSP_DEF_TIMELIMIT) { + return (out); + } else if (out == OSP_DEF_TIMELIMIT) { + return (in); + } else { + return(in < out ? in : out); + } +} + +int ast_osp_lookup( + const char* provider, /* OSP provider conttext name */ + const char* srcdev, /* Source device of out_bound call */ + const char* calling, /* Calling number */ + const char* called, /* Called number */ + struct ast_osp_result* result) /* OSP lookup results, output */ +{ + int res; + char source[OSP_NORSTR_SIZE]; unsigned int callidlen; - char callidstr[OSPC_CALLID_MAXSIZE] = ""; - struct osp_provider *osp; - char source[OSP_MAX] = ""; /* Same length as osp->source */ - char callednum[2048]=""; - char callingnum[2048]=""; - char destination[2048]=""; - char token[2000]; - char tmp[256]="", *l, *n; - OSPE_DEST_PROT prot; - OSPE_DEST_OSP_ENABLED ospenabled; - char *devinfo = NULL; + char callidstr[OSPC_CALLID_MAXSIZE]; + char callingnum[OSP_NORSTR_SIZE]; + char callednum[OSP_NORSTR_SIZE]; + char destination[OSP_NORSTR_SIZE]; + unsigned int tokenlen; + char token[OSP_TOKSTR_SIZE]; + unsigned int dummy = 0; + OSPE_DEST_PROT protocol; + OSPE_DEST_OSP_ENABLED enabled; + enum OSPEFAILREASON cause; + int error; - result->handle = -1; - result->numresults = 0; + result->outhandle = OSP_INVALID_HANDLE; result->tech[0] = '\0'; result->dest[0] = '\0'; + result->calling[0] = '\0'; result->token[0] = '\0'; + result->numresults = 0; + result->outtimelimit = OSP_DEF_TIMELIMIT; - if (!provider || !strlen(provider)) - provider = "default"; + if ((res = osp_genTransaction(provider, &result->outhandle, sizeof(source), source)) <= 0) { + result->outhandle = OSP_INVALID_HANDLE; + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } + ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n"); + return(-1); + } - if (!callerid) - callerid = ""; - ast_copy_string(tmp, callerid, sizeof(tmp)); - ast_callerid_parse(tmp, &n, &l); - if (!l) - l = ""; - else { - ast_shrink_phone_number(l); - if (!ast_isphonenumber(l)) - l = ""; + res = 0; + dummy = 0; + result->numresults = OSP_DEF_DESTINATIONS; + error = OSPPTransactionRequestAuthorisation( + result->outhandle, + source, srcdev, + calling ? calling : "", OSPC_E164, + called, OSPC_E164, + NULL, + 0, NULL, + NULL, + &result->numresults, + &dummy, NULL); + if (error != OSPC_ERR_NO_ERROR) { + result->numresults = 0; + OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED); + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } + return(res); } - callerid = l; - if (chan) { - cres = ast_autoservice_start(chan); - if (cres < 0) - return cres; + if (!result->numresults) { + result->numresults = 0; + OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } + return(res); } - 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"); + + callidlen = sizeof(callidstr); + tokenlen = sizeof(token); + error = OSPPTransactionGetFirstDestination( + result->outhandle, + 0, NULL, NULL, + &result->outtimelimit, + &callidlen, callidstr, + sizeof(callednum), callednum, + sizeof(callingnum), callingnum, + sizeof(destination), destination, + 0, NULL, + &tokenlen, token); + if (error != OSPC_ERR_NO_ERROR) { + result->token[0] = '\0'; + result->numresults = 0; + result->outtimelimit = OSP_DEF_TIMELIMIT; + OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED); + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } + ast_log(LOG_DEBUG, "OSP: Unable to get first route\n"); + return(res); + } + + do { + result->outtimelimit = osp_choTimelimit(result->intimelimit, result->outtimelimit); + ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit); + ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum); + ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum); + ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination); + ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen); + + if (strlen(destination) <= 2) { + cause = OSPC_FAIL_INCOMPATIBLE_DEST; + } else { + error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled); + if ((error == OSPC_ERR_NO_ERROR) && (enabled == OSPE_OSP_FALSE)) { + result->token[0] = '\0'; } else { - ast_copy_string(source, osp->source, sizeof(source)); + ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1); + } + + error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol); + if (error != OSPC_ERR_NO_ERROR) { + cause = OSPC_FAIL_PROTOCOL_ERROR; + } else { res = 1; + /* Strip leading and trailing brackets */ + destination[strlen(destination) - 1] = '\0'; + switch(protocol) { + case OSPE_DEST_PROT_H323_SETUP: + ast_copy_string(result->tech, "H323", sizeof(result->tech)); + ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol); + snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + ast_copy_string(result->calling, callingnum, sizeof(result->calling)); + break; + case OSPE_DEST_PROT_SIP: + ast_copy_string(result->tech, "SIP", sizeof(result->tech)); + ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol); + snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + ast_copy_string(result->calling, callingnum, sizeof(result->calling)); + break; + case OSPE_DEST_PROT_IAX: + ast_copy_string(result->tech, "IAX", sizeof(result->tech)); + ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol); + snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + ast_copy_string(result->calling, callingnum, sizeof(result->calling)); + break; + default: + ast_log(LOG_DEBUG, "OSP: Unknown protocol '%d'\n", protocol); + cause = OSPC_FAIL_PROTOCOL_ERROR; + res = 0; + } } - break; } - osp = osp->next; - } - ast_mutex_unlock(&osplock); - if (res) { - res = 0; - /* No more than 10 back */ - counts = 10; - dummy = 0; - devinfo = pbx_builtin_getvar_helper (chan, "OSPPEER"); - if (!devinfo) { - devinfo = ""; - } - if (!OSPPTransactionRequestAuthorisation(result->handle, source, devinfo, - callerid,OSPC_E164, extension, OSPC_E164, NULL, 0, NULL, NULL, &counts, &dummy, NULL)) { - if (counts) { + if (!res) { + result->numresults--; + if (result->numresults) { + callidlen = sizeof(callidstr); tokenlen = sizeof(token); - result->numresults = counts - 1; - callidlen = sizeof(callidstr); - if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, callidstr, - sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { - ast_log(LOG_DEBUG, "Got destination '%s' and called: '%s' calling: '%s' for '%s' (provider '%s')\n", - destination, callednum, callingnum, extension, provider); - /* Only support OSP server with only one duration limit */ - if (ast_channel_cmpwhentohangup (chan, timelimit) < 0) { - ast_channel_setwhentohangup (chan, timelimit); + error = OSPPTransactionGetNextDestination( + result->outhandle, + cause, + 0, NULL, NULL, + &result->outtimelimit, + &callidlen, callidstr, + sizeof(callednum), callednum, + sizeof(callingnum), callingnum, + sizeof(destination), destination, + 0, NULL, + &tokenlen, token); + if (error != OSPC_ERR_NO_ERROR) { + result->token[0] = '\0'; + result->numresults = 0; + result->outtimelimit = OSP_DEF_TIMELIMIT; + OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED); + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); } - do { - if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) { - result->token[0] = 0; - } - else { - 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: - ast_copy_string(result->tech, "H323", sizeof(result->tech)); - snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); - break; - case OSPE_DEST_PROT_SIP: - ast_copy_string(result->tech, "SIP", sizeof(result->tech)); - snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); - break; - case OSPE_DEST_PROT_IAX: - ast_copy_string(result->tech, "IAX", sizeof(result->tech)); - 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--; - callidlen = sizeof(callidstr); - if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, - sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { - break; - } - } - } else { - ast_log(LOG_DEBUG, "Missing destination protocol\n"); - break; - } - } while(!res && result->numresults); + break; } + } else { + result->token[0] = '\0'; + result->numresults = 0; + result->outtimelimit = OSP_DEF_TIMELIMIT; + OSPPTransactionRecordFailure(result->outhandle, cause); + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } } - + } else { + result->numresults--; } - if (!res) { - OSPPTransactionDelete(result->handle); - result->handle = -1; - } - + } while(!res && result->numresults); + + return(res); +} + +static enum OSPEFAILREASON reason2cause( + int reason) /* Last call failure reason */ +{ + enum OSPEFAILREASON cause; + + switch(reason) { + case AST_CAUSE_NOTDEFINED: + cause = OSPC_FAIL_NONE; + break; + case AST_CAUSE_BUSY: + cause = OSPC_FAIL_USER_BUSY; + break; + case AST_CAUSE_CONGESTION: + cause = OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION; + break; + case AST_CAUSE_UNALLOCATED: + cause = OSPC_FAIL_UNALLOC_NUMBER; + break; + case AST_CAUSE_NOANSWER: + cause = OSPC_FAIL_NO_ANSWER_FROM_USER; + break; + case AST_CAUSE_NORMAL: + default: + cause = OSPC_FAIL_NORMAL_CALL_CLEARING; + break; } - 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; + + return(cause); } -int ast_osp_next(struct ast_osp_result *result, int cause) +int ast_osp_next( + int reason, /* Last desintaion failure reason */ + struct ast_osp_result *result) /* OSP lookup results, output */ { int res = 0; - int tokenlen; - unsigned int dummy=0; - unsigned int timelimit; unsigned int callidlen; - char callidstr[OSPC_CALLID_MAXSIZE] = ""; - char callednum[2048]=""; - char callingnum[2048]=""; - char destination[2048]=""; - char token[2000]; - OSPE_DEST_PROT prot; - OSPE_DEST_OSP_ENABLED ospenabled; + char callidstr[OSPC_CALLID_MAXSIZE]; + char callingnum[OSP_NORSTR_SIZE]; + char callednum[OSP_NORSTR_SIZE]; + char destination[OSP_NORSTR_SIZE]; + unsigned int tokenlen; + char token[OSP_TOKSTR_SIZE]; + OSPE_DEST_PROT protocol; + OSPE_DEST_OSP_ENABLED enabled; + enum OSPEFAILREASON cause; + int error; result->tech[0] = '\0'; result->dest[0] = '\0'; + result->calling[0] = '\0'; result->token[0] = '\0'; + result->outtimelimit = OSP_DEF_TIMELIMIT; - if (result->handle > -1) { - dummy = 0; - if (result->numresults) { - tokenlen = sizeof(token); - while(!res && result->numresults) { - result->numresults--; - callidlen = sizeof(callidstr); - if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, - sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { - if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) { - result->token[0] = 0; - } - else { - 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) { + if (result->outhandle == OSP_INVALID_HANDLE) { + result->numresults = 0; + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } + ast_log(LOG_WARNING, "OSP: Transaction handle undefined\n"); + return(-1); + } + + cause = reason2cause(reason); + if (!result->numresults) { + OSPPTransactionRecordFailure(result->outhandle, cause); + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } + ast_log(LOG_DEBUG, "OSP: No more destination\n"); + return(res); + } + + while(!res && result->numresults) { + result->numresults--; + callidlen = sizeof(callidstr); + tokenlen = sizeof(token); + error = OSPPTransactionGetNextDestination( + result->outhandle, + cause, + 0, NULL, NULL, + &result->outtimelimit, + &callidlen, callidstr, + sizeof(callednum), callednum, + sizeof(callingnum), callingnum, + sizeof(destination), destination, + 0, NULL, + &tokenlen, token); + if (error == OSPC_ERR_NO_ERROR) { + result->outtimelimit = osp_choTimelimit(result->intimelimit, result->outtimelimit); + ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit); + ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum); + ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum); + ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination); + ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen); + + if (strlen(destination) <= 2) { + cause = OSPC_FAIL_INCOMPATIBLE_DEST; + } else { + error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled); + if ((error == OSPC_ERR_NO_ERROR) && (enabled == OSPE_OSP_FALSE)) { + result->token[0] = '\0'; + } else { + ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1); + } + + error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol); + if (error != OSPC_ERR_NO_ERROR) { + cause = OSPC_FAIL_PROTOCOL_ERROR; + } else { + res = 1; + /* Strip leading and trailing brackets */ + destination[strlen(destination) - 1] = '\0'; + switch(protocol) { case OSPE_DEST_PROT_H323_SETUP: ast_copy_string(result->tech, "H323", sizeof(result->tech)); + ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + ast_copy_string(result->calling, callingnum, sizeof(result->calling)); break; case OSPE_DEST_PROT_SIP: ast_copy_string(result->tech, "SIP", sizeof(result->tech)); + ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + ast_copy_string(result->calling, callingnum, sizeof(result->calling)); break; case OSPE_DEST_PROT_IAX: ast_copy_string(result->tech, "IAX", sizeof(result->tech)); + ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + ast_copy_string(result->calling, callingnum, sizeof(result->calling)); break; default: - ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot); + ast_log(LOG_DEBUG, "OSP: Unknown protocol '%d'\n", protocol); + cause = OSPC_FAIL_PROTOCOL_ERROR; res = 0; - } - } else { - ast_log(LOG_DEBUG, "Missing destination protocol\n"); - break; } } } - + if (!res && !result->numresults) { + OSPPTransactionRecordFailure(result->outhandle, cause); + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } + } + } else { + result->token[0] = '\0'; + result->numresults = 0; + result->outtimelimit = OSP_DEF_TIMELIMIT; + OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED); + if (result->inhandle != OSP_INVALID_HANDLE) { + OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST); + } } - 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; - } + return(res); } -int ast_osp_terminate(int handle, int cause, time_t start, time_t duration) +int ast_osp_finish( + int handle, /* OSP in/out_bound transaction handle */ + int reason, /* Last destination failure reason */ + time_t start, /* Call start time */ + time_t connect, /* Call connect time */ + time_t end) /* Call end time*/ { + int res = 1; unsigned int dummy = 0; - int res = -1; - enum OSPEFAILREASON reason; - - time_t endTime = 0; - time_t alertTime = 0; - time_t connectTime = 0; + enum OSPEFAILREASON cause; + time_t alert = 0; unsigned isPddInfoPresent = 0; unsigned pdd = 0; unsigned releaseSource = 0; unsigned char *confId = ""; + int error; - 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, - endTime,alertTime,connectTime,isPddInfoPresent,pdd,releaseSource,confId, - 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); + if (handle == OSP_INVALID_HANDLE) { + return(res); + } + + if ((cause = reason2cause(reason)) != OSPC_FAIL_NONE) { + OSPPTransactionRecordFailure(handle, cause); + } + error = OSPPTransactionReportUsage( + handle, + difftime(end, connect), start, end, alert, connect, + isPddInfoPresent, pdd, + releaseSource, + confId, + 0, 0, 0, 0, + &dummy, NULL); + if (error == OSPC_ERR_NO_ERROR) { + ast_log(LOG_DEBUG, "OSP: Usage reported\n"); + res = 1; + } else { + ast_log(LOG_DEBUG, "OSP: Unable to report usage, error = %d\n", error); res = 0; } - return res; + OSPPTransactionDelete(handle); + + return(res); } -static int config_load(void) +void ast_osp_adduse(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; + osp_usecount++; +} + +void ast_osp_deluse(void) +{ + if (osp_usecount > 0) { + osp_usecount--; } - ast_mutex_unlock(&osplock); - cfg = ast_config_load("osp.conf"); +} + +static char osp_usage[] = +"Usage: show osp\n" +" Displays information on Open Settlement Protocol support\n"; + +static struct ast_cli_entry osp_cli = { + {"show", "osp", NULL}, + osp_show, + "Displays OSP information", + osp_usage +}; + +static int osp_load(void) +{ + char* t; + unsigned int v; + struct ast_config* cfg; + int error = OSPC_ERR_NO_ERROR; + + cfg = ast_config_load(OSP_CONFIG_FILE); 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 + t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate"); + if (t && ast_true(t)) { + if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) { + ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n"); OSPPInit(0); - initialized = 1; + } else { + osp_hardware = 1; + } + } else { + OSPPInit(0); } - cat = ast_variable_retrieve(cfg, "general", "tokenformat"); - if (cat) { - if ((sscanf(cat, "%d", &tokenformat) != 1) || (tokenformat < TOKEN_ALGO_SIGNED) || (tokenformat > TOKEN_ALGO_BOTH)) { - tokenformat = TOKEN_ALGO_SIGNED; - ast_log(LOG_WARNING, "tokenformat should be an integer from 0 to 2, not '%s'\n", cat); + ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware); + + t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat"); + if (t) { + if ((sscanf(t, "%d", &v) == 1) && + ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH))) + { + osp_tokenformat = v; + } else { + ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n", + TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t); } } - cat = ast_category_browse(cfg, NULL); - while(cat) { - if (strcasecmp(cat, "general")) - osp_build(cfg, cat); - cat = ast_category_browse(cfg, cat); + ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat); + + t = ast_category_browse(cfg, NULL); + while(t) { + if (strcasecmp(t, OSP_GENERAL_CAT)) { + osp_buildProvider(cfg, t); + } + t = ast_category_browse(cfg, t); } + + osp_initialized = 1; + ast_config_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; + } else { + ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n"); } - ast_mutex_unlock(&osplock); - return 0; + ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized); + + return(0); } -static char show_osp_usage[] = -"Usage: show osp\n" -" Displays information on Open Settlement Protocol\n"; +static int osp_unload(void) +{ + struct osp_provider* p; + struct osp_provider* next; -static struct ast_cli_entry cli_show_osp = -{ { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage }; + if (osp_initialized) { + ast_mutex_lock(&osplock); + p = ospproviders; + while(p) { + next = p->next; + OSPPProviderDelete(p->handle, 0); + free(p); + p = next; + } + ospproviders = NULL; + ast_mutex_unlock(&osplock); -int reload(void) + OSPPCleanup(); + + osp_usecount = 0; + osp_tokenformat = TOKEN_ALGO_SIGNED; + osp_hardware = 0; + osp_initialized = 0; + } + return(0); +} + +static int osp_show(int fd, int argc, char *argv[]) { - config_load(); - ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n"); - return 0; + int i; + int found = 0; + struct osp_provider* p; + char* provider = NULL; + char* tokenalgo; + + if ((argc < 2) || (argc > 3)) { + return(RESULT_SHOWUSAGE); + } + if (argc > 2) { + provider = argv[2]; + } + if (!provider) { + switch (osp_tokenformat) { + case TOKEN_ALGO_BOTH: + tokenalgo = "Both"; + break; + case TOKEN_ALGO_UNSIGNED: + tokenalgo = "Unsigned"; + break; + case TOKEN_ALGO_SIGNED: + default: + tokenalgo = "Signed"; + break; + } + ast_cli(fd, "OSP: %s %s %s\n", + osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo); + } + + ast_mutex_lock(&osplock); + p = ospproviders; + while(p) { + if (!provider || !strcasecmp(p->name, provider)) { + if (found) { + ast_cli(fd, "\n"); + } + ast_cli(fd, " == OSP Provider '%s' == \n", p->name); + ast_cli(fd, "Local Private Key: %s\n", p->privatekey); + ast_cli(fd, "Local Certificate: %s\n", p->localcert); + for (i = 0; i < p->cacount; i++) { + ast_cli(fd, "CA Certificate %d: %s\n", i + 1, p->cacerts[i]); + } + for (i = 0; i < p->spcount; i++) { + ast_cli(fd, "Service Point %d: %s\n", i + 1, p->srvpoints[i]); + } + ast_cli(fd, "Max Connections: %d\n", p->maxconnections); + ast_cli(fd, "Retry Delay: %d seconds\n", p->retrydelay); + ast_cli(fd, "Retry Limit: %d\n", p->retrylimit); + ast_cli(fd, "Timeout: %d milliseconds\n", p->timeout); + ast_cli(fd, "Source: %s\n", strlen(p->source) ? p->source : ""); + ast_cli(fd, "Auth Policy %d\n", p->authpolicy); + ast_cli(fd, "OSP Handle: %d\n", p->handle); + found++; + } + p = p->next; + } + ast_mutex_unlock(&osplock); + + if (!found) { + if (provider) { + ast_cli(fd, "Unable to find OSP provider '%s'\n", provider); + } else { + ast_cli(fd, "No OSP providers configured\n"); + } + } + return(RESULT_SUCCESS); } int load_module(void) { - config_load(); - ast_cli_register(&cli_show_osp); - return 0; + osp_load(); + ast_cli_register(&osp_cli); + return(0); } +int reload(void) +{ + ast_cli_unregister(&osp_cli); + osp_unload(); + osp_load(); + ast_cli_register(&osp_cli); + return(0); +} + int unload_module(void) { - /* Can't unload this once we're loaded */ - return -1; + ast_cli_unregister(&osp_cli); + osp_unload(); + return(0); } char *description(void) { - return "Open Settlement Protocol Support"; + return("Open Settlement Protocol Support"); } int usecount(void) { - /* We should never be unloaded */ - return 1; + return(osp_usecount); } char *key() { - return ASTERISK_GPL_KEY; + return(ASTERISK_GPL_KEY); } +