Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:55 2009

## Asterisk developer's documentation

# res_osp.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2005, 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 /*! \file
    00020  *
    00021  * \brief Provide Open Settlement Protocol capability
    00022  *
    00023  * \arg See also: \ref chan_sip.c
    00024  */
    00025
    00026 #include <sys/types.h>
    00027 #include <osp.h>
    00028 #include <openssl/err.h>
    00029 #include <stdio.h>
    00030 #include <dirent.h>
    00031 #include <string.h>
    00032 #include <errno.h>
    00033 #include <unistd.h>
    00034 #include <fcntl.h>
    00035 #include <openssl/bio.h>
    00036 #include <openssl/pem.h>
    00037 #include <openssl/evp.h>
    00038
    00039 #include "asterisk.h"
    00040
    00041 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211526 $")
    00042
    00043 #include "asterisk/file.h"
    00044 #include "asterisk/channel.h"
    00045 #include "asterisk/logger.h"
    00046 #include "asterisk/say.h"
    00047 #include "asterisk/module.h"
    00048 #include "asterisk/options.h"
    00049 #include "asterisk/crypto.h"
    00050 #include "asterisk/md5.h"
    00051 #include "asterisk/cli.h"
    00052 #include "asterisk/io.h"
    00053 #include "asterisk/lock.h"
    00054 #include "asterisk/astosp.h"
    00055 #include "asterisk/config.h"
    00056 #include "asterisk/utils.h"
    00057 #include "asterisk/lock.h"
    00058 #include "asterisk/causes.h"
    00059 #include "asterisk/callerid.h"
    00060 #include "asterisk/pbx.h"
    00061
    00062 #define MAX_CERTS 10
    00063 #define MAX_SERVICEPOINTS 10
    00064 #define OSP_MAX 256
    00065
    00066 #define OSP_DEFAULT_MAX_CONNECTIONS 20
    00067 #define OSP_DEFAULT_RETRY_DELAY     0
    00068 #define OSP_DEFAULT_RETRY_LIMIT     2
    00069 #define OSP_DEFAULT_TIMEOUT         500
    00070
    00071 static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len);
    00072 static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len);
    00073
    00074 AST_MUTEX_DEFINE_STATIC(osplock);
    00075
    00076 static int initialized = 0;
    00077 static int hardware = 0;
    00078 static unsigned tokenformat = TOKEN_ALGO_SIGNED;
    00079
    00080 struct osp_provider {
    00081    char name[OSP_MAX];
    00082    char localpvtkey[OSP_MAX];
    00083    char localcert[OSP_MAX];
    00084    char cacerts[MAX_CERTS][OSP_MAX];
    00085    int cacount;
    00086    char servicepoints[MAX_SERVICEPOINTS][OSP_MAX];
    00087    char source[OSP_MAX];
    00088    int spcount;
    00089    int dead;
    00090    int maxconnections;
    00091    int retrydelay;
    00092    int retrylimit;
    00093    int timeout;
    00094    OSPTPROVHANDLE handle;
    00095    struct osp_provider *next;
    00096 };
    00097 static struct osp_provider *providers;
    00098
    00099 static int osp_build(struct ast_config *cfg, char *cat)
    00100 {
    00101    OSPTCERT TheAuthCert[MAX_CERTS];
    00102    unsigned char Reqbuf[4096],LocalBuf[4096],AuthBuf[MAX_CERTS][4096];
    00103    struct ast_variable *v;
    00104    struct osp_provider *osp;
    00105    int x,length,errorcode=0;
    00106    int mallocd=0,i;
    00107    char *cacerts[MAX_CERTS];
    00108    const char *servicepoints[MAX_SERVICEPOINTS];
    00109    OSPTPRIVATEKEY privatekey;
    00110    OSPTCERT localcert;
    00111    OSPTCERT *authCerts[MAX_CERTS];
    00112
    00113
    00114
    00115    ast_mutex_lock(&osplock);
    00116    osp = providers;
    00117    while(osp) {
    00118       if (!strcasecmp(osp->name, cat))
    00119          break;
    00120       osp = osp->next;
    00121    }
    00122    ast_mutex_unlock(&osplock);
    00123    if (!osp) {
    00124       mallocd = 1;
    00125       osp = malloc(sizeof(struct osp_provider));
    00126       if (!osp) {
    00127          ast_log(LOG_WARNING, "Out of memory!\n");
    00128          return -1;
    00129       }
    00130       memset(osp, 0, sizeof(struct osp_provider));
    00131       osp->handle = -1;
    00132    }
    00133    ast_copy_string(osp->name, cat, sizeof(osp->name));
    00134    snprintf(osp->localpvtkey, sizeof(osp->localpvtkey) ,"%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, cat);
    00135    snprintf(osp->localcert, sizeof(osp->localpvtkey), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, cat);
    00136    osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS;
    00137    osp->retrydelay = OSP_DEFAULT_RETRY_DELAY;
    00138    osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT;
    00139    osp->timeout = OSP_DEFAULT_TIMEOUT;
    00140    osp->source[0] = '\0';
    00141    ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat);
    00142    v = ast_variable_browse(cfg, cat);
    00143    while(v) {
    00144       if (!strcasecmp(v->name, "privatekey")) {
    00145          if (v->value[0] == '/')
    00146             ast_copy_string(osp->localpvtkey, v->value, sizeof(osp->localpvtkey));
    00147          else
    00148             snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), "%s/%s", ast_config_AST_KEY_DIR , v->value);
    00149       } else if (!strcasecmp(v->name, "localcert")) {
    00150          if (v->value[0] == '/')
    00151             ast_copy_string(osp->localcert, v->value, sizeof(osp->localcert));
    00152          else
    00153             snprintf(osp->localcert, sizeof(osp->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
    00154       } else if (!strcasecmp(v->name, "cacert")) {
    00155          if (osp->cacount < MAX_CERTS) {
    00156             if (v->value[0] == '/')
    00157                ast_copy_string(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0]));
    00158             else
    00159                snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
    00160             osp->cacount++;
    00161          } else
    00162             ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno);
    00163       } else if (!strcasecmp(v->name, "servicepoint")) {
    00164          if (osp->spcount < MAX_SERVICEPOINTS) {
    00165             ast_copy_string(osp->servicepoints[osp->spcount], v->value, sizeof(osp->servicepoints[0]));
    00166             osp->spcount++;
    00167          } else
    00168             ast_log(LOG_WARNING, "Too many Service points at line %d\n", v->lineno);
    00169       } else if (!strcasecmp(v->name, "maxconnections")) {
    00170          if ((sscanf(v->value, "%30d", &x) == 1) && (x > 0) && (x <= 1000)) {
    00171             osp->maxconnections = x;
    00172          } else
    00173             ast_log(LOG_WARNING, "maxconnections should be an integer from 1 to 1000, not '%s' at line %d\n", v->value, v->lineno);
    00174       } else if (!strcasecmp(v->name, "retrydelay")) {
    00175          if ((sscanf(v->value, "%30d", &x) == 1) && (x >= 0) && (x <= 10)) {
    00176             osp->retrydelay = x;
    00177          } else
    00178             ast_log(LOG_WARNING, "retrydelay should be an integer from 0 to 10, not '%s' at line %d\n", v->value, v->lineno);
    00179       } else if (!strcasecmp(v->name, "retrylimit")) {
    00180          if ((sscanf(v->value, "%30d", &x) == 1) && (x >= 0) && (x <= 100)) {
    00181             osp->retrylimit = x;
    00182          } else
    00183             ast_log(LOG_WARNING, "retrylimit should be an integer from 0 to 100, not '%s' at line %d\n", v->value, v->lineno);
    00184       } else if (!strcasecmp(v->name, "timeout")) {
    00185          if ((sscanf(v->value, "%30d", &x) == 1) && (x >= 200) && (x <= 10000)) {
    00186             osp->timeout = x;
    00187          } else
    00188             ast_log(LOG_WARNING, "timeout should be an integer from 200 to 10000, not '%s' at line %d\n", v->value, v->lineno);
    00189       } else if (!strcasecmp(v->name, "source")) {
    00190          ast_copy_string(osp->source, v->value, sizeof(osp->source));
    00191       }
    00192       v = v->next;
    00193    }
    00194    if (osp->cacount < 1) {
    00195       snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, cat);
    00196       osp->cacount++;
    00197    }
    00198    for (x=0;x<osp->cacount;x++)
    00199       cacerts[x] = osp->cacerts[x];
    00200    for (x=0;x<osp->spcount;x++)
    00201       servicepoints[x] = osp->servicepoints[x];
    00202
    00203    ast_mutex_lock(&osplock);
    00204    osp->dead = 0;
    00205    if (osp->handle > -1) {
    00206       ast_log(LOG_DEBUG, "Deleting old handle for '%s'\n", osp->name);
    00207       OSPPProviderDelete(osp->handle, 0);
    00208    }
    00209
    00210
    00211     length = 0;
    00212    ast_log(LOG_DEBUG, "Loading private key for '%s' (%s)\n", osp->name, osp->localpvtkey);
    00213     errorcode = loadPemPrivateKey(osp->localpvtkey,Reqbuf,&length);
    00214     if (errorcode == 0)
    00215     {
    00216         privatekey.PrivateKeyData = Reqbuf;
    00217         privatekey.PrivateKeyLength = length;
    00218     }
    00219     else
    00220     {
    00221          return -1;
    00222     }
    00223
    00224     length = 0;
    00225    ast_log(LOG_DEBUG, "Loading local cert for '%s' (%s)\n", osp->name, osp->localcert);
    00226     errorcode = loadPemCert(osp->localcert,LocalBuf,&length);
    00227     if (errorcode == 0)
    00228     {
    00229         localcert.CertData = LocalBuf;
    00230         localcert.CertDataLength = length;
    00231     }
    00232     else
    00233     {
    00234          return -1;
    00235     }
    00236
    00237     for (i=0;i<osp->cacount;i++)
    00238     {
    00239         length = 0;
    00240       ast_log(LOG_DEBUG, "Loading CA cert %d for '%s' (%s)\n", i + 1, osp->name, osp->cacerts[i]);
    00241         errorcode = loadPemCert(osp->cacerts[i],AuthBuf[i],&length);
    00242         if (errorcode == 0)
    00243         {
    00244             TheAuthCert[i].CertData = AuthBuf[i];
    00245             TheAuthCert[i].CertDataLength = length;
    00246             authCerts[i] = &(TheAuthCert[i]);
    00247         }
    00248         else
    00249         {
    00250          return -1;
    00251       }
    00252     }
    00253
    00254    ast_log(LOG_DEBUG, "Creating provider handle for '%s'\n", osp->name);
    00255
    00256    ast_log(LOG_DEBUG, "Service point '%s %d'\n", servicepoints[0], osp->spcount);
    00257
    00258    if (OSPPProviderNew(osp->spcount,
    00259                    servicepoints,
    00260                   NULL,
    00261                   "localhost",
    00262                   &privatekey,
    00263                   &localcert,
    00264                   osp->cacount,
    00265                   (const OSPTCERT **)authCerts,
    00266                   1,
    00267                   300,
    00268                   osp->maxconnections,
    00269                   1,
    00270                   osp->retrydelay,
    00271                   osp->retrylimit,
    00272                   osp->timeout,
    00273                   "",
    00274                   "",
    00275                   &osp->handle)) {
    00276       ast_log(LOG_WARNING, "Unable to initialize provider '%s'\n", cat);
    00277       osp->dead = 1;
    00278    }
    00279
    00280    if (mallocd) {
    00281       osp->next = providers;
    00282       providers = osp;
    00283    }
    00284    ast_mutex_unlock(&osplock);
    00285    return 0;
    00286 }
    00287
    00288 static int show_osp(int fd, int argc, char *argv[])
    00289 {
    00290    struct osp_provider *osp;
    00291    char *search = NULL;
    00292    int x;
    00293    int found = 0;
    00294    char *tokenalgo;
    00295
    00296    if ((argc < 2) || (argc > 3))
    00297       return RESULT_SHOWUSAGE;
    00298    if (argc > 2)
    00299       search = argv[2];
    00300    if (!search) {
    00301       switch (tokenformat) {
    00302          case TOKEN_ALGO_BOTH:
    00303             tokenalgo = "Both";
    00304             break;
    00305          case TOKEN_ALGO_UNSIGNED:
    00306             tokenalgo = "Unsigned";
    00307             break;
    00308          case TOKEN_ALGO_SIGNED:
    00309          default:
    00310             tokenalgo = "Signed";
    00311             break;
    00312       }
    00313       ast_cli(fd, "OSP: %s %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal", tokenalgo);
    00314    }
    00315
    00316    ast_mutex_lock(&osplock);
    00317    osp = providers;
    00318    while(osp) {
    00319       if (!search || !strcasecmp(osp->name, search)) {
    00320          if (found)
    00321             ast_cli(fd, "\n");
    00322          ast_cli(fd, " == OSP Provider '%s' ==\n", osp->name);
    00323          ast_cli(fd, "Local Private Key: %s\n", osp->localpvtkey);
    00324          ast_cli(fd, "Local Certificate: %s\n", osp->localcert);
    00325          for (x=0;x<osp->cacount;x++)
    00326             ast_cli(fd, "CA Certificate %d:  %s\n", x + 1, osp->cacerts[x]);
    00327          for (x=0;x<osp->spcount;x++)
    00328             ast_cli(fd, "Service Point %d:   %s\n", x + 1, osp->servicepoints[x]);
    00329          ast_cli(fd, "Max Connections:   %d\n", osp->maxconnections);
    00330          ast_cli(fd, "Retry Delay:       %d seconds\n", osp->retrydelay);
    00331          ast_cli(fd, "Retry Limit:       %d\n", osp->retrylimit);
    00332          ast_cli(fd, "Timeout:           %d milliseconds\n", osp->timeout);
    00333          ast_cli(fd, "Source:            %s\n", strlen(osp->source) ? osp->source : "<unspecified>");
    00334          ast_cli(fd, "OSP Handle:        %d\n", osp->handle);
    00335          found++;
    00336       }
    00337       osp = osp->next;
    00338    }
    00339    ast_mutex_unlock(&osplock);
    00340    if (!found) {
    00341       if (search)
    00342          ast_cli(fd, "Unable to find OSP provider '%s'\n", search);
    00343       else
    00344          ast_cli(fd, "No OSP providers configured\n");
    00345    }
    00346    return RESULT_SUCCESS;
    00347 }
    00348
    00349
    00350 /*----------------------------------------------*
    00351  *               Loads the Certificate          *
    00352  *----------------------------------------------*/
    00353 static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len)
    00354 {
    00355     int length = 0;
    00356     unsigned char *temp;
    00357     BIO *bioIn = NULL;
    00358     X509 *cert=NULL;
    00359     int retVal = OSPC_ERR_NO_ERROR;
    00360
    00361     temp = buffer;
    00362     bioIn = BIO_new_file((const char*)FileName,"r");
    00363     if (bioIn == NULL)
    00364     {
    00365       ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
    00366       return -1;
    00367     }
    00368     else
    00369     {
    00370         cert = PEM_read_bio_X509(bioIn,NULL,NULL,NULL);
    00371         if (cert == NULL)
    00372         {
    00373          ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s \n",FileName);
    00374          return -1;
    00375         }
    00376         else
    00377         {
    00378             length = i2d_X509(cert,&temp);
    00379             if (cert == 0)
    00380             {
    00381             ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s, Length=0 \n",FileName);
    00382             return -1;
    00383             }
    00384             else
    00385          {
    00386                *len = length;
    00387             }
    00388         }
    00389     }
    00390
    00391     if (bioIn != NULL)
    00392     {
    00393         BIO_free(bioIn);
    00394     }
    00395
    00396     if (cert != NULL)
    00397     {
    00398         X509_free(cert);
    00399     }
    00400     return retVal;
    00401 }
    00402
    00403 /*----------------------------------------------*
    00404  *               Loads the Private Key          *
    00405  *----------------------------------------------*/
    00406 static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len)
    00407 {
    00408     int length = 0;
    00409     unsigned char *temp;
    00410     BIO *bioIn = NULL;
    00411     RSA *pKey = NULL;
    00412     int retVal = OSPC_ERR_NO_ERROR;
    00413
    00414     temp = buffer;
    00415
    00416     bioIn = BIO_new_file((const char*)FileName,"r");
    00417     if (bioIn == NULL)
    00418     {
    00419       ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
    00420       return -1;
    00421     }
    00422     else
    00423     {
    00424         pKey = PEM_read_bio_RSAPrivateKey(bioIn,NULL,NULL,NULL);
    00425         if (pKey == NULL)
    00426         {
    00427          ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s \n",FileName);
    00428          return -1;
    00429         }
    00430         else
    00431         {
    00432             length = i2d_RSAPrivateKey(pKey,&temp);
    00433             if (length == 0)
    00434             {
    00435             ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s, Length=0 \n",FileName);
    00436             return -1;
    00437             }
    00438             else
    00439             {
    00440                 *len = length;
    00441             }
    00442         }
    00443     }
    00444     if (bioIn != NULL)
    00445     {
    00446         BIO_free(bioIn);
    00447     }
    00448
    00449     if (pKey != NULL)
    00450     {
    00451        RSA_free(pKey);
    00452     }
    00453     return retVal;
    00454 }
    00455
    00456 int ast_osp_validate(char *provider, char *token, int *handle, unsigned int *timelimit, char *callerid, struct in_addr addr, char *extension)
    00457 {
    00458    char tmp[256]="", *l, *n;
    00459    char iabuf[INET_ADDRSTRLEN];
    00460    char source[OSP_MAX] = ""; /* Same length as osp->source */
    00461    char *token2;
    00462    int tokenlen;
    00463    struct osp_provider *osp;
    00464    int res = 0;
    00465    unsigned int authorised, dummy;
    00466
    00467    if (!provider || !strlen(provider))
    00468       provider = "default";
    00469
    00470    token2 = ast_strdupa(token);
    00471    if (!token2)
    00472       return -1;
    00473    tokenlen = ast_base64decode(token2, token, strlen(token));
    00474    *handle = -1;
    00475    if (!callerid)
    00476       callerid = "";
    00477    ast_copy_string(tmp, callerid, sizeof(tmp));
    00478    ast_callerid_parse(tmp, &n, &l);
    00479    if (!l)
    00480       l = "";
    00481    else {
    00482       ast_shrink_phone_number(l);
    00483       if (!ast_isphonenumber(l))
    00484          l = "";
    00485    }
    00486    callerid = l;
    00487    ast_mutex_lock(&osplock);
    00488    ast_inet_ntoa(iabuf, sizeof(iabuf), addr);
    00489    osp = providers;
    00490    while(osp) {
    00491       if (!strcasecmp(osp->name, provider)) {
    00492          if (OSPPTransactionNew(osp->handle, handle)) {
    00493             ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
    00494          } else {
    00495             ast_copy_string(source, osp->source, sizeof(source));
    00496             res = 1;
    00497          }
    00498          break;
    00499       }
    00500       osp = osp->next;
    00501    }
    00502    ast_mutex_unlock(&osplock);
    00503    if (res) {
    00504       res = 0;
    00505       dummy = 0;
    00506       if (!OSPPTransactionValidateAuthorisation(*handle, iabuf, source, NULL, NULL,
    00507          callerid, OSPC_E164, extension, OSPC_E164, 0, "", tokenlen, token2, &authorised, timelimit, &dummy, NULL, tokenformat)) {
    00508          if (authorised) {
    00509             ast_log(LOG_DEBUG, "Validated token for '%s' from '%s@%s'\n", extension, callerid, iabuf);
    00510             res = 1;
    00511          }
    00512       }
    00513    }
    00514    return res;
    00515 }
    00516
    00517 int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result)
    00518 {
    00519    int cres;
    00520    int res = 0;
    00521    int counts;
    00522    int tokenlen;
    00523    unsigned int dummy=0;
    00524    unsigned int timelimit;
    00525    unsigned int callidlen;
    00526    char callidstr[OSPC_CALLID_MAXSIZE] = "";
    00527    struct osp_provider *osp;
    00528    char source[OSP_MAX] = ""; /* Same length as osp->source */
    00529    char callednum[2048]="";
    00530    char callingnum[2048]="";
    00531    char destination[2048]="";
    00532    char token[2000];
    00533    char tmp[256]="", *l, *n;
    00534    OSPE_DEST_PROT prot;
    00535    OSPE_DEST_OSP_ENABLED ospenabled;
    00536    char *devinfo = NULL;
    00537
    00538    result->handle = -1;
    00539    result->numresults = 0;
    00540    result->tech[0] = '\0';
    00541    result->dest[0] = '\0';
    00542    result->token[0] = '\0';
    00543
    00544    if (!provider || !strlen(provider))
    00545       provider = "default";
    00546
    00547    if (!callerid)
    00548       callerid = "";
    00549    ast_copy_string(tmp, callerid, sizeof(tmp));
    00550    ast_callerid_parse(tmp, &n, &l);
    00551    if (!l)
    00552       l = "";
    00553    else {
    00554       ast_shrink_phone_number(l);
    00555       if (!ast_isphonenumber(l))
    00556          l = "";
    00557    }
    00558    callerid = l;
    00559
    00560    if (chan) {
    00561       cres = ast_autoservice_start(chan);
    00562       if (cres < 0)
    00563          return cres;
    00564    }
    00565    ast_mutex_lock(&osplock);
    00566    osp = providers;
    00567    while(osp) {
    00568       if (!strcasecmp(osp->name, provider)) {
    00569          if (OSPPTransactionNew(osp->handle, &result->handle)) {
    00570             ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
    00571          } else {
    00572             ast_copy_string(source, osp->source, sizeof(source));
    00573             res = 1;
    00574          }
    00575          break;
    00576       }
    00577       osp = osp->next;
    00578    }
    00579    ast_mutex_unlock(&osplock);
    00580    if (res) {
    00581       res = 0;
    00582       /* No more than 10 back */
    00583       counts = 10;
    00584       dummy = 0;
    00585       devinfo = pbx_builtin_getvar_helper (chan, "OSPPEER");
    00586       if (!devinfo) {
    00587          devinfo = "";
    00588       }
    00589       if (!OSPPTransactionRequestAuthorisation(result->handle, source, devinfo,
    00590            callerid,OSPC_E164, extension, OSPC_E164, NULL, 0, NULL, NULL, &counts, &dummy, NULL)) {
    00591          if (counts) {
    00592             tokenlen = sizeof(token);
    00593             result->numresults = counts - 1;
    00594             callidlen = sizeof(callidstr);
    00595             if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, callidstr,
    00596                sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
    00597                ast_log(LOG_DEBUG, "Got destination '%s' and called: '%s' calling: '%s' for '%s' (provider '%s')\n",
    00598                   destination, callednum, callingnum, extension, provider);
    00599                /* Only support OSP server with only one duration limit */
    00600                if (ast_channel_cmpwhentohangup (chan, timelimit) < 0) {
    00601                   ast_channel_setwhentohangup (chan, timelimit);
    00602                }
    00603                do {
    00604                   if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) {
    00605                      result->token[0] = 0;
    00606                   }
    00607                   else {
    00608                      ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
    00609                   }
    00610                   if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
    00611                      res = 1;
    00612                      /* Strip leading and trailing brackets */
    00613                      destination[strlen(destination) - 1] = '\0';
    00614                      switch(prot) {
    00615                      case OSPE_DEST_PROT_H323_SETUP:
    00616                         ast_copy_string(result->tech, "H323", sizeof(result->tech));
    00617                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
    00618                         break;
    00619                      case OSPE_DEST_PROT_SIP:
    00620                         ast_copy_string(result->tech, "SIP", sizeof(result->tech));
    00621                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
    00622                         break;
    00623                      case OSPE_DEST_PROT_IAX:
    00624                         ast_copy_string(result->tech, "IAX", sizeof(result->tech));
    00625                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
    00626                         break;
    00627                      default:
    00628                         ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
    00629                         res = 0;
    00630                      }
    00631                      if (!res && result->numresults) {
    00632                         result->numresults--;
    00633                         callidlen = sizeof(callidstr);
    00634                         if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr,
    00635                               sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
    00636                               break;
    00637                         }
    00638                      }
    00639                   } else {
    00640                      ast_log(LOG_DEBUG, "Missing destination protocol\n");
    00641                      break;
    00642                   }
    00643                } while(!res && result->numresults);
    00644             }
    00645          }
    00646
    00647       }
    00648       if (!res) {
    00649          OSPPTransactionDelete(result->handle);
    00650          result->handle = -1;
    00651       }
    00652
    00653    }
    00654    if (!osp)
    00655       ast_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider);
    00656    if (chan) {
    00657       cres = ast_autoservice_stop(chan);
    00658       if (cres < 0)
    00659          return cres;
    00660    }
    00661    return res;
    00662 }
    00663
    00664 int ast_osp_next(struct ast_osp_result *result, int cause)
    00665 {
    00666    int res = 0;
    00667    int tokenlen;
    00668    unsigned int dummy=0;
    00669    unsigned int timelimit;
    00670    unsigned int callidlen;
    00671    char callidstr[OSPC_CALLID_MAXSIZE] = "";
    00672    char callednum[2048]="";
    00673    char callingnum[2048]="";
    00674    char destination[2048]="";
    00675    char token[2000];
    00676    OSPE_DEST_PROT prot;
    00677    OSPE_DEST_OSP_ENABLED ospenabled;
    00678
    00679    result->tech[0] = '\0';
    00680    result->dest[0] = '\0';
    00681    result->token[0] = '\0';
    00682
    00683    if (result->handle > -1) {
    00684       dummy = 0;
    00685       if (result->numresults) {
    00686          tokenlen = sizeof(token);
    00687          while(!res && result->numresults) {
    00688             result->numresults--;
    00689             callidlen = sizeof(callidstr);
    00690             if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr,
    00691                            sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
    00692                if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) {
    00693                   result->token[0] = 0;
    00694                }
    00695                else {
    00696                   ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
    00697                }
    00698                if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
    00699                   res = 1;
    00700                   /* Strip leading and trailing brackets */
    00701                   destination[strlen(destination) - 1] = '\0';
    00702                   switch(prot) {
    00703                   case OSPE_DEST_PROT_H323_SETUP:
    00704                      ast_copy_string(result->tech, "H323", sizeof(result->tech));
    00705                      snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
    00706                      break;
    00707                   case OSPE_DEST_PROT_SIP:
    00708                      ast_copy_string(result->tech, "SIP", sizeof(result->tech));
    00709                      snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
    00710                      break;
    00711                   case OSPE_DEST_PROT_IAX:
    00712                      ast_copy_string(result->tech, "IAX", sizeof(result->tech));
    00713                      snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
    00714                      break;
    00715                   default:
    00716                      ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
    00717                      res = 0;
    00718                   }
    00719                } else {
    00720                   ast_log(LOG_DEBUG, "Missing destination protocol\n");
    00721                   break;
    00722                }
    00723             }
    00724          }
    00725
    00726       }
    00727       if (!res) {
    00728          OSPPTransactionDelete(result->handle);
    00729          result->handle = -1;
    00730       }
    00731
    00732    }
    00733    return res;
    00734 }
    00735
    00736 static enum OSPEFAILREASON cause2reason(int cause)
    00737 {
    00738    switch(cause) {
    00739    case AST_CAUSE_BUSY:
    00740       return OSPC_FAIL_USER_BUSY;
    00741    case AST_CAUSE_CONGESTION:
    00742       return OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION;
    00743    case AST_CAUSE_UNALLOCATED:
    00744       return OSPC_FAIL_UNALLOC_NUMBER;
    00745    case AST_CAUSE_NOTDEFINED:
    00746       return OSPC_FAIL_NORMAL_UNSPECIFIED;
    00747    case AST_CAUSE_NOANSWER:
    00748       return OSPC_FAIL_NO_ANSWER_FROM_USER;
    00749    case AST_CAUSE_NORMAL:
    00750    default:
    00751       return OSPC_FAIL_NORMAL_CALL_CLEARING;
    00752    }
    00753 }
    00754
    00755 int ast_osp_terminate(int handle, int cause, time_t start, time_t duration)
    00756 {
    00757    unsigned int dummy = 0;
    00758    int res = -1;
    00759    enum OSPEFAILREASON reason;
    00760
    00761    time_t endTime = 0;
    00762    time_t alertTime = 0;
    00763    time_t connectTime = 0;
    00764    unsigned isPddInfoPresent = 0;
    00765    unsigned pdd = 0;
    00766    unsigned releaseSource = 0;
    00767    unsigned char *confId = "";
    00768
    00769    reason = cause2reason(cause);
    00770    if (OSPPTransactionRecordFailure(handle, reason))
    00771       ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle);
    00772    else if (OSPPTransactionReportUsage(handle, duration, start,
    00773                 endTime,alertTime,connectTime,isPddInfoPresent,pdd,releaseSource,confId,
    00774                       0, 0, 0, 0, &dummy, NULL))
    00775       ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle);
    00776    else {
    00777       ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle);
    00778       OSPPTransactionDelete(handle);
    00779       res = 0;
    00780    }
    00781    return res;
    00782 }
    00783
    00784 static int config_load(void)
    00785 {
    00786    struct ast_config *cfg;
    00787    char *cat;
    00788    struct osp_provider *osp, *prev = NULL, *next;
    00789    ast_mutex_lock(&osplock);
    00790    osp = providers;
    00791    while(osp) {
    00792       osp->dead = 1;
    00793       osp = osp->next;
    00794    }
    00795    ast_mutex_unlock(&osplock);
    00796    cfg = ast_config_load("osp.conf");
    00797    if (cfg) {
    00798       if (!initialized) {
    00799          cat = ast_variable_retrieve(cfg, "general", "accelerate");
    00800          if (cat && ast_true(cat))
    00801             if (OSPPInit(1)) {
    00802                ast_log(LOG_WARNING, "Failed to enable hardware accelleration, falling back to software mode\n");
    00803                OSPPInit(0);
    00804             } else
    00805                hardware = 1;
    00806          else
    00807             OSPPInit(0);
    00808          initialized = 1;
    00809       }
    00810       cat = ast_variable_retrieve(cfg, "general", "tokenformat");
    00811       if (cat) {
    00812          if ((sscanf(cat, "%30d", &tokenformat) != 1) || (tokenformat < TOKEN_ALGO_SIGNED) || (tokenformat > TOKEN_ALGO_BOTH)) {
    00813             tokenformat = TOKEN_ALGO_SIGNED;
    00814             ast_log(LOG_WARNING, "tokenformat should be an integer from 0 to 2, not '%s'\n", cat);
    00815          }
    00816       }
    00817       cat = ast_category_browse(cfg, NULL);
    00818       while(cat) {
    00819          if (strcasecmp(cat, "general"))
    00820             osp_build(cfg, cat);
    00821          cat = ast_category_browse(cfg, cat);
    00822       }
    00823       ast_config_destroy(cfg);
    00824    } else
    00825       ast_log(LOG_NOTICE, "No OSP configuration found.  OSP support disabled\n");
    00826    ast_mutex_lock(&osplock);
    00827    osp = providers;
    00828    while(osp) {
    00829       next = osp->next;
    00830       if (osp->dead) {
    00831          if (prev)
    00832             prev->next = next;
    00833          else
    00834             providers = next;
    00835          /* XXX Cleanup OSP structure first XXX */
    00836          free(osp);
    00837       } else
    00838          prev = osp;
    00839       osp = next;
    00840    }
    00841    ast_mutex_unlock(&osplock);
    00842    return 0;
    00843 }
    00844
    00845 static char show_osp_usage[] =
    00846 "Usage: show osp\n"
    00847 "       Displays information on Open Settlement Protocol\n";
    00848
    00849 static struct ast_cli_entry cli_show_osp =
    00850 { { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage };
    00851
    00852 int reload(void)
    00853 {
    00854    config_load();
    00855    ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n");
    00856    return 0;
    00857 }
    00858
    00859 int load_module(void)
    00860 {
    00861    config_load();
    00862    ast_cli_register(&cli_show_osp);
    00863    return 0;
    00864 }
    00865
    00866 int unload_module(void)
    00867 {
    00868    /* Can't unload this once we're loaded */
    00869    return -1;
    00870 }
    00871
    00872 char *description(void)
    00873 {
    00874    return "Open Settlement Protocol Support";
    00875 }
    00876
    00877 int usecount(void)
    00878 {
    00879    /* We should never be unloaded */
    00880    return 1;
    00881 }
    00882
    00883 char *key()
    00884 {
    00885    return ASTERISK_GPL_KEY;
    00886 }