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

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