From 69bd8edf419ecef8f2dccf437e3ba32d6fd71529 Mon Sep 17 00:00:00 2001 From: Di-Shi Sun Date: Fri, 15 Mar 2013 08:32:02 +0000 Subject: [PATCH] Rewrote mod_osp module and updated documentation. --- src/mod/applications/mod_osp/docs/mod_osp.txt | 354 +- src/mod/applications/mod_osp/mod_osp.c | 3796 +++++++++-------- 2 files changed, 2314 insertions(+), 1836 deletions(-) diff --git a/src/mod/applications/mod_osp/docs/mod_osp.txt b/src/mod/applications/mod_osp/docs/mod_osp.txt index a5686a4a03..a12e718740 100644 --- a/src/mod/applications/mod_osp/docs/mod_osp.txt +++ b/src/mod/applications/mod_osp/docs/mod_osp.txt @@ -1,84 +1,322 @@ FreeSWITCH Open Settlement Protocol (OSP) module -This module provides OSP based call authentication, authorization, routing lookup and call detail record (CDR) collection services using standard FreeSWITCH application and dailplan interfaces. +1 Introduction +FreeSWITCH OSP module provides OSP based call authentication, authorization, routing lookup and call detail record (CDR) collection services using standard FreeSWITCH application interface and state handlers. -The OSP module can be configured by the following parameters in osp.conf.xml: +2 Configuration Parameters +The OSP module can be configured by OSP module global parameters and OSP provider profile parameters in osp.conf.xml. -Global parameters: +2.1 Global Parameters +FreeSWITCH OSP module global configuration parameters can be set using the following format: - + Global parameter names and values can be: + - debug-info: Flag to show OSP module debug information. The default is "disabled". + - log-level: At which log level to show OSP module debug information. The default is "info". + - crypto-hardware: If to use hardware for OpenSSL. The default is "disabled". + - sip: Used SIP module and profile. The default is "sofia" and "external". + - h323: Used H.323 module and profile. The default is "h323" and "external". This option has not been implemented. + - iax: Used IAX2 module and profile. The default is "iax" and "external". This option has not been implemented. + - skype: Used Skype module and profile. The default is "skypopen" and "external". This option has not been implemented. + - default-protocol: The VoIP protocol for destinations with unknown/undefined protocol. The default is "sip". -debug-info: Flag to show OSP module debug information. The default is "disabled". -log-level: At which log level to show OSP module debug information. The default is "info". -crypto-hardware: If to use hardware for OpenSSL. The default is "disabled". -sip: Used SIP module and profile. The default is "sofia" and "external". -h323: Used H.323 module and profile. The default is "h323" and "external". This option has not been implemented. -iax: Used IAX2 module and profile. The default is "iax" and "external". This option has not been implemented. -skype: Used Skype module and profile. The default is "skypopen" and "external". This option has not been implemented. -default-protocol: The VoIP protocol for destinations with unknown/undefined protocol. The default is "sip". - -OSP provider parameters: +2.2 OSP Provider Parameters +FreeSWITCH OSP module OSP provider configuration parameters can be set using the following format: - - - + + + OSP provider parameter names ane values cab be: + - profile: OSP provider profile name. + - service-point-url: OSP service point URL. This parameter must be defined. Up to 8 URLs are allowed. + - device-ip: FreeSWITCH IP for OSP module. This parameter must be defined. + - ssl-lifetime: SSL lifetime. The default is 300 in seconds. + - http-max-connections: HTTP max connections. The default is 20. + - http-persistence: HTTP persistence. The default is 60 in seconds. + - http-retry-delay: HTTP retry delay. The default is 0 in seconds. + - http-retry-limit: HTTP retry times. The default is 2. + - http-timeout: HTTP timeout. The default is 10000 in ms. + - work-mode: OSP module work mode (direct and indirect). The default is "direct". + - service-type: OSP service type (voice and npquery). The default is "voice". + - max-destinations: Max destinations OSP server will return. It is up to 12. The default is 12. -profile: OSP provider profile name. -service-point-url: OSP service point URL. This parameter must be defined. Up to 8 URLs are allowed. -device-ip: FreeSWITCH IP for OSP module. This parameter must be defined. -ssl-lifetime: SSL lifetime. The default is 300 in seconds. -http-max-connections: HTTP max connections. The default is 20. -http-persistence: HTTP persistence. The default is 60 in seconds. -http-retry-delay: HTTP retry delay. The default is 0 in seconds. -http-retry-limit: HTTP retry times. The default is 2. -http-timeout: HTTP timeout. The default is 10000 in ms. -work-mode: OSP module work mode (direct and indirect). The default is "direct". -service-type: OSP service type (voice and npquery). The default is "voice". -max-destinations: Max destinations OSP server will return. It is up to 12. The default is 12. +3 OSP Applications +The OSP applications are called in dial plan like this: -The OSP application is called in dial plan like this: + and - +*PROFILE* is an OSP service provider profile name configured in osp.conf.xml. If data attribute is not provided or its value is empty, profile name "default" is used. -The OSP dialplan is called in dial plan like this: +3.1 OSPLookup Application +osplookup application does OSP authorization request and gets first supported destination for inbound calls. It exports a set channel variables for FreeSWITCH dial plan logic. +osplookup application accepts two sets of channel variables that are used to pass additional inbound call information and outbound control parameters to OSP module. It also exports a set of channel variables for outbound channels and FreeSWITCH dial plan logic. - +3.1.1 Inbound Call Information + - osp_source_device: Actual source device IP address channel variable. It is only for FreeSWITH OSP module running in indirect mode. + - osp_source_nid: Source device network ID channel variable. + - osp_custom_info_N: Up to 8 custom info channel variables. N is the index starting from 1. -For both OSP application and dialplan, the is an OSP service provider name configured in osp.conf.xml. If it is empty, profile "default" is used. +3.1.2 Outbound Control Parameters + - osp_networkid_userparam: The URI user parameter name that is used to present destination network ID. For example, sip:callednumber;networkid=dnid@host. + - osp_networkid_uriparam: The URI parameter name that is used to present destination network ID. For example, sip:callednumber @host;networkid=dnid. + - osp_user_phone: Flag to add "user=phone" URI parameter. The default is "disabled". + - osp_outbound_proxy: Outbound proxy IP address channel variable. -Both OSP application and dialplan accept a set of inbound channel variables that are used to pass additional call information to OSP module. These channel variables include: +3.1.3 Exported Parameters + - osp_profile_name: Used OSP provider profile name. It will be used by ospnext application and OSP module state handlers. + - osp_transaction_handle: OSP transaction handle. It will be used by ospnext application and OSP module state handlers. + - osp_transaction_id: OSP transaction ID. It will be used by ospnext application and OSP module state handlers for log purpose. + - osp_lookup_status: osplookup application status. It will be used by FreeSWITCH dial plan logic. 0 for no error. + - osp_route_total: Total number of destinations from OSP servers. It will be used by ospnext application and OSP module state handlers. + - osp_route_count: Destination index starting from 1. It will be used by ospnext application and OSP module state handlers. + - osp_auto_route: Bridge route string. It will be used by bridge application. + - osp_termiation_cause: Destination termination cause. It will be used by ospnext application and OSP module state handlers. -osp_source_device: Actual source device IP address channel variable. It is only for FreeSWITH OSP module running in indirect mode. -osp_source_nid: Source device network ID channel variable. -osp_custom_info_N: Up to 8 custom info channel variables. N is the index starting from 1. -osp_networkid_userparam: The URI user parameter name that is used to present destination network ID. -osp_networkid_uriparam: The URI parameter name that is used to present destination network ID. -osp_user_phone: Flag to add "user=phone" URI parameter. The default is "disabled". -osp_outbound_proxy: Outbound proxy IP address channel variable. +3.2 OSPNext Application +ospnext application gets next supported destination for inbound calls. It exports a set channel variables for FreeSWITCH dial plan logic. +ospnext application accepts a set of channel variables exported by osplookup application to pass OSP call transaction information to OSP module. It also exports a set of channel variables for outbound channels and FreeSWITCH dial plan logic. -Both OSP application and dialplan also export a set of channel variables for outbound channels and FreeSWITCH dial plan logic (for OSP dialplan, some exported channel variables are not visible for dial plan). These channel variables include: +3.2.1 Transaction Parameters + - osp_profile_name: Used OSP provider profile name. + - osp_transaction_handle: OSP transaction handle. + - osp_transaction_id: OSP transaction ID. It is for log purpose. + - osp_route_total: Total number of destinations from OSP servers. + - osp_route_count: destination index starting from 1. + - osp_termiation_cause: Destination termination cause. -osp_profile: Used OSP profile name. Used by outbound channels. -osp_transaction_id: OSP transaction ID. Used by outbound channels. -osp_calling: Original inbound calling number. Used by outbound channels. -osp_called: Original inbound called number. Used by outbound channels. -osp_start_time: Inbound call start time. Used by outbound channels. -osp_source_device: Actual source device. Used by outbound channels. It is only for FreeSWITH OSP module running in indirect mode. -osp_source_nid: Source network ID. Used by outbound channels. -osp_destination_total: Total number of destinations from OSP servers. Used by outbound channels. -osp_destination_count: Destination index. Used by outbound channels. -osp_destination_ip: Destination IP. Used by outbound channels. -osp_destination_nid: Destination network ID. Used by outbound channels. -osp_authreq_status: Authorization request result status. -osp_route_count: Number of supported destinations. -osp_route_N: Destination route string. N is the index starting from 1. -osp_auto_route: Bridge route string. +3.2.2 Exported Parameters + - osp_next_status: ospnext application status. It will be used by FreeSWITCH dial plan logic. 0 for no error. + - osp_route_count: Destination index starting from 1. It will be used by ospnext application and OSP module state handlers. + - osp_termiation_cause: Destination termination cause. It will be used by ospnext application and OSP module state handlers. + - osp_auto_route: Bridge route string. It will be used by bridge application. + +4 State Handler +OSP module state handler reports usage of calls. +OSP module state handler accepts a set of channel variables exported by osplookup and/or ospnext applications to pass OSP call transaction information to OSP module. + +4.1 Transaction Parameters + - osp_profile_name: Used OSP provider profile name. + - osp_transaction_handle: OSP transaction handle. + - osp_transaction_id: OSP transaction ID. It is for log purpose. + - osp_route_total: Total number of destinations from OSP servers. + - osp_route_count: destination index starting from 1. + - osp_termiation_cause: Destination termination cause. + +5 Appendix + +5.1 Sample Configuration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +5.2 Sample Dialplan + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/applications/mod_osp/mod_osp.c b/src/mod/applications/mod_osp/mod_osp.c index 6f312386f4..52ccf7d2b1 100644 --- a/src/mod/applications/mod_osp/mod_osp.c +++ b/src/mod/applications/mod_osp/mod_osp.c @@ -35,15 +35,14 @@ #include /* OSP Buffer Size Constants */ -#define OSP_SIZE_NORSTR 256 /* OSP normal string buffer size */ +#define OSP_SIZE_NORSTR 512 /* OSP normal string buffer size */ #define OSP_SIZE_KEYSTR 1024 /* OSP certificate string buffer size */ -#define OSP_SIZE_ROUSTR 4096 /* OSP route buffer size */ -#define OSP_SIZE_TOKSTR 4096 /* OSP token string buffer size */ +#define OSP_SIZE_ROUSTR 1024 /* OSP route 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 */ +/* OSP Module Configuration Constants */ +#define OSP_CONFIG_FILE "osp.conf" /* OSP module configuration file name */ +#define OSP_DEF_PROFILE "default" /* Default OSP profile name */ +#define OSP_MAX_SPNUMBER 8 /* Max number of OSP service points */ #define OSP_DEF_LIFETIME 300 /* OSP default SSL lifetime */ #define OSP_MIN_MAXCONN 1 /* OSP min max connections */ #define OSP_MAX_MAXCONN 1000 /* OSP max max connections */ @@ -58,23 +57,29 @@ #define OSP_MIN_TIMEOUT 200 /* OSP min timeout in ms */ #define OSP_MAX_TIMEOUT 60000 /* OSP max timeout in ms */ #define OSP_DEF_TIMEOUT 10000 /* OSP default timeout in ms */ -#define OSP_CUSTOMER_ID "" /* OSP customer ID */ -#define OSP_DEVICE_ID "" /* OSP device ID */ #define OSP_MIN_MAXDEST 1 /* OSP min max destinations */ #define OSP_MAX_MAXDEST 12 /* OSP max max destinations */ #define OSP_DEF_MAXDEST OSP_MAX_MAXDEST /* OSP default 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 Provider Contants */ +#define OSP_AUDIT_URL "localhost" /* OSP default Audit URL */ +#define OSP_LOCAL_VALID 1 /* OSP token validating method, locally */ +#define OSP_CUSTOMER_ID "" /* OSP customer ID */ +#define OSP_DEVICE_ID "" /* OSP device ID */ + +/* URI Contants */ +#define OSP_URI_DELIM '@' /* URI delimit */ +#define OSP_USER_DELIM ";:" /* URI userinfo delimit */ +#define OSP_HOST_DELIM ";>" /* URI hostport delimit */ + +/* OSP Module Other Contants */ +#define OSP_MAX_CINFO 8 /* Max number of custom info */ +#define OSP_DEF_STRING "" /* OSP default empty string */ +#define OSP_DEF_STATS -1 /* OSP default statistics */ + /* OSP Supported Signaling Protocols for Default Protocol */ #define OSP_PROTOCOL_SIP "sip" /* SIP protocol name */ #define OSP_PROTOCOL_H323 "h323" /* H.323 protocol name */ @@ -90,29 +95,26 @@ #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" /* Profile name, in cookie */ -#define OSP_VAR_TRANSID "osp_transaction_id" /* Transaction ID, in cookie */ -#define OSP_VAR_CALLING "osp_calling" /* Original calling number, in cookie */ -#define OSP_VAR_CALLED "osp_called" /* Original called number, in cookie */ -#define OSP_VAR_START "osp_start_time" /* Inbound Call start time, in cookie */ -#define OSP_VAR_SRCDEV "osp_source_device" /* Source device IP, in cookie or inbound (actual source device)*/ -#define OSP_VAR_SRCNID "osp_source_nid" /* Source network ID, inbound and in cookie */ -#define OSP_VAR_DESTTOTAL "osp_destination_total" /* Total number of destinations in AuthRsp, in cookie */ -#define OSP_VAR_DESTCOUNT "osp_destination_count" /* Destination count, in cookie */ -#define OSP_VAR_DESTIP "osp_destination_ip" /* Destination IP, in cookie */ -#define OSP_VAR_DESTNID "osp_destination_nid" /* Destination network ID, in cookie */ -#define OSP_VAR_CUSTOMINFO "osp_custom_info_" /* Custom info */ -#define OSP_VAR_DNIDUSERPARAM "osp_networkid_userparam" /* Destination network ID user parameter name */ -#define OSP_VAR_DNIDURIPARAM "osp_networkid_uriparam" /* Destination network ID URI parameter name */ -#define OSP_VAR_USERPHONE "osp_user_phone" /* If to add "user=phone" */ -#define OSP_VAR_OUTPROXY "osp_outbound_proxy" /* Outbound proxy */ -#define OSP_VAR_AUTHSTATUS "osp_authreq_status" /* AuthReq Status */ -#define OSP_VAR_ROUTECOUNT "osp_route_count" /* Number of destinations */ -#define OSP_VAR_ROUTEPRE "osp_route_" /* Destination prefix */ +/* OSP Variable Names */ +#define OSP_VAR_SRCDEV "osp_source_device" /* Source device IP, inbound (actual source device)*/ +#define OSP_VAR_SRCNID "osp_source_nid" /* Source network ID, inbound */ +#define OSP_VAR_CUSTOMINFO "osp_custom_info_" /* Custom info, inbound */ +#define OSP_VAR_DNIDUSERPARAM "osp_networkid_userparam" /* Destination network ID user parameter name, outbound */ +#define OSP_VAR_DNIDURIPARAM "osp_networkid_uriparam" /* Destination network ID URI parameter name, outbound */ +#define OSP_VAR_USERPHONE "osp_user_phone" /* If to add "user=phone", outbound */ +#define OSP_VAR_OUTPROXY "osp_outbound_proxy" /* Outbound proxy, outbound */ +#define OSP_VAR_PROFILE "osp_profile_name" /* Profile name */ +#define OSP_VAR_TRANSACTION "osp_transaction_handle" /* Transaction handle */ +#define OSP_VAR_TRANSID "osp_transaction_id" /* Transaction ID */ +#define OSP_VAR_ROUTETOTAL "osp_route_total" /* Total number of destinations */ +#define OSP_VAR_ROUTECOUNT "osp_route_count" /* Destination count */ +#define OSP_VAR_TCCODE "osp_termination_cause" /* Terimation cause */ #define OSP_VAR_AUTOROUTE "osp_auto_route" /* Bridge route string */ +#define OSP_VAR_LOOKUPSTATUS "osp_lookup_status" /* OSP lookup function status */ +#define OSP_VAR_NEXTSTATUS "osp_next_status" /* OSP next function status */ -/* OSP Use Variable Name */ +/* OSP Using FreeSWITCH Variable Names */ +#define OSP_FS_CALLID "sip_call_id" /* Inbound SIP Call-ID */ #define OSP_FS_FROMUSER "sip_from_user" /* Inbound SIP From user */ #define OSP_FS_TOHOST "sip_to_host" /* Inbound SIP To host */ #define OSP_FS_TOPORT "sip_to_port" /* Inbound SIP To port */ @@ -120,26 +122,32 @@ #define OSP_FS_PAI "sip_P-Asserted-Identity" /* Inbound SIP P-Asserted-Identity header */ #define OSP_FS_DIV "sip_h_Diversion" /* Inbound SIP Diversion header */ #define OSP_FS_PCI "sip_h_P-Charge-Info" /* Inbound SIP P-Charge-Info 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_SRCCODEC "write_codec" /* Source codec */ -#define OSP_FS_DESTCODEC "read_codec" /* Destiantion codec */ -#define OSP_FS_RTPSRCREPOCTS "rtp_audio_out_media_bytes" /* Source->reporter octets */ -#define OSP_FS_RTPDESTREPOCTS "rtp_audio_in_media_bytes" /* Destination->reporter octets */ -#define OSP_FS_RTPSRCREPPKTS "rtp_audio_out_media_packet_count" /* Source->reporter packets */ -#define OSP_FS_RTPDESTREPPKTS "rtp_audio_in_media_packet_count" /* Destination->reporter packets */ +#define OSP_FS_SIPRELEASE "sip_hangup_disposition" /* Usage SIP release source */ +#define OSP_FS_SRCCODEC "write_codec" /* Usage source codec */ +#define OSP_FS_DESTCODEC "read_codec" /* Usage destiantion codec */ +#define OSP_FS_RTPSRCREPOCTS "rtp_audio_out_media_bytes" /* Usage source->reporter octets */ +#define OSP_FS_RTPDESTREPOCTS "rtp_audio_in_media_bytes" /* Usage destination->reporter octets */ +#define OSP_FS_RTPSRCREPPKTS "rtp_audio_out_media_packet_count" /* Usage source->reporter packets */ +#define OSP_FS_RTPDESTREPPKTS "rtp_audio_in_media_packet_count" /* Usage destination->reporter packets */ +#define OSP_FS_HANGUPCAUSE "last_bridge_hangup_cause" /* Termination cause */ -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 *modules[OSPC_PROTNAME_NUMBER]; /* Endpoint names */ - const char *profiles[OSPC_PROTNAME_NUMBER]; /* Endpoint profile names */ - OSPE_PROTOCOL_NAME protocol; /* Default signaling protocol */ - switch_bool_t shutdown; /* OSP module status */ - switch_memory_pool_t *pool; /* OSP module memory pool */ -} osp_settings_t; +/* FreeSWITCH Endpoint Parameters */ +typedef struct osp_endpoint { + const char *module; /* Endpoint module name */ + const char *profile; /* Endpoint profile name */ +} osp_endpoint_t; + +/* OSP Global Status */ +typedef struct osp_global { + switch_bool_t debug; /* OSP module debug flag */ + switch_log_level_t loglevel; /* Log level for debug messages */ + switch_bool_t hardware; /* Crypto hardware flag */ + osp_endpoint_t endpoint[OSPC_PROTNAME_NUMBER]; /* Used endpoints */ + OSPE_PROTOCOL_NAME protocol; /* Default signaling protocol */ + switch_bool_t shutdown; /* OSP module status */ + switch_memory_pool_t *pool; /* OSP module memory pool */ +} osp_global_t; /* OSP Work Modes */ typedef enum osp_workmode { @@ -153,28 +161,32 @@ typedef enum osp_srvtype { OSP_SRV_NPQUERY /* Number portability query service */ } osp_srvtype_t; +/* OSP Profile Parameters */ typedef struct osp_profile { - const char *name; /* OSP profile name */ - int spnum; /* Number of OSP service points */ - const char *spurls[OSP_MAX_SP]; /* OSP 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_workmode_t workmode; /* OSP work mode */ - osp_srvtype_t srvtype; /* OSP service type */ - int maxdest; /* Max destinations */ - OSPTPROVHANDLE provider; /* OSP provider handle */ - struct osp_profile *next; /* Next OSP profile */ + const char *name; /* OSP profile name */ + int spnumber; /* Number of OSP service points */ + const char *spurl[OSP_MAX_SPNUMBER]; /* OSP service point URLs */ + const char *deviceip; /* OSP client end 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_workmode_t workmode; /* OSP work mode */ + osp_srvtype_t srvtype; /* OSP service type */ + int maxdest; /* Max destinations */ + OSPTPROVHANDLE provider; /* OSP provider handle */ + struct osp_profile *next; /* Next OSP profile */ } osp_profile_t; +/* OSP Inbound Parameters */ typedef struct osp_inbound { const char *actsrc; /* Actual source device IP address */ const char *srcdev; /* Source device IP address */ + const char *srcnid; /* Source network ID */ OSPE_PROTOCOL_NAME protocol; /* Inbound signaling protocol */ + const char *callid; /* Inbound Call-ID */ char calling[OSP_SIZE_NORSTR]; /* Inbound calling number */ char called[OSP_SIZE_NORSTR]; /* Inbound called number */ char nprn[OSP_SIZE_NORSTR]; /* Inbound NP routing number */ @@ -187,16 +199,20 @@ typedef struct osp_inbound { char divuser[OSP_SIZE_NORSTR]; /* Inbound user of SIP Diversion header */ char divhost[OSP_SIZE_NORSTR]; /* Inbound hostport of SIP Diversion header */ char pciuser[OSP_SIZE_NORSTR]; /* Inbound user of SIP P-Charge-Info 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 { +/* OSP Route Parameters */ +typedef struct osp_results { + const char *profile; /* Profile name */ + OSPTTRANHANDLE transaction; /* Transaction handle */ + uint64_t transid; /* Transaction ID */ + unsigned int total; /* Total number of destinations */ + unsigned int count; /* Destination count starting from 1 */ 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 dest[OSP_SIZE_NORSTR]; /* Destination IP address */ 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 */ @@ -204,35 +220,10 @@ typedef struct osp_destination { char opname[OSPC_OPNAME_NUMBER][OSP_SIZE_NORSTR]; /* Outbound Operator names */ OSPE_PROTOCOL_NAME protocol; /* Signaling protocol */ switch_bool_t supported; /* Supported by FreeRADIUS OSP module */ -} osp_destination_t; - -typedef struct osp_results { - const char *profile; /* Profile name */ - uint64_t transid; /* Transaction ID */ - switch_time_t start; /* Call start time */ - char calling[OSP_SIZE_NORSTR]; /* Original calling number */ - char called[OSP_SIZE_NORSTR]; /* Original called number */ - const char *srcdev; /* Source device IP */ - const char *srcnid; /* Source network ID */ - int status; /* AuthReq status */ - int numdest; /* Number of destinations */ - osp_destination_t dests[OSP_MAX_MAXDEST]; /* Destinations */ + switch_call_cause_t cause; /* Termination cause for current destination */ } osp_results_t; -typedef struct osp_cookie { - const char *profile; /* Profile name */ - uint64_t transid; /* Transaction ID */ - const char *calling; /* Original calling number */ - const char *called; /* Original called number */ - switch_time_t start; /* Call start time */ - const char *srcdev; /* Source Device IP */ - int desttotal; /* Total number of destinations in AuthRsp */ - int destcount; /* Destination count */ - const char *dest; /* Destination IP */ - const char *srcnid; /* Source network ID */ - const char *destnid; /* Destination network ID */ -} osp_cookie_t; - +/* OSP Outbound Parameters */ typedef struct osp_outbound { const char *dniduserparam; /* Destination network ID user parameter name */ const char *dniduriparam; /* Destination network ID URI parameter name */ @@ -240,55 +231,46 @@ typedef struct osp_outbound { const char *outproxy; /* Outbound proxy IP address */ } osp_outbound_t; +/* OSP Usage Parameters */ typedef struct osp_usage { - const char *srcdev; /* Source device IP */ - const char *callid; /* Call-ID */ - OSPE_PROTOCOL_NAME inprotocol; /* Inbound signaling protocol */ - OSPE_PROTOCOL_NAME outprotocol; /* Outbound signaling 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, in us */ - const char *srccodec; /* Source codec */ - const char *destcodec; /* Destination codec */ - int rtpsrcrepoctets; /* RTP source->reporter bytes */ - int rtpdestrepoctets; /* RTP destination->reporter bytes */ - int rtpsrcreppackets; /* RTP source->reporter packets */ - int rtpdestreppackets; /* RTP destiantion->reporter packets */ + OSPE_RELEASE release; /* Release source */ + switch_call_cause_t cause; /* Termination cause */ + switch_time_t start; /* Call start time */ + 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, in us */ + const char *srccodec; /* Source codec */ + const char *destcodec; /* Destination codec */ + int rtpsrcrepoctets; /* RTP source->reporter bytes */ + int rtpdestrepoctets; /* RTP destination->reporter bytes */ + int rtpsrcreppackets; /* RTP source->reporter packets */ + int rtpdestreppackets; /* RTP destiantion->reporter packets */ } osp_usage_t; -typedef struct osp_threadarg { - OSPTTRANHANDLE transaction; /* Transaction handle */ - uint64_t 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, in ms */ - int release; /* EP that released the call */ -} osp_threadarg_t; +/* Macro functions for debug */ +#define OSP_DEBUG(_fmt, ...) if (osp_global.debug) { switch_log_printf(SWITCH_CHANNEL_LOG, osp_global.loglevel, "%s: "_fmt"\n", __SWITCH_FUNC__, __VA_ARGS__); } +#define OSP_DEBUG_MSG(_msg) OSP_DEBUG("%s", _msg) +#define OSP_DEBUG_START OSP_DEBUG_MSG("Start") +#define OSP_DEBUG_END OSP_DEBUG_MSG("End") +/* Macro to prevent NULL string */ +#define OSP_FILTER_NULLSTR(_str) (switch_strlen_zero(_str) ? OSP_DEF_STRING : (_str)) +/* Macro to prevent NULL integer */ +#define OSP_FILTER_NULLINT(_int) ((_int) ? *(_int) : 0) +/* Macro to adjust buffer length */ +#define OSP_ADJUST_LEN(_head, _size, _len) { (_len) = strlen(_head); (_head) += (_len); (_size) -= (_len); } -/* OSP module global settings */ -static osp_settings_t osp_globals; +/* OSP Module Global Status */ +static osp_global_t osp_global; /* OSP module profiles */ static osp_profile_t *osp_profiles = 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; } +/* OSP default certificates */ +static const char *B64PKey = "MIIBOgIBAAJBAK8t5l+PUbTC4lvwlNxV5lpl+2dwSZGW46dowTe6y133XyVEwNiiRma2YNk3xKs/TJ3Wl9Wpns2SYEAJsFfSTukCAwEAAQJAPz13vCm2GmZ8Zyp74usTxLCqSJZNyMRLHQWBM0g44Iuy4wE3vpi7Wq+xYuSOH2mu4OddnxswCP4QhaXVQavTAQIhAOBVCKXtppEw9UaOBL4vW0Ed/6EA/1D8hDW6St0h7EXJAiEAx+iRmZKhJD6VT84dtX5ZYNVk3j3dAcIOovpzUj9a0CECIEduTCapmZQ5xqAEsLXuVlxRtQgLTUD4ZxDElPn8x0MhAiBE2HlcND0+qDbvtwJQQOUzDgqg5xk3w8capboVdzAlQQIhAMC+lDL7+gDYkNAft5Mu+NObJmQs4Cr+DkDFsKqoxqrm"; +static const char *B64LCert = "MIIBeTCCASMCEHqkOHVRRWr+1COq3CR/xsowDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTA1MDYyMzAwMjkxOFoXDTA2MDYyNDAwMjkxOFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCvLeZfj1G0wuJb8JTcVeZaZftncEmRluOnaME3ustd918lRMDYokZmtmDZN8SrP0yd1pfVqZ7NkmBACbBX0k7pAgMBAAEwDQYJKoZIhvcNAQEEBQADQQDnV8QNFVVJx/+7IselU0wsepqMurivXZzuxOmTEmTVDzCJx1xhA8jd3vGAj7XDIYiPub1PV23eY5a2ARJuw5w9"; +static const char *B64CACert = "MIIBYDCCAQoCAQEwDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTAyMDIwNDE4MjU1MloXDTEyMDIwMzE4MjU1MlowOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPGeGwV41EIhX0jEDFLRXQhDEr50OUQPq+f55VwQd0TQNts06BP29+UiNdRW3c3IRHdZcJdC1Cg68ME9cgeq0h8CAwEAATANBgkqhkiG9w0BAQQFAANBAGkzBSj1EnnmUxbaiG1N4xjIuLAWydun7o3bFk2tV8dBIhnuh445obYyk1EnQ27kI7eACCILBZqi2MHDOIMnoN0="; /* * Find OSP profile by name @@ -303,6 +285,8 @@ static switch_status_t osp_find_profile( osp_profile_t *p; switch_status_t status = SWITCH_STATUS_FALSE; + OSP_DEBUG_START; + if (name) { if (profile) { *profile = NULL; @@ -319,6 +303,14 @@ static switch_status_t osp_find_profile( } } + if (status == SWITCH_STATUS_SUCCESS) { + OSP_DEBUG("Found profile '%s'", name); + } else { + OSP_DEBUG("Unable to find profile '%s'", name); + } + + OSP_DEBUG_END; + return status; } @@ -327,11 +319,10 @@ static switch_status_t osp_find_profile( * 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( +static switch_status_t osp_load_config( switch_memory_pool_t *pool) { - char *cf = "osp.conf"; - switch_xml_t cfg, xml = NULL, param, settings, xprofile, profiles; + switch_xml_t xcfg, xml = NULL, xsettings, xparam, xprofile, xprofiles; const char *name; const char *value; const char *module; @@ -340,128 +331,162 @@ static switch_status_t osp_load_settings( 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; + OSP_DEBUG_START; + + /* Load OSP module configuration file */ + if (!(xml = switch_xml_open_cfg(OSP_CONFIG_FILE, &xcfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open OSP module configuration file '%s'\n", OSP_CONFIG_FILE); + OSP_DEBUG_END; + return SWITCH_STATUS_FALSE; } - memset(&osp_globals, 0, sizeof(osp_globals)); - osp_globals.loglevel = SWITCH_LOG_DEBUG; - osp_globals.pool = pool; - osp_globals.protocol = OSPC_PROTNAME_SIP; + OSP_DEBUG_MSG("Parsing settings"); - 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"); + /* Init OSP module global status */ + memset(&osp_global, 0, sizeof(osp_global)); + osp_global.loglevel = SWITCH_LOG_DEBUG; + osp_global.protocol = OSPC_PROTNAME_SIP; + osp_global.pool = pool; + + /* Get OSP module global settings */ + if ((xsettings = switch_xml_child(xcfg, "settings"))) { + for (xparam = switch_xml_child(xsettings, "param"); xparam; xparam = xparam->next) { + /* Settings parameter name */ + name = switch_xml_attr_soft(xparam, "name"); + /* Settings parameter value */ + value = switch_xml_attr_soft(xparam, "value"); + /* Endpoint module name */ + module = switch_xml_attr_soft(xparam, "module"); + /* Endpoint profile name */ + context = switch_xml_attr_soft(xparam, "profile"); + + /* Ignore parameter without name */ if (switch_strlen_zero(name)) { continue; } + if (!strcasecmp(name, "debug-info")) { + /* OSP module debug flag */ if (!switch_strlen_zero(value)) { - osp_globals.debug = switch_true(value); + osp_global.debug = switch_true(value); } + OSP_DEBUG("debug-info: '%d'", osp_global.debug); } else if (!strcasecmp(name, "log-level")) { + /* OSP module debug message log level */ if (switch_strlen_zero(value)) { continue; } else if (!strcasecmp(value, "console")) { - osp_globals.loglevel = SWITCH_LOG_CONSOLE; + osp_global.loglevel = SWITCH_LOG_CONSOLE; } else if (!strcasecmp(value, "alert")) { - osp_globals.loglevel = SWITCH_LOG_ALERT; + osp_global.loglevel = SWITCH_LOG_ALERT; } else if (!strcasecmp(value, "crit")) { - osp_globals.loglevel = SWITCH_LOG_CRIT; + osp_global.loglevel = SWITCH_LOG_CRIT; } else if (!strcasecmp(value, "error")) { - osp_globals.loglevel = SWITCH_LOG_ERROR; + osp_global.loglevel = SWITCH_LOG_ERROR; } else if (!strcasecmp(value, "warning")) { - osp_globals.loglevel = SWITCH_LOG_WARNING; + osp_global.loglevel = SWITCH_LOG_WARNING; } else if (!strcasecmp(value, "notice")) { - osp_globals.loglevel = SWITCH_LOG_NOTICE; + osp_global.loglevel = SWITCH_LOG_NOTICE; } else if (!strcasecmp(value, "info")) { - osp_globals.loglevel = SWITCH_LOG_INFO; + osp_global.loglevel = SWITCH_LOG_INFO; } else if (!strcasecmp(value, "debug")) { - osp_globals.loglevel = SWITCH_LOG_DEBUG; + osp_global.loglevel = SWITCH_LOG_DEBUG; } + OSP_DEBUG("log-level: '%d'", osp_global.loglevel); } else if (!strcasecmp(name, "crypto-hardware")) { + /* OSP module crypto hardware flag */ if (!switch_strlen_zero(value)) { - osp_globals.hardware = switch_true(value); + osp_global.hardware = switch_true(value); } + OSP_DEBUG("crypto-hardware: '%d'", osp_global.hardware); } else if (!strcasecmp(name, "default-protocol")) { + /* OSP module default signaling protocol */ if (switch_strlen_zero(value)) { continue; } else if (!strcasecmp(value, OSP_PROTOCOL_SIP)) { - osp_globals.protocol = OSPC_PROTNAME_SIP; + osp_global.protocol = OSPC_PROTNAME_SIP; } else if (!strcasecmp(value, OSP_PROTOCOL_H323)) { - osp_globals.protocol = OSPC_PROTNAME_Q931; + osp_global.protocol = OSPC_PROTNAME_Q931; } else if (!strcasecmp(value, OSP_PROTOCOL_IAX)) { - osp_globals.protocol = OSPC_PROTNAME_IAX; + osp_global.protocol = OSPC_PROTNAME_IAX; } else if (!strcasecmp(value, OSP_PROTOCOL_SKYPE)) { - osp_globals.protocol = OSPC_PROTNAME_SKYPE; + osp_global.protocol = OSPC_PROTNAME_SKYPE; } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported default protocol '%s'\n", value); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported protocol '%s'\n", value); } - } else if (!strcasecmp(name, "sip")) { + OSP_DEBUG("default-protocol: '%d'", osp_global.protocol); + } else if (!strcasecmp(name, OSP_PROTOCOL_SIP)) { + /* SIP endpoint module */ if (!switch_strlen_zero(module)) { - if (!(osp_globals.modules[OSPC_PROTNAME_SIP] = switch_core_strdup(osp_globals.pool, module))) { + if (!(osp_global.endpoint[OSPC_PROTNAME_SIP].module = switch_core_strdup(osp_global.pool, module))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to duplicate SIP module name\n"); status = SWITCH_STATUS_MEMERR; break; } } + /* SIP endpoint profile */ if (!switch_strlen_zero(context)) { - if (!(osp_globals.profiles[OSPC_PROTNAME_SIP] = switch_core_strdup(osp_globals.pool, context))) { + if (!(osp_global.endpoint[OSPC_PROTNAME_SIP].profile = switch_core_strdup(osp_global.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")) { + OSP_DEBUG("SIP: '%s/%s'", osp_global.endpoint[OSPC_PROTNAME_SIP].module, osp_global.endpoint[OSPC_PROTNAME_SIP].profile); + } else if (!strcasecmp(name, OSP_PROTOCOL_H323)) { + /* H.323 endpoint module */ if (!switch_strlen_zero(module)) { - if (!(osp_globals.modules[OSPC_PROTNAME_Q931] = switch_core_strdup(osp_globals.pool, module))) { + if (!(osp_global.endpoint[OSPC_PROTNAME_Q931].module = switch_core_strdup(osp_global.pool, module))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to duplicate H.323 module name\n"); status = SWITCH_STATUS_MEMERR; break; } } + /* H.323 endpoint profile */ if (!switch_strlen_zero(context)) { - if (!(osp_globals.profiles[OSPC_PROTNAME_Q931] = switch_core_strdup(osp_globals.pool, context))) { + if (!(osp_global.endpoint[OSPC_PROTNAME_Q931].profile = switch_core_strdup(osp_global.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")) { + OSP_DEBUG("H.323: '%s/%s'", osp_global.endpoint[OSPC_PROTNAME_Q931].module, osp_global.endpoint[OSPC_PROTNAME_Q931].profile); + } else if (!strcasecmp(name, OSP_PROTOCOL_IAX)) { + /* IAX endpoint module */ if (!switch_strlen_zero(module)) { - if (!(osp_globals.modules[OSPC_PROTNAME_IAX] = switch_core_strdup(osp_globals.pool, module))) { + if (!(osp_global.endpoint[OSPC_PROTNAME_IAX].module = switch_core_strdup(osp_global.pool, module))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to duplicate IAX module name\n"); status = SWITCH_STATUS_MEMERR; break; } } + /* IAX endpoint profile */ if (!switch_strlen_zero(context)) { - if (!(osp_globals.profiles[OSPC_PROTNAME_IAX] = switch_core_strdup(osp_globals.pool, context))) { + if (!(osp_global.endpoint[OSPC_PROTNAME_IAX].profile = switch_core_strdup(osp_global.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")) { + OSP_DEBUG("IAX: '%s/%s'", osp_global.endpoint[OSPC_PROTNAME_IAX].module, osp_global.endpoint[OSPC_PROTNAME_IAX].profile); + } else if (!strcasecmp(name, OSP_PROTOCOL_SKYPE)) { + /* Skype endpoint module */ if (!switch_strlen_zero(module)) { - if (!(osp_globals.modules[OSPC_PROTNAME_SKYPE] = switch_core_strdup(osp_globals.pool, module))) { + if (!(osp_global.endpoint[OSPC_PROTNAME_SKYPE].module = switch_core_strdup(osp_global.pool, module))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to duplicate Skype module name\n"); status = SWITCH_STATUS_MEMERR; break; } - } + } + /* Skype endpoint profile */ if (!switch_strlen_zero(context)) { - if (!(osp_globals.profiles[OSPC_PROTNAME_SKYPE] = switch_core_strdup(osp_globals.pool, context))) { + if (!(osp_global.endpoint[OSPC_PROTNAME_SKYPE].profile = switch_core_strdup(osp_global.pool, context))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to duplicate Skype profile name\n"); status = SWITCH_STATUS_MEMERR; break; } } + OSP_DEBUG("SKYPE: '%s/%s'", osp_global.endpoint[OSPC_PROTNAME_SKYPE].module, osp_global.endpoint[OSPC_PROTNAME_SKYPE].profile); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown parameter '%s'\n", name); } @@ -469,26 +494,37 @@ static switch_status_t osp_load_settings( } if (status != SWITCH_STATUS_SUCCESS) { + /* Fail for SWITCH_STATUS_MEMERR */ switch_xml_free(xml); + OSP_DEBUG_END; return status; } - if ((profiles = switch_xml_child(cfg, "profiles"))) { - for (xprofile = switch_xml_child(profiles, "profile"); xprofile; xprofile = xprofile->next) { + /* Get OSP module profiles */ + if ((xprofiles = switch_xml_child(xcfg, "profiles"))) { + for (xprofile = switch_xml_child(xprofiles, "profile"); xprofile; xprofile = xprofile->next) { + /* Profile name */ name = switch_xml_attr_soft(xprofile, "name"); if (switch_strlen_zero(name)) { name = OSP_DEF_PROFILE; } + OSP_DEBUG("Parsing profile '%s'", name); + + /* Check duplate profile name */ if (osp_find_profile(name, NULL) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignored duplicate profile '%s'\n", name); continue; } - if (!(profile = switch_core_alloc(osp_globals.pool, sizeof(*profile)))) { + + /* Allocate profile */ + if (!(profile = switch_core_alloc(osp_global.pool, sizeof(*profile)))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to alloc profile\n"); status = SWITCH_STATUS_MEMERR; break; } - if (!(profile->name = switch_core_strdup(osp_globals.pool, name))) { + + /* Store profile name */ + if (!(profile->name = switch_core_strdup(osp_global.pool, name))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to duplicate profile name\n"); status = SWITCH_STATUS_MEMERR; /* "profile" cannot free to pool in FreeSWITCH */ @@ -505,62 +541,80 @@ static switch_status_t osp_load_settings( profile->maxdest = OSP_DEF_MAXDEST; profile->provider = OSP_INVALID_HANDLE; - for (param = switch_xml_child(xprofile, "param"); param; param = param->next) { - name = switch_xml_attr_soft(param, "name"); - value = switch_xml_attr_soft(param, "value"); + for (xparam = switch_xml_child(xprofile, "param"); xparam; xparam = xparam->next) { + /* Profile parameter name */ + name = switch_xml_attr_soft(xparam, "name"); + /* Profile parameter value */ + value = switch_xml_attr_soft(xparam, "value"); + + /* Ignore profile parameter without name or value */ if (switch_strlen_zero(name) || switch_strlen_zero(value)) { continue; } + if (!strcasecmp(name, "service-point-url")) { - if (profile->spnum < OSP_MAX_SP) { - profile->spurls[profile->spnum] = switch_core_strdup(osp_globals.pool, value); - profile->spnum++; + /* OSP service point URL */ + if (profile->spnumber < OSP_MAX_SPNUMBER) { + profile->spurl[profile->spnumber] = switch_core_strdup(osp_global.pool, value); + OSP_DEBUG("service-point-url[%d]: '%s'", profile->spnumber, profile->spurl[profile->spnumber]); + profile->spnumber++; } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignored excess service point '%s'\n", value); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignored service point '%s'\n", value); } } else if (!strcasecmp(name, "device-ip")) { - profile->device = switch_core_strdup(osp_globals.pool, value); + /* OSP client end IP */ + profile->deviceip = switch_core_strdup(osp_global.pool, value); + OSP_DEBUG("device-ip: '%s'", profile->deviceip); } else if (!strcasecmp(name, "ssl-lifetime")) { + /* SSL lifetime */ if (sscanf(value, "%d", &number) == 1) { profile->lifetime = number; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "ssl-lifetime must be a number\n"); } + OSP_DEBUG("ssl-lifetime: '%d'", profile->lifetime); } else if (!strcasecmp(name, "http-max-connections")) { + /* HTTP max connections */ if ((sscanf(value, "%d", &number) == 1) && (number >= OSP_MIN_MAXCONN) && (number <= OSP_MAX_MAXCONN)) { profile->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); + 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); } + OSP_DEBUG("http-max-connections: '%d'", profile->maxconnect); } else if (!strcasecmp(name, "http-persistence")) { + /* HTTP persistence */ if (sscanf(value, "%d", &number) == 1) { profile->persistence = number; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "http-persistence must be a number\n"); } + OSP_DEBUG("http-persistence: '%d'", profile->persistence); } else if (!strcasecmp(name, "http-retry-delay")) { + /* HTTP retry delay */ if ((sscanf(value, "%d", &number) == 1) && (number >= OSP_MIN_RETRYDELAY) && (number <= OSP_MAX_RETRYDELAY)) { profile->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); + 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); } + OSP_DEBUG("http-retry-delay: '%d'", profile->retrydelay); } else if (!strcasecmp(name, "http-retry-limit")) { + /* HTTP retry limit */ if ((sscanf(value, "%d", &number) == 1) && (number >= OSP_MIN_RETRYLIMIT) && (number <= OSP_MAX_RETRYLIMIT)) { profile->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); + 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); } + OSP_DEBUG("http-retry-limit: '%d'", profile->retrylimit); } else if (!strcasecmp(name, "http-timeout")) { + /* HTTP timeout value */ if ((sscanf(value, "%d", &number) == 1) && (number >= OSP_MIN_TIMEOUT) && (number <= OSP_MAX_TIMEOUT)) { profile->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); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "http-timeout must be between %d and %d\n", OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT); } + OSP_DEBUG("http-timeout: '%d'", profile->timeout); } else if (!strcasecmp(name, "work-mode")) { + /* OSP work mode */ if (!strcasecmp(value, "direct")) { profile->workmode = OSP_MODE_DIRECT; } else if (!strcasecmp(value, "indirect")) { @@ -568,7 +622,9 @@ static switch_status_t osp_load_settings( } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown work mode '%s'\n", value); } + OSP_DEBUG("work-mode: '%d'", profile->workmode); } else if (!strcasecmp(name, "service-type")) { + /* OSP service type */ if (!strcasecmp(value, "voice")) { profile->srvtype = OSP_SRV_VOICE; } else if (!strcasecmp(value, "npquery")) { @@ -576,19 +632,22 @@ static switch_status_t osp_load_settings( } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown service type '%s'\n", value); } + OSP_DEBUG("service-type: '%d'", profile->srvtype); } else if (!strcasecmp(name, "max-destinations")) { + /* Max destinations */ if ((sscanf(value, "%d", &number) == 1) && (number >= OSP_MIN_MAXDEST) && (number <= OSP_MAX_MAXDEST)) { profile->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); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "max-destinations must be between %d and %d\n", OSP_MIN_MAXDEST, OSP_MAX_MAXDEST); } + OSP_DEBUG("max-destinations: '%d'", profile->maxdest); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown parameter '%s'\n", name); } } - if (!profile->spnum) { + /* Check number of service porints */ + if (!profile->spnumber) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Without service point URI in profile '%s'\n", profile->name); /* "profile" cannot free to pool in FreeSWITCH */ continue; @@ -601,14 +660,11 @@ static switch_status_t osp_load_settings( switch_xml_free(xml); + OSP_DEBUG_END; + 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 @@ -625,16 +681,21 @@ static void osp_init_osptk(void) unsigned char cacertdata[OSP_SIZE_KEYSTR]; int error; - if (osp_globals.hardware) { + OSP_DEBUG_START; + + /* Init OSP Toolkit */ + if (osp_global.hardware) { if ((error = OSPPInit(OSPC_TRUE)) != OSPC_ERR_NO_ERROR) { + /* Unable to enable crypto hardware, disable it */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to enable crypto hardware, error '%d'\n", error); - osp_globals.hardware = SWITCH_FALSE; + osp_global.hardware = SWITCH_FALSE; OSPPInit(OSPC_FALSE); } } else { OSPPInit(OSPC_FALSE); } + /* Init OSP profile, using default certificates */ for (profile = osp_profiles; profile; profile = profile->next) { privatekey.PrivateKeyData = privatekeydata; privatekey.PrivateKeyLength = sizeof(privatekeydata); @@ -655,9 +716,10 @@ static void osp_init_osptk(void) } if (error == OSPC_ERR_NO_ERROR) { + /* Create provider handle */ error = OSPPProviderNew( - profile->spnum, /* Number of service points */ - profile->spurls, /* Service point URLs */ + profile->spnumber, /* Number of service points */ + profile->spurl, /* Service point URLs */ NULL, /* Weights */ OSP_AUDIT_URL, /* Audit URL */ &privatekey, /* Provate key */ @@ -677,21 +739,52 @@ static void osp_init_osptk(void) if (error != OSPC_ERR_NO_ERROR) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to create provider for profile %s, error '%d'\n", profile->name, error); profile->provider = OSP_INVALID_HANDLE; + } else { + OSP_DEBUG("Created provider handle for profile '%s'", profile->name); } } } + + OSP_DEBUG_END; +} + +/* + * Cleanup OSP client end + * return + */ +static void osp_cleanup_osptk(void) +{ + osp_profile_t *profile; + + OSP_DEBUG_START; + + for (profile = osp_profiles; profile; profile = profile->next) { + if (profile->provider != OSP_INVALID_HANDLE) { + /* Delete provider handle */ + OSPPProviderDelete(profile->provider, 0); + profile->provider = OSP_INVALID_HANDLE; + OSP_DEBUG("Deleted provider handle for profile '%s'", profile->name); + } + } + + /* Cleanup OSP Toolkit */ + OSPPCleanup(); + + OSP_DEBUG_END; } /* * Get protocol name - * param protocol Supported protocol + * param protocol Protocol * return protocol name */ -static const char *osp_get_protocol( +static const char *osp_get_protocolname( OSPE_PROTOCOL_NAME protocol) { const char *name; + OSP_DEBUG_START; + switch (protocol) { case OSPC_PROTNAME_UNKNOWN: name = OSP_PROTOCOL_UNKNO; @@ -721,15 +814,1593 @@ static const char *osp_get_protocol( name = OSP_PROTOCOL_UNSUP; break; } + OSP_DEBUG("Protocol %d: '%s'", protocol, name); + + OSP_DEBUG_END; 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) + * Get protocol from module name + * param module Endpoint module name + * return protocol Endpoint protocol name */ -SWITCH_STANDARD_API(osp_api_function) +static OSPE_PROTOCOL_NAME osp_get_protocol( + const char *module) +{ + OSPE_PROTOCOL_NAME protocol; + + OSP_DEBUG_START; + + if (!strcasecmp(module, OSP_MODULE_SIP)) { + protocol = OSPC_PROTNAME_SIP; + } else if (!strcasecmp(module, OSP_MODULE_H323)) { + protocol = OSPC_PROTNAME_Q931; + } else if (!strcasecmp(module, OSP_MODULE_IAX)) { + protocol = OSPC_PROTNAME_IAX; + } else if (!strcasecmp(module, OSP_MODULE_SKYPE)) { + protocol = OSPC_PROTNAME_SKYPE; + } else { + protocol = OSPC_PROTNAME_UNKNOWN; + } + OSP_DEBUG("Module %s: '%d'", module, protocol); + + OSP_DEBUG_END; + + return protocol; +} + +/* + * Parse userinfo for user and LNP + * param userinfo SIP URI userinfo + * param user User part + * param usersize Size of user buffer + * param rn Routing number + * param rnsize Size of rn buffer + * param cic Carrier Identification Cod + * param cicsize Size of cic buffer + * param npdi NP Database Dip Indicator + * return + */ +static void osp_parse_userinfo( + const char *userinfo, + char *user, + switch_size_t usersize, + char *rn, + switch_size_t rnsize, + char *cic, + switch_size_t cicsize, + int *npdi) +{ + char buffer[OSP_SIZE_NORSTR]; + char *item; + char *tmp; + + OSP_DEBUG_START; + + /* Set default values */ + if (user && usersize) { + user[0] = '\0'; + } + if (rn && rnsize) { + rn[0] = '\0'; + } + if (cic && cicsize) { + cic[0] = '\0'; + } + if (npdi) { + *npdi = 0; + } + + /* Parse userinfo */ + if (!switch_strlen_zero(userinfo)) { + /* Copy userinfo to temporary buffer */ + switch_copy_string(buffer, userinfo, sizeof(buffer)); + + /* Parse user */ + item = strtok_r(buffer, OSP_USER_DELIM, &tmp); + if (user && usersize) { + switch_copy_string(user, item, usersize); + } + + /* Parse LNP parameters */ + for (item = strtok_r(NULL, OSP_USER_DELIM, &tmp); item; item = strtok_r(NULL, OSP_USER_DELIM, &tmp)) { + if (!strncasecmp(item, "rn=", 3)) { + /* Parsed routing number */ + if (rn && rnsize) { + switch_copy_string(rn, item + 3, rnsize); + } + } else if (!strncasecmp(item, "cic=", 4)) { + /* Parsed cic */ + if (cic && cicsize) { + switch_copy_string(cic, item + 4, cicsize); + } + } else if (!strcasecmp(item, "npdi")) { + /* Parsed npdi */ + if (npdi) { + *npdi = 1; + } + } + } + } + + OSP_DEBUG("user: '%s'", OSP_FILTER_NULLSTR(user)); + OSP_DEBUG("rn: '%s'", OSP_FILTER_NULLSTR(rn)); + OSP_DEBUG("cic: '%s'", OSP_FILTER_NULLSTR(cic)); + OSP_DEBUG("npdi: '%d'", OSP_FILTER_NULLINT(npdi)); + + OSP_DEBUG_END; +} + +/* + * Parse SIP header user + * param header SIP header + * param user SIP header user + * param usersize Size of user buffer + * return + */ +static void osp_parse_header_user( + const char *header, + char *user, + switch_size_t usersize) +{ + char buffer[OSP_SIZE_NORSTR]; + char *head; + char *tmp; + char *item; + + OSP_DEBUG_START; + + if (user && usersize) { + user[0] = '\0'; + + /* Parse user */ + if (!switch_strlen_zero(header) && user && usersize) { + /* Copy header to temporary buffer */ + switch_copy_string(buffer, header, sizeof(buffer)); + + if ((head = strstr(buffer, "sip:"))) { + head += 4; + if ((tmp = strchr(head, OSP_URI_DELIM))) { + *tmp = '\0'; + item = strtok_r(head, OSP_USER_DELIM, &tmp); + switch_copy_string(user, item, usersize); + } + } + } + + OSP_DEBUG("user: '%s'", user); + } + + OSP_DEBUG_END; +} + +/* + * Parse SIP header host + * param header SIP header + * param host SIP header host + * param hostsize Size of host buffer + * return + */ +static void osp_parse_header_host( + const char *header, + char *host, + switch_size_t hostsize) +{ + char buffer[OSP_SIZE_NORSTR]; + char *head; + char *tmp; + + OSP_DEBUG_START; + + if (hostsize) { + host[0] = '\0'; + + /* Parse host*/ + if (!switch_strlen_zero(header) && host && hostsize) { + /* Copy header to temporary buffer */ + switch_copy_string(buffer, header, sizeof(buffer)); + + if ((head = strstr(buffer, "sip:"))) { + head += 4; + if ((tmp = strchr(head, OSP_URI_DELIM))) { + head = tmp + 1; + } + tmp = strtok(head, OSP_HOST_DELIM); + switch_copy_string(host, tmp, hostsize); + } + } + + OSP_DEBUG("host: '%s'", host); + } + + OSP_DEBUG_END; +} + +/* + * 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; + + OSP_DEBUG_START; + + if (dest && destsize) { + dest[0] = '\0'; + + if (!switch_strlen_zero(src)) { + /* Copy IP address to temporary buffer */ + 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); + } + } + + OSP_DEBUG("out: '%s'", dest); + } + + OSP_DEBUG_END; +} + +/* + * 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; + + OSP_DEBUG_START; + + if (dest && destsize) { + dest[0] = '\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); + } + } + OSP_DEBUG("in: '%s'", dest); + } + + OSP_DEBUG_END; +} + +/* + * Always log AuthReq parameters + * param profile OSP profile + * param inbound Inbound info + * return + */ +static void osp_log_authreq( + osp_profile_t *profile, + osp_inbound_t *inbound) +{ + char *srvtype; + const char *source; + const char *srcdev; + char term[OSP_SIZE_NORSTR]; + int total; + + OSP_DEBUG_START; + + /* Get source device and source */ + if (profile->workmode == OSP_MODE_INDIRECT) { + source = inbound->srcdev; + if (switch_strlen_zero(inbound->actsrc)) { + srcdev = inbound->srcdev; + } else { + srcdev = inbound->actsrc; + } + } else { + source = profile->deviceip; + srcdev = inbound->srcdev; + } + + /* Get preferred destination for NP query */ + if (profile->srvtype == OSP_SRV_NPQUERY) { + srvtype = "npquery"; + if (switch_strlen_zero(inbound->tohost)) { + switch_copy_string(term, source, 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 = profile->maxdest; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, osp_global.loglevel, + "AuthReq: " + "srvtype '%s' " + "source '%s' " + "srcdev '%s' " + "srcnid '%s' " + "protocol '%s' " + "callid '%s' " + "calling '%s' " + "called '%s' " + "lnp '%s/%s/%d' " + "preferred '%s' " + "rpid '%s' " + "pai '%s' " + "div '%s/%s' " + "pci '%s' " + "cinfo '%s/%s/%s/%s/%s/%s/%s/%s' " + "maxcount '%d'\n", + srvtype, + source, + srcdev, + OSP_FILTER_NULLSTR(inbound->srcnid), + osp_get_protocolname(inbound->protocol), + OSP_FILTER_NULLSTR(inbound->callid), + inbound->calling, + inbound->called, + inbound->nprn, inbound->npcic, inbound->npdi, + term, + inbound->rpiduser, + inbound->paiuser, + inbound->divuser, inbound->divhost, + inbound->pciuser, + OSP_FILTER_NULLSTR(inbound->cinfo[0]), OSP_FILTER_NULLSTR(inbound->cinfo[1]), OSP_FILTER_NULLSTR(inbound->cinfo[2]), OSP_FILTER_NULLSTR(inbound->cinfo[3]), + OSP_FILTER_NULLSTR(inbound->cinfo[4]), OSP_FILTER_NULLSTR(inbound->cinfo[5]), OSP_FILTER_NULLSTR(inbound->cinfo[6]), OSP_FILTER_NULLSTR(inbound->cinfo[7]), + total); + + OSP_DEBUG_END; +} + +/* + * Always log AuthRsp parameters + * param results Routing info + * return + */ +static void osp_log_authrsp( + osp_results_t *results) +{ + OSP_DEBUG_START; + + switch_log_printf(SWITCH_CHANNEL_LOG, osp_global.loglevel, + "AuthRsp: " + "destcount '%d/%d' " + "transid '%"PRIu64"' " + "timelimit '%u' " + "calling '%s' " + "called '%s' " + "destination '%s' " + "destnid '%s' " + "lnp '%s/%s/%d' " + "protocol '%s' " + "supported '%d'\n", + results->count, + results->total, + results->transid, + results->timelimit, + results->calling, + results->called, + results->dest, + results->destnid, + results->nprn, results->npcic, results->npdi, + osp_get_protocolname(results->protocol), + results->supported); + + OSP_DEBUG_END; +} + +/* + * Alway log UsageInd parameters + * param results Route info + * param usage Usage info + * return + */ +static void osp_log_usageind( + osp_results_t *results, + osp_usage_t *usage) +{ + OSP_DEBUG_START; + + switch_log_printf(SWITCH_CHANNEL_LOG, osp_global.loglevel, + "UsageInd: " + "destcount '%d/%d' " + "transid '%"PRIu64"' " + "cause '%d' " + "release '%d' " + "times '%"PRId64"/%"PRId64"/%"PRId64"/%"PRId64"' " + "duration '%"PRId64"' " + "pdd '%"PRId64"' " + "codec '%s/%s' " + "rtpctets '%d/%d' " + "rtppackets '%d/%d'\n", + results->count, results->total, + results->transid, + results->cause ? results->cause : usage->cause, + usage->release, + usage->start / 1000000, usage->alert / 1000000, usage->connect / 1000000, usage->end / 1000000, + usage->duration / 1000000, + usage->pdd / 1000, + OSP_FILTER_NULLSTR(usage->srccodec), OSP_FILTER_NULLSTR(usage->destcodec), + usage->rtpsrcrepoctets, usage->rtpdestrepoctets, + usage->rtpsrcreppackets, usage->rtpdestreppackets); + + OSP_DEBUG_END; +} + +/* + * 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; + const char *tmp; + int i; + char name[OSP_SIZE_NORSTR]; + + OSP_DEBUG_START; + + /* Cleanup buffer */ + memset(inbound, 0, sizeof(*inbound)); + + /* Get caller profile */ + caller = switch_channel_get_caller_profile(channel); + + /* osp_source_device */ + inbound->actsrc = switch_channel_get_variable(channel, OSP_VAR_SRCDEV); + OSP_DEBUG("actsrc: '%s'", OSP_FILTER_NULLSTR(inbound->actsrc)); + + /* Source device */ + inbound->srcdev = caller->network_addr; + OSP_DEBUG("srcdev: '%s'", OSP_FILTER_NULLSTR(inbound->srcdev)); + + /* osp_source_nid */ + inbound->srcnid = switch_channel_get_variable(channel, OSP_VAR_SRCNID); + OSP_DEBUG("srcnid: '%s'", OSP_FILTER_NULLSTR(inbound->srcnid)); + + /* Source signaling protocol */ + inbound->protocol = osp_get_protocol(caller->source); + OSP_DEBUG("protocol: '%d'", inbound->protocol); + + /* Call-ID */ + inbound->callid = switch_channel_get_variable(channel, OSP_FS_CALLID); + OSP_DEBUG("callid: '%s'", OSP_FILTER_NULLSTR(inbound->callid)); + + /* Calling number */ + if ((tmp = switch_channel_get_variable(channel, OSP_FS_FROMUSER))) { + osp_parse_userinfo(tmp, inbound->calling, sizeof(inbound->calling), NULL, 0, NULL, 0, NULL); + } else { + osp_parse_userinfo(caller->caller_id_number, inbound->calling, sizeof(inbound->calling), NULL, 0, NULL, 0, NULL); + } + OSP_DEBUG("calling: '%s'", inbound->calling); + + /* Called number and LNP parameters */ + osp_parse_userinfo(caller->destination_number, inbound->called, sizeof(inbound->called), inbound->nprn, sizeof(inbound->nprn), inbound->npcic, sizeof(inbound->npcic), + &inbound->npdi); + OSP_DEBUG("called: '%s'", inbound->called); + OSP_DEBUG("nprn: '%s'", inbound->nprn); + OSP_DEBUG("npcic: '%s'", inbound->npcic); + OSP_DEBUG("npdi: '%d'", inbound->npdi); + + /* To header */ + inbound->tohost = switch_channel_get_variable(channel, OSP_FS_TOHOST); + OSP_DEBUG("tohost: '%s'", OSP_FILTER_NULLSTR(inbound->tohost)); + inbound->toport = switch_channel_get_variable(channel, OSP_FS_TOPORT); + OSP_DEBUG("toport: '%s'", OSP_FILTER_NULLSTR(inbound->toport)); + + /* RPID calling number */ + if ((tmp = switch_channel_get_variable(channel, OSP_FS_RPID))) { + osp_parse_header_user(tmp, inbound->rpiduser, sizeof(inbound->rpiduser)); + } + OSP_DEBUG("RPID user: '%s'", inbound->rpiduser); + + /* PAI calling number */ + if ((tmp = switch_channel_get_variable(channel, OSP_FS_PAI))) { + osp_parse_userinfo(tmp, inbound->paiuser, sizeof(inbound->paiuser), NULL, 0, NULL, 0, NULL); + } + OSP_DEBUG("PAI user: '%s'", inbound->paiuser); + + /* DIV calling number */ + if ((tmp = switch_channel_get_variable(channel, OSP_FS_DIV))) { + osp_parse_header_user(tmp, inbound->divuser, sizeof(inbound->divuser)); + osp_parse_header_host(tmp, inbound->divhost, sizeof(inbound->divhost)); + } + OSP_DEBUG("DIV user: '%s'", inbound->divuser); + OSP_DEBUG("DIV host: '%s'", inbound->divhost); + + /* PCI calling number */ + if ((tmp = switch_channel_get_variable(channel, OSP_FS_PCI))) { + osp_parse_header_user(tmp, inbound->pciuser, sizeof(inbound->pciuser)); + } + OSP_DEBUG("PCI user: '%s'", inbound->pciuser); + + /* Custom info */ + 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); + OSP_DEBUG("cinfo[%d]: '%s'", i, OSP_FILTER_NULLSTR(inbound->cinfo[i])); + } + + OSP_DEBUG_END; +} + +/* + * Get outbound settings + * param channel Inbound channel + * param outbound Outbound settings + * return + */ +static void osp_get_outbound( + switch_channel_t *channel, + osp_outbound_t *outbound) +{ + const char *tmp; + + OSP_DEBUG_START; + + /* Cleanup buffer */ + memset(outbound, 0, sizeof(*outbound)); + + /* Get destination network ID namd & location info */ + outbound->dniduserparam = switch_channel_get_variable(channel, OSP_VAR_DNIDUSERPARAM); + OSP_DEBUG("dniduserparam: '%s'", OSP_FILTER_NULLSTR(outbound->dniduserparam)); + outbound->dniduriparam = switch_channel_get_variable(channel, OSP_VAR_DNIDURIPARAM); + OSP_DEBUG("dniduriparam: '%s'", OSP_FILTER_NULLSTR(outbound->dniduriparam)); + + /* Get "user=phone" insert flag */ + tmp = switch_channel_get_variable(channel, OSP_VAR_USERPHONE); + if (!switch_strlen_zero(tmp)) { + outbound->userphone = switch_true(tmp); + } + OSP_DEBUG("userphone: '%d'", outbound->userphone); + + /* Get outbound proxy info */ + outbound->outproxy = switch_channel_get_variable(channel, OSP_VAR_OUTPROXY); + OSP_DEBUG("outporxy: '%s'", OSP_FILTER_NULLSTR(outbound->outproxy)); + + OSP_DEBUG_END; +} + +/* + * Get transaction info + * param channel Inbound channel + * param aleg If A-leg + * param results Route info + * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed + */ +static switch_status_t osp_get_transaction( + switch_channel_t *channel, + switch_bool_t aleg, + osp_results_t *results) +{ + const char *tmp; + osp_profile_t *profile; + switch_status_t status = SWITCH_STATUS_FALSE; + + OSP_DEBUG_START; + + /* Get profile name */ + if (!(results->profile = switch_channel_get_variable(channel, OSP_VAR_PROFILE))) { + results->profile = OSP_DEF_PROFILE; + } + + /* Get transaction handle */ + if (osp_find_profile(results->profile, &profile) == SWITCH_STATUS_FALSE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find profile '%s'\n", results->profile); + } else if (profile->provider == OSP_INVALID_HANDLE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Disabled profile '%s'\n", results->profile); + } else if (!(tmp = switch_channel_get_variable(channel, OSP_VAR_TRANSACTION)) || (sscanf(tmp, "%d", &results->transaction) != 1)){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get transaction handle'\n"); + } else if (results->transaction == OSP_INVALID_HANDLE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid transaction handle'\n"); + } else { + if (!(tmp = switch_channel_get_variable(channel, OSP_VAR_TRANSID)) || (sscanf(tmp, "%"PRIu64"", &results->transid) != 1)) { + results->transid = 0; + } + + /* Get destination total */ + if (!(tmp = switch_channel_get_variable(channel, OSP_VAR_ROUTETOTAL)) || (sscanf(tmp, "%u", &results->total) != 1)) { + results->total = 0; + } + + /* Get destination count */ + if (!(tmp = switch_channel_get_variable(channel, OSP_VAR_ROUTECOUNT)) || (sscanf(tmp, "%u", &results->count) != 1)) { + results->count = 0; + } + + /* + * Get termiantion cause + * The logic is + * 1. osp_next_function should get TCCode from last_bridge_hangup_cause + * 2. osp_on_reporting should get TCCode from osp_terimation_cause + */ + if (aleg) { + /* A-leg */ + if (!(tmp = switch_channel_get_variable(channel, OSP_VAR_TCCODE)) || (sscanf(tmp, "%u", &results->cause) != 1)) { + results->cause = 0; + } + } else { + /* B-leg */ + if ((tmp = switch_channel_get_variable(channel, OSP_FS_HANGUPCAUSE))) { + results->cause = switch_channel_str2cause(tmp); + } + } + + status = SWITCH_STATUS_SUCCESS; + } + OSP_DEBUG("profile: '%s'", results->profile); + OSP_DEBUG("transaction: '%d'", results->transaction); + OSP_DEBUG("transid: '%"PRIu64"'", results->transid); + OSP_DEBUG("total: '%d'", results->total); + OSP_DEBUG("count: '%d'", results->count); + OSP_DEBUG("cause: '%d'", results->cause); + + OSP_DEBUG_END; + + return status; +} + +/* + * Retrieve usage info + * param channel channel + * param originator Originator profile + * param terminator Terminator profile, not used at this time + * param results Route info + * param usage Usage info + * return + */ +static void osp_get_usage( + switch_channel_t *channel, + switch_caller_profile_t *originator, + switch_caller_profile_t *terminator_unused, + osp_results_t *results, + osp_usage_t *usage) +{ + const char *tmp; + switch_channel_timetable_t *times; + + OSP_DEBUG_START; + + /* Cleanup buffer */ + memset(usage, 0, sizeof(*usage)); + + /* Release source */ + usage->release = OSPC_RELEASE_UNKNOWN; + if (osp_get_protocol(originator->source) == OSPC_PROTNAME_SIP) { + tmp = switch_channel_get_variable(channel, OSP_FS_SIPRELEASE); + if (!tmp) { + usage->release = OSPC_RELEASE_UNDEFINED; + } else if (!strcasecmp(tmp, "send_bye")) { + usage->release = OSPC_RELEASE_DESTINATION; + } else if (!strcasecmp(tmp, "recv_bye")) { + usage->release = OSPC_RELEASE_SOURCE; + } else if (!strcasecmp(tmp, "send_refuse")) { + usage->release = OSPC_RELEASE_INTERNAL; + } else if (!strcasecmp(tmp, "send_cancel")) { + usage->release = OSPC_RELEASE_SOURCE; + } + } + OSP_DEBUG("release: '%d'", usage->release); + + /* Termiation cause */ + usage->cause = switch_channel_get_cause_q850(channel); + OSP_DEBUG("cause: '%d'", usage->cause); + + /* Timestamps */ + times = switch_channel_get_timetable(channel); + usage->start = times->created; + OSP_DEBUG("start: '%"PRIu64"'", usage->start); + usage->alert = times->progress; + OSP_DEBUG("alert: '%"PRIu64"'", usage->alert); + usage->connect = times->answered; + OSP_DEBUG("connect: '%"PRIu64"'", usage->connect); + usage->end = times->hungup; + OSP_DEBUG("end: '%"PRIu64"'", usage->end); + if (times->answered) { + usage->duration = times->hungup - times->answered; + OSP_DEBUG("duration: '%"PRIu64"'", usage->duration); + } + if (times->progress) { + usage->pdd = times->progress - usage->start; + OSP_DEBUG("pdd: '%"PRIu64"'", usage->pdd); + } + + /* Codecs */ + usage->srccodec = switch_channel_get_variable(channel, OSP_FS_SRCCODEC); + OSP_DEBUG("srccodec: '%s'", OSP_FILTER_NULLSTR(usage->srccodec)); + usage->destcodec = switch_channel_get_variable(channel, OSP_FS_DESTCODEC); + OSP_DEBUG("destcodec: '%s'", OSP_FILTER_NULLSTR(usage->destcodec)); + + /* QoS statistics */ + if (!(tmp = switch_channel_get_variable(channel, OSP_FS_RTPSRCREPOCTS)) || (sscanf(tmp, "%d", &usage->rtpsrcrepoctets) != 1)) { + usage->rtpsrcrepoctets = OSP_DEF_STATS; + } + OSP_DEBUG("rtpsrcrepoctets: '%d'", usage->rtpsrcrepoctets); + if (!(tmp = switch_channel_get_variable(channel, OSP_FS_RTPDESTREPOCTS)) || (sscanf(tmp, "%d", &usage->rtpdestrepoctets) != 1)) { + usage->rtpdestrepoctets = OSP_DEF_STATS; + } + OSP_DEBUG("rtpdestrepoctets: '%d'", usage->rtpdestrepoctets); + if (!(tmp = switch_channel_get_variable(channel, OSP_FS_RTPSRCREPPKTS)) || (sscanf(tmp, "%d", &usage->rtpsrcreppackets) != 1)) { + usage->rtpsrcreppackets = OSP_DEF_STATS; + } + OSP_DEBUG("rtpsrcreppackets: '%d'", usage->rtpsrcreppackets); + if (!(tmp = switch_channel_get_variable(channel, OSP_FS_RTPDESTREPPKTS)) || (sscanf(tmp, "%d", &usage->rtpdestreppackets) != 1)) { + usage->rtpdestreppackets = OSP_DEF_STATS; + } + OSP_DEBUG("rtpdestreppackets: '%d'", usage->rtpdestreppackets); + + OSP_DEBUG_END; +} + +/* + * Check destination + * param results Routing info + * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed + */ +static switch_status_t osp_check_destination( + osp_results_t *results) +{ + OSPE_DEST_OSPENABLED enabled; + OSPE_PROTOCOL_NAME protocol; + OSPE_OPERATOR_NAME type; + int error; + switch_status_t status = SWITCH_STATUS_FALSE; + + OSP_DEBUG_START; + + if ((error = OSPPTransactionIsDestOSPEnabled(results->transaction, &enabled)) != OSPC_ERR_NO_ERROR) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get destination OSP version, error '%d'\n", error); + } else if ((error = OSPPTransactionGetDestProtocol(results->transaction, &protocol)) != OSPC_ERR_NO_ERROR) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get signaling protocol, error '%d'\n", error); + } else { + switch(protocol) { + case OSPC_PROTNAME_UNDEFINED: + case OSPC_PROTNAME_UNKNOWN: + protocol = osp_global.protocol; + case OSPC_PROTNAME_SIP: + case OSPC_PROTNAME_Q931: + case OSPC_PROTNAME_IAX: + case OSPC_PROTNAME_SKYPE: + results->protocol = protocol; + if (!switch_strlen_zero(osp_global.endpoint[protocol].module) && !switch_strlen_zero(osp_global.endpoint[protocol].profile)) { + results->supported = SWITCH_TRUE; + results->cause = 0; + status = SWITCH_STATUS_SUCCESS; + break; + } + case OSPC_PROTNAME_LRQ: + case OSPC_PROTNAME_T37: + case OSPC_PROTNAME_T38: + case OSPC_PROTNAME_SMPP: + case OSPC_PROTNAME_XMPP: + default: + results->protocol = protocol; + results->supported = SWITCH_FALSE; + /* Q.850 protocol error, unspecified */ + results->cause = 111; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported protocol '%d'\n", protocol); + break; + } + OSP_DEBUG("protocol: '%d'", results->protocol); + OSP_DEBUG("supported: '%d'", results->supported); + OSP_DEBUG("cause: '%d'", results->cause); + + if ((error = OSPPTransactionGetDestinationNetworkId(results->transaction, sizeof(results->destnid), results->destnid)) != OSPC_ERR_NO_ERROR) { + results->destnid[0] = '\0'; + } + OSP_DEBUG("destnid: '%s'", results->destnid); + + error = OSPPTransactionGetNumberPortabilityParameters( + results->transaction, + sizeof(results->nprn), + results->nprn, + sizeof(results->npcic), + results->npcic, + &results->npdi); + if (error != OSPC_ERR_NO_ERROR) { + results->nprn[0] = '\0'; + results->npcic[0] = '\0'; + results->npdi = 0; + } + OSP_DEBUG("nprn: '%s'", results->nprn); + OSP_DEBUG("npcic: '%s'", results->npcic); + OSP_DEBUG("npdi: '%d'", results->npdi); + + for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) { + if ((error = OSPPTransactionGetOperatorName(results->transaction, type, sizeof(results->opname[type]), results->opname[type])) != OSPC_ERR_NO_ERROR) { + results->opname[type][0] = '\0'; + } + OSP_DEBUG("opname[%d]: '%s'", type, results->opname[type]); + } + + osp_log_authrsp(results); + } + + OSP_DEBUG_END; + + return status; +} + +/* + * Build parameter string for each channel + * param results Route info + * param buffer Buffer + * param bufsize Buffer size + * return + */ +static void osp_build_eachparam( + osp_results_t *results, + char *buffer, + switch_size_t bufsize) +{ + OSP_DEBUG_START; + + if (results && buffer && bufsize) { + switch_snprintf(buffer, bufsize, "[%s=%s]", OSP_FS_OUTCALLING, results->calling); + OSP_DEBUG("eachparam: '%s'", buffer); + } + + OSP_DEBUG_END; +} + +/* + * Build endpoint string + * param results Route info + * param outbound Outbound settings + * param buffer Buffer + * param bufsize Buffer size + * return + */ +static void osp_build_endpoint( + osp_results_t *results, + osp_outbound_t *outbound, + char *buffer, + switch_size_t bufsize) +{ + char *head = buffer; + switch_size_t len, size = bufsize; + + OSP_DEBUG_START; + + if (results && buffer && bufsize) { + switch (results->protocol) { + case OSPC_PROTNAME_SIP: + /* module/profile/called */ + switch_snprintf(head, size, "%s/%s/%s", osp_global.endpoint[OSPC_PROTNAME_SIP].module, osp_global.endpoint[OSPC_PROTNAME_SIP].profile, results->called); + OSP_ADJUST_LEN(head, size, len); + + /* RN */ + if (!switch_strlen_zero_buf(results->nprn)) { + switch_snprintf(head, size, ";rn=%s", results->nprn); + OSP_ADJUST_LEN(head, size, len); + } + + /* CIC */ + if (!switch_strlen_zero_buf(results->npcic)) { + switch_snprintf(head, size, ";cic=%s", results->npcic); + OSP_ADJUST_LEN(head, size, len); + } + + /* NPDI */ + if (results->npdi) { + switch_snprintf(head, size, ";npdi"); + OSP_ADJUST_LEN(head, size, len); + } + + /* User parameter destination network ID */ + if (!switch_strlen_zero(outbound->dniduserparam) && !switch_strlen_zero_buf(results->destnid)) { + switch_snprintf(head, size, ";%s=%s", outbound->dniduserparam, results->destnid); + OSP_ADJUST_LEN(head, size, len); + } + + /* Destination */ + switch_snprintf(head, size, "@%s", results->dest); + OSP_ADJUST_LEN(head, size, len); + + /* URI parameter destination network ID */ + if (!switch_strlen_zero(outbound->dniduriparam) && !switch_strlen_zero_buf(results->destnid)) { + switch_snprintf(head, size, ";%s=%s", outbound->dniduriparam, results->destnid); + OSP_ADJUST_LEN(head, size, len); + } + + /* user=phone */ + if (outbound->userphone) { + switch_snprintf(head, size, ";user=phone"); + OSP_ADJUST_LEN(head, size, len); + } + + /* Outbound proxy */ + if (!switch_strlen_zero(outbound->outproxy)) { + switch_snprintf(head, size, ";fs_path=sip:%s", outbound->outproxy); + OSP_ADJUST_LEN(head, size, len); + } + break; + case OSPC_PROTNAME_Q931: + /* module/profile/called@destination */ + switch_snprintf(head, size, "%s/%s/%s@%s", osp_global.endpoint[OSPC_PROTNAME_Q931].module, osp_global.endpoint[OSPC_PROTNAME_Q931].profile, + results->called, results->dest); + OSP_ADJUST_LEN(head, size, len); + break; + case OSPC_PROTNAME_IAX: + /* module/profile/destination/called */ + switch_snprintf(head, size, "%s/%s/%s/%s", osp_global.endpoint[OSPC_PROTNAME_Q931].module, osp_global.endpoint[OSPC_PROTNAME_Q931].profile, + results->dest, results->called); + OSP_ADJUST_LEN(head, size, len); + break; + case OSPC_PROTNAME_SKYPE: + /* module/profile/called */ + switch_snprintf(head, size, "%s/%s/%s", osp_global.endpoint[OSPC_PROTNAME_Q931].module, osp_global.endpoint[OSPC_PROTNAME_Q931].profile, results->called); + OSP_ADJUST_LEN(head, size, len); + break; + default: + buffer[0] = '\0'; + break; + } + OSP_DEBUG("endpoint: '%s'", buffer); + } + + OSP_DEBUG_END; +} + +/* + * Create route string + * param outbound Outbound info + * param results Routing info + * param buffer Buffer + * param bufsize Buffer size + * return + */ +static void osp_create_route( + osp_outbound_t *outbound, + osp_results_t *results, + char *buffer, + switch_size_t bufsize) +{ + char eachparam[OSP_SIZE_NORSTR]; + char endpoint[OSP_SIZE_NORSTR]; + + OSP_DEBUG_START; + + /* Build dial string for each channel part */ + osp_build_eachparam(results, eachparam, sizeof(eachparam)); + + /* Build dial string for endpoint part */ + osp_build_endpoint(results, outbound, endpoint, sizeof(endpoint)); + + /* Build dail string */ + switch_snprintf(buffer, bufsize, "%s%s", eachparam, endpoint); + OSP_DEBUG("route: '%s'", buffer); + + OSP_DEBUG_END; +} + +/* + * Do AuthReq + * param profile OSP profile + * param inbound Call originator info + * param results Routing info + * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed + */ +static switch_status_t osp_request_auth( + osp_profile_t *profile, + osp_inbound_t *inbound, + osp_results_t *results) +{ + const char *source; + const char *srcdev; + 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 }; + OSPTTRANS *context; + int i, error; + switch_status_t status = SWITCH_STATUS_FALSE; + + OSP_DEBUG_START; + + /* Set source network ID */ + OSPPTransactionSetNetworkIds(results->transaction, inbound->srcnid, NULL); + + /* Set source signaling protocol */ + OSPPTransactionSetProtocol(results->transaction, OSPC_PROTTYPE_SOURCE, inbound->protocol); + + /* Set source LNP parameters */ + OSPPTransactionSetNumberPortability(results->transaction, inbound->nprn, inbound->npcic, inbound->npdi); + + /* Set RPID */ + OSPPTransactionSetRemotePartyId(results->transaction, OSPC_NFORMAT_E164, inbound->rpiduser); + + /* Set PAI */ + OSPPTransactionSetAssertedId(results->transaction, OSPC_NFORMAT_E164, inbound->paiuser); + + /* Set diversion */ + osp_convert_inout(inbound->divhost, tmp, sizeof(tmp)); + OSPPTransactionSetDiversion(results->transaction, inbound->divuser, tmp); + + /* Set PCI */ + OSPPTransactionSetChargeInfo(results->transaction, OSPC_NFORMAT_E164, inbound->pciuser); + + /* Set custom info */ + for (i = 0; i < OSP_MAX_CINFO; i++) { + if (!switch_strlen_zero(inbound->cinfo[i])) { + OSPPTransactionSetCustomInfo(results->transaction, i, inbound->cinfo[i]); + } + } + + /* Device info and source */ + if (profile->workmode == OSP_MODE_INDIRECT) { + source = inbound->srcdev; + if (switch_strlen_zero(inbound->actsrc)) { + srcdev = inbound->srcdev; + } else { + srcdev = inbound->actsrc; + } + } else { + source = profile->deviceip; + srcdev = inbound->srcdev; + } + osp_convert_inout(source, src, sizeof(src)); + osp_convert_inout(srcdev, dev, sizeof(dev)); + + /* Preferred and max destinations */ + if (profile->srvtype == OSP_SRV_NPQUERY) { + OSPPTransactionSetServiceType(results->transaction, 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; + + results->total = 1; + } else { + OSPPTransactionSetServiceType(results->transaction, OSPC_SERVICE_VOICE); + + results->total = profile->maxdest; + } + + OSP_DEBUG_MSG("RequestAuthorisation"); + + /* Request authorization */ + error = OSPPTransactionRequestAuthorisation( + results->transaction, /* 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 */ + &results->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 for '%s/%s', error '%d'\n", inbound->calling, inbound->called, error); + results->total = 0; + } else if (results->total == 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Without destination\n"); + } else { + context = OSPPTransactionGetContext(results->transaction, &error); + if (error == OSPC_ERR_NO_ERROR) { + results->transid = context->TransactionID; + } else { + results->transid = 0; + } + status = SWITCH_STATUS_SUCCESS; + } + OSP_DEBUG("transid: '%"PRIu64"'", results->transid); + OSP_DEBUG("total: '%d'", results->total); + + OSP_DEBUG_END; + + return status; +} + +/* + * Get first destination + * param results Routing info + * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed + */ +static switch_status_t osp_get_first( + osp_results_t *results) +{ + int error; + char term[OSP_SIZE_NORSTR]; + unsigned int callidlen = 0, tokenlen = 0; + switch_status_t status = SWITCH_STATUS_FALSE; + + OSP_DEBUG_START; + + /* Set destination count */ + results->count = 1; + + OSP_DEBUG_MSG("GetFirstDestination"); + + /* Get first destination */ + error = OSPPTransactionGetFirstDestination( + results->transaction, /* Transaction handle */ + 0, /* Timestamp buffer size */ + NULL, /* Valid after */ + NULL, /* Valid until */ + &results->timelimit, /* Call duration limit */ + &callidlen, /* Callid buffer size */ + NULL, /* Callid buffer */ + sizeof(results->called), /* Called buffer size */ + results->called, /* Called buffer */ + sizeof(results->calling), /* Calling buffer size */ + results->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); + } else { + osp_convert_outin(term, results->dest, sizeof(results->dest)); + + /* Check destination */ + status = osp_check_destination(results); + } + OSP_DEBUG("status: '%d'", status); + + OSP_DEBUG_END; + + return status; +} + +/* + * Get next destination + * param results Routing info + * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed + */ +static switch_status_t osp_get_next( + osp_results_t *results) +{ + int error; + char term[OSP_SIZE_NORSTR]; + unsigned int callidlen = 0, tokenlen = 0; + switch_status_t status = SWITCH_STATUS_FALSE; + + OSP_DEBUG_START; + + while ((status == SWITCH_STATUS_FALSE) && (results->count < results->total)) { + /* Set destination count */ + results->count++; + + OSP_DEBUG_MSG("GetNextDestination"); + + /* Get next destination */ + error = OSPPTransactionGetNextDestination( + results->transaction, /* Transsaction handle */ + results->cause, /* Failure reason */ + 0, /* Timestamp buffer size */ + NULL, /* Valid after */ + NULL, /* Valid until */ + &results->timelimit, /* Call duration limit */ + &callidlen, /* Callid buffer size */ + NULL, /* Callid buffer */ + sizeof(results->called), /* Called buffer size */ + results->called, /* Called buffer */ + sizeof(results->calling), /* Calling buffer size */ + results->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 destination, error '%d'\n", error); + break; + } else { + osp_convert_outin(term, results->dest, sizeof(results->dest)); + + /* Check destination */ + status = osp_check_destination(results); + } + } + OSP_DEBUG("status: '%d'", status); + + OSP_DEBUG_END; + + return status; +} + +/* + * Report usage + * param results Route info + * param usage Usage info + * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed + */ +static switch_status_t osp_report_usage( + osp_results_t *results, + osp_usage_t *usage) +{ + int error; + unsigned int dummy = 0; + switch_status_t status = SWITCH_STATUS_FALSE; + + OSP_DEBUG_START; + + /* Set role info */ + OSPPTransactionSetRoleInfo(results->transaction, OSPC_RSTATE_STOP, OSPC_RFORMAT_OSP, OSPC_RVENDOR_FREESWITCH); + + /* Set termination cause */ + if (results->cause) { + OSPPTransactionRecordFailure(results->transaction, results->cause); + } else { + OSPPTransactionRecordFailure(results->transaction, usage->cause); + } + + /* Set codecs */ + if (!switch_strlen_zero(usage->srccodec)) { + OSPPTransactionSetCodec(results->transaction, OSPC_CODEC_SOURCE, usage->srccodec); + } + if (!switch_strlen_zero(usage->destcodec)) { + OSPPTransactionSetCodec(results->transaction, OSPC_CODEC_DESTINATION, usage->destcodec); + } + + /* Set QoS statistics */ + if (usage->rtpsrcrepoctets != OSP_DEF_STATS) { + OSPPTransactionSetOctets(results->transaction, OSPC_SMETRIC_RTP, OSPC_SDIR_SRCREP, usage->rtpsrcrepoctets); + } + if (usage->rtpdestrepoctets != OSP_DEF_STATS) { + OSPPTransactionSetOctets(results->transaction, OSPC_SMETRIC_RTP, OSPC_SDIR_DESTREP, usage->rtpdestrepoctets); + } + if (usage->rtpsrcreppackets != OSP_DEF_STATS) { + OSPPTransactionSetPackets(results->transaction, OSPC_SMETRIC_RTP, OSPC_SDIR_SRCREP, usage->rtpsrcreppackets); + } + if (usage->rtpdestreppackets != OSP_DEF_STATS) { + OSPPTransactionSetPackets(results->transaction, OSPC_SMETRIC_RTP, OSPC_SDIR_DESTREP, usage->rtpdestreppackets); + } + + OSP_DEBUG_MSG("ReportUsage"); + + /* Report usage */ + error = OSPPTransactionReportUsage( + results->transaction, /* Transaction handle */ + usage->duration / 1000000, /* Duration */ + usage->start / 1000000, /* Start time */ + usage->end / 1000000, /* End time */ + usage->alert / 1000000, /* Alert time */ + usage->connect / 1000000, /* Connect time */ + usage->alert, /* If PDD exist (call ringed) */ + usage->pdd / 1000, /* Post dial delay, in ms */ + usage->release, /* Release source */ + NULL, /* Conference ID */ + OSP_DEF_STATS, /* Loss packet sent */ + OSP_DEF_STATS, /* Loss fraction sent */ + OSP_DEF_STATS, /* Loss packet received */ + OSP_DEF_STATS, /* Loss fraction received */ + &dummy, /* Detail log buffer size */ + NULL); /* Detail log buffer */ + if (error != OSPC_ERR_NO_ERROR) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to report usage, error '%d'\n", error); + } else { + status = SWITCH_STATUS_SUCCESS; + } + + /* Delete transaction handle */ + OSPPTransactionDelete(results->transaction); + + OSP_DEBUG_END; + + return status; +} + +/* + * Export OSP lookup status to channel + * param channel Originator channel + * param status OSP lookup status + * param outbound Outbound info + * param results Routing info + * return + */ +static void osp_export_lookup( + switch_channel_t *channel, + switch_status_t status, + osp_outbound_t *outbound, + osp_results_t *results) +{ + char value[OSP_SIZE_ROUSTR]; + + OSP_DEBUG_START; + + /* Profile name */ + switch_channel_set_variable_var_check(channel, OSP_VAR_PROFILE, results->profile, SWITCH_FALSE); + OSP_DEBUG("%s: '%s'", OSP_VAR_PROFILE, results->profile); + + /* Transaction handle */ + switch_snprintf(value, sizeof(value), "%d", results->transaction); + switch_channel_set_variable_var_check(channel, OSP_VAR_TRANSACTION, value, SWITCH_FALSE); + OSP_DEBUG("%s: '%s'", OSP_VAR_TRANSACTION, value); + + /* Transaction ID */ + switch_snprintf(value, sizeof(value), "%"PRIu64"", results->transid); + switch_channel_set_variable_var_check(channel, OSP_VAR_TRANSID, value, SWITCH_FALSE); + OSP_DEBUG("%s: '%s'", OSP_VAR_TRANSID, value); + + /* OSP lookup status */ + switch_snprintf(value, sizeof(value), "%d", status); + switch_channel_set_variable_var_check(channel, OSP_VAR_LOOKUPSTATUS, value, SWITCH_FALSE); + OSP_DEBUG("%s: '%s'", OSP_VAR_LOOKUPSTATUS, value); + + /* Destination total */ + switch_snprintf(value, sizeof(value), "%d", results->total); + switch_channel_set_variable_var_check(channel, OSP_VAR_ROUTETOTAL, value, SWITCH_FALSE); + OSP_DEBUG("%s: '%s'", OSP_VAR_ROUTETOTAL, value); + + /* Destination count */ + switch_snprintf(value, sizeof(value), "%d", results->count); + switch_channel_set_variable_var_check(channel, OSP_VAR_ROUTECOUNT, value, SWITCH_FALSE); + OSP_DEBUG("%s: '%s'", OSP_VAR_ROUTECOUNT, value); + + /* Dial string */ + if (status == SWITCH_STATUS_SUCCESS) { + osp_create_route(outbound, results, value, sizeof(value)); + switch_channel_set_variable_var_check(channel, OSP_VAR_AUTOROUTE, value, SWITCH_FALSE); + } else { + value[0] = '\0'; + switch_channel_set_variable(channel, OSP_VAR_AUTOROUTE, NULL); + } + OSP_DEBUG("%s: '%s'", OSP_VAR_AUTOROUTE, value); + + /* Termiantion cause */ + if (results->cause) { + switch_snprintf(value, sizeof(value), "%d", results->cause); + switch_channel_set_variable_var_check(channel, OSP_VAR_TCCODE, value, SWITCH_FALSE); + } else { + value[0] = '\0'; + switch_channel_set_variable(channel, OSP_VAR_TCCODE, NULL); + } + OSP_DEBUG("%s: '%s'", OSP_VAR_TCCODE, value); + + OSP_DEBUG_END; +} + +/* + * Export OSP next status to channel + * param channel Originator channel + * param status OSP next status + * param outbound Outbound info + * param results Routing info + * return + */ +static void osp_export_next( + switch_channel_t *channel, + switch_status_t status, + osp_outbound_t *outbound, + osp_results_t *results) +{ + char value[OSP_SIZE_NORSTR]; + + OSP_DEBUG_START; + + /* OSP next status */ + switch_snprintf(value, sizeof(value), "%d", status); + switch_channel_set_variable_var_check(channel, OSP_VAR_NEXTSTATUS, value, SWITCH_FALSE); + OSP_DEBUG("%s: '%s'", OSP_VAR_NEXTSTATUS, value); + + /* Destination count */ + switch_snprintf(value, sizeof(value), "%d", results->count); + switch_channel_set_variable_var_check(channel, OSP_VAR_ROUTECOUNT, value, SWITCH_FALSE); + OSP_DEBUG("%s: '%s'", OSP_VAR_ROUTECOUNT, value); + + /* Dial string */ + if (status == SWITCH_STATUS_SUCCESS) { + osp_create_route(outbound, results, value, sizeof(value)); + switch_channel_set_variable_var_check(channel, OSP_VAR_AUTOROUTE, value, SWITCH_FALSE); + } else { + value[0] = '\0'; + switch_channel_set_variable(channel, OSP_VAR_AUTOROUTE, NULL); + } + OSP_DEBUG("%s: '%s'", OSP_VAR_AUTOROUTE, value); + + /* Termiantion cause */ + if (results->cause) { + switch_snprintf(value, sizeof(value), "%d", results->cause); + switch_channel_set_variable_var_check(channel, OSP_VAR_TCCODE, value, SWITCH_FALSE); + } else { + value[0] = '\0'; + switch_channel_set_variable(channel, OSP_VAR_TCCODE, NULL); + } + OSP_DEBUG("%s: '%s'", OSP_VAR_TCCODE, value); + + OSP_DEBUG_END; +} + +/* + * Request auth and get first OSP route + * param channel Originator channel + * param results Routing info + * return + */ +static void osp_do_lookup( + switch_channel_t *channel, + osp_results_t *results) +{ + int error; + osp_profile_t *profile; + osp_inbound_t inbound; + osp_outbound_t outbound; + switch_status_t status = SWITCH_STATUS_FALSE; + + OSP_DEBUG_START; + + if (osp_find_profile(results->profile, &profile) == SWITCH_STATUS_FALSE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find profile '%s'\n", results->profile); + } else if (profile->provider == OSP_INVALID_HANDLE) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Disabled profile '%s'\n", results->profile); + } else if ((error = OSPPTransactionNew(profile->provider, &results->transaction)) != OSPC_ERR_NO_ERROR) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create transaction handle, error '%d'\n", error); + } else { + /* Get inbound info */ + osp_get_inbound(channel, &inbound); + + /* Log AuthReq parameters */ + osp_log_authreq(profile, &inbound); + + /* Do AuthReq */ + if (osp_request_auth(profile, &inbound, results) == SWITCH_STATUS_SUCCESS) { + /* Get route */ + if ((osp_get_first(results) == SWITCH_STATUS_SUCCESS) || (osp_get_next(results) == SWITCH_STATUS_SUCCESS)) { + /* Get outbound info */ + osp_get_outbound(channel, &outbound); + status = SWITCH_STATUS_SUCCESS; + } + } + } + + /* Export OSP lookup info */ + osp_export_lookup(channel, status, &outbound, results); + + OSP_DEBUG_END; +} + +/* + * Get next OSP route + * param channel Originator channel + * param results Routing info + * return + */ +static void osp_do_next( + switch_channel_t *channel, + osp_results_t *results) +{ + osp_outbound_t outbound; + switch_status_t status = SWITCH_STATUS_FALSE; + + OSP_DEBUG_START; + + if (osp_get_transaction(channel, SWITCH_FALSE, results) == SWITCH_STATUS_SUCCESS) { + /* Get next OSP route */ + if ((status = osp_get_next(results)) == SWITCH_STATUS_SUCCESS) { + /* Get outbound info */ + osp_get_outbound(channel, &outbound); + } + } + + /* Export OSP next info */ + osp_export_next(channel, status, &outbound, results); + + OSP_DEBUG_END; +} + +/* + * Report OSP usage + * param channel Originator channel + * param originator Originate profile + * param terminator Terminate profile + * param results Routing info + * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed + */ +static switch_status_t osp_do_report( + switch_channel_t *channel, + switch_caller_profile_t *originator, + switch_caller_profile_t *terminator, + osp_results_t *results) +{ + osp_usage_t usage; + switch_status_t status = SWITCH_STATUS_SUCCESS; + + OSP_DEBUG_START; + + if (osp_get_transaction(channel, SWITCH_TRUE, results) == SWITCH_STATUS_SUCCESS) { + /* Do not report usage for failed AuthReq */ + if (results->total) { + /* Get usage info */ + osp_get_usage(channel, originator, terminator, results, &usage); + + /* Log usage info */ + osp_log_usageind(results, &usage); + + /* Report OSP usage */ + status = osp_report_usage(results, &usage); + } else { + OSP_DEBUG_MSG("Do not report usage"); + } + } + + OSP_DEBUG_END; + + return status; +} + +/* + * OSP module CLI command + * Macro expands to: + * static switch_status_t osp_cli_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream) + */ +SWITCH_STANDARD_API(osp_cli_function) { int i, argc = 0; char *argv[2] = { 0 }; @@ -738,18 +2409,23 @@ SWITCH_STANDARD_API(osp_api_function) osp_profile_t *profile; char *loglevel; + OSP_DEBUG_START; + if (session) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This function cannot be called from the dialplan.\n"); + OSP_DEBUG_END; return SWITCH_STATUS_FALSE; } if (switch_strlen_zero(cmd)) { stream->write_function(stream, "Usage: osp status\n"); + OSP_DEBUG_END; return SWITCH_STATUS_SUCCESS; } if (!(params = switch_safe_strdup(cmd))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to duplicate parameters\n"); + OSP_DEBUG_END; return SWITCH_STATUS_MEMERR; } @@ -757,8 +2433,8 @@ SWITCH_STANDARD_API(osp_api_function) 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) { + stream->write_function(stream, " debug-info: %s\n", osp_global.debug ? "enabled" : "disabled"); + switch (osp_global.loglevel) { case SWITCH_LOG_CONSOLE: loglevel = "console"; break; @@ -786,39 +2462,39 @@ SWITCH_STANDARD_API(osp_api_function) 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.modules[OSPC_PROTNAME_SIP]) || switch_strlen_zero(osp_globals.profiles[OSPC_PROTNAME_SIP])) { + stream->write_function(stream, " crypto-hardware: %s\n", osp_global.hardware ? "enabled" : "disabled"); + if (switch_strlen_zero(osp_global.endpoint[OSPC_PROTNAME_SIP].module) || switch_strlen_zero(osp_global.endpoint[OSPC_PROTNAME_SIP].profile)) { stream->write_function(stream, " sip: unsupported\n"); } else { stream->write_function(stream, " sip: %s/%s\n", - osp_globals.modules[OSPC_PROTNAME_SIP], osp_globals.profiles[OSPC_PROTNAME_SIP]); + osp_global.endpoint[OSPC_PROTNAME_SIP].module, osp_global.endpoint[OSPC_PROTNAME_SIP].profile); } - if (switch_strlen_zero(osp_globals.modules[OSPC_PROTNAME_Q931]) || switch_strlen_zero(osp_globals.profiles[OSPC_PROTNAME_Q931])) { + if (switch_strlen_zero(osp_global.endpoint[OSPC_PROTNAME_Q931].module) || switch_strlen_zero(osp_global.endpoint[OSPC_PROTNAME_Q931].profile)) { stream->write_function(stream, " h323: unsupported\n"); } else { stream->write_function(stream, " h323: %s/%s\n", - osp_globals.modules[OSPC_PROTNAME_Q931], osp_globals.profiles[OSPC_PROTNAME_Q931]); + osp_global.endpoint[OSPC_PROTNAME_Q931].module, osp_global.endpoint[OSPC_PROTNAME_Q931].profile); } - if (switch_strlen_zero(osp_globals.modules[OSPC_PROTNAME_IAX]) || switch_strlen_zero(osp_globals.profiles[OSPC_PROTNAME_IAX])) { + if (switch_strlen_zero(osp_global.endpoint[OSPC_PROTNAME_IAX].module) || switch_strlen_zero(osp_global.endpoint[OSPC_PROTNAME_IAX].profile)) { stream->write_function(stream, " iax: unsupported\n"); } else { stream->write_function(stream, " iax: %s/%s\n", - osp_globals.modules[OSPC_PROTNAME_IAX], osp_globals.profiles[OSPC_PROTNAME_IAX]); + osp_global.endpoint[OSPC_PROTNAME_IAX].module, osp_global.endpoint[OSPC_PROTNAME_IAX].profile); } - if (switch_strlen_zero(osp_globals.modules[OSPC_PROTNAME_SKYPE]) || switch_strlen_zero(osp_globals.profiles[OSPC_PROTNAME_SKYPE])) { + if (switch_strlen_zero(osp_global.endpoint[OSPC_PROTNAME_SKYPE].module) || switch_strlen_zero(osp_global.endpoint[OSPC_PROTNAME_SKYPE].profile)) { stream->write_function(stream, " skype: unsupported\n"); } else { stream->write_function(stream, " skype: %s/%s\n", - osp_globals.modules[OSPC_PROTNAME_SKYPE], osp_globals.profiles[OSPC_PROTNAME_SKYPE]); + osp_global.endpoint[OSPC_PROTNAME_SKYPE].module, osp_global.endpoint[OSPC_PROTNAME_SKYPE].profile); } - stream->write_function(stream, " default-protocol: %s\n", osp_get_protocol(osp_globals.protocol)); + stream->write_function(stream, " default-protocol: %s\n", osp_get_protocolname(osp_global.protocol)); stream->write_function(stream, "============== OSP Profile Settings & Status ==============\n"); for (profile = osp_profiles; profile; profile = profile->next) { stream->write_function(stream, "Profile: %s\n", profile->name); - for (i = 0; i < profile->spnum; i++) { - stream->write_function(stream, " service-point-url: %s\n", profile->spurls[i]); + for (i = 0; i < profile->spnumber; i++) { + stream->write_function(stream, " service-point-url: %s\n", profile->spurl[i]); } - stream->write_function(stream, " device-ip: %s\n", profile->device); + stream->write_function(stream, " device-ip: %s\n", profile->deviceip); stream->write_function(stream, " ssl-lifetime: %d\n", profile->lifetime); stream->write_function(stream, " http-max-connections: %d\n", profile->maxconnect); stream->write_function(stream, " http-persistence: %d\n", profile->persistence); @@ -855,1518 +2531,74 @@ SWITCH_STANDARD_API(osp_api_function) switch_safe_free(params); + OSP_DEBUG_END; + return SWITCH_STATUS_SUCCESS; } -/* - * Parse Userinfo for user and LNP - * param userinfo SIP URI userinfo - * param user User part - * param usersize Size of user buffer - * param rn Routing number - * param rnsize Size of rn buffer - * param cic Carrier Identification Cod - * param cicsize Size of cic buffer - * param npdi NP Database Dip Indicator - * return - */ -static void osp_parse_userinfo( - const char *userinfo, - char *user, - switch_size_t usersize, - char *rn, - switch_size_t rnsize, - char *cic, - switch_size_t cicsize, - int *npdi) -{ - char buffer[OSP_SIZE_NORSTR]; - char *item; - char *tmp; - - if (!switch_strlen_zero(userinfo)) { - switch_copy_string(buffer, userinfo, sizeof(buffer)); - item = strtok_r(buffer, OSP_USER_DELIM, &tmp); - if (user && usersize) { - switch_copy_string(user, item, usersize); - } - for (item = strtok_r(NULL, OSP_USER_DELIM, &tmp); item; item = strtok_r(NULL, OSP_USER_DELIM, &tmp)) { - if (!strncasecmp(item, "rn=", 3)) { - if (rn && rnsize) { - switch_copy_string(rn, item + 3, rnsize); - } - } else if (!strncasecmp(item, "cic=", 4)) { - if (cic && cicsize) { - switch_copy_string(cic, item + 4, cicsize); - } - } else if (!strcasecmp(item, "npdi")) { - *npdi = 1; - } - } - } -} - -/* - * Parse SIP header user - * param header SIP header - * param user SIP header user - * param usersize Size of user buffer - * return - */ -static void osp_parse_header_user( - const char *header, - char *user, - switch_size_t usersize) -{ - char buffer[OSP_SIZE_NORSTR]; - char *head; - char *tmp; - char *item; - - if (!switch_strlen_zero(header) && user && usersize) { - *user = '\0'; - switch_copy_string(buffer, header, sizeof(buffer)); - if ((head = strstr(buffer, "sip:"))) { - head += 4; - if ((tmp = strchr(head, OSP_URI_DELIM))) { - *tmp = '\0'; - item = strtok_r(head, OSP_USER_DELIM, &tmp); - switch_copy_string(user, item, usersize); - } - } - } -} - -/* - * Parse SIP header host - * param header SIP header - * param host SIP header host - * param hostsize Size of host buffer - * return - */ -static void osp_parse_header_host( - const char *header, - char *host, - switch_size_t hostsize) -{ - char buffer[OSP_SIZE_NORSTR]; - char *head; - char *tmp; - - if (!switch_strlen_zero(header) && host && hostsize) { - *host = '\0'; - switch_copy_string(buffer, header, sizeof(buffer)); - if ((head = strstr(buffer, "sip:"))) { - head += 4; - if ((tmp = strchr(head, OSP_URI_DELIM))) { - head = tmp + 1; - } - tmp = strtok(head, OSP_HOST_DELIM); - switch_copy_string(host, tmp, hostsize); - } - } -} - -/* - * Log AuthReq parameters - * param profile OSP profile - * param inbound Inbound info - * return - */ -static void osp_log_authreq( - osp_profile_t *profile, - osp_inbound_t *inbound) -{ - char *srvtype; - const char *source; - const char *srcdev; - char term[OSP_SIZE_NORSTR]; - int total; - - if (osp_globals.debug) { - if (profile->workmode == OSP_MODE_INDIRECT) { - source = inbound->srcdev; - if (switch_strlen_zero(inbound->actsrc)) { - srcdev = inbound->srcdev; - } else { - srcdev = inbound->actsrc; - } - } else { - source = profile->device; - srcdev = inbound->srcdev; - } - - if (profile->srvtype == OSP_SRV_NPQUERY) { - srvtype = "npquery"; - if (switch_strlen_zero(inbound->tohost)) { - switch_copy_string(term, source, 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 = profile->maxdest; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, osp_globals.loglevel, - "AuthReq: " - "srvtype '%s' " - "source '%s' " - "srcdev '%s' " - "protocol '%s' " - "calling '%s' " - "called '%s' " - "lnp '%s/%s/%d' " - "prefer '%s' " - "rpid '%s' " - "pai '%s' " - "div '%s/%s' " - "pci '%s' " - "srcnid '%s' " - "cinfo '%s/%s/%s/%s/%s/%s/%s/%s' " - "maxcount '%d'\n", - srvtype, - source, - srcdev, - osp_get_protocol(inbound->protocol), - inbound->calling, - inbound->called, - inbound->nprn, inbound->npcic, inbound->npdi, - term, - inbound->rpiduser, - inbound->paiuser, - inbound->divuser, inbound->divhost, - inbound->pciuser, - 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 protocol from module name - * param module Module name - * return protocol name - */ -static OSPE_PROTOCOL_NAME osp_get_moduleprotocol( - const char *module) -{ - OSPE_PROTOCOL_NAME protocol; - - if (!strcasecmp(module, OSP_MODULE_SIP)) { - protocol = OSPC_PROTNAME_SIP; - } else if (!strcasecmp(module, OSP_MODULE_H323)) { - protocol = OSPC_PROTNAME_Q931; - } else if (!strcasecmp(module, OSP_MODULE_IAX)) { - protocol = OSPC_PROTNAME_IAX; - } else if (!strcasecmp(module, OSP_MODULE_SKYPE)) { - protocol = OSPC_PROTNAME_SKYPE; - } else { - protocol = OSPC_PROTNAME_UNKNOWN; - } - - return protocol; -} - -/* - * 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->actsrc = switch_channel_get_variable(channel, OSP_VAR_SRCDEV); - inbound->srcdev = caller->network_addr; - inbound->protocol = osp_get_moduleprotocol(caller->source); - if ((tmp = switch_channel_get_variable(channel, OSP_FS_FROMUSER))) { - osp_parse_userinfo(tmp, inbound->calling, sizeof(inbound->calling), NULL, 0, NULL, 0, NULL); - } else { - osp_parse_userinfo(caller->caller_id_number, inbound->calling, sizeof(inbound->calling), NULL, 0, NULL, 0, NULL); - } - osp_parse_userinfo(caller->destination_number, inbound->called, sizeof(inbound->called), inbound->nprn, sizeof(inbound->nprn), - inbound->npcic, sizeof(inbound->npcic), &inbound->npdi); - - 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_RPID))) { - osp_parse_header_user(tmp, inbound->rpiduser, sizeof(inbound->rpiduser)); - } - if ((tmp = switch_channel_get_variable(channel, OSP_FS_PAI))) { - osp_parse_userinfo(tmp, inbound->paiuser, sizeof(inbound->paiuser), NULL, 0, NULL, 0, NULL); - } - if ((tmp = switch_channel_get_variable(channel, OSP_FS_DIV))) { - osp_parse_header_user(tmp, inbound->divuser, sizeof(inbound->divuser)); - osp_parse_header_host(tmp, inbound->divhost, sizeof(inbound->divhost)); - } - if ((tmp = switch_channel_get_variable(channel, OSP_FS_PCI))) { - osp_parse_header_user(tmp, inbound->pciuser, sizeof(inbound->pciuser)); - } - - 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); - } -} - -/* - * Get outbound settings - * param channel Inbound channel - * param outbound Outbound settings - * return - */ -static void osp_get_outbound( - switch_channel_t *channel, - osp_outbound_t *outbound) -{ - const char *value; - - memset(outbound, 0, sizeof(*outbound)); - - /* Get destination network ID namd & location info */ - outbound->dniduserparam = switch_channel_get_variable(channel, OSP_VAR_DNIDUSERPARAM); - outbound->dniduriparam = switch_channel_get_variable(channel, OSP_VAR_DNIDURIPARAM); - - /* Get "user=phone" insert flag */ - value = switch_channel_get_variable(channel, OSP_VAR_USERPHONE); - if (!switch_strlen_zero(value)) { - outbound->userphone = switch_true(value); - } - - /* Get outbound proxy info */ - outbound->outproxy = switch_channel_get_variable(channel, OSP_VAR_OUTPROXY); -} - -/* - * 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 transaction Transaction handle - * param dest Destination - * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed - */ -static switch_status_t osp_check_destination( - OSPTTRANHANDLE transaction, - osp_destination_t *dest) -{ - OSPE_DEST_OSPENABLED enabled; - OSPE_PROTOCOL_NAME protocol; - OSPE_OPERATOR_NAME type; - int error; - switch_status_t status = SWITCH_STATUS_FALSE; - - if ((transaction == 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(transaction, &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(transaction, &protocol)) != OSPC_ERR_NO_ERROR) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get signaling protocol, error '%d'\n", error); - return status; - } - - switch(protocol) { - case OSPC_PROTNAME_UNDEFINED: - case OSPC_PROTNAME_UNKNOWN: - protocol = osp_globals.protocol; - case OSPC_PROTNAME_SIP: - case OSPC_PROTNAME_Q931: - case OSPC_PROTNAME_IAX: - case OSPC_PROTNAME_SKYPE: - dest->protocol = protocol; - if (!switch_strlen_zero(osp_globals.modules[protocol]) && !switch_strlen_zero(osp_globals.profiles[protocol])) { - dest->supported = SWITCH_TRUE; - status = SWITCH_STATUS_SUCCESS; - } - break; - case OSPC_PROTNAME_LRQ: - case OSPC_PROTNAME_T37: - case OSPC_PROTNAME_T38: - case OSPC_PROTNAME_SMPP: - case OSPC_PROTNAME_XMPP: - default: - dest->protocol = protocol; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported protocol '%d'\n", protocol); - break; - } - - if ((error = OSPPTransactionGetDestinationNetworkId(transaction, sizeof(dest->destnid), dest->destnid)) != OSPC_ERR_NO_ERROR) { - dest->destnid[0] = '\0'; - } - - error = OSPPTransactionGetNumberPortabilityParameters( - transaction, - 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(transaction, 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 '%"PRIu64"' " - "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 profile OSP profile - * param transaction Transaction handle - * param inbound Call originator info - * param results Routing info - * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed - */ -static switch_status_t osp_do_request( - osp_profile_t *profile, - OSPTTRANHANDLE transaction, - osp_inbound_t *inbound, - osp_results_t *results) -{ - OSPTTRANS *context; - osp_destination_t *dest; - char tmp[OSP_SIZE_NORSTR]; - const char *source; - const char *srcdev; - 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(profile, inbound); - - OSPPTransactionSetProtocol(transaction, OSPC_PROTTYPE_SOURCE, inbound->protocol); - - OSPPTransactionSetNumberPortability(transaction, inbound->nprn, inbound->npcic, inbound->npdi); - - OSPPTransactionSetRemotePartyId(transaction, OSPC_NFORMAT_E164, inbound->rpiduser); - OSPPTransactionSetAssertedId(transaction, OSPC_NFORMAT_E164, inbound->paiuser); - osp_convert_inout(inbound->divhost, tmp, sizeof(tmp)); - OSPPTransactionSetDiversion(transaction, inbound->divuser, tmp); - OSPPTransactionSetChargeInfo(transaction, OSPC_NFORMAT_E164, inbound->pciuser); - - OSPPTransactionSetNetworkIds(transaction, inbound->srcnid, NULL); - - for (count = 0; count < OSP_MAX_CINFO; count++) { - if (!switch_strlen_zero(inbound->cinfo[count])) { - OSPPTransactionSetCustomInfo(transaction, count, inbound->cinfo[count]); - } - } - - if (profile->workmode == OSP_MODE_INDIRECT) { - source = inbound->srcdev; - if (switch_strlen_zero(inbound->actsrc)) { - srcdev = inbound->srcdev; - } else { - srcdev = inbound->actsrc; - } - } else { - source = profile->device; - srcdev = inbound->srcdev; - } - osp_convert_inout(source, src, sizeof(src)); - osp_convert_inout(srcdev, dev, sizeof(dev)); - - if (profile->srvtype == OSP_SRV_NPQUERY) { - OSPPTransactionSetServiceType(transaction, 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(transaction, OSPC_SERVICE_VOICE); - - total = profile->maxdest; - } - - error = OSPPTransactionRequestAuthorisation( - transaction, /* 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 for '%s/%s', error '%d'\n", - inbound->calling, inbound->called, error); - results->status = error; - results->numdest = 0; - return status; - } else if (!total) { - results->status = error; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Without destination\n"); - results->status = error; - results->numdest = 0; - return status; - } - - context = OSPPTransactionGetContext(transaction, &error); - if (error == OSPC_ERR_NO_ERROR) { - results->transid = context->TransactionID; - } else { - results->transid = 0; - } - - switch_copy_string(results->calling, inbound->calling, sizeof(results->calling)); - switch_copy_string(results->called, inbound->called, sizeof(results->called)); - results->srcdev = srcdev; - results->srcnid = inbound->srcnid; - results->start = inbound->start; - - count = 0; - dest = &results->dests[count]; - error = OSPPTransactionGetFirstDestination( - transaction, /* 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); - results->status = error; - results->numdest = 0; - return status; - } - - osp_convert_outin(term, dest->dest, sizeof(dest->dest)); - osp_check_destination(transaction, dest); - - for (count = 1; count < total; count++) { - dest = &results->dests[count]; - error = OSPPTransactionGetNextDestination( - transaction, /* 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(transaction, dest); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get destination, error '%d'\n", error); - break; - } - } - if (count == total) { - results->status = OSPC_ERR_NO_ERROR; - results->numdest = total; - osp_log_authrsp(results); - status = SWITCH_STATUS_SUCCESS; - } else { - results->status = error; - results->numdest = 0; - } - - return status; -} - -/* - * Request auth/routing info - * param channel Originator channel - * param profile Profile 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 *profilename, - osp_results_t *results) -{ - osp_profile_t *profile; - OSPTTRANHANDLE transaction; - osp_inbound_t inbound; - int error; - switch_status_t status = SWITCH_STATUS_FALSE; - - if (osp_find_profile(profilename, &profile) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find profile '%s'\n", profilename); - return status; - } - - if (profile->provider == OSP_INVALID_HANDLE) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Disabled profile '%s'\n", profilename); - return status; - } - - results->profile = profilename; - - if ((error = OSPPTransactionNew(profile->provider, &transaction)) != 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(profile, transaction, &inbound, results); - - OSPPTransactionDelete(transaction); - - 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=%"PRIu64",%s=%s,%s=%s,%s=%"PRId64",%s=%s,%s=%d", - OSP_VAR_PROFILE, results->profile, - OSP_VAR_TRANSID, results->transid, - OSP_VAR_CALLING, results->calling, - OSP_VAR_CALLED, results->called, - OSP_VAR_START, results->start, - OSP_VAR_SRCDEV, results->srcdev, - OSP_VAR_DESTTOTAL, results->numdest); - 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 outbound Outbound settings - * param buffer Buffer - * param bufsize Buffer size - * return - */ -static void osp_build_endpoint( - osp_destination_t *dest, - osp_outbound_t *outbound, - char *buffer, - switch_size_t bufsize) -{ - char *head = buffer; - switch_size_t len, size = bufsize; - - if (head && size) { - switch (dest->protocol) { - case OSPC_PROTNAME_SIP: - switch_snprintf(head, size, "%s/%s/%s", osp_globals.modules[OSPC_PROTNAME_SIP], osp_globals.profiles[OSPC_PROTNAME_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); - } - - if (!switch_strlen_zero(outbound->dniduserparam) && !switch_strlen_zero_buf(dest->destnid)) { - switch_snprintf(head, size, ";%s=%s", outbound->dniduserparam, dest->destnid); - osp_adjust_len(head, size, len); - } - - switch_snprintf(head, size, "@%s", dest->dest); - osp_adjust_len(head, size, len); - - if (!switch_strlen_zero(outbound->dniduriparam) && !switch_strlen_zero_buf(dest->destnid)) { - switch_snprintf(head, size, ";%s=%s", outbound->dniduriparam, dest->destnid); - osp_adjust_len(head, size, len); - } - - if (outbound->userphone) { - switch_snprintf(head, size, ";user=phone"); - osp_adjust_len(head, size, len); - } - - if (!switch_strlen_zero(outbound->outproxy)) { - switch_snprintf(head, size, ";fs_path=sip:%s", outbound->outproxy); - osp_adjust_len(head, size, len); - } - break; - case OSPC_PROTNAME_Q931: - switch_snprintf(head, size, "%s/%s/%s@%s", osp_globals.modules[OSPC_PROTNAME_Q931], osp_globals.profiles[OSPC_PROTNAME_Q931], - dest->called, dest->dest); - osp_adjust_len(head, size, len); - break; - case OSPC_PROTNAME_IAX: - switch_snprintf(head, size, "%s/%s/%s/%s", osp_globals.modules[OSPC_PROTNAME_Q931], osp_globals.profiles[OSPC_PROTNAME_Q931], - dest->dest, dest->called); - osp_adjust_len(head, size, len); - break; - case OSPC_PROTNAME_SKYPE: - switch_snprintf(head, size, "%s/%s/%s", osp_globals.modules[OSPC_PROTNAME_Q931], osp_globals.profiles[OSPC_PROTNAME_Q931], - dest->called); - osp_adjust_len(head, size, len); - break; - default: - buffer[0] = '\0'; - break; - } - } -} - -/* - * Create route string - * param channel Originator channel - * param results Routing info - * 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_ROUSTR]; - char allparam[OSP_SIZE_NORSTR]; - char eachparam[OSP_SIZE_NORSTR]; - char endpoint[OSP_SIZE_NORSTR]; - osp_outbound_t outbound; - char tmp[OSP_SIZE_ROUSTR]; - char buffer[OSP_SIZE_ROUSTR]; - int i, len, count, size = sizeof(buffer); - char *head = buffer; - switch_event_header_t *hi; - char *var; - - osp_get_outbound(channel, &outbound); - - /* 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); - } - - switch_snprintf(value, sizeof(value), "%d", results->status); - switch_channel_set_variable_var_check(channel, OSP_VAR_AUTHSTATUS, value, SWITCH_FALSE); - - osp_build_allparam(results, head, size); - switch_copy_string(allparam, head, sizeof(allparam)); - 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, &outbound, endpoint, sizeof(endpoint)); - - switch_snprintf(name, sizeof(name), "%s%d", OSP_VAR_ROUTEPRE, count); - switch_snprintf(value, sizeof(value), "%s%s%s", allparam, eachparam, endpoint); - switch_channel_set_variable_var_check(channel, name, value, SWITCH_FALSE); - - switch_snprintf(tmp, sizeof(tmp), "%s%s", eachparam, endpoint); - switch_snprintf(head, size, "%s|", tmp); - 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); -} - -/* - * Export AuthReq status to channel - * param channel Originator channel - * param results Routing info - * return - */ -static void osp_export_failure( - switch_channel_t *channel, - osp_results_t *results) -{ - char value[OSP_SIZE_NORSTR]; - 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); - } - - switch_snprintf(value, sizeof(value), "%d", results->status); - switch_channel_set_variable_var_check(channel, OSP_VAR_AUTHSTATUS, value, SWITCH_FALSE); - - switch_snprintf(value, sizeof(value), "%d", results->numdest); - switch_channel_set_variable_var_check(channel, OSP_VAR_ROUTECOUNT, value, SWITCH_FALSE); -} - /* * Macro expands to: - * static void osp_app_function(switch_core_session_t *session, const char *data) + * static void osp_lookup_function(switch_core_session_t *session, const char *data) */ -SWITCH_STANDARD_APP(osp_app_function) +SWITCH_STANDARD_APP(osp_lookup_function) { + switch_channel_t *channel; 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) { + OSP_DEBUG_START; + + if (osp_global.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))) { + } else if (!(channel = switch_core_session_get_channel(session))) { + /* Make sure there is a valid channel when starting the OSP application */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to find origiantor channel\n"); - return; - } - - if (!(params = switch_core_session_strdup(session, data))) { + } else 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); - } else { - osp_export_failure(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]; - osp_outbound_t outbound; - char name[OSP_SIZE_NORSTR]; - char value[OSP_SIZE_ROUSTR]; - int i, count; - switch_event_header_t *hi; - char *var; - - 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; - } - - osp_get_outbound(channel, &outbound); - - switch_channel_set_variable(channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, "true"); - - /* 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); - } + memset(&results, 0, sizeof(osp_results_t)); + if ((argc = switch_separate_string(params, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { + results.profile = argv[0]; + } else { + results.profile = OSP_DEF_PROFILE; } - switch_channel_variable_last(channel); + results.transaction = OSP_INVALID_HANDLE; + results.protocol = OSPC_PROTNAME_UNKNOWN; + + /* Do OSP lookup */ + osp_do_lookup(channel, &results); } - switch_snprintf(value, sizeof(value), "%d", results->status); - switch_channel_set_variable_var_check(channel, OSP_VAR_AUTHSTATUS, value, SWITCH_FALSE); - - osp_build_allparam(results, allparam, sizeof(allparam)); - - 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, &outbound, endpoint, sizeof(endpoint)); - - switch_snprintf(name, sizeof(name), "%s%d", OSP_VAR_ROUTEPRE, count); - switch_snprintf(value, sizeof(value), "%s%s%s", allparam, eachparam, endpoint); - switch_channel_set_variable_var_check(channel, name, value, SWITCH_FALSE); - - switch_caller_extension_add_application(session, *extension, "bridge", value); - } - } - - switch_snprintf(value, sizeof(value), "%d", count); - switch_channel_set_variable_var_check(channel, OSP_VAR_ROUTECOUNT, value, SWITCH_FALSE); + OSP_DEBUG_END; } /* * Macro expands to: - * switch_caller_extension_t * osp_dialplan_function(switch_core_session_t *session, void *arg, switch_caller_profile_t *caller_profile) + * static void osp_next_function(switch_core_session_t *session, const char *data) */ -SWITCH_STANDARD_DIALPLAN(osp_dialplan_function) +SWITCH_STANDARD_APP(osp_next_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); + 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 dialplan inavailable\n"); - return extension; - } + OSP_DEBUG_START; - if ((argc = switch_separate_string((char *)arg, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { - profile = argv[0]; + if (osp_global.shutdown) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "OSP application inavailable\n"); + } else if (!(channel = switch_core_session_get_channel(session))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to find origiantor channel\n"); } else { - profile = OSP_DEF_PROFILE; + memset(&results, 0, sizeof(osp_results_t)); + results.transaction = OSP_INVALID_HANDLE; + results.protocol = OSPC_PROTNAME_UNKNOWN; + + /* Do OSP next */ + osp_do_next(channel, &results); } - retval = osp_request_routing(channel, profile, &results); - if (retval == SWITCH_STATUS_SUCCESS) { - osp_add_application(session, channel, &extension, &results); - } else { - osp_export_failure(channel, &results); - } - - return extension; -} - -/* - * Retrieve cookie - * param channel Destination channel - * param cookie Cookie - * return SWITCH_STATUS_SUCCESS Successful, SWITCH_STATUS_FALSE Failed - */ -static switch_status_t osp_get_cookie( - 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)) || (sscanf(strvar, "%"PRIu64"", &cookie->transid) != 1)) { - cookie->transid = 0; - } - - cookie->calling = switch_channel_get_variable(channel, OSP_VAR_CALLING); - cookie->called = switch_channel_get_variable(channel, OSP_VAR_CALLED); - - if (!(strvar = switch_channel_get_variable(channel, OSP_VAR_START)) || (sscanf(strvar, "%"PRId64"", &cookie->start) != 1)) { - cookie->start = 0; - } - - cookie->srcdev = switch_channel_get_variable(channel, OSP_VAR_SRCDEV); - - if (!(strvar = switch_channel_get_variable(channel, OSP_VAR_DESTTOTAL)) || (sscanf(strvar, "%d", &cookie->desttotal) != 1)) { - cookie->desttotal = 0; - } - - if (!(strvar = switch_channel_get_variable(channel, OSP_VAR_DESTCOUNT)) || (sscanf(strvar, "%d", &cookie->destcount) != 1)) { - 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 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->inprotocol = osp_get_moduleprotocol(originator->source); - } - - terminator = switch_channel_get_caller_profile(channel); - usage->outprotocol = osp_get_moduleprotocol(terminator->source); - if (usage->outprotocol == OSPC_PROTNAME_SIP) { - strvar = switch_channel_get_variable(channel, OSP_FS_SIPRELEASE); - if (!strvar || !strcasecmp(strvar, "recv_bye")) { - usage->release = 1; - } - } - 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->srccodec = switch_channel_get_variable(channel, OSP_FS_SRCCODEC); - usage->destcodec = switch_channel_get_variable(channel, OSP_FS_DESTCODEC); - if (!(strvar = switch_channel_get_variable(channel, OSP_FS_RTPSRCREPOCTS)) || - (sscanf(strvar, "%d", &usage->rtpsrcrepoctets) != 1)) - { - usage->rtpsrcrepoctets = OSP_DEF_STATS; - } - if (!(strvar = switch_channel_get_variable(channel, OSP_FS_RTPDESTREPOCTS)) || - (sscanf(strvar, "%d", &usage->rtpdestrepoctets) != 1)) - { - usage->rtpdestrepoctets = OSP_DEF_STATS; - } - if (!(strvar = switch_channel_get_variable(channel, OSP_FS_RTPSRCREPPKTS)) || - (sscanf(strvar, "%d", &usage->rtpsrcreppackets) != 1)) - { - usage->rtpsrcreppackets = OSP_DEF_STATS; - } - if (!(strvar = switch_channel_get_variable(channel, OSP_FS_RTPDESTREPPKTS)) || - (sscanf(strvar, "%d", &usage->rtpdestreppackets) != 1)) - { - usage->rtpdestreppackets = 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->transaction, info->cause); - - for (i = 0; i < 3; i++) { - error = OSPPTransactionReportUsage( - info->transaction, /* 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 '%"PRIu64"' attempt '%d'\n", - info->transid, - i + 1); - } else { - break; - } - } - - OSPPTransactionDelete(info->transaction); - - switch_safe_free(info); - - OSPTTHREADRETURN_NULL(); -} - -/* - * Report usage - * param cookie 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_profile_t *profile; - char source[OSP_SIZE_NORSTR]; - char destination[OSP_SIZE_NORSTR]; - char srcdev[OSP_SIZE_NORSTR]; - OSPTTRANHANDLE transaction; - osp_threadarg_t *info; - OSPTTHREADID threadid; - OSPTTHRATTR threadattr; - int error; - switch_status_t status = SWITCH_STATUS_FALSE; - - if (osp_find_profile(cookie->profile, &profile) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find profile '%s'\n", cookie->profile); - return status; - } - - if ((error = OSPPTransactionNew(profile->provider, &transaction)) != OSPC_ERR_NO_ERROR) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create transaction handle, error '%d'\n", error); - return status; - } - - if (profile->workmode == OSP_MODE_INDIRECT) { - osp_convert_inout(usage->srcdev, source, sizeof(source)); - } else { - osp_convert_inout(profile->device, source, sizeof(source)); - } - - osp_convert_inout(cookie->dest, destination, sizeof(destination)); - - osp_convert_inout(cookie->srcdev, srcdev, sizeof(srcdev)); - - error = OSPPTransactionBuildUsageFromScratch( - transaction, /* Transaction handle */ - cookie->transid, /* Transaction ID */ - OSPC_ROLE_SOURCE, /* CDR type, source */ - source, /* Source */ - destination, /* Destination */ - srcdev, /* Source device */ - OSP_DEF_STRING, /* Destination device */ - cookie->calling, /* Calling */ - OSPC_NFORMAT_E164, /* Calling format */ - cookie->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(transaction); - return status; - } - - status = SWITCH_STATUS_SUCCESS; - - OSPPTransactionSetDestinationCount(transaction, cookie->destcount); - - OSPPTransactionSetProtocol(transaction, OSPC_PROTTYPE_SOURCE, usage->inprotocol); - OSPPTransactionSetProtocol(transaction, OSPC_PROTTYPE_DESTINATION, usage->outprotocol); - - if (!switch_strlen_zero(cookie->srcnid)) { - OSPPTransactionSetSrcNetworkId(transaction, cookie->srcnid); - } - - if (!switch_strlen_zero(cookie->destnid)) { - OSPPTransactionSetDestNetworkId(transaction, cookie->destnid); - } - - if (!switch_strlen_zero(usage->srccodec)) { - OSPPTransactionSetCodec(transaction, OSPC_CODEC_SOURCE, usage->srccodec); - } - if (!switch_strlen_zero(usage->destcodec)) { - OSPPTransactionSetCodec(transaction, OSPC_CODEC_DESTINATION, usage->destcodec); - } - - if (usage->rtpsrcrepoctets != OSP_DEF_STATS) { - OSPPTransactionSetOctets(transaction, OSPC_SMETRIC_RTP, OSPC_SDIR_SRCREP, usage->rtpsrcrepoctets); - } - if (usage->rtpdestrepoctets != OSP_DEF_STATS) { - OSPPTransactionSetOctets(transaction, OSPC_SMETRIC_RTP, OSPC_SDIR_DESTREP, usage->rtpdestrepoctets); - } - if (usage->rtpsrcreppackets != OSP_DEF_STATS) { - OSPPTransactionSetPackets(transaction, OSPC_SMETRIC_RTP, OSPC_SDIR_SRCREP, usage->rtpsrcreppackets); - } - if (usage->rtpdestreppackets != OSP_DEF_STATS) { - OSPPTransactionSetPackets(transaction, OSPC_SMETRIC_RTP, OSPC_SDIR_DESTREP, usage->rtpdestreppackets); - } - -/* TODO: The logic to identify the last call attempt needs improvement. - if ((cookie->destcount == cookie->desttotal) || (usage->cause == SWITCH_CAUSE_NORMAL_CLEARING)) { - OSPPTransactionSetRoleInfo(transaction, OSPC_RSTATE_STOP, OSPC_RFORMAT_OSP, OSPC_RVENDOR_FREESWITCH); - } else { - OSPPTransactionSetRoleInfo(transaction, OSPC_RSTATE_INTERIM, OSPC_RFORMAT_OSP, OSPC_RVENDOR_FREESWITCH); - } -*/ - OSPPTransactionSetRoleInfo(transaction, OSPC_RSTATE_STOP, OSPC_RFORMAT_OSP, OSPC_RVENDOR_FREESWITCH); - - info = (osp_threadarg_t *)malloc(sizeof(osp_threadarg_t)); - info->transaction = transaction; - 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 / 1000; - 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); - - /* transaction and info will be released by osp_report_thread */ - - return status; -} - -/* - * Log UsageInd parameters - * param cookie 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 '%"PRIu64"' " - "destcount '%d' " - "callid '%s' " - "calling '%s' " - "called '%s' " - "srcdev '%s' " - "dest '%s' " - "nid '%s/%s' " - "protocol '%s/%s' " - "cause '%d' " - "release '%s' " - "times '%"PRId64"/%"PRId64"/%"PRId64"/%"PRId64"' " - "duration '%"PRId64"' " - "pdd '%"PRId64"' " - "outsessionid '%s' " - "codec '%s/%s' " - "rtpctets '%d/%d' " - "rtppackets '%d/%d'\n", - cookie->transid, - cookie->destcount, - usage->callid, - cookie->calling, - cookie->called, - cookie->srcdev, - cookie->dest, - osp_filter_null(cookie->srcnid), osp_filter_null(cookie->destnid), - osp_get_protocol(usage->inprotocol), osp_get_protocol(usage->outprotocol), - 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->srccodec), osp_filter_null(usage->destcodec), - usage->rtpsrcrepoctets, usage->rtpdestrepoctets, - usage->rtpsrcreppackets, usage->rtpdestreppackets); - } + OSP_DEBUG_END; } /* @@ -2378,30 +2610,40 @@ 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; + switch_caller_profile_t *terminator; + osp_results_t results; + switch_status_t status = SWITCH_STATUS_FALSE; - if (osp_globals.shutdown) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "OSP application inavailable\n"); - return status; + OSP_DEBUG_START; + + if (osp_global.shutdown) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OSP application inavailable\n"); + } else if (!(channel = switch_core_session_get_channel(session))) { + /* Make sure there is a valid channel when starting the OSP application */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to find origiantor channel\n"); + } else if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { + /* A-leg */ + OSP_DEBUG_MSG("A-leg"); + + /* Get originator profile */ + if ((originator = switch_channel_get_caller_profile(channel))) { + /* Get terminator profile, may be NULL */ + terminator = switch_channel_get_originatee_caller_profile(channel); + + memset(&results, 0, sizeof(osp_results_t)); + results.transaction = OSP_INVALID_HANDLE; + results.protocol = OSPC_PROTNAME_UNKNOWN; + + /* Do OSP usage report */ + status = osp_do_report(channel, originator, terminator, &results); + } + } else { + /* B-leg */ + OSP_DEBUG_MSG("B-leg"); } - /* 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_cookie(channel, &cookie) != SWITCH_STATUS_SUCCESS) { - return status; - } - - osp_get_usage(channel, originator, &cookie, &usage); - - osp_log_usageind(&cookie, &usage); - - osp_report_usage(&cookie, &usage); + OSP_DEBUG_END; return status; } @@ -2409,7 +2651,7 @@ static switch_status_t osp_on_reporting( /* * OSP module state handlers */ -static switch_state_handler_table_t state_handlers = { +static switch_state_handler_table_t osp_handlers = { NULL, /*.on_init */ NULL, /*.on_routing */ NULL, /*.on_execute */ @@ -2423,59 +2665,53 @@ static switch_state_handler_table_t state_handlers = { osp_on_reporting /*.on_reporting */ }; +/* 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); + /* + * Called when OSP module is loaded * 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_api_interface_t *cli_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) { + OSP_DEBUG_START; + + /* Load OSP module configuration */ + if ((status = osp_load_config(pool)) != SWITCH_STATUS_SUCCESS) { + OSP_DEBUG_END; return status; } - /* Init OSP Toolkit */ + /* Init OSP client end */ osp_init_osptk(); - /* Connect OSP internal structure to the blank pointer passed to OSP module */ + /* Connect OSP module 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"); + /* Add CLI osp status command */ + SWITCH_ADD_API(cli_interface, "osp", "OSP", osp_cli_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 module applications */ + SWITCH_ADD_APP(app_interface, "osplookup", "Perform an OSP lookup", "Perform an OSP lookup", osp_lookup_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC); + SWITCH_ADD_APP(app_interface, "ospnext", "Retrive next OSP route", "Retrive next OSP route", osp_next_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC); - /* Add OSP dialplan */ - SWITCH_ADD_DIALPLAN(dp_interface, "osp", osp_dialplan_function); + /* Add OSP module state handlers */ + switch_core_add_state_handler(&osp_handlers); - /* Add OSP state handlers */ - switch_core_add_state_handler(&state_handlers); + OSP_DEBUG_END; /* Indicate that the module should continue to be loaded */ - return status; -} - -/* - * Cleanup OSP client end - * return - */ -static void osp_cleanup_osptk(void) -{ - osp_profile_t *profile; - - for (profile = osp_profiles; profile; profile = profile->next) { - OSPPProviderDelete(profile->provider, 0); - profile->provider = OSP_INVALID_HANDLE; - } - - OSPPCleanup(); + return SWITCH_STATUS_SUCCESS; } /* @@ -2485,14 +2721,18 @@ static void osp_cleanup_osptk(void) */ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_osp_shutdown) { - /* Shutdown OSP module */ - osp_globals.shutdown = SWITCH_TRUE; + OSP_DEBUG_START; - /* Cleanup OSP Toolkit */ + /* Shutdown OSP module */ + osp_global.shutdown = SWITCH_TRUE; + + /* Cleanup OSP client end */ osp_cleanup_osptk(); - /* Remoeve OSP state handlers */ - switch_core_remove_state_handler(&state_handlers); + /* Remoeve OSP module state handlers */ + switch_core_remove_state_handler(&osp_handlers); + + OSP_DEBUG_END; return SWITCH_STATUS_SUCCESS; }