Wed Oct 28 11:50:53 2009

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>ssl</depend>
00034  ***/
00035 
00036 #include "asterisk.h"
00037 
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211569 $")
00039 
00040 #include <osp/osp.h>
00041 #include <osp/osputils.h>
00042 
00043 #include "asterisk/paths.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/config.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/causes.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/app.h"
00050 #include "asterisk/module.h"
00051 #include "asterisk/pbx.h"
00052 #include "asterisk/cli.h"
00053 #include "asterisk/astosp.h"
00054 
00055 /* OSP Buffer Sizes */
00056 #define OSP_INTSTR_SIZE    ((unsigned int)16)      /* OSP signed/unsigned int string buffer size */
00057 #define OSP_NORSTR_SIZE    ((unsigned int)256)     /* OSP normal string buffer size */
00058 #define OSP_TOKSTR_SIZE    ((unsigned int)4096) /* OSP token string buffer size */
00059 #define OSP_TECHSTR_SIZE   ((unsigned int)32)      /* OSP signed/unsigned int string buffer size */
00060 #define OSP_UUID_SIZE      ((unsigned int)16)      /* UUID size */
00061 #define OSP_UUIDSTR_SIZE   ((unsigned int)36)      /* UUID string size */
00062 
00063 /* OSP Authentication Policy */
00064 enum osp_authpolicy {
00065    OSP_AUTH_NO,      /* Accept any call */
00066    OSP_AUTH_YES,     /* Accept call with valid OSP token or without OSP token */
00067    OSP_AUTH_EXCLUSIVE   /* Only accept call with valid OSP token */
00068 };
00069 
00070 /* Call ID type*/
00071 #define OSP_CALLID_UNDEFINED  ((unsigned int)0)       /* UNDEFINED */
00072 #define OSP_CALLID_H323       ((unsigned int)(1 << 0))   /* H.323 */
00073 #define OSP_CALLID_SIP        ((unsigned int)(1 << 1))   /* SIP */
00074 #define OSP_CALLID_IAX        ((unsigned int)(1 << 2))   /* IAX2 */
00075 #define OSP_CALLID_MAXNUM     ((unsigned int)3)       /* Max number of call ID type */
00076 
00077 /* OSP Supported Destination Protocols */
00078 #define OSP_PROT_H323         ((char*)"H323")            /* H323 Q931 protocol name*/
00079 #define OSP_PROT_SIP       ((char*)"SIP")          /* SIP protocol name */
00080 #define OSP_PROT_IAX       ((char*)"IAX")          /* IAX protocol name */
00081 #define OSP_PROT_OTHER        ((char*)"OTHER")        /* Other protocol name */
00082 
00083 /* OSP supported Destination Tech */
00084 #if 0
00085 #define OSP_TECH_H323         ((char*)"OOH323")       /* OOH323 tech name */
00086 #endif
00087 #define OSP_TECH_H323         ((char*)"H323")            /* OH323 tech name */
00088 #define OSP_TECH_SIP       ((char*)"SIP")          /* SIP tech name */
00089 #define OSP_TECH_IAX       ((char*)"IAX2")            /* IAX2 tech name */
00090 
00091 /* SIP OSP header field name */
00092 #define OSP_SIP_HEADER        ((char*)"P-OSP-Auth-Token: ")
00093 
00094 /* OSP Constants */
00095 #define OSP_INVALID_HANDLE    ((int)-1)               /* Invalid OSP handle, provider, transaction etc. */
00096 #define OSP_CONFIG_FILE       ((const char*)"osp.conf")  /* OSP configuration file name */
00097 #define OSP_GENERAL_CAT       ((const char*)"general")   /* OSP global configuration context name */
00098 #define OSP_DEF_PROVIDER      ((const char*)"default")   /* OSP default provider context name */
00099 #define OSP_MAX_CERTS         ((unsigned int)10)         /* OSP max number of cacerts */
00100 #define OSP_MAX_SRVS       ((unsigned int)10)         /* OSP max number of service points */
00101 #define OSP_DEF_MAXCONNECTIONS   ((unsigned int)20)         /* OSP default max_connections */
00102 #define OSP_MIN_MAXCONNECTIONS   ((unsigned int)1)       /* OSP min max_connections */
00103 #define OSP_MAX_MAXCONNECTIONS   ((unsigned int)1000)    /* OSP max max_connections */
00104 #define OSP_DEF_RETRYDELAY    ((unsigned int)0)       /* OSP default retry delay */
00105 #define OSP_MIN_RETRYDELAY    ((unsigned int)0)       /* OSP min retry delay */
00106 #define OSP_MAX_RETRYDELAY    ((unsigned int)10)         /* OSP max retry delay */
00107 #define OSP_DEF_RETRYLIMIT    ((unsigned int)2)       /* OSP default retry times */
00108 #define OSP_MIN_RETRYLIMIT    ((unsigned int)0)       /* OSP min retry times */
00109 #define OSP_MAX_RETRYLIMIT    ((unsigned int)100)        /* OSP max retry times */
00110 #define OSP_DEF_TIMEOUT       ((unsigned int)500)        /* OSP default timeout in ms */
00111 #define OSP_MIN_TIMEOUT       ((unsigned int)200)        /* OSP min timeout in ms */
00112 #define OSP_MAX_TIMEOUT       ((unsigned int)10000)      /* OSP max timeout in ms */
00113 #define OSP_DEF_AUTHPOLICY    ((enum osp_authpolicy)OSP_AUTH_YES)
00114 #define OSP_AUDIT_URL         ((const char*)"localhost") /* OSP default Audit URL */
00115 #define OSP_LOCAL_VALIDATION  ((int)1)             /* Validate OSP token locally */
00116 #define OSP_SSL_LIFETIME      ((unsigned int)300)        /* SSL life time, in seconds */
00117 #define OSP_HTTP_PERSISTENCE  ((int)1)             /* In seconds */
00118 #define OSP_CUSTOMER_ID       ((const char*)"")       /* OSP customer ID */
00119 #define OSP_DEVICE_ID         ((const char*)"")       /* OSP device ID */
00120 #define OSP_DEF_DESTINATIONS  ((unsigned int)5)       /* OSP default max number of destinations */
00121 #define OSP_DEF_TIMELIMIT     ((unsigned int)0)       /* OSP default duration limit, no limit */
00122 #define OSP_DEF_PROTOCOL      OSP_PROT_SIP            /* OSP default destination protocol, SIP */
00123 
00124 /* OSP Provider */
00125 struct osp_provider {
00126    char name[OSP_NORSTR_SIZE];                  /* OSP provider context name */
00127    char privatekey[OSP_NORSTR_SIZE];            /* OSP private key file name */
00128    char localcert[OSP_NORSTR_SIZE];          /* OSP local cert file name */
00129    unsigned int cacount;                     /* Number of cacerts */
00130    char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE];   /* Cacert file names */
00131    unsigned int spcount;                     /* Number of service points */
00132    char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];  /* Service point URLs */
00133    int maxconnections;                       /* Max number of connections */
00134    int retrydelay;                           /* Retry delay */
00135    int retrylimit;                           /* Retry limit */
00136    int timeout;                           /* Timeout in ms */
00137    char source[OSP_NORSTR_SIZE];             /* IP of self */
00138    enum osp_authpolicy authpolicy;              /* OSP authentication policy */
00139    char* defaultprotocol;                    /* OSP default destination protocol */
00140    OSPTPROVHANDLE handle;                    /* OSP provider handle */
00141    struct osp_provider* next;                /* Pointer to next OSP provider */
00142 };
00143 
00144 /* Call ID */
00145 struct osp_callid {
00146    unsigned char buf[OSPC_CALLID_MAXSIZE];      /* Call ID string */
00147    unsigned int len;                   /* Call ID length */
00148 };
00149 
00150 /* OSP Application In/Output Results */
00151 struct osp_result {
00152    int inhandle;                 /* Inbound transaction handle */
00153    int outhandle;                /* Outbound transaction handle */
00154    unsigned int intimelimit;        /* Inbound duration limit */
00155    unsigned int outtimelimit;       /* Outbound duration limit */
00156    char tech[OSP_TECHSTR_SIZE];     /* Outbound Asterisk TECH string */
00157    char dest[OSP_NORSTR_SIZE];         /* Outbound destination IP address */
00158    char called[OSP_NORSTR_SIZE];    /* Outbound called number, may be translated */
00159    char calling[OSP_NORSTR_SIZE];      /* Outbound calling number, may be translated */
00160    char token[OSP_TOKSTR_SIZE];     /* Outbound OSP token */
00161    char networkid[OSP_NORSTR_SIZE]; /* Outbound network ID */
00162    unsigned int numresults;         /* Number of remain outbound destinations */
00163    struct osp_callid outcallid;     /* Outbound call ID */
00164 };
00165 
00166 /* OSP Module Global Variables */
00167 AST_MUTEX_DEFINE_STATIC(osplock);                     /* Lock of OSP provider list */
00168 static int osp_initialized = 0;                       /* Init flag */
00169 static int osp_hardware = 0;                       /* Hardware accelleration flag */
00170 static struct osp_provider* ospproviders = NULL;         /* OSP provider list */
00171 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED; /* Token format supported */
00172 
00173 /* OSP Client Wrapper APIs */
00174 
00175 /*!
00176  * \brief Create OSP provider handle according to configuration
00177  * \param cfg OSP configuration
00178  * \param provider OSP provider context name
00179  * \return 1 Success, 0 Failed, -1 Error
00180  */
00181 static int osp_create_provider(
00182    struct ast_config* cfg,
00183    const char* provider)
00184 {
00185    int res = 0;
00186    struct ast_variable* v;
00187    struct osp_provider* p;
00188    OSPTPRIVATEKEY privatekey;
00189    OSPT_CERT localcert;
00190    OSPT_CERT cacerts[OSP_MAX_CERTS];
00191    const OSPT_CERT* pcacerts[OSP_MAX_CERTS];
00192    const char* psrvpoints[OSP_MAX_SRVS];
00193    int t, i, j, error = OSPC_ERR_NO_ERROR;
00194 
00195    if (!(p = ast_calloc(1, sizeof(*p)))) {
00196       ast_log(LOG_ERROR, "Out of memory\n");
00197       return -1;
00198    }
00199 
00200    /* ast_calloc has set 0 in p */
00201    ast_copy_string(p->name, provider, sizeof(p->name));
00202    snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
00203    snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
00204    snprintf(p->cacerts[0], sizeof(p->cacerts[0]), "%s/%s-cacert_0.pem", ast_config_AST_KEY_DIR, provider);
00205    p->maxconnections = OSP_DEF_MAXCONNECTIONS;
00206    p->retrydelay = OSP_DEF_RETRYDELAY;
00207    p->retrylimit = OSP_DEF_RETRYLIMIT;
00208    p->timeout = OSP_DEF_TIMEOUT;
00209    p->authpolicy = OSP_DEF_AUTHPOLICY;
00210    p->defaultprotocol = OSP_DEF_PROTOCOL;
00211    p->handle = OSP_INVALID_HANDLE;
00212 
00213    v = ast_variable_browse(cfg, provider);
00214    while(v) {
00215       if (!strcasecmp(v->name, "privatekey")) {
00216          if (v->value[0] == '/') {
00217             ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
00218          } else {
00219             snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00220          }
00221          ast_debug(1, "OSP: privatekey '%s'\n", p->privatekey);
00222       } else if (!strcasecmp(v->name, "localcert")) {
00223          if (v->value[0] == '/') {
00224             ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
00225          } else {
00226             snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00227          }
00228          ast_debug(1, "OSP: localcert '%s'\n", p->localcert);
00229       } else if (!strcasecmp(v->name, "cacert")) {
00230          if (p->cacount < OSP_MAX_CERTS) {
00231             if (v->value[0] == '/') {
00232                ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
00233             } else {
00234                snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00235             }
00236             ast_debug(1, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
00237             p->cacount++;
00238          } else {
00239             ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
00240          }
00241       } else if (!strcasecmp(v->name, "servicepoint")) {
00242          if (p->spcount < OSP_MAX_SRVS) {
00243             ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
00244             ast_debug(1, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
00245             p->spcount++;
00246          } else {
00247             ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
00248          }
00249       } else if (!strcasecmp(v->name, "maxconnections")) {
00250          if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
00251             p->maxconnections = t;
00252             ast_debug(1, "OSP: maxconnections '%d'\n", t);
00253          } else {
00254             ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n",
00255                OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
00256          }
00257       } else if (!strcasecmp(v->name, "retrydelay")) {
00258          if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
00259             p->retrydelay = t;
00260             ast_debug(1, "OSP: retrydelay '%d'\n", t);
00261          } else {
00262             ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n",
00263                OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
00264          }
00265       } else if (!strcasecmp(v->name, "retrylimit")) {
00266          if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
00267             p->retrylimit = t;
00268             ast_debug(1, "OSP: retrylimit '%d'\n", t);
00269          } else {
00270             ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n",
00271                OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
00272          }
00273       } else if (!strcasecmp(v->name, "timeout")) {
00274          if ((sscanf(v->value, "%30d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
00275             p->timeout = t;
00276             ast_debug(1, "OSP: timeout '%d'\n", t);
00277          } else {
00278             ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n",
00279                OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
00280          }
00281       } else if (!strcasecmp(v->name, "source")) {
00282          ast_copy_string(p->source, v->value, sizeof(p->source));
00283          ast_debug(1, "OSP: source '%s'\n", p->source);
00284       } else if (!strcasecmp(v->name, "authpolicy")) {
00285          if ((sscanf(v->value, "%30d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
00286             p->authpolicy = t;
00287             ast_debug(1, "OSP: authpolicy '%d'\n", t);
00288          } else {
00289             ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n",
00290                OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
00291          }
00292       } else if (!strcasecmp(v->name, "defaultprotocol")) {
00293          if (!strcasecmp(v->value, OSP_PROT_SIP)) {
00294             p->defaultprotocol = OSP_PROT_SIP;
00295             ast_debug(1, "OSP: default protocol '%s'\n", p->defaultprotocol);
00296          } else if (!strcasecmp(v->value, OSP_PROT_H323)) {
00297             p->defaultprotocol = OSP_PROT_H323;
00298             ast_debug(1, "OSP: default protocol '%s'\n", p->defaultprotocol);
00299          } else if (!strcasecmp(v->value, OSP_PROT_IAX)) {
00300             p->defaultprotocol = OSP_PROT_IAX;
00301             ast_debug(1, "OSP: default protocol '%s'\n", p->defaultprotocol);
00302          } else {
00303             ast_log(LOG_WARNING, "OSP: default protocol should be %s, %s, %s, or %s not '%s' at line %d\n",
00304                OSP_PROT_SIP, OSP_PROT_H323, OSP_PROT_IAX, OSP_PROT_OTHER, v->value, v->lineno);
00305          }
00306       }
00307       v = v->next;
00308    }
00309 
00310    error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey);
00311    if (error != OSPC_ERR_NO_ERROR) {
00312       ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
00313       ast_free(p);
00314       return 0;
00315    }
00316 
00317    error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert);
00318    if (error != OSPC_ERR_NO_ERROR) {
00319       ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
00320       if (privatekey.PrivateKeyData) {
00321          ast_free(privatekey.PrivateKeyData);
00322       }
00323       ast_free(p);
00324       return 0;
00325    }
00326 
00327    if (p->cacount < 1) {
00328       snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
00329       ast_debug(1, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
00330       p->cacount++;
00331    }
00332    for (i = 0; i < p->cacount; i++) {
00333       error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i]);
00334       if (error != OSPC_ERR_NO_ERROR) {
00335          ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
00336          for (j = 0; j < i; j++) {
00337             if (cacerts[j].CertData) {
00338                ast_free(cacerts[j].CertData);
00339             }
00340          }
00341          if (localcert.CertData) {
00342             ast_free(localcert.CertData);
00343          }
00344          if (privatekey.PrivateKeyData) {
00345             ast_free(privatekey.PrivateKeyData);
00346          }
00347          ast_free(p);
00348          return 0;
00349       }
00350       pcacerts[i] = &cacerts[i];
00351    }
00352 
00353    for (i = 0; i < p->spcount; i++) {
00354       psrvpoints[i] = p->srvpoints[i];
00355    }
00356 
00357    error = OSPPProviderNew(
00358       p->spcount,
00359       psrvpoints,
00360       NULL,
00361       OSP_AUDIT_URL,
00362       &privatekey,
00363       &localcert,
00364       p->cacount,
00365       pcacerts,
00366       OSP_LOCAL_VALIDATION,
00367       OSP_SSL_LIFETIME,
00368       p->maxconnections,
00369       OSP_HTTP_PERSISTENCE,
00370       p->retrydelay,
00371       p->retrylimit,
00372       p->timeout,
00373       OSP_CUSTOMER_ID,
00374       OSP_DEVICE_ID,
00375       &p->handle);
00376    if (error != OSPC_ERR_NO_ERROR) {
00377       ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
00378       ast_free(p);
00379       res = -1;
00380    } else {
00381       ast_debug(1, "OSP: provider '%s'\n", provider);
00382       ast_mutex_lock(&osplock);
00383       p->next = ospproviders;
00384       ospproviders = p;
00385       ast_mutex_unlock(&osplock);
00386       res = 1;
00387    }
00388 
00389    for (i = 0; i < p->cacount; i++) {
00390       if (cacerts[i].CertData) {
00391          ast_free(cacerts[i].CertData);
00392       }
00393    }
00394    if (localcert.CertData) {
00395       ast_free(localcert.CertData);
00396    }
00397    if (privatekey.PrivateKeyData) {
00398       ast_free(privatekey.PrivateKeyData);
00399    }
00400 
00401    return res;
00402 }
00403 
00404 /*!
00405  * \brief Get OSP provider by name
00406  * \param name OSP provider context name
00407  * \param provider OSP provider structure
00408  * \return 1 Success, 0 Failed, -1 Error
00409  */
00410 static int osp_get_provider(
00411    const char* name,
00412    struct osp_provider** provider)
00413 {
00414    int res = 0;
00415    struct osp_provider* p;
00416 
00417    ast_mutex_lock(&osplock);
00418    p = ospproviders;
00419    while(p) {
00420       if (!strcasecmp(p->name, name)) {
00421          *provider = p;
00422          ast_debug(1, "OSP: find provider '%s'\n", name);
00423          res = 1;
00424          break;
00425       }
00426       p = p->next;
00427    }
00428    ast_mutex_unlock(&osplock);
00429 
00430    return res;
00431 }
00432 
00433 /*!
00434  * \brief Create OSP transaction handle
00435  * \param provider OSP provider context name
00436  * \param transaction OSP transaction handle, output
00437  * \param sourcesize Size of source buffer, in/output
00438  * \param source Source of provider, output
00439  * \return 1 Success, 0 Failed, -1 Error
00440  */
00441 static int osp_create_transaction(
00442    const char* provider,
00443    int* transaction,
00444    unsigned int sourcesize,
00445    char* source)
00446 {
00447    int res = 0;
00448    struct osp_provider* p;
00449    int error;
00450 
00451    ast_mutex_lock(&osplock);
00452    p = ospproviders;
00453    while(p) {
00454       if (!strcasecmp(p->name, provider)) {
00455          error = OSPPTransactionNew(p->handle, transaction);
00456          if (error == OSPC_ERR_NO_ERROR) {
00457             ast_debug(1, "OSP: transaction '%d'\n", *transaction);
00458             ast_copy_string(source, p->source, sourcesize);
00459             ast_debug(1, "OSP: source '%s'\n", source);
00460             res = 1;
00461          } else {
00462             *transaction = OSP_INVALID_HANDLE;
00463             ast_debug(1, "OSP: Unable to create transaction handle, error '%d'\n", error);
00464             res = -1;
00465          }
00466          break;
00467       }
00468       p = p->next;
00469    }
00470    ast_mutex_unlock(&osplock);
00471 
00472    return res;
00473 }
00474 
00475 /*!
00476  * \brief Convert address to "[x.x.x.x]" or "host.domain" format
00477  * \param src Source address string
00478  * \param dst Destination address string
00479  * \param buffersize Size of dst buffer
00480  */
00481 static void osp_convert_address(
00482    const char* src,
00483    char* dst,
00484    int buffersize)
00485 {
00486    struct in_addr inp;
00487 
00488    if (inet_aton(src, &inp) != 0) {
00489       snprintf(dst, buffersize, "[%s]", src);
00490    } else {
00491       snprintf(dst, buffersize, "%s", src);
00492    }
00493 }
00494 
00495 /*!
00496  * \brief Validate OSP token of inbound call
00497  * \param transaction OSP transaction handle
00498  * \param source Source of inbound call
00499  * \param destination Destination of inbound call
00500  * \param calling Calling number
00501  * \param called Called number
00502  * \param token OSP token, may be empty
00503  * \param timelimit Call duration limit, output
00504  * \return 1 Success, 0 Failed, -1 Error
00505  */
00506 static int osp_validate_token(
00507    int transaction,
00508    const char* source,
00509    const char* destination,
00510    const char* calling,
00511    const char* called,
00512    const char* token,
00513    unsigned int* timelimit)
00514 {
00515    int res;
00516    int tokenlen;
00517    unsigned char tokenstr[OSP_TOKSTR_SIZE];
00518    char src[OSP_NORSTR_SIZE];
00519    char dst[OSP_NORSTR_SIZE];
00520    unsigned int authorised;
00521    unsigned int dummy = 0;
00522    int error;
00523 
00524    tokenlen = ast_base64decode(tokenstr, token, strlen(token));
00525    osp_convert_address(source, src, sizeof(src));
00526    osp_convert_address(destination, dst, sizeof(dst));
00527    error = OSPPTransactionValidateAuthorisation(
00528       transaction,
00529       src,
00530       dst,
00531       NULL,
00532       NULL,
00533       calling ? calling : "",
00534       OSPC_NFORMAT_E164,
00535       called,
00536       OSPC_NFORMAT_E164,
00537       0,
00538       NULL,
00539       tokenlen,
00540       (char*)tokenstr,
00541       &authorised,
00542       timelimit,
00543       &dummy,
00544       NULL,
00545       osp_tokenformat);
00546    if (error != OSPC_ERR_NO_ERROR) {
00547       ast_debug(1, "OSP: Unable to validate inbound token, error '%d'\n", error);
00548       res = -1;
00549    } else if (authorised) {
00550       ast_debug(1, "OSP: Authorised\n");
00551       res = 1;
00552    } else {
00553       ast_debug(1, "OSP: Unauthorised\n");
00554       res = 0;
00555    }
00556 
00557    return res;
00558 }
00559 
00560 /*!
00561  * \brief Choose min duration limit
00562  * \param in Inbound duration limit
00563  * \param out Outbound duration limit
00564  * \return min duration limit
00565  */
00566 static unsigned int osp_choose_timelimit(
00567    unsigned int in,
00568    unsigned int out)
00569 {
00570    if (in == OSP_DEF_TIMELIMIT) {
00571       return out;
00572    } else if (out == OSP_DEF_TIMELIMIT) {
00573       return in;
00574    } else {
00575       return in < out ? in : out;
00576    }
00577 }
00578 
00579 /*!
00580  * \brief Choose min duration limit
00581  * \param provider OSP provider
00582  * \param called Called number
00583  * \param calling Calling number
00584  * \param destination Destination IP in '[x.x.x.x]' format
00585  * \param tokenlen OSP token length
00586  * \param token OSP token
00587  * \param reason Failure reason, output
00588  * \param result OSP lookup results, in/output
00589  * \return 1 Success, 0 Failed, -1 Error
00590  */
00591 static int osp_check_destination(
00592    struct osp_provider* provider,
00593    const char* called,
00594    const char* calling,
00595    char* destination,
00596    unsigned int tokenlen,
00597    const char* token,
00598    OSPEFAILREASON* reason,
00599    struct osp_result* result)
00600 {
00601    int res;
00602    OSPE_DEST_OSPENABLED enabled;
00603    OSPE_DEST_PROTOCOL protocol;
00604    int error;
00605 
00606    if (strlen(destination) <= 2) {
00607       ast_debug(1, "OSP: Wrong destination format '%s'\n", destination);
00608       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
00609       return -1;
00610    }
00611 
00612    if ((error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
00613       ast_debug(1, "OSP: Unable to get destination OSP version, error '%d'\n", error);
00614       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
00615       return -1;
00616    }
00617 
00618    if (enabled == OSPC_DOSP_FALSE) {
00619       result->token[0] = '\0';
00620    } else {
00621       ast_base64encode(result->token, (const unsigned char*)token, tokenlen, sizeof(result->token) - 1);
00622    }
00623 
00624    if ((error = OSPPTransactionGetDestNetworkId(result->outhandle, result->networkid)) != OSPC_ERR_NO_ERROR) {
00625       ast_debug(1, "OSP: Unable to get destination network ID, error '%d'\n", error);
00626       result->networkid[0] = '\0';
00627    }
00628 
00629    if ((error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
00630       ast_debug(1, "OSP: Unable to get destination protocol, error '%d'\n", error);
00631       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
00632       result->token[0] = '\0';
00633       result->networkid[0] = '\0';
00634       return -1;
00635    }
00636 
00637    res = 1;
00638    /* Strip leading and trailing brackets */
00639    destination[strlen(destination) - 1] = '\0';
00640    switch(protocol) {
00641    case OSPC_DPROT_Q931:
00642       ast_debug(1, "OSP: protocol '%s'\n", OSP_PROT_H323);
00643       ast_copy_string(result->tech, OSP_TECH_H323, sizeof(result->tech));
00644       ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
00645       ast_copy_string(result->called, called, sizeof(result->called));
00646       ast_copy_string(result->calling, calling, sizeof(result->calling));
00647       break;
00648    case OSPC_DPROT_SIP:
00649       ast_debug(1, "OSP: protocol '%s'\n", OSP_PROT_SIP);
00650       ast_copy_string(result->tech, OSP_TECH_SIP, sizeof(result->tech));
00651       ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
00652       ast_copy_string(result->called, called, sizeof(result->called));
00653       ast_copy_string(result->calling, calling, sizeof(result->calling));
00654       break;
00655    case OSPC_DPROT_IAX:
00656       ast_debug(1, "OSP: protocol '%s'\n", OSP_PROT_IAX);
00657       ast_copy_string(result->tech, OSP_TECH_IAX, sizeof(result->tech));
00658       ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
00659       ast_copy_string(result->called, called, sizeof(result->called));
00660       ast_copy_string(result->calling, calling, sizeof(result->calling));
00661       break;
00662    case OSPC_DPROT_UNDEFINED:
00663    case OSPC_DPROT_UNKNOWN:
00664       ast_debug(1, "OSP: unknown/undefined protocol '%d'\n", protocol);
00665       ast_debug(1, "OSP: use default protocol '%s'\n", provider->defaultprotocol);
00666 
00667       ast_copy_string(result->tech, provider->defaultprotocol, sizeof(result->tech));
00668       ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
00669       ast_copy_string(result->called, called, sizeof(result->called));
00670       ast_copy_string(result->calling, calling, sizeof(result->calling));
00671       break;
00672    case OSPC_DPROT_LRQ:
00673    default:
00674       ast_log(LOG_WARNING, "OSP: unsupported protocol '%d'\n", protocol);
00675       *reason = OSPC_FAIL_PROTOCOL_ERROR;
00676       result->token[0] = '\0';
00677       result->networkid[0] = '\0';
00678       res = 0;
00679       break;
00680    }
00681 
00682    return res;
00683 }
00684 
00685 /*!
00686  * \brief Convert Asterisk status to TC code
00687  * \param cause Asterisk hangup cause
00688  * \return OSP TC code
00689  */
00690 static OSPEFAILREASON asterisk2osp(
00691    int cause)
00692 {
00693    return (OSPEFAILREASON)cause;
00694 }
00695 
00696 /*!
00697  * \brief OSP Authentication function
00698  * \param provider OSP provider context name
00699  * \param transaction OSP transaction handle, output
00700  * \param source Source of inbound call
00701  * \param calling Calling number
00702  * \param called Called number
00703  * \param token OSP token, may be empty
00704  * \param timelimit Call duration limit, output
00705  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
00706  */
00707 static int osp_auth(
00708    const char* provider,
00709    int* transaction,
00710    const char* source,
00711    const char* calling,
00712    const char* called,
00713    const char* token,
00714    unsigned int* timelimit)
00715 {
00716    int res;
00717    struct osp_provider* p = NULL;
00718    char dest[OSP_NORSTR_SIZE];
00719 
00720    *transaction = OSP_INVALID_HANDLE;
00721    *timelimit = OSP_DEF_TIMELIMIT;
00722 
00723    if ((res = osp_get_provider(provider, &p)) <= 0) {
00724       ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
00725       return res;
00726    }
00727 
00728    switch (p->authpolicy) {
00729    case OSP_AUTH_NO:
00730       res = 1;
00731       break;
00732    case OSP_AUTH_EXCLUSIVE:
00733       if (ast_strlen_zero(token)) {
00734          res = 0;
00735       } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
00736          ast_debug(1, "OSP: Unable to generate transaction handle\n");
00737          *transaction = OSP_INVALID_HANDLE;
00738          res = 0;
00739       } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
00740          OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
00741       }
00742       break;
00743    case OSP_AUTH_YES:
00744    default:
00745       if (ast_strlen_zero(token)) {
00746          res = 1;
00747       } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
00748          ast_debug(1, "OSP: Unable to generate transaction handle\n");
00749          *transaction = OSP_INVALID_HANDLE;
00750          res = 0;
00751       } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
00752          OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
00753       }
00754       break;
00755    }
00756 
00757    return res;
00758 }
00759 
00760 /*!
00761  * \brief Create a UUID
00762  * \param uuid UUID buffer
00763  * \param buffersize UUID buffer size
00764  * \return 1 Created, -1 Error
00765  */
00766 static int osp_create_uuid(
00767    unsigned char* uuid,
00768    unsigned int* buffersize)
00769 {
00770    int i, res;
00771    long int* tmp;
00772 
00773    if (*buffersize >= OSP_UUID_SIZE) {
00774       tmp = (long int*)uuid;
00775       for (i = 0; i < OSP_UUID_SIZE / sizeof(long int); i++) {
00776          tmp[i] = ast_random();
00777       }
00778       *buffersize = OSP_UUID_SIZE;
00779       res = 1;
00780    } else {
00781       res = -1;
00782    }
00783 
00784    return res;
00785 }
00786 
00787 /*!
00788  * \brief UUID to string
00789  * \param uuid UUID
00790  * \param buffer String buffer
00791  * \param buffersize String buffer size
00792  * \return 1 Successed, -1 Error
00793  */
00794 static int osp_uuid2str(
00795    unsigned char* uuid,
00796    char* buffer,
00797    unsigned int buffersize)
00798 {
00799    int res;
00800 
00801    if (buffersize > OSP_UUIDSTR_SIZE) {
00802       snprintf(buffer, buffersize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
00803          uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
00804          uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
00805       res = 1;
00806    } else {
00807       res = -1;
00808    }
00809 
00810    return res;
00811 }
00812 
00813 /*!
00814  * \brief Create a call ID according to the type
00815  * \param type Call ID type
00816  * \param callid Call ID buffer
00817  * \return 1 Created, 0 Not create, -1 Error
00818  */
00819 static int osp_create_callid(
00820    unsigned int type,
00821    struct osp_callid* callid)
00822 {
00823    int res;
00824 
00825    callid->len = sizeof(callid->buf);
00826    switch (type) {
00827    case OSP_CALLID_H323:
00828       res = osp_create_uuid(callid->buf, &callid->len);
00829       break;
00830    case OSP_CALLID_SIP:
00831    case OSP_CALLID_IAX:
00832       res = 0;
00833    default:
00834       res = -1;
00835       break;
00836    }
00837 
00838    if ((res != 1) && (callid->len != 0)) {
00839       callid->buf[0] = '\0';
00840       callid->len = 0;
00841    }
00842 
00843    return res;
00844 }
00845 
00846 /*!
00847  * \brief OSP Lookup function
00848  * \param provider OSP provider context name
00849  * \param srcdev Source device of outbound call
00850  * \param calling Calling number
00851  * \param called Called number
00852  * \param callidtypes Call ID types
00853  * \param result Lookup results
00854  * \return 1 Found , 0 No route, -1 Error
00855  */
00856 static int osp_lookup(
00857    const char* provider,
00858    const char* srcdev,
00859    const char* calling,
00860    const char* called,
00861    unsigned int callidtypes,
00862    struct osp_result* result)
00863 {
00864    int res;
00865    struct osp_provider* p = NULL;
00866    char source[OSP_NORSTR_SIZE];
00867    char callingnum[OSP_NORSTR_SIZE];
00868    char callednum[OSP_NORSTR_SIZE];
00869    char destination[OSP_NORSTR_SIZE];
00870    unsigned int tokenlen;
00871    char token[OSP_TOKSTR_SIZE];
00872    char src[OSP_NORSTR_SIZE];
00873    char dev[OSP_NORSTR_SIZE];
00874    unsigned int i, type;
00875    struct osp_callid callid;
00876    unsigned int callidnum;
00877    OSPT_CALL_ID* callids[OSP_CALLID_MAXNUM];
00878    unsigned int dummy = 0;
00879    OSPEFAILREASON reason;
00880    int error;
00881 
00882    result->outhandle = OSP_INVALID_HANDLE;
00883    result->tech[0] = '\0';
00884    result->dest[0] = '\0';
00885    result->called[0] = '\0';
00886    result->calling[0] = '\0';
00887    result->token[0] = '\0';
00888    result->networkid[0] = '\0';
00889    result->numresults = 0;
00890    result->outtimelimit = OSP_DEF_TIMELIMIT;
00891 
00892    if ((res = osp_get_provider(provider, &p)) <= 0) {
00893       ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
00894       return res;
00895    }
00896 
00897    if ((res = osp_create_transaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
00898       ast_debug(1, "OSP: Unable to generate transaction handle\n");
00899       result->outhandle = OSP_INVALID_HANDLE;
00900       if (result->inhandle != OSP_INVALID_HANDLE) {
00901          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00902       }
00903       return -1;
00904    }
00905 
00906    callidnum = 0;
00907    callids[0] = NULL;
00908    for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
00909       type = 1 << i;
00910       if (callidtypes & type) {
00911          error = osp_create_callid(type, &callid);
00912          if (error == 1) {
00913             callids[callidnum] = OSPPCallIdNew(callid.len, callid.buf);
00914             callidnum++;
00915          }
00916       }
00917    }
00918 
00919    osp_convert_address(source, src, sizeof(src));
00920    osp_convert_address(srcdev, dev, sizeof(dev));
00921    result->numresults = OSP_DEF_DESTINATIONS;
00922    error = OSPPTransactionRequestAuthorisation(
00923       result->outhandle,
00924       src,
00925       dev,
00926       calling ? calling : "",
00927       OSPC_NFORMAT_E164,
00928       called,
00929       OSPC_NFORMAT_E164,
00930       NULL,
00931       callidnum,
00932       callids,
00933       NULL,
00934       &result->numresults,
00935       &dummy,
00936       NULL);
00937 
00938    for (i = 0; i < callidnum; i++) {
00939       OSPPCallIdDelete(&callids[i]);
00940    }
00941 
00942    if (error != OSPC_ERR_NO_ERROR) {
00943       ast_debug(1, "OSP: Unable to request authorization, error '%d'\n", error);
00944       result->numresults = 0;
00945       if (result->inhandle != OSP_INVALID_HANDLE) {
00946          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00947       }
00948       return -1;
00949    }
00950 
00951    if (!result->numresults) {
00952       ast_debug(1, "OSP: No more destination\n");
00953       if (result->inhandle != OSP_INVALID_HANDLE) {
00954          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00955       }
00956       return 0;
00957    }
00958 
00959    result->outcallid.len = sizeof(result->outcallid.buf);
00960    tokenlen = sizeof(token);
00961    error = OSPPTransactionGetFirstDestination(
00962       result->outhandle,
00963       0,
00964       NULL,
00965       NULL,
00966       &result->outtimelimit,
00967       &result->outcallid.len,
00968       result->outcallid.buf,
00969       sizeof(callednum),
00970       callednum,
00971       sizeof(callingnum),
00972       callingnum,
00973       sizeof(destination),
00974       destination,
00975       0,
00976       NULL,
00977       &tokenlen,
00978       token);
00979    if (error != OSPC_ERR_NO_ERROR) {
00980       ast_debug(1, "OSP: Unable to get first route, error '%d'\n", error);
00981       result->numresults = 0;
00982       result->outtimelimit = OSP_DEF_TIMELIMIT;
00983       if (result->inhandle != OSP_INVALID_HANDLE) {
00984          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00985       }
00986       return -1;
00987    }
00988 
00989    result->numresults--;
00990    result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
00991    ast_debug(1, "OSP: outtimelimit '%d'\n", result->outtimelimit);
00992    ast_debug(1, "OSP: called '%s'\n", callednum);
00993    ast_debug(1, "OSP: calling '%s'\n", callingnum);
00994    ast_debug(1, "OSP: destination '%s'\n", destination);
00995    ast_debug(1, "OSP: token size '%d'\n", tokenlen);
00996 
00997    if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
00998       return 1;
00999    }
01000 
01001    if (!result->numresults) {
01002       ast_debug(1, "OSP: No more destination\n");
01003       result->outtimelimit = OSP_DEF_TIMELIMIT;
01004       OSPPTransactionRecordFailure(result->outhandle, reason);
01005       if (result->inhandle != OSP_INVALID_HANDLE) {
01006          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01007       }
01008       return 0;
01009    }
01010 
01011    while(result->numresults) {
01012       result->outcallid.len = sizeof(result->outcallid.buf);
01013       tokenlen = sizeof(token);
01014       error = OSPPTransactionGetNextDestination(
01015          result->outhandle,
01016          reason,
01017          0,
01018          NULL,
01019          NULL,
01020          &result->outtimelimit,
01021          &result->outcallid.len,
01022          result->outcallid.buf,
01023          sizeof(callednum),
01024          callednum,
01025          sizeof(callingnum),
01026          callingnum,
01027          sizeof(destination),
01028          destination,
01029          0,
01030          NULL,
01031          &tokenlen,
01032          token);
01033       if (error == OSPC_ERR_NO_ERROR) {
01034          result->numresults--;
01035          result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
01036          ast_debug(1, "OSP: outtimelimit '%d'\n", result->outtimelimit);
01037          ast_debug(1, "OSP: called '%s'\n", callednum);
01038          ast_debug(1, "OSP: calling '%s'\n", callingnum);
01039          ast_debug(1, "OSP: destination '%s'\n", destination);
01040          ast_debug(1, "OSP: token size '%d'\n", tokenlen);
01041 
01042          if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
01043             break;
01044          } else if (!result->numresults) {
01045             ast_debug(1, "OSP: No more destination\n");
01046             OSPPTransactionRecordFailure(result->outhandle, reason);
01047             if (result->inhandle != OSP_INVALID_HANDLE) {
01048                OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01049             }
01050             res = 0;
01051             break;
01052          }
01053       } else {
01054          ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
01055          result->numresults = 0;
01056          result->outtimelimit = OSP_DEF_TIMELIMIT;
01057          if (result->inhandle != OSP_INVALID_HANDLE) {
01058             OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
01059          }
01060          res = -1;
01061          break;
01062       }
01063    }
01064    return res;
01065 }
01066 
01067 /*!
01068  * \brief OSP Lookup Next function
01069  * \param provider OSP provider name
01070  * \param cause Asterisk hangup cuase
01071  * \param result Lookup results, in/output
01072  * \return 1 Found , 0 No route, -1 Error
01073  */
01074 static int osp_next(
01075    const char* provider,
01076    int cause,
01077    struct osp_result* result)
01078 {
01079    int res;
01080    struct osp_provider* p = NULL;
01081    char callingnum[OSP_NORSTR_SIZE];
01082    char callednum[OSP_NORSTR_SIZE];
01083    char destination[OSP_NORSTR_SIZE];
01084    unsigned int tokenlen;
01085    char token[OSP_TOKSTR_SIZE];
01086    OSPEFAILREASON reason;
01087    int error;
01088 
01089    result->tech[0] = '\0';
01090    result->dest[0] = '\0';
01091    result->called[0] = '\0';
01092    result->calling[0] = '\0';
01093    result->token[0] = '\0';
01094    result->networkid[0] = '\0';
01095    result->outtimelimit = OSP_DEF_TIMELIMIT;
01096 
01097    if ((res = osp_get_provider(provider, &p)) <= 0) {
01098       ast_debug(1, "OSP: Unabe to find OSP provider '%s'\n", provider);
01099       return res;
01100    }
01101 
01102    if (result->outhandle == OSP_INVALID_HANDLE) {
01103       ast_debug(1, "OSP: Transaction handle undefined\n");
01104       result->numresults = 0;
01105       if (result->inhandle != OSP_INVALID_HANDLE) {
01106          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
01107       }
01108       return -1;
01109    }
01110 
01111    reason = asterisk2osp(cause);
01112 
01113    if (!result->numresults) {
01114       ast_debug(1, "OSP: No more destination\n");
01115       OSPPTransactionRecordFailure(result->outhandle, reason);
01116       if (result->inhandle != OSP_INVALID_HANDLE) {
01117          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01118       }
01119       return 0;
01120    }
01121 
01122    while(result->numresults) {
01123       result->outcallid.len = sizeof(result->outcallid.buf);
01124       tokenlen = sizeof(token);
01125       error = OSPPTransactionGetNextDestination(
01126          result->outhandle,
01127          reason,
01128          0,
01129          NULL,
01130          NULL,
01131          &result->outtimelimit,
01132          &result->outcallid.len,
01133          result->outcallid.buf,
01134          sizeof(callednum),
01135          callednum,
01136          sizeof(callingnum),
01137          callingnum,
01138          sizeof(destination),
01139          destination,
01140          0,
01141          NULL,
01142          &tokenlen,
01143          token);
01144       if (error == OSPC_ERR_NO_ERROR) {
01145          result->numresults--;
01146          result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
01147          ast_debug(1, "OSP: outtimelimit '%d'\n", result->outtimelimit);
01148          ast_debug(1, "OSP: called '%s'\n", callednum);
01149          ast_debug(1, "OSP: calling '%s'\n", callingnum);
01150          ast_debug(1, "OSP: destination '%s'\n", destination);
01151          ast_debug(1, "OSP: token size '%d'\n", tokenlen);
01152 
01153          if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
01154             res = 1;
01155             break;
01156          } else if (!result->numresults) {
01157             ast_debug(1, "OSP: No more destination\n");
01158             OSPPTransactionRecordFailure(result->outhandle, reason);
01159             if (result->inhandle != OSP_INVALID_HANDLE) {
01160                OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
01161             }
01162             res = 0;
01163             break;
01164          }
01165       } else {
01166          ast_debug(1, "OSP: Unable to get route, error '%d'\n", error);
01167          result->token[0] = '\0';
01168          result->numresults = 0;
01169          result->outtimelimit = OSP_DEF_TIMELIMIT;
01170          if (result->inhandle != OSP_INVALID_HANDLE) {
01171             OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
01172          }
01173          res = -1;
01174          break;
01175       }
01176    }
01177 
01178    return res;
01179 }
01180 
01181 /*!
01182  * \brief OSP Finish function
01183  * \param handle OSP in/outbound transaction handle
01184  * \param recorded If failure reason has been recorded
01185  * \param cause Asterisk hangup cause
01186  * \param start Call start time
01187  * \param connect Call connect time
01188  * \param end Call end time
01189  * \param release Who release first, 0 source, 1 destination
01190  * \return 1 Success, 0 Failed, -1 Error
01191  */
01192 static int osp_finish(
01193    int handle,
01194    int recorded,
01195    int cause,
01196    time_t start,
01197    time_t connect,
01198    time_t end,
01199    unsigned int release)
01200 {
01201    int res;
01202    OSPEFAILREASON reason;
01203    time_t alert = 0;
01204    unsigned isPddInfoPresent = 0;
01205    unsigned pdd = 0;
01206    unsigned int dummy = 0;
01207    int error;
01208 
01209    if (handle == OSP_INVALID_HANDLE) {
01210       return 0;
01211    }
01212 
01213    if (!recorded) {
01214       reason = asterisk2osp(cause);
01215       OSPPTransactionRecordFailure(handle, reason);
01216    }
01217 
01218    error = OSPPTransactionReportUsage(
01219       handle,
01220       difftime(end, connect),
01221       start,
01222       end,
01223       alert,
01224       connect,
01225       isPddInfoPresent,
01226       pdd,
01227       release,
01228       NULL,
01229       -1,
01230       -1,
01231       -1,
01232       -1,
01233       &dummy,
01234       NULL);
01235    if (error == OSPC_ERR_NO_ERROR) {
01236       ast_debug(1, "OSP: Usage reported\n");
01237       res = 1;
01238    } else {
01239       ast_debug(1, "OSP: Unable to report usage, error '%d'\n", error);
01240       res = -1;
01241    }
01242    OSPPTransactionDelete(handle);
01243 
01244    return res;
01245 }
01246 
01247 /* OSP Application APIs */
01248 
01249 /*!
01250  * \brief OSP Application OSPAuth
01251  * \param chan Channel
01252  * \param data Parameter
01253  * \return 0 Success, -1 Failed
01254  */
01255 static int ospauth_exec(
01256    struct ast_channel* chan,
01257    void* data)
01258 {
01259    int res;
01260    const char* provider = OSP_DEF_PROVIDER;
01261    struct varshead* headp;
01262    struct ast_var_t* current;
01263    const char* source = "";
01264    const char* token = "";
01265    int handle;
01266    unsigned int timelimit;
01267    char buffer[OSP_INTSTR_SIZE];
01268    const char* status;
01269    char* tmp;
01270 
01271    AST_DECLARE_APP_ARGS(args,
01272       AST_APP_ARG(provider);
01273       AST_APP_ARG(options);
01274    );
01275 
01276    if (!(tmp = ast_strdupa(data))) {
01277       ast_log(LOG_ERROR, "Out of memory\n");
01278       return -1;
01279    }
01280 
01281    AST_STANDARD_APP_ARGS(args, tmp);
01282 
01283    if (!ast_strlen_zero(args.provider)) {
01284       provider = args.provider;
01285    }
01286    ast_debug(1, "OSPAuth: provider '%s'\n", provider);
01287 
01288    headp = &chan->varshead;
01289    AST_LIST_TRAVERSE(headp, current, entries) {
01290       if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
01291          source = ast_var_value(current);
01292       } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
01293          token = ast_var_value(current);
01294       }
01295    }
01296 
01297    ast_debug(1, "OSPAuth: source '%s'\n", source);
01298    ast_debug(1, "OSPAuth: token size '%zd'\n", strlen(token));
01299 
01300    if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
01301       status = AST_OSP_SUCCESS;
01302    } else {
01303       timelimit = OSP_DEF_TIMELIMIT;
01304       if (!res) {
01305          status = AST_OSP_FAILED;
01306       } else {
01307          status = AST_OSP_ERROR;
01308       }
01309    }
01310 
01311    snprintf(buffer, sizeof(buffer), "%d", handle);
01312    pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
01313    ast_debug(1, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
01314    snprintf(buffer, sizeof(buffer), "%d", timelimit);
01315    pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
01316    ast_debug(1, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
01317    pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
01318    ast_debug(1, "OSPAuth: %s\n", status);
01319 
01320    if(res <= 0) {
01321       res = -1;
01322    } else {
01323       res = 0;
01324    }
01325 
01326    return res;
01327 }
01328 
01329 /*!
01330  * \brief OSP Application OSPLookup
01331  * \param chan Channel
01332  * \param data Parameter
01333  * \return 0 Success, -1 Failed
01334  */
01335 static int osplookup_exec(
01336    struct ast_channel* chan,
01337    void* data)
01338 {
01339    int res, cres;
01340    const char* provider = OSP_DEF_PROVIDER;
01341    struct varshead* headp;
01342    struct ast_var_t* current;
01343    const char* srcdev = "";
01344    const char* snetid = "";
01345    char buffer[OSP_TOKSTR_SIZE];
01346    unsigned int callidtypes = OSP_CALLID_UNDEFINED;
01347    struct osp_result result;
01348    const char* status;
01349    char* tmp;
01350 
01351    AST_DECLARE_APP_ARGS(args,
01352       AST_APP_ARG(exten);
01353       AST_APP_ARG(provider);
01354       AST_APP_ARG(options);
01355    );
01356 
01357    if (ast_strlen_zero(data)) {
01358       ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
01359       return -1;
01360    }
01361 
01362    if (!(tmp = ast_strdupa(data))) {
01363       ast_log(LOG_ERROR, "Out of memory\n");
01364       return -1;
01365    }
01366 
01367    AST_STANDARD_APP_ARGS(args, tmp);
01368 
01369    ast_debug(1, "OSPLookup: exten '%s'\n", args.exten);
01370 
01371    if (!ast_strlen_zero(args.provider)) {
01372       provider = args.provider;
01373    }
01374    ast_debug(1, "OSPlookup: provider '%s'\n", provider);
01375 
01376    if (args.options) {
01377       if (strchr(args.options, 'h')) {
01378          callidtypes |= OSP_CALLID_H323;
01379       }
01380       if (strchr(args.options, 's')) {
01381          callidtypes |= OSP_CALLID_SIP;
01382       }
01383       if (strchr(args.options, 'i')) {
01384          callidtypes |= OSP_CALLID_IAX;
01385       }
01386    }
01387    ast_debug(1, "OSPLookup: call id types '%d'\n", callidtypes);
01388 
01389    result.inhandle = OSP_INVALID_HANDLE;
01390    result.intimelimit = OSP_DEF_TIMELIMIT;
01391 
01392    headp = &chan->varshead;
01393    AST_LIST_TRAVERSE(headp, current, entries) {
01394       if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
01395          if (sscanf(ast_var_value(current), "%30d", &result.inhandle) != 1) {
01396             result.inhandle = OSP_INVALID_HANDLE;
01397          }
01398       } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
01399          if (sscanf(ast_var_value(current), "%30d", &result.intimelimit) != 1) {
01400             result.intimelimit = OSP_DEF_TIMELIMIT;
01401          }
01402       } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
01403          snetid = ast_var_value(current);
01404       } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
01405          srcdev = ast_var_value(current);
01406       }
01407    }
01408    ast_debug(1, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
01409    ast_debug(1, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
01410    ast_debug(1, "OSPLookup: OSPINNETWORKID '%s'\n", snetid);
01411    ast_debug(1, "OSPLookup: source device '%s'\n", srcdev);
01412 
01413    if ((cres = ast_autoservice_start(chan)) < 0) {
01414       return -1;
01415    }
01416 
01417    if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, callidtypes, &result)) > 0) {
01418       status = AST_OSP_SUCCESS;
01419    } else {
01420       result.tech[0] = '\0';
01421       result.dest[0] = '\0';
01422       result.called[0] = '\0';
01423       result.calling[0] = '\0';
01424       result.token[0] = '\0';
01425       result.networkid[0] = '\0';
01426       result.numresults = 0;
01427       result.outtimelimit = OSP_DEF_TIMELIMIT;
01428       result.outcallid.buf[0] = '\0';
01429       result.outcallid.len = 0;
01430       if (!res) {
01431          status = AST_OSP_FAILED;
01432       } else {
01433          status = AST_OSP_ERROR;
01434       }
01435    }
01436 
01437    snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
01438    pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
01439    ast_debug(1, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
01440    pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
01441    ast_debug(1, "OSPLookup: OSPTECH '%s'\n", result.tech);
01442    pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
01443    ast_debug(1, "OSPLookup: OSPDEST '%s'\n", result.dest);
01444    pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
01445    ast_debug(1, "OSPLookup: OSPCALLED '%s'\n", result.called);
01446    pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
01447    ast_debug(1, "OSPLookup: OSPCALLING '%s'\n", result.calling);
01448    pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
01449    ast_debug(1, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
01450    snprintf(buffer, sizeof(buffer), "%d", result.numresults);
01451    pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
01452    ast_debug(1, "OSPLookup: OSPRESULTS '%s'\n", buffer);
01453    snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
01454    pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
01455    ast_debug(1, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
01456    snprintf(buffer, sizeof(buffer), "%d", callidtypes);
01457    pbx_builtin_setvar_helper(chan, "OSPOUTCALLIDTYPES", buffer);
01458    ast_debug(1, "OSPLookup: OSPOUTCALLIDTYPES '%s'\n", buffer);
01459    pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
01460    ast_debug(1, "OSPLookup: %s\n", status);
01461 
01462    if (!strcasecmp(result.tech, OSP_TECH_H323)) {
01463       if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
01464          osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
01465       } else {
01466          buffer[0] = '\0';
01467       }
01468       pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
01469       snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
01470       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
01471    } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
01472       snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
01473       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
01474       if (!ast_strlen_zero(result.token)) {
01475          snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
01476          pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
01477          ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
01478       }
01479    } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
01480       snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
01481       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
01482    }
01483 
01484    if ((cres = ast_autoservice_stop(chan)) < 0) {
01485       return -1;
01486    }
01487 
01488    if(res <= 0) {
01489       res = -1;
01490    } else {
01491       res = 0;
01492    }
01493 
01494    return res;
01495 }
01496 
01497 /*!
01498  * \brief OSP Application OSPNext
01499  * \param chan Channel
01500  * \param data Parameter
01501  * \return 0 Success, -1 Failed
01502  */
01503 static int ospnext_exec(
01504    struct ast_channel* chan,
01505    void* data)
01506 {
01507    int res;
01508    const char* provider = OSP_DEF_PROVIDER;
01509    int cause = 0;
01510    struct varshead* headp;
01511    struct ast_var_t* current;
01512    struct osp_result result;
01513    char buffer[OSP_TOKSTR_SIZE];
01514    unsigned int callidtypes = OSP_CALLID_UNDEFINED;
01515    const char* status;
01516    char* tmp;
01517 
01518    AST_DECLARE_APP_ARGS(args,
01519       AST_APP_ARG(cause);
01520       AST_APP_ARG(provider);
01521       AST_APP_ARG(options);
01522    );
01523 
01524    if (ast_strlen_zero(data)) {
01525       ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|provider[|options]])\n");
01526       return -1;
01527    }
01528 
01529    if (!(tmp = ast_strdupa(data))) {
01530       ast_log(LOG_ERROR, "Out of memory\n");
01531       return -1;
01532    }
01533 
01534    AST_STANDARD_APP_ARGS(args, tmp);
01535 
01536    if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
01537       cause = 0;
01538    }
01539    ast_debug(1, "OSPNext: cause '%d'\n", cause);
01540 
01541    if (!ast_strlen_zero(args.provider)) {
01542       provider = args.provider;
01543    }
01544    ast_debug(1, "OSPlookup: provider '%s'\n", provider);
01545 
01546    result.inhandle = OSP_INVALID_HANDLE;
01547    result.outhandle = OSP_INVALID_HANDLE;
01548    result.intimelimit = OSP_DEF_TIMELIMIT;
01549    result.numresults = 0;
01550 
01551    headp = &chan->varshead;
01552    AST_LIST_TRAVERSE(headp, current, entries) {
01553       if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
01554          if (sscanf(ast_var_value(current), "%30d", &result.inhandle) != 1) {
01555             result.inhandle = OSP_INVALID_HANDLE;
01556          }
01557       } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
01558          if (sscanf(ast_var_value(current), "%30d", &result.outhandle) != 1) {
01559             result.outhandle = OSP_INVALID_HANDLE;
01560          }
01561       } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
01562          if (sscanf(ast_var_value(current), "%30d", &result.intimelimit) != 1) {
01563             result.intimelimit = OSP_DEF_TIMELIMIT;
01564          }
01565       } else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
01566          if (sscanf(ast_var_value(current), "%30d", &callidtypes) != 1) {
01567             callidtypes = OSP_CALLID_UNDEFINED;
01568          }
01569       } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
01570          if (sscanf(ast_var_value(current), "%30d", &result.numresults) != 1) {
01571             result.numresults = 0;
01572          }
01573       }
01574    }
01575    ast_debug(1, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
01576    ast_debug(1, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
01577    ast_debug(1, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
01578    ast_debug(1, "OSPNext: OSPOUTCALLIDTYPES '%d'\n", callidtypes);
01579    ast_debug(1, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
01580 
01581    if ((res = osp_next(provider, cause, &result)) > 0) {
01582       status = AST_OSP_SUCCESS;
01583    } else {
01584       result.tech[0] = '\0';
01585       result.dest[0] = '\0';
01586       result.called[0] = '\0';
01587       result.calling[0] = '\0';
01588       result.token[0] = '\0';
01589       result.networkid[0] = '\0';
01590       result.numresults = 0;
01591       result.outtimelimit = OSP_DEF_TIMELIMIT;
01592       result.outcallid.buf[0] = '\0';
01593       result.outcallid.len = 0;
01594       if (!res) {
01595          status = AST_OSP_FAILED;
01596       } else {
01597          status = AST_OSP_ERROR;
01598       }
01599    }
01600 
01601    pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
01602    ast_debug(1, "OSPNext: OSPTECH '%s'\n", result.tech);
01603    pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
01604    ast_debug(1, "OSPNext: OSPDEST '%s'\n", result.dest);
01605    pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
01606    ast_debug(1, "OSPNext: OSPCALLED'%s'\n", result.called);
01607    pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
01608    ast_debug(1, "OSPNext: OSPCALLING '%s'\n", result.calling);
01609    pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
01610    ast_debug(1, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
01611    snprintf(buffer, sizeof(buffer), "%d", result.numresults);
01612    pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
01613    ast_debug(1, "OSPNext: OSPRESULTS '%s'\n", buffer);
01614    snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
01615    pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
01616    ast_debug(1, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
01617    pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
01618    ast_debug(1, "OSPNext: %s\n", status);
01619 
01620    if (!strcasecmp(result.tech, OSP_TECH_H323)) {
01621       if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
01622          osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
01623       } else {
01624          buffer[0] = '\0';
01625       }
01626       pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
01627       snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
01628       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
01629    } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
01630       snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
01631       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
01632       if (!ast_strlen_zero(result.token)) {
01633          snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
01634          pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
01635          ast_debug(1, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
01636       }
01637    } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
01638       snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
01639       pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
01640    }
01641 
01642    if(res <= 0) {
01643       res = -1;
01644    } else {
01645       res = 0;
01646    }
01647 
01648    return res;
01649 }
01650 
01651 /*!
01652  * \brief OSP Application OSPFinish
01653  * \param chan Channel
01654  * \param data Parameter
01655  * \return 0 Success, -1 Failed
01656  */
01657 static int ospfinished_exec(
01658    struct ast_channel* chan,
01659    void* data)
01660 {
01661    int res = 1;
01662    int cause = 0;
01663    struct varshead* headp;
01664    struct ast_var_t* current;
01665    int inhandle = OSP_INVALID_HANDLE;
01666    int outhandle = OSP_INVALID_HANDLE;
01667    int recorded = 0;
01668    time_t start, connect, end;
01669    unsigned int release;
01670    char buffer[OSP_INTSTR_SIZE];
01671    const char* status;
01672    char* tmp;
01673 
01674    AST_DECLARE_APP_ARGS(args,
01675       AST_APP_ARG(cause);
01676       AST_APP_ARG(options);
01677    );
01678 
01679    if (!(tmp = ast_strdupa(data))) {
01680       ast_log(LOG_ERROR, "Out of memory\n");
01681       return -1;
01682    }
01683 
01684    AST_STANDARD_APP_ARGS(args, tmp);
01685 
01686    headp = &chan->varshead;
01687    AST_LIST_TRAVERSE(headp, current, entries) {
01688       if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
01689          if (sscanf(ast_var_value(current), "%30d", &inhandle) != 1) {
01690             inhandle = OSP_INVALID_HANDLE;
01691          }
01692       } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
01693          if (sscanf(ast_var_value(current), "%30d", &outhandle) != 1) {
01694             outhandle = OSP_INVALID_HANDLE;
01695          }
01696       } else if (!recorded &&
01697          (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
01698          !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
01699          !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
01700       {
01701          if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
01702             recorded = 1;
01703          }
01704       }
01705    }
01706    ast_debug(1, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
01707    ast_debug(1, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
01708    ast_debug(1, "OSPFinish: recorded '%d'\n", recorded);
01709 
01710    if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%30d", &cause) != 1) {
01711       cause = 0;
01712    }
01713    ast_debug(1, "OSPFinish: cause '%d'\n", cause);
01714 
01715    if (chan->cdr) {
01716       start = chan->cdr->start.tv_sec;
01717       connect = chan->cdr->answer.tv_sec;
01718       if (connect) {
01719          end = time(NULL);
01720       } else {
01721          end = connect;
01722       }
01723    } else {
01724       start = 0;
01725       connect = 0;
01726       end = 0;
01727    }
01728    ast_debug(1, "OSPFinish: start '%ld'\n", start);
01729    ast_debug(1, "OSPFinish: connect '%ld'\n", connect);
01730    ast_debug(1, "OSPFinish: end '%ld'\n", end);
01731 
01732    release = ast_check_hangup(chan) ? 0 : 1;
01733 
01734    if (osp_finish(outhandle, recorded, cause, start, connect, end, release) <= 0) {
01735       ast_debug(1, "OSPFinish: Unable to report usage for outbound call\n");
01736    }
01737    switch (cause) {
01738    case AST_CAUSE_NORMAL_CLEARING:
01739       break;
01740    default:
01741       cause = AST_CAUSE_NO_ROUTE_DESTINATION;
01742       break;
01743    }
01744    if (osp_finish(inhandle, recorded, cause, start, connect, end, release) <= 0) {
01745       ast_debug(1, "OSPFinish: Unable to report usage for inbound call\n");
01746    }
01747    snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
01748    pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
01749    pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
01750 
01751    if (res > 0) {
01752       status = AST_OSP_SUCCESS;
01753    } else if (!res) {
01754       status = AST_OSP_FAILED;
01755    } else {
01756       status = AST_OSP_ERROR;
01757    }
01758    pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
01759 
01760    if(!res) {
01761       res = -1;
01762    } else {
01763       res = 0;
01764    }
01765 
01766    return res;
01767 }
01768 
01769 /* OSP Module APIs */
01770 
01771 static int osp_unload(void);
01772 static int osp_load(int reload)
01773 {
01774    const char* t;
01775    unsigned int v;
01776    struct ast_config* cfg;
01777    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01778    int error = OSPC_ERR_NO_ERROR;
01779 
01780    if ((cfg = ast_config_load(OSP_CONFIG_FILE, config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
01781       return 0;
01782 
01783    if (cfg) {
01784       if (reload)
01785          osp_unload();
01786 
01787       t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
01788       if (t && ast_true(t)) {
01789          if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
01790             ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
01791             OSPPInit(0);
01792          } else {
01793             osp_hardware = 1;
01794          }
01795       } else {
01796          OSPPInit(0);
01797       }
01798       ast_debug(1, "OSP: osp_hardware '%d'\n", osp_hardware);
01799 
01800       t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
01801       if (t) {
01802          if ((sscanf(t, "%30d", &v) == 1) &&
01803             ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH)))
01804          {
01805             osp_tokenformat = v;
01806          } else {
01807             ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
01808                TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
01809          }
01810       }
01811       ast_debug(1, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
01812 
01813       t = ast_category_browse(cfg, NULL);
01814       while(t) {
01815          if (strcasecmp(t, OSP_GENERAL_CAT)) {
01816             osp_create_provider(cfg, t);
01817          }
01818          t = ast_category_browse(cfg, t);
01819       }
01820 
01821       osp_initialized = 1;
01822 
01823       ast_config_destroy(cfg);
01824    } else {
01825       ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
01826       return 0;
01827    }
01828    ast_debug(1, "OSP: osp_initialized '%d'\n", osp_initialized);
01829 
01830    return 1;
01831 }
01832 
01833 static int osp_unload(void)
01834 {
01835    struct osp_provider* p;
01836    struct osp_provider* next;
01837 
01838    if (osp_initialized) {
01839       ast_mutex_lock(&osplock);
01840       p = ospproviders;
01841       while(p) {
01842          next = p->next;
01843          OSPPProviderDelete(p->handle, 0);
01844          ast_free(p);
01845          p = next;
01846       }
01847       ospproviders = NULL;
01848       ast_mutex_unlock(&osplock);
01849 
01850       OSPPCleanup();
01851 
01852       osp_tokenformat = TOKEN_ALGO_SIGNED;
01853       osp_hardware = 0;
01854       osp_initialized = 0;
01855    }
01856    return 0;
01857 }
01858 
01859 static char *handle_cli_osp_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01860 {
01861    int i;
01862    int found = 0;
01863    struct osp_provider* p;
01864    const char* provider = NULL;
01865    const char* tokenalgo;
01866 
01867    switch (cmd) {
01868    case CLI_INIT:
01869       e->command = "osp show";
01870       e->usage =
01871          "Usage: osp show\n"
01872          "       Displays information on Open Settlement Protocol support\n";
01873       return NULL;
01874    case CLI_GENERATE:
01875       return NULL;
01876    }
01877 
01878    if ((a->argc < 2) || (a->argc > 3))
01879       return CLI_SHOWUSAGE;
01880    if (a->argc > 2) 
01881       provider = a->argv[2];
01882    if (!provider) {
01883       switch (osp_tokenformat) {
01884       case TOKEN_ALGO_BOTH:
01885          tokenalgo = "Both";
01886          break;
01887       case TOKEN_ALGO_UNSIGNED:
01888          tokenalgo = "Unsigned";
01889          break;
01890       case TOKEN_ALGO_SIGNED:
01891       default:
01892          tokenalgo = "Signed";
01893          break;
01894       }
01895       ast_cli(a->fd, "OSP: %s %s %s\n",
01896          osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
01897    }
01898 
01899    ast_mutex_lock(&osplock);
01900    p = ospproviders;
01901    while(p) {
01902       if (!provider || !strcasecmp(p->name, provider)) {
01903          if (found) {
01904             ast_cli(a->fd, "\n");
01905          }
01906          ast_cli(a->fd, " == OSP Provider '%s' == \n", p->name);
01907          ast_cli(a->fd, "Local Private Key: %s\n", p->privatekey);
01908          ast_cli(a->fd, "Local Certificate: %s\n", p->localcert);
01909          for (i = 0; i < p->cacount; i++) {
01910             ast_cli(a->fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
01911          }
01912          for (i = 0; i < p->spcount; i++) {
01913             ast_cli(a->fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
01914          }
01915          ast_cli(a->fd, "Max Connections:   %d\n", p->maxconnections);
01916          ast_cli(a->fd, "Retry Delay:       %d seconds\n", p->retrydelay);
01917          ast_cli(a->fd, "Retry Limit:       %d\n", p->retrylimit);
01918          ast_cli(a->fd, "Timeout:           %d milliseconds\n", p->timeout);
01919          ast_cli(a->fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
01920          ast_cli(a->fd, "Auth Policy        %d\n", p->authpolicy);
01921          ast_cli(a->fd, "Default protocol   %s\n", p->defaultprotocol);
01922          ast_cli(a->fd, "OSP Handle:        %d\n", p->handle);
01923          found++;
01924       }
01925       p = p->next;
01926    }
01927    ast_mutex_unlock(&osplock);
01928 
01929    if (!found) {
01930       if (provider) {
01931          ast_cli(a->fd, "Unable to find OSP provider '%s'\n", provider);
01932       } else {
01933          ast_cli(a->fd, "No OSP providers configured\n");
01934       }
01935    }
01936    return CLI_SUCCESS;
01937 }
01938 
01939 static const char* app1= "OSPAuth";
01940 static const char* synopsis1 = "OSP authentication";
01941 static const char* descrip1 =
01942 "  OSPAuth([provider[,options]]):  Authenticate a SIP INVITE by OSP and sets\n"
01943 "the variables:\n"
01944 " ${OSPINHANDLE}:  The inbound call transaction handle\n"
01945 " ${OSPINTIMELIMIT}:  The inbound call duration limit in seconds\n"
01946 "\n"
01947 "This application sets the following channel variable upon completion:\n"
01948 "  OSPAUTHSTATUS  The status of the OSP Auth attempt as a text string, one of\n"
01949 "     SUCCESS | FAILED | ERROR\n";
01950 
01951 static const char* app2= "OSPLookup";
01952 static const char* synopsis2 = "Lookup destination by OSP";
01953 static const char* descrip2 =
01954 "  OSPLookup(exten[,provider[,options]]):  Looks up an extension via OSP and sets\n"
01955 "the variables, where 'n' is the number of the result beginning with 1:\n"
01956 " ${OSPOUTHANDLE}:  The OSP Handle for anything remaining\n"
01957 " ${OSPTECH}:  The technology to use for the call\n"
01958 " ${OSPDEST}:  The destination to use for the call\n"
01959 " ${OSPCALLED}:  The called number to use for the call\n"
01960 " ${OSPCALLING}:  The calling number to use for the call\n"
01961 " ${OSPDIALSTR}:  The dial command string\n"
01962 " ${OSPOUTTOKEN}:  The actual OSP token as a string\n"
01963 " ${OSPOUTTIMELIMIT}:  The outbound call duration limit in seconds\n"
01964 " ${OSPOUTCALLIDTYPES}:  The outbound call id types\n"
01965 " ${OSPOUTCALLID}:  The outbound call id\n"
01966 " ${OSPRESULTS}:  The number of OSP results total remaining\n"
01967 "\n"
01968 "The option string may contain the following character:\n"
01969 "  'h' -- generate H323 call id for the outbound call\n"
01970 "  's' -- generate SIP call id for the outbound call. Have not been implemented\n"
01971 "  'i' -- generate IAX call id for the outbound call. Have not been implemented\n"
01972 "This application sets the following channel variable upon completion:\n"
01973 "  OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
01974 "     SUCCESS | FAILED | ERROR\n";
01975 
01976 static const char* app3 = "OSPNext";
01977 static const char* synopsis3 = "Lookup next destination by OSP";
01978 static const char* descrip3 =
01979 "  OSPNext(cause[,provider[,options]]):  Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
01980 "See OSPLookup for more information\n"
01981 "\n"
01982 "This application sets the following channel variable upon completion:\n"
01983 "  OSPNEXTSTATUS The status of the OSP Next attempt as a text string, one of\n"
01984 "     SUCCESS | FAILED | ERROR\n";
01985 
01986 static const char* app4 = "OSPFinish";
01987 static const char* synopsis4 = "Record OSP entry";
01988 static const char* descrip4 =
01989 "  OSPFinish([status[,options]]):  Records call state for ${OSPINHANDLE}, according to\n"
01990 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
01991 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
01992 "\n"
01993 "This application sets the following channel variable upon completion:\n"
01994 "  OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
01995 "     SUCCESS | FAILED | ERROR \n";
01996 
01997 static struct ast_cli_entry cli_osp[] = {
01998    AST_CLI_DEFINE(handle_cli_osp_show, "Displays OSF information")
01999 };
02000 
02001 static int load_module(void)
02002 {
02003    int res;
02004 
02005    if (!osp_load(0))
02006       return AST_MODULE_LOAD_DECLINE;
02007 
02008    ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
02009    res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
02010    res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
02011    res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
02012    res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
02013 
02014    return res;
02015 }
02016 
02017 static int unload_module(void)
02018 {
02019    int res;
02020 
02021    res = ast_unregister_application(app4);
02022    res |= ast_unregister_application(app3);
02023    res |= ast_unregister_application(app2);
02024    res |= ast_unregister_application(app1);
02025    ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
02026    osp_unload();
02027 
02028    return res;
02029 }
02030 
02031 static int reload(void)
02032 {
02033    osp_load(1);
02034 
02035    return 0;
02036 }
02037 
02038 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
02039    .load = load_module,
02040    .unload = unload_module,
02041    .reload = reload,
02042 );

Generated on Wed Oct 28 11:50:53 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6