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.
21 * \brief Open Settlement Protocol (OSP) Applications
23 * \author Mark Spencer <markster@digium.com>
25 * \ingroup applications
29 <depend>osptk</depend>
35 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
37 #include <sys/types.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 */
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 */
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 */
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 */
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
)
149 unsigned int t
, i
, j
;
150 struct osp_provider
* p
;
151 struct ast_variable
* v
;
152 OSPTPRIVATEKEY privatekey
;
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");
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
);
176 if (!strcasecmp(v
->name
, "privatekey")) {
177 if (v
->value
[0] == '/') {
178 ast_copy_string(p
->privatekey
, v
->value
, sizeof(p
->privatekey
));
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
));
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]));
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
]);
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
]);
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
);
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
)) {
221 ast_log(LOG_DEBUG
, "OSP: retrydelay '%d'\n", t
);
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
)) {
229 ast_log(LOG_DEBUG
, "OSP: retrylimit '%d'\n", t
);
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
)) {
237 ast_log(LOG_DEBUG
, "OSP: timeout '%d'\n", t
);
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
))) {
248 ast_log(LOG_DEBUG
, "OSP: authpolicy '%d'\n", t
);
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
);
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
);
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
);
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
]);
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
);
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
);
312 ast_log(LOG_DEBUG
, "OSP: provider '%s'\n", provider
);
313 ast_mutex_lock(&osplock
);
314 p
->next
= ospproviders
;
316 ast_mutex_unlock(&osplock
);
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
);
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
)
344 struct osp_provider
* p
;
346 ast_mutex_lock(&osplock
);
349 if (!strcasecmp(p
->name
, provider
)) {
350 *policy
= p
->authpolicy
;
351 ast_log(LOG_DEBUG
, "OSP: authpolicy '%d'\n", *policy
);
357 ast_mutex_unlock(&osplock
);
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
)
373 struct osp_provider
* p
;
376 ast_mutex_lock(&osplock
);
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
);
387 *transaction
= OSP_INVALID_HANDLE
;
388 ast_log(LOG_DEBUG
, "OSP: Unable to create transaction handle, error '%d'\n", error
);
395 ast_mutex_unlock(&osplock
);
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(
413 if (inet_aton(src
, &inp
) != 0) {
414 snprintf(dst
, buffersize
, "[%s]", src
);
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
)
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;
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(
447 src
, dst
, NULL
, NULL
,
448 calling
? calling
: "", OSPC_E164
,
451 tokenlen
, (char *) tokenstr
,
456 if (error
!= OSPC_ERR_NO_ERROR
) {
457 ast_log(LOG_DEBUG
, "OSP: Unable to validate inbound token\n");
459 } else if (authorised
) {
460 ast_log(LOG_DEBUG
, "OSP: Authorised\n");
463 ast_log(LOG_DEBUG
, "OSP: Unauthorised\n");
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
) {
480 } else if (out
== OSP_DEF_TIMELIMIT
) {
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
)
501 OSPE_DEST_OSP_ENABLED enabled
;
502 OSPE_DEST_PROT protocol
;
505 if (strlen(destination
) <= 2) {
506 ast_log(LOG_DEBUG
, "OSP: Wrong destination format '%s'\n", destination
);
507 *reason
= OSPC_FAIL_NORMAL_UNSPECIFIED
;
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
;
517 if (enabled
== OSPE_OSP_FALSE
) {
518 result
->token
[0] = '\0';
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';
531 /* Strip leading and trailing brackets */
532 destination
[strlen(destination
) - 1] = '\0';
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
));
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
));
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
));
553 ast_log(LOG_DEBUG
, "OSP: Unknown protocol '%d'\n", protocol
);
554 *reason
= OSPC_FAIL_PROTOCOL_ERROR
;
555 result
->token
[0] = '\0';
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
)
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
);
593 ast_log(LOG_DEBUG
, "OSP: Unabe to find OSP authentication policy\n");
601 case OSP_AUTH_EXCLUSIVE
:
602 if (ast_strlen_zero(token
)) {
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
;
608 } else if((res
= osp_validate_token(*transaction
, source
, dest
, calling
, called
, token
, timelimit
)) <= 0) {
609 OSPPTransactionRecordFailure(*transaction
, OSPC_FAIL_CALL_REJECTED
);
614 if (ast_strlen_zero(token
)) {
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
;
620 } else if((res
= osp_validate_token(*transaction
, source
, dest
, calling
, called
, token
, timelimit
)) <= 0) {
621 OSPPTransactionRecordFailure(*transaction
, OSPC_FAIL_CALL_REJECTED
);
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
)
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
;
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
);
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
);
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
);
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
);
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) {
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
);
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) {
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
);
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
);
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
)
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
;
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
);
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
);
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) {
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
);
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
);
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
)
868 enum OSPEFAILREASON reason
;
870 unsigned isPddInfoPresent
= 0;
872 unsigned int dummy
= 0;
875 if (handle
== OSP_INVALID_HANDLE
) {
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");
890 ast_log(LOG_DEBUG
, "OSP: Unable to report usage, error '%d'\n", error
);
893 OSPPTransactionDelete(handle
);
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
)
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
= "";
917 unsigned int timelimit
;
918 char buffer
[OSP_INTSTR_SIZE
];
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
);
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'))) {
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
;
962 timelimit
= OSP_DEF_TIMELIMIT
;
964 status
= AST_OSP_FAILED
;
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
);
980 if (priority_jump
|| ast_opt_priority_jumping
) {
981 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
990 ast_module_user_remove(u
);
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
)
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
;
1015 AST_DECLARE_APP_ARGS(args
,
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");
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
);
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'))) {
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
);
1074 if ((res
= osp_lookup(provider
, srcdev
, chan
->cid
.cid_num
, args
.exten
, &result
)) > 0) {
1075 status
= AST_OSP_SUCCESS
;
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
;
1084 status
= AST_OSP_FAILED
;
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
);
1126 if (priority_jump
|| ast_opt_priority_jumping
) {
1127 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
1136 ast_module_user_remove(u
);
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
)
1150 struct ast_module_user
*u
;
1151 int priority_jump
= 0;
1153 struct varshead
* headp
;
1154 struct ast_var_t
* current
;
1155 struct osp_result result
;
1156 char buffer
[OSP_TOKSTR_SIZE
];
1160 AST_DECLARE_APP_ARGS(args
,
1162 AST_APP_ARG(options
);
1165 if (ast_strlen_zero(data
)) {
1166 ast_log(LOG_WARNING
, "OSPNext: Arg required, OSPNext(cause[|options])\n");
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
);
1178 AST_STANDARD_APP_ARGS(args
, tmp
);
1180 if (!ast_strlen_zero(args
.cause
) && sscanf(args
.cause
, "%d", &cause
) != 1) {
1183 ast_log(LOG_DEBUG
, "OSPNext: cause '%d'\n", cause
);
1185 if ((args
.options
) && (strchr(args
.options
, 'j'))) {
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
;
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
;
1230 status
= AST_OSP_FAILED
;
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")) {
1264 if (priority_jump
|| ast_opt_priority_jumping
) {
1265 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
1274 ast_module_user_remove(u
);
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
)
1288 struct ast_module_user
*u
;
1289 int priority_jump
= 0;
1291 struct varshead
*headp
;
1292 struct ast_var_t
*current
;
1293 int inhandle
= OSP_INVALID_HANDLE
;
1294 int outhandle
= OSP_INVALID_HANDLE
;
1296 time_t start
, connect
, end
;
1297 unsigned int release
;
1298 char buffer
[OSP_INTSTR_SIZE
];
1302 AST_DECLARE_APP_ARGS(args
,
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
);
1315 AST_STANDARD_APP_ARGS(args
, tmp
);
1317 if ((args
.options
) && (strchr(args
.options
, 'j'))) {
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
)) {
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) {
1349 ast_log(LOG_DEBUG
, "OSPFinish: cause '%d'\n", cause
);
1352 start
= chan
->cdr
->start
.tv_sec
;
1353 connect
= chan
->cdr
->answer
.tv_sec
;
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");
1374 case AST_CAUSE_NORMAL_CLEARING
:
1377 cause
= AST_CAUSE_NO_ROUTE_DESTINATION
;
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
);
1388 status
= AST_OSP_SUCCESS
;
1390 status
= AST_OSP_FAILED
;
1392 status
= AST_OSP_ERROR
;
1394 pbx_builtin_setvar_helper(chan
, "OSPFINISHSTATUS", status
);
1397 if (priority_jump
|| ast_opt_priority_jumping
) {
1398 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
1407 ast_module_user_remove(u
);
1412 /* OSP Module APIs */
1414 static int osp_load(void)
1418 struct ast_config
* cfg
;
1419 int error
= OSPC_ERR_NO_ERROR
;
1421 cfg
= ast_config_load(OSP_CONFIG_FILE
);
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");
1434 ast_log(LOG_DEBUG
, "OSP: osp_hardware '%d'\n", osp_hardware
);
1436 t
= ast_variable_retrieve(cfg
, OSP_GENERAL_CAT
, "tokenformat");
1438 if ((sscanf(t
, "%d", &v
) == 1) &&
1439 ((v
== TOKEN_ALGO_SIGNED
) || (v
== TOKEN_ALGO_UNSIGNED
) || (v
== TOKEN_ALGO_BOTH
)))
1441 osp_tokenformat
= v
;
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
);
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
);
1461 ast_log(LOG_WARNING
, "OSP: Unable to find configuration. OSP support disabled\n");
1464 ast_log(LOG_DEBUG
, "OSP: osp_initialized '%d'\n", osp_initialized
);
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
);
1479 OSPPProviderDelete(p
->handle
, 0);
1483 ospproviders
= NULL
;
1484 ast_mutex_unlock(&osplock
);
1488 osp_tokenformat
= TOKEN_ALGO_SIGNED
;
1490 osp_initialized
= 0;
1495 static int osp_show(int fd
, int argc
, char* argv
[])
1499 struct osp_provider
* p
;
1500 const char* provider
= NULL
;
1501 const char* tokenalgo
;
1503 if ((argc
< 2) || (argc
> 3)) {
1504 return RESULT_SHOWUSAGE
;
1510 switch (osp_tokenformat
) {
1511 case TOKEN_ALGO_BOTH
:
1514 case TOKEN_ALGO_UNSIGNED
:
1515 tokenalgo
= "Unsigned";
1517 case TOKEN_ALGO_SIGNED
:
1519 tokenalgo
= "Signed";
1522 ast_cli(fd
, "OSP: %s %s %s\n",
1523 osp_initialized
? "Initialized" : "Uninitialized", osp_hardware
? "Accelerated" : "Normal", tokenalgo
);
1526 ast_mutex_lock(&osplock
);
1529 if (!provider
|| !strcasecmp(p
->name
, provider
)) {
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
);
1553 ast_mutex_unlock(&osplock
);
1557 ast_cli(fd
, "Unable to find OSP provider '%s'\n", provider
);
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"
1570 " ${OSPINHANDLE}: The inbound call transaction handle\n"
1571 " ${OSPINTIMELIMIT}: The inbound call duration limit in seconds\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"
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"
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"
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
[] =
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",
1633 static int load_module(void)
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
);
1649 static int unload_module(void)
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
));
1660 ast_module_user_hangup_all();
1665 static int reload(void)
1673 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Open Settlement Protocol Applications",
1674 .load
= load_module
,
1675 .unload
= unload_module
,