Mon Mar 19 11:30:20 2012

Asterisk developer's documentation


app_osplookup.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief Open Settlement Protocol (OSP) Applications
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  *
00025  * \extref The OSP Toolkit: http://www.transnexus.com
00026  * \extref OpenSSL http://www.openssl.org
00027  *
00028  * \ingroup applications
00029  */
00030 
00031 /*** MODULEINFO
00032    <depend>osptk</depend>
00033    <depend>openssl</depend>
00034    <support_level>extended</support_level>
00035  ***/
00036 
00037 #include "asterisk.h"
00038 
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 338609 $")
00040 
00041 #include <osp/osp.h>
00042 #include <osp/osputils.h>
00043 #include <osp/ospb64.h>
00044 
00045 #include "asterisk/paths.h"
00046 #include "asterisk/lock.h"
00047 #include "asterisk/config.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/causes.h"
00050 #include "asterisk/channel.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/pbx.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/astosp.h"
00056 
00057 /*** DOCUMENTATION
00058    <application name="OSPAuth" language="en_US">
00059       <synopsis>
00060          OSP Authentication.
00061       </synopsis>
00062       <syntax>
00063          <parameter name="provider">
00064             <para>The name of the provider that authenticates the call.</para>
00065          </parameter>
00066          <parameter name="options">
00067             <para>Reserverd.</para>
00068          </parameter>
00069       </syntax>
00070       <description>
00071          <para>Authenticate a call by OSP.</para>
00072          <para>Input variables:</para>
00073          <variablelist>
00074             <variable name="OSPINPEERIP">
00075                <para>The last hop IP address.</para>
00076             </variable>
00077             <variable name="OSPINTOKEN">
00078                <para>The inbound OSP token.</para>
00079             </variable>
00080          </variablelist>
00081          <para>Output variables:</para>
00082          <variablelist>
00083             <variable name="OSPINHANDLE">
00084                <para>The inbound call OSP transaction handle.</para>
00085             </variable>
00086             <variable name="OSPINTIMELIMIT">
00087                <para>The inbound call duration limit in seconds.</para>
00088             </variable>
00089          </variablelist>
00090          <para>This application sets the following channel variable upon completion:</para>
00091          <variablelist>
00092             <variable name="OSPAUTHSTATUS">
00093                <para>The status of OSPAuth attempt as a text string, one of</para>
00094                <value name="SUCCESS" />
00095                <value name="FAILED" />
00096                <value name="ERROR" />
00097             </variable>
00098          </variablelist>
00099       </description>
00100       <see-also>
00101          <ref type="application">OSPLookup</ref>
00102          <ref type="application">OSPNext</ref>
00103          <ref type="application">OSPFinish</ref>
00104       </see-also>
00105    </application>
00106    <application name="OSPLookup" language="en_US">
00107       <synopsis>
00108          Lookup destination by OSP.
00109       </synopsis>
00110       <syntax>
00111          <parameter name="exten" required="true">
00112             <para>The exten of the call.</para>
00113          </parameter>
00114          <parameter name="provider">
00115             <para>The name of the provider that is used to route the call.</para>
00116          </parameter>
00117          <parameter name="options">
00118             <enumlist>
00119                <enum name="h">
00120                   <para>generate H323 call id for the outbound call</para>
00121                </enum>
00122                <enum name="s">
00123                   <para>generate SIP call id for the outbound call. Have not been implemented</para>
00124                </enum>
00125                <enum name="i">
00126                   <para>generate IAX call id for the outbound call. Have not been implemented</para>
00127                </enum>
00128             </enumlist>
00129          </parameter>
00130       </syntax>
00131       <description>
00132          <para>Looks up destination via OSP.</para>
00133          <para>Input variables:</para>
00134          <variablelist>
00135             <variable name="OSPINACTUALSRC">
00136                <para>The actual source device IP address in indirect mode.</para>
00137             </variable>
00138             <variable name="OSPINPEERIP">
00139                <para>The last hop IP address.</para>
00140             </variable>
00141             <variable name="OSPINHANDLE">
00142                <para>The inbound call OSP transaction handle.</para>
00143             </variable>
00144             <variable name="OSPINTIMELIMIT">
00145                <para>The inbound call duration limit in seconds.</para>
00146             </variable>
00147             <variable name="OSPINNETWORKID">
00148                <para>The inbound source network ID.</para>
00149             </variable>
00150             <variable name="OSPINNPRN">
00151                <para>The inbound routing number.</para>
00152             </variable>
00153             <variable name="OSPINNPCIC">
00154                <para>The inbound carrier identification code.</para>
00155             </variable>
00156             <variable name="OSPINNPDI">
00157                <para>The inbound number portability database dip indicator.</para>
00158             </variable>
00159             <variable name="OSPINSPID">
00160                <para>The inbound service provider identity.</para>
00161             </variable>
00162             <variable name="OSPINOCN">
00163                <para>The inbound operator company number.</para>
00164             </variable>
00165             <variable name="OSPINSPN">
00166                <para>The inbound service provider name.</para>
00167             </variable>
00168             <variable name="OSPINALTSPN">
00169                <para>The inbound alternate service provider name.</para>
00170             </variable>
00171             <variable name="OSPINMCC">
00172                <para>The inbound mobile country code.</para>
00173             </variable>
00174             <variable name="OSPINMNC">
00175                <para>The inbound mobile network code.</para>
00176             </variable>
00177             <variable name="OSPINTOHOST">
00178                <para>The inbound To header host part.</para>
00179             </variable>
00180             <variable name="OSPINDIVUSER">
00181                <para>The inbound Diversion header user part.</para>
00182             </variable>
00183             <variable name="OSPINDIVHOST">
00184                <para>The inbound Diversion header host part.</para>
00185             </variable>
00186             <variable name="OSPINCUSTOMINFOn">
00187                <para>The inbound custom information, where <literal>n</literal> is the index beginning with <literal>1</literal>
00188                upto <literal>8</literal>.</para>
00189             </variable>
00190          </variablelist>
00191          <para>Output variables:</para>
00192          <variablelist>
00193             <variable name="OSPOUTHANDLE">
00194                <para>The outbound call OSP transaction handle.</para>
00195             </variable>
00196             <variable name="OSPOUTTECH">
00197                <para>The outbound channel technology for the call.</para>
00198             </variable>
00199             <variable name="OSPDESTINATION">
00200                <para>The outbound destination IP address.</para>
00201             </variable>
00202             <variable name="OSPOUTCALLING">
00203                <para>The outbound calling number.</para>
00204             </variable>
00205             <variable name="OSPOUTCALLED">
00206                <para>The outbound called number.</para>
00207             </variable>
00208             <variable name="OSPOUTNETWORKID">
00209                <para>The outbound destination network ID.</para>
00210             </variable>
00211             <variable name="OSPOUTNPRN">
00212                <para>The outbound routing number.</para>
00213             </variable>
00214             <variable name="OSPOUTNPCIC">
00215                <para>The outbound carrier identification code.</para>
00216             </variable>
00217             <variable name="OSPOUTNPDI">
00218                <para>The outbound number portability database dip indicator.</para>
00219             </variable>
00220             <variable name="OSPOUTSPID">
00221                <para>The outbound service provider identity.</para>
00222             </variable>
00223             <variable name="OSPOUTOCN">
00224                <para>The outbound operator company number.</para>
00225             </variable>
00226             <variable name="OSPOUTSPN">
00227                <para>The outbound service provider name.</para>
00228             </variable>
00229             <variable name="OSPOUTALTSPN">
00230                <para>The outbound alternate service provider name.</para>
00231             </variable>
00232             <variable name="OSPOUTMCC">
00233                <para>The outbound mobile country code.</para>
00234             </variable>
00235             <variable name="OSPOUTMNC">
00236                <para>The outbound mobile network code.</para>
00237             </variable>
00238             <variable name="OSPOUTTOKEN">
00239                <para>The outbound OSP token.</para>
00240             </variable>
00241             <variable name="OSPDESTREMAILS">
00242                <para>The number of remained destinations.</para>
00243             </variable>
00244             <variable name="OSPOUTTIMELIMIT">
00245                <para>The outbound call duration limit in seconds.</para>
00246             </variable>
00247             <variable name="OSPOUTCALLIDTYPES">
00248                <para>The outbound Call-ID types.</para>
00249             </variable>
00250             <variable name="OSPOUTCALLID">
00251                <para>The outbound Call-ID. Only for H.323.</para>
00252             </variable>
00253             <variable name="OSPDIALSTR">
00254                <para>The outbound Dial command string.</para>
00255             </variable>
00256          </variablelist>
00257          <para>This application sets the following channel variable upon completion:</para>
00258          <variablelist>
00259             <variable name="OSPLOOKUPSTATUS">
00260                <para>The status of OSPLookup attempt as a text string, one of</para>
00261                <value name="SUCCESS" />
00262                <value name="FAILED" />
00263                <value name="ERROR" />
00264             </variable>
00265          </variablelist>
00266       </description>
00267       <see-also>
00268          <ref type="application">OSPAuth</ref>
00269          <ref type="application">OSPNext</ref>
00270          <ref type="application">OSPFinish</ref>
00271       </see-also>
00272    </application>
00273    <application name="OSPNext" language="en_US">
00274       <synopsis>
00275          Lookup next destination by OSP.
00276       </synopsis>
00277       <description>
00278          <para>Looks up the next destination via OSP.</para>
00279          <para>Input variables:</para>
00280          <variablelist>
00281             <variable name="OSPINHANDLE">
00282                <para>The inbound call OSP transaction handle.</para>
00283             </variable>
00284             <variable name="OSPOUTHANDLE">
00285                <para>The outbound call OSP transaction handle.</para>
00286             </variable>
00287             <variable name="OSPINTIMELIMIT">
00288                <para>The inbound call duration limit in seconds.</para>
00289             </variable>
00290             <variable name="OSPOUTCALLIDTYPES">
00291                <para>The outbound Call-ID types.</para>
00292             </variable>
00293             <variable name="OSPDESTREMAILS">
00294                <para>The number of remained destinations.</para>
00295             </variable>
00296          </variablelist>
00297          <para>Output variables:</para>
00298          <variablelist>
00299             <variable name="OSPOUTTECH">
00300                <para>The outbound channel technology.</para>
00301             </variable>
00302             <variable name="OSPDESTINATION">
00303                <para>The destination IP address.</para>
00304             </variable>
00305             <variable name="OSPOUTCALLING">
00306                <para>The outbound calling number.</para>
00307             </variable>
00308             <variable name="OSPOUTCALLED">
00309                <para>The outbound called number.</para>
00310             </variable>
00311             <variable name="OSPOUTNETWORKID">
00312                <para>The outbound destination network ID.</para>
00313             </variable>
00314             <variable name="OSPOUTNPRN">
00315                <para>The outbound routing number.</para>
00316             </variable>
00317             <variable name="OSPOUTNPCIC">
00318                <para>The outbound carrier identification code.</para>
00319             </variable>
00320             <variable name="OSPOUTNPDI">
00321                <para>The outbound number portability database dip indicator.</para>
00322             </variable>
00323             <variable name="OSPOUTSPID">
00324                <para>The outbound service provider identity.</para>
00325             </variable>
00326             <variable name="OSPOUTOCN">
00327                <para>The outbound operator company number.</para>
00328             </variable>
00329             <variable name="OSPOUTSPN">
00330                <para>The outbound service provider name.</para>
00331             </variable>
00332             <variable name="OSPOUTALTSPN">
00333                <para>The outbound alternate service provider name.</para>
00334             </variable>
00335             <variable name="OSPOUTMCC">
00336                <para>The outbound mobile country code.</para>
00337             </variable>
00338             <variable name="OSPOUTMNC">
00339                <para>The outbound mobile network code.</para>
00340             </variable>
00341             <variable name="OSPOUTTOKEN">
00342                <para>The outbound OSP token.</para>
00343             </variable>
00344             <variable name="OSPDESTREMAILS">
00345                <para>The number of remained destinations.</para>
00346             </variable>
00347             <variable name="OSPOUTTIMELIMIT">
00348                <para>The outbound call duration limit in seconds.</para>
00349             </variable>
00350             <variable name="OSPOUTCALLID">
00351                <para>The outbound Call-ID. Only for H.323.</para>
00352             </variable>
00353             <variable name="OSPDIALSTR">
00354                <para>The outbound Dial command string.</para>
00355             </variable>
00356          </variablelist>
00357          <para>This application sets the following channel variable upon completion:</para>
00358          <variablelist>
00359             <variable name="OSPNEXTSTATUS">
00360                <para>The status of the OSPNext attempt as a text string, one of</para>
00361                <value name="SUCCESS" />
00362                <value name="FAILED" />
00363                <value name="ERROR" />
00364             </variable>
00365          </variablelist>
00366       </description>
00367       <see-also>
00368          <ref type="application">OSPAuth</ref>
00369          <ref type="application">OSPLookup</ref>
00370          <ref type="application">OSPFinish</ref>
00371       </see-also>
00372    </application>
00373    <application name="OSPFinish" language="en_US">
00374       <synopsis>
00375          Report OSP entry.
00376       </synopsis>
00377       <syntax>
00378          <parameter name="cause">
00379             <para>Hangup cause.</para>
00380          </parameter>
00381          <parameter name="options">
00382             <para>Reserved.</para>
00383          </parameter>
00384       </syntax>
00385       <description>
00386          <para>Report call state.</para>
00387          <para>Input variables:</para>
00388          <variablelist>
00389             <variable name="OSPINHANDLE">
00390                <para>The inbound call OSP transaction handle.</para>
00391             </variable>
00392             <variable name="OSPOUTHANDLE">
00393                <para>The outbound call OSP transaction handle.</para>
00394             </variable>
00395             <variable name="OSPAUTHSTATUS">
00396                <para>The OSPAuth status.</para>
00397             </variable>
00398             <variable name="OSPLOOKUPSTATUS">
00399                <para>The OSPLookup status.</para>
00400             </variable>
00401             <variable name="OSPNEXTSTATUS">
00402                <para>The OSPNext status.</para>
00403             </variable>
00404             <variable name="OSPINAUDIOQOS">
00405                <para>The inbound call leg audio QoS string.</para>
00406             </variable>
00407             <variable name="OSPOUTAUDIOQOS">
00408                <para>The outbound call leg audio QoS string.</para>
00409             </variable>
00410          </variablelist>
00411          <para>This application sets the following channel variable upon completion:</para>
00412          <variablelist>
00413             <variable name="OSPFINISHSTATUS">
00414                <para>The status of the OSPFinish attempt as a text string, one of</para>
00415                <value name="SUCCESS" />
00416                <value name="FAILED" />
00417                <value name="ERROR" />
00418             </variable>
00419          </variablelist>
00420       </description>
00421       <see-also>
00422          <ref type="application">OSPAuth</ref>
00423          <ref type="application">OSPLookup</ref>
00424          <ref type="application">OSPNext</ref>
00425       </see-also>
00426    </application>
00427  ***/
00428 
00429 /* OSP Buffer Sizes */
00430 #define OSP_SIZE_INTSTR    ((unsigned int)16)         /* OSP signed/unsigned int string buffer size */
00431 #define OSP_SIZE_NORSTR    ((unsigned int)256)        /* OSP normal string buffer size */
00432 #define OSP_SIZE_KEYSTR    ((unsigned int)1024)    /* OSP certificate string buffer size */
00433 #define OSP_SIZE_TOKSTR    ((unsigned int)4096)    /* OSP token string buffer size */
00434 #define OSP_SIZE_TECHSTR   ((unsigned int)32)         /* OSP signed/unsigned int string buffer size */
00435 #define OSP_SIZE_UUID      ((unsigned int)16)         /* UUID size */
00436 #define OSP_SIZE_UUIDSTR   ((unsigned int)36)         /* UUID string size */
00437 #define OSP_SIZE_QOSSTR    ((unsigned int)1024)    /* QoS string buffer size */
00438 
00439 /* Call ID Type*/
00440 #define OSP_CALLID_UNDEF   ((unsigned int)0)       /* Undefined */
00441 #define OSP_CALLID_SIP     ((unsigned int)(1 << 0))   /* SIP */
00442 #define OSP_CALLID_H323    ((unsigned int)(1 << 1))   /* H.323 */
00443 #define OSP_CALLID_IAX     ((unsigned int)(1 << 2))   /* IAX2 */
00444 #define OSP_CALLID_MAXNUM  ((unsigned int)3)       /* Max number of call ID types */
00445 
00446 /* OSP Supported Destination Protocols */
00447 #define OSP_PROT_SIP    ((const char*)"SIP")    /* SIP protocol name */
00448 #define OSP_PROT_H323      ((const char*)"H323")      /* H.323 Q.931 protocol name*/
00449 #define OSP_PROT_IAX    ((const char*)"IAX")    /* IAX2 protocol name */
00450 #define OSP_PROT_SKYPE     ((const char*)"SKYPE")     /* Skype protocol name */
00451 
00452 /* OSP supported Destination Tech */
00453 #define OSP_TECH_SIP    ((const char*)"SIP")    /* SIP tech name */
00454 #define OSP_TECH_H323      ((const char*)"H323")      /* OH323 tech name */
00455 #define OSP_TECH_IAX    ((const char*)"IAX2")      /* IAX2 tech name */
00456 #define OSP_TECH_SKYPE     ((const char*)"SKYPE")     /* Skype tech name */
00457 
00458 /* SIP OSP header field name */
00459 #define OSP_SIP_HEADER     ((const char*)"P-OSP-Auth-Token")
00460 
00461 /* OSP Authentication Policy */
00462 enum osp_authpolicy {
00463    OSP_AUTH_NO = 0,  /* Accept any call */
00464    OSP_AUTH_YES,     /* Accept call with valid OSP token or without OSP token */
00465    OSP_AUTH_EXC      /* Only accept call with valid OSP token */
00466 };
00467 
00468 /* OSP Work Mode */
00469 enum osp_workmode {
00470    OSP_MODE_DIRECT= 0,  /* Direct */
00471    OSP_MODE_INDIRECT /* Indirect */
00472 };
00473 
00474 /* OSP Service Type */
00475 enum osp_srvtype {
00476    OSP_SRV_VOICE = 0,   /* Normal voice service */
00477    OSP_SRV_NPQUERY      /* Ported number query service */
00478 };
00479 
00480 /* OSP Constants */
00481 #define OSP_OK             ((int)1)             /* OSP function call successful */
00482 #define OSP_FAILED            ((int)0)             /* OSP function call failed */
00483 #define OSP_ERROR          ((int)-1)               /* OSP function call error */
00484 #define OSP_AST_OK            ((int)0)             /* Asterisk function call successful */
00485 #define OSP_AST_ERROR         ((int)-1)               /* Asterisk function call error */
00486 #define OSP_INVALID_HANDLE    ((int)-1)               /* Invalid OSP handle, provider, transaction etc. */
00487 #define OSP_CONFIG_FILE       ((const char*)"osp.conf")  /* OSP configuration file name */
00488 #define OSP_GENERAL_CAT       ((const char*)"general")   /* OSP global configuration context name */
00489 #define OSP_DEF_PROVIDER      ((const char*)"default")   /* OSP default provider context name */
00490 #define OSP_MAX_CERTS         ((unsigned int)10)         /* OSP max number of cacerts */
00491 #define OSP_MAX_SPOINTS       ((unsigned int)10)         /* OSP max number of service points */
00492 #define OSP_DEF_MAXCONNECT    ((unsigned int)20)         /* OSP default max_connections */
00493 #define OSP_MIN_MAXCONNECT    ((unsigned int)1)       /* OSP min max_connections */
00494 #define OSP_MAX_MAXCONNECT    ((unsigned int)1000)    /* OSP max max_connections */
00495 #define OSP_DEF_RETRYDELAY    ((unsigned int)0)       /* OSP default retry delay */
00496 #define OSP_MIN_RETRYDELAY    ((unsigned int)0)       /* OSP min retry delay */
00497 #define OSP_MAX_RETRYDELAY    ((unsigned int)10)         /* OSP max retry delay */
00498 #define OSP_DEF_RETRYLIMIT    ((unsigned int)2)       /* OSP default retry times */
00499 #define OSP_MIN_RETRYLIMIT    ((unsigned int)0)       /* OSP min retry times */
00500 #define OSP_MAX_RETRYLIMIT    ((unsigned int)100)        /* OSP max retry times */
00501 #define OSP_DEF_TIMEOUT       ((unsigned int)500)        /* OSP default timeout in ms */
00502 #define OSP_MIN_TIMEOUT       ((unsigned int)200)        /* OSP min timeout in ms */
00503 #define OSP_MAX_TIMEOUT       ((unsigned int)10000)      /* OSP max timeout in ms */
00504 #define OSP_DEF_AUTHPOLICY    OSP_AUTH_YES            /* OSP default auth policy, yes */
00505 #define OSP_AUDIT_URL         ((const char*)"localhost") /* OSP default Audit URL */
00506 #define OSP_LOCAL_VALIDATION  ((int)1)             /* Validate OSP token locally */
00507 #define OSP_SSL_LIFETIME      ((unsigned int)300)        /* SSL life time, in seconds */
00508 #define OSP_HTTP_PERSISTENCE  ((int)1)             /* In seconds */
00509 #define OSP_CUSTOMER_ID       ((const char*)"")       /* OSP customer ID */
00510 #define OSP_DEVICE_ID         ((const char*)"")       /* OSP device ID */
00511 #define OSP_DEF_MAXDESTS      ((unsigned int)5)       /* OSP default max number of destinations */
00512 #define OSP_DEF_TIMELIMIT     ((unsigned int)0)       /* OSP default duration limit, no limit */
00513 #define OSP_DEF_PROTOCOL      OSP_PROT_SIP            /* OSP default destination protocol, SIP */
00514 #define OSP_DEF_WORKMODE      OSP_MODE_DIRECT            /* OSP default work mode, direct */
00515 #define OSP_DEF_SRVTYPE       OSP_SRV_VOICE           /* OSP default service type, voice */
00516 #define OSP_MAX_CUSTOMINFO    ((unsigned int)8)       /* OSP max number of custom info */
00517 #define OSP_DEF_INTSTATS      ((int)-1)               /* OSP default int statistic */
00518 #define OSP_DEF_FLOATSTATS    ((float)-1)             /* OSP default float statistic */
00519 
00520 /* OSP Provider */
00521 struct osp_provider {
00522    OSPTPROVHANDLE handle;                    /* OSP provider handle */
00523    char name[OSP_SIZE_NORSTR];                  /* OSP provider context name */
00524    char privatekey[OSP_SIZE_NORSTR];            /* OSP private key file name */
00525    char localcert[OSP_SIZE_NORSTR];          /* OSP local cert file name */
00526    unsigned int canum;                       /* Number of cacerts */
00527    char cacerts[OSP_MAX_CERTS][OSP_SIZE_NORSTR];   /* Cacert file names */
00528    unsigned int spnum;                       /* Number of service points */
00529    char spoints[OSP_MAX_SPOINTS][OSP_SIZE_NORSTR]; /* Service point URLs */
00530    unsigned int maxconnect;                  /* Max number of connections */
00531    unsigned int retrydelay;                  /* Retry delay */
00532    unsigned int retrylimit;                  /* Retry limit */
00533    unsigned int timeout;                     /* Timeout in ms */
00534    char source[OSP_SIZE_NORSTR];             /* IP of self */
00535    enum osp_authpolicy authpolicy;              /* OSP authentication policy */
00536    const char* defprotocol;                  /* OSP default destination protocol */
00537    enum osp_workmode workmode;                  /* OSP work mode */
00538    enum osp_srvtype srvtype;                 /* OSP service type */
00539    struct osp_provider* next;                /* Pointer to next OSP provider */
00540 };
00541 
00542 /* Call ID */
00543 struct osp_callid {
00544    unsigned char buf[OSP_SIZE_NORSTR];    /* Call ID string */
00545    unsigned int len;                /* Call ID length */
00546 };
00547 
00548 /* Number Portability Data */
00549 struct osp_npdata {
00550    const char* rn;                     /* Rounding Number */
00551    const char* cic;                 /* Carrier Identification Code */
00552    int npdi;                        /* NP Database Dip Indicator */
00553    const char* opname[OSPC_OPNAME_NUMBER];   /* Operator Names */
00554 };
00555 
00556 /* SIP Diversion Header Parameters */
00557 struct osp_diversion {
00558    const char* user;                /* Diversion header user info */
00559    const char* host;                /* Diversion header host info */
00560 };
00561 
00562 /* OSP Application In/Output Results */
00563 struct osp_results {
00564    int inhandle;                             /* Inbound transaction handle */
00565    int outhandle;                            /* Outbound transaction handle */
00566    unsigned int intimelimit;                    /* Inbound duration limit */
00567    unsigned int outtimelimit;                   /* Outbound duration limit */
00568    char tech[OSP_SIZE_TECHSTR];                 /* Outbound Asterisk TECH string */
00569    char dest[OSP_SIZE_NORSTR];                     /* Outbound destination IP address */
00570    char calling[OSP_SIZE_NORSTR];                  /* Outbound calling number, may be translated */
00571    char called[OSP_SIZE_NORSTR];                /* Outbound called number, may be translated */
00572    char token[OSP_SIZE_TOKSTR];                 /* Outbound OSP token */
00573    char networkid[OSP_SIZE_NORSTR];             /* Outbound network ID */
00574    char nprn[OSP_SIZE_NORSTR];                     /* Outbound NP routing number */
00575    char npcic[OSP_SIZE_NORSTR];                 /* Outbound NP carrier identification code */
00576    int npdi;                                 /* Outbound NP database dip indicator */
00577    char opname[OSPC_OPNAME_NUMBER][OSP_SIZE_NORSTR];  /* Outbound Operator names */
00578    unsigned int numdests;                       /* Number of remain outbound destinations */
00579    struct osp_callid outcallid;                 /* Outbound call ID */
00580 };
00581 
00582 /* OSP Call Leg */
00583 enum osp_callleg {
00584    OSP_CALL_INBOUND, /* Inbound call leg */
00585    OSP_CALL_OUTBOUND /* Outbound call leg */
00586 };
00587 
00588 /* OSP Media Stream Direction */
00589 enum osp_direction {
00590    OSP_DIR_RX = 0,      /* Receive */
00591    OSP_DIR_TX,       /* Send */
00592    OSP_DIR_NUMBER    /* Number of directions */
00593 };
00594 
00595 /* OSP Metrics */
00596 struct osp_metrics {
00597    int value;        /* Value */
00598    float min;        /* Minimum */
00599    float max;        /* Maximum */
00600    float avg;        /* Average */
00601    float ndev;       /* Normal deviation */
00602    float sdev;       /* Standard deviation */
00603 };
00604 
00605 /* OSP Module Global Variables */
00606 AST_MUTEX_DEFINE_STATIC(osp_lock);                    /* Lock of OSP provider list */
00607 static int osp_initialized = 0;                       /* Init flag */
00608 static int osp_hardware = 0;                       /* Hardware accelleration flag */
00609 static int osp_security = 0;                       /* Using security features flag */
00610 static struct osp_provider* osp_providers = NULL;        /* OSP provider list */
00611 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED; /* Token format supported */
00612 
00613 /* OSP default certificates */
00614 const char* B64PKey = "MIIBOgIBAAJBAK8t5l+PUbTC4lvwlNxV5lpl+2dwSZGW46dowTe6y133XyVEwNiiRma2YNk3xKs/TJ3Wl9Wpns2SYEAJsFfSTukCAwEAAQJAPz13vCm2GmZ8Zyp74usTxLCqSJZNyMRLHQWBM0g44Iuy4wE3vpi7Wq+xYuSOH2mu4OddnxswCP4QhaXVQavTAQIhAOBVCKXtppEw9UaOBL4vW0Ed/6EA/1D8hDW6St0h7EXJAiEAx+iRmZKhJD6VT84dtX5ZYNVk3j3dAcIOovpzUj9a0CECIEduTCapmZQ5xqAEsLXuVlxRtQgLTUD4ZxDElPn8x0MhAiBE2HlcND0+qDbvtwJQQOUzDgqg5xk3w8capboVdzAlQQIhAMC+lDL7+gDYkNAft5Mu+NObJmQs4Cr+DkDFsKqoxqrm";
00615 const char* B64LCert = "MIIBeTCCASMCEHqkOHVRRWr+1COq3CR/xsowDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTA1MDYyMzAwMjkxOFoXDTA2MDYyNDAwMjkxOFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCvLeZfj1G0wuJb8JTcVeZaZftncEmRluOnaME3ustd918lRMDYokZmtmDZN8SrP0yd1pfVqZ7NkmBACbBX0k7pAgMBAAEwDQYJKoZIhvcNAQEEBQADQQDnV8QNFVVJx/+7IselU0wsepqMurivXZzuxOmTEmTVDzCJx1xhA8jd3vGAj7XDIYiPub1PV23eY5a2ARJuw5w9";
00616 const char* B64CACert = "MIIBYDCCAQoCAQEwDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTAyMDIwNDE4MjU1MloXDTEyMDIwMzE4MjU1MlowOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPGeGwV41EIhX0jEDFLRXQhDEr50OUQPq+f55VwQd0TQNts06BP29+UiNdRW3c3IRHdZcJdC1Cg68ME9cgeq0h8CAwEAATANBgkqhkiG9w0BAQQFAANBAGkzBSj1EnnmUxbaiG1N4xjIuLAWydun7o3bFk2tV8dBIhnuh445obYyk1EnQ27kI7eACCILBZqi2MHDOIMnoN0=";
00617 
00618 /* OSP Client Wrapper APIs */
00619 
00620 /*!
00621  * \brief Create OSP provider handle according to configuration
00622  * \param cfg OSP configuration
00623  * \param name OSP provider context name
00624  * \return OSP_OK Success, OSP_FAILED Failed, OSP_ERROR Error
00625  */
00626 static int osp_create_provider(
00627    struct ast_config* cfg,
00628    const char* name)
00629 {
00630    int res = OSP_FAILED;
00631    struct ast_variable* var;
00632    struct osp_provider* provider;
00633    OSPTPRIVATEKEY privatekey;
00634    OSPT_CERT localcert;
00635    OSPT_CERT cacerts[OSP_MAX_CERTS];
00636    const OSPT_CERT* pcacerts[OSP_MAX_CERTS];
00637    const char* pspoints[OSP_MAX_SPOINTS];
00638    unsigned char privatekeydata[OSP_SIZE_KEYSTR];
00639    unsigned char localcertdata[OSP_SIZE_KEYSTR];
00640    unsigned char cacertdata[OSP_SIZE_KEYSTR];
00641    int i, num, error = OSPC_ERR_NO_ERROR;
00642 
00643    if (!(provider = ast_calloc(1, sizeof(*provider)))) {
00644       ast_log(LOG_ERROR, "Out of memory\n");
00645       return OSP_ERROR;
00646    }
00647 
00648    /* ast_calloc has set 0 in provider */
00649    provider->handle = OSP_INVALID_HANDLE;
00650    ast_copy_string(provider->name, name, sizeof(provider->name));
00651    snprintf(provider->privatekey, sizeof(provider->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, name);
00652    snprintf(provider->localcert, sizeof(provider->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, name);
00653    snprintf(provider->cacerts[0], sizeof(provider->cacerts[0]), "%s/%s-cacert_0.pem", ast_config_AST_KEY_DIR, name);
00654    provider->maxconnect = OSP_DEF_MAXCONNECT;
00655    provider->retrydelay = OSP_DEF_RETRYDELAY;
00656    provider->retrylimit = OSP_DEF_RETRYLIMIT;
00657    provider->timeout = OSP_DEF_TIMEOUT;
00658    provider->authpolicy = OSP_DEF_AUTHPOLICY;
00659    provider->defprotocol = OSP_DEF_PROTOCOL;
00660    provider->workmode = OSP_DEF_WORKMODE;
00661    provider->srvtype = OSP_DEF_SRVTYPE;
00662 
00663    for (var = ast_variable_browse(cfg, name); var != NULL; var = var->next) {
00664       if (!strcasecmp(var->name, "privatekey")) {
00665          if (osp_security) {
00666             if (var->value[0] == '/') {
00667                ast_copy_string(provider->privatekey, var->value, sizeof(provider->privatekey));
00668             } else {
00669                snprintf(provider->privatekey, sizeof(provider->privatekey), "%s/%s", ast_config_AST_KEY_DIR, var->value);
00670             }
00671             ast_debug(1, "OSP: privatekey '%s'\n", provider->privatekey);
00672          }
00673       } else if (!strcasecmp(var->name, "localcert")) {
00674          if (osp_security) {
00675             if (var->value[0] == '/') {
00676                ast_copy_string(provider->localcert, var->value, sizeof(provider->localcert));
00677             } else {
00678                snprintf(provider->localcert, sizeof(provider->localcert), "%s/%s", ast_config_AST_KEY_DIR, var->value);
00679             }
00680             ast_debug(1, "OSP: localcert '%s'\n", provider->localcert);
00681          }
00682       } else if (!strcasecmp(var->name, "cacert")) {
00683          if (osp_security) {
00684             if (provider->canum < OSP_MAX_CERTS) {
00685                if (var->value[0] == '/') {
00686                   ast_copy_string(provider->cacerts[provider->canum], var->value, sizeof(provider->cacerts[provider->canum]));
00687                } else {
00688                   snprintf(provider->cacerts[provider->canum], sizeof(provider->cacerts[provider->canum]), "%s/%s", ast_config_AST_KEY_DIR, var->value);
00689                }
00690                ast_debug(1, "OSP: cacerts[%d]: '%s'\n", provider->canum, provider->cacerts[provider->canum]);
00691                provider->canum++;
00692             } else {
00693                ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", var->lineno);
00694             }
00695          }
00696       } else if (!strcasecmp(var->name, "servicepoint")) {
00697          if (provider->spnum < OSP_MAX_SPOINTS) {
00698             ast_copy_string(provider->spoints[provider->spnum], var->value, sizeof(provider->spoints[provider->spnum]));
00699             ast_debug(1, "OSP: servicepoint[%d]: '%s'\n", provider->spnum, provider->spoints[provider->spnum]);
00700             provider->spnum++;
00701          } else {
00702             ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", var->lineno);
00703          }
00704       } else if (!strcasecmp(var->name, "maxconnect")) {
00705          if ((sscanf(var->value, "%30d", &num) == 1) && (num >= OSP_MIN_MAXCONNECT) && (num <= OSP_MAX_MAXCONNECT)) {
00706             provider->maxconnect = num;
00707             ast_debug(1, "OSP: maxconnect '%d'\n", num);
00708          } else {
00709             ast_log(LOG_WARNING, "OSP: maxconnect should be an integer from %d to %d, not '%s' at line %d\n",
00710                OSP_MIN_MAXCONNECT, OSP_MAX_MAXCONNECT, var->value, var->lineno);
00711          }
00712       } else if (!strcasecmp(var->name, "retrydelay")) {
00713          if ((sscanf(var->value, "%30d", &num) == 1) && (num >= OSP_MIN_RETRYDELAY) && (num <= OSP_MAX_RETRYDELAY)) {
00714             provider->retrydelay = num;
00715             ast_debug(1, "OSP: retrydelay '%d'\n", num);
00716          } else {
00717             ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n",
00718                OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, var->value, var->lineno);
00719          }
00720       } else if (!strcasecmp(var->name, "retrylimit")) {
00721          if ((sscanf(var->value, "%30d", &num) == 1) && (num >= OSP_MIN_RETRYLIMIT) && (num <= OSP_MAX_RETRYLIMIT)) {
00722             provider->retrylimit = num;
00723             ast_debug(1, "OSP: retrylimit '%d'\n", num);
00724          } else {
00725             ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n",
00726                OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, var->value, var->lineno);
00727          }
00728       } else if (!strcasecmp(var->name, "timeout")) {
00729          if ((sscanf(var->value, "%30d", &num) == 1) && (num >= OSP_MIN_TIMEOUT) && (num <= OSP_MAX_TIMEOUT)) {
00730             provider->timeout = num;
00731             ast_debug(1, "OSP: timeout '%d'\n", num);
00732          } else {
00733             ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n",
00734                OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, var->value, var->lineno);
00735          }
00736       } else if (!strcasecmp(var->name, "source")) {
00737          ast_copy_string(provider->source, var->value, sizeof(provider->source));
00738          ast_debug(1, "OSP: source '%s'\n", provider->source);
00739       } else if (!strcasecmp(var->name, "authpolicy")) {
00740          if ((sscanf(var->value, "%30d", &num) == 1) && ((num == OSP_AUTH_NO) || (num == OSP_AUTH_YES) || (num == OSP_AUTH_EXC))) {
00741             provider->authpolicy = num;
00742             ast_debug(1, "OSP: authpolicy '%d'\n", num);
00743          } else {
00744             ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n",
00745                OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXC, var->value, var->lineno);
00746          }
00747       } else if (!strcasecmp(var->name, "defprotocol")) {
00748          if (!strcasecmp(var->value, OSP_PROT_SIP)) {
00749             provider->defprotocol = OSP_PROT_SIP;
00750             ast_debug(1, "OSP: default protocol SIP\n");
00751          } else if (!strcasecmp(var->value, OSP_PROT_H323)) {
00752             provider->defprotocol = OSP_PROT_H323;
00753             ast_debug(1, "OSP: default protocol H.323\n");
00754          } else if (!strcasecmp(var->value, OSP_PROT_IAX)) {
00755             provider->defprotocol = OSP_PROT_IAX;
00756             ast_debug(1, "OSP: default protocol IAX\n");
00757          } else if (!strcasecmp(var->value, OSP_PROT_SKYPE)) {
00758             provider->defprotocol = OSP_PROT_SKYPE;
00759             ast_debug(1, "OSP: default protocol Skype\n");
00760          } else {
00761             ast_log(LOG_WARNING, "OSP: default protocol should be %s, %s, %s or %s not '%s' at line %d\n",
00762                OSP_PROT_SIP, OSP_PROT_H323, OSP_PROT_IAX, OSP_PROT_SKYPE, var->value, var->lineno);
00763          }
00764       } else if (!strcasecmp(var->name, "workmode")) {
00765          if ((sscanf(var->value, "%30d", &num) == 1) && ((num == OSP_MODE_DIRECT) || (num == OSP_MODE_INDIRECT))) {
00766             provider->workmode = num;
00767             ast_debug(1, "OSP: workmode '%d'\n", num);
00768          } else {
00769             ast_log(LOG_WARNING, "OSP: workmode should be %d or %d, not '%s' at line %d\n",
00770                OSP_MODE_DIRECT, OSP_MODE_INDIRECT, var->value, var->lineno);
00771          }
00772       } else if (!strcasecmp(var->name, "servicetype")) {
00773          if ((sscanf(var->value, "%30d", &num) == 1) && ((num == OSP_SRV_VOICE) || (num == OSP_SRV_NPQUERY))) {
00774             provider->srvtype = num;
00775             ast_debug(1, "OSP: servicetype '%d'\n", num);
00776          } else {
00777             ast_log(LOG_WARNING, "OSP: servicetype should be %d or %d, not '%s' at line %d\n",
00778                OSP_SRV_VOICE, OSP_SRV_NPQUERY, var->value, var->lineno);
00779          }
00780       }
00781    }
00782 
00783    if (provider->canum == 0) {
00784       provider->canum = 1;
00785    }
00786 
00787    for (i = 0; i < provider->spnum; i++) {
00788       pspoints[i] = provider->spoints[i];
00789    }
00790 
00791    if (osp_security) {
00792       privatekey.PrivateKeyData = NULL;
00793       privatekey.PrivateKeyLength = 0;
00794 
00795       localcert.CertData = NULL;
00796       localcert.CertDataLength = 0;
00797 
00798       for (i = 0; i < provider->canum; i++) {
00799          cacerts[i].CertData = NULL;
00800          cacerts[i].CertDataLength = 0;
00801       }
00802 
00803       if ((error = OSPPUtilLoadPEMPrivateKey((unsigned char*)provider->privatekey, &privatekey)) != OSPC_ERR_NO_ERROR) {
00804          ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", provider->privatekey, error);
00805       } else if ((error = OSPPUtilLoadPEMCert((unsigned char*)provider->localcert, &localcert)) != OSPC_ERR_NO_ERROR) {
00806          ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", provider->localcert, error);
00807       } else {
00808          for (i = 0; i < provider->canum; i++) {
00809             if ((error = OSPPUtilLoadPEMCert((unsigned char*)provider->cacerts[i], &cacerts[i])) != OSPC_ERR_NO_ERROR) {
00810                ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", provider->cacerts[i], error);
00811                break;
00812             } else {
00813                pcacerts[i] = &cacerts[i];
00814             }
00815          }
00816       }
00817    } else {
00818       privatekey.PrivateKeyData = privatekeydata;
00819       privatekey.PrivateKeyLength = sizeof(privatekeydata);
00820 
00821       localcert.CertData = localcertdata;
00822       localcert.CertDataLength = sizeof(localcertdata);
00823 
00824       cacerts[0].CertData = cacertdata;
00825       cacerts[0].CertDataLength = sizeof(cacertdata);
00826       pcacerts[0] = &cacerts[0];
00827 
00828       if ((error = OSPPBase64Decode(B64PKey, strlen(B64PKey), privatekey.PrivateKeyData, &privatekey.PrivateKeyLength)) != OSPC_ERR_NO_ERROR) {
00829          ast_log(LOG_WARNING, "OSP: Unable to decode private key, error '%d'\n", error);
00830       } else if ((error = OSPPBase64Decode(B64LCert, strlen(B64LCert), localcert.CertData, &localcert.CertDataLength)) != OSPC_ERR_NO_ERROR) {
00831          ast_log(LOG_WARNING, "OSP: Unable to decode local cert, error '%d'\n", error);
00832       } else if ((error = OSPPBase64Decode(B64CACert, strlen(B64CACert), cacerts[0].CertData, &cacerts[0].CertDataLength)) != OSPC_ERR_NO_ERROR) {
00833          ast_log(LOG_WARNING, "OSP: Unable to decode cacert, error '%d'\n", error);
00834       }
00835    }
00836 
00837    if (error == OSPC_ERR_NO_ERROR) {
00838       error = OSPPProviderNew(provider->spnum,
00839          pspoints,
00840          NULL,
00841          OSP_AUDIT_URL,
00842          &privatekey,
00843          &localcert,
00844          provider->canum,
00845          pcacerts,
00846          OSP_LOCAL_VALIDATION,
00847          OSP_SSL_LIFETIME,
00848          provider->maxconnect,
00849          OSP_HTTP_PERSISTENCE,
00850          provider->retrydelay,
00851          provider->retrylimit,
00852          provider->timeout,
00853          OSP_CUSTOMER_ID,
00854          OSP_DEVICE_ID,
00855          &provider->handle);
00856       if (error != OSPC_ERR_NO_ERROR) {
00857          ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", name, error);
00858          res = OSP_ERROR;
00859       } else {
00860          ast_debug(1, "OSP: provider '%s'\n", name);
00861          ast_mutex_lock(&osp_lock);
00862          provider->next = osp_providers;
00863          osp_providers = provider;
00864          ast_mutex_unlock(&osp_lock);
00865          res = OSP_OK;
00866       }
00867    }
00868 
00869    if (osp_security) {
00870       for (i = 0; i < provider->canum; i++) {
00871          if (cacerts[i].CertData) {
00872             ast_free(cacerts[i].CertData);
00873          }
00874       }
00875       if (localcert.CertData) {
00876          ast_free(localcert.CertData);
00877       }
00878       if (privatekey.PrivateKeyData) {
00879          ast_free(privatekey.PrivateKeyData);
00880       }
00881    }
00882 
00883    if (res != OSP_OK) {
00884       ast_free(provider);
00885    }
00886 
00887    return res;
00888 }
00889 
00890 /*!
00891  * \brief Get OSP provider by name
00892  * \param name OSP provider context name
00893  * \param provider OSP provider structure
00894  * \return OSP_OK Success, OSP_FAILED Failed, OSP_ERROR Error
00895  */
00896 static int osp_get_provider(
00897    const char* name,
00898    struct osp_provider** provider)
00899 {
00900    int res = OSP_FAILED;
00901    struct osp_provider* p;
00902 
00903    *provider = NULL;
00904 
00905    ast_mutex_lock(&osp_lock);
00906    for (p = osp_providers; p != NULL; p = p->next) {
00907       if (!strcasecmp(p->name, name)) {
00908          *provider = p;
00909          ast_debug(1, "OSP: find provider '%s'\n", name);
00910          res = OSP_OK;
00911          break;
00912       }
00913    }
00914    ast_mutex_unlock(&osp_lock);
00915 
00916    return res;
00917 }
00918 
00919 /*!
00920  * \brief Create OSP transaction handle
00921  * \param name OSP provider context name
00922  * \param trans OSP transaction handle, output
00923  * \param source Source of provider, output
00924  * \param srcsize Size of source buffer, in
00925  * \return OSK_OK Success, OSK_FAILED Failed, OSP_ERROR Error
00926  */
00927 static int osp_create_transaction(
00928    const char* name,
00929    int* trans,
00930    char* source,
00931    unsigned int srcsize)
00932 {
00933    int res = OSP_FAILED;
00934    struct osp_provider* provider;
00935    int error;
00936 
00937    if ((trans == NULL) || (source == NULL) || (srcsize <= 0)) {
00938       ast_log(LOG_ERROR, "Invalid parameters\n");
00939       return OSP_ERROR;
00940    }
00941 
00942    *trans = OSP_INVALID_HANDLE;
00943    *source = '\0';
00944 
00945    ast_mutex_lock(&osp_lock);
00946    for (provider = osp_providers; provider; provider = provider->next) {
00947       if (!strcasecmp(provider->name, name)) {
00948          error = OSPPTransactionNew(provider->handle, trans);
00949          if (error == OSPC_ERR_NO_ERROR) {
00950             ast_debug(1, "OSP: transaction '%d'\n", *trans);
00951             ast_copy_string(source, provider->source, srcsize);
00952             ast_debug(1, "OSP: source '%s'\n", source);
00953             res = OSP_OK;
00954          } else {
00955             *trans = OSP_INVALID_HANDLE;
00956             ast_debug(1, "OSP: Unable to create transaction handle, error '%d'\n", error);
00957             *source = '\0';
00958             res = OSP_ERROR;
00959          }
00960          break;
00961       }
00962    }
00963    ast_mutex_unlock(&osp_lock);
00964 
00965    return res;
00966 }
00967 
00968 /*!
00969  * \brief Convert "address:port" to "[x.x.x.x]:port" or "hostname:port" format
00970  * \param src Source address string
00971  * \param dest Destination address string
00972  * \param destsize Size of dest buffer
00973  */
00974 static void osp_convert_inout(
00975    const char* src,
00976    char* dest,
00977    unsigned int destsize)
00978 {
00979    struct in_addr inp;
00980    char buffer[OSP_SIZE_NORSTR];
00981    char* port;
00982 
00983    if ((dest != NULL) && (destsize > 0)) {
00984       if (!ast_strlen_zero(src)) {
00985          ast_copy_string(buffer, src, sizeof(buffer));
00986 
00987          if((port = strchr(buffer, ':')) != NULL) {
00988             *port = '\0';
00989             port++;
00990          }
00991 
00992          if (inet_pton(AF_INET, buffer, &inp) == 1) {
00993             if (port != NULL) {
00994                snprintf(dest, destsize, "[%s]:%s", buffer, port);
00995             } else {
00996                snprintf(dest, destsize, "[%s]", buffer);
00997             }
00998             dest[destsize - 1] = '\0';
00999          } else {
01000             ast_copy_string(dest, src, destsize);
01001          }
01002       } else {
01003          *dest = '\0';
01004       }
01005    }
01006 }
01007 
01008 /*!
01009  * \brief Convert "[x.x.x.x]:port" or "hostname:prot" to "address:port" format
01010  * \param src Source address string
01011  * \param dest Destination address string
01012  * \param destsize Size of dest buffer
01013  */
01014 static void osp_convert_outin(
01015    const char* src,
01016    char* dest,
01017    unsigned int destsize)
01018 {
01019    char buffer[OSP_SIZE_NORSTR];
01020    char* end;
01021    char* port;
01022 
01023    if ((dest != NULL) && (destsize > 0)) {
01024       if (!ast_strlen_zero(src)) {
01025          ast_copy_string(buffer, src, sizeof(buffer));
01026 
01027          if (buffer[0] == '[') {
01028             if((port = strchr(buffer + 1, ':')) != NULL) {
01029                *port = '\0';
01030                port++;
01031             }
01032 
01033             if ((end = strchr(buffer + 1, ']')) != NULL) {
01034                *end = '\0';
01035             }
01036 
01037             if (port != NULL) {
01038                snprintf(dest, destsize, "%s:%s", buffer + 1, port);
01039                dest[destsize - 1] = '\0';
01040             } else {
01041                ast_copy_string(dest, buffer + 1, destsize);
01042             }
01043          } else {
01044             ast_copy_string(dest, src, destsize);
01045          }
01046       } else {
01047          *dest = '\0';
01048       }
01049    }
01050 }
01051 
01052 /*!
01053  * \brief Validate OSP token of inbound call
01054  * \param trans OSP transaction handle
01055  * \param source Source of inbound call
01056  * \param destination Destination of inbound call
01057  * \param calling Calling number
01058  * \param called Called number
01059  * \param token OSP token, may be empty
01060  * \param timelimit Call duration limit, output
01061  * \return OSP_OK Success, OSP_FAILED Failed, OSP_ERROR Error
01062  */
01063 static int osp_validate_token(
01064    int trans,
01065    const char* source,
01066    const char* destination,
01067    const char* calling,
01068    const char* called,
01069    const char* token,
01070    unsigned int* timelimit)
01071 {
01072    int res;
01073    int tokenlen;
01074    unsigned char tokenstr[OSP_SIZE_TOKSTR];
01075    char src[OSP_SIZE_NORSTR];
01076    char dest[OSP_SIZE_NORSTR];
01077    unsigned int authorised;
01078    unsigned int dummy = 0;
01079    int error;
01080 
01081    if (timelimit == NULL) {
01082       ast_log(LOG_ERROR, "Invalid parameters\n");
01083       return OSP_ERROR;
01084    }
01085 
01086    tokenlen = ast_base64decode(tokenstr, token, strlen(token));
01087    osp_convert_inout(source, src, sizeof(src));
01088    osp_convert_inout(destination, dest, sizeof(dest));
01089    error = OSPPTransactionValidateAuthorisation(trans,
01090       src,
01091       dest,
01092       NULL,
01093       NULL,
01094       calling ? calling : "",
01095       OSPC_NFORMAT_E164,
01096       called,
01097       OSPC_NFORMAT_E164,
01098       0,
01099       NULL,
01100       tokenlen,
01101       (char*)tokenstr,
01102       &authorised,
01103       timelimit,
01104       &dummy,
01105       NULL,
01106       osp_tokenformat);
01107    if (error != OSPC_ERR_NO_ERROR) {
01108       ast_log(LOG_WARNING, "OSP: Unable to validate inbound token, error '%d'\n", error);
01109       *timelimit = 0;
01110       res = OSP_ERROR;
01111    } else if (authorised) {
01112       ast_debug(1, "OSP: Authorised\n");
01113       res = OSP_OK;
01114    } else {
01115       ast_debug(1, "OSP: Unauthorised\n");
01116       res = OSP_FAILED;
01117    }
01118 
01119    return res;
01120 }
01121 
01122 /*!
01123  * \brief Choose min duration limit
01124  * \param in Inbound duration limit
01125  * \param out Outbound duration limit
01126  * \return min duration limit
01127  */
01128 static unsigned int osp_choose_timelimit(
01129    unsigned int in,
01130    unsigned int out)
01131 {
01132    if (in == OSP_DEF_TIMELIMIT) {
01133       return out;
01134    } else if (out == OSP_DEF_TIMELIMIT) {
01135       return in;
01136    } else {
01137       return in < out ? in : out;
01138    }
01139 }
01140 
01141 /*!
01142  * \brief Choose min duration limit
01143  * \param provider OSP provider
01144  * \param calling Calling number
01145  * \param called Called number
01146  * \param destination Destination IP in '[x.x.x.x]' format
01147  * \param tokenlen OSP token length
01148  * \param token OSP token
01149  * \param reason Failure reason, output
01150  * \param results OSP lookup results, in/output
01151  * \return OSP_OK Success, OSP_FAILED Failed, OSP_ERROR Error
01152  */
01153 static int osp_check_destination(
01154    struct osp_provider* provider,
01155    const char* calling,
01156    const char* called,
01157    const char* destination,
01158    unsigned int tokenlen,
01159    const char* token,
01160    OSPEFAILREASON* reason,
01161    struct osp_results* results)
01162 {
01163    int res;
01164    OSPE_DEST_OSPENABLED enabled;
01165    OSPE_DEST_PROTOCOL protocol;
01166    char dest[OSP_SIZE_NORSTR];
01167    OSPE_OPERATOR_NAME type;
01168    int error;
01169 
01170    if ((provider == NULL) || (reason == NULL) || (results == NULL)) {
01171       ast_log(LOG_ERROR, "Invalid parameters\n");
01172       return OSP_ERROR;
01173    }
01174 
01175    if ((error = OSPPTransactionIsDestOSPEnabled(results->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
01176       ast_debug(1, "OSP: Unable to get destination OSP version, error '%d'\n", error);
01177       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
01178       return OSP_ERROR;
01179    }
01180 
01181    if (enabled == OSPC_DOSP_FALSE) {
01182       results->token[0] = '\0';
01183    } else {
01184       ast_base64encode(results->token, (const unsigned char*)token, tokenlen, sizeof(results->token) - 1);
01185    }
01186 
01187    if ((error = OSPPTransactionGetDestinationNetworkId(results->outhandle, sizeof(results->networkid), results->networkid)) != OSPC_ERR_NO_ERROR) {
01188       ast_debug(1, "OSP: Unable to get destination network ID, error '%d'\n", error);
01189       results->networkid[0] = '\0';
01190    }
01191 
01192    error = OSPPTransactionGetNumberPortabilityParameters(results->outhandle,
01193       sizeof(results->nprn),
01194       results->nprn,
01195       sizeof(results->npcic),
01196       results->npcic,
01197       &results->npdi);
01198    if (error != OSPC_ERR_NO_ERROR) {
01199       ast_debug(1, "OSP: Unable to get number portability parameters, error '%d'\n", error);
01200       results->nprn[0] = '\0';
01201       results->npcic[0] = '\0';
01202       results->npdi = 0;
01203    }
01204 
01205    for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
01206       error = OSPPTransactionGetOperatorName(results->outhandle, type, sizeof(results->opname[type]), results->opname[type]);
01207       if (error != OSPC_ERR_NO_ERROR) {
01208          ast_debug(1, "OSP: Unable to get operator name of type '%d', error '%d'\n", type, error);
01209          results->opname[type][0] = '\0';
01210       }
01211    }
01212 
01213    if ((error = OSPPTransactionGetDestProtocol(results->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
01214       ast_debug(1, "OSP: Unable to get destination protocol, error '%d'\n", error);
01215       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
01216       results->token[0] = '\0';
01217       results->networkid[0] = '\0';
01218       results->nprn[0] = '\0';
01219       results->npcic[0] = '\0';
01220       results->npdi = 0;
01221       for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
01222          results->opname[type][0] = '\0';
01223       }
01224       return OSP_ERROR;
01225    }
01226 
01227    res = OSP_OK;
01228    osp_convert_outin(destination, dest, sizeof(dest));
01229    switch(protocol) {
01230    case OSPC_DPROT_SIP:
01231       ast_debug(1, "OSP: protocol SIP\n");
01232       ast_copy_string(results->tech, OSP_TECH_SIP, sizeof(results->tech));
01233       ast_copy_string(results->dest, dest, sizeof(results->dest));
01234       ast_copy_string(results->calling, calling, sizeof(results->calling));
01235       ast_copy_string(results->called, called, sizeof(results->called));
01236       break;
01237    case OSPC_DPROT_Q931:
01238       ast_debug(1, "OSP: protocol Q.931\n");
01239       ast_copy_string(results->tech, OSP_TECH_H323, sizeof(results->tech));
01240       ast_copy_string(results->dest, dest, sizeof(results->dest));
01241       ast_copy_string(results->calling, calling, sizeof(results->calling));
01242       ast_copy_string(results->called, called, sizeof(results->called));
01243       break;
01244    case OSPC_DPROT_IAX:
01245       ast_debug(1, "OSP: protocol IAX\n");
01246       ast_copy_string(results->tech, OSP_TECH_IAX, sizeof(results->tech));
01247       ast_copy_string(results->dest, dest, sizeof(results->dest));
01248       ast_copy_string(results->calling, calling, sizeof(results->calling));
01249       ast_copy_string(results->called, called, sizeof(results->called));
01250       break;
01251    case OSPC_DPROT_SKYPE:
01252       ast_debug(1, "OSP: protocol Skype\n");
01253       ast_copy_string(results->tech, OSP_TECH_SKYPE, sizeof(results->tech));
01254       ast_copy_string(results->dest, dest, sizeof(results->dest));
01255       ast_copy_string(results->calling, calling, sizeof(results->calling));
01256       ast_copy_string(results->called, called, sizeof(results->called));
01257       break;
01258    case OSPC_DPROT_UNDEFINED:
01259    case OSPC_DPROT_UNKNOWN:
01260       ast_debug(1, "OSP: unknown/undefined protocol '%d'\n", protocol);
01261       ast_debug(1, "OSP: use default protocol '%s'\n", provider->defprotocol);
01262       ast_copy_string(results->tech, provider->defprotocol, sizeof(results->tech));
01263       ast_copy_string(results->dest, dest, sizeof(results->dest));
01264       ast_copy_string(results->calling, calling, sizeof(results->calling));
01265       ast_copy_string(results->called, called, sizeof(results->called));
01266       break;
01267    case OSPC_DPROT_LRQ:
01268    case OSPC_DPROT_T37:
01269    case OSPC_DPROT_T38:
01270    case OSPC_DPROT_SMPP:
01271    case OSPC_DPROT_XMPP:
01272    default:
01273       ast_log(LOG_WARNING, "OSP: unsupported protocol '%d'\n", protocol);
01274       *reason = OSPC_FAIL_PROTOCOL_ERROR;
01275       results->token[0] = '\0';
01276       results->networkid[0] = '\0';
01277       results->nprn[0] = '\0';
01278       results->npcic[0] = '\0';
01279       results->npdi = 0;
01280       for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
01281          results->opname[type][0] = '\0';
01282       }
01283       res = OSP_FAILED;
01284       break;
01285    }
01286 
01287    return res;
01288 }
01289 
01290 /*!
01291  * \brief Convert Asterisk status to TC code
01292  * \param cause Asterisk hangup cause
01293  * \return OSP TC code
01294  */
01295 static OSPEFAILREASON asterisk2osp(
01296    int cause)
01297 {
01298    return (OSPEFAILREASON)cause;
01299 }
01300 
01301 /*!
01302  * \brief OSP Authentication function
01303  * \param name OSP provider context name
01304  * \param trans OSP transaction handle, output
01305  * \param source Source of inbound call
01306  * \param calling Calling number
01307  * \param called Called number
01308  * \param token OSP token, may be empty
01309  * \param timelimit Call duration limit, output
01310  * \return OSP_OK Authenricated, OSP_FAILED Unauthenticated, OSP_ERROR Error
01311  */
01312 static int osp_auth(
01313    const char* name,
01314    int* trans,
01315    const char* source,
01316    const char* calling,
01317    const char* called,
01318    const char* token,
01319    unsigned int* timelimit)
01320 {
01321    int res;
01322    struct osp_provider* provider = NULL;
01323    char dest[OSP_SIZE_NORSTR];
01324 
01325    if ((trans == NULL) || (timelimit == NULL)) {
01326       ast_log(LOG_ERROR, "Invalid parameters\n");
01327       return OSP_ERROR;
01328    }
01329 
01330    *trans = OSP_INVALID_HANDLE;
01331    *timelimit = OSP_DEF_TIMELIMIT;
01332 
01333    if ((res = osp_get_provider(name, &provider)) <= 0) {
01334       ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", name);
01335       return res;
01336    }
01337 
01338    switch (provider->authpolicy) {
01339    case OSP_AUTH_NO:
01340       res = OSP_OK;
01341       break;
01342    case OSP_AUTH_EXC:
01343       if (ast_strlen_zero(token)) {
01344          res = OSP_FAILED;
01345       } else if ((res = osp_create_transaction(name, trans, dest, sizeof(dest))) <= 0) {
01346          ast_debug(1, "OSP: Unable to generate transaction handle\n");
01347          *trans = OSP_INVALID_HANDLE;
01348          res = OSP_FAILED;
01349       } else if((res = osp_validate_token(*trans, source, dest, calling, called, token, timelimit)) <= 0) {
01350          OSPPTransactionRecordFailure(*trans, OSPC_FAIL_CALL_REJECTED);
01351       }
01352       break;
01353    case OSP_AUTH_YES:
01354    default:
01355       if (ast_strlen_zero(token)) {
01356          res = OSP_OK;
01357       } else if ((res = osp_create_transaction(name, trans, dest, sizeof(dest))) <= 0) {
01358          ast_debug(1, "OSP: Unable to generate transaction handle\n");
01359          *trans = OSP_INVALID_HANDLE;
01360          res = OSP_FAILED;
01361       } else if((res = osp_validate_token(*trans, source, dest, calling, called, token, timelimit)) <= 0) {
01362          OSPPTransactionRecordFailure(*trans, OSPC_FAIL_CALL_REJECTED);
01363       }
01364       break;
01365    }
01366 
01367    return res;
01368 }
01369 
01370 /*!
01371  * \brief Create a UUID
01372  * \param uuid UUID buffer
01373  * \param bufsize UUID buffer size
01374  * \return OSK_OK Created, OSP_ERROR Error
01375  */
01376 static int osp_create_uuid(
01377    unsigned char* uuid,
01378    unsigned int* bufsize)
01379 {
01380    int i, res;
01381    long int tmp[OSP_SIZE_UUID / sizeof(long int)];
01382 
01383    if ((uuid != NULL) && (*bufsize >= OSP_SIZE_UUID)) {
01384       for (i = 0; i < OSP_SIZE_UUID / sizeof(long int); i++) {
01385          tmp[i] = ast_random();
01386       }
01387       memcpy(uuid, tmp, OSP_SIZE_UUID);
01388       *bufsize = OSP_SIZE_UUID;
01389       res = OSP_OK;
01390    } else {
01391       ast_log(LOG_ERROR, "Invalid parameters\n");
01392       res = OSP_ERROR;
01393    }
01394 
01395    return res;
01396 }
01397 
01398 /*!
01399  * \brief UUID to string
01400  * \param uuid UUID
01401  * \param buffer String buffer
01402  * \param bufsize String buffer size
01403  * \return OSP_OK Successed, OSP_ERROR Error
01404  */
01405 static int osp_uuid2str(
01406    unsigned char* uuid,
01407    char* buffer,
01408    unsigned int bufsize)
01409 {
01410    int res;
01411 
01412    if ((uuid != NULL) && (bufsize > OSP_SIZE_UUIDSTR)) {
01413       snprintf(buffer, bufsize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
01414          uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
01415          uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
01416       res = OSP_OK;
01417    } else {
01418       ast_log(LOG_ERROR, "Invalid parameters\n");
01419       res = OSP_ERROR;
01420    }
01421 
01422    return res;
01423 }
01424 
01425 /*!
01426  * \brief Create a call ID according to the type
01427  * \param type Call ID type
01428  * \param callid Call ID buffer
01429  * \return OSK_OK Created, OSP_FAILED Not create, OSP_ERROR Error
01430  */
01431 static int osp_create_callid(
01432    unsigned int type,
01433    struct osp_callid* callid)
01434 {
01435    int res;
01436 
01437    if (callid == NULL) {
01438       ast_log(LOG_ERROR, "Invalid parameters\n");
01439       res = OSP_ERROR;
01440    }
01441 
01442    callid->len = sizeof(callid->buf);
01443    switch (type) {
01444    case OSP_CALLID_H323:
01445       res = osp_create_uuid(callid->buf, &callid->len);
01446       break;
01447    case OSP_CALLID_SIP:
01448    case OSP_CALLID_IAX:
01449       res = OSP_FAILED;
01450    default:
01451       res = OSP_ERROR;
01452       break;
01453    }
01454 
01455    if ((res != OSP_OK) && (callid->len != 0)) {
01456       callid->buf[0] = '\0';
01457       callid->len = 0;
01458    }
01459 
01460    return res;
01461 }
01462 
01463 /*!
01464  * \brief OSP Lookup function
01465  * \param name OSP provider context name
01466  * \param callidtypes Call ID types
01467  * \param actualsrc Actual source device in indirect mode
01468  * \param srcdev Source device of outbound call
01469  * \param calling Calling number
01470  * \param called Called number
01471  * \param snetid Source network ID
01472  * \param np NP parameters
01473  * \param div SIP Diversion header parameters
01474  * \param cinfo Custom info
01475  * \param results Lookup results
01476  * \return OSP_OK Found , OSP_FAILED No route, OSP_ERROR Error
01477  */
01478 static int osp_lookup(
01479    const char* name,
01480    unsigned int callidtypes,
01481    const char* actualsrc,
01482    const char* srcdev,
01483    const char* calling,
01484    const char* called,
01485    const char* snetid,
01486    struct osp_npdata* np,
01487    struct osp_diversion* div,
01488    const char* cinfo[],
01489    struct osp_results* results)
01490 {
01491    int res;
01492    struct osp_provider* provider = NULL;
01493    char source[OSP_SIZE_NORSTR];
01494    char callingnum[OSP_SIZE_NORSTR];
01495    char callednum[OSP_SIZE_NORSTR];
01496    char destination[OSP_SIZE_NORSTR];
01497    char* tmp;
01498    unsigned int tokenlen;
01499    char token[OSP_SIZE_TOKSTR];
01500    char src[OSP_SIZE_NORSTR];
01501    char dev[OSP_SIZE_NORSTR];
01502    char host[OSP_SIZE_NORSTR];
01503    unsigned int i, type;
01504    struct osp_callid callid;
01505    unsigned int callidnum;
01506    OSPT_CALL_ID* callids[OSP_CALLID_MAXNUM];
01507    char dest[OSP_SIZE_NORSTR];
01508    const char* preferred[2] = { NULL };
01509    unsigned int dummy = 0;
01510    OSPEFAILREASON reason;
01511    int error;
01512 
01513    if (results == NULL) {
01514       ast_log(LOG_ERROR, "Invalid parameters\n");
01515       res = OSP_ERROR;
01516    }
01517 
01518    osp_convert_inout(results->dest, dest, sizeof(dest));
01519 
01520    results->outhandle = OSP_INVALID_HANDLE;
01521    results->tech[0] = '\0';
01522    results->calling[0] = '\0';
01523    results->called[0] = '\0';
01524    results->token[0] = '\0';
01525    results->networkid[0] = '\0';
01526    results->nprn[0] = '\0';
01527    results->npcic[0] = '\0';
01528    results->npdi = 0;
01529    for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
01530       results->opname[type][0] = '\0';
01531    }
01532    results->numdests = 0;
01533    results->outtimelimit = OSP_DEF_TIMELIMIT;
01534 
01535    if ((res = osp_get_provider(name, &provider)) <= 0) {
01536       ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", name);
01537       return res;
01538    }
01539 
01540    if ((res = osp_create_transaction(name, &results->outhandle, source, sizeof(source))) <= 0) {
01541       ast_debug(1, "OSP: Unable to generate transaction handle\n");
01542       results->outhandle = OSP_INVALID_HANDLE;
01543       if (results->inhandle != OSP_INVALID_HANDLE) {
01544          OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
01545       }
01546       return OSP_ERROR;
01547    }
01548 
01549    if (!ast_strlen_zero(snetid)) {
01550       OSPPTransactionSetNetworkIds(results->outhandle, snetid, "");
01551    }
01552 
01553    OSPPTransactionSetNumberPortability(results->outhandle, np->rn, np->cic, np->npdi);
01554 
01555    for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
01556       OSPPTransactionSetOperatorName(results->outhandle, type, np->opname[type]);
01557    }
01558 
01559    osp_convert_inout(div->host, host, sizeof(host));
01560    OSPPTransactionSetDiversion(results->outhandle, div->user, host);
01561 
01562    if (cinfo != NULL) {
01563       for (i = 0; i < OSP_MAX_CUSTOMINFO; i++) {
01564          if (!ast_strlen_zero(cinfo[i])) {
01565             OSPPTransactionSetCustomInfo(results->outhandle, i, cinfo[i]);
01566          }
01567       }
01568    }
01569 
01570    ast_copy_string(callednum, called, sizeof(callednum));
01571    if((tmp = strchr(callednum, ';')) != NULL) {
01572       *tmp = '\0';
01573    }
01574 
01575    callidnum = 0;
01576    callids[0] = NULL;
01577    for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
01578       type = 1 << i;
01579       if (callidtypes & type) {
01580          error = osp_create_callid(type, &callid);
01581          if (error == 1) {
01582             callids[callidnum] = OSPPCallIdNew(callid.len, callid.buf);
01583             callidnum++;
01584          }
01585       }
01586    }
01587 
01588    if (provider->workmode == OSP_MODE_INDIRECT) {
01589       osp_convert_inout(srcdev, src, sizeof(src));
01590       if (ast_strlen_zero(actualsrc)) {
01591          osp_convert_inout(srcdev, dev, sizeof(dev));
01592       } else {
01593          osp_convert_inout(actualsrc, dev, sizeof(dev));
01594       }
01595    } else {
01596       osp_convert_inout(source, src, sizeof(src));
01597       osp_convert_inout(srcdev, dev, sizeof(dev));
01598    }
01599 
01600    if (provider->srvtype == OSP_SRV_NPQUERY) {
01601       OSPPTransactionSetServiceType(results->outhandle, OSPC_SERVICE_NPQUERY);
01602       if (!ast_strlen_zero(dest)) {
01603          preferred[0] = dest;
01604       }
01605       results->numdests = 1;
01606    } else {
01607       OSPPTransactionSetServiceType(results->outhandle, OSPC_SERVICE_VOICE);
01608       results->numdests = OSP_DEF_MAXDESTS;
01609    }
01610    error = OSPPTransactionRequestAuthorisation(results->outhandle,
01611       src,
01612       dev,
01613       calling ? calling : "",
01614       OSPC_NFORMAT_E164,
01615       callednum,
01616       OSPC_NFORMAT_E164,
01617       NULL,
01618       callidnum,
01619       callids,
01620       preferred,
01621       &results->numdests,
01622       &dummy,
01623       NULL);
01624 
01625    for (i = 0; i < callidnum; i++) {
01626       OSPPCallIdDelete(&callids[i]);
01627    }
01628 
01629    if (error != OSPC_ERR_NO_ERROR) {
01630       ast_log(LOG_WARNING, "OSP: Unable to request authorization, error '%d'\n", error);
01631       results->numdests = 0;
01632       if (results->inhandle != OSP_INVALID_HANDLE) {
01633          OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
01634       }
01635       return OSP_ERROR;
01636    }
01637 
01638    if (!results->numdests) {
01639       ast_debug(1, "OSP: No more destination\n");
01640       if (results->inhandle != OSP_INVALID_HANDLE) {
01641          OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01642       }
01643       return OSP_FAILED;
01644    }
01645 
01646    results->outcallid.len = sizeof(results->outcallid.buf);
01647    tokenlen = sizeof(token);
01648    error = OSPPTransactionGetFirstDestination(results->outhandle,
01649       0,
01650       NULL,
01651       NULL,
01652       &results->outtimelimit,
01653       &results->outcallid.len,
01654       results->outcallid.buf,
01655       sizeof(callednum),
01656       callednum,
01657       sizeof(callingnum),
01658       callingnum,
01659       sizeof(destination),
01660       destination,
01661       0,
01662       NULL,
01663       &tokenlen,
01664       token);
01665    if (error != OSPC_ERR_NO_ERROR) {
01666       ast_debug(1, "OSP: Unable to get first route, error '%d'\n", error);
01667       results->numdests = 0;
01668       results->outtimelimit = OSP_DEF_TIMELIMIT;
01669       if (results->inhandle != OSP_INVALID_HANDLE) {
01670          OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01671       }
01672       return OSP_ERROR;
01673    }
01674 
01675    results->numdests--;
01676    results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
01677    ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
01678    ast_debug(1, "OSP: calling '%s'\n", callingnum);
01679    ast_debug(1, "OSP: called '%s'\n", callednum);
01680    ast_debug(1, "OSP: destination '%s'\n", destination);
01681    ast_debug(1, "OSP: token size '%d'\n", tokenlen);
01682 
01683    if ((res = osp_check_destination(provider, callingnum, callednum, destination, tokenlen, token, &reason, results)) > 0) {
01684       return OSP_OK;
01685    }
01686 
01687    if (!results->numdests) {
01688       ast_debug(1, "OSP: No more destination\n");
01689       results->outtimelimit = OSP_DEF_TIMELIMIT;
01690       OSPPTransactionRecordFailure(results->outhandle, reason);
01691       if (results->inhandle != OSP_INVALID_HANDLE) {
01692          OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01693       }
01694       return OSP_FAILED;
01695    }
01696 
01697    while(results->numdests) {
01698       results->outcallid.len = sizeof(results->outcallid.buf);
01699       tokenlen = sizeof(token);
01700       error = OSPPTransactionGetNextDestination(results->outhandle,
01701          reason,
01702          0,
01703          NULL,
01704          NULL,
01705          &results->outtimelimit,
01706          &results->outcallid.len,
01707          results->outcallid.buf,
01708          sizeof(callednum),
01709          callednum,
01710          sizeof(callingnum),
01711          callingnum,
01712          sizeof(destination),
01713          destination,
01714          0,
01715          NULL,
01716          &tokenlen,
01717          token);
01718       if (error == OSPC_ERR_NO_ERROR) {
01719          results->numdests--;
01720          results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
01721          ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
01722          ast_debug(1, "OSP: calling '%s'\n", callingnum);
01723          ast_debug(1, "OSP: called '%s'\n", callednum);
01724          ast_debug(1, "OSP: destination '%s'\n", destination);
01725          ast_debug(1, "OSP: token size '%d'\n", tokenlen);
01726 
01727          if ((res = osp_check_destination(provider, callingnum, callednum, destination, tokenlen, token, &reason, results)) > 0) {
01728             break;
01729          } else if (!results->numdests) {
01730             ast_debug(1, "OSP: No more destination\n");
01731             OSPPTransactionRecordFailure(results->outhandle, reason);
01732             if (results->inhandle != OSP_INVALID_HANDLE) {
01733                OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01734             }
01735             res = OSP_FAILED;
01736             break;
01737          }
01738       } else {
01739          ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
01740          results->numdests = 0;
01741          results->outtimelimit = OSP_DEF_TIMELIMIT;
01742          if (results->inhandle != OSP_INVALID_HANDLE) {
01743             OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
01744          }
01745          res = OSP_ERROR;
01746          break;
01747       }
01748    }
01749 
01750    return res;
01751 }
01752 
01753 /*!
01754  * \brief OSP Lookup Next function
01755  * \param name OSP provider name
01756  * \param cause Asterisk hangup cuase
01757  * \param results Lookup results, in/output
01758  * \return OSP_OK Found , OSP_FAILED No route, OSP_ERROR Error
01759  */
01760 static int osp_next(
01761    const char* name,
01762    int cause,
01763    struct osp_results* results)
01764 {
01765    int res;
01766    struct osp_provider* provider = NULL;
01767    char calling[OSP_SIZE_NORSTR];
01768    char called[OSP_SIZE_NORSTR];
01769    char dest[OSP_SIZE_NORSTR];
01770    unsigned int tokenlen;
01771    char token[OSP_SIZE_TOKSTR];
01772    OSPEFAILREASON reason;
01773    OSPE_OPERATOR_NAME type;
01774    int error;
01775 
01776    if (results == NULL) {
01777       ast_log(LOG_ERROR, "Invalid parameters\n");
01778       res = OSP_ERROR;
01779    }
01780 
01781    results->tech[0] = '\0';
01782    results->dest[0] = '\0';
01783    results->calling[0] = '\0';
01784    results->called[0] = '\0';
01785    results->token[0] = '\0';
01786    results->networkid[0] = '\0';
01787    results->nprn[0] = '\0';
01788    results->npcic[0] = '\0';
01789    results->npdi = 0;
01790    for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
01791       results->opname[type][0] = '\0';
01792    }
01793    results->outtimelimit = OSP_DEF_TIMELIMIT;
01794 
01795    if ((res = osp_get_provider(name, &provider)) <= 0) {
01796       ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", name);
01797       return res;
01798    }
01799 
01800    if (results->outhandle == OSP_INVALID_HANDLE) {
01801       ast_debug(1, "OSP: Transaction handle undefined\n");
01802       results->numdests = 0;
01803       if (results->inhandle != OSP_INVALID_HANDLE) {
01804          OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
01805       }
01806       return OSP_ERROR;
01807    }
01808 
01809    reason = asterisk2osp(cause);
01810 
01811    if (!results->numdests) {
01812       ast_debug(1, "OSP: No more destination\n");
01813       OSPPTransactionRecordFailure(results->outhandle, reason);
01814       if (results->inhandle != OSP_INVALID_HANDLE) {
01815          OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01816       }
01817       return OSP_FAILED;
01818    }
01819 
01820    while(results->numdests) {
01821       results->outcallid.len = sizeof(results->outcallid.buf);
01822       tokenlen = sizeof(token);
01823       error = OSPPTransactionGetNextDestination(
01824          results->outhandle,
01825          reason,
01826          0,
01827          NULL,
01828          NULL,
01829          &results->outtimelimit,
01830          &results->outcallid.len,
01831          results->outcallid.buf,
01832          sizeof(called),
01833          called,
01834          sizeof(calling),
01835          calling,
01836          sizeof(dest),
01837          dest,
01838          0,
01839          NULL,
01840          &tokenlen,
01841          token);
01842       if (error == OSPC_ERR_NO_ERROR) {
01843          results->numdests--;
01844          results->outtimelimit = osp_choose_timelimit(results->intimelimit, results->outtimelimit);
01845          ast_debug(1, "OSP: outtimelimit '%d'\n", results->outtimelimit);
01846          ast_debug(1, "OSP: calling '%s'\n", calling);
01847          ast_debug(1, "OSP: called '%s'\n", called);
01848          ast_debug(1, "OSP: destination '%s'\n", dest);
01849          ast_debug(1, "OSP: token size '%d'\n", tokenlen);
01850 
01851          if ((res = osp_check_destination(provider, calling, called, dest, tokenlen, token, &reason, results)) > 0) {
01852             res = OSP_OK;
01853             break;
01854          } else if (!results->numdests) {
01855             ast_debug(1, "OSP: No more destination\n");
01856             OSPPTransactionRecordFailure(results->outhandle, reason);
01857             if (results->inhandle != OSP_INVALID_HANDLE) {
01858                OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01859             }
01860             res = OSP_FAILED;
01861             break;
01862          }
01863       } else {
01864          ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
01865          results->token[0] = '\0';
01866          results->numdests = 0;
01867          results->outtimelimit = OSP_DEF_TIMELIMIT;
01868          if (results->inhandle != OSP_INVALID_HANDLE) {
01869             OSPPTransactionRecordFailure(results->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
01870          }
01871          res = OSP_ERROR;
01872          break;
01873       }
01874    }
01875 
01876    return res;
01877 }
01878 
01879 /*!
01880  * \brief Get integer from variable string
01881  * \param vstr Variable string
01882  * \return OSP_DEF_INTSTATS Error
01883  */
01884 static int osp_get_varint(
01885    const char* vstr)
01886 {
01887    char* tmp;
01888    int value = OSP_DEF_INTSTATS;
01889 
01890    if (!ast_strlen_zero(vstr)) {
01891       if ((tmp = strchr(vstr, '=')) != NULL) {
01892          tmp++;
01893          if (sscanf(tmp, "%30d", &value) != 1) {
01894             value = OSP_DEF_INTSTATS;
01895          }
01896       }
01897    }
01898 
01899    return value;
01900 }
01901 
01902 /*!
01903  * \brief Get float from variable string
01904  * \param vstr Variable string
01905  * \return OSP_DEF_FLOATSTATS Error
01906  */
01907 static float osp_get_varfloat(
01908    const char* vstr)
01909 {
01910    char* tmp;
01911    float value = OSP_DEF_FLOATSTATS;
01912 
01913    if (!ast_strlen_zero(vstr)) {
01914       if ((tmp = strchr(vstr, '=')) != NULL) {
01915          tmp++;
01916          if (sscanf(tmp, "%30f", &value) != 1) {
01917             value = OSP_DEF_FLOATSTATS;
01918          }
01919       }
01920    }
01921 
01922    return value;
01923 }
01924 
01925 /*!
01926  * \brief Report QoS
01927  * \param trans OSP in/outbound transaction handle
01928  * \param leg Inbound/outbound
01929  * \param qos QoS string
01930  * \return OSP_OK Success, OSP_FAILED Failed, OSP_ERROR Error
01931  */
01932 static int osp_report_qos(
01933    int trans,
01934    enum osp_callleg leg,
01935    const char* qos)
01936 {
01937    int res = OSP_FAILED;
01938    enum osp_direction dir;
01939    char buffer[OSP_SIZE_NORSTR];
01940    char* tmp;
01941    char* item;
01942    int totalpackets[OSP_DIR_NUMBER];
01943    struct osp_metrics lost[OSP_DIR_NUMBER];
01944    struct osp_metrics jitter[OSP_DIR_NUMBER];
01945    struct osp_metrics rtt;
01946    int value;
01947 
01948    if (!ast_strlen_zero(qos)) {
01949       for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
01950          totalpackets[dir] = OSP_DEF_INTSTATS;
01951       }
01952 
01953       for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
01954          lost[dir].value = OSP_DEF_INTSTATS;
01955          lost[dir].min = OSP_DEF_FLOATSTATS;
01956          lost[dir].max = OSP_DEF_FLOATSTATS;
01957          lost[dir].avg = OSP_DEF_FLOATSTATS;
01958          lost[dir].sdev = OSP_DEF_FLOATSTATS;
01959       }
01960 
01961       for (dir = OSP_DIR_RX; dir < OSP_DIR_NUMBER; dir++) {
01962          jitter[dir].value = OSP_DEF_INTSTATS;
01963          jitter[dir].min = OSP_DEF_FLOATSTATS;
01964          jitter[dir].max = OSP_DEF_FLOATSTATS;
01965          jitter[dir].avg = OSP_DEF_FLOATSTATS;
01966          jitter[dir].sdev = OSP_DEF_FLOATSTATS;
01967       }
01968 
01969       rtt.value = OSP_DEF_INTSTATS;
01970       rtt.min = OSP_DEF_FLOATSTATS;
01971       rtt.max = OSP_DEF_FLOATSTATS;
01972       rtt.avg = OSP_DEF_FLOATSTATS;
01973       rtt.sdev = OSP_DEF_FLOATSTATS;
01974 
01975       ast_copy_string(buffer, qos, sizeof(buffer));
01976       for (item = strtok_r(buffer, ";", &tmp); item; item = strtok_r(NULL, ";", &tmp)) {
01977          if (!strncasecmp(item, "rxcount", strlen("rxcount"))) {
01978             totalpackets[OSP_DIR_RX] = osp_get_varint(item);
01979          } else if (!strncasecmp(item, "txcount", strlen("txcount"))) {
01980             totalpackets[OSP_DIR_TX] = osp_get_varint(item);
01981          } else if (!strncasecmp(item, "lp", strlen("lp"))) {
01982             lost[OSP_DIR_RX].value = osp_get_varint(item);
01983          } else if (!strncasecmp(item, "minrxlost", strlen("minrxlost"))) {
01984             lost[OSP_DIR_RX].min = osp_get_varfloat(item);
01985          } else if (!strncasecmp(item, "maxrxlost", strlen("maxrxlost"))) {
01986             lost[OSP_DIR_RX].max = osp_get_varfloat(item);
01987          } else if (!strncasecmp(item, "avgrxlost", strlen("avgrxlost"))) {
01988             lost[OSP_DIR_RX].avg = osp_get_varfloat(item);
01989          } else if (!strncasecmp(item, "stdevrxlost", strlen("stdevrxlost"))) {
01990             lost[OSP_DIR_RX].sdev = osp_get_varfloat(item);
01991          } else if (!strncasecmp(item, "rlp", strlen("rlp"))) {
01992             lost[OSP_DIR_TX].value = osp_get_varint(item);
01993          } else if (!strncasecmp(item, "reported_minlost", strlen("reported_minlost"))) {
01994             lost[OSP_DIR_TX].min = osp_get_varfloat(item);
01995          } else if (!strncasecmp(item, "reported_maxlost", strlen("reported_maxlost"))) {
01996             lost[OSP_DIR_TX].max = osp_get_varfloat(item);
01997          } else if (!strncasecmp(item, "reported_avglost", strlen("reported_avglost"))) {
01998             lost[OSP_DIR_TX].avg = osp_get_varfloat(item);
01999          } else if (!strncasecmp(item, "reported_stdevlost", strlen("reported_stdevlost"))) {
02000             lost[OSP_DIR_TX].sdev = osp_get_varfloat(item);
02001          } else if (!strncasecmp(item, "rxjitter", strlen("rxjitter"))) {
02002             jitter[OSP_DIR_RX].value = osp_get_varint(item);
02003          } else if (!strncasecmp(item, "minrxjitter", strlen("minrxjitter"))) {
02004             jitter[OSP_DIR_RX].min = osp_get_varfloat(item);
02005          } else if (!strncasecmp(item, "maxrxjitter", strlen("maxrxjitter"))) {
02006             jitter[OSP_DIR_RX].max = osp_get_varfloat(item);
02007          } else if (!strncasecmp(item, "avgrxjitter", strlen("avgjitter"))) {
02008             jitter[OSP_DIR_RX].avg = osp_get_varfloat(item);
02009          } else if (!strncasecmp(item, "stdevrxjitter", strlen("stdevjitter"))) {
02010             jitter[OSP_DIR_RX].sdev = osp_get_varfloat(item);
02011          } else if (!strncasecmp(item, "txjitter", strlen("txjitter"))) {
02012             jitter[OSP_DIR_TX].value = osp_get_varint(item);
02013          } else if (!strncasecmp(item, "reported_minjitter", strlen("reported_minjitter"))) {
02014             jitter[OSP_DIR_TX].min = osp_get_varfloat(item);
02015          } else if (!strncasecmp(item, "reported_maxjitter", strlen("reported_maxjitter"))) {
02016             jitter[OSP_DIR_TX].max = osp_get_varfloat(item);
02017          } else if (!strncasecmp(item, "reported_avgjitter", strlen("reported_avgjitter"))) {
02018             jitter[OSP_DIR_TX].avg = osp_get_varfloat(item);
02019          } else if (!strncasecmp(item, "reported_stdevjitter", strlen("reported_stdevjitter"))) {
02020             jitter[OSP_DIR_TX].sdev = osp_get_varfloat(item);
02021          } else if (!strncasecmp(item, "rtt", strlen("rtt"))) {
02022             rtt.value = osp_get_varint(item);
02023          } else if (!strncasecmp(item, "minrtt", strlen("minrtt"))) {
02024             rtt.min = osp_get_varfloat(item);
02025          } else if (!strncasecmp(item, "maxrtt", strlen("maxrtt"))) {
02026             rtt.max = osp_get_varfloat(item);
02027          } else if (!strncasecmp(item, "avgrtt", strlen("avgrtt"))) {
02028             rtt.avg = osp_get_varfloat(item);
02029          } else if (!strncasecmp(item, "stdevrtt", strlen("stdevrtt"))) {
02030             rtt.sdev = osp_get_varfloat(item);
02031          }
02032       }
02033 
02034       ast_debug(1, "OSP: call leg '%d'\n", leg);
02035       ast_debug(1, "OSP: rxcount '%d'\n", totalpackets[OSP_DIR_RX]);
02036       ast_debug(1, "OSP: txcount '%d'\n", totalpackets[OSP_DIR_TX]);
02037       ast_debug(1, "OSP: lp '%d'\n",lost[OSP_DIR_RX].value);
02038       ast_debug(1, "OSP: minrxlost '%f'\n", lost[OSP_DIR_RX].min);
02039       ast_debug(1, "OSP: maxrxlost '%f'\n", lost[OSP_DIR_RX].max);
02040       ast_debug(1, "OSP: avgrxlost '%f'\n", lost[OSP_DIR_RX].avg);
02041       ast_debug(1, "OSP: stdevrxlost '%f'\n", lost[OSP_DIR_RX].sdev);
02042       ast_debug(1, "OSP: rlp '%d'\n", lost[OSP_DIR_TX].value);
02043       ast_debug(1, "OSP: reported_minlost '%f'\n", lost[OSP_DIR_TX].min);
02044       ast_debug(1, "OSP: reported_maxlost '%f'\n", lost[OSP_DIR_TX].max);
02045       ast_debug(1, "OSP: reported_avglost '%f'\n", lost[OSP_DIR_TX].avg);
02046       ast_debug(1, "OSP: reported_stdevlost '%f'\n", lost[OSP_DIR_TX].sdev);
02047       ast_debug(1, "OSP: rxjitter '%d'\n", jitter[OSP_DIR_RX].value);
02048       ast_debug(1, "OSP: minrxjitter '%f'\n", jitter[OSP_DIR_RX].min);
02049       ast_debug(1, "OSP: maxrxjitter '%f'\n", jitter[OSP_DIR_RX].max);
02050       ast_debug(1, "OSP: avgrxjitter '%f'\n", jitter[OSP_DIR_RX].avg);
02051       ast_debug(1, "OSP: stdevrxjitter '%f'\n", jitter[OSP_DIR_RX].sdev);
02052       ast_debug(1, "OSP: txjitter '%d'\n", jitter[OSP_DIR_TX].value);
02053       ast_debug(1, "OSP: reported_minjitter '%f'\n", jitter[OSP_DIR_TX].min);
02054       ast_debug(1, "OSP: reported_maxjitter '%f'\n", jitter[OSP_DIR_TX].max);
02055       ast_debug(1, "OSP: reported_avgjitter '%f'\n", jitter[OSP_DIR_TX].avg);
02056       ast_debug(1, "OSP: reported_stdevjitter '%f'\n", jitter[OSP_DIR_TX].sdev);
02057       ast_debug(1, "OSP: rtt '%d'\n", rtt.value);
02058       ast_debug(1, "OSP: minrtt '%f'\n", rtt.min);
02059       ast_debug(1, "OSP: maxrtt '%f'\n", rtt.max);
02060       ast_debug(1, "OSP: avgrtt '%f'\n", rtt.avg);
02061       ast_debug(1, "OSP: stdevrtt '%f'\n", rtt.sdev);
02062 
02063       if (leg == OSP_CALL_INBOUND) {
02064          OSPPTransactionSetPackets(trans, OSPC_SMETRIC_RTP, OSPC_SFLOW_DOWNSTREAM, totalpackets[OSP_DIR_RX]);
02065          OSPPTransactionSetPackets(trans, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM, totalpackets[OSP_DIR_TX]);
02066          if (lost[OSP_DIR_RX].value >= 0) {
02067             value = lost[OSP_DIR_RX].value;
02068          } else {
02069             value = (int)lost[OSP_DIR_RX].avg;
02070          }
02071          OSPPTransactionSetLost(trans, OSPC_SMETRIC_RTP, OSPC_SFLOW_DOWNSTREAM, value, OSP_DEF_INTSTATS);
02072          if (lost[OSP_DIR_TX].value >= 0) {
02073             value = lost[OSP_DIR_TX].value;
02074          } else {
02075             value = (int)lost[OSP_DIR_TX].avg;
02076          }
02077          OSPPTransactionSetLost(trans, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM, value, OSP_DEF_INTSTATS);
02078          if (jitter[OSP_DIR_RX].value >= 0) {
02079             value = jitter[OSP_DIR_RX].value;
02080          } else {
02081             value = (int)jitter[OSP_DIR_RX].avg;
02082          }
02083          OSPPTransactionSetJitter(trans,
02084             OSPC_SMETRIC_RTP,
02085             OSPC_SFLOW_DOWNSTREAM,
02086             OSP_DEF_INTSTATS,
02087             (int)jitter[OSP_DIR_RX].min,
02088             (int)jitter[OSP_DIR_RX].max,
02089             value, jitter[OSP_DIR_RX].sdev);
02090          if (jitter[OSP_DIR_TX].value >= 0) {
02091             value = jitter[OSP_DIR_TX].value;
02092          } else {
02093             value = (int)jitter[OSP_DIR_TX].avg;
02094          }
02095          OSPPTransactionSetJitter(trans, OSPC_SMETRIC_RTCP, OSPC_SFLOW_UPSTREAM,
02096             OSP_DEF_INTSTATS, (int)jitter[OSP_DIR_TX].min, (int)jitter[OSP_DIR_TX].max, value, jitter[OSP_DIR_TX].sdev);
02097       } else {
02098          OSPPTransactionSetPackets(trans, OSPC_SMETRIC_RTP, OSPC_SFLOW_UPSTREAM, totalpackets[OSP_DIR_RX]);
02099          OSPPTransactionSetPackets(trans, OSPC_SMETRIC_RTCP, OSPC_SFLOW_DOWNSTREAM, totalpackets[OSP_DIR_TX]);
02100          OSPPTransactionSetLost(trans, OSPC_SMETRIC_RTP, OSPC_SFLOW_UPSTREAM, lost[OSP_DIR_RX].value, OSP_DEF_INTSTATS);
02101          OSPPTransactionSetLost(trans, OSPC_SMETRIC_RTCP, OSPC_SFLOW_DOWNSTREAM, lost[OSP_DIR_TX].value, OSP_DEF_INTSTATS);
02102          if (jitter[OSP_DIR_RX].value >= 0) {
02103             value = jitter[OSP_DIR_RX].value;
02104          } else {
02105             value = (int)jitter[OSP_DIR_RX].avg;
02106          }
02107          OSPPTransactionSetJitter(trans,
02108             OSPC_SMETRIC_RTP,
02109             OSPC_SFLOW_UPSTREAM,
02110             OSP_DEF_INTSTATS,
02111             (int)jitter[OSP_DIR_RX].min,
02112             (int)jitter[OSP_DIR_RX].max,
02113             value,
02114             jitter[OSP_DIR_RX].sdev);
02115          if (jitter[OSP_DIR_TX].value >= 0) {
02116             value = jitter[OSP_DIR_TX].value;
02117          } else {
02118             value = (int)jitter[OSP_DIR_TX].avg;
02119          }
02120          OSPPTransactionSetJitter(trans,
02121             OSPC_SMETRIC_RTCP,
02122             OSPC_SFLOW_DOWNSTREAM,
02123             OSP_DEF_INTSTATS,
02124             (int)jitter[OSP_DIR_TX].min,
02125             (int)jitter[OSP_DIR_TX].max,
02126             value,
02127             jitter[OSP_DIR_TX].sdev);
02128       }
02129       if (rtt.value >= 0) {
02130          value = rtt.value;
02131       } else {
02132          value = (int)rtt.avg;
02133       }
02134       OSPPTransactionSetRoundTripDelay(trans, OSP_DEF_INTSTATS, (int)rtt.min, (int)rtt.max, value, rtt.sdev);
02135 
02136       res = OSP_OK;
02137    }
02138 
02139    return res;
02140 }
02141 
02142 /*!
02143  * \brief OSP Finish function
02144  * \param trans OSP in/outbound transaction handle
02145  * \param recorded If failure reason has been recorded
02146  * \param cause Asterisk hangup cause
02147  * \param start Call start time
02148  * \param connect Call connect time
02149  * \param end Call end time
02150  * \param release Who release first, 0 source, 1 destination
02151  * \param inqos Inbound QoS string
02152  * \param outqos Outbound QoS string
02153  * \return OSP_OK Success, OSP_FAILED Failed, OSP_ERROR Error
02154  */
02155 static int osp_finish(
02156    int trans,
02157    int recorded,
02158    int cause,
02159    time_t start,
02160    time_t connect,
02161    time_t end,
02162    unsigned int release,
02163    const char* inqos,
02164    const char* outqos)
02165 {
02166    int res;
02167    OSPEFAILREASON reason;
02168    time_t alert = 0;
02169    unsigned isPddInfoPresent = 0;
02170    unsigned pdd = 0;
02171    unsigned int dummy = 0;
02172    int error;
02173 
02174    if (trans == OSP_INVALID_HANDLE) {
02175       return OSP_FAILED;
02176    }
02177 
02178    if (!recorded) {
02179       reason = asterisk2osp(cause);
02180       OSPPTransactionRecordFailure(trans, reason);
02181    }
02182 
02183    osp_report_qos(trans, OSP_CALL_INBOUND, inqos);
02184    osp_report_qos(trans, OSP_CALL_OUTBOUND, outqos);
02185 
02186    error = OSPPTransactionReportUsage(trans,
02187       difftime(end, connect),
02188       start,
02189       end,
02190       alert,
02191       connect,
02192       isPddInfoPresent,
02193       pdd,
02194       release,
02195       NULL,
02196       OSP_DEF_INTSTATS,
02197       OSP_DEF_INTSTATS,
02198       OSP_DEF_INTSTATS,
02199       OSP_DEF_INTSTATS,
02200       &dummy,
02201       NULL);
02202    if (error == OSPC_ERR_NO_ERROR) {
02203       ast_debug(1, "OSP: Usage reported\n");
02204       res = OSP_OK;
02205    } else {
02206       ast_debug(1, "OSP: Unable to report usage, error '%d'\n", error);
02207       res = OSP_ERROR;
02208    }
02209    OSPPTransactionDelete(trans);
02210 
02211    return res;
02212 }
02213 
02214 /* OSP Application APIs */
02215 
02216 /*!
02217  * \brief OSP Application OSPAuth
02218  * \param chan Channel
02219  * \param data Parameter
02220  * \return OSP_AST_OK Success, OSP_AST_ERROR Error
02221  */
02222 static int ospauth_exec(
02223    struct ast_channel *chan,
02224    const char *data)
02225 {
02226    int res;
02227    const char* provider = OSP_DEF_PROVIDER;
02228    struct varshead* headp;
02229    struct ast_var_t* current;
02230    const char* source = "";
02231    const char* token = "";
02232    int handle;
02233    unsigned int timelimit;
02234    char buffer[OSP_SIZE_INTSTR];
02235    const char* status;
02236    char* tmp;
02237 
02238    AST_DECLARE_APP_ARGS(args,
02239       AST_APP_ARG(provider);
02240       AST_APP_ARG(options);
02241    );
02242 
02243    if (!(tmp = ast_strdupa(data))) {
02244       ast_log(LOG_ERROR, "Out of memory\n");
02245       return OSP_AST_ERROR;
02246    }
02247 
02248    AST_STANDARD_APP_ARGS(args, tmp);
02249 
02250    if (!ast_strlen_zero(args.provider)) {
02251       provider = args.provider;
02252    }
02253    ast_debug(1, "OSPAuth: provider '%s'\n", provider);
02254 
02255    headp = &chan->varshead;
02256    AST_LIST_TRAVERSE(headp, current, entries) {
02257       if (!strcasecmp(ast_var_name(current), "OSPINPEERIP")) {
02258          source = ast_var_value(current);
02259       } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
02260          token = ast_var_value(current);
02261       }
02262    }
02263 
02264    ast_debug(1, "OSPAuth: source '%s'\n", source);
02265    ast_debug(1, "OSPAuth: token size '%zd'\n", strlen(token));
02266 
02267    res = osp_auth(provider, &handle, source,
02268       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02269       chan->exten, token, &timelimit);
02270    if (res > 0) {
02271       status = AST_OSP_SUCCESS;
02272    } else {
02273       timelimit = OSP_DEF_TIMELIMIT;
02274       if (!res) {
02275          status = AST_OSP_FAILED;
02276       } else {
02277          status = AST_OSP_ERROR;
02278       }
02279    }
02280 
02281    snprintf(buffer, sizeof(buffer), "%d", handle);
02282    pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
02283    ast_debug(1, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
02284    snprintf(buffer, sizeof(buffer), "%d", timelimit);
02285    pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
02286    ast_debug(1, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
02287    pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
02288    ast_debug(1, "OSPAuth: %s\n", status);
02289 
02290    if(res != OSP_OK) {
02291       res = OSP_AST_ERROR;
02292    } else {
02293       res = OSP_AST_OK;
02294    }
02295 
02296    return res;
02297 }
02298 
02299 /*!
02300  * \brief OSP Application OSPLookup
02301  * \param chan Channel
02302  * \param data Parameter
02303  * \return OSP_AST_OK Success, OSP_AST_ERROR Error
02304  */
02305 static int osplookup_exec(
02306    struct ast_channel* chan,
02307    const char * data)
02308 {
02309    int res, cres;
02310    const char* provider = OSP_DEF_PROVIDER;
02311    unsigned int callidtypes = OSP_CALLID_UNDEF;
02312    struct varshead* headp;
02313    struct ast_var_t* current;
02314    const char* actualsrc = "";
02315    const char* srcdev = "";
02316    const char* snetid = "";
02317    struct osp_npdata np;
02318    OSPE_OPERATOR_NAME type;
02319    struct osp_diversion div;
02320    unsigned int i;
02321    const char* cinfo[OSP_MAX_CUSTOMINFO] = { NULL };
02322    char buffer[OSP_SIZE_TOKSTR];
02323    struct osp_results results;
02324    const char* status;
02325    char* tmp;
02326 
02327    AST_DECLARE_APP_ARGS(args,
02328       AST_APP_ARG(exten);
02329       AST_APP_ARG(provider);
02330       AST_APP_ARG(options);
02331    );
02332 
02333    if (ast_strlen_zero(data)) {
02334       ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[,provider[,options]])\n");
02335       return OSP_AST_ERROR;
02336    }
02337 
02338    if (!(tmp = ast_strdupa(data))) {
02339       ast_log(LOG_ERROR, "Out of memory\n");
02340       return OSP_AST_ERROR;
02341    }
02342 
02343    AST_STANDARD_APP_ARGS(args, tmp);
02344 
02345    ast_debug(1, "OSPLookup: exten '%s'\n", args.exten);
02346 
02347    if (!ast_strlen_zero(args.provider)) {
02348       provider = args.provider;
02349    }
02350    ast_debug(1, "OSPlookup: provider '%s'\n", provider);
02351 
02352    if (args.options) {
02353       if (strchr(args.options, 'h')) {
02354          callidtypes |= OSP_CALLID_H323;
02355       }
02356       if (strchr(args.options, 's')) {
02357          callidtypes |= OSP_CALLID_SIP;
02358       }
02359       if (strchr(args.options, 'i')) {
02360          callidtypes |= OSP_CALLID_IAX;
02361       }
02362    }
02363    ast_debug(1, "OSPLookup: call id types '%d'\n", callidtypes);
02364 
02365    results.inhandle = OSP_INVALID_HANDLE;
02366    results.intimelimit = OSP_DEF_TIMELIMIT;
02367    results.dest[0] = '\0';
02368 
02369    np.rn = "";
02370    np.cic = "";
02371    np.npdi = 0;
02372    for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
02373       np.opname[type] = "";
02374    }
02375 
02376    div.user = "";
02377    div.host = "";
02378 
02379    headp = &chan->varshead;
02380    AST_LIST_TRAVERSE(headp, current, entries) {
02381       if (!strcasecmp(ast_var_name(current), "OSPINACTUALSRC")) {
02382          actualsrc = ast_var_value(current);
02383       } else if (!strcasecmp(ast_var_name(current), "OSPINPEERIP")) {
02384          srcdev = ast_var_value(current);
02385       } else if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
02386          if (sscanf(ast_var_value(current), "%30d", &results.inhandle) != 1) {
02387             results.inhandle = OSP_INVALID_HANDLE;
02388          }
02389       } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
02390          if (sscanf(ast_var_value(current), "%30d", &results.intimelimit) != 1) {
02391             results.intimelimit = OSP_DEF_TIMELIMIT;
02392          }
02393       } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
02394          snetid = ast_var_value(current);
02395       } else if (!strcasecmp(ast_var_name(current), "OSPINNPRN")) {
02396          np.rn = ast_var_value(current);
02397       } else if (!strcasecmp(ast_var_name(current), "OSPINNPCIC")) {
02398          np.cic = ast_var_value(current);
02399       } else if (!strcasecmp(ast_var_name(current), "OSPINNPDI")) {
02400          if (ast_true(ast_var_value(current))) {
02401             np.npdi = 1;
02402          }
02403       } else if (!strcasecmp(ast_var_name(current), "OSPINSPID")) {
02404          np.opname[OSPC_OPNAME_SPID] = ast_var_value(current);
02405       } else if (!strcasecmp(ast_var_name(current), "OSPINOCN")) {
02406          np.opname[OSPC_OPNAME_OCN] = ast_var_value(current);
02407       } else if (!strcasecmp(ast_var_name(current), "OSPINSPN")) {
02408          np.opname[OSPC_OPNAME_SPN] = ast_var_value(current);
02409       } else if (!strcasecmp(ast_var_name(current), "OSPINALTSPN")) {
02410          np.opname[OSPC_OPNAME_ALTSPN] = ast_var_value(current);
02411       } else if (!strcasecmp(ast_var_name(current), "OSPINMCC")) {
02412          np.opname[OSPC_OPNAME_MCC] = ast_var_value(current);
02413       } else if (!strcasecmp(ast_var_name(current), "OSPINMNC")) {
02414          np.opname[OSPC_OPNAME_MNC] = ast_var_value(current);
02415       } else if (!strcasecmp(ast_var_name(current), "OSPINTOHOST")) {
02416          ast_copy_string(results.dest, ast_var_value(current), sizeof(results.dest));
02417       } else if (!strcasecmp(ast_var_name(current), "OSPINDIVUSER")) {
02418          div.user = ast_var_value(current);
02419       } else if (!strcasecmp(ast_var_name(current), "OSPINDIVHOST")) {
02420          div.host = ast_var_value(current);
02421       } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO1")) {
02422          cinfo[0] = ast_var_value(current);
02423       } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO2")) {
02424          cinfo[1] = ast_var_value(current);
02425       } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO3")) {
02426          cinfo[2] = ast_var_value(current);
02427       } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO4")) {
02428          cinfo[3] = ast_var_value(current);
02429       } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO5")) {
02430          cinfo[4] = ast_var_value(current);
02431       } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO6")) {
02432          cinfo[5] = ast_var_value(current);
02433       } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO7")) {
02434          cinfo[6] = ast_var_value(current);
02435       } else if (!strcasecmp(ast_var_name(current), "OSPINCUSTOMINFO8")) {
02436          cinfo[7] = ast_var_value(current);
02437       }
02438    }
02439    ast_debug(1, "OSPLookup: actual source device '%s'\n", actualsrc);
02440    ast_debug(1, "OSPLookup: source device '%s'\n", srcdev);
02441    ast_debug(1, "OSPLookup: OSPINHANDLE '%d'\n", results.inhandle);
02442    ast_debug(1, "OSPLookup: OSPINTIMELIMIT '%d'\n", results.intimelimit);
02443    ast_debug(1, "OSPLookup: OSPINNETWORKID '%s'\n", snetid);
02444    ast_debug(1, "OSPLookup: OSPINNPRN '%s'\n", np.rn);
02445    ast_debug(1, "OSPLookup: OSPINNPCIC '%s'\n", np.cic);
02446    ast_debug(1, "OSPLookup: OSPINNPDI '%d'\n", np.npdi);
02447    ast_debug(1, "OSPLookup: OSPINSPID '%s'\n", np.opname[OSPC_OPNAME_SPID]);
02448    ast_debug(1, "OSPLookup: OSPINOCN '%s'\n", np.opname[OSPC_OPNAME_OCN]);
02449    ast_debug(1, "OSPLookup: OSPINSPN '%s'\n", np.opname[OSPC_OPNAME_SPN]);
02450    ast_debug(1, "OSPLookup: OSPINALTSPN '%s'\n", np.opname[OSPC_OPNAME_ALTSPN]);
02451    ast_debug(1, "OSPLookup: OSPINMCC '%s'\n", np.opname[OSPC_OPNAME_MCC]);
02452    ast_debug(1, "OSPLookup: OSPINMNC '%s'\n", np.opname[OSPC_OPNAME_MNC]);
02453    ast_debug(1, "OSPLookup: OSPINTOHOST '%s'\n", results.dest);
02454    ast_debug(1, "OSPLookup: OSPINDIVUSER '%s'\n", div.user);
02455    ast_debug(1, "OSPLookup: OSPINDIVHOST'%s'\n", div.host);
02456    for (i = 0; i < OSP_MAX_CUSTOMINFO; i++) {
02457       if (!ast_strlen_zero(cinfo[i])) {
02458          ast_debug(1, "OSPLookup: OSPINCUSTOMINFO%d '%s'\n", i, cinfo[i]);
02459       }
02460    }
02461 
02462    if ((cres = ast_autoservice_start(chan)) < 0) {
02463       return OSP_AST_ERROR;
02464    }
02465 
02466    res = osp_lookup(provider, callidtypes, actualsrc, srcdev,
02467       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02468       args.exten, snetid, &np, &div, cinfo, &results);
02469    if (res > 0) {
02470       status = AST_OSP_SUCCESS;
02471    } else {
02472       results.tech[0] = '\0';
02473       results.dest[0] = '\0';
02474       results.calling[0] = '\0';
02475       results.called[0] = '\0';
02476       results.token[0] = '\0';
02477       results.networkid[0] = '\0';
02478       results.nprn[0] = '\0';
02479       results.npcic[0] = '\0';
02480       results.npdi = 0;
02481       for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
02482          results.opname[type][0] = '\0';
02483       }
02484       results.numdests = 0;
02485       results.outtimelimit = OSP_DEF_TIMELIMIT;
02486       results.outcallid.buf[0] = '\0';
02487       results.outcallid.len = 0;
02488       if (!res) {
02489          status = AST_OSP_FAILED;
02490       } else {
02491          status = AST_OSP_ERROR;
02492       }
02493    }
02494 
02495    snprintf(buffer, sizeof(buffer), "%d", results.outhandle);
02496    pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
02497    ast_debug(1, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
02498    pbx_builtin_setvar_helper(chan, "OSPOUTTECH", results.tech);
02499    ast_debug(1, "OSPLookup: OSPOUTTECH '%s'\n", results.tech);
02500    pbx_builtin_setvar_helper(chan, "OSPDESTINATION", results.dest);
02501    ast_debug(1, "OSPLookup: OSPDESTINATION '%s'\n", results.dest);
02502    pbx_builtin_setvar_helper(chan, "OSPOUTCALLING", results.calling);
02503    ast_debug(1, "OSPLookup: OSPOUTCALLING '%s'\n", results.calling);
02504    pbx_builtin_setvar_helper(chan, "OSPOUTCALLED", results.called);
02505    ast_debug(1, "OSPLookup: OSPOUTCALLED '%s'\n", results.called);
02506    pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", results.networkid);
02507    ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", results.networkid);
02508    pbx_builtin_setvar_helper(chan, "OSPOUTNPRN", results.nprn);
02509    ast_debug(1, "OSPLookup: OSPOUTNPRN '%s'\n", results.nprn);
02510    pbx_builtin_setvar_helper(chan, "OSPOUTNPCIC", results.npcic);
02511    ast_debug(1, "OSPLookup: OSPOUTNPCIC '%s'\n", results.npcic);
02512    snprintf(buffer, sizeof(buffer), "%d", results.npdi);
02513    pbx_builtin_setvar_helper(chan, "OSPOUTNPDI", buffer);
02514    ast_debug(1, "OSPLookup: OSPOUTNPDI'%s'\n", buffer);
02515    pbx_builtin_setvar_helper(chan, "OSPOUTSPID", results.opname[OSPC_OPNAME_SPID]);
02516    ast_debug(1, "OSPLookup: OSPOUTSPID '%s'\n", results.opname[OSPC_OPNAME_SPID]);
02517    pbx_builtin_setvar_helper(chan, "OSPOUTOCN", results.opname[OSPC_OPNAME_OCN]);
02518    ast_debug(1, "OSPLookup: OSPOUTOCN '%s'\n", results.opname[OSPC_OPNAME_OCN]);
02519    pbx_builtin_setvar_helper(chan, "OSPOUTSPN", results.opname[OSPC_OPNAME_SPN]);
02520    ast_debug(1, "OSPLookup: OSPOUTSPN '%s'\n", results.opname[OSPC_OPNAME_SPN]);
02521    pbx_builtin_setvar_helper(chan, "OSPOUTALTSPN", results.opname[OSPC_OPNAME_ALTSPN]);
02522    ast_debug(1, "OSPLookup: OSPOUTALTSPN '%s'\n", results.opname[OSPC_OPNAME_ALTSPN]);
02523    pbx_builtin_setvar_helper(chan, "OSPOUTMCC", results.opname[OSPC_OPNAME_MCC]);
02524    ast_debug(1, "OSPLookup: OSPOUTMCC '%s'\n", results.opname[OSPC_OPNAME_MCC]);
02525    pbx_builtin_setvar_helper(chan, "OSPOUTMNC", results.opname[OSPC_OPNAME_MNC]);
02526    ast_debug(1, "OSPLookup: OSPOUTMNC '%s'\n", results.opname[OSPC_OPNAME_MNC]);
02527    pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", results.token);
02528    ast_debug(1, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(results.token));
02529    snprintf(buffer, sizeof(buffer), "%d", results.numdests);
02530    pbx_builtin_setvar_helper(chan, "OSPDESTREMAILS", buffer);
02531    ast_debug(1, "OSPLookup: OSPDESTREMAILS '%s'\n", buffer);
02532    snprintf(buffer, sizeof(buffer), "%d", results.outtimelimit);
02533    pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
02534    ast_debug(1, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
02535    snprintf(buffer, sizeof(buffer), "%d", callidtypes);
02536    pbx_builtin_setvar_helper(chan, "OSPOUTCALLIDTYPES", buffer);
02537    ast_debug(1, "OSPLookup: OSPOUTCALLIDTYPES '%s'\n", buffer);
02538    pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
02539    ast_debug(1, "OSPLookup: %s\n", status);
02540 
02541    if (!strcasecmp(results.tech, OSP_TECH_SIP)) {
02542       snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
02543       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
02544       if (!ast_strlen_zero(results.token)) {
02545          snprintf(buffer, sizeof(buffer), "%s: %s", OSP_SIP_HEADER, results.token);
02546          pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
02547          ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
02548       }
02549    } else if (!strcasecmp(results.tech, OSP_TECH_H323)) {
02550       if ((callidtypes & OSP_CALLID_H323) && (results.outcallid.len != 0)) {
02551          osp_uuid2str(results.outcallid.buf, buffer, sizeof(buffer));
02552       } else {
02553          buffer[0] = '\0';
02554       }
02555       pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
02556       snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
02557       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
02558    } else if (!strcasecmp(results.tech, OSP_TECH_IAX)) {
02559       snprintf(buffer, sizeof(buffer), "%s/%s/%s", results.tech, results.dest, results.called);
02560       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
02561    } else if (!strcasecmp(results.tech, OSP_TECH_SKYPE)) {
02562       snprintf(buffer, sizeof(buffer), "%s/%s", results.tech, results.called);
02563       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
02564    }
02565 
02566    if ((cres = ast_autoservice_stop(chan)) < 0) {
02567       return OSP_AST_ERROR;
02568    }
02569 
02570    if(res != OSP_OK) {
02571       res = OSP_AST_ERROR;
02572    } else {
02573       res = OSP_AST_OK;
02574    }
02575 
02576    return res;
02577 }
02578 
02579 /*!
02580  * \brief OSP Application OSPNext
02581  * \param chan Channel
02582  * \param data Parameter
02583  * \return OSP_AST_OK Success, OSP_AST_ERROR Error
02584  */
02585 static int ospnext_exec(
02586    struct ast_channel* chan,
02587    const char * data)
02588 {
02589    int res;
02590    const char* provider = OSP_DEF_PROVIDER;
02591    int cause = 0;
02592    struct varshead* headp;
02593    struct ast_var_t* current;
02594    struct osp_results results;
02595    OSPE_OPERATOR_NAME type;
02596    char buffer[OSP_SIZE_TOKSTR];
02597    unsigned int callidtypes = OSP_CALLID_UNDEF;
02598    const char* status;
02599    char* tmp;
02600 
02601    AST_DECLARE_APP_ARGS(args,
02602       AST_APP_ARG(cause);
02603       AST_APP_ARG(provider);
02604       AST_APP_ARG(options);
02605    );
02606 
02607    if (ast_strlen_zero(data)) {
02608       ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[,provider[,options]])\n");
02609       return OSP_AST_ERROR;
02610    }
02611 
02612    if (!(tmp = ast_strdupa(data))) {
02613       ast_log(LOG_ERROR, "Out of memory\n");
02614       return OSP_AST_ERROR;
02615    }
02616 
02617    AST_STANDARD_APP_ARGS(args, tmp);
02618 
02619    if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
02620       cause = 0;
02621    }
02622    ast_debug(1, "OSPNext: cause '%d'\n", cause);
02623 
02624    if (!ast_strlen_zero(args.provider)) {
02625       provider = args.provider;
02626    }
02627    ast_debug(1, "OSPlookup: provider '%s'\n", provider);
02628 
02629    results.inhandle = OSP_INVALID_HANDLE;
02630    results.outhandle = OSP_INVALID_HANDLE;
02631    results.intimelimit = OSP_DEF_TIMELIMIT;
02632    results.numdests = 0;
02633 
02634    headp = &chan->varshead;
02635    AST_LIST_TRAVERSE(headp, current, entries) {
02636       if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
02637          if (sscanf(ast_var_value(current), "%30d", &results.inhandle) != 1) {
02638             results.inhandle = OSP_INVALID_HANDLE;
02639          }
02640       } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
02641          if (sscanf(ast_var_value(current), "%30d", &results.outhandle) != 1) {
02642             results.outhandle = OSP_INVALID_HANDLE;
02643          }
02644       } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
02645          if (sscanf(ast_var_value(current), "%30d", &results.intimelimit) != 1) {
02646             results.intimelimit = OSP_DEF_TIMELIMIT;
02647          }
02648       } else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
02649          if (sscanf(ast_var_value(current), "%30d", &callidtypes) != 1) {
02650             callidtypes = OSP_CALLID_UNDEF;
02651          }
02652       } else if (!strcasecmp(ast_var_name(current), "OSPDESTREMAILS")) {
02653          if (sscanf(ast_var_value(current), "%30d", &results.numdests) != 1) {
02654             results.numdests = 0;
02655          }
02656       }
02657    }
02658    ast_debug(1, "OSPNext: OSPINHANDLE '%d'\n", results.inhandle);
02659    ast_debug(1, "OSPNext: OSPOUTHANDLE '%d'\n", results.outhandle);
02660    ast_debug(1, "OSPNext: OSPINTIMELIMIT '%d'\n", results.intimelimit);
02661    ast_debug(1, "OSPNext: OSPOUTCALLIDTYPES '%d'\n", callidtypes);
02662    ast_debug(1, "OSPNext: OSPDESTREMAILS '%d'\n", results.numdests);
02663 
02664    if ((res = osp_next(provider, cause, &results)) > 0) {
02665       status = AST_OSP_SUCCESS;
02666    } else {
02667       results.tech[0] = '\0';
02668       results.dest[0] = '\0';
02669       results.calling[0] = '\0';
02670       results.called[0] = '\0';
02671       results.token[0] = '\0';
02672       results.networkid[0] = '\0';
02673       results.nprn[0] = '\0';
02674       results.npcic[0] = '\0';
02675       results.npdi = 0;
02676       for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) {
02677          results.opname[type][0] = '\0';
02678       }
02679       results.numdests = 0;
02680       results.outtimelimit = OSP_DEF_TIMELIMIT;
02681       results.outcallid.buf[0] = '\0';
02682       results.outcallid.len = 0;
02683       if (!res) {
02684          status = AST_OSP_FAILED;
02685       } else {
02686          status = AST_OSP_ERROR;
02687       }
02688    }
02689 
02690    pbx_builtin_setvar_helper(chan, "OSPOUTTECH", results.tech);
02691    ast_debug(1, "OSPNext: OSPOUTTECH '%s'\n", results.tech);
02692    pbx_builtin_setvar_helper(chan, "OSPDESTINATION", results.dest);
02693    ast_debug(1, "OSPNext: OSPDESTINATION '%s'\n", results.dest);
02694    pbx_builtin_setvar_helper(chan, "OSPOUTCALLING", results.calling);
02695    ast_debug(1, "OSPNext: OSPOUTCALLING '%s'\n", results.calling);
02696    pbx_builtin_setvar_helper(chan, "OSPOUTCALLED", results.called);
02697    ast_debug(1, "OSPNext: OSPOUTCALLED'%s'\n", results.called);
02698    pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", results.networkid);
02699    ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", results.networkid);
02700    pbx_builtin_setvar_helper(chan, "OSPOUTNPRN", results.nprn);
02701    ast_debug(1, "OSPLookup: OSPOUTNPRN '%s'\n", results.nprn);
02702    pbx_builtin_setvar_helper(chan, "OSPOUTNPCIC", results.npcic);
02703    ast_debug(1, "OSPLookup: OSPOUTNPCIC '%s'\n", results.npcic);
02704    snprintf(buffer, sizeof(buffer), "%d", results.npdi);
02705    pbx_builtin_setvar_helper(chan, "OSPOUTNPDI", buffer);
02706    ast_debug(1, "OSPLookup: OSPOUTNPDI'%s'\n", buffer);
02707    pbx_builtin_setvar_helper(chan, "OSPOUTSPID", results.opname[OSPC_OPNAME_SPID]);
02708    ast_debug(1, "OSPLookup: OSPOUTSPID '%s'\n", results.opname[OSPC_OPNAME_SPID]);
02709    pbx_builtin_setvar_helper(chan, "OSPOUTOCN", results.opname[OSPC_OPNAME_OCN]);
02710    ast_debug(1, "OSPLookup: OSPOUTOCN '%s'\n", results.opname[OSPC_OPNAME_OCN]);
02711    pbx_builtin_setvar_helper(chan, "OSPOUTSPN", results.opname[OSPC_OPNAME_SPN]);
02712    ast_debug(1, "OSPLookup: OSPOUTSPN '%s'\n", results.opname[OSPC_OPNAME_SPN]);
02713    pbx_builtin_setvar_helper(chan, "OSPOUTALTSPN", results.opname[OSPC_OPNAME_ALTSPN]);
02714    ast_debug(1, "OSPLookup: OSPOUTALTSPN '%s'\n", results.opname[OSPC_OPNAME_ALTSPN]);
02715    pbx_builtin_setvar_helper(chan, "OSPOUTMCC", results.opname[OSPC_OPNAME_MCC]);
02716    ast_debug(1, "OSPLookup: OSPOUTMCC '%s'\n", results.opname[OSPC_OPNAME_MCC]);
02717    pbx_builtin_setvar_helper(chan, "OSPOUTMNC", results.opname[OSPC_OPNAME_MNC]);
02718    ast_debug(1, "OSPLookup: OSPOUTMNC '%s'\n", results.opname[OSPC_OPNAME_MNC]);
02719    pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", results.token);
02720    ast_debug(1, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(results.token));
02721    snprintf(buffer, sizeof(buffer), "%d", results.numdests);
02722    pbx_builtin_setvar_helper(chan, "OSPDESTREMAILS", buffer);
02723    ast_debug(1, "OSPNext: OSPDESTREMAILS '%s'\n", buffer);
02724    snprintf(buffer, sizeof(buffer), "%d", results.outtimelimit);
02725    pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
02726    ast_debug(1, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
02727    pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
02728    ast_debug(1, "OSPNext: %s\n", status);
02729 
02730    if (!strcasecmp(results.tech, OSP_TECH_SIP)) {
02731       snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
02732       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
02733       if (!ast_strlen_zero(results.token)) {
02734          snprintf(buffer, sizeof(buffer), "%s: %s", OSP_SIP_HEADER, results.token);
02735          pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
02736          ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
02737       }
02738    } else if (!strcasecmp(results.tech, OSP_TECH_H323)) {
02739       if ((callidtypes & OSP_CALLID_H323) && (results.outcallid.len != 0)) {
02740          osp_uuid2str(results.outcallid.buf, buffer, sizeof(buffer));
02741       } else {
02742          buffer[0] = '\0';
02743       }
02744       pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
02745       snprintf(buffer, sizeof(buffer), "%s/%s@%s", results.tech, results.called, results.dest);
02746       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
02747    } else if (!strcasecmp(results.tech, OSP_TECH_IAX)) {
02748       snprintf(buffer, sizeof(buffer), "%s/%s/%s", results.tech, results.dest, results.called);
02749       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
02750    } else if (!strcasecmp(results.tech, OSP_TECH_SKYPE)) {
02751       snprintf(buffer, sizeof(buffer), "%s/%s", results.tech, results.called);
02752       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
02753    }
02754 
02755    if(res != OSP_OK) {
02756       res = OSP_AST_ERROR;
02757    } else {
02758       res = OSP_AST_OK;
02759    }
02760 
02761    return res;
02762 }
02763 
02764 /*!
02765  * \brief OSP Application OSPFinish
02766  * \param chan Channel
02767  * \param data Parameter
02768  * \return OSP_AST_OK Success, OSP_AST_ERROR Error
02769  */
02770 static int ospfinished_exec(
02771    struct ast_channel* chan,
02772    const char * data)
02773 {
02774    int res = OSP_OK;
02775    int cause = 0;
02776    struct varshead* headp;
02777    struct ast_var_t* current;
02778    int inhandle = OSP_INVALID_HANDLE;
02779    int outhandle = OSP_INVALID_HANDLE;
02780    int recorded = 0;
02781    time_t start, connect, end;
02782    unsigned int release;
02783    char buffer[OSP_SIZE_INTSTR];
02784    char inqos[OSP_SIZE_QOSSTR] = { 0 };
02785    char outqos[OSP_SIZE_QOSSTR] = { 0 };
02786    const char* status;
02787    char* tmp;
02788 
02789    AST_DECLARE_APP_ARGS(args,
02790       AST_APP_ARG(cause);
02791       AST_APP_ARG(options);
02792    );
02793 
02794    if (!(tmp = ast_strdupa(data))) {
02795       ast_log(LOG_ERROR, "Out of memory\n");
02796       return OSP_AST_ERROR;
02797    }
02798 
02799    AST_STANDARD_APP_ARGS(args, tmp);
02800 
02801    headp = &chan->varshead;
02802    AST_LIST_TRAVERSE(headp, current, entries) {
02803       if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
02804          if (sscanf(ast_var_value(current), "%30d", &inhandle) != 1) {
02805             inhandle = OSP_INVALID_HANDLE;
02806          }
02807       } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
02808          if (sscanf(ast_var_value(current), "%30d", &outhandle) != 1) {
02809             outhandle = OSP_INVALID_HANDLE;
02810          }
02811       } else if (!recorded &&
02812          (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
02813          !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
02814          !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
02815       {
02816          if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
02817             recorded = 1;
02818          }
02819       } else if (!strcasecmp(ast_var_name(current), "OSPINAUDIOQOS")) {
02820          ast_copy_string(inqos, ast_var_value(current), sizeof(inqos));
02821       } else if (!strcasecmp(ast_var_name(current), "OSPOUTAUDIOQOS")) {
02822          ast_copy_string(outqos, ast_var_value(current), sizeof(outqos));
02823       }
02824    }
02825    ast_debug(1, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
02826    ast_debug(1, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
02827    ast_debug(1, "OSPFinish: recorded '%d'\n", recorded);
02828    ast_debug(1, "OSPFinish: OSPINAUDIOQOS '%s'\n", inqos);
02829    ast_debug(1, "OSPFinish: OSPOUTAUDIOQOS '%s'\n", outqos);
02830 
02831    if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
02832       cause = 0;
02833    }
02834    ast_debug(1, "OSPFinish: cause '%d'\n", cause);
02835 
02836    if (chan->cdr) {
02837       start = chan->cdr->start.tv_sec;
02838       connect = chan->cdr->answer.tv_sec;
02839       if (connect) {
02840          end = time(NULL);
02841       } else {
02842          end = connect;
02843       }
02844    } else {
02845       start = 0;
02846       connect = 0;
02847       end = 0;
02848    }
02849    ast_debug(1, "OSPFinish: start '%ld'\n", start);
02850    ast_debug(1, "OSPFinish: connect '%ld'\n", connect);
02851    ast_debug(1, "OSPFinish: end '%ld'\n", end);
02852 
02853    release = ast_check_hangup(chan) ? 0 : 1;
02854 
02855    if (osp_finish(outhandle, recorded, cause, start, connect, end, release, inqos, outqos) <= 0) {
02856       ast_debug(1, "OSPFinish: Unable to report usage for outbound call\n");
02857    }
02858    switch (cause) {
02859    case AST_CAUSE_NORMAL_CLEARING:
02860       break;
02861    default:
02862       cause = AST_CAUSE_NO_ROUTE_DESTINATION;
02863       break;
02864    }
02865    if (osp_finish(inhandle, recorded, cause, start, connect, end, release, inqos, outqos) <= 0) {
02866       ast_debug(1, "OSPFinish: Unable to report usage for inbound call\n");
02867    }
02868    snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
02869    pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
02870    pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
02871 
02872    if (res > 0) {
02873       status = AST_OSP_SUCCESS;
02874    } else if (!res) {
02875       status = AST_OSP_FAILED;
02876    } else {
02877       status = AST_OSP_ERROR;
02878    }
02879    pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
02880 
02881    if(res != OSP_OK) {
02882       res = OSP_AST_ERROR;
02883    } else {
02884       res = OSP_AST_OK;
02885    }
02886 
02887    return res;
02888 }
02889 
02890 /* OSP Module APIs */
02891 
02892 static int osp_unload(void)
02893 {
02894    struct osp_provider* provider;
02895    struct osp_provider* next;
02896 
02897    if (osp_initialized) {
02898       ast_mutex_lock(&osp_lock);
02899       for (provider = osp_providers; provider; provider = next) {
02900          next = provider->next;
02901          OSPPProviderDelete(provider->handle, 0);
02902          ast_free(provider);
02903       }
02904       osp_providers = NULL;
02905       ast_mutex_unlock(&osp_lock);
02906 
02907       OSPPCleanup();
02908 
02909       osp_tokenformat = TOKEN_ALGO_SIGNED;
02910       osp_security = 0;
02911       osp_hardware = 0;
02912       osp_initialized = 0;
02913    }
02914 
02915    return 0;
02916 }
02917 
02918 static int osp_load(int reload)
02919 {
02920    const char* cvar;
02921    unsigned int ivar;
02922    struct ast_config* cfg;
02923    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02924    int error = OSPC_ERR_NO_ERROR;
02925 
02926    if ((cfg = ast_config_load(OSP_CONFIG_FILE, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
02927       return 0;
02928    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
02929       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", OSP_CONFIG_FILE);
02930       return 0;
02931    }
02932 
02933    if (cfg) {
02934       if (reload) {
02935          osp_unload();
02936       }
02937 
02938       if ((cvar = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate")) && ast_true(cvar)) {
02939          if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
02940             ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
02941             OSPPInit(0);
02942          } else {
02943             osp_hardware = 1;
02944          }
02945       } else {
02946          OSPPInit(0);
02947       }
02948       ast_debug(1, "OSP: osp_hardware '%d'\n", osp_hardware);
02949 
02950       if ((cvar = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "securityfeatures")) && ast_true(cvar)) {
02951          osp_security = 1;
02952       }
02953       ast_debug(1, "OSP: osp_security '%d'\n", osp_security);
02954 
02955       if ((cvar = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat"))) {
02956          if ((sscanf(cvar, "%30d", &ivar) == 1) &&
02957             ((ivar == TOKEN_ALGO_SIGNED) || (ivar == TOKEN_ALGO_UNSIGNED) || (ivar == TOKEN_ALGO_BOTH)))
02958          {
02959             osp_tokenformat = ivar;
02960          } else {
02961             ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
02962                TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, cvar);
02963          }
02964       }
02965       ast_debug(1, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
02966 
02967       for (cvar = ast_category_browse(cfg, NULL); cvar != NULL; cvar = ast_category_browse(cfg, cvar)) {
02968          if (strcasecmp(cvar, OSP_GENERAL_CAT)) {
02969             osp_create_provider(cfg, cvar);
02970          }
02971       }
02972 
02973       osp_initialized = 1;
02974 
02975       ast_config_destroy(cfg);
02976    } else {
02977       ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
02978       return 0;
02979    }
02980    ast_debug(1, "OSP: osp_initialized '%d'\n", osp_initialized);
02981 
02982    return 1;
02983 }
02984 
02985 static char *handle_cli_osp_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02986 {
02987    int i;
02988    int found = 0;
02989    struct osp_provider* provider;
02990    const char* name = NULL;
02991    const char* tokenalgo;
02992 
02993    switch (cmd) {
02994    case CLI_INIT:
02995       e->command = "osp show";
02996       e->usage =
02997          "Usage: osp show\n"
02998          "       Displays information on Open Settlement Protocol support\n";
02999       return NULL;
03000    case CLI_GENERATE:
03001       return NULL;
03002    }
03003 
03004    if ((a->argc < 2) || (a->argc > 3)) {
03005       return CLI_SHOWUSAGE;
03006    }
03007 
03008    if (a->argc > 2) {
03009       name = a->argv[2];
03010    }
03011 
03012    if (!name) {
03013       switch (osp_tokenformat) {
03014       case TOKEN_ALGO_BOTH:
03015          tokenalgo = "Both";
03016          break;
03017       case TOKEN_ALGO_UNSIGNED:
03018          tokenalgo = "Unsigned";
03019          break;
03020       case TOKEN_ALGO_SIGNED:
03021       default:
03022          tokenalgo = "Signed";
03023          break;
03024       }
03025       ast_cli(a->fd, "OSP: %s/%s/%s/%s\n",
03026          osp_initialized ? "Initialized" : "Uninitialized",
03027          osp_hardware ? "Accelerated" : "Normal",
03028          osp_security ? "Enabled" : "Disabled",
03029          tokenalgo);
03030    }
03031 
03032    ast_mutex_lock(&osp_lock);
03033    for (provider = osp_providers; provider; provider = provider->next) {
03034       if (!name || !strcasecmp(provider->name, name)) {
03035          if (found) {
03036             ast_cli(a->fd, "\n");
03037          }
03038          ast_cli(a->fd, " == OSP Provider '%s' == \n", provider->name);
03039          if (osp_security) {
03040             ast_cli(a->fd, "Local Private Key: %s\n", provider->privatekey);
03041             ast_cli(a->fd, "Local Certificate: %s\n", provider->localcert);
03042             for (i = 0; i < provider->canum; i++) {
03043                ast_cli(a->fd, "CA Certificate %d:  %s\n", i + 1, provider->cacerts[i]);
03044             }
03045          }
03046          for (i = 0; i < provider->spnum; i++) {
03047             ast_cli(a->fd, "Service Point %d:   %s\n", i + 1, provider->spoints[i]);
03048          }
03049          ast_cli(a->fd, "Max Connections:   %d\n", provider->maxconnect);
03050          ast_cli(a->fd, "Retry Delay:       %d seconds\n", provider->retrydelay);
03051          ast_cli(a->fd, "Retry Limit:       %d\n", provider->retrylimit);
03052          ast_cli(a->fd, "Timeout:           %d milliseconds\n", provider->timeout);
03053          ast_cli(a->fd, "Source:            %s\n", strlen(provider->source) ? provider->source : "<unspecified>");
03054          ast_cli(a->fd, "Auth Policy        %d\n", provider->authpolicy);
03055          ast_cli(a->fd, "Default protocol   %s\n", provider->defprotocol);
03056          ast_cli(a->fd, "Work mode          %d\n", provider->workmode);
03057          ast_cli(a->fd, "Service type       %d\n", provider->srvtype);
03058          ast_cli(a->fd, "OSP Handle:        %d\n", provider->handle);
03059          found++;
03060       }
03061    }
03062    ast_mutex_unlock(&osp_lock);
03063 
03064    if (!found) {
03065       if (name) {
03066          ast_cli(a->fd, "Unable to find OSP provider '%s'\n", name);
03067       } else {
03068          ast_cli(a->fd, "No OSP providers configured\n");
03069       }
03070    }
03071 
03072    return CLI_SUCCESS;
03073 }
03074 
03075 /* OSPAuth() dialplan application */
03076 static const char app1[] = "OSPAuth";
03077 
03078 /* OSPLookup() dialplan application */
03079 static const char app2[] = "OSPLookup";
03080 
03081 /* OSPNext() dialplan application */
03082 static const char app3[] = "OSPNext";
03083 
03084 /* OSPFinish() dialplan application */
03085 static const char app4[] = "OSPFinish";
03086 
03087 static struct ast_cli_entry cli_osp[] = {
03088    AST_CLI_DEFINE(handle_cli_osp_show, "Displays OSF information")
03089 };
03090 
03091 static int load_module(void)
03092 {
03093    int res;
03094 
03095    if (!osp_load(0))
03096       return AST_MODULE_LOAD_DECLINE;
03097 
03098    ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
03099    res = ast_register_application_xml(app1, ospauth_exec);
03100    res |= ast_register_application_xml(app2, osplookup_exec);
03101    res |= ast_register_application_xml(app3, ospnext_exec);
03102    res |= ast_register_application_xml(app4, ospfinished_exec);
03103 
03104    return res;
03105 }
03106 
03107 static int unload_module(void)
03108 {
03109    int res;
03110 
03111    res = ast_unregister_application(app4);
03112    res |= ast_unregister_application(app3);
03113    res |= ast_unregister_application(app2);
03114    res |= ast_unregister_application(app1);
03115    ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
03116    osp_unload();
03117 
03118    return res;
03119 }
03120 
03121 static int reload(void)
03122 {
03123    osp_load(1);
03124 
03125    return 0;
03126 }
03127 
03128 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
03129    .load = load_module,
03130    .unload = unload_module,
03131    .reload = reload,
03132 );

Generated on Mon Mar 19 11:30:20 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7