diff options
author | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2004-06-25 03:59:07 +0000 |
---|---|---|
committer | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2004-06-25 03:59:07 +0000 |
commit | 96c27903b13f3789f60fb8299eace827ca4ff3d6 (patch) | |
tree | 10ec669a31a880a3a24a8a842bec640b09caeac5 /res | |
parent | 461824ef0bcd514c3678e297c76010cd3e316f1d (diff) |
Add outgoing OSP support (SIP only at this point)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@3296 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res')
-rwxr-xr-x | res/Makefile | 5 | ||||
-rwxr-xr-x | res/res_crypto.c | 124 | ||||
-rwxr-xr-x | res/res_osp.c | 736 |
3 files changed, 744 insertions, 121 deletions
diff --git a/res/Makefile b/res/Makefile index fa6e3cf81..302c3499f 100755 --- a/res/Makefile +++ b/res/Makefile @@ -14,6 +14,7 @@ MODS=res_adsi.so res_parking.so res_crypto.so res_musiconhold.so res_indications.so res_monitor.so MODS+=$(shell if [ -f "/usr/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi) MODS+=$(shell if [ -f "/usr/local/include/odbcinst.h" ]; then echo "res_odbc.so res_config_odbc.so"; fi) +MODS+=$(shell if [ -f "/usr/include/osp/osp.h" ]; then echo "res_osp.so"; fi) CRYPTO_LIBS=-lssl -lcrypto @@ -24,6 +25,7 @@ CFLAGS+=$(shell [ -f /usr/local/include/zaptel.h ] && echo " -DZAPATA_MOH") # Work around buggy RedHat 9.0 # CFLAGS+=-DOPENSSL_NO_KRB5 -fPIC +OSPLIB=/usr/lib/libosp.a all: depend $(MODS) @@ -39,6 +41,9 @@ clean: res_odbc.so: res_odbc.o $(CC) $(SOLINK) -o $@ $< -lodbc +res_osp.so: res_osp.o $(OSPLIB) + $(CC) $(SOLINK) -o $@ $< $(OSPLIB) + %.so : %.o $(CC) $(SOLINK) -o $@ $< diff --git a/res/res_crypto.c b/res/res_crypto.c index 4e12eb5b7..8df8d2b4c 100755 --- a/res/res_crypto.c +++ b/res/res_crypto.c @@ -23,6 +23,7 @@ #include <asterisk/cli.h> #include <asterisk/io.h> #include <asterisk/lock.h> +#include <asterisk/utils.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <stdio.h> @@ -56,9 +57,6 @@ * XXXX */ -static char base64[64]; -static char b2a[256]; - AST_MUTEX_DEFINE_STATIC(keylock); #define KEY_NEEDS_PASSCODE (1 << 16) @@ -298,89 +296,6 @@ static char *binary(int y, int len) #endif -static int base64decode(unsigned char *dst, char *src, int max) -{ - int cnt = 0; - unsigned int byte = 0; - unsigned int bits = 0; - int incnt = 0; -#if 0 - unsigned char *odst = dst; -#endif - while(*src && (cnt < max)) { - /* Shift in 6 bits of input */ - byte <<= 6; - byte |= (b2a[(int)(*src)]) & 0x3f; - bits += 6; -#if 0 - printf("Add: %c %s\n", *src, binary(b2a[(int)(*src)] & 0x3f, 6)); -#endif - src++; - incnt++; - /* If we have at least 8 bits left over, take that character - off the top */ - if (bits >= 8) { - bits -= 8; - *dst = (byte >> bits) & 0xff; -#if 0 - printf("Remove: %02x %s\n", *dst, binary(*dst, 8)); -#endif - dst++; - cnt++; - } - } -#if 0 - dump(odst, cnt); -#endif - /* Dont worry about left over bits, they're extra anyway */ - return cnt; -} - -static int base64encode(char *dst, unsigned char *src, int srclen, int max) -{ - int cnt = 0; - unsigned int byte = 0; - int bits = 0; - int index; - int cntin = 0; -#if 0 - char *odst = dst; - dump(src, srclen); -#endif - /* Reserve one bit for end */ - max--; - while((cntin < srclen) && (cnt < max)) { - byte <<= 8; -#if 0 - printf("Add: %02x %s\n", *src, binary(*src, 8)); -#endif - byte |= *(src++); - bits += 8; - cntin++; - while((bits >= 6) && (cnt < max)) { - bits -= 6; - /* We want only the top */ - index = (byte >> bits) & 0x3f; - *dst = base64[index]; -#if 0 - printf("Remove: %c %s\n", *dst, binary(index, 6)); -#endif - dst++; - cnt++; - } - } - if (bits && (cnt < max)) { - /* Add one last character for the remaining bits, - padding the rest with 0 */ - byte <<= (6 - bits); - index = (byte) & 0x3f; - *(dst++) = base64[index]; - cnt++; - } - *dst = '\0'; - return cnt; -} - int ast_sign(struct ast_key *key, char *msg, char *sig) { unsigned char digest[20]; @@ -410,7 +325,7 @@ int ast_sign(struct ast_key *key, char *msg, char *sig) } /* Success -- encode (256 bytes max as documented) */ - base64encode(sig, dsig, siglen, 256); + ast_base64encode(sig, dsig, siglen, 256); return 0; } @@ -429,7 +344,7 @@ int ast_check_signature(struct ast_key *key, char *msg, char *sig) } /* Decode signature */ - res = base64decode(dsig, sig, sizeof(dsig)); + res = ast_base64decode(dsig, sig, sizeof(dsig)); if (res != sizeof(dsig)) { ast_log(LOG_WARNING, "Signature improper length (expect %d, got %d)\n", (int)sizeof(dsig), (int)res); return -1; @@ -558,41 +473,8 @@ static struct ast_cli_entry cli_show_keys = static struct ast_cli_entry cli_init_keys = { { "init", "keys", NULL }, init_keys, "Initialize RSA key passcodes", init_keys_usage }; -static void base64_init(void) -{ - int x; - memset(b2a, -1, sizeof(b2a)); - /* Initialize base-64 Conversion table */ - for (x=0;x<26;x++) { - /* A-Z */ - base64[x] = 'A' + x; - b2a['A' + x] = x; - /* a-z */ - base64[x + 26] = 'a' + x; - b2a['a' + x] = x + 26; - /* 0-9 */ - if (x < 10) { - base64[x + 52] = '0' + x; - b2a['0' + x] = x + 52; - } - } - base64[62] = '+'; - base64[63] = '/'; - b2a[(int)'+'] = 62; - b2a[(int)'/'] = 63; -#if 0 - for (x=0;x<64;x++) { - if (b2a[(int)base64[x]] != x) { - fprintf(stderr, "!!! %d failed\n", x); - } else - fprintf(stderr, "--- %d passed\n", x); - } -#endif -} - static int crypto_init(void) { - base64_init(); SSL_library_init(); ERR_load_crypto_strings(); ast_cli_register(&cli_show_keys); diff --git a/res/res_osp.c b/res/res_osp.c new file mode 100755 index 000000000..deac15c7b --- /dev/null +++ b/res/res_osp.c @@ -0,0 +1,736 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * Provide Open Settlement Protocol capability + * + * Copyright (C) 2004, Digium, Inc. + * + * Mark Spencer <markster@digium.com> + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#include <sys/types.h> +#include <asterisk/file.h> +#include <asterisk/channel.h> +#include <asterisk/logger.h> +#include <asterisk/say.h> +#include <asterisk/module.h> +#include <asterisk/options.h> +#include <asterisk/crypto.h> +#include <asterisk/md5.h> +#include <asterisk/cli.h> +#include <asterisk/io.h> +#include <asterisk/lock.h> +#include <asterisk/astosp.h> +#include <asterisk/config.h> +#include <asterisk/utils.h> +#include <asterisk/lock.h> +#include <asterisk/causes.h> +#include <osp.h> +#include <openssl/err.h> +#include <stdio.h> +#include <dirent.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include "../asterisk.h" +#include "../astconf.h" +#include <openssl/bio.h> +#include <openssl/pem.h> +#include <openssl/evp.h> + + +#define MAX_CERTS 10 +#define MAX_SERVICEPOINTS 10 +#define OSP_MAX 256 + +#define OSP_DEFAULT_MAX_CONNECTIONS 20 +#define OSP_DEFAULT_RETRY_DELAY 0 +#define OSP_DEFAULT_RETRY_LIMIT 2 +#define OSP_DEFAULT_TIMEOUT 500 + +static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len); +static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len); + +AST_MUTEX_DEFINE_STATIC(osplock); + +static int initialized = 0; +static int hardware = 0; + +struct osp_provider { + char name[OSP_MAX]; + char localpvtkey[OSP_MAX]; + char localcert[OSP_MAX]; + char cacerts[MAX_CERTS][OSP_MAX]; + int cacount; + char servicepoints[MAX_SERVICEPOINTS][OSP_MAX]; + char source[OSP_MAX]; + int spcount; + int dead; + int maxconnections; + int retrydelay; + int retrylimit; + int timeout; + OSPTPROVHANDLE handle; + struct osp_provider *next; +}; +static struct osp_provider *providers; + +static int osp_build(struct ast_config *cfg, char *cat) +{ + OSPTCERT TheAuthCert[MAX_CERTS]; + unsigned char Reqbuf[4096],LocalBuf[4096],AuthBuf[MAX_CERTS][4096]; + struct ast_variable *v; + struct osp_provider *osp; + int x,length,errorcode=0; + int mallocd=0,i; + char *cacerts[MAX_CERTS]; + const char *servicepoints[MAX_SERVICEPOINTS]; + OSPTPRIVATEKEY privatekey; + OSPTCERT localcert; + OSPTCERT *authCerts[MAX_CERTS]; + + + + ast_mutex_lock(&osplock); + osp = providers; + while(osp) { + if (!strcasecmp(osp->name, cat)) + break; + osp = osp->next; + } + ast_mutex_unlock(&osplock); + if (!osp) { + mallocd = 1; + osp = malloc(sizeof(struct osp_provider)); + if (!osp) { + ast_log(LOG_WARNING, "Out of memory!\n"); + return -1; + } + memset(osp, 0, sizeof(struct osp_provider)); + osp->handle = -1; + } + strncpy(osp->name, cat, sizeof(osp->name) - 1); + snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s-privatekey.pem", cat); + snprintf(osp->localcert, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s-localcert.pem", cat); + osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS; + osp->retrydelay = OSP_DEFAULT_RETRY_DELAY; + osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT; + osp->timeout = OSP_DEFAULT_TIMEOUT; + strcpy(osp->source, ""); + ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat); + v = ast_variable_browse(cfg, cat); + while(v) { + if (!strcasecmp(v->name, "privatekey")) { + if (v->value[0] == '/') + strncpy(osp->localpvtkey, v->value, sizeof(osp->localpvtkey) - 1); + else + snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s", v->value); + } else if (!strcasecmp(v->name, "localcert")) { + if (v->value[0] == '/') + strncpy(osp->localcert, v->value, sizeof(osp->localcert) - 1); + else + snprintf(osp->localcert, sizeof(osp->localcert), AST_KEY_DIR "/%s", v->value); + } else if (!strcasecmp(v->name, "cacert")) { + if (osp->cacount < MAX_CERTS) { + if (v->value[0] == '/') + strncpy(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0])); + else + snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), AST_KEY_DIR "/%s", v->value); + osp->cacount++; + } else + ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno); + } else if (!strcasecmp(v->name, "servicepoint")) { + if (osp->spcount < MAX_SERVICEPOINTS) { + strncpy(osp->servicepoints[osp->spcount], v->value, sizeof(osp->servicepoints[0])); + osp->spcount++; + } else + ast_log(LOG_WARNING, "Too many Service points at line %d\n", v->lineno); + } else if (!strcasecmp(v->name, "maxconnections")) { + if ((sscanf(v->value, "%i", &x) == 1) && (x > 0) && (x <= 1000)) { + osp->maxconnections = x; + } else + ast_log(LOG_WARNING, "maxconnections should be an integer from 1 to 1000, not '%s' at line %d\n", v->value, v->lineno); + } else if (!strcasecmp(v->name, "retrydelay")) { + if ((sscanf(v->value, "%i", &x) == 1) && (x >= 0) && (x <= 10)) { + osp->retrydelay = x; + } else + ast_log(LOG_WARNING, "retrydelay should be an integer from 0 to 10, not '%s' at line %d\n", v->value, v->lineno); + } else if (!strcasecmp(v->name, "retrylimit")) { + if ((sscanf(v->value, "%i", &x) == 1) && (x >= 0) && (x <= 100)) { + osp->retrylimit = x; + } else + ast_log(LOG_WARNING, "retrylimit should be an integer from 0 to 100, not '%s' at line %d\n", v->value, v->lineno); + } else if (!strcasecmp(v->name, "timeout")) { + if ((sscanf(v->value, "%i", &x) == 1) && (x >= 200) && (x <= 10000)) { + osp->timeout = x; + } else + ast_log(LOG_WARNING, "timeout should be an integer from 200 to 10000, not '%s' at line %d\n", v->value, v->lineno); + } + v = v->next; + } + if (osp->cacount < 1) { + snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), AST_KEY_DIR "/%s-cacert.pem", cat); + osp->cacount++; + } + for (x=0;x<osp->cacount;x++) + cacerts[x] = osp->cacerts[x]; + for (x=0;x<osp->spcount;x++) + servicepoints[x] = osp->servicepoints[x]; + + ast_mutex_lock(&osplock); + osp->dead = 0; + if (osp->handle > -1) { + ast_log(LOG_DEBUG, "Deleting old handle for '%s'\n", osp->name); + OSPPProviderDelete(osp->handle, 0); + } + + + length = 0; + ast_log(LOG_DEBUG, "Loading private key for '%s' (%s)\n", osp->name, osp->localpvtkey); + errorcode = loadPemPrivateKey(osp->localpvtkey,Reqbuf,&length); + if (errorcode == 0) + { + privatekey.PrivateKeyData = Reqbuf; + privatekey.PrivateKeyLength = length; + } + else + { + return -1; + } + + length = 0; + ast_log(LOG_DEBUG, "Loading local cert for '%s' (%s)\n", osp->name, osp->localcert); + errorcode = loadPemCert(osp->localcert,LocalBuf,&length); + if (errorcode == 0) + { + localcert.CertData = LocalBuf; + localcert.CertDataLength = length; + } + else + { + return -1; + } + + for (i=0;i<osp->cacount;i++) + { + length = 0; + ast_log(LOG_DEBUG, "Loading CA cert %d for '%s' (%s)\n", i + 1, osp->name, osp->cacerts[i]); + errorcode = loadPemCert(osp->cacerts[i],AuthBuf[i],&length); + if (errorcode == 0) + { + TheAuthCert[i].CertData = AuthBuf[i]; + TheAuthCert[i].CertDataLength = length; + authCerts[i] = &(TheAuthCert[i]); + } + else + { + return -1; + } + } + + ast_log(LOG_DEBUG, "Creating provider handle for '%s'\n", osp->name); + + ast_log(LOG_DEBUG, "Service point '%s %d'\n", servicepoints[0], osp->spcount); + + if (OSPPProviderNew(osp->spcount, + servicepoints, + NULL, + "localhost", + &privatekey, + &localcert, + osp->cacount, + (const OSPTCERT **)authCerts, + 1, + 300, + osp->maxconnections, + 60000, + osp->retrydelay, + osp->retrylimit, + osp->timeout, + "", + "", + &osp->handle)) { + ast_log(LOG_WARNING, "Unable to initialize provider '%s'\n", cat); + osp->dead = 1; + } + + if (mallocd) { + osp->next = providers; + providers = osp; + } + ast_mutex_unlock(&osplock); + return 0; +} + +static int show_osp(int fd, int argc, char *argv[]) +{ + struct osp_provider *osp; + char *search = NULL; + int x; + int found = 0; + if ((argc < 2) || (argc > 3)) + return RESULT_SHOWUSAGE; + if (argc > 2) + search = argv[2]; + if (!search) + ast_cli(fd, "OSP: %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal"); + + ast_mutex_lock(&osplock); + osp = providers; + while(osp) { + if (!search || !strcasecmp(osp->name, search)) { + if (found) + ast_cli(fd, "\n"); + ast_cli(fd, " == OSP Provider '%s' ==\n", osp->name); + ast_cli(fd, "Local Private Key: %s\n", osp->localpvtkey); + ast_cli(fd, "Local Certificate: %s\n", osp->localcert); + for (x=0;x<osp->cacount;x++) + ast_cli(fd, "CA Certificate %d: %s\n", x + 1, osp->cacerts[x]); + for (x=0;x<osp->spcount;x++) + ast_cli(fd, "Service Point %d: %s\n", x + 1, osp->servicepoints[x]); + ast_cli(fd, "Max Connections: %d\n", osp->maxconnections); + ast_cli(fd, "Retry Delay: %d seconds\n", osp->retrydelay); + ast_cli(fd, "Retry Limit: %d\n", osp->retrylimit); + ast_cli(fd, "Timeout: %d milliseconds\n", osp->timeout); + ast_cli(fd, "Source: %s\n", strlen(osp->source) ? osp->source : "<unspecified>"); + ast_cli(fd, "OSP Handle: %d\n", osp->handle); + found++; + } + osp = osp->next; + } + ast_mutex_unlock(&osplock); + if (!found) { + if (search) + ast_cli(fd, "Unable to find OSP provider '%s'\n", search); + else + ast_cli(fd, "No OSP providers configured\n"); + } + return RESULT_SUCCESS; +} + + +/*----------------------------------------------* + * Loads the Certificate * + *----------------------------------------------*/ +static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len) +{ + int length = 0; + unsigned char *temp; + BIO *bioIn = NULL; + X509 *cert=NULL; + int retVal = OSPC_ERR_NO_ERROR; + + temp = buffer; + bioIn = BIO_new_file((const char*)FileName,"r"); + if (bioIn == NULL) + { + ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName); + return -1; + } + else + { + cert = PEM_read_bio_X509(bioIn,NULL,NULL,NULL); + if (cert == NULL) + { + ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s \n",FileName); + return -1; + } + else + { + length = i2d_X509(cert,&temp); + if (cert == 0) + { + ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s, Length=0 \n",FileName); + return -1; + } + else + { + *len = length; + } + } + } + + if (bioIn != NULL) + { + BIO_free(bioIn); + } + + if (cert != NULL) + { + X509_free(cert); + } + return retVal; +} + +/*----------------------------------------------* + * Loads the Private Key * + *----------------------------------------------*/ +static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len) +{ + int length = 0; + unsigned char *temp; + BIO *bioIn = NULL; + RSA *pKey = NULL; + int retVal = OSPC_ERR_NO_ERROR; + + temp = buffer; + + bioIn = BIO_new_file((const char*)FileName,"r"); + if (bioIn == NULL) + { + ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName); + return -1; + } + else + { + pKey = PEM_read_bio_RSAPrivateKey(bioIn,NULL,NULL,NULL); + if (pKey == NULL) + { + ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s \n",FileName); + return -1; + } + else + { + length = i2d_RSAPrivateKey(pKey,&temp); + if (length == 0) + { + ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s, Length=0 \n",FileName); + return -1; + } + else + { + *len = length; + } + } + } + if (bioIn != NULL) + { + BIO_free(bioIn); + } + + if (pKey != NULL) + { + RSA_free(pKey); + } + return retVal; +} + +int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result) +{ + int cres; + int res = 0; + int counts; + int tokenlen; + unsigned int dummy=0; + unsigned int timelimit; + unsigned int callidlen; + struct osp_provider *osp; + char source[OSP_MAX]; /* Same length as osp->source */ + char uniqueid[32] = ""; + char callednum[2048]=""; + char destination[2048]=""; + char token[2000]; + OSPTCALLID *callid; + OSPE_DEST_PROT prot; + + result->handle = -1; + result->numresults = 0; + strcpy(result->tech, ""); + strcpy(result->dest, ""); + strcpy(result->token, ""); + + if (!provider || !strlen(provider)) + provider = "default"; + + if (!callerid) + callerid = ""; + + if (chan) { + strncpy(uniqueid, chan->uniqueid, sizeof(uniqueid) - 1); + cres = ast_autoservice_start(chan); + if (cres < 0) + return cres; + } + ast_mutex_lock(&osplock); + osp = providers; + while(osp) { + if (!strcasecmp(osp->name, provider)) { + if (OSPPTransactionNew(osp->handle, &result->handle)) { + ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n"); + } else { + strcpy(source, osp->source); + res = 1; + } + break; + } + osp = osp->next; + } + ast_mutex_unlock(&osplock); + if (res) { + res = 0; + callid = OSPPCallIdNew(strlen(uniqueid), uniqueid); + if (callid) { + /* No more than 10 back */ + counts = 10; + dummy = 0; + callidlen = sizeof(uniqueid); + if (!OSPPTransactionRequestAuthorisation(result->handle, source, "", + callerid,OSPC_E164, extension, OSPC_E164, NULL, 1, &callid, NULL, &counts, &dummy, NULL)) { + if (counts) { + tokenlen = sizeof(token); + result->numresults = counts - 1; + if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, uniqueid, + sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { + ast_log(LOG_DEBUG, "Got destination '%s' and '%s' for '%s' (provider '%s')\n", + destination, callednum, extension, provider); + do { + ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1); + if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) { + res = 1; + /* Strip leading and trailing brackets */ + destination[strlen(destination) - 1] = '\0'; + switch(prot) { + case OSPE_DEST_PROT_H323_SETUP: + strcpy(result->tech, "H323"); + snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + break; + case OSPE_DEST_PROT_SIP: + strcpy(result->tech, "SIP"); + snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + break; + default: + ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot); + res = 0; + } + if (!res && result->numresults) { + result->numresults--; + if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid, + sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { + break; + } + } + } else { + ast_log(LOG_DEBUG, "Missing destination protocol\n"); + break; + } + } while(!res && result->numresults); + } + } + + } + OSPPCallIdDelete(&callid); + } + if (!res) { + OSPPTransactionDelete(result->handle); + result->handle = -1; + } + + } + if (!osp) + ast_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider); + if (chan) { + cres = ast_autoservice_stop(chan); + if (cres < 0) + return cres; + } + return res; +} + +int ast_osp_next(struct ast_osp_result *result, int cause) +{ + int res = 0; + int tokenlen; + unsigned int dummy=0; + unsigned int timelimit; + unsigned int callidlen; + char uniqueid[32] = ""; + char callednum[2048]=""; + char destination[2048]=""; + char token[2000]; + OSPE_DEST_PROT prot; + + strcpy(result->tech, ""); + strcpy(result->dest, ""); + strcpy(result->token, ""); + + if (result->handle > -1) { + dummy = 0; + callidlen = sizeof(uniqueid); + if (result->numresults) { + tokenlen = sizeof(token); + while(!res && result->numresults) { + result->numresults--; + if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid, + sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { + ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1); + if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) { + res = 1; + /* Strip leading and trailing brackets */ + destination[strlen(destination) - 1] = '\0'; + switch(prot) { + case OSPE_DEST_PROT_H323_SETUP: + strcpy(result->tech, "H323"); + snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + break; + case OSPE_DEST_PROT_SIP: + strcpy(result->tech, "SIP"); + snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); + break; + default: + ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot); + res = 0; + } + } else { + ast_log(LOG_DEBUG, "Missing destination protocol\n"); + break; + } + } + } + + } + if (!res) { + OSPPTransactionDelete(result->handle); + result->handle = -1; + } + + } + return res; +} + +static enum OSPEFAILREASON cause2reason(int cause) +{ + switch(cause) { + case AST_CAUSE_BUSY: + return OSPC_FAIL_USER_BUSY; + case AST_CAUSE_CONGESTION: + return OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION; + case AST_CAUSE_UNALLOCATED: + return OSPC_FAIL_UNALLOC_NUMBER; + case AST_CAUSE_NOTDEFINED: + return OSPC_FAIL_NORMAL_UNSPECIFIED; + case AST_CAUSE_NOANSWER: + return OSPC_FAIL_NO_ANSWER_FROM_USER; + case AST_CAUSE_NORMAL: + default: + return OSPC_FAIL_NORMAL_CALL_CLEARING; + } +} + +int ast_osp_terminate(int handle, int cause, time_t start, time_t duration) +{ + unsigned int dummy = 0; + int res = -1; + enum OSPEFAILREASON reason; + reason = cause2reason(cause); + if (OSPPTransactionRecordFailure(handle, reason)) + ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle); + else if (OSPPTransactionReportUsage(handle, duration, start, 0, 0, 0, 0, &dummy, NULL)) + ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle); + else { + ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle); + OSPPTransactionDelete(handle); + res = 0; + } + return res; +} + +static int config_load(void) +{ + struct ast_config *cfg; + char *cat; + struct osp_provider *osp, *prev = NULL, *next; + ast_mutex_lock(&osplock); + osp = providers; + while(osp) { + osp->dead = 1; + osp = osp->next; + } + ast_mutex_unlock(&osplock); + cfg = ast_load("osp.conf"); + if (cfg) { + if (!initialized) { + cat = ast_variable_retrieve(cfg, "general", "accelerate"); + if (cat && ast_true(cat)) + if (OSPPInit(1)) { + ast_log(LOG_WARNING, "Failed to enable hardware accelleration, falling back to software mode\n"); + OSPPInit(0); + } else + hardware = 1; + else + OSPPInit(0); + initialized = 1; + } + cat = ast_category_browse(cfg, NULL); + while(cat) { + if (strcasecmp(cat, "general")) + osp_build(cfg, cat); + cat = ast_category_browse(cfg, cat); + } + ast_destroy(cfg); + } else + ast_log(LOG_NOTICE, "No OSP configuration found. OSP support disabled\n"); + ast_mutex_lock(&osplock); + osp = providers; + while(osp) { + next = osp->next; + if (osp->dead) { + if (prev) + prev->next = next; + else + providers = next; + /* XXX Cleanup OSP structure first XXX */ + free(osp); + } else + prev = osp; + osp = next; + } + ast_mutex_unlock(&osplock); + return 0; +} + +static char show_osp_usage[] = +"Usage: show osp\n" +" Displays information on Open Settlement Protocol\n"; + +static struct ast_cli_entry cli_show_osp = +{ { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage }; + +int reload(void) +{ + config_load(); + ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n"); + return 0; +} + +int load_module(void) +{ + config_load(); + ast_cli_register(&cli_show_osp); + return 0; +} + +int unload_module(void) +{ + /* Can't unload this once we're loaded */ + return -1; +} + +char *description(void) +{ + return "Open Settlement Protocol Support"; +} + +int usecount(void) +{ + /* We should never be unloaded */ + return 1; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} |