(closes issue #12846)
[asterisk-bristuff.git] / apps / app_osplookup.c
blobad2ce506528064f60b72c2031349a74c2f223596
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*!
20 * \file
21 * \brief Open Settlement Protocol (OSP) Applications
23 * \author Mark Spencer <markster@digium.com>
25 * \ingroup applications
28 /*** MODULEINFO
29 <depend>osptk</depend>
30 <depend>ssl</depend>
31 ***/
33 #include "asterisk.h"
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37 #include <sys/types.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <osp/osp.h>
43 #include <osp/osputils.h>
45 #include "asterisk/lock.h"
46 #include "asterisk/config.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/causes.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/app.h"
51 #include "asterisk/module.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/options.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/logger.h"
56 #include "asterisk/astosp.h"
58 /* OSP Buffer Sizes */
59 #define OSP_INTSTR_SIZE ((unsigned int)16) /* OSP signed/unsigned int string buffer size */
60 #define OSP_NORSTR_SIZE ((unsigned int)256) /* OSP normal string buffer size */
61 #define OSP_TOKSTR_SIZE ((unsigned int)4096) /* OSP token string buffer size */
63 /* OSP Constants */
64 #define OSP_INVALID_HANDLE ((int)-1) /* Invalid OSP handle, provider, transaction etc. */
65 #define OSP_CONFIG_FILE ((const char*)"osp.conf") /* OSP configuration file name */
66 #define OSP_GENERAL_CAT ((const char*)"general") /* OSP global configuration context name */
67 #define OSP_DEF_PROVIDER ((const char*)"default") /* OSP default provider context name */
68 #define OSP_MAX_CERTS ((unsigned int)10) /* OSP max number of cacerts */
69 #define OSP_MAX_SRVS ((unsigned int)10) /* OSP max number of service points */
70 #define OSP_DEF_MAXCONNECTIONS ((unsigned int)20) /* OSP default max_connections */
71 #define OSP_MIN_MAXCONNECTIONS ((unsigned int)1) /* OSP min max_connections */
72 #define OSP_MAX_MAXCONNECTIONS ((unsigned int)1000) /* OSP max max_connections */
73 #define OSP_DEF_RETRYDELAY ((unsigned int)0) /* OSP default retry delay */
74 #define OSP_MIN_RETRYDELAY ((unsigned int)0) /* OSP min retry delay */
75 #define OSP_MAX_RETRYDELAY ((unsigned int)10) /* OSP max retry delay */
76 #define OSP_DEF_RETRYLIMIT ((unsigned int)2) /* OSP default retry times */
77 #define OSP_MIN_RETRYLIMIT ((unsigned int)0) /* OSP min retry times */
78 #define OSP_MAX_RETRYLIMIT ((unsigned int)100) /* OSP max retry times */
79 #define OSP_DEF_TIMEOUT ((unsigned int)500) /* OSP default timeout in ms */
80 #define OSP_MIN_TIMEOUT ((unsigned int)200) /* OSP min timeout in ms */
81 #define OSP_MAX_TIMEOUT ((unsigned int)10000) /* OSP max timeout in ms */
82 #define OSP_DEF_AUTHPOLICY ((enum osp_authpolicy)OSP_AUTH_YES)
83 #define OSP_AUDIT_URL ((const char*)"localhost") /* OSP default Audit URL */
84 #define OSP_LOCAL_VALIDATION ((int)1) /* Validate OSP token locally */
85 #define OSP_SSL_LIFETIME ((unsigned int)300) /* SSL life time, in seconds */
86 #define OSP_HTTP_PERSISTENCE ((int)1) /* In seconds */
87 #define OSP_CUSTOMER_ID ((const char*)"") /* OSP customer ID */
88 #define OSP_DEVICE_ID ((const char*)"") /* OSP device ID */
89 #define OSP_DEF_DESTINATIONS ((unsigned int)5) /* OSP default max number of destinations */
90 #define OSP_DEF_TIMELIMIT ((unsigned int)0) /* OSP default duration limit, no limit */
92 /* OSP Authentication Policy */
93 enum osp_authpolicy {
94 OSP_AUTH_NO, /* Accept any call */
95 OSP_AUTH_YES, /* Accept call with valid OSP token or without OSP token */
96 OSP_AUTH_EXCLUSIVE /* Only accept call with valid OSP token */
99 /* OSP Provider */
100 struct osp_provider {
101 char name[OSP_NORSTR_SIZE]; /* OSP provider context name */
102 char privatekey[OSP_NORSTR_SIZE]; /* OSP private key file name */
103 char localcert[OSP_NORSTR_SIZE]; /* OSP local cert file name */
104 unsigned int cacount; /* Number of cacerts */
105 char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE]; /* Cacert file names */
106 unsigned int spcount; /* Number of service points */
107 char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE]; /* Service point URLs */
108 int maxconnections; /* Max number of connections */
109 int retrydelay; /* Retry delay */
110 int retrylimit; /* Retry limit */
111 int timeout; /* Timeout in ms */
112 char source[OSP_NORSTR_SIZE]; /* IP of self */
113 enum osp_authpolicy authpolicy; /* OSP authentication policy */
114 OSPTPROVHANDLE handle; /* OSP provider handle */
115 struct osp_provider* next; /* Pointer to next OSP provider */
118 /* OSP Application In/Output Results */
119 struct osp_result {
120 int inhandle; /* Inbound transaction handle */
121 int outhandle; /* Outbound transaction handle */
122 unsigned int intimelimit; /* Inbound duration limit */
123 unsigned int outtimelimit; /* Outbound duration limit */
124 char tech[20]; /* Asterisk TECH string */
125 char dest[OSP_NORSTR_SIZE]; /* Destination in called@IP format */
126 char calling[OSP_NORSTR_SIZE]; /* Calling number, may be translated */
127 char token[OSP_TOKSTR_SIZE]; /* Outbound OSP token */
128 unsigned int numresults; /* Number of remain destinations */
131 /* OSP Module Global Variables */
132 AST_MUTEX_DEFINE_STATIC(osplock); /* Lock of OSP provider list */
133 static int osp_initialized = 0; /* Init flag */
134 static int osp_hardware = 0; /* Hardware accelleration flag */
135 static struct osp_provider* ospproviders = NULL; /* OSP provider list */
136 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED; /* Token format supported */
138 /* OSP Client Wrapper APIs */
141 * \brief Create OSP provider handle according to configuration
142 * \param cfg OSP configuration
143 * \param provider OSP provider context name
144 * \return 1 Success, 0 Failed, -1 Error
146 static int osp_create_provider(struct ast_config* cfg, const char* provider)
148 int res;
149 unsigned int t, i, j;
150 struct osp_provider* p;
151 struct ast_variable* v;
152 OSPTPRIVATEKEY privatekey;
153 OSPTCERT localcert;
154 const char* psrvpoints[OSP_MAX_SRVS];
155 OSPTCERT cacerts[OSP_MAX_CERTS];
156 const OSPTCERT* pcacerts[OSP_MAX_CERTS];
157 int error = OSPC_ERR_NO_ERROR;
159 if (!(p = ast_calloc(1, sizeof(*p)))) {
160 ast_log(LOG_ERROR, "Out of memory\n");
161 return -1;
164 ast_copy_string(p->name, provider, sizeof(p->name));
165 snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
166 snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
167 p->maxconnections = OSP_DEF_MAXCONNECTIONS;
168 p->retrydelay = OSP_DEF_RETRYDELAY;
169 p->retrylimit = OSP_DEF_RETRYLIMIT;
170 p->timeout = OSP_DEF_TIMEOUT;
171 p->authpolicy = OSP_DEF_AUTHPOLICY;
172 p->handle = OSP_INVALID_HANDLE;
174 v = ast_variable_browse(cfg, provider);
175 while(v) {
176 if (!strcasecmp(v->name, "privatekey")) {
177 if (v->value[0] == '/') {
178 ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
179 } else {
180 snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
182 ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey);
183 } else if (!strcasecmp(v->name, "localcert")) {
184 if (v->value[0] == '/') {
185 ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
186 } else {
187 snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
189 ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert);
190 } else if (!strcasecmp(v->name, "cacert")) {
191 if (p->cacount < OSP_MAX_CERTS) {
192 if (v->value[0] == '/') {
193 ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
194 } else {
195 snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
197 ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
198 p->cacount++;
199 } else {
200 ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
202 } else if (!strcasecmp(v->name, "servicepoint")) {
203 if (p->spcount < OSP_MAX_SRVS) {
204 ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
205 ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
206 p->spcount++;
207 } else {
208 ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
210 } else if (!strcasecmp(v->name, "maxconnections")) {
211 if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
212 p->maxconnections = t;
213 ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t);
214 } else {
215 ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n",
216 OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
218 } else if (!strcasecmp(v->name, "retrydelay")) {
219 if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
220 p->retrydelay = t;
221 ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t);
222 } else {
223 ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n",
224 OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
226 } else if (!strcasecmp(v->name, "retrylimit")) {
227 if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
228 p->retrylimit = t;
229 ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t);
230 } else {
231 ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n",
232 OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
234 } else if (!strcasecmp(v->name, "timeout")) {
235 if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
236 p->timeout = t;
237 ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t);
238 } else {
239 ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n",
240 OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
242 } else if (!strcasecmp(v->name, "source")) {
243 ast_copy_string(p->source, v->value, sizeof(p->source));
244 ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source);
245 } else if (!strcasecmp(v->name, "authpolicy")) {
246 if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
247 p->authpolicy = t;
248 ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t);
249 } else {
250 ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n",
251 OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
254 v = v->next;
257 error = OSPPUtilLoadPEMPrivateKey((unsigned char *) p->privatekey, &privatekey);
258 if (error != OSPC_ERR_NO_ERROR) {
259 ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
260 free(p);
261 return 0;
264 error = OSPPUtilLoadPEMCert((unsigned char *) p->localcert, &localcert);
265 if (error != OSPC_ERR_NO_ERROR) {
266 ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
267 if (privatekey.PrivateKeyData) {
268 free(privatekey.PrivateKeyData);
270 free(p);
271 return 0;
274 if (p->cacount < 1) {
275 snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
276 ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
277 p->cacount++;
279 for (i = 0; i < p->cacount; i++) {
280 error = OSPPUtilLoadPEMCert((unsigned char *) p->cacerts[i], &cacerts[i]);
281 if (error != OSPC_ERR_NO_ERROR) {
282 ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
283 for (j = 0; j < i; j++) {
284 if (cacerts[j].CertData) {
285 free(cacerts[j].CertData);
288 if (localcert.CertData) {
289 free(localcert.CertData);
291 if (privatekey.PrivateKeyData) {
292 free(privatekey.PrivateKeyData);
294 free(p);
295 return 0;
297 pcacerts[i] = &cacerts[i];
300 for (i = 0; i < p->spcount; i++) {
301 psrvpoints[i] = p->srvpoints[i];
304 error = OSPPProviderNew(p->spcount, psrvpoints, NULL, OSP_AUDIT_URL, &privatekey, &localcert, p->cacount, pcacerts, OSP_LOCAL_VALIDATION,
305 OSP_SSL_LIFETIME, p->maxconnections, OSP_HTTP_PERSISTENCE, p->retrydelay, p->retrylimit,p->timeout, OSP_CUSTOMER_ID,
306 OSP_DEVICE_ID, &p->handle);
307 if (error != OSPC_ERR_NO_ERROR) {
308 ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
309 free(p);
310 res = -1;
311 } else {
312 ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider);
313 ast_mutex_lock(&osplock);
314 p->next = ospproviders;
315 ospproviders = p;
316 ast_mutex_unlock(&osplock);
317 res = 1;
320 for (i = 0; i < p->cacount; i++) {
321 if (cacerts[i].CertData) {
322 free(cacerts[i].CertData);
325 if (localcert.CertData) {
326 free(localcert.CertData);
328 if (privatekey.PrivateKeyData) {
329 free(privatekey.PrivateKeyData);
332 return res;
336 * \brief Get OSP authenticiation policy of provider
337 * \param provider OSP provider context name
338 * \param policy OSP authentication policy, output
339 * \return 1 Success, 0 Failed, -1 Error
341 static int osp_get_policy(const char* provider, int* policy)
343 int res = 0;
344 struct osp_provider* p;
346 ast_mutex_lock(&osplock);
347 p = ospproviders;
348 while(p) {
349 if (!strcasecmp(p->name, provider)) {
350 *policy = p->authpolicy;
351 ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", *policy);
352 res = 1;
353 break;
355 p = p->next;
357 ast_mutex_unlock(&osplock);
359 return res;
363 * \brief Create OSP transaction handle
364 * \param provider OSP provider context name
365 * \param transaction OSP transaction handle, output
366 * \param sourcesize Size of source buffer, in/output
367 * \param source Source of provider, output
368 * \return 1 Success, 0 Failed, -1 Error
370 static int osp_create_transaction(const char* provider, int* transaction, unsigned int sourcesize, char* source)
372 int res = 0;
373 struct osp_provider* p;
374 int error;
376 ast_mutex_lock(&osplock);
377 p = ospproviders;
378 while(p) {
379 if (!strcasecmp(p->name, provider)) {
380 error = OSPPTransactionNew(p->handle, transaction);
381 if (error == OSPC_ERR_NO_ERROR) {
382 ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction);
383 ast_copy_string(source, p->source, sourcesize);
384 ast_log(LOG_DEBUG, "OSP: source '%s'\n", source);
385 res = 1;
386 } else {
387 *transaction = OSP_INVALID_HANDLE;
388 ast_log(LOG_DEBUG, "OSP: Unable to create transaction handle, error '%d'\n", error);
389 res = -1;
391 break;
393 p = p->next;
395 ast_mutex_unlock(&osplock);
397 return res;
401 * \brief Convert address to "[x.x.x.x]" or "host.domain" format
402 * \param src Source address string
403 * \param dst Destination address string
404 * \param buffersize Size of dst buffer
406 static void osp_convert_address(
407 const char* src,
408 char* dst,
409 int buffersize)
411 struct in_addr inp;
413 if (inet_aton(src, &inp) != 0) {
414 snprintf(dst, buffersize, "[%s]", src);
415 } else {
416 snprintf(dst, buffersize, "%s", src);
421 * \brief Validate OSP token of inbound call
422 * \param transaction OSP transaction handle
423 * \param source Source of inbound call
424 * \param dest Destination of inbound call
425 * \param calling Calling number
426 * \param called Called number
427 * \param token OSP token, may be empty
428 * \param timelimit Call duration limit, output
429 * \return 1 Success, 0 Failed, -1 Error
431 static int osp_validate_token(int transaction, const char* source, const char* dest, const char* calling, const char* called, const char* token, unsigned int* timelimit)
433 int res;
434 int tokenlen;
435 unsigned char tokenstr[OSP_TOKSTR_SIZE];
436 char src[OSP_NORSTR_SIZE];
437 char dst[OSP_NORSTR_SIZE];
438 unsigned int authorised;
439 unsigned int dummy = 0;
440 int error;
442 tokenlen = ast_base64decode(tokenstr, token, strlen(token));
443 osp_convert_address(source, src, sizeof(src));
444 osp_convert_address(dest, dst, sizeof(dst));
445 error = OSPPTransactionValidateAuthorisation(
446 transaction,
447 src, dst, NULL, NULL,
448 calling ? calling : "", OSPC_E164,
449 called, OSPC_E164,
450 0, NULL,
451 tokenlen, (char *) tokenstr,
452 &authorised,
453 timelimit,
454 &dummy, NULL,
455 osp_tokenformat);
456 if (error != OSPC_ERR_NO_ERROR) {
457 ast_log(LOG_DEBUG, "OSP: Unable to validate inbound token\n");
458 res = -1;
459 } else if (authorised) {
460 ast_log(LOG_DEBUG, "OSP: Authorised\n");
461 res = 1;
462 } else {
463 ast_log(LOG_DEBUG, "OSP: Unauthorised\n");
464 res = 0;
467 return res;
471 * \brief Choose min duration limit
472 * \param in Inbound duration limit
473 * \param out Outbound duration limit
474 * \return min duration limit
476 static unsigned int osp_choose_timelimit(unsigned int in, unsigned int out)
478 if (in == OSP_DEF_TIMELIMIT) {
479 return out;
480 } else if (out == OSP_DEF_TIMELIMIT) {
481 return in;
482 } else {
483 return in < out ? in : out;
488 * \brief Choose min duration limit
489 * \param called Called number
490 * \param calling Calling number
491 * \param destination Destination IP in '[x.x.x.x]' format
492 * \param tokenlen OSP token length
493 * \param token OSP token
494 * \param reason Failure reason, output
495 * \param result OSP lookup results, in/output
496 * \return 1 Success, 0 Failed, -1 Error
498 static int osp_check_destination(const char* called, const char* calling, char* destination, unsigned int tokenlen, const char* token, enum OSPEFAILREASON* reason, struct osp_result* result)
500 int res;
501 OSPE_DEST_OSP_ENABLED enabled;
502 OSPE_DEST_PROT protocol;
503 int error;
505 if (strlen(destination) <= 2) {
506 ast_log(LOG_DEBUG, "OSP: Wrong destination format '%s'\n", destination);
507 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
508 return -1;
511 if ((error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
512 ast_log(LOG_DEBUG, "OSP: Unable to get destination OSP version, error '%d'\n", error);
513 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
514 return -1;
517 if (enabled == OSPE_OSP_FALSE) {
518 result->token[0] = '\0';
519 } else {
520 ast_base64encode(result->token, (const unsigned char *) token, tokenlen, sizeof(result->token) - 1);
523 if ((error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
524 ast_log(LOG_DEBUG, "OSP: Unable to get destination protocol, error '%d'\n", error);
525 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
526 result->token[0] = '\0';
527 return -1;
530 res = 1;
531 /* Strip leading and trailing brackets */
532 destination[strlen(destination) - 1] = '\0';
533 switch(protocol) {
534 case OSPE_DEST_PROT_H323_SETUP:
535 ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
536 ast_copy_string(result->tech, "H323", sizeof(result->tech));
537 snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
538 ast_copy_string(result->calling, calling, sizeof(result->calling));
539 break;
540 case OSPE_DEST_PROT_SIP:
541 ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
542 ast_copy_string(result->tech, "SIP", sizeof(result->tech));
543 snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
544 ast_copy_string(result->calling, calling, sizeof(result->calling));
545 break;
546 case OSPE_DEST_PROT_IAX:
547 ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
548 ast_copy_string(result->tech, "IAX", sizeof(result->tech));
549 snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
550 ast_copy_string(result->calling, calling, sizeof(result->calling));
551 break;
552 default:
553 ast_log(LOG_DEBUG, "OSP: Unknown protocol '%d'\n", protocol);
554 *reason = OSPC_FAIL_PROTOCOL_ERROR;
555 result->token[0] = '\0';
556 res = 0;
559 return res;
563 * \brief Convert Asterisk status to TC code
564 * \param cause Asterisk hangup cause
565 * \return OSP TC code
567 static enum OSPEFAILREASON asterisk2osp(int cause)
569 return (enum OSPEFAILREASON)cause;
573 * \brief OSP Authentication function
574 * \param provider OSP provider context name
575 * \param transaction OSP transaction handle, output
576 * \param source Source of inbound call
577 * \param calling Calling number
578 * \param called Called number
579 * \param token OSP token, may be empty
580 * \param timelimit Call duration limit, output
581 * \return 1 Authenricated, 0 Unauthenticated, -1 Error
583 static int osp_auth(const char* provider, int* transaction, const char* source, const char* calling, const char* called, const char* token, unsigned int* timelimit)
585 int res;
586 int policy = OSP_AUTH_YES;
587 char dest[OSP_NORSTR_SIZE];
589 *transaction = OSP_INVALID_HANDLE;
590 *timelimit = OSP_DEF_TIMELIMIT;
591 res = osp_get_policy(provider, &policy);
592 if (!res) {
593 ast_log(LOG_DEBUG, "OSP: Unabe to find OSP authentication policy\n");
594 return res;
597 switch (policy) {
598 case OSP_AUTH_NO:
599 res = 1;
600 break;
601 case OSP_AUTH_EXCLUSIVE:
602 if (ast_strlen_zero(token)) {
603 res = 0;
604 } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
605 ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
606 *transaction = OSP_INVALID_HANDLE;
607 res = 0;
608 } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
609 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
611 break;
612 case OSP_AUTH_YES:
613 default:
614 if (ast_strlen_zero(token)) {
615 res = 1;
616 } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
617 ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
618 *transaction = OSP_INVALID_HANDLE;
619 res = 0;
620 } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
621 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
623 break;
626 return res;
630 * \brief OSP Lookup function
631 * \param provider OSP provider context name
632 * \param srcdev Source device of outbound call
633 * \param calling Calling number
634 * \param called Called number
635 * \param result Lookup results
636 * \return 1 Found , 0 No route, -1 Error
638 static int osp_lookup(const char* provider, const char* srcdev, const char* calling, const char* called, struct osp_result* result)
640 int res;
641 char source[OSP_NORSTR_SIZE];
642 unsigned int callidlen;
643 char callid[OSPC_CALLID_MAXSIZE];
644 char callingnum[OSP_NORSTR_SIZE];
645 char callednum[OSP_NORSTR_SIZE];
646 char destination[OSP_NORSTR_SIZE];
647 unsigned int tokenlen;
648 char token[OSP_TOKSTR_SIZE];
649 char src[OSP_NORSTR_SIZE];
650 char dev[OSP_NORSTR_SIZE];
651 unsigned int dummy = 0;
652 enum OSPEFAILREASON reason;
653 int error;
655 result->outhandle = OSP_INVALID_HANDLE;
656 result->tech[0] = '\0';
657 result->dest[0] = '\0';
658 result->calling[0] = '\0';
659 result->token[0] = '\0';
660 result->numresults = 0;
661 result->outtimelimit = OSP_DEF_TIMELIMIT;
663 if ((res = osp_create_transaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
664 ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
665 result->outhandle = OSP_INVALID_HANDLE;
666 if (result->inhandle != OSP_INVALID_HANDLE) {
667 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
669 return -1;
672 osp_convert_address(source, src, sizeof(src));
673 osp_convert_address(srcdev, dev, sizeof(dev));
674 result->numresults = OSP_DEF_DESTINATIONS;
675 error = OSPPTransactionRequestAuthorisation(result->outhandle, src, dev, calling ? calling : "",
676 OSPC_E164, called, OSPC_E164, NULL, 0, NULL, NULL, &result->numresults, &dummy, NULL);
677 if (error != OSPC_ERR_NO_ERROR) {
678 ast_log(LOG_DEBUG, "OSP: Unable to request authorization\n");
679 result->numresults = 0;
680 if (result->inhandle != OSP_INVALID_HANDLE) {
681 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
683 return -1;
686 if (!result->numresults) {
687 ast_log(LOG_DEBUG, "OSP: No more destination\n");
688 if (result->inhandle != OSP_INVALID_HANDLE) {
689 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
691 return 0;
694 callidlen = sizeof(callid);
695 tokenlen = sizeof(token);
696 error = OSPPTransactionGetFirstDestination(result->outhandle, 0, NULL, NULL, &result->outtimelimit, &callidlen, callid,
697 sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
698 if (error != OSPC_ERR_NO_ERROR) {
699 ast_log(LOG_DEBUG, "OSP: Unable to get first route\n");
700 result->numresults = 0;
701 result->outtimelimit = OSP_DEF_TIMELIMIT;
702 if (result->inhandle != OSP_INVALID_HANDLE) {
703 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
705 return -1;
708 result->numresults--;
709 result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
710 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
711 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
712 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
713 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
714 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
716 if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
717 return 1;
720 if (!result->numresults) {
721 ast_log(LOG_DEBUG, "OSP: No more destination\n");
722 result->outtimelimit = OSP_DEF_TIMELIMIT;
723 OSPPTransactionRecordFailure(result->outhandle, reason);
724 if (result->inhandle != OSP_INVALID_HANDLE) {
725 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
727 return 0;
730 while(result->numresults) {
731 callidlen = sizeof(callid);
732 tokenlen = sizeof(token);
733 error = OSPPTransactionGetNextDestination(result->outhandle, reason, 0, NULL, NULL, &result->outtimelimit, &callidlen, callid,
734 sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
735 if (error == OSPC_ERR_NO_ERROR) {
736 result->numresults--;
737 result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
738 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
739 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
740 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
741 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
742 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
743 if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
744 break;
745 } else if (!result->numresults) {
746 ast_log(LOG_DEBUG, "OSP: No more destination\n");
747 OSPPTransactionRecordFailure(result->outhandle, reason);
748 if (result->inhandle != OSP_INVALID_HANDLE) {
749 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
751 res = 0;
752 break;
754 } else {
755 ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
756 result->numresults = 0;
757 result->outtimelimit = OSP_DEF_TIMELIMIT;
758 if (result->inhandle != OSP_INVALID_HANDLE) {
759 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
761 res = -1;
762 break;
765 return res;
769 * \brief OSP Lookup Next function
770 * \param cause Asterisk hangup cuase
771 * \param result Lookup results, in/output
772 * \return 1 Found , 0 No route, -1 Error
774 static int osp_next(int cause, struct osp_result* result)
776 int res;
777 unsigned int callidlen;
778 char callid[OSPC_CALLID_MAXSIZE];
779 char callingnum[OSP_NORSTR_SIZE];
780 char callednum[OSP_NORSTR_SIZE];
781 char destination[OSP_NORSTR_SIZE];
782 unsigned int tokenlen;
783 char token[OSP_TOKSTR_SIZE];
784 enum OSPEFAILREASON reason;
785 int error;
787 result->tech[0] = '\0';
788 result->dest[0] = '\0';
789 result->calling[0] = '\0';
790 result->token[0] = '\0';
791 result->outtimelimit = OSP_DEF_TIMELIMIT;
793 if (result->outhandle == OSP_INVALID_HANDLE) {
794 ast_log(LOG_DEBUG, "OSP: Transaction handle undefined\n");
795 result->numresults = 0;
796 if (result->inhandle != OSP_INVALID_HANDLE) {
797 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
799 return -1;
802 reason = asterisk2osp(cause);
804 if (!result->numresults) {
805 ast_log(LOG_DEBUG, "OSP: No more destination\n");
806 OSPPTransactionRecordFailure(result->outhandle, reason);
807 if (result->inhandle != OSP_INVALID_HANDLE) {
808 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
810 return 0;
813 while(result->numresults) {
814 callidlen = sizeof(callid);
815 tokenlen = sizeof(token);
816 error = OSPPTransactionGetNextDestination(result->outhandle, reason, 0, NULL, NULL, &result->outtimelimit, &callidlen,
817 callid, sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
818 if (error == OSPC_ERR_NO_ERROR) {
819 result->numresults--;
820 result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
821 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
822 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
823 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
824 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
825 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
826 if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
827 res = 1;
828 break;
829 } else if (!result->numresults) {
830 ast_log(LOG_DEBUG, "OSP: No more destination\n");
831 OSPPTransactionRecordFailure(result->outhandle, reason);
832 if (result->inhandle != OSP_INVALID_HANDLE) {
833 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
835 res = 0;
836 break;
838 } else {
839 ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
840 result->token[0] = '\0';
841 result->numresults = 0;
842 result->outtimelimit = OSP_DEF_TIMELIMIT;
843 if (result->inhandle != OSP_INVALID_HANDLE) {
844 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
846 res = -1;
847 break;
851 return res;
855 * \brief OSP Finish function
856 * \param handle OSP in/outbound transaction handle
857 * \param recorded If failure reason has been recorded
858 * \param cause Asterisk hangup cause
859 * \param start Call start time
860 * \param connect Call connect time
861 * \param end Call end time
862 * \param release Who release first, 0 source, 1 destination
863 * \return 1 Success, 0 Failed, -1 Error
865 static int osp_finish(int handle, int recorded, int cause, time_t start, time_t connect, time_t end, unsigned int release)
867 int res;
868 enum OSPEFAILREASON reason;
869 time_t alert = 0;
870 unsigned isPddInfoPresent = 0;
871 unsigned pdd = 0;
872 unsigned int dummy = 0;
873 int error;
875 if (handle == OSP_INVALID_HANDLE) {
876 return 0;
879 if (!recorded) {
880 reason = asterisk2osp(cause);
881 OSPPTransactionRecordFailure(handle, reason);
884 error = OSPPTransactionReportUsage(handle, difftime(end, connect), start, end, alert, connect, isPddInfoPresent, pdd,
885 release, (unsigned char *) "", 0, 0, 0, 0, &dummy, NULL);
886 if (error == OSPC_ERR_NO_ERROR) {
887 ast_log(LOG_DEBUG, "OSP: Usage reported\n");
888 res = 1;
889 } else {
890 ast_log(LOG_DEBUG, "OSP: Unable to report usage, error '%d'\n", error);
891 res = -1;
893 OSPPTransactionDelete(handle);
895 return res;
898 /* OSP Application APIs */
901 * \brief OSP Application OSPAuth
902 * \param chan Channel
903 * \param data Parameter
904 * \return 0 Success, -1 Failed
906 static int ospauth_exec(struct ast_channel* chan, void* data)
908 int res;
909 struct ast_module_user *u;
910 const char* provider = OSP_DEF_PROVIDER;
911 int priority_jump = 0;
912 struct varshead *headp;
913 struct ast_var_t *current;
914 const char *source = "";
915 const char *token = "";
916 int handle;
917 unsigned int timelimit;
918 char buffer[OSP_INTSTR_SIZE];
919 const char *status;
920 char *tmp;
922 AST_DECLARE_APP_ARGS(args,
923 AST_APP_ARG(provider);
924 AST_APP_ARG(options);
927 u = ast_module_user_add(chan);
929 if (!(tmp = ast_strdupa(data))) {
930 ast_log(LOG_ERROR, "Out of memory\n");
931 ast_module_user_remove(u);
932 return -1;
935 AST_STANDARD_APP_ARGS(args, tmp);
937 if (!ast_strlen_zero(args.provider)) {
938 provider = args.provider;
940 ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider);
942 if ((args.options) && (strchr(args.options, 'j'))) {
943 priority_jump = 1;
945 ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump);
947 headp = &chan->varshead;
948 AST_LIST_TRAVERSE(headp, current, entries) {
949 if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
950 source = ast_var_value(current);
951 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
952 token = ast_var_value(current);
955 ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source);
956 ast_log(LOG_DEBUG, "OSPAuth: token size '%zd'\n", strlen(token));
959 if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
960 status = AST_OSP_SUCCESS;
961 } else {
962 timelimit = OSP_DEF_TIMELIMIT;
963 if (!res) {
964 status = AST_OSP_FAILED;
965 } else {
966 status = AST_OSP_ERROR;
970 snprintf(buffer, sizeof(buffer), "%d", handle);
971 pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
972 ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
973 snprintf(buffer, sizeof(buffer), "%d", timelimit);
974 pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
975 ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
976 pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
977 ast_log(LOG_DEBUG, "OSPAuth: %s\n", status);
979 if(res <= 0) {
980 if (priority_jump || ast_opt_priority_jumping) {
981 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
982 res = 0;
983 } else {
984 res = -1;
986 } else {
987 res = 0;
990 ast_module_user_remove(u);
992 return res;
996 * \brief OSP Application OSPLookup
997 * \param chan Channel
998 * \param data Parameter
999 * \return 0 Success, -1 Failed
1001 static int osplookup_exec(struct ast_channel* chan, void* data)
1003 int res, cres;
1004 struct ast_module_user *u;
1005 const char *provider = OSP_DEF_PROVIDER;
1006 int priority_jump = 0;
1007 struct varshead *headp;
1008 struct ast_var_t* current;
1009 const char *srcdev = "";
1010 char buffer[OSP_TOKSTR_SIZE];
1011 struct osp_result result;
1012 const char *status;
1013 char *tmp;
1015 AST_DECLARE_APP_ARGS(args,
1016 AST_APP_ARG(exten);
1017 AST_APP_ARG(provider);
1018 AST_APP_ARG(options);
1021 if (ast_strlen_zero(data)) {
1022 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
1023 return -1;
1026 u = ast_module_user_add(chan);
1028 if (!(tmp = ast_strdupa(data))) {
1029 ast_log(LOG_ERROR, "Out of memory\n");
1030 ast_module_user_remove(u);
1031 return -1;
1034 AST_STANDARD_APP_ARGS(args, tmp);
1036 ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten);
1038 if (!ast_strlen_zero(args.provider)) {
1039 provider = args.provider;
1041 ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
1043 if ((args.options) && (strchr(args.options, 'j'))) {
1044 priority_jump = 1;
1046 ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump);
1048 result.inhandle = OSP_INVALID_HANDLE;
1049 result.intimelimit = OSP_DEF_TIMELIMIT;
1051 headp = &chan->varshead;
1052 AST_LIST_TRAVERSE(headp, current, entries) {
1053 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1054 if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1055 result.inhandle = OSP_INVALID_HANDLE;
1057 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1058 if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1059 result.intimelimit = OSP_DEF_TIMELIMIT;
1061 } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1062 srcdev = ast_var_value(current);
1065 ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
1066 ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1067 ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev);
1069 if ((cres = ast_autoservice_start(chan)) < 0) {
1070 ast_module_user_remove(u);
1071 return -1;
1074 if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, &result)) > 0) {
1075 status = AST_OSP_SUCCESS;
1076 } else {
1077 result.tech[0] = '\0';
1078 result.dest[0] = '\0';
1079 result.calling[0] = '\0';
1080 result.token[0] = '\0';
1081 result.numresults = 0;
1082 result.outtimelimit = OSP_DEF_TIMELIMIT;
1083 if (!res) {
1084 status = AST_OSP_FAILED;
1085 } else {
1086 status = AST_OSP_ERROR;
1090 snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
1091 pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1092 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
1093 pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1094 ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech);
1095 pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1096 ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest);
1097 pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1098 ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling);
1099 pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1100 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1101 snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1102 pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1103 ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer);
1104 snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1105 pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1106 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
1107 pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
1108 ast_log(LOG_DEBUG, "OSPLookup: %s\n", status);
1110 if (!strcasecmp(result.tech, "SIP")) {
1111 if (!ast_strlen_zero(result.token)) {
1112 snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
1113 pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1114 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1116 } else if (!strcasecmp(result.tech, "H323")) {
1117 } else if (!strcasecmp(result.tech, "IAX")) {
1120 if ((cres = ast_autoservice_stop(chan)) < 0) {
1121 ast_module_user_remove(u);
1122 return -1;
1125 if(res <= 0) {
1126 if (priority_jump || ast_opt_priority_jumping) {
1127 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1128 res = 0;
1129 } else {
1130 res = -1;
1132 } else {
1133 res = 0;
1136 ast_module_user_remove(u);
1138 return res;
1142 * \brief OSP Application OSPNext
1143 * \param chan Channel
1144 * \param data Parameter
1145 * \return 0 Success, -1 Failed
1147 static int ospnext_exec(struct ast_channel* chan, void* data)
1149 int res;
1150 struct ast_module_user *u;
1151 int priority_jump = 0;
1152 int cause = 0;
1153 struct varshead* headp;
1154 struct ast_var_t* current;
1155 struct osp_result result;
1156 char buffer[OSP_TOKSTR_SIZE];
1157 const char* status;
1158 char* tmp;
1160 AST_DECLARE_APP_ARGS(args,
1161 AST_APP_ARG(cause);
1162 AST_APP_ARG(options);
1165 if (ast_strlen_zero(data)) {
1166 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|options])\n");
1167 return -1;
1170 u = ast_module_user_add(chan);
1172 if (!(tmp = ast_strdupa(data))) {
1173 ast_log(LOG_ERROR, "Out of memory\n");
1174 ast_module_user_remove(u);
1175 return -1;
1178 AST_STANDARD_APP_ARGS(args, tmp);
1180 if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1181 cause = 0;
1183 ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause);
1185 if ((args.options) && (strchr(args.options, 'j'))) {
1186 priority_jump = 1;
1188 ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump);
1190 result.inhandle = OSP_INVALID_HANDLE;
1191 result.outhandle = OSP_INVALID_HANDLE;
1192 result.intimelimit = OSP_DEF_TIMELIMIT;
1193 result.numresults = 0;
1195 headp = &chan->varshead;
1196 AST_LIST_TRAVERSE(headp, current, entries) {
1197 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1198 if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1199 result.inhandle = OSP_INVALID_HANDLE;
1201 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1202 if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) {
1203 result.outhandle = OSP_INVALID_HANDLE;
1205 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1206 if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1207 result.intimelimit = OSP_DEF_TIMELIMIT;
1209 } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
1210 if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) {
1211 result.numresults = 0;
1215 ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
1216 ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
1217 ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1218 ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
1220 if ((res = osp_next(cause, &result)) > 0) {
1221 status = AST_OSP_SUCCESS;
1222 } else {
1223 result.tech[0] = '\0';
1224 result.dest[0] = '\0';
1225 result.calling[0] = '\0';
1226 result.token[0] = '\0';
1227 result.numresults = 0;
1228 result.outtimelimit = OSP_DEF_TIMELIMIT;
1229 if (!res) {
1230 status = AST_OSP_FAILED;
1231 } else {
1232 status = AST_OSP_ERROR;
1236 pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1237 ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech);
1238 pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1239 ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest);
1240 pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1241 ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling);
1242 pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1243 ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1244 snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1245 pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1246 ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer);
1247 snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1248 pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1249 ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
1250 pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
1251 ast_log(LOG_DEBUG, "OSPNext: %s\n", status);
1253 if (!strcasecmp(result.tech, "SIP")) {
1254 if (!ast_strlen_zero(result.token)) {
1255 snprintf(buffer, sizeof(buffer), "P-OSP-Auth-Token: %s", result.token);
1256 pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1257 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1259 } else if (!strcasecmp(result.tech, "H323")) {
1260 } else if (!strcasecmp(result.tech, "IAX")) {
1263 if(res <= 0) {
1264 if (priority_jump || ast_opt_priority_jumping) {
1265 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1266 res = 0;
1267 } else {
1268 res = -1;
1270 } else {
1271 res = 0;
1274 ast_module_user_remove(u);
1276 return res;
1280 * \brief OSP Application OSPFinish
1281 * \param chan Channel
1282 * \param data Parameter
1283 * \return 0 Success, -1 Failed
1285 static int ospfinished_exec(struct ast_channel* chan, void* data)
1287 int res = 1;
1288 struct ast_module_user *u;
1289 int priority_jump = 0;
1290 int cause = 0;
1291 struct varshead *headp;
1292 struct ast_var_t *current;
1293 int inhandle = OSP_INVALID_HANDLE;
1294 int outhandle = OSP_INVALID_HANDLE;
1295 int recorded = 0;
1296 time_t start, connect, end;
1297 unsigned int release;
1298 char buffer[OSP_INTSTR_SIZE];
1299 const char *status;
1300 char *tmp;
1302 AST_DECLARE_APP_ARGS(args,
1303 AST_APP_ARG(cause);
1304 AST_APP_ARG(options);
1307 u = ast_module_user_add(chan);
1309 if (!(tmp = ast_strdupa(data))) {
1310 ast_log(LOG_ERROR, "Out of memory\n");
1311 ast_module_user_remove(u);
1312 return -1;
1315 AST_STANDARD_APP_ARGS(args, tmp);
1317 if ((args.options) && (strchr(args.options, 'j'))) {
1318 priority_jump = 1;
1320 ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump);
1322 headp = &chan->varshead;
1323 AST_LIST_TRAVERSE(headp, current, entries) {
1324 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1325 if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) {
1326 inhandle = OSP_INVALID_HANDLE;
1328 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1329 if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) {
1330 outhandle = OSP_INVALID_HANDLE;
1332 } else if (!recorded &&
1333 (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
1334 !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
1335 !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
1337 if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
1338 recorded = 1;
1342 ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
1343 ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
1344 ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded);
1346 if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1347 cause = 0;
1349 ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause);
1351 if (chan->cdr) {
1352 start = chan->cdr->start.tv_sec;
1353 connect = chan->cdr->answer.tv_sec;
1354 if (connect) {
1355 end = time(NULL);
1356 } else {
1357 end = connect;
1359 } else {
1360 start = 0;
1361 connect = 0;
1362 end = 0;
1364 ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start);
1365 ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect);
1366 ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end);
1368 release = chan->_softhangup ? 0 : 1;
1370 if (osp_finish(outhandle, recorded, cause, start, connect, end, release) <= 0) {
1371 ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for outbound call\n");
1373 switch (cause) {
1374 case AST_CAUSE_NORMAL_CLEARING:
1375 break;
1376 default:
1377 cause = AST_CAUSE_NO_ROUTE_DESTINATION;
1378 break;
1380 if (osp_finish(inhandle, recorded, cause, start, connect, end, release) <= 0) {
1381 ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for inbound call\n");
1383 snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
1384 pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1385 pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1387 if (res > 0) {
1388 status = AST_OSP_SUCCESS;
1389 } else if (!res) {
1390 status = AST_OSP_FAILED;
1391 } else {
1392 status = AST_OSP_ERROR;
1394 pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
1396 if(!res) {
1397 if (priority_jump || ast_opt_priority_jumping) {
1398 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1399 res = 0;
1400 } else {
1401 res = -1;
1403 } else {
1404 res = 0;
1407 ast_module_user_remove(u);
1409 return res;
1412 /* OSP Module APIs */
1414 static int osp_load(void)
1416 const char* t;
1417 unsigned int v;
1418 struct ast_config* cfg;
1419 int error = OSPC_ERR_NO_ERROR;
1421 cfg = ast_config_load(OSP_CONFIG_FILE);
1422 if (cfg) {
1423 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
1424 if (t && ast_true(t)) {
1425 if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
1426 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
1427 OSPPInit(0);
1428 } else {
1429 osp_hardware = 1;
1431 } else {
1432 OSPPInit(0);
1434 ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware);
1436 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
1437 if (t) {
1438 if ((sscanf(t, "%d", &v) == 1) &&
1439 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH)))
1441 osp_tokenformat = v;
1442 } else {
1443 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
1444 TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
1447 ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
1449 t = ast_category_browse(cfg, NULL);
1450 while(t) {
1451 if (strcasecmp(t, OSP_GENERAL_CAT)) {
1452 osp_create_provider(cfg, t);
1454 t = ast_category_browse(cfg, t);
1457 osp_initialized = 1;
1459 ast_config_destroy(cfg);
1460 } else {
1461 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
1462 return 0;
1464 ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized);
1466 return 1;
1469 static int osp_unload(void)
1471 struct osp_provider* p;
1472 struct osp_provider* next;
1474 if (osp_initialized) {
1475 ast_mutex_lock(&osplock);
1476 p = ospproviders;
1477 while(p) {
1478 next = p->next;
1479 OSPPProviderDelete(p->handle, 0);
1480 free(p);
1481 p = next;
1483 ospproviders = NULL;
1484 ast_mutex_unlock(&osplock);
1486 OSPPCleanup();
1488 osp_tokenformat = TOKEN_ALGO_SIGNED;
1489 osp_hardware = 0;
1490 osp_initialized = 0;
1492 return 0;
1495 static int osp_show(int fd, int argc, char* argv[])
1497 int i;
1498 int found = 0;
1499 struct osp_provider* p;
1500 const char* provider = NULL;
1501 const char* tokenalgo;
1503 if ((argc < 2) || (argc > 3)) {
1504 return RESULT_SHOWUSAGE;
1506 if (argc > 2) {
1507 provider = argv[2];
1509 if (!provider) {
1510 switch (osp_tokenformat) {
1511 case TOKEN_ALGO_BOTH:
1512 tokenalgo = "Both";
1513 break;
1514 case TOKEN_ALGO_UNSIGNED:
1515 tokenalgo = "Unsigned";
1516 break;
1517 case TOKEN_ALGO_SIGNED:
1518 default:
1519 tokenalgo = "Signed";
1520 break;
1522 ast_cli(fd, "OSP: %s %s %s\n",
1523 osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
1526 ast_mutex_lock(&osplock);
1527 p = ospproviders;
1528 while(p) {
1529 if (!provider || !strcasecmp(p->name, provider)) {
1530 if (found) {
1531 ast_cli(fd, "\n");
1533 ast_cli(fd, " == OSP Provider '%s' == \n", p->name);
1534 ast_cli(fd, "Local Private Key: %s\n", p->privatekey);
1535 ast_cli(fd, "Local Certificate: %s\n", p->localcert);
1536 for (i = 0; i < p->cacount; i++) {
1537 ast_cli(fd, "CA Certificate %d: %s\n", i + 1, p->cacerts[i]);
1539 for (i = 0; i < p->spcount; i++) {
1540 ast_cli(fd, "Service Point %d: %s\n", i + 1, p->srvpoints[i]);
1542 ast_cli(fd, "Max Connections: %d\n", p->maxconnections);
1543 ast_cli(fd, "Retry Delay: %d seconds\n", p->retrydelay);
1544 ast_cli(fd, "Retry Limit: %d\n", p->retrylimit);
1545 ast_cli(fd, "Timeout: %d milliseconds\n", p->timeout);
1546 ast_cli(fd, "Source: %s\n", strlen(p->source) ? p->source : "<unspecified>");
1547 ast_cli(fd, "Auth Policy %d\n", p->authpolicy);
1548 ast_cli(fd, "OSP Handle: %d\n", p->handle);
1549 found++;
1551 p = p->next;
1553 ast_mutex_unlock(&osplock);
1555 if (!found) {
1556 if (provider) {
1557 ast_cli(fd, "Unable to find OSP provider '%s'\n", provider);
1558 } else {
1559 ast_cli(fd, "No OSP providers configured\n");
1562 return RESULT_SUCCESS;
1565 static const char* app1= "OSPAuth";
1566 static const char* synopsis1 = "OSP authentication";
1567 static const char* descrip1 =
1568 " OSPAuth([provider[|options]]): Authenticate a SIP INVITE by OSP and sets\n"
1569 "the variables:\n"
1570 " ${OSPINHANDLE}: The inbound call transaction handle\n"
1571 " ${OSPINTIMELIMIT}: The inbound call duration limit in seconds\n"
1572 "\n"
1573 "The option string may contain the following character:\n"
1574 " 'j' -- jump to n+101 priority if the authentication was NOT successful\n"
1575 "This application sets the following channel variable upon completion:\n"
1576 " OSPAUTHSTATUS The status of the OSP Auth attempt as a text string, one of\n"
1577 " SUCCESS | FAILED | ERROR\n";
1579 static const char* app2= "OSPLookup";
1580 static const char* synopsis2 = "Lookup destination by OSP";
1581 static const char* descrip2 =
1582 " OSPLookup(exten[|provider[|options]]): Looks up an extension via OSP and sets\n"
1583 "the variables, where 'n' is the number of the result beginning with 1:\n"
1584 " ${OSPOUTHANDLE}: The OSP Handle for anything remaining\n"
1585 " ${OSPTECH}: The technology to use for the call\n"
1586 " ${OSPDEST}: The destination to use for the call\n"
1587 " ${OSPCALLING}: The calling number to use for the call\n"
1588 " ${OSPOUTTOKEN}: The actual OSP token as a string\n"
1589 " ${OSPOUTTIMELIMIT}: The outbound call duration limit in seconds\n"
1590 " ${OSPRESULTS}: The number of OSP results total remaining\n"
1591 "\n"
1592 "The option string may contain the following character:\n"
1593 " 'j' -- jump to n+101 priority if the lookup was NOT successful\n"
1594 "This application sets the following channel variable upon completion:\n"
1595 " OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
1596 " SUCCESS | FAILED | ERROR\n";
1598 static const char* app3 = "OSPNext";
1599 static const char* synopsis3 = "Lookup next destination by OSP";
1600 static const char* descrip3 =
1601 " OSPNext(cause[|options]): Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
1602 "See OSPLookup for more information\n"
1603 "\n"
1604 "The option string may contain the following character:\n"
1605 " 'j' -- jump to n+101 priority if the lookup was NOT successful\n"
1606 "This application sets the following channel variable upon completion:\n"
1607 " OSPNEXTSTATUS The status of the OSP Next attempt as a text string, one of\n"
1608 " SUCCESS | FAILED |ERROR\n";
1610 static const char* app4 = "OSPFinish";
1611 static const char* synopsis4 = "Record OSP entry";
1612 static const char* descrip4 =
1613 " OSPFinish([status[|options]]): Records call state for ${OSPINHANDLE}, according to\n"
1614 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
1615 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
1616 "\n"
1617 "The option string may contain the following character:\n"
1618 " 'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
1619 "This application sets the following channel variable upon completion:\n"
1620 " OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
1621 " SUCCESS | FAILED |ERROR \n";
1623 static const char osp_usage[] =
1624 "Usage: osp show\n"
1625 " Displays information on Open Settlement Protocol support\n";
1627 static struct ast_cli_entry cli_osp[] = {
1628 { { "osp", "show", NULL},
1629 osp_show, "Displays OSP information",
1630 osp_usage },
1633 static int load_module(void)
1635 int res;
1637 if(!osp_load())
1638 return AST_MODULE_LOAD_DECLINE;
1640 ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
1641 res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
1642 res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
1643 res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
1644 res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
1646 return res;
1649 static int unload_module(void)
1651 int res;
1653 res = ast_unregister_application(app4);
1654 res |= ast_unregister_application(app3);
1655 res |= ast_unregister_application(app2);
1656 res |= ast_unregister_application(app1);
1657 ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
1658 osp_unload();
1660 ast_module_user_hangup_all();
1662 return res;
1665 static int reload(void)
1667 osp_unload();
1668 osp_load();
1670 return 0;
1673 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
1674 .load = load_module,
1675 .unload = unload_module,
1676 .reload = reload,