6270c4a72a0341f68908a30f3bf13ae5153637ac
[asterisk/asterisk.git] / res / res_osp.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Provide Open Settlement Protocol capability
5  * 
6  * Copyright (C) 2004, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <asterisk/file.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/say.h>
19 #include <asterisk/module.h>
20 #include <asterisk/options.h>
21 #include <asterisk/crypto.h>
22 #include <asterisk/md5.h>
23 #include <asterisk/cli.h>
24 #include <asterisk/io.h>
25 #include <asterisk/lock.h>
26 #include <asterisk/astosp.h>
27 #include <asterisk/config.h>
28 #include <asterisk/utils.h>
29 #include <asterisk/lock.h>
30 #include <asterisk/causes.h>
31 #include <asterisk/callerid.h>
32 #include <osp.h>
33 #include <openssl/err.h>
34 #include <stdio.h>
35 #include <dirent.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include "../asterisk.h"
41 #include "../astconf.h"
42 #include <openssl/bio.h>
43 #include <openssl/pem.h>
44 #include <openssl/evp.h>
45
46
47 #define MAX_CERTS 10
48 #define MAX_SERVICEPOINTS 10
49 #define OSP_MAX 256
50
51 #define OSP_DEFAULT_MAX_CONNECTIONS     20
52 #define OSP_DEFAULT_RETRY_DELAY         0
53 #define OSP_DEFAULT_RETRY_LIMIT         2
54 #define OSP_DEFAULT_TIMEOUT                     500
55
56 static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len);
57 static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len);
58
59 AST_MUTEX_DEFINE_STATIC(osplock);
60
61 static int initialized = 0;
62 static int hardware = 0;
63
64 struct osp_provider {
65         char name[OSP_MAX];
66         char localpvtkey[OSP_MAX];
67         char localcert[OSP_MAX];
68         char cacerts[MAX_CERTS][OSP_MAX]; 
69         int cacount;
70         char servicepoints[MAX_SERVICEPOINTS][OSP_MAX];
71         char source[OSP_MAX];
72         int spcount;
73         int dead;
74         int maxconnections;
75         int retrydelay;
76         int retrylimit;
77         int timeout;
78         OSPTPROVHANDLE handle;
79         struct osp_provider *next;
80 };
81 static struct osp_provider *providers;
82
83 static int osp_build(struct ast_config *cfg, char *cat)
84 {
85         OSPTCERT TheAuthCert[MAX_CERTS];
86         unsigned char Reqbuf[4096],LocalBuf[4096],AuthBuf[MAX_CERTS][4096];
87         struct ast_variable *v;
88         struct osp_provider *osp;
89         int x,length,errorcode=0;
90         int mallocd=0,i;
91         char *cacerts[MAX_CERTS];
92         const char *servicepoints[MAX_SERVICEPOINTS];
93         OSPTPRIVATEKEY privatekey;
94         OSPTCERT localcert;
95         OSPTCERT *authCerts[MAX_CERTS];
96
97         
98         
99         ast_mutex_lock(&osplock);
100         osp = providers;
101         while(osp) {
102                 if (!strcasecmp(osp->name, cat))
103                         break;
104                 osp = osp->next;
105         }
106         ast_mutex_unlock(&osplock);
107         if (!osp) {
108                 mallocd = 1;
109                 osp = malloc(sizeof(struct osp_provider));
110                 if (!osp) {
111                         ast_log(LOG_WARNING, "Out of memory!\n");
112                         return -1;
113                 }
114                 memset(osp, 0, sizeof(struct osp_provider));
115                 osp->handle = -1;
116         }
117         strncpy(osp->name, cat, sizeof(osp->name) - 1);
118         snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s-privatekey.pem", cat);
119         snprintf(osp->localcert, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s-localcert.pem", cat);
120         osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS;
121         osp->retrydelay = OSP_DEFAULT_RETRY_DELAY;
122         osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT;
123         osp->timeout = OSP_DEFAULT_TIMEOUT;
124         strcpy(osp->source, "");
125         ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat);
126         v = ast_variable_browse(cfg, cat);
127         while(v) {
128                 if (!strcasecmp(v->name, "privatekey")) {
129                         if (v->value[0] == '/')
130                                 strncpy(osp->localpvtkey, v->value, sizeof(osp->localpvtkey) - 1);
131                         else
132                                 snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s", v->value);
133                 } else if (!strcasecmp(v->name, "localcert")) {
134                         if (v->value[0] == '/')
135                                 strncpy(osp->localcert, v->value, sizeof(osp->localcert) - 1);
136                         else
137                                 snprintf(osp->localcert, sizeof(osp->localcert), AST_KEY_DIR "/%s", v->value);
138                 } else if (!strcasecmp(v->name, "cacert")) {
139                         if (osp->cacount < MAX_CERTS) {
140                                 if (v->value[0] == '/')
141                                         strncpy(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0]));
142                                 else
143                                         snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), AST_KEY_DIR "/%s", v->value);
144                                 osp->cacount++;
145                         } else
146                                 ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno);
147                 } else if (!strcasecmp(v->name, "servicepoint")) {
148                         if (osp->spcount < MAX_SERVICEPOINTS) {
149                                 strncpy(osp->servicepoints[osp->spcount], v->value, sizeof(osp->servicepoints[0]));
150                                 osp->spcount++;
151                         } else
152                                 ast_log(LOG_WARNING, "Too many Service points at line %d\n", v->lineno);
153                 } else if (!strcasecmp(v->name, "maxconnections")) {
154                         if ((sscanf(v->value, "%i", &x) == 1) && (x > 0) && (x <= 1000)) {
155                                 osp->maxconnections = x;
156                         } else
157                                 ast_log(LOG_WARNING, "maxconnections should be an integer from 1 to 1000, not '%s' at line %d\n", v->value, v->lineno);
158                 } else if (!strcasecmp(v->name, "retrydelay")) {
159                         if ((sscanf(v->value, "%i", &x) == 1) && (x >= 0) && (x <= 10)) {
160                                 osp->retrydelay = x;
161                         } else
162                                 ast_log(LOG_WARNING, "retrydelay should be an integer from 0 to 10, not '%s' at line %d\n", v->value, v->lineno);
163                 } else if (!strcasecmp(v->name, "retrylimit")) {
164                         if ((sscanf(v->value, "%i", &x) == 1) && (x >= 0) && (x <= 100)) {
165                                 osp->retrylimit = x;
166                         } else
167                                 ast_log(LOG_WARNING, "retrylimit should be an integer from 0 to 100, not '%s' at line %d\n", v->value, v->lineno);
168                 } else if (!strcasecmp(v->name, "timeout")) {
169                         if ((sscanf(v->value, "%i", &x) == 1) && (x >= 200) && (x <= 10000)) {
170                                 osp->timeout = x;
171                         } else
172                                 ast_log(LOG_WARNING, "timeout should be an integer from 200 to 10000, not '%s' at line %d\n", v->value, v->lineno);
173                 }
174                 v = v->next;
175         }
176         if (osp->cacount < 1) {
177                 snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), AST_KEY_DIR "/%s-cacert.pem", cat);
178                 osp->cacount++;
179         }
180         for (x=0;x<osp->cacount;x++)
181                 cacerts[x] = osp->cacerts[x];
182         for (x=0;x<osp->spcount;x++)
183                 servicepoints[x] = osp->servicepoints[x];
184         
185         ast_mutex_lock(&osplock);
186         osp->dead = 0;
187         if (osp->handle > -1) {
188                 ast_log(LOG_DEBUG, "Deleting old handle for '%s'\n", osp->name);
189                 OSPPProviderDelete(osp->handle, 0);
190         }
191                 
192
193     length = 0;
194         ast_log(LOG_DEBUG, "Loading private key for '%s' (%s)\n", osp->name, osp->localpvtkey);
195     errorcode = loadPemPrivateKey(osp->localpvtkey,Reqbuf,&length);
196     if (errorcode == 0)
197     {
198         privatekey.PrivateKeyData = Reqbuf;
199         privatekey.PrivateKeyLength = length;
200     }
201     else
202     {
203          return -1;
204     }
205
206     length = 0;
207         ast_log(LOG_DEBUG, "Loading local cert for '%s' (%s)\n", osp->name, osp->localcert);
208     errorcode = loadPemCert(osp->localcert,LocalBuf,&length);
209     if (errorcode == 0)
210     {
211         localcert.CertData = LocalBuf;
212         localcert.CertDataLength = length;
213     }
214     else
215     {
216          return -1;
217     }
218
219     for (i=0;i<osp->cacount;i++)
220     {
221         length = 0;
222                 ast_log(LOG_DEBUG, "Loading CA cert %d for '%s' (%s)\n", i + 1, osp->name, osp->cacerts[i]);
223         errorcode = loadPemCert(osp->cacerts[i],AuthBuf[i],&length);
224         if (errorcode == 0)
225         {
226             TheAuthCert[i].CertData = AuthBuf[i];
227             TheAuthCert[i].CertDataLength = length;
228             authCerts[i] = &(TheAuthCert[i]);
229         }
230         else
231         {
232                         return -1;        
233                 }
234     }
235         
236         ast_log(LOG_DEBUG, "Creating provider handle for '%s'\n", osp->name);
237         
238         ast_log(LOG_DEBUG, "Service point '%s %d'\n", servicepoints[0], osp->spcount);
239         
240         if (OSPPProviderNew(osp->spcount, 
241                                             servicepoints, 
242                                            NULL, 
243                                            "localhost", 
244                                            &privatekey, 
245                                            &localcert, 
246                                            osp->cacount, 
247                                            (const OSPTCERT **)authCerts, 
248                                            1, 
249                                            300, 
250                                            osp->maxconnections, 
251                                            60000, 
252                                            osp->retrydelay, 
253                                            osp->retrylimit, 
254                                            osp->timeout, 
255                                            "", 
256                                            "", 
257                                            &osp->handle)) {
258                 ast_log(LOG_WARNING, "Unable to initialize provider '%s'\n", cat);
259                 osp->dead = 1;
260         }
261         
262         if (mallocd) {
263                 osp->next = providers;
264                 providers = osp;
265         }
266         ast_mutex_unlock(&osplock);     
267         return 0;
268 }
269
270 static int show_osp(int fd, int argc, char *argv[])
271 {
272         struct osp_provider *osp;
273         char *search = NULL;
274         int x;
275         int found = 0;
276         if ((argc < 2) || (argc > 3))
277                 return RESULT_SHOWUSAGE;
278         if (argc > 2)
279                 search = argv[2];
280         if (!search) 
281                 ast_cli(fd, "OSP: %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal");
282         
283         ast_mutex_lock(&osplock);
284         osp = providers;
285         while(osp) {
286                 if (!search || !strcasecmp(osp->name, search)) {
287                         if (found)
288                                 ast_cli(fd, "\n");
289                         ast_cli(fd, " == OSP Provider '%s' ==\n", osp->name);
290                         ast_cli(fd, "Local Private Key: %s\n", osp->localpvtkey);
291                         ast_cli(fd, "Local Certificate: %s\n", osp->localcert);
292                         for (x=0;x<osp->cacount;x++)
293                                 ast_cli(fd, "CA Certificate %d:  %s\n", x + 1, osp->cacerts[x]);
294                         for (x=0;x<osp->spcount;x++)
295                                 ast_cli(fd, "Service Point %d:   %s\n", x + 1, osp->servicepoints[x]);
296                         ast_cli(fd, "Max Connections:   %d\n", osp->maxconnections);
297                         ast_cli(fd, "Retry Delay:       %d seconds\n", osp->retrydelay);
298                         ast_cli(fd, "Retry Limit:       %d\n", osp->retrylimit);
299                         ast_cli(fd, "Timeout:           %d milliseconds\n", osp->timeout);
300                         ast_cli(fd, "Source:            %s\n", strlen(osp->source) ? osp->source : "<unspecified>");
301                         ast_cli(fd, "OSP Handle:        %d\n", osp->handle);
302                         found++;
303                 }
304                 osp = osp->next;
305         }
306         ast_mutex_unlock(&osplock);
307         if (!found) {
308                 if (search) 
309                         ast_cli(fd, "Unable to find OSP provider '%s'\n", search);
310                 else
311                         ast_cli(fd, "No OSP providers configured\n");
312         }
313         return RESULT_SUCCESS;
314 }
315
316
317 /*----------------------------------------------*
318  *               Loads the Certificate          *
319  *----------------------------------------------*/
320 static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len)
321 {
322     int length = 0;
323     unsigned char *temp;
324     BIO *bioIn = NULL;
325     X509 *cert=NULL;
326     int retVal = OSPC_ERR_NO_ERROR;
327
328     temp = buffer;
329     bioIn = BIO_new_file((const char*)FileName,"r");
330     if (bioIn == NULL)
331     {
332                 ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
333                 return -1;
334     }
335     else
336     {
337         cert = PEM_read_bio_X509(bioIn,NULL,NULL,NULL);
338         if (cert == NULL)
339         {
340                         ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s \n",FileName);
341                         return -1;
342         }
343         else
344         {
345             length = i2d_X509(cert,&temp);
346             if (cert == 0)
347             {
348                                 ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s, Length=0 \n",FileName);
349                                 return -1;
350             }
351             else
352                         {
353                *len = length;
354             }
355         }
356     }
357
358     if (bioIn != NULL)
359     {
360         BIO_free(bioIn);
361     }
362
363     if (cert != NULL)
364     {
365         X509_free(cert);
366     }
367     return retVal;
368 }
369
370 /*----------------------------------------------*
371  *               Loads the Private Key          *
372  *----------------------------------------------*/
373 static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len)
374 {
375     int length = 0;
376     unsigned char *temp;
377     BIO *bioIn = NULL;
378     RSA *pKey = NULL;
379     int retVal = OSPC_ERR_NO_ERROR;
380
381     temp = buffer;
382
383     bioIn = BIO_new_file((const char*)FileName,"r");
384     if (bioIn == NULL)
385     {
386                 ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
387                 return -1;
388     }
389     else
390     {
391         pKey = PEM_read_bio_RSAPrivateKey(bioIn,NULL,NULL,NULL);
392         if (pKey == NULL)
393         {
394                         ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s \n",FileName);
395                         return -1;
396         }
397         else
398         {
399             length = i2d_RSAPrivateKey(pKey,&temp);
400             if (length == 0)
401             {
402                                 ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s, Length=0 \n",FileName);
403                                 return -1;
404             }
405             else
406             {
407                 *len = length;
408             }
409         }
410     }
411     if (bioIn != NULL)
412     {
413         BIO_free(bioIn);
414     }
415
416     if (pKey != NULL)
417     {
418        RSA_free(pKey);
419     }
420     return retVal;
421 }
422
423 int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result)
424 {
425         int cres;
426         int res = 0;
427         int counts;
428         int tokenlen;
429         unsigned int dummy=0;
430         unsigned int timelimit;
431         unsigned int callidlen;
432         struct osp_provider *osp;
433         char source[OSP_MAX]; /* Same length as osp->source */
434         char uniqueid[32] = "";
435         char callednum[2048]="";
436         char destination[2048]="";
437         char token[2000];
438         char tmp[256]="", *l, *n;
439         OSPTCALLID *callid;
440         OSPE_DEST_PROT prot;
441
442         result->handle = -1;
443         result->numresults = 0;
444         strcpy(result->tech, "");
445         strcpy(result->dest, "");
446         strcpy(result->token, "");
447
448         if (!provider || !strlen(provider))
449                 provider = "default";
450
451         if (!callerid)
452                 callerid = "";
453         strncpy(tmp, callerid, sizeof(tmp) - 1);
454         ast_callerid_parse(tmp, &n, &l);
455         if (!l)
456                 l = "";
457         else {
458                 ast_shrink_phone_number(l);
459                 if (!ast_isphonenumber(l))
460                         l = "";
461         }
462         callerid = l;
463
464         if (chan) {
465                 strncpy(uniqueid, chan->uniqueid, sizeof(uniqueid) - 1);
466                 cres = ast_autoservice_start(chan);
467                 if (cres < 0)
468                         return cres;
469         }
470         ast_mutex_lock(&osplock);
471         osp = providers;
472         while(osp) {
473                 if (!strcasecmp(osp->name, provider)) {
474                         if (OSPPTransactionNew(osp->handle, &result->handle)) {
475                                 ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
476                         } else {
477                                 strcpy(source, osp->source);
478                                 res = 1;
479                         }
480                         break;
481                 }
482                 osp = osp->next;
483         }
484         ast_mutex_unlock(&osplock);
485         if (res) {
486                 res = 0;
487                 callid = OSPPCallIdNew(strlen(uniqueid), uniqueid);
488                 if (callid) {
489                         /* No more than 10 back */
490                         counts = 10;
491                         dummy = 0;
492                         callidlen = sizeof(uniqueid);
493                         if (!OSPPTransactionRequestAuthorisation(result->handle, source, "", 
494                                   callerid,OSPC_E164, extension, OSPC_E164, NULL, 1, &callid, NULL, &counts, &dummy, NULL)) {
495                                 if (counts) {
496                                         tokenlen = sizeof(token);
497                                         result->numresults = counts - 1;
498                                         if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, uniqueid, 
499                                                 sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
500                                                 ast_log(LOG_DEBUG, "Got destination '%s' and '%s' for '%s' (provider '%s')\n",
501                                                         destination, callednum, extension, provider);
502                                                 do {
503                                                         ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
504                                                         if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
505                                                                 res = 1;
506                                                                 /* Strip leading and trailing brackets */
507                                                                 destination[strlen(destination) - 1] = '\0';
508                                                                 switch(prot) {
509                                                                 case OSPE_DEST_PROT_H323_SETUP:
510                                                                         strcpy(result->tech, "H323");
511                                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
512                                                                         break;
513                                                                 case OSPE_DEST_PROT_SIP:
514                                                                         strcpy(result->tech, "SIP");
515                                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
516                                                                         break;
517                                                                 default:
518                                                                         ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
519                                                                         res = 0;
520                                                                 }
521                                                                 if (!res && result->numresults) {
522                                                                         result->numresults--;
523                                                                         if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid, 
524                                                                                         sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
525                                                                                         break;
526                                                                         }
527                                                                 }
528                                                         } else {
529                                                                 ast_log(LOG_DEBUG, "Missing destination protocol\n");
530                                                                 break;
531                                                         }
532                                                 } while(!res && result->numresults);
533                                         }
534                                 }
535                                 
536                         }
537                         OSPPCallIdDelete(&callid);
538                 }
539                 if (!res) {
540                         OSPPTransactionDelete(result->handle);
541                         result->handle = -1;
542                 }
543                 
544         }
545         if (!osp) 
546                 ast_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider);
547         if (chan) {
548                 cres = ast_autoservice_stop(chan);
549                 if (cres < 0)
550                         return cres;
551         }
552         return res;
553 }
554
555 int ast_osp_next(struct ast_osp_result *result, int cause)
556 {
557         int res = 0;
558         int tokenlen;
559         unsigned int dummy=0;
560         unsigned int timelimit;
561         unsigned int callidlen;
562         char uniqueid[32] = "";
563         char callednum[2048]="";
564         char destination[2048]="";
565         char token[2000];
566         OSPE_DEST_PROT prot;
567
568         strcpy(result->tech, "");
569         strcpy(result->dest, "");
570         strcpy(result->token, "");
571
572         if (result->handle > -1) {
573                 dummy = 0;
574                 callidlen = sizeof(uniqueid);
575                 if (result->numresults) {
576                         tokenlen = sizeof(token);
577                         while(!res && result->numresults) {
578                                 result->numresults--;
579                                 if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid, 
580                                                                         sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
581                                         ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
582                                         if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
583                                                 res = 1;
584                                                 /* Strip leading and trailing brackets */
585                                                 destination[strlen(destination) - 1] = '\0';
586                                                 switch(prot) {
587                                                 case OSPE_DEST_PROT_H323_SETUP:
588                                                         strcpy(result->tech, "H323");
589                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
590                                                         break;
591                                                 case OSPE_DEST_PROT_SIP:
592                                                         strcpy(result->tech, "SIP");
593                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
594                                                         break;
595                                                 default:
596                                                         ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
597                                                         res = 0;
598                                                 }
599                                         } else {
600                                                 ast_log(LOG_DEBUG, "Missing destination protocol\n");
601                                                 break;
602                                         }
603                                 }
604                         }
605                         
606                 }
607                 if (!res) {
608                         OSPPTransactionDelete(result->handle);
609                         result->handle = -1;
610                 }
611                 
612         }
613         return res;
614 }
615
616 static enum OSPEFAILREASON cause2reason(int cause)
617 {
618         switch(cause) {
619         case AST_CAUSE_BUSY:
620                 return OSPC_FAIL_USER_BUSY;
621         case AST_CAUSE_CONGESTION:
622                 return OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION;
623         case AST_CAUSE_UNALLOCATED:
624                 return OSPC_FAIL_UNALLOC_NUMBER;
625         case AST_CAUSE_NOTDEFINED:
626                 return OSPC_FAIL_NORMAL_UNSPECIFIED;
627         case AST_CAUSE_NOANSWER:
628                 return OSPC_FAIL_NO_ANSWER_FROM_USER;
629         case AST_CAUSE_NORMAL:
630         default:
631                 return OSPC_FAIL_NORMAL_CALL_CLEARING;
632         }
633 }
634
635 int ast_osp_terminate(int handle, int cause, time_t start, time_t duration)
636 {
637         unsigned int dummy = 0;
638         int res = -1;
639         enum OSPEFAILREASON reason;
640         reason = cause2reason(cause);
641         if (OSPPTransactionRecordFailure(handle, reason))
642                 ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle);
643         else if (OSPPTransactionReportUsage(handle, duration, start, 0, 0, 0, 0, &dummy, NULL))
644                 ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle);
645         else {
646                 ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle);
647                 OSPPTransactionDelete(handle);
648                 res = 0;
649         }
650         return res;
651 }
652
653 static int config_load(void)
654 {
655         struct ast_config *cfg;
656         char *cat;
657         struct osp_provider *osp, *prev = NULL, *next;
658         ast_mutex_lock(&osplock);
659         osp = providers;
660         while(osp) {
661                 osp->dead = 1;
662                 osp = osp->next;
663         }
664         ast_mutex_unlock(&osplock);
665         cfg = ast_load("osp.conf");
666         if (cfg) {
667                 if (!initialized) {
668                         cat = ast_variable_retrieve(cfg, "general", "accelerate");
669                         if (cat && ast_true(cat))
670                                 if (OSPPInit(1)) {
671                                         ast_log(LOG_WARNING, "Failed to enable hardware accelleration, falling back to software mode\n");
672                                         OSPPInit(0);
673                                 } else
674                                         hardware = 1;
675                         else
676                                 OSPPInit(0);
677                         initialized = 1;
678                 }
679                 cat = ast_category_browse(cfg, NULL);
680                 while(cat) {
681                         if (strcasecmp(cat, "general"))
682                                 osp_build(cfg, cat);
683                         cat = ast_category_browse(cfg, cat);
684                 }
685                 ast_destroy(cfg);
686         } else
687                 ast_log(LOG_NOTICE, "No OSP configuration found.  OSP support disabled\n");
688         ast_mutex_lock(&osplock);
689         osp = providers;
690         while(osp) {
691                 next = osp->next;
692                 if (osp->dead) {
693                         if (prev)
694                                 prev->next = next;
695                         else
696                                 providers = next;
697                         /* XXX Cleanup OSP structure first XXX */
698                         free(osp);
699                 } else 
700                         prev = osp;
701                 osp = next;
702         }
703         ast_mutex_unlock(&osplock);
704         return 0;
705 }
706
707 static char show_osp_usage[] = 
708 "Usage: show osp\n"
709 "       Displays information on Open Settlement Protocol\n";
710
711 static struct ast_cli_entry cli_show_osp = 
712 { { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage };
713
714 int reload(void)
715 {
716         config_load();
717         ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n");
718         return 0;
719 }
720
721 int load_module(void)
722 {
723         config_load();
724         ast_cli_register(&cli_show_osp);
725         return 0;
726 }
727
728 int unload_module(void)
729 {
730         /* Can't unload this once we're loaded */
731         return -1;
732 }
733
734 char *description(void)
735 {
736         return "Open Settlement Protocol Support";
737 }
738
739 int usecount(void)
740 {
741         /* We should never be unloaded */
742         return 1;
743 }
744
745 char *key()
746 {
747         return ASTERISK_GPL_KEY;
748 }