Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
6436e6b2
提交
6436e6b2
authored
4月 29, 2010
作者:
Brian West
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Check in mod_osp from transnexus thank you.
上级
6b694950
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
2261 行增加
和
0 行删除
+2261
-0
modules.conf.in
build/modules.conf.in
+1
-0
osp.conf.xml
conf/autoload_configs/osp.conf.xml
+55
-0
Makefile.am
src/mod/applications/mod_osp/Makefile.am
+8
-0
mod_osp.c
src/mod/applications/mod_osp/mod_osp.c
+2197
-0
没有找到文件。
build/modules.conf.in
浏览文件 @
6436e6b2
...
@@ -6,6 +6,7 @@ applications/mod_commands
...
@@ -6,6 +6,7 @@ applications/mod_commands
applications/mod_conference
applications/mod_conference
applications/mod_dptools
applications/mod_dptools
applications/mod_enum
applications/mod_enum
#applications/mod_osp
applications/mod_fifo
applications/mod_fifo
#applications/mod_fax
#applications/mod_fax
#applications/mod_curl
#applications/mod_curl
...
...
conf/autoload_configs/osp.conf.xml
0 → 100644
浏览文件 @
6436e6b2
<configuration
name=
"osp.conf"
description=
"OSP Module Configuration"
>
<settings>
<!-- Debug info flag -->
<param
name=
"debug-info"
value=
"disabled"
/>
<!-- Log level for debug info -->
<param
name=
"log-level"
value=
"info"
/>
<!-- Crypto hareware accelerate is disabled by default -->
<param
name=
"crypto-hardware"
value=
"disabled"
/>
<!-- SIP settings -->
<param
name=
"sip"
module=
"sofia"
profile=
"external"
/>
<!-- H.323 settings -->
<!-- <param name="h323" module="h323" profile="external"/> -->
<!-- IAX settings -->
<!-- <param name="iax" module="iax" profile="external"/> -->
<!-- Skype settings -->
<!-- <param name="skype" module="skypopen" profile="external"/> -->
<!-- Default destination protocol -->
<param
name=
"default-protocol"
value=
"sip"
/>
</settings>
<profiles>
<!-- Default OSP provider profile -->
<profile
name=
"default"
>
<!-- Service point URLs, up to 8 allowed -->
<!-- <param name="service-point-url" value="http://osptestserver.transnexus.com:1080/osp"/> -->
<!-- <param name="service-point-url" value="https://127.0.0.1:1443/osp"/> -->
<param
name=
"service-point-url"
value=
"http://127.0.0.1:1080/osp"
/>
<!-- FreeSWITCH IP address for OSP -->
<param
name=
"device-ip"
value=
"127.0.0.1:5080"
/>
<!-- SSL lifetime in seconds -->
<param
name=
"ssl-lifetime"
value=
"300"
/>
<!-- HTTP max connections, 1~1000 -->
<param
name=
"http-max-connections"
value=
"20"
/>
<!-- HTTP persistence in seconds -->
<param
name=
"http-persistence"
value=
"60"
/>
<!-- HTTP retry delay in seconds, 0~10 -->
<param
name=
"http-retry-delay"
value=
"0"
/>
<!-- HTTP retry limit, 0~100 -->
<param
name=
"http-retry-limit"
value=
"2"
/>
<!-- HTTP timeout in milliseconds, 200~60000 -->
<param
name=
"http-timeout"
value=
"10000"
/>
<!-- OSP service type, voice or npquery -->
<param
name=
"service-type"
value=
"voice"
/>
<!-- Max number of destinations -->
<param
name=
"max-destinations"
value=
"5"
/>
<!-- SIP features -->
<!-- Add "user=phone" URI parameter in outbound SIP messages -->
<param
name=
"user-phone"
value=
"disabled"
/>
</profile>
</profiles>
</configuration>
src/mod/applications/mod_osp/Makefile.am
0 → 100644
浏览文件 @
6436e6b2
include
$(top_srcdir)/build/modmake.rulesam
MODNAME
=
mod_osp
mod_LTLIBRARIES
=
mod_osp.la
mod_osp_la_SOURCES
=
mod_osp.c
mod_osp_la_CFLAGS
=
$(AM_CFLAGS)
mod_osp_la_LDFLAGS
=
-avoid-version
-module
-no-undefined
-shared
-losptk
-lssl
-lcrypto
-lpthread
-lm
src/mod/applications/mod_osp/mod_osp.c
0 → 100644
浏览文件 @
6436e6b2
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Di-Shi Sun <di-shi@transnexus.com>
*
* mod_osp.c -- Open Settlement Protocol (OSP) Module
*
*/
/*
* TODO:
* 1. NID -> outbound messages
*/
#include <switch.h>
#include <osp/osp.h>
#include <osp/ospb64.h>
#include <osp/osptrans.h>
/* OSP Buffer Size Constants */
#define OSP_SIZE_NORSTR 256
/* OSP normal string buffer size */
#define OSP_SIZE_KEYSTR 1024
/* OSP certificate string buffer size */
#define OSP_SIZE_ROUSTR 1024
/* OSP route buffer size */
#define OSP_SIZE_TOKSTR 4096
/* OSP token string buffer size */
/* OSP Settings Constants */
#define OSP_MAX_SP 8
/* Max number of OSP service points */
#define OSP_AUDIT_URL "localhost"
/* OSP default Audit URL */
#define OSP_LOCAL_VALID 1
/* OSP token validating method, locally */
#define OSP_DEF_LIFETIME 300
/* OSP default SSL lifetime */
#define OSP_DEF_MAXCONN 20
/* OSP default max connections */
#define OSP_MIN_MAXCONN 1
/* OSP min max connections */
#define OSP_MAX_MAXCONN 1000
/* OSP max max connections */
#define OSP_DEF_PERSIST 60
/* OSP default HTTP persistence in seconds */
#define OSP_DEF_RETRYDELAY 0
/* OSP default retry delay in seconds */
#define OSP_MIN_RETRYDELAY 0
/* OSP min retry delay */
#define OSP_MAX_RETRYDELAY 10
/* OSP max retry delay */
#define OSP_DEF_RETRYLIMIT 2
/* OSP default retry times */
#define OSP_MIN_RETRYLIMIT 0
/* OSP min retry times */
#define OSP_MAX_RETRYLIMIT 100
/* OSP max retry times */
#define OSP_DEF_TIMEOUT 10000
/* OSP default timeout in ms */
#define OSP_MIN_TIMEOUT 200
/* OSP min timeout in ms */
#define OSP_MAX_TIMEOUT 60000
/* OSP max timeout in ms */
#define OSP_CUSTOMER_ID ""
/* OSP customer ID */
#define OSP_DEVICE_ID ""
/* OSP device ID */
#define OSP_DEF_MAXDEST 5
/* OSP default max destinations */
#define OSP_MIN_MAXDEST 1
/* OSP min max destinations */
#define OSP_MAX_MAXDEST 10
/* OSP max max destinations */
#define OSP_DEF_PROFILE "default"
/* OSP default profile name */
#define OSP_DEF_STRING ""
/* OSP default empty string */
#define OSP_DEF_CALLID "UNDEFINED"
/* OSP default Call-ID */
#define OSP_DEF_STATS -1
/* OSP default statistics */
#define OSP_URI_DELIM '@'
/* URI delimit */
#define OSP_USER_DELIM ";:"
/* URI userinfo delimit */
#define OSP_HOST_DELIM ";>"
/* URI hostport delimit */
#define OSP_MAX_CINFO 8
/* Max number of custom info */
/* OSP Handle Constant */
#define OSP_INVALID_HANDLE -1
/* Invalid OSP handle, provider, transaction etc. */
/* OSP Supported Destination Protocols for Default Protocol */
#define OSP_PROTOCOL_SIP "sip"
/* SIP protocol name */
#define OSP_PROTOCOL_H323 "h323"
/* H.323 protocol name */
#define OSP_PROTOCOL_IAX "iax"
/* IAX protocol name */
#define OSP_PROTOCOL_SKYPE "skype"
/* Skype protocol name */
#define OSP_PROTOCOL_UNKNO "unknown"
/* Unknown protocol */
#define OSP_PROTOCOL_UNDEF "undefined"
/* Undefined protocol */
#define OSP_PROTOCOL_UNSUP "unsupported"
/* Unsupported protocol */
/* OSP Supported Destination Protocols for Destination Protocol Usage */
#define OSP_MODULE_SIP "mod_sofia"
/* FreeSWITCH SIP module name */
#define OSP_MODULE_H323 "mod_h323"
/* FreeSWITCH H.323 module name */
#define OSP_MODULE_IAX "mod_iax"
/* FreeSWITCH IAX module name */
#define OSP_MODULE_SKYPE "mod_skypopen"
/* FreeSWITCH Skype module name */
/* OSP Variables Name */
#define OSP_VAR_PROFILE "osp_profile"
/* Provider name, in OSP cookie */
#define OSP_VAR_TRANSID "osp_transaction_id"
/* Transaction ID, in OSP cookie */
#define OSP_VAR_START "osp_start_time"
/* Inbound Call start time, in OSP cookie */
#define OSP_VAR_DESTCOUNT "osp_destination_count"
/* Destination count, in OSP cookie */
#define OSP_VAR_SRCNID "osp_source_nid"
/* Source network ID, inbound and in OSP cookie */
#define OSP_VAR_DESTIP "osp_destination_ip"
/* Destination IP, in OSP cookie */
#define OSP_VAR_DESTNID "osp_destination_nid"
/* Destination network ID, in OSP cookie */
#define OSP_VAR_CUSTOMINFO "osp_custom_info_"
/* Custom info */
#define OSP_VAR_ROUTECOUNT "osp_route_count"
/* Number of destinations */
#define OSP_VAR_ROUTEPRE "osp_route_"
/* Destination prefix */
#define OSP_VAR_AUTOROUTE "osp_auto_route"
/* Bridge route string */
/* OSP Use Variable Name */
#define OSP_FS_TOHOST "sip_to_host"
/* Inbound SIP To host */
#define OSP_FS_TOPORT "sip_to_port"
/* Inbound SIP To port */
#define OSP_FS_DIVERSION "sip_h_Diversion"
/* Inbound SIP Diversion header */
#define OSP_FS_OUTCALLID "sip_call_id"
/* Outbound SIP Call-ID */
#define OSP_FS_OUTCALLING "origination_caller_id_number"
/* Outbound calling number */
#define OSP_FS_SIPRELEASE "sip_hangup_disposition"
/* SIP release source */
#define OSP_FS_DOWNCODEC "write_codec"
/* Downstream codec */
#define OSP_FS_UPCODEC "read_codec"
/* Upstream codec */
#define OSP_FS_RTPDOWNOCTS "rtp_audio_out_media_bytes"
/* Downstream octets */
#define OSP_FS_RTPUPOCTS "rtp_audio_in_media_bytes"
/* Upstream octets */
#define OSP_FS_RTPDOWNPKTS "rtp_audio_out_media_packet_count"
/* Downstream packets */
#define OSP_FS_RTPUPPKTS "rtp_audio_in_media_packet_count"
/* Upstream packets */
typedef
struct
osp_settings
{
switch_bool_t
debug
;
/* OSP module debug info flag */
switch_log_level_t
loglevel
;
/* Log level for debug info */
switch_bool_t
hardware
;
/* Crypto hardware flag */
const
char
*
module
[
OSPC_DPROT_NUMBER
];
/* Endpoint names */
const
char
*
profile
[
OSPC_DPROT_NUMBER
];
/* Profile names */
OSPE_DEST_PROTOCOL
protocol
;
/* Default destination protocol */
switch_bool_t
shutdown
;
/* OSP module status */
switch_memory_pool_t
*
pool
;
/* OSP module memory pool */
}
osp_settings_t
;
/* OSP Service Types */
typedef
enum
osp_srvtype
{
OSP_SRV_VOICE
=
0
,
/* Normal voice service */
OSP_SRV_NPQUERY
/* Number portability query service */
}
osp_srvtype_t
;
typedef
struct
osp_provider
{
const
char
*
name
;
/* OSP provider profile name */
int
spnum
;
/* Number of OSP service points */
const
char
*
spurls
[
OSP_MAX_SP
];
/* OSP provider service point URLs */
const
char
*
device
;
/* OSP source IP */
int
lifetime
;
/* SSL life time */
int
maxconnect
;
/* Max number of HTTP connections */
int
persistence
;
/* HTTP persistence in seconds */
int
retrydelay
;
/* HTTP retry delay in seconds */
int
retrylimit
;
/* HTTP retry times */
int
timeout
;
/* HTTP timeout in ms */
osp_srvtype_t
srvtype
;
/* OSP service type */
int
maxdest
;
/* Max destinations */
switch_bool_t
userphone
;
/* Add "user=phone" URI parameter */
OSPTPROVHANDLE
handle
;
/* OSP provider handle */
struct
osp_provider
*
next
;
/* Next OSP provider */
}
osp_provider_t
;
typedef
struct
osp_inbound
{
const
char
*
srcdev
;
/* Source device IP address */
const
char
*
calling
;
/* Inbound calling number */
char
called
[
OSP_SIZE_NORSTR
];
/* Inbound called number */
char
nprn
[
OSP_SIZE_NORSTR
];
/* Inbound NP routing number */
char
npcic
[
OSP_SIZE_NORSTR
];
/* Inbound NP carrier identification code */
int
npdi
;
/* Inbound NP database dip indicator */
const
char
*
tohost
;
/* Inbound host of To URI */
const
char
*
toport
;
/* Inbound port of To URI */
char
divuser
[
OSP_SIZE_NORSTR
];
/* Inbound user of SIP Diversion header */
char
divhost
[
OSP_SIZE_NORSTR
];
/* Inbound hostport of SIP Diversion header */
const
char
*
srcnid
;
/* Inbound source network ID */
switch_time_t
start
;
/* Call start time */
const
char
*
cinfo
[
OSP_MAX_CINFO
];
/* Custom info */
}
osp_inbound_t
;
typedef
struct
osp_destination
{
unsigned
int
timelimit
;
/* Outbound duration limit */
char
dest
[
OSP_SIZE_NORSTR
];
/* Destination IP address */
char
calling
[
OSP_SIZE_NORSTR
];
/* Outbound calling number, may be translated */
char
called
[
OSP_SIZE_NORSTR
];
/* Outbound called number, may be translated */
char
destnid
[
OSP_SIZE_NORSTR
];
/* Destination network ID */
char
nprn
[
OSP_SIZE_NORSTR
];
/* Outbound NP routing number */
char
npcic
[
OSP_SIZE_NORSTR
];
/* Outbound NP carrier identification code */
int
npdi
;
/* Outbound NP database dip indicator */
char
opname
[
OSPC_OPNAME_NUMBER
][
OSP_SIZE_NORSTR
];
/* Outbound Operator names */
OSPE_DEST_PROTOCOL
protocol
;
/* Destination protocol */
switch_bool_t
supported
;
/* Supported by FreeRADIUS OSP module */
switch_bool_t
userphone
;
/* Add "user=phone" parameter */
}
osp_destination_t
;
typedef
struct
osp_results
{
const
char
*
profile
;
/* Provider name */
unsigned
long
long
transid
;
/* Transaction ID */
switch_time_t
start
;
/* Call start time */
char
called
[
OSP_SIZE_NORSTR
];
/* Original called number */
const
char
*
srcnid
;
/* Source network ID */
int
numdest
;
/* Number of destinations */
osp_destination_t
dests
[
OSP_MAX_SP
];
/* Destinations */
}
osp_results_t
;
typedef
struct
osp_cookie
{
const
char
*
profile
;
/* Provider name */
unsigned
long
long
transid
;
/* Transaction ID */
switch_time_t
start
;
/* Call start time */
int
destcount
;
/* Destination count */
const
char
*
dest
;
/* Destination IP */
const
char
*
srcnid
;
/* Source network ID */
const
char
*
destnid
;
/* Destination network ID */
}
osp_cookie_t
;
typedef
struct
osp_usage
{
const
char
*
callid
;
/* Call-ID */
const
char
*
calling
;
/* Calling number */
char
called
[
OSP_SIZE_NORSTR
];
/* Called number */
const
char
*
srcdev
;
/* Source device IP */
OSPE_DEST_PROTOCOL
protocol
;
/* Destination protocol */
int
release
;
/* Release source */
switch_call_cause_t
cause
;
/* Termination cause */
switch_time_t
alert
;
/* Call alert time */
switch_time_t
connect
;
/* Call answer time */
switch_time_t
end
;
/* Call end time */
switch_time_t
duration
;
/* Call duration */
switch_time_t
pdd
;
/* Post dial delay */
const
char
*
fcodec
;
/* Forward codec */
const
char
*
rcodec
;
/* Reverse codec */
int
rtpdownoctets
;
/* RTP downstream bytes */
int
rtpupoctets
;
/* RTP upstream bytes */
int
rtpdownpackets
;
/* RTP downstream packets */
int
rtpuppackets
;
/* RTP upstream packets */
}
osp_usage_t
;
typedef
struct
osp_threadarg
{
OSPTTRANHANDLE
handle
;
/* Transaction handle */
unsigned
long
long
transid
;
/* Transaction ID */
switch_call_cause_t
cause
;
/* Release code */
time_t
start
;
/* Call start time */
time_t
alert
;
/* Call alert time */
time_t
connect
;
/* Call connect time */
time_t
end
;
/* Call end time */
int
duration
;
/* Call duration */
int
pdd
;
/* Post dial delay */
int
release
;
/* EP that released the call */
}
osp_threadarg_t
;
/* OSP module global settings */
static
osp_settings_t
osp_globals
;
/* OSP module providers */
static
osp_provider_t
*
osp_providers
=
NULL
;
/* switch_status_t mod_osp_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION
(
mod_osp_load
);
/* switch_status_t mod_osp_shutdown(void) */
SWITCH_MODULE_SHUTDOWN_FUNCTION
(
mod_osp_shutdown
);
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime) */
SWITCH_MODULE_DEFINITION
(
mod_osp
,
mod_osp_load
,
mod_osp_shutdown
,
NULL
);
/* Macro to prevent NULL string */
#define osp_filter_null(_str) switch_strlen_zero(_str) ? OSP_DEF_STRING : _str
#define osp_adjust_len(_head, _size, _len) { _len = strlen(_head); _head += _len; _size -= _len; }
/*
* Find OSP provider by name
* param name OSP provider name
* param provider OSP provider, NULL is allowed
* return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed
*/
static
switch_status_t
osp_find_provider
(
const
char
*
name
,
osp_provider_t
**
provider
)
{
osp_provider_t
*
p
;
switch_status_t
status
=
SWITCH_STATUS_FALSE
;
if
(
name
)
{
if
(
provider
)
{
*
provider
=
NULL
;
}
for
(
p
=
osp_providers
;
p
;
p
=
p
->
next
)
{
if
(
!
strcasecmp
(
p
->
name
,
name
))
{
if
(
provider
)
{
*
provider
=
p
;
}
status
=
SWITCH_STATUS_SUCCESS
;
break
;
}
}
}
return
status
;
}
/*
* Load OSP module configuration
* param pool OSP module memory pool
* return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed, SWITCH_STATUS_MEMERR Memory Error.
*/
static
switch_status_t
osp_load_settings
(
switch_memory_pool_t
*
pool
)
{
char
*
cf
=
"osp.conf"
;
switch_xml_t
cfg
,
xml
=
NULL
,
param
,
settings
,
profile
,
profiles
;
const
char
*
name
;
const
char
*
value
;
const
char
*
module
;
const
char
*
context
;
osp_provider_t
*
provider
;
int
number
;
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
if
(
!
(
xml
=
switch_xml_open_cfg
(
cf
,
&
cfg
,
NULL
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to open '%s'
\n
"
,
cf
);
status
=
SWITCH_STATUS_FALSE
;
return
status
;
}
memset
(
&
osp_globals
,
0
,
sizeof
(
osp_globals
));
osp_globals
.
loglevel
=
SWITCH_LOG_DEBUG
;
osp_globals
.
pool
=
pool
;
osp_globals
.
protocol
=
OSPC_DPROT_SIP
;
if
((
settings
=
switch_xml_child
(
cfg
,
"settings"
)))
{
for
(
param
=
switch_xml_child
(
settings
,
"param"
);
param
;
param
=
param
->
next
)
{
name
=
switch_xml_attr_soft
(
param
,
"name"
);
value
=
switch_xml_attr_soft
(
param
,
"value"
);
module
=
switch_xml_attr_soft
(
param
,
"module"
);
context
=
switch_xml_attr_soft
(
param
,
"profile"
);
if
(
switch_strlen_zero
(
name
))
{
continue
;
}
if
(
!
strcasecmp
(
name
,
"debug-info"
))
{
if
(
!
switch_strlen_zero
(
value
))
{
osp_globals
.
debug
=
switch_true
(
value
);
}
}
else
if
(
!
strcasecmp
(
name
,
"log-level"
))
{
if
(
switch_strlen_zero
(
value
))
{
continue
;
}
else
if
(
!
strcasecmp
(
value
,
"console"
))
{
osp_globals
.
loglevel
=
SWITCH_LOG_CONSOLE
;
}
else
if
(
!
strcasecmp
(
value
,
"alert"
))
{
osp_globals
.
loglevel
=
SWITCH_LOG_ALERT
;
}
else
if
(
!
strcasecmp
(
value
,
"crit"
))
{
osp_globals
.
loglevel
=
SWITCH_LOG_CRIT
;
}
else
if
(
!
strcasecmp
(
value
,
"error"
))
{
osp_globals
.
loglevel
=
SWITCH_LOG_ERROR
;
}
else
if
(
!
strcasecmp
(
value
,
"warning"
))
{
osp_globals
.
loglevel
=
SWITCH_LOG_WARNING
;
}
else
if
(
!
strcasecmp
(
value
,
"notice"
))
{
osp_globals
.
loglevel
=
SWITCH_LOG_NOTICE
;
}
else
if
(
!
strcasecmp
(
value
,
"info"
))
{
osp_globals
.
loglevel
=
SWITCH_LOG_INFO
;
}
else
if
(
!
strcasecmp
(
value
,
"debug"
))
{
osp_globals
.
loglevel
=
SWITCH_LOG_DEBUG
;
}
}
else
if
(
!
strcasecmp
(
name
,
"crypto-hardware"
))
{
if
(
!
switch_strlen_zero
(
value
))
{
osp_globals
.
hardware
=
switch_true
(
value
);
}
}
else
if
(
!
strcasecmp
(
name
,
"default-protocol"
))
{
if
(
switch_strlen_zero
(
value
))
{
continue
;
}
else
if
(
!
strcasecmp
(
value
,
OSP_PROTOCOL_SIP
))
{
osp_globals
.
protocol
=
OSPC_DPROT_SIP
;
}
else
if
(
!
strcasecmp
(
value
,
OSP_PROTOCOL_H323
))
{
osp_globals
.
protocol
=
OSPC_DPROT_Q931
;
}
else
if
(
!
strcasecmp
(
value
,
OSP_PROTOCOL_IAX
))
{
osp_globals
.
protocol
=
OSPC_DPROT_IAX
;
}
else
if
(
!
strcasecmp
(
value
,
OSP_PROTOCOL_SKYPE
))
{
osp_globals
.
protocol
=
OSPC_DPROT_SKYPE
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unsupported default protocol '%s'
\n
"
,
value
);
}
}
else
if
(
!
strcasecmp
(
name
,
"sip"
))
{
if
(
!
switch_strlen_zero
(
module
))
{
if
(
!
(
osp_globals
.
module
[
OSPC_DPROT_SIP
]
=
switch_core_strdup
(
osp_globals
.
pool
,
module
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate SIP module name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
}
if
(
!
switch_strlen_zero
(
context
))
{
if
(
!
(
osp_globals
.
profile
[
OSPC_DPROT_SIP
]
=
switch_core_strdup
(
osp_globals
.
pool
,
context
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate SIP profile name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
}
}
else
if
(
!
strcasecmp
(
name
,
"h323"
))
{
if
(
!
switch_strlen_zero
(
module
))
{
if
(
!
(
osp_globals
.
module
[
OSPC_DPROT_Q931
]
=
switch_core_strdup
(
osp_globals
.
pool
,
module
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate H.323 module name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
}
if
(
!
switch_strlen_zero
(
context
))
{
if
(
!
(
osp_globals
.
profile
[
OSPC_DPROT_Q931
]
=
switch_core_strdup
(
osp_globals
.
pool
,
context
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate H.323 profile name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
}
}
else
if
(
!
strcasecmp
(
name
,
"iax"
))
{
if
(
!
switch_strlen_zero
(
module
))
{
if
(
!
(
osp_globals
.
module
[
OSPC_DPROT_IAX
]
=
switch_core_strdup
(
osp_globals
.
pool
,
module
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate IAX module name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
}
if
(
!
switch_strlen_zero
(
context
))
{
if
(
!
(
osp_globals
.
profile
[
OSPC_DPROT_IAX
]
=
switch_core_strdup
(
osp_globals
.
pool
,
context
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate IAX profile name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
}
}
else
if
(
!
strcasecmp
(
name
,
"skype"
))
{
if
(
!
switch_strlen_zero
(
module
))
{
if
(
!
(
osp_globals
.
module
[
OSPC_DPROT_SKYPE
]
=
switch_core_strdup
(
osp_globals
.
pool
,
module
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate Skype module name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
}
if
(
!
switch_strlen_zero
(
context
))
{
if
(
!
(
osp_globals
.
profile
[
OSPC_DPROT_SKYPE
]
=
switch_core_strdup
(
osp_globals
.
pool
,
context
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate Skype profile name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
}
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unknown parameter '%s'
\n
"
,
name
);
}
}
}
if
(
status
!=
SWITCH_STATUS_SUCCESS
)
{
switch_xml_free
(
xml
);
return
status
;
}
if
((
profiles
=
switch_xml_child
(
cfg
,
"profiles"
)))
{
for
(
profile
=
switch_xml_child
(
profiles
,
"profile"
);
profile
;
profile
=
profile
->
next
)
{
name
=
switch_xml_attr_soft
(
profile
,
"name"
);
if
(
switch_strlen_zero
(
name
))
{
name
=
OSP_DEF_PROFILE
;
}
if
(
osp_find_provider
(
name
,
NULL
)
==
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Ignored duplicate profile '%s'
\n
"
,
name
);
continue
;
}
if
(
!
(
provider
=
switch_core_alloc
(
osp_globals
.
pool
,
sizeof
(
*
provider
))))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to alloc provider
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
break
;
}
if
(
!
(
provider
->
name
=
switch_core_strdup
(
osp_globals
.
pool
,
name
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate provider name
\n
"
);
status
=
SWITCH_STATUS_MEMERR
;
/* "provider" cannot free to pool in FreeSWITCH */
break
;
}
/* Provider has been set to 0 by switch_core_alloc */
provider
->
lifetime
=
OSP_DEF_LIFETIME
;
provider
->
maxconnect
=
OSP_DEF_MAXCONN
;
provider
->
persistence
=
OSP_DEF_PERSIST
;
provider
->
retrydelay
=
OSP_DEF_RETRYDELAY
;
provider
->
retrylimit
=
OSP_DEF_RETRYLIMIT
;
provider
->
timeout
=
OSP_DEF_TIMEOUT
;
provider
->
maxdest
=
OSP_DEF_MAXDEST
;
provider
->
handle
=
OSP_INVALID_HANDLE
;
for
(
param
=
switch_xml_child
(
profile
,
"param"
);
param
;
param
=
param
->
next
)
{
name
=
switch_xml_attr_soft
(
param
,
"name"
);
value
=
switch_xml_attr_soft
(
param
,
"value"
);
if
(
switch_strlen_zero
(
name
)
||
switch_strlen_zero
(
value
))
{
continue
;
}
if
(
!
strcasecmp
(
name
,
"service-point-url"
))
{
if
(
provider
->
spnum
<
OSP_MAX_SP
)
{
provider
->
spurls
[
provider
->
spnum
]
=
switch_core_strdup
(
osp_globals
.
pool
,
value
);
provider
->
spnum
++
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Ignored excess service point '%s'
\n
"
,
value
);
}
}
else
if
(
!
strcasecmp
(
name
,
"device-ip"
))
{
provider
->
device
=
switch_core_strdup
(
osp_globals
.
pool
,
value
);
}
else
if
(
!
strcasecmp
(
name
,
"ssl-lifetime"
))
{
provider
->
lifetime
=
atoi
(
value
);
}
else
if
(
!
strcasecmp
(
name
,
"http-max-connections"
))
{
number
=
atoi
(
value
);
if
((
number
>=
OSP_MIN_MAXCONN
)
&&
(
number
<=
OSP_MAX_MAXCONN
))
{
provider
->
maxconnect
=
number
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"http-max-connections must be between %d and %d
\n
"
,
OSP_MIN_MAXCONN
,
OSP_MAX_MAXCONN
);
}
}
else
if
(
!
strcasecmp
(
name
,
"http-persistence"
))
{
provider
->
persistence
=
atoi
(
value
);
}
else
if
(
!
strcasecmp
(
name
,
"http-retry-delay"
))
{
number
=
atoi
(
value
);
if
((
number
>=
OSP_MIN_RETRYDELAY
)
&&
(
number
<=
OSP_MAX_RETRYDELAY
))
{
provider
->
retrydelay
=
number
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"http-retry-delay must be between %d and %d
\n
"
,
OSP_MIN_RETRYDELAY
,
OSP_MAX_RETRYDELAY
);
}
}
else
if
(
!
strcasecmp
(
name
,
"http-retry-limit"
))
{
number
=
atoi
(
value
);
if
((
number
>=
OSP_MIN_RETRYLIMIT
)
&&
(
number
<=
OSP_MAX_RETRYLIMIT
))
{
provider
->
retrylimit
=
number
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"http-retry-limit must be between %d and %d
\n
"
,
OSP_MIN_RETRYLIMIT
,
OSP_MAX_RETRYLIMIT
);
}
}
else
if
(
!
strcasecmp
(
name
,
"http-timeout"
))
{
number
=
atoi
(
value
);
if
((
number
>=
OSP_MIN_TIMEOUT
)
&&
(
number
<=
OSP_MAX_TIMEOUT
))
{
provider
->
timeout
=
number
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"http-timeout must be between %d and %d
\n
"
,
OSP_MIN_TIMEOUT
,
OSP_MAX_TIMEOUT
);
}
}
else
if
(
!
strcasecmp
(
name
,
"service-type"
))
{
if
(
!
strcasecmp
(
value
,
"voice"
))
{
provider
->
srvtype
=
OSP_SRV_VOICE
;
}
else
if
(
!
strcasecmp
(
value
,
"npquery"
))
{
provider
->
srvtype
=
OSP_SRV_NPQUERY
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unknown service type '%s'
\n
"
,
value
);
}
}
else
if
(
!
strcasecmp
(
name
,
"max-destinations"
))
{
number
=
atoi
(
value
);
if
((
number
>=
OSP_MIN_MAXDEST
)
&&
(
number
<=
OSP_MAX_MAXDEST
))
{
provider
->
maxdest
=
number
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"max-destinations must be between %d and %d
\n
"
,
OSP_MIN_MAXDEST
,
OSP_MAX_MAXDEST
);
}
}
else
if
(
!
strcasecmp
(
name
,
"user-phone"
))
{
provider
->
userphone
=
switch_true
(
value
);
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unknown parameter '%s'
\n
"
,
name
);
}
}
if
(
!
provider
->
spnum
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Without service point URI in profile '%s'
\n
"
,
provider
->
name
);
/* "provider" cannot free to pool in FreeSWITCH */
continue
;
}
provider
->
next
=
osp_providers
;
osp_providers
=
provider
;
}
}
switch_xml_free
(
xml
);
return
status
;
}
/* OSP default certificates */
const
char
*
B64PKey
=
"MIIBOgIBAAJBAK8t5l+PUbTC4lvwlNxV5lpl+2dwSZGW46dowTe6y133XyVEwNiiRma2YNk3xKs/TJ3Wl9Wpns2SYEAJsFfSTukCAwEAAQJAPz13vCm2GmZ8Zyp74usTxLCqSJZNyMRLHQWBM0g44Iuy4wE3vpi7Wq+xYuSOH2mu4OddnxswCP4QhaXVQavTAQIhAOBVCKXtppEw9UaOBL4vW0Ed/6EA/1D8hDW6St0h7EXJAiEAx+iRmZKhJD6VT84dtX5ZYNVk3j3dAcIOovpzUj9a0CECIEduTCapmZQ5xqAEsLXuVlxRtQgLTUD4ZxDElPn8x0MhAiBE2HlcND0+qDbvtwJQQOUzDgqg5xk3w8capboVdzAlQQIhAMC+lDL7+gDYkNAft5Mu+NObJmQs4Cr+DkDFsKqoxqrm"
;
const
char
*
B64LCert
=
"MIIBeTCCASMCEHqkOHVRRWr+1COq3CR/xsowDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTA1MDYyMzAwMjkxOFoXDTA2MDYyNDAwMjkxOFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCvLeZfj1G0wuJb8JTcVeZaZftncEmRluOnaME3ustd918lRMDYokZmtmDZN8SrP0yd1pfVqZ7NkmBACbBX0k7pAgMBAAEwDQYJKoZIhvcNAQEEBQADQQDnV8QNFVVJx/+7IselU0wsepqMurivXZzuxOmTEmTVDzCJx1xhA8jd3vGAj7XDIYiPub1PV23eY5a2ARJuw5w9"
;
const
char
*
B64CACert
=
"MIIBYDCCAQoCAQEwDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTAyMDIwNDE4MjU1MloXDTEyMDIwMzE4MjU1MlowOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPGeGwV41EIhX0jEDFLRXQhDEr50OUQPq+f55VwQd0TQNts06BP29+UiNdRW3c3IRHdZcJdC1Cg68ME9cgeq0h8CAwEAATANBgkqhkiG9w0BAQQFAANBAGkzBSj1EnnmUxbaiG1N4xjIuLAWydun7o3bFk2tV8dBIhnuh445obYyk1EnQ27kI7eACCILBZqi2MHDOIMnoN0="
;
/*
* Init OSP client end
* return
*/
static
void
osp_init_osptk
(
void
)
{
osp_provider_t
*
provider
;
OSPTPRIVATEKEY
privatekey
;
unsigned
char
privatekeydata
[
OSP_SIZE_KEYSTR
];
OSPT_CERT
localcert
;
unsigned
char
localcertdata
[
OSP_SIZE_KEYSTR
];
const
OSPT_CERT
*
pcacert
;
OSPT_CERT
cacert
;
unsigned
char
cacertdata
[
OSP_SIZE_KEYSTR
];
int
error
;
if
(
osp_globals
.
hardware
)
{
if
((
error
=
OSPPInit
(
OSPC_TRUE
))
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unable to enable crypto hardware, error '%d'
\n
"
,
error
);
osp_globals
.
hardware
=
SWITCH_FALSE
;
OSPPInit
(
OSPC_FALSE
);
}
}
else
{
OSPPInit
(
OSPC_FALSE
);
}
for
(
provider
=
osp_providers
;
provider
;
provider
=
provider
->
next
)
{
privatekey
.
PrivateKeyData
=
privatekeydata
;
privatekey
.
PrivateKeyLength
=
sizeof
(
privatekeydata
);
localcert
.
CertData
=
localcertdata
;
localcert
.
CertDataLength
=
sizeof
(
localcertdata
);
pcacert
=
&
cacert
;
cacert
.
CertData
=
cacertdata
;
cacert
.
CertDataLength
=
sizeof
(
cacertdata
);
if
((
error
=
OSPPBase64Decode
(
B64PKey
,
strlen
(
B64PKey
),
privatekey
.
PrivateKeyData
,
&
privatekey
.
PrivateKeyLength
))
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unable to decode private key, error '%d'
\n
"
,
error
);
}
else
if
((
error
=
OSPPBase64Decode
(
B64LCert
,
strlen
(
B64LCert
),
localcert
.
CertData
,
&
localcert
.
CertDataLength
))
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unable to decode local cert, error '%d'
\n
"
,
error
);
}
else
if
((
error
=
OSPPBase64Decode
(
B64CACert
,
strlen
(
B64CACert
),
cacert
.
CertData
,
&
cacert
.
CertDataLength
))
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unable to decode cacert, error '%d'
\n
"
,
error
);
}
if
(
error
==
OSPC_ERR_NO_ERROR
)
{
error
=
OSPPProviderNew
(
provider
->
spnum
,
/* Number of service points */
provider
->
spurls
,
/* Service point URLs */
NULL
,
/* Weights */
OSP_AUDIT_URL
,
/* Audit URL */
&
privatekey
,
/* Provate key */
&
localcert
,
/* Local cert */
1
,
/* Number of cacerts */
&
pcacert
,
/* cacerts */
OSP_LOCAL_VALID
,
/* Validating method */
provider
->
lifetime
,
/* SS lifetime */
provider
->
maxconnect
,
/* HTTP max connections */
provider
->
persistence
,
/* HTTP persistence */
provider
->
retrydelay
,
/* HTTP retry delay, in seconds */
provider
->
retrylimit
,
/* HTTP retry times */
provider
->
timeout
,
/* HTTP timeout */
OSP_CUSTOMER_ID
,
/* Customer ID */
OSP_DEVICE_ID
,
/* Device ID */
&
provider
->
handle
);
/* Provider handle */
if
(
error
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unable to create provider %s, error '%d'
\n
"
,
provider
->
name
,
error
);
provider
->
handle
=
OSP_INVALID_HANDLE
;
}
}
}
}
/*
* Get protocol name
* param protocol Supported protocol
* return protocol name
*/
static
const
char
*
osp_get_protocol
(
OSPE_DEST_PROTOCOL
protocol
)
{
const
char
*
name
;
switch
(
protocol
)
{
case
OSPC_DPROT_UNKNOWN
:
name
=
OSP_PROTOCOL_UNKNO
;
break
;
case
OSPC_DPROT_UNDEFINED
:
name
=
OSP_PROTOCOL_UNDEF
;
break
;
case
OSPC_DPROT_SIP
:
name
=
OSP_PROTOCOL_SIP
;
break
;
case
OSPC_DPROT_Q931
:
name
=
OSP_PROTOCOL_H323
;
break
;
case
OSPC_DPROT_IAX
:
name
=
OSP_PROTOCOL_IAX
;
break
;
case
OSPC_DPROT_SKYPE
:
name
=
OSP_PROTOCOL_SKYPE
;
break
;
case
OSPC_DPROT_LRQ
:
case
OSPC_DPROT_T37
:
case
OSPC_DPROT_T38
:
case
OSPC_DPROT_SMPP
:
case
OSPC_DPROT_XMPP
:
case
OSPC_DPROT_SMS
:
default:
name
=
OSP_PROTOCOL_UNSUP
;
break
;
}
return
name
;
}
/*
* Macro expands to:
* static switch_status_t osp_api_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream)
*/
SWITCH_STANDARD_API
(
osp_api_function
)
{
int
i
,
argc
=
0
;
char
*
argv
[
2
]
=
{
0
};
char
*
params
=
NULL
;
char
*
param
=
NULL
;
osp_provider_t
*
provider
;
char
*
loglevel
;
if
(
session
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"This function cannot be called from the dialplan.
\n
"
);
return
SWITCH_STATUS_FALSE
;
}
if
(
switch_strlen_zero
(
cmd
))
{
stream
->
write_function
(
stream
,
"Usage: osp status
\n
"
);
return
SWITCH_STATUS_SUCCESS
;
}
if
(
!
(
params
=
switch_safe_strdup
(
cmd
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to duplicate parameters
\n
"
);
return
SWITCH_STATUS_MEMERR
;
}
if
((
argc
=
switch_separate_string
(
params
,
' '
,
argv
,
(
sizeof
(
argv
)
/
sizeof
(
argv
[
0
])))))
{
param
=
argv
[
0
];
if
(
!
strcasecmp
(
param
,
"status"
))
{
stream
->
write_function
(
stream
,
"=============== OSP Module Settings & Status ===============
\n
"
);
stream
->
write_function
(
stream
,
" debug-info: %s
\n
"
,
osp_globals
.
debug
?
"enabled"
:
"disabled"
);
switch
(
osp_globals
.
loglevel
)
{
case
SWITCH_LOG_CONSOLE
:
loglevel
=
"console"
;
break
;
case
SWITCH_LOG_ALERT
:
loglevel
=
"alert"
;
break
;
case
SWITCH_LOG_CRIT
:
loglevel
=
"crit"
;
break
;
case
SWITCH_LOG_ERROR
:
loglevel
=
"error"
;
break
;
case
SWITCH_LOG_WARNING
:
loglevel
=
"warning"
;
break
;
case
SWITCH_LOG_NOTICE
:
loglevel
=
"notice"
;
break
;
case
SWITCH_LOG_INFO
:
loglevel
=
"info"
;
break
;
case
SWITCH_LOG_DEBUG
:
default
:
loglevel
=
"debug"
;
break
;
}
stream
->
write_function
(
stream
,
" log-level: %s
\n
"
,
loglevel
);
stream
->
write_function
(
stream
,
" crypto-hardware: %s
\n
"
,
osp_globals
.
hardware
?
"enabled"
:
"disabled"
);
if
(
switch_strlen_zero
(
osp_globals
.
module
[
OSPC_DPROT_SIP
])
||
switch_strlen_zero
(
osp_globals
.
profile
[
OSPC_DPROT_SIP
]))
{
stream
->
write_function
(
stream
,
" sip: unsupported
\n
"
);
}
else
{
stream
->
write_function
(
stream
,
" sip: %s/%s
\n
"
,
osp_globals
.
module
[
OSPC_DPROT_SIP
],
osp_globals
.
profile
[
OSPC_DPROT_SIP
]);
}
if
(
switch_strlen_zero
(
osp_globals
.
module
[
OSPC_DPROT_Q931
])
||
switch_strlen_zero
(
osp_globals
.
profile
[
OSPC_DPROT_Q931
]))
{
stream
->
write_function
(
stream
,
" h323: unsupported
\n
"
);
}
else
{
stream
->
write_function
(
stream
,
" h323: %s/%s
\n
"
,
osp_globals
.
module
[
OSPC_DPROT_Q931
],
osp_globals
.
profile
[
OSPC_DPROT_Q931
]);
}
if
(
switch_strlen_zero
(
osp_globals
.
module
[
OSPC_DPROT_IAX
])
||
switch_strlen_zero
(
osp_globals
.
profile
[
OSPC_DPROT_IAX
]))
{
stream
->
write_function
(
stream
,
" iax: unsupported
\n
"
);
}
else
{
stream
->
write_function
(
stream
,
" iax: %s/%s
\n
"
,
osp_globals
.
module
[
OSPC_DPROT_IAX
],
osp_globals
.
profile
[
OSPC_DPROT_IAX
]);
}
if
(
switch_strlen_zero
(
osp_globals
.
module
[
OSPC_DPROT_SKYPE
])
||
switch_strlen_zero
(
osp_globals
.
profile
[
OSPC_DPROT_SKYPE
]))
{
stream
->
write_function
(
stream
,
" skype: unsupported
\n
"
);
}
else
{
stream
->
write_function
(
stream
,
" skype: %s/%s
\n
"
,
osp_globals
.
module
[
OSPC_DPROT_SKYPE
],
osp_globals
.
profile
[
OSPC_DPROT_SKYPE
]);
}
stream
->
write_function
(
stream
,
" default-protocol: %s
\n
"
,
osp_get_protocol
(
osp_globals
.
protocol
));
stream
->
write_function
(
stream
,
"============== OSP Profiles Settings & Status ==============
\n
"
);
for
(
provider
=
osp_providers
;
provider
;
provider
=
provider
->
next
)
{
stream
->
write_function
(
stream
,
"Profile: %s
\n
"
,
provider
->
name
);
for
(
i
=
0
;
i
<
provider
->
spnum
;
i
++
)
{
stream
->
write_function
(
stream
,
" service-point-url: %s
\n
"
,
provider
->
spurls
[
i
]);
}
stream
->
write_function
(
stream
,
" device-ip: %s
\n
"
,
provider
->
device
);
stream
->
write_function
(
stream
,
" ssl-lifetime: %d
\n
"
,
provider
->
lifetime
);
stream
->
write_function
(
stream
,
" http-max-connections: %d
\n
"
,
provider
->
maxconnect
);
stream
->
write_function
(
stream
,
" http-persistence: %d
\n
"
,
provider
->
persistence
);
stream
->
write_function
(
stream
,
" http-retry-dalay: %d
\n
"
,
provider
->
retrydelay
);
stream
->
write_function
(
stream
,
" http-retry-limit: %d
\n
"
,
provider
->
retrylimit
);
stream
->
write_function
(
stream
,
" http-timeout: %d
\n
"
,
provider
->
timeout
);
switch
(
provider
->
srvtype
)
{
case
OSP_SRV_NPQUERY
:
stream
->
write_function
(
stream
,
" service-type: npquery
\n
"
);
break
;
case
OSP_SRV_VOICE
:
default
:
stream
->
write_function
(
stream
,
" service-type: voice
\n
"
);
break
;
}
stream
->
write_function
(
stream
,
" max-destinations: %d
\n
"
,
provider
->
maxdest
);
stream
->
write_function
(
stream
,
" user-phone: %s
\n
"
,
provider
->
userphone
?
"enabled"
:
"disabled"
);
stream
->
write_function
(
stream
,
" status: %s
\n
"
,
provider
->
handle
!=
OSP_INVALID_HANDLE
?
"enabled"
:
"disabled"
);
}
}
else
{
stream
->
write_function
(
stream
,
"Invalid Syntax!
\n
"
);
}
}
else
{
stream
->
write_function
(
stream
,
"Invalid Input!
\n
"
);
}
switch_safe_free
(
params
);
return
SWITCH_STATUS_SUCCESS
;
}
/*
* Parse URI userinfo
* param user URI userinfo
* param user URI user
* param usersize Size of user buffer
* param inbound Inbound info
* return
*/
static
void
osp_parse_userinfo
(
const
char
*
userinfo
,
char
*
user
,
switch_size_t
usersize
,
osp_inbound_t
*
inbound
)
{
char
buffer
[
OSP_SIZE_NORSTR
];
char
*
item
;
char
*
tmp
;
if
(
switch_strlen_zero
(
userinfo
))
{
if
(
user
&&
usersize
)
{
user
[
0
]
=
'\0'
;
}
/* It is not necessary to clean inbound */
return
;
}
switch_copy_string
(
buffer
,
userinfo
,
sizeof
(
buffer
));
item
=
strtok_r
(
buffer
,
OSP_USER_DELIM
,
&
tmp
);
if
(
user
&&
usersize
)
{
switch_copy_string
(
user
,
item
,
usersize
);
}
if
(
inbound
)
{
switch_copy_string
(
inbound
->
called
,
item
,
sizeof
(
inbound
->
called
));
for
(
item
=
strtok_r
(
NULL
,
OSP_USER_DELIM
,
&
tmp
);
item
;
item
=
strtok_r
(
NULL
,
OSP_USER_DELIM
,
&
tmp
))
{
if
(
!
strncasecmp
(
item
,
"rn="
,
3
))
{
switch_copy_string
(
inbound
->
nprn
,
item
+
3
,
sizeof
(
inbound
->
nprn
));
}
else
if
(
!
strncasecmp
(
item
,
"cic="
,
4
))
{
switch_copy_string
(
inbound
->
npcic
,
item
+
4
,
sizeof
(
inbound
->
npcic
));
}
else
if
(
!
strcasecmp
(
item
,
"npdi"
))
{
inbound
->
npdi
=
1
;
}
}
}
}
/*
* Parse SIP Diversion
* param diversion SIP Diversion header
* param inbound Inbound info
* return
*/
static
void
osp_parse_diversion
(
const
char
*
diversion
,
osp_inbound_t
*
inbound
)
{
char
buffer
[
OSP_SIZE_NORSTR
];
char
userinfo
[
OSP_SIZE_NORSTR
];
char
*
head
;
char
*
tmp
;
if
(
switch_strlen_zero
(
diversion
))
{
/* It is not necessary to clean inbound */
return
;
}
switch_copy_string
(
buffer
,
diversion
,
sizeof
(
buffer
));
if
((
head
=
strstr
(
buffer
,
"sip:"
)))
{
head
+=
4
;
if
((
tmp
=
strchr
(
head
,
OSP_URI_DELIM
)))
{
*
tmp
=
'\0'
;
switch_copy_string
(
userinfo
,
head
,
sizeof
(
userinfo
));
osp_parse_userinfo
(
userinfo
,
inbound
->
divuser
,
sizeof
(
inbound
->
divuser
),
NULL
);
head
=
tmp
+
1
;
tmp
=
strtok
(
head
,
OSP_HOST_DELIM
);
switch_copy_string
(
inbound
->
divhost
,
tmp
,
sizeof
(
inbound
->
divhost
));
}
}
}
/*
* Log AuthReq parameters
* param provider OSP provider
* param inbound Inbound info
* return
*/
static
void
osp_log_authreq
(
osp_provider_t
*
provider
,
osp_inbound_t
*
inbound
)
{
char
*
srvtype
;
char
term
[
OSP_SIZE_NORSTR
];
int
total
;
if
(
osp_globals
.
debug
)
{
if
(
provider
->
srvtype
==
OSP_SRV_NPQUERY
)
{
srvtype
=
"npquery"
;
if
(
switch_strlen_zero
(
inbound
->
tohost
))
{
switch_copy_string
(
term
,
provider
->
device
,
sizeof
(
term
));
}
else
{
if
(
switch_strlen_zero
(
inbound
->
toport
))
{
switch_copy_string
(
term
,
inbound
->
tohost
,
sizeof
(
term
));
}
else
{
switch_snprintf
(
term
,
sizeof
(
term
),
"%s:%s"
,
inbound
->
tohost
,
inbound
->
toport
);
}
}
total
=
1
;
}
else
{
srvtype
=
"voice"
;
term
[
0
]
=
'\0'
;
total
=
provider
->
maxdest
;
}
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
osp_globals
.
loglevel
,
"AuthReq: "
"srvtype = '%s' "
"source = '%s' "
"srcdev = '%s' "
"calling = '%s' "
"called = '%s' "
"lnp = '%s/%s/%d' "
"prefer = '%s' "
"div = '%s/%s' "
"srcnid = '%s' "
"cinfo = '%s/%s/%s/%s/%s/%s/%s/%s' "
"maxcount = '%d'
\n
"
,
srvtype
,
provider
->
device
,
inbound
->
srcdev
,
inbound
->
calling
,
inbound
->
called
,
inbound
->
nprn
,
inbound
->
npcic
,
inbound
->
npdi
,
term
,
inbound
->
divuser
,
inbound
->
divhost
,
osp_filter_null
(
inbound
->
srcnid
),
osp_filter_null
(
inbound
->
cinfo
[
0
]),
osp_filter_null
(
inbound
->
cinfo
[
1
]),
osp_filter_null
(
inbound
->
cinfo
[
2
]),
osp_filter_null
(
inbound
->
cinfo
[
3
]),
osp_filter_null
(
inbound
->
cinfo
[
4
]),
osp_filter_null
(
inbound
->
cinfo
[
5
]),
osp_filter_null
(
inbound
->
cinfo
[
6
]),
osp_filter_null
(
inbound
->
cinfo
[
7
]),
total
);
}
}
/*
* Get inbound info
* param channel Inbound channel
* param inbound Inbound info
* return
*/
static
void
osp_get_inbound
(
switch_channel_t
*
channel
,
osp_inbound_t
*
inbound
)
{
switch_caller_profile_t
*
caller
;
switch_channel_timetable_t
*
times
;
const
char
*
tmp
;
int
i
;
char
name
[
OSP_SIZE_NORSTR
];
memset
(
inbound
,
0
,
sizeof
(
*
inbound
));
caller
=
switch_channel_get_caller_profile
(
channel
);
inbound
->
srcdev
=
caller
->
network_addr
;
inbound
->
calling
=
caller
->
caller_id_number
;
osp_parse_userinfo
(
caller
->
destination_number
,
NULL
,
0
,
inbound
);
inbound
->
tohost
=
switch_channel_get_variable
(
channel
,
OSP_FS_TOHOST
);
inbound
->
toport
=
switch_channel_get_variable
(
channel
,
OSP_FS_TOPORT
);
if
((
tmp
=
switch_channel_get_variable
(
channel
,
OSP_FS_DIVERSION
)))
{
osp_parse_diversion
(
tmp
,
inbound
);
}
inbound
->
srcnid
=
switch_channel_get_variable
(
channel
,
OSP_VAR_SRCNID
);
times
=
switch_channel_get_timetable
(
channel
);
inbound
->
start
=
times
->
created
;
for
(
i
=
0
;
i
<
OSP_MAX_CINFO
;
i
++
)
{
switch_snprintf
(
name
,
sizeof
(
name
),
"%s%d"
,
OSP_VAR_CUSTOMINFO
,
i
+
1
);
inbound
->
cinfo
[
i
]
=
switch_channel_get_variable
(
channel
,
name
);
}
}
/*
* Convert "address:port" to "[x.x.x.x]:port" or "hostname:port" format
* param src Source address string
* param dest Destination address string
* param destsize Size of dest buffer
* return
*/
static
void
osp_convert_inout
(
const
char
*
src
,
char
*
dest
,
int
destsize
)
{
struct
in_addr
inp
;
char
buffer
[
OSP_SIZE_NORSTR
];
char
*
port
;
if
(
dest
&&
(
destsize
>
0
))
{
if
(
!
switch_strlen_zero
(
src
))
{
switch_copy_string
(
buffer
,
src
,
sizeof
(
buffer
));
if
((
port
=
strchr
(
buffer
,
':'
)))
{
*
port
=
'\0'
;
port
++
;
}
if
(
inet_pton
(
AF_INET
,
buffer
,
&
inp
)
==
1
)
{
if
(
port
)
{
switch_snprintf
(
dest
,
destsize
,
"[%s]:%s"
,
buffer
,
port
);
}
else
{
switch_snprintf
(
dest
,
destsize
,
"[%s]"
,
buffer
);
}
dest
[
destsize
-
1
]
=
'\0'
;
}
else
{
switch_copy_string
(
dest
,
src
,
destsize
);
}
}
else
{
*
dest
=
'\0'
;
}
}
}
/*
* Convert "[x.x.x.x]:port" or "hostname:prot" to "address:port" format
* param src Source address string
* param dest Destination address string
* param destsize Size of dest buffer
* return
*/
static
void
osp_convert_outin
(
const
char
*
src
,
char
*
dest
,
int
destsize
)
{
char
buffer
[
OSP_SIZE_NORSTR
];
char
*
end
;
char
*
port
;
if
(
dest
&&
(
destsize
>
0
))
{
if
(
!
switch_strlen_zero
(
src
))
{
switch_copy_string
(
buffer
,
src
,
sizeof
(
buffer
));
if
(
buffer
[
0
]
==
'['
)
{
if
((
port
=
strchr
(
buffer
+
1
,
':'
)))
{
*
port
=
'\0'
;
port
++
;
}
if
((
end
=
strchr
(
buffer
+
1
,
']'
)))
{
*
end
=
'\0'
;
}
if
(
port
)
{
switch_snprintf
(
dest
,
destsize
,
"%s:%s"
,
buffer
+
1
,
port
);
dest
[
destsize
-
1
]
=
'\0'
;
}
else
{
switch_copy_string
(
dest
,
buffer
+
1
,
destsize
);
}
}
else
{
switch_copy_string
(
dest
,
src
,
destsize
);
}
}
else
{
*
dest
=
'\0'
;
}
}
}
/*
* Check destination
* param handle Transaction handle
* param dest Destination
* return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed
*/
static
switch_status_t
osp_check_destination
(
OSPTTRANHANDLE
handle
,
osp_destination_t
*
dest
)
{
OSPE_DEST_OSPENABLED
enabled
;
OSPE_DEST_PROTOCOL
protocol
;
OSPE_OPERATOR_NAME
type
;
int
error
;
switch_status_t
status
=
SWITCH_STATUS_FALSE
;
if
((
handle
==
OSP_INVALID_HANDLE
)
||
!
dest
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Invalid parameters
\n
"
);
return
status
;
}
dest
->
supported
=
SWITCH_FALSE
;
if
((
error
=
OSPPTransactionIsDestOSPEnabled
(
handle
,
&
enabled
))
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to get destination OSP version, error '%d'
\n
"
,
error
);
return
status
;
}
if
((
error
=
OSPPTransactionGetDestProtocol
(
handle
,
&
protocol
))
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to get destination protocol, error '%d'
\n
"
,
error
);
return
status
;
}
switch
(
protocol
)
{
case
OSPC_DPROT_UNDEFINED
:
case
OSPC_DPROT_UNKNOWN
:
protocol
=
osp_globals
.
protocol
;
case
OSPC_DPROT_SIP
:
case
OSPC_DPROT_Q931
:
case
OSPC_DPROT_IAX
:
case
OSPC_DPROT_SKYPE
:
dest
->
protocol
=
protocol
;
if
(
!
switch_strlen_zero
(
osp_globals
.
module
[
protocol
])
&&
!
switch_strlen_zero
(
osp_globals
.
profile
[
protocol
]))
{
dest
->
supported
=
SWITCH_TRUE
;
status
=
SWITCH_STATUS_SUCCESS
;
}
break
;
case
OSPC_DPROT_LRQ
:
case
OSPC_DPROT_T37
:
case
OSPC_DPROT_T38
:
case
OSPC_DPROT_SMPP
:
case
OSPC_DPROT_XMPP
:
default
:
dest
->
protocol
=
protocol
;
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unsupported protocol '%d'
\n
"
,
protocol
);
break
;
}
if
((
error
=
OSPPTransactionGetDestinationNetworkId
(
handle
,
sizeof
(
dest
->
destnid
),
dest
->
destnid
))
!=
OSPC_ERR_NO_ERROR
)
{
dest
->
destnid
[
0
]
=
'\0'
;
}
error
=
OSPPTransactionGetNumberPortabilityParameters
(
handle
,
sizeof
(
dest
->
nprn
),
dest
->
nprn
,
sizeof
(
dest
->
npcic
),
dest
->
npcic
,
&
dest
->
npdi
);
if
(
error
!=
OSPC_ERR_NO_ERROR
)
{
dest
->
nprn
[
0
]
=
'\0'
;
dest
->
npcic
[
0
]
=
'\0'
;
dest
->
npdi
=
0
;
}
for
(
type
=
OSPC_OPNAME_START
;
type
<
OSPC_OPNAME_NUMBER
;
type
++
)
{
if
((
error
=
OSPPTransactionGetOperatorName
(
handle
,
type
,
sizeof
(
dest
->
opname
[
type
]),
dest
->
opname
[
type
]))
!=
OSPC_ERR_NO_ERROR
)
{
dest
->
opname
[
type
][
0
]
=
'\0'
;
}
}
return
status
;
}
/*
* Log AuthRsp parameters
* param results Routing info
* return
*/
static
void
osp_log_authrsp
(
osp_results_t
*
results
)
{
int
i
;
if
(
osp_globals
.
debug
)
{
for
(
i
=
0
;
i
<
results
->
numdest
;
i
++
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
osp_globals
.
loglevel
,
"AuthRsp: "
"transid = '%llu' "
"destcount = '%d' "
"timelimit = '%u' "
"destination = '%s' "
"calling = '%s' "
"called = '%s' "
"destnid = '%s' "
"lnp = '%s/%s/%d' "
"protocol = '%s' "
"supported = '%d'
\n
"
,
results
->
transid
,
i
+
1
,
results
->
dests
[
i
].
timelimit
,
results
->
dests
[
i
].
dest
,
results
->
dests
[
i
].
calling
,
results
->
dests
[
i
].
called
,
results
->
dests
[
i
].
destnid
,
results
->
dests
[
i
].
nprn
,
results
->
dests
[
i
].
npcic
,
results
->
dests
[
i
].
npdi
,
osp_get_protocol
(
results
->
dests
[
i
].
protocol
),
results
->
dests
[
i
].
supported
);
}
}
}
/*
* Do auth/routing request
* param provider OSP provider
* param handle Transaction handle
* param source Call originator info
* param results Routing info
* return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed
*/
static
switch_status_t
osp_do_request
(
osp_provider_t
*
provider
,
OSPTTRANHANDLE
handle
,
osp_inbound_t
*
inbound
,
osp_results_t
*
results
)
{
OSPTTRANS
*
context
;
osp_destination_t
*
dest
;
char
tmp
[
OSP_SIZE_NORSTR
];
char
src
[
OSP_SIZE_NORSTR
];
char
dev
[
OSP_SIZE_NORSTR
];
char
term
[
OSP_SIZE_NORSTR
];
const
char
*
preferred
[
2
]
=
{
NULL
};
unsigned
int
callidlen
=
0
,
tokenlen
=
0
,
total
;
int
count
,
error
;
switch_status_t
status
=
SWITCH_STATUS_FALSE
;
osp_log_authreq
(
provider
,
inbound
);
OSPPTransactionSetNumberPortability
(
handle
,
inbound
->
nprn
,
inbound
->
npcic
,
inbound
->
npdi
);
osp_convert_inout
(
inbound
->
divhost
,
tmp
,
sizeof
(
tmp
));
OSPPTransactionSetDiversion
(
handle
,
inbound
->
divuser
,
tmp
);
OSPPTransactionSetNetworkIds
(
handle
,
inbound
->
srcnid
,
NULL
);
for
(
count
=
0
;
count
<
OSP_MAX_CINFO
;
count
++
)
{
if
(
!
switch_strlen_zero
(
inbound
->
cinfo
[
count
]))
{
OSPPTransactionSetCustomInfo
(
handle
,
count
,
inbound
->
cinfo
[
count
]);
}
}
osp_convert_inout
(
provider
->
device
,
src
,
sizeof
(
src
));
osp_convert_inout
(
inbound
->
srcdev
,
dev
,
sizeof
(
dev
));
if
(
provider
->
srvtype
==
OSP_SRV_NPQUERY
)
{
OSPPTransactionSetServiceType
(
handle
,
OSPC_SERVICE_NPQUERY
);
if
(
switch_strlen_zero
(
inbound
->
tohost
))
{
switch_copy_string
(
term
,
src
,
sizeof
(
term
));
}
else
{
if
(
switch_strlen_zero
(
inbound
->
toport
))
{
switch_copy_string
(
tmp
,
inbound
->
tohost
,
sizeof
(
tmp
));
}
else
{
switch_snprintf
(
tmp
,
sizeof
(
tmp
),
"%s:%s"
,
inbound
->
tohost
,
inbound
->
toport
);
}
osp_convert_inout
(
tmp
,
term
,
sizeof
(
term
));
}
preferred
[
0
]
=
term
;
total
=
1
;
}
else
{
OSPPTransactionSetServiceType
(
handle
,
OSPC_SERVICE_VOICE
);
total
=
provider
->
maxdest
;
}
error
=
OSPPTransactionRequestAuthorisation
(
handle
,
/* Transaction handle */
src
,
/* Source */
dev
,
/* Source device */
inbound
->
calling
,
/* Calling */
OSPC_NFORMAT_E164
,
/* Calling format */
inbound
->
called
,
/* Called */
OSPC_NFORMAT_E164
,
/* Called format */
NULL
,
/* User */
0
,
/* Number of callids */
NULL
,
/* Callids */
preferred
,
/* Preferred destinations */
&
total
,
/* Destination number */
NULL
,
/* Log buffer size */
NULL
);
/* Log buffer */
if
(
error
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Unable to request routing, error '%d'
\n
"
,
error
);
results
->
numdest
=
0
;
return
status
;
}
else
if
(
!
total
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Without destination
\n
"
);
results
->
numdest
=
0
;
return
status
;
}
context
=
OSPPTransactionGetContext
(
handle
,
&
error
);
if
(
error
==
OSPC_ERR_NO_ERROR
)
{
results
->
transid
=
context
->
TransactionID
;
}
else
{
results
->
transid
=
0
;
}
switch_copy_string
(
results
->
called
,
inbound
->
called
,
sizeof
(
results
->
called
));
results
->
srcnid
=
inbound
->
srcnid
;
results
->
start
=
inbound
->
start
;
count
=
0
;
dest
=
&
results
->
dests
[
count
];
error
=
OSPPTransactionGetFirstDestination
(
handle
,
/* Transaction handle */
0
,
/* Timestamp buffer size */
NULL
,
/* Valid after */
NULL
,
/* Valid until */
&
dest
->
timelimit
,
/* Call duration limit */
&
callidlen
,
/* Callid buffer size */
NULL
,
/* Callid buffer */
sizeof
(
dest
->
called
),
/* Called buffer size */
dest
->
called
,
/* Called buffer */
sizeof
(
dest
->
calling
),
/* Calling buffer size */
dest
->
calling
,
/* Calling buffer */
sizeof
(
term
),
/* Destination buffer size */
term
,
/* Destination buffer */
0
,
/* Destination device buffer size */
NULL
,
/* Destination device buffer */
&
tokenlen
,
/* Token buffer length */
NULL
);
/* Token buffer */
if
(
error
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to get first destination, error '%d'
\n
"
,
error
);
return
status
;
}
osp_convert_outin
(
term
,
dest
->
dest
,
sizeof
(
dest
->
dest
));
osp_check_destination
(
handle
,
dest
);
dest
->
userphone
=
provider
->
userphone
;
for
(
count
=
1
;
count
<
total
;
count
++
)
{
dest
=
&
results
->
dests
[
count
];
error
=
OSPPTransactionGetNextDestination
(
handle
,
/* Transsaction handle */
OSPC_FAIL_NONE
,
/* Failure reason */
0
,
/* Timestamp buffer size */
NULL
,
/* Valid after */
NULL
,
/* Valid until */
&
dest
->
timelimit
,
/* Call duration limit */
&
callidlen
,
/* Callid buffer size */
NULL
,
/* Callid buffer */
sizeof
(
dest
->
called
),
/* Called buffer size */
dest
->
called
,
/* Called buffer */
sizeof
(
dest
->
calling
),
/* Calling buffer size */
dest
->
calling
,
/* Calling buffer */
sizeof
(
term
),
/* Destination buffer size */
term
,
/* Destination buffer */
0
,
/* Destination device buffer size */
NULL
,
/* Destination device buffer */
&
tokenlen
,
/* Token buffer length */
NULL
);
/* Token buffer */
if
(
error
==
OSPC_ERR_NO_ERROR
)
{
osp_convert_outin
(
term
,
dest
->
dest
,
sizeof
(
dest
->
dest
));
osp_check_destination
(
handle
,
dest
);
dest
->
userphone
=
provider
->
userphone
;
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to get destination, error '%d'
\n
"
,
error
);
break
;
}
}
if
(
count
==
total
)
{
results
->
numdest
=
total
;
osp_log_authrsp
(
results
);
status
=
SWITCH_STATUS_SUCCESS
;
}
return
status
;
}
/*
* Request auth/routing info
* param channel Originator channel
* param profile Provider name
* param results Routing info
* return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed
*/
static
switch_status_t
osp_request_routing
(
switch_channel_t
*
channel
,
const
char
*
profile
,
osp_results_t
*
results
)
{
osp_provider_t
*
provider
;
OSPTTRANHANDLE
handle
;
osp_inbound_t
inbound
;
int
error
;
switch_status_t
status
=
SWITCH_STATUS_FALSE
;
if
(
osp_find_provider
(
profile
,
&
provider
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to find provider '%s'
\n
"
,
profile
);
return
status
;
}
if
(
provider
->
handle
==
OSP_INVALID_HANDLE
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Disabled provider '%s'
\n
"
,
profile
);
return
status
;
}
results
->
profile
=
profile
;
if
((
error
=
OSPPTransactionNew
(
provider
->
handle
,
&
handle
))
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to create transaction handle, error '%d'
\n
"
,
error
);
return
status
;
}
osp_get_inbound
(
channel
,
&
inbound
);
status
=
osp_do_request
(
provider
,
handle
,
&
inbound
,
results
);
OSPPTransactionDelete
(
handle
);
return
status
;
}
/*
* Build parameter string for all channels
* param results Routing results
* param buffer Buffer
* param bufsize Buffer size
* return
*/
static
void
osp_build_allparam
(
osp_results_t
*
results
,
char
*
buffer
,
switch_size_t
bufsize
)
{
char
*
head
=
buffer
;
switch_size_t
len
,
size
=
bufsize
;
if
(
results
&&
head
&&
size
)
{
switch_snprintf
(
head
,
size
,
"{%s=%s,%s=%llu,%s=%llu"
,
OSP_VAR_PROFILE
,
results
->
profile
,
OSP_VAR_TRANSID
,
results
->
transid
,
OSP_VAR_START
,
results
->
start
);
osp_adjust_len
(
head
,
size
,
len
);
if
(
!
switch_strlen_zero
(
results
->
srcnid
))
{
switch_snprintf
(
head
,
size
,
",%s=%s"
,
OSP_VAR_SRCNID
,
results
->
srcnid
);
}
osp_adjust_len
(
head
,
size
,
len
);
switch_snprintf
(
head
,
size
,
"}"
);
osp_adjust_len
(
head
,
size
,
len
);
}
}
/*
* Build parameter string for each channel
* param count Destination count
* param dest Destination
* param buffer Buffer
* param bufsize Buffer size
* return
*/
static
void
osp_build_eachparam
(
int
count
,
osp_destination_t
*
dest
,
char
*
buffer
,
switch_size_t
bufsize
)
{
char
*
head
=
buffer
;
switch_size_t
len
,
size
=
bufsize
;
if
((
count
>
0
)
&&
dest
&&
head
&&
size
)
{
switch_snprintf
(
buffer
,
bufsize
,
"[%s=%d,%s=%s,%s=%s"
,
OSP_VAR_DESTCOUNT
,
count
,
OSP_VAR_DESTIP
,
dest
->
dest
,
OSP_FS_OUTCALLING
,
dest
->
calling
);
osp_adjust_len
(
head
,
size
,
len
);
if
(
!
switch_strlen_zero_buf
(
dest
->
destnid
))
{
switch_snprintf
(
head
,
size
,
",%s=%s"
,
OSP_VAR_DESTNID
,
dest
->
destnid
);
}
osp_adjust_len
(
head
,
size
,
len
);
switch_snprintf
(
head
,
size
,
"]"
);
osp_adjust_len
(
head
,
size
,
len
);
}
}
/*
* Build endpoint string
* param dest Destination
* param buffer Buffer
* param bufsize Buffer size
* return
*/
static
void
osp_build_endpoint
(
osp_destination_t
*
dest
,
char
*
buffer
,
switch_size_t
bufsize
)
{
char
*
head
=
buffer
;
switch_size_t
len
,
size
=
bufsize
;
if
(
head
&&
size
)
{
switch
(
dest
->
protocol
)
{
case
OSPC_DPROT_SIP
:
switch_snprintf
(
head
,
size
,
"%s/%s/%s"
,
osp_globals
.
module
[
OSPC_DPROT_SIP
],
osp_globals
.
profile
[
OSPC_DPROT_SIP
],
dest
->
called
);
osp_adjust_len
(
head
,
size
,
len
);
if
(
!
switch_strlen_zero_buf
(
dest
->
nprn
))
{
switch_snprintf
(
head
,
size
,
";rn=%s"
,
dest
->
nprn
);
osp_adjust_len
(
head
,
size
,
len
);
}
if
(
!
switch_strlen_zero_buf
(
dest
->
npcic
))
{
switch_snprintf
(
head
,
size
,
";cic=%s"
,
dest
->
npcic
);
osp_adjust_len
(
head
,
size
,
len
);
}
if
(
dest
->
npdi
)
{
switch_snprintf
(
head
,
size
,
";npdi"
);
osp_adjust_len
(
head
,
size
,
len
);
}
switch_snprintf
(
head
,
size
,
"@%s"
,
dest
->
dest
);
osp_adjust_len
(
head
,
size
,
len
);
if
(
dest
->
userphone
)
{
switch_snprintf
(
head
,
size
,
";user=phone"
);
osp_adjust_len
(
head
,
size
,
len
);
}
break
;
case
OSPC_DPROT_Q931
:
switch_snprintf
(
head
,
size
,
"%s/%s/%s@%s"
,
osp_globals
.
module
[
OSPC_DPROT_Q931
],
osp_globals
.
profile
[
OSPC_DPROT_Q931
],
dest
->
called
,
dest
->
dest
);
osp_adjust_len
(
head
,
size
,
len
);
break
;
case
OSPC_DPROT_IAX
:
switch_snprintf
(
head
,
size
,
"%s/%s/%s/%s"
,
osp_globals
.
module
[
OSPC_DPROT_Q931
],
osp_globals
.
profile
[
OSPC_DPROT_Q931
],
dest
->
dest
,
dest
->
called
);
osp_adjust_len
(
head
,
size
,
len
);
break
;
case
OSPC_DPROT_SKYPE
:
switch_snprintf
(
head
,
size
,
"%s/%s/%s"
,
osp_globals
.
module
[
OSPC_DPROT_Q931
],
osp_globals
.
profile
[
OSPC_DPROT_Q931
],
dest
->
called
);
osp_adjust_len
(
head
,
size
,
len
);
break
;
default
:
buffer
[
0
]
=
'\0'
;
break
;
}
}
}
/*
* Create route string
* param channel Originator channel
* param numdest Numer of destinations
* param destlist Destinations
* return
*/
static
void
osp_create_route
(
switch_channel_t
*
channel
,
osp_results_t
*
results
)
{
osp_destination_t
*
dest
;
char
name
[
OSP_SIZE_NORSTR
];
char
value
[
OSP_SIZE_NORSTR
];
char
eachparam
[
OSP_SIZE_NORSTR
];
char
endpoint
[
OSP_SIZE_NORSTR
];
char
buffer
[
OSP_SIZE_ROUSTR
];
int
i
,
len
,
count
,
size
=
sizeof
(
buffer
);
char
*
head
=
buffer
;
switch_event_header_t
*
hi
;
char
*
var
;
/* Cleanup OSP varibales in originator */
if
((
hi
=
switch_channel_variable_first
(
channel
)))
{
for
(;
hi
;
hi
=
hi
->
next
)
{
var
=
hi
->
name
;
if
(
var
&&
!
strncmp
(
var
,
"osp_"
,
4
))
{
switch_channel_set_variable
(
channel
,
var
,
NULL
);
}
}
switch_channel_variable_last
(
channel
);
}
osp_build_allparam
(
results
,
head
,
size
);
osp_adjust_len
(
head
,
size
,
len
);
for
(
count
=
0
,
i
=
0
;
i
<
results
->
numdest
;
i
++
)
{
dest
=
&
results
->
dests
[
i
];
if
(
dest
->
supported
)
{
count
++
;
osp_build_eachparam
(
i
+
1
,
dest
,
eachparam
,
sizeof
(
eachparam
));
osp_build_endpoint
(
dest
,
endpoint
,
sizeof
(
endpoint
));
switch_snprintf
(
name
,
sizeof
(
name
),
"%s%d"
,
OSP_VAR_ROUTEPRE
,
count
);
switch_snprintf
(
value
,
sizeof
(
value
),
"%s%s"
,
eachparam
,
endpoint
);
switch_channel_set_variable_var_check
(
channel
,
name
,
value
,
SWITCH_FALSE
);
switch_snprintf
(
head
,
size
,
"%s|"
,
value
);
osp_adjust_len
(
head
,
size
,
len
);
}
}
switch_snprintf
(
value
,
sizeof
(
value
),
"%d"
,
count
);
switch_channel_set_variable_var_check
(
channel
,
OSP_VAR_ROUTECOUNT
,
value
,
SWITCH_FALSE
);
if
(
count
)
{
*
(
buffer
+
strlen
(
buffer
)
-
1
)
=
'\0'
;
}
else
{
buffer
[
0
]
=
'\0'
;
}
switch_channel_set_variable_var_check
(
channel
,
OSP_VAR_AUTOROUTE
,
buffer
,
SWITCH_FALSE
);
}
/*
* Macro expands to:
* static void osp_app_function(switch_core_session_t *session, const char *data)
*/
SWITCH_STANDARD_APP
(
osp_app_function
)
{
int
argc
=
0
;
char
*
argv
[
2
]
=
{
0
};
char
*
params
=
NULL
;
char
*
profile
=
NULL
;
switch_channel_t
*
channel
;
osp_results_t
results
;
switch_status_t
retval
;
if
(
osp_globals
.
shutdown
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"OSP application inavailable
\n
"
);
return
;
}
/* Make sure there is a valid channel when starting the OSP application */
if
(
!
(
channel
=
switch_core_session_get_channel
(
session
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to find origiantor channel
\n
"
);
return
;
}
if
(
!
(
params
=
switch_core_session_strdup
(
session
,
data
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to alloc parameters
\n
"
);
return
;
}
if
((
argc
=
switch_separate_string
(
params
,
' '
,
argv
,
(
sizeof
(
argv
)
/
sizeof
(
argv
[
0
])))))
{
profile
=
argv
[
0
];
}
else
{
profile
=
OSP_DEF_PROFILE
;
}
retval
=
osp_request_routing
(
channel
,
profile
,
&
results
);
if
(
retval
==
SWITCH_STATUS_SUCCESS
)
{
osp_create_route
(
channel
,
&
results
);
}
}
/*
* Add application
* param session
* param channel Originator channel
* param extenstion
* param results OSP routing info
* return
*/
static
void
osp_add_application
(
switch_core_session_t
*
session
,
switch_channel_t
*
channel
,
switch_caller_extension_t
**
extension
,
osp_results_t
*
results
)
{
osp_destination_t
*
dest
;
char
allparam
[
OSP_SIZE_NORSTR
];
char
eachparam
[
OSP_SIZE_NORSTR
];
char
endpoint
[
OSP_SIZE_NORSTR
];
char
buffer
[
OSP_SIZE_ROUSTR
];
int
i
;
if
((
*
extension
=
switch_caller_extension_new
(
session
,
results
->
called
,
results
->
called
))
==
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_CRIT
,
"Failed to create extension
\n
"
);
return
;
}
switch_channel_set_variable
(
channel
,
SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE
,
"true"
);
osp_build_allparam
(
results
,
allparam
,
sizeof
(
allparam
));
for
(
i
=
0
;
i
<
results
->
numdest
;
i
++
)
{
dest
=
&
results
->
dests
[
i
];
if
(
dest
->
supported
)
{
osp_build_eachparam
(
i
+
1
,
dest
,
eachparam
,
sizeof
(
eachparam
));
osp_build_endpoint
(
dest
,
endpoint
,
sizeof
(
endpoint
));
switch_snprintf
(
buffer
,
sizeof
(
buffer
),
"%s%s%s"
,
allparam
,
eachparam
,
endpoint
);
switch_caller_extension_add_application
(
session
,
*
extension
,
"bridge"
,
buffer
);
}
}
}
/*
* Macro expands to:
* switch_caller_extension_t * osp_dialplan_function(switch_core_session_t *session, void *arg, switch_caller_profile_t *caller_profile)
*/
SWITCH_STANDARD_DIALPLAN
(
osp_dialplan_function
)
{
int
argc
=
0
;
char
*
argv
[
2
]
=
{
0
};
char
*
profile
=
NULL
;
switch_caller_extension_t
*
extension
=
NULL
;
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
session
);
osp_results_t
results
;
switch_status_t
retval
;
if
(
osp_globals
.
shutdown
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"OSP dialplan inavailable
\n
"
);
return
extension
;
}
if
((
argc
=
switch_separate_string
((
char
*
)
arg
,
' '
,
argv
,
(
sizeof
(
argv
)
/
sizeof
(
argv
[
0
])))))
{
profile
=
argv
[
0
];
}
else
{
profile
=
OSP_DEF_PROFILE
;
}
retval
=
osp_request_routing
(
channel
,
profile
,
&
results
);
if
(
retval
==
SWITCH_STATUS_SUCCESS
)
{
osp_add_application
(
session
,
channel
,
&
extension
,
&
results
);
}
return
extension
;
}
/*
* Retrieve OSP cookie
* param channel Destination channel
* param cookie OSP cookie
* return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed
*/
static
switch_status_t
osp_get_ospcookie
(
switch_channel_t
*
channel
,
osp_cookie_t
*
cookie
)
{
const
char
*
strvar
;
if
(
!
(
cookie
->
profile
=
switch_channel_get_variable
(
channel
,
OSP_VAR_PROFILE
)))
{
return
SWITCH_STATUS_FALSE
;
}
if
((
strvar
=
switch_channel_get_variable
(
channel
,
OSP_VAR_TRANSID
)))
{
cookie
->
transid
=
atoll
(
strvar
);
}
else
{
cookie
->
transid
=
0
;
}
if
((
strvar
=
switch_channel_get_variable
(
channel
,
OSP_VAR_START
)))
{
cookie
->
start
=
atoll
(
strvar
);
}
else
{
cookie
->
start
=
0
;
}
if
((
strvar
=
switch_channel_get_variable
(
channel
,
OSP_VAR_DESTCOUNT
)))
{
cookie
->
destcount
=
atoi
(
strvar
);
}
else
{
cookie
->
destcount
=
0
;
}
cookie
->
dest
=
switch_channel_get_variable
(
channel
,
OSP_VAR_DESTIP
);
cookie
->
srcnid
=
switch_channel_get_variable
(
channel
,
OSP_VAR_SRCNID
);
cookie
->
destnid
=
switch_channel_get_variable
(
channel
,
OSP_VAR_DESTNID
);
return
SWITCH_STATUS_SUCCESS
;
}
/*
* Retrieve usage info
* param channel Destination channel
* param originator Originator channel
* param cookie OSP cookie
* param usage Usage info
* return
*/
static
void
osp_get_usage
(
switch_channel_t
*
channel
,
switch_caller_profile_t
*
originator
,
osp_cookie_t
*
cookie
,
osp_usage_t
*
usage
)
{
const
char
*
strvar
;
switch_caller_profile_t
*
terminator
;
switch_channel_timetable_t
*
times
;
memset
(
usage
,
0
,
sizeof
(
*
usage
));
usage
->
callid
=
switch_channel_get_variable
(
channel
,
OSP_FS_OUTCALLID
);
if
(
switch_strlen_zero
(
usage
->
callid
))
{
usage
->
callid
=
OSP_DEF_CALLID
;
}
/* Originator had been checked by osp_on_reporting */
if
(
originator
)
{
usage
->
srcdev
=
originator
->
network_addr
;
usage
->
calling
=
originator
->
caller_id_number
;
osp_parse_userinfo
(
originator
->
destination_number
,
usage
->
called
,
sizeof
(
usage
->
called
),
NULL
);
}
terminator
=
switch_channel_get_caller_profile
(
channel
);
if
(
!
strcasecmp
(
terminator
->
source
,
OSP_MODULE_SIP
))
{
usage
->
protocol
=
OSPC_DPROT_SIP
;
strvar
=
switch_channel_get_variable
(
channel
,
OSP_FS_SIPRELEASE
);
if
(
!
strvar
||
!
strcasecmp
(
strvar
,
"recv_bye"
))
{
usage
->
release
=
1
;
}
}
else
if
(
!
strcasecmp
(
terminator
->
source
,
OSP_MODULE_H323
))
{
usage
->
protocol
=
OSPC_DPROT_Q931
;
}
else
if
(
!
strcasecmp
(
terminator
->
source
,
OSP_MODULE_IAX
))
{
usage
->
protocol
=
OSPC_DPROT_IAX
;
}
else
if
(
!
strcasecmp
(
terminator
->
source
,
OSP_MODULE_SKYPE
))
{
usage
->
protocol
=
OSPC_DPROT_SKYPE
;
}
else
{
usage
->
protocol
=
OSPC_DPROT_UNKNOWN
;
}
usage
->
cause
=
switch_channel_get_cause_q850
(
channel
);
times
=
switch_channel_get_timetable
(
channel
);
usage
->
alert
=
times
->
progress
;
usage
->
connect
=
times
->
answered
;
usage
->
end
=
times
->
hungup
;
if
(
times
->
answered
)
{
usage
->
duration
=
times
->
hungup
-
times
->
answered
;
usage
->
pdd
=
times
->
answered
-
cookie
->
start
;
}
usage
->
fcodec
=
switch_channel_get_variable
(
channel
,
OSP_FS_DOWNCODEC
);
usage
->
rcodec
=
switch_channel_get_variable
(
channel
,
OSP_FS_UPCODEC
);
if
((
strvar
=
switch_channel_get_variable
(
channel
,
OSP_FS_RTPDOWNOCTS
)))
{
usage
->
rtpdownoctets
=
atoi
(
strvar
);
}
else
{
usage
->
rtpdownoctets
=
OSP_DEF_STATS
;
}
if
((
strvar
=
switch_channel_get_variable
(
channel
,
OSP_FS_RTPUPOCTS
)))
{
usage
->
rtpupoctets
=
atoi
(
strvar
);
}
else
{
usage
->
rtpupoctets
=
OSP_DEF_STATS
;
}
if
((
strvar
=
switch_channel_get_variable
(
channel
,
OSP_FS_RTPDOWNPKTS
)))
{
usage
->
rtpdownpackets
=
atoi
(
strvar
);
}
else
{
usage
->
rtpdownpackets
=
OSP_DEF_STATS
;
}
if
((
strvar
=
switch_channel_get_variable
(
channel
,
OSP_FS_RTPUPPKTS
)))
{
usage
->
rtpuppackets
=
atoi
(
strvar
);
}
else
{
usage
->
rtpuppackets
=
OSP_DEF_STATS
;
}
}
/*
* Report OSP usage thread function
* param threadarg Thread argments
* return
*/
static
OSPTTHREADRETURN
osp_report_thread
(
void
*
threadarg
)
{
int
i
,
error
;
osp_threadarg_t
*
info
;
info
=
(
osp_threadarg_t
*
)
threadarg
;
OSPPTransactionRecordFailure
(
info
->
handle
,
info
->
cause
);
for
(
i
=
0
;
i
<
3
;
i
++
)
{
error
=
OSPPTransactionReportUsage
(
info
->
handle
,
/* Transaction handle */
info
->
duration
,
/* Call duration */
info
->
start
,
/* Call start time */
info
->
end
,
/* Call end time */
info
->
alert
,
/* Call alert time */
info
->
connect
,
/* Call connect time */
info
->
pdd
!=
0
,
/* Post dial delay present */
info
->
pdd
,
/* Post dial delay */
info
->
release
,
/* Release source */
NULL
,
/* Conference ID */
-
1
,
/* Packets not received by peer */
-
1
,
/* Fraction of packets not received by peer */
-
1
,
/* Packets not received that were expected */
-
1
,
/* Fraction of packets expected but not received */
NULL
,
/* Log buffer size */
NULL
);
/* Log buffer */
if
(
error
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to report usage for '%llu' attempt '%d'
\n
"
,
info
->
transid
,
i
+
1
);
}
else
{
break
;
}
}
OSPPTransactionDelete
(
info
->
handle
);
switch_safe_free
(
info
);
OSPTTHREADRETURN_NULL
();
}
/*
* Report usage
* param cookie OSP cookie
* param usage Usage
* return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed
*/
static
switch_status_t
osp_report_usage
(
osp_cookie_t
*
cookie
,
osp_usage_t
*
usage
)
{
osp_provider_t
*
provider
;
OSPTTRANHANDLE
handle
;
osp_threadarg_t
*
info
;
OSPTTHREADID
threadid
;
OSPTTHRATTR
threadattr
;
int
error
;
switch_status_t
status
=
SWITCH_STATUS_FALSE
;
if
(
osp_find_provider
(
cookie
->
profile
,
&
provider
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to find provider '%s'
\n
"
,
cookie
->
profile
);
return
status
;
}
if
((
error
=
OSPPTransactionNew
(
provider
->
handle
,
&
handle
))
!=
OSPC_ERR_NO_ERROR
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to create transaction handle, error '%d'
\n
"
,
error
);
return
status
;
}
error
=
OSPPTransactionBuildUsageFromScratch
(
handle
,
/* Transaction handle */
cookie
->
transid
,
/* Transaction ID */
OSPC_ROLE_SOURCE
,
/* CDR type, source */
provider
->
device
,
/* Source */
cookie
->
dest
,
/* Destination */
usage
->
srcdev
,
/* Source device */
OSP_DEF_STRING
,
/* Destination device */
usage
->
calling
,
/* Calling */
OSPC_NFORMAT_E164
,
/* Calling format */
usage
->
called
,
/* Called */
OSPC_NFORMAT_E164
,
/* Called format */
strlen
(
usage
->
callid
),
/* Size of Call-ID */
usage
->
callid
,
/* Call-ID */
0
,
/* Failure reason */
NULL
,
/* Log buffer size */
NULL
);
/* Log buffer */
if
(
error
!=
OSPC_ERR_NO_ERROR
)
{
OSPPTransactionDelete
(
handle
);
return
status
;
}
status
=
SWITCH_STATUS_SUCCESS
;
OSPPTransactionSetDestinationCount
(
handle
,
cookie
->
destcount
);
if
(
!
switch_strlen_zero
(
cookie
->
srcnid
))
{
OSPPTransactionSetSrcNetworkId
(
handle
,
cookie
->
srcnid
);
}
if
(
!
switch_strlen_zero
(
cookie
->
destnid
))
{
OSPPTransactionSetDestNetworkId
(
handle
,
cookie
->
destnid
);
}
if
(
!
switch_strlen_zero
(
usage
->
fcodec
))
{
OSPPTransactionSetForwardCodec
(
handle
,
usage
->
fcodec
);
}
if
(
!
switch_strlen_zero
(
usage
->
rcodec
))
{
OSPPTransactionSetReverseCodec
(
handle
,
usage
->
rcodec
);
}
if
(
usage
->
rtpdownoctets
!=
OSP_DEF_STATS
)
{
OSPPTransactionSetOctets
(
handle
,
OSPC_SMETRIC_RTP
,
OSPC_SFLOW_DOWNSTREAM
,
usage
->
rtpdownoctets
);
}
if
(
usage
->
rtpupoctets
!=
OSP_DEF_STATS
)
{
OSPPTransactionSetOctets
(
handle
,
OSPC_SMETRIC_RTP
,
OSPC_SFLOW_UPSTREAM
,
usage
->
rtpupoctets
);
}
if
(
usage
->
rtpdownpackets
!=
OSP_DEF_STATS
)
{
OSPPTransactionSetPackets
(
handle
,
OSPC_SMETRIC_RTP
,
OSPC_SFLOW_DOWNSTREAM
,
usage
->
rtpdownpackets
);
}
if
(
usage
->
rtpuppackets
!=
OSP_DEF_STATS
)
{
OSPPTransactionSetPackets
(
handle
,
OSPC_SMETRIC_RTP
,
OSPC_SFLOW_UPSTREAM
,
usage
->
rtpuppackets
);
}
info
=
(
osp_threadarg_t
*
)
malloc
(
sizeof
(
osp_threadarg_t
));
info
->
handle
=
handle
;
info
->
transid
=
cookie
->
transid
;
info
->
cause
=
usage
->
cause
;
info
->
start
=
cookie
->
start
/
1000000
;
info
->
alert
=
usage
->
alert
/
1000000
;
info
->
connect
=
usage
->
connect
/
1000000
;
info
->
end
=
usage
->
end
/
1000000
;
info
->
duration
=
usage
->
duration
/
1000000
;
info
->
pdd
=
usage
->
pdd
/
1000000
;
info
->
release
=
usage
->
release
;
OSPM_THRATTR_INIT
(
threadattr
,
error
);
OSPM_SETDETACHED_STATE
(
threadattr
,
error
);
OSPM_CREATE_THREAD
(
threadid
,
&
threadattr
,
osp_report_thread
,
info
,
error
);
OSPM_THRATTR_DESTROY
(
threadattr
);
/* handle and info will be released by osp_report_thread */
return
status
;
}
/*
* Log UsageInd parameters
* param cookie OSP cookie
* param usage Usage info
* return
*/
static
void
osp_log_usageind
(
osp_cookie_t
*
cookie
,
osp_usage_t
*
usage
)
{
if
(
osp_globals
.
debug
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
osp_globals
.
loglevel
,
"UsageInd: "
"transid = '%llu' "
"destcount = '%d' "
"callid = '%s' "
"calling = '%s' "
"called = '%s' "
"srcdev = '%s' "
"dest = '%s' "
"nid = '%s/%s' "
"protocol = '%s' "
"cause = '%d' "
"release = '%s' "
"times = '%llu/%llu/%llu/%llu' "
"duration = '%llu' "
"pdd = '%llu' "
"outsessionid = '%s' "
"codec = '%s/%s' "
"rtpctets = '%d/%d' "
"rtppackets = '%d/%d'
\n
"
,
cookie
->
transid
,
cookie
->
destcount
,
usage
->
callid
,
usage
->
calling
,
usage
->
called
,
usage
->
srcdev
,
cookie
->
dest
,
osp_filter_null
(
cookie
->
srcnid
),
osp_filter_null
(
cookie
->
destnid
),
osp_get_protocol
(
usage
->
protocol
),
usage
->
cause
,
usage
->
release
?
"term"
:
"orig"
,
cookie
->
start
/
1000000
,
usage
->
alert
/
1000000
,
usage
->
connect
/
1000000
,
usage
->
end
/
1000000
,
usage
->
duration
/
1000000
,
usage
->
pdd
/
1000000
,
usage
->
callid
,
osp_filter_null
(
usage
->
fcodec
),
osp_filter_null
(
usage
->
rcodec
),
usage
->
rtpdownoctets
,
usage
->
rtpupoctets
,
usage
->
rtpdownpackets
,
usage
->
rtpuppackets
);
}
}
/*
* OSP module CS_REPORTING state handler
* param session Session
* return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed
*/
static
switch_status_t
osp_on_reporting
(
switch_core_session_t
*
session
)
{
switch_channel_t
*
channel
;
osp_cookie_t
cookie
;
osp_usage_t
usage
;
switch_caller_profile_t
*
originator
;
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
if
(
osp_globals
.
shutdown
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"OSP application inavailable
\n
"
);
return
status
;
}
/* Only report for B-leg */
if
(
!
(
channel
=
switch_core_session_get_channel
(
session
))
||
!
(
originator
=
switch_channel_get_originator_caller_profile
(
channel
)))
{
return
status
;
}
if
(
osp_get_ospcookie
(
channel
,
&
cookie
)
!=
SWITCH_STATUS_SUCCESS
)
{
return
status
;
}
osp_get_usage
(
channel
,
originator
,
&
cookie
,
&
usage
);
osp_log_usageind
(
&
cookie
,
&
usage
);
osp_report_usage
(
&
cookie
,
&
usage
);
return
status
;
}
/*
* OSP module state handlers
*/
static
switch_state_handler_table_t
state_handlers
=
{
NULL
,
/*.on_init */
NULL
,
/*.on_routing */
NULL
,
/*.on_execute */
NULL
,
/*.on_hangup */
NULL
,
/*.on_exchange_media */
NULL
,
/*.on_soft_execute */
NULL
,
/*.on_consume_media */
NULL
,
/*.on_hibernate */
NULL
,
/*.on_reset */
NULL
,
/*.on_park */
osp_on_reporting
/*.on_reporting */
};
/*
* Macro expands to:
* switch_status_t mod_osp_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool)
*/
SWITCH_MODULE_LOAD_FUNCTION
(
mod_osp_load
)
{
switch_api_interface_t
*
api_interface
;
switch_application_interface_t
*
app_interface
;
switch_dialplan_interface_t
*
dp_interface
;
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
/* Load OSP configuration */
if
((
status
=
osp_load_settings
(
pool
))
!=
SWITCH_STATUS_SUCCESS
)
{
return
status
;
}
/* Init OSP Toolkit */
osp_init_osptk
();
/* Connect OSP internal structure to the blank pointer passed to OSP module */
*
module_interface
=
switch_loadable_module_create_module_interface
(
pool
,
modname
);
/* Add CLI OSP command */
SWITCH_ADD_API
(
api_interface
,
"osp"
,
"OSP"
,
osp_api_function
,
"status"
);
switch_console_set_complete
(
"add osp status"
);
/* Add OSP application */
SWITCH_ADD_APP
(
app_interface
,
"osp"
,
"Perform an OSP lookup"
,
"Perform an OSP lookup"
,
osp_app_function
,
""
,
SAF_SUPPORT_NOMEDIA
|
SAF_ROUTING_EXEC
);
/* Add OSP dialplan */
SWITCH_ADD_DIALPLAN
(
dp_interface
,
"osp"
,
osp_dialplan_function
);
/* Add OSP state handlers */
switch_core_add_state_handler
(
&
state_handlers
);
/* Indicate that the module should continue to be loaded */
return
status
;
}
/*
* Cleanup OSP client end
* return
*/
static
void
osp_cleanup_osptk
(
void
)
{
osp_provider_t
*
provider
;
for
(
provider
=
osp_providers
;
provider
;
provider
=
provider
->
next
)
{
OSPPProviderDelete
(
provider
->
handle
,
0
);
provider
->
handle
=
OSP_INVALID_HANDLE
;
}
OSPPCleanup
();
}
/*
* Called when the system shuts down
* Macro expands to:
* switch_status_t mod_osp_shutdown(void)
*/
SWITCH_MODULE_SHUTDOWN_FUNCTION
(
mod_osp_shutdown
)
{
/* Shutdown OSP module */
osp_globals
.
shutdown
=
SWITCH_TRUE
;
/* Cleanup OSP Toolkit */
osp_cleanup_osptk
();
/* Remoeve OSP state handlers */
switch_core_remove_state_handler
(
&
state_handlers
);
return
SWITCH_STATUS_SUCCESS
;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论