Merging in latest from upstream (FS/freeswitch:refs/heads/master)
* commit '564393cf27618ddf3140ef05f35901d6beb6dbcd': (43 commits) refresh checkboxes in demo FS-7587 #comment one profile to rule them all (part 2) FS-7602 FS-7499 FS-7587 #comment another refactoring pass on candidate parsing and ipv4/6 parsing (part 2) FS-7587 #comment one profile to rule them all FS-7602 FS-7499 FS-7587 #comment another refactoring pass on candidate parsing and ipv4/6 parsing FS-7513 make sure user does not have auto avatar when not visible FS-7586 Change the default min-required-recording-participants option for mod_conference from 2 to 1. #NEEDSDOCS FS-7602 add some of3b2d00f3e6
from verto to sip and refactor some code to keep sip working like verto add a bit to2db8f94ab6
FS-7258, FS-7571: [mod_xml_cdr] properly encode xml cdr for post to web server FS-7585 increasing AMF buffer for larger picture FS-7603: Implement failover for socket application FS-7604 #resolve FS-7436: [mod_opus] fix the plc counter to actually count FS-7436: added FEC support for mod_opus FS-7564 #resolve #comment [mod_rayo] Added new algorithms for offering calls to clients. Two new params added to autoload_configs/rayo.conf.xml offer-algorithm all: offer to all clients (default and old behavior) first: offer to first client, fails over to next client in list random: offer to random client, fails over to next random client set affected_rows also for non-SELECT queries Add sip_watched_headers variable to launch events when a SIP message contains a given SIP header FS-7426 shouuld not be disabled on all, only squeeze and wheezy Fixed encoded_data_len for MODE 2400, it should be 6 bytes. Also replaced 2550 bps bitrate (obsoleted operation mode) by 2400 ...
This commit is contained in:
commit
390ebac3c1
|
@ -8,6 +8,11 @@
|
|||
<param name="mixer-conf-profile" value="sla"/>
|
||||
<!-- if true, to attribute in offer uses URI instead of name/number -->
|
||||
<param name="offer-uri" value="true"/>
|
||||
<!-- how offers are distributed to clients (all, first, random). -->
|
||||
<param name="offer-algorithm" value="all"/>
|
||||
<!-- If offer is not answered after timeout, next client is offered (based on algorithm picked).
|
||||
If no other clients are available, the call is rejected. Set to 0 to disable -->
|
||||
<param name="offer-timeout-ms" value="5000"/>
|
||||
<!-- if true, channel variables are added to rayo client offer -->
|
||||
<param name="add-variables-to-offer" value="false"/>
|
||||
<!-- if true, channel variables are added to offer, ringing, answered, and end events sent to rayo clients -->
|
||||
|
|
|
@ -185,6 +185,7 @@
|
|||
<!-- <param name="video-layout-bgcolor" value="#000000"/> -->
|
||||
<!-- <param name="video-codec-bandwidth" value="2mb"/> -->
|
||||
<!-- <param name="video-fps" value="15"/> -->
|
||||
<!-- <param name="video-auto-floor-msec" value="100"/> -->
|
||||
|
||||
|
||||
<!-- <param name="tts-engine" value="flite"/> -->
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
</settings>
|
||||
|
||||
<profiles>
|
||||
<profile name="mine">
|
||||
<param name="bind-local" value="0.0.0.0:8081"/>
|
||||
<param name="bind-local" value="0.0.0.0:8082" secure="true"/>
|
||||
<profile name="default">
|
||||
<param name="bind-local" value="$${local_ip_v4}:8081"/>
|
||||
<param name="bind-local" value="$${local_ip_v4}:8082" secure="true"/>
|
||||
<param name="bind-local" value="[$${local_ip_v6}]:8081"/>
|
||||
<param name="bind-local" value="[$${local_ip_v6}]:8082" secure="true"/>
|
||||
<param name="force-register-domain" value="$${domain}"/>
|
||||
<param name="secure-combined" value="$${certs_dir}/wss.pem"/>
|
||||
<param name="secure-chain" value="$${certs_dir}/wss.pem"/>
|
||||
|
@ -16,15 +18,20 @@
|
|||
<param name="blind-reg" value="false"/>
|
||||
<param name="mcast-ip" value="224.1.1.1"/>
|
||||
<param name="mcast-port" value="1337"/>
|
||||
<param name="rtp-ip" value="$${local_ip_v6}"/>
|
||||
<param name="rtp-ip" value="$${local_ip_v4}"/>
|
||||
<!-- <param name="ext-rtp-ip" value=""/> -->
|
||||
<param name="local-network" value="localnet.auto"/>
|
||||
<param name="outbound-codec-string" value="opus,vp8"/>
|
||||
<param name="inbound-codec-string" value="opus,vp8"/>
|
||||
<param name="apply-candidate-acl" value="wan.auto"/>
|
||||
<param name="apply-candidate-acl" value="localnet.auto"/>
|
||||
<param name="apply-candidate-acl" value="wan_v6.auto"/>
|
||||
<param name="apply-candidate-acl" value="wan_v4.auto"/>
|
||||
<param name="apply-candidate-acl" value="rfc1918.auto"/>
|
||||
<param name="apply-candidate-acl" value="any_v6.auto"/>
|
||||
<param name="apply-candidate-acl" value="any_v4.auto"/>
|
||||
<param name="timer-name" value="soft"/>
|
||||
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</configuration>
|
||||
|
|
|
@ -413,8 +413,6 @@
|
|||
openssl ciphers -v 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH'
|
||||
|
||||
Will show you what is available in your verion of openssl.
|
||||
Freeswitch does not support non-Elliptic Curve Diffie Hellman key
|
||||
exchange.
|
||||
-->
|
||||
<X-PRE-PROCESS cmd="set" data="sip_tls_ciphers=ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"/>
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ avoid_mods=(
|
|||
endpoints/mod_opal
|
||||
endpoints/mod_reference
|
||||
endpoints/mod_unicall
|
||||
event_handlers/mod_amqp
|
||||
sdk/autotools
|
||||
xml_int/mod_xml_ldap
|
||||
xml_int/mod_xml_radius
|
||||
|
|
|
@ -795,6 +795,7 @@ function refresh_devices()
|
|||
|
||||
//$("input[type='radio']).checkboxradio({});
|
||||
$("input[type='radio']").checkboxradio("refresh");
|
||||
$("input[type='checkbox']").checkboxradio("refresh");
|
||||
|
||||
//console.error($("#usecamera").find(":selected").val());
|
||||
}
|
||||
|
|
|
@ -99,6 +99,9 @@ static History *myhistory;
|
|||
static HistEvent ev;
|
||||
#endif
|
||||
|
||||
|
||||
static esl_mutex_t *MUTEX = NULL;
|
||||
|
||||
static void _sleep_ns(int secs, long nsecs) {
|
||||
#ifndef WIN32
|
||||
if (nsecs > 999999999) {
|
||||
|
@ -720,8 +723,15 @@ static void *msg_thread_run(esl_thread_t *me, void *obj)
|
|||
thread_running = 1;
|
||||
while(thread_running && handle->connected) {
|
||||
int aok = 1;
|
||||
esl_status_t status = esl_recv_event_timed(handle, 10, 1, NULL);
|
||||
if (status == ESL_FAIL) {
|
||||
esl_status_t status;
|
||||
|
||||
esl_mutex_lock(MUTEX);
|
||||
status = esl_recv_event_timed(handle, 10, 1, NULL);
|
||||
esl_mutex_unlock(MUTEX);
|
||||
|
||||
if (status == ESL_BREAK) {
|
||||
sleep_ms(1);
|
||||
} else if (status == ESL_FAIL) {
|
||||
esl_log(ESL_LOG_WARNING, "Disconnected.\n");
|
||||
running = -1; thread_running = 0;
|
||||
} else if (status == ESL_SUCCESS) {
|
||||
|
@ -851,8 +861,11 @@ static const char *cli_usage =
|
|||
|
||||
static int process_command(esl_handle_t *handle, const char *cmd)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
while (*cmd == ' ') cmd++;
|
||||
|
||||
esl_mutex_lock(MUTEX);
|
||||
|
||||
if ((*cmd == '/' && cmd++) || !strncasecmp(cmd, "...", 3)) {
|
||||
if (!strcasecmp(cmd, "help")) {
|
||||
|
@ -865,7 +878,7 @@ static int process_command(esl_handle_t *handle, const char *cmd)
|
|||
!strcasecmp(cmd, "bye")
|
||||
) {
|
||||
esl_log(ESL_LOG_INFO, "Goodbye!\nSee you at ClueCon http://www.cluecon.com/\n");
|
||||
return -1;
|
||||
r = -1; goto end;
|
||||
} else if (!strncasecmp(cmd, "logfilter", 9)) {
|
||||
cmd += 9;
|
||||
while (*cmd && *cmd == ' ') {
|
||||
|
@ -922,7 +935,7 @@ static int process_command(esl_handle_t *handle, const char *cmd)
|
|||
snprintf(cmd_str, sizeof(cmd_str), "api %s\nconsole_execute: true\n\n", cmd);
|
||||
if (esl_send_recv(handle, cmd_str)) {
|
||||
output_printf("Socket interrupted, bye!\n");
|
||||
return -1;
|
||||
r = -1; goto end;
|
||||
}
|
||||
if (handle->last_sr_event) {
|
||||
if (handle->last_sr_event->body) {
|
||||
|
@ -932,8 +945,12 @@ static int process_command(esl_handle_t *handle, const char *cmd)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return 0;
|
||||
|
||||
esl_mutex_unlock(MUTEX);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_profile(const char *name, cli_profile_t **profile)
|
||||
|
@ -1142,7 +1159,9 @@ static unsigned char esl_console_complete(const char *buffer, const char *cursor
|
|||
} else {
|
||||
snprintf(cmd_str, sizeof(cmd_str), "api console_complete %s\n\n", buf);
|
||||
}
|
||||
|
||||
esl_send_recv(global_handle, cmd_str);
|
||||
|
||||
if (global_handle->last_sr_event && global_handle->last_sr_event->body) {
|
||||
char *r = global_handle->last_sr_event->body;
|
||||
char *w, *p1;
|
||||
|
@ -1183,7 +1202,13 @@ static unsigned char esl_console_complete(const char *buffer, const char *cursor
|
|||
static unsigned char complete(EditLine *el, int ch)
|
||||
{
|
||||
const LineInfo *lf = el_line(el);
|
||||
return esl_console_complete(lf->buffer, lf->cursor, lf->lastchar);
|
||||
int r;
|
||||
|
||||
esl_mutex_lock(MUTEX);
|
||||
r = esl_console_complete(lf->buffer, lf->cursor, lf->lastchar);
|
||||
esl_mutex_unlock(MUTEX);
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1378,6 +1403,9 @@ int main(int argc, char *argv[])
|
|||
int loops = 2, reconnect = 0;
|
||||
char *ccheck;
|
||||
|
||||
|
||||
esl_mutex_create(&MUTEX);
|
||||
|
||||
#if HAVE_DECL_EL_PROMPT_ESC
|
||||
feature_level = 1;
|
||||
#else
|
||||
|
@ -1755,6 +1783,9 @@ int main(int argc, char *argv[])
|
|||
esl_disconnect(&handle);
|
||||
global_handle = NULL;
|
||||
thread_running = 0;
|
||||
|
||||
esl_mutex_destroy(&MUTEX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -933,9 +933,9 @@ ESL_DECLARE(int) esl_wait_sock(esl_socket_t sock, uint32_t ms, esl_poll_t flags)
|
|||
if ((flags & ESL_POLL_ERROR)) {
|
||||
pfds[0].events |= POLLERR;
|
||||
}
|
||||
|
||||
s = poll(pfds, 1, ms);
|
||||
|
||||
s = poll(pfds, 1, ms);
|
||||
|
||||
if (s < 0) {
|
||||
r = s;
|
||||
} else if (s > 0) {
|
||||
|
|
|
@ -381,6 +381,27 @@ int tls_init_context(tls_t *tls, tls_issues_t const *ti)
|
|||
#if require_client_certificate
|
||||
errno = EIO;
|
||||
return -1;
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_DH
|
||||
} else {
|
||||
BIO *bio = BIO_new_file(ti->key, "r");
|
||||
if (bio != NULL) {
|
||||
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
|
||||
if (dh != NULL) {
|
||||
if (!SSL_CTX_set_tmp_dh(tls->ctx, dh)) {
|
||||
SU_DEBUG_1(("%s: invalid DH parameters (PFS) because %s: %s\n",
|
||||
"tls_init_context",
|
||||
ERR_reason_error_string(ERR_get_error()),
|
||||
ti->key));
|
||||
} else {
|
||||
long options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE;
|
||||
options = SSL_CTX_set_options(tls->ctx, options);
|
||||
SU_DEBUG_3(("%s\n", "tls: initialized DHE"));
|
||||
}
|
||||
DH_free(dh);
|
||||
}
|
||||
BIO_free(bio);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -691,6 +691,7 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
|||
ssize_t need = 2;
|
||||
char *maskp;
|
||||
int ll = 0;
|
||||
int frag = 0;
|
||||
|
||||
again:
|
||||
need = 2;
|
||||
|
@ -741,8 +742,16 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
|||
case WSOC_PING:
|
||||
case WSOC_PONG:
|
||||
{
|
||||
//int fin = (wsh->buffer[0] >> 7) & 1;
|
||||
int fin = (wsh->buffer[0] >> 7) & 1;
|
||||
int mask = (wsh->buffer[1] >> 7) & 1;
|
||||
|
||||
if (fin) {
|
||||
if (*oc == WSOC_CONTINUATION) {
|
||||
frag = 1;
|
||||
} else {
|
||||
frag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask) {
|
||||
need += 4;
|
||||
|
@ -837,6 +846,10 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
|||
ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (frag) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
|
||||
*(wsh->payload+wsh->rplen) = '\0';
|
||||
|
|
|
@ -497,14 +497,14 @@ static __inline__ void symbol_sync(v27ter_rx_state_t *s)
|
|||
|
||||
s->gardner_integrate += (p + q > 0) ? s->gardner_step : -s->gardner_step;
|
||||
|
||||
if (abs(s->gardner_integrate) >= 256)
|
||||
if (abs(s->gardner_integrate) >= 128)
|
||||
{
|
||||
/* This integrate and dump approach avoids rapid changes of the equalizer put step.
|
||||
Rapid changes, without hysteresis, are bad. They degrade the equalizer performance
|
||||
when the true symbol boundary is close to a sample boundary. */
|
||||
//span_log(&s->logging, SPAN_LOG_FLOW, "Hop %d\n", s->gardner_integrate);
|
||||
s->eq_put_step += (s->gardner_integrate/256);
|
||||
s->total_baud_timing_correction += (s->gardner_integrate/256);
|
||||
s->eq_put_step += (s->gardner_integrate/128);
|
||||
s->total_baud_timing_correction += (s->gardner_integrate/128);
|
||||
if (s->qam_report)
|
||||
s->qam_report(s->qam_user_data, NULL, NULL, s->gardner_integrate);
|
||||
s->gardner_integrate = 0;
|
||||
|
|
|
@ -125,6 +125,9 @@ typedef struct switch_core_media_params_s {
|
|||
|
||||
char *extrtpip;
|
||||
char *rtpip;
|
||||
char *rtpip4;
|
||||
char *rtpip6;
|
||||
|
||||
|
||||
char *remote_ip;
|
||||
int remote_port;
|
||||
|
@ -329,6 +332,7 @@ SWITCH_DECLARE(switch_media_flow_t) switch_core_session_media_flow(switch_core_s
|
|||
SWITCH_DECLARE(switch_status_t) switch_core_media_get_vid_params(switch_core_session_t *session, switch_vid_params_t *vid_params);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh, switch_rw_t rw);
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_session_in_video_thread(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t *session);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
|
|
|
@ -103,8 +103,9 @@ typedef struct icand_s {
|
|||
typedef struct ice_s {
|
||||
|
||||
icand_t cands[MAX_CAND][2];
|
||||
int cand_idx;
|
||||
int cand_idx[2];
|
||||
int chosen[2];
|
||||
int is_chosen[2];
|
||||
char *ufrag;
|
||||
char *pwd;
|
||||
char *options;
|
||||
|
|
|
@ -197,6 +197,8 @@ SWITCH_DECLARE(char *) switch_stun_host_lookup(const char *host, switch_memory_p
|
|||
\return true or false
|
||||
*/
|
||||
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_get_mapped_address(switch_stun_packet_attribute_t *attribute, char *ipstr, uint16_t *port);
|
||||
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_get_xor_mapped_address(switch_stun_packet_attribute_t *attribute, uint32_t cookie, char *ipstr, uint16_t *port);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Extract a username from a packet attribute
|
||||
|
|
|
@ -1052,6 +1052,7 @@ static inline int switch_needs_url_encode(const char *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(char *) switch_url_encode_opt(const char *url, char *buf, size_t len, switch_bool_t double_encode);
|
||||
SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len);
|
||||
SWITCH_DECLARE(char *) switch_url_decode(char *s);
|
||||
SWITCH_DECLARE(switch_bool_t) switch_simple_email(const char *to,
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*
|
||||
* Marc Olivier Chouinard <mochouinard@moctel.com>
|
||||
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
|
||||
*
|
||||
* Ítalo Rossi <italorossib@gmail.com>
|
||||
*
|
||||
* mod_callcenter.c -- Call Center Module
|
||||
*
|
||||
|
@ -1506,19 +1506,18 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
const char *cid_number = NULL;
|
||||
const char *cid_name_prefix = NULL;
|
||||
|
||||
if ((cid_name_prefix = switch_channel_get_variable(member_channel, "cc_outbound_cid_name_prefix"))) {
|
||||
cid_name_freeable = switch_mprintf("%s%s", cid_name_prefix, h->member_cid_name);
|
||||
cid_name = cid_name_freeable;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Setting outbound caller_id_name to: %s\n", cid_name);
|
||||
} else {
|
||||
if (!(cid_name = switch_channel_get_variable(member_channel, "effective_caller_id_name"))) {
|
||||
cid_name = h->member_cid_name;
|
||||
}
|
||||
|
||||
if (!(cid_number = switch_channel_get_variable(member_channel, "effective_caller_id_number"))) {
|
||||
cid_number = h->member_cid_number;
|
||||
}
|
||||
if (!(cid_name = switch_channel_get_variable(member_channel, "effective_caller_id_name"))) {
|
||||
cid_name = h->member_cid_name;
|
||||
}
|
||||
if (!(cid_number = switch_channel_get_variable(member_channel, "effective_caller_id_number"))) {
|
||||
cid_number = h->member_cid_number;
|
||||
}
|
||||
if ((cid_name_prefix = switch_channel_get_variable(member_channel, "cc_outbound_cid_name_prefix"))) {
|
||||
cid_name_freeable = switch_mprintf("%s%s", cid_name_prefix, cid_name);
|
||||
cid_name = cid_name_freeable;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Setting outbound caller_id_name to: %s\n", cid_name);
|
||||
|
||||
switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue_name);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_uuid", "%s", h->member_uuid);
|
||||
|
@ -2108,6 +2107,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
|
|||
agent_callback_t cbt;
|
||||
const char *member_state = NULL;
|
||||
const char *member_abandoned_epoch = NULL;
|
||||
const char *serving_agent = NULL;
|
||||
memset(&cbt, 0, sizeof(cbt));
|
||||
|
||||
cbt.queue_name = argv[0];
|
||||
|
@ -2119,6 +2119,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
|
|||
cbt.member_score = argv[6];
|
||||
member_state = argv[7];
|
||||
member_abandoned_epoch = argv[8];
|
||||
serving_agent = argv[9];
|
||||
|
||||
if (!cbt.queue_name || !(queue = get_queue(cbt.queue_name))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, skip this member\n", cbt.queue_name);
|
||||
|
@ -2153,7 +2154,23 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
|
|||
}
|
||||
/* Skip this member */
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tracking queue strategy changes */
|
||||
/* member is ring-all but not the queue */
|
||||
if (!strcasecmp(serving_agent, "ring-all") && (strcasecmp(queue_strategy, "ring-all") != 0)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Queue '%s' changed strategy, adjusting member parameters", queue_name);
|
||||
sql = switch_mprintf("UPDATE members SET serving_agent = '', state = '%s' WHERE uuid = '%s' AND state = '%s' AND serving_agent = 'ring-all'", cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt.member_uuid, cc_member_state2str(CC_MEMBER_STATE_TRYING));
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
/* Queue is now ring-all and not the member */
|
||||
else if (!strcasecmp(queue_strategy, "ring-all") && (strcasecmp(serving_agent, "ring-all") != 0)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Queue '%s' changed strategy, adjusting member parameters", queue_name);
|
||||
sql = switch_mprintf("UPDATE members SET serving_agent = 'ring-all', state = '%s' WHERE uuid = '%s' AND state = '%s' AND serving_agent = ''", cc_member_state2str(CC_MEMBER_STATE_TRYING), cbt.member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING));
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
/* Check if member is in the queue waiting */
|
||||
if (zstr(cbt.member_session_uuid)) {
|
||||
|
@ -2307,7 +2324,7 @@ void *SWITCH_THREAD_FUNC cc_agent_dispatch_thread_run(switch_thread_t *thread, v
|
|||
|
||||
while (globals.running == 1) {
|
||||
char *sql = NULL;
|
||||
sql = switch_mprintf("SELECT queue,uuid,session_uuid,cid_number,cid_name,joined_epoch,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score, state, abandoned_epoch FROM members"
|
||||
sql = switch_mprintf("SELECT queue,uuid,session_uuid,cid_number,cid_name,joined_epoch,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score, state, abandoned_epoch, serving_agent FROM members"
|
||||
" WHERE state = '%q' OR state = '%q' OR (serving_agent = 'ring-all' AND state = '%q') ORDER BY score DESC",
|
||||
local_epoch_time_now(NULL),
|
||||
cc_member_state2str(CC_MEMBER_STATE_WAITING), cc_member_state2str(CC_MEMBER_STATE_ABANDONED), cc_member_state2str(CC_MEMBER_STATE_TRYING));
|
||||
|
@ -2518,6 +2535,7 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score");
|
||||
int cc_base_score_int = 0;
|
||||
const char *cur_moh = NULL;
|
||||
char *moh_expanded = NULL;
|
||||
char start_epoch[64];
|
||||
switch_event_t *event;
|
||||
switch_time_t t_member_called = local_epoch_time_now(NULL);
|
||||
|
@ -2679,6 +2697,7 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
cur_moh = switch_core_session_strdup(member_session, queue->moh);
|
||||
}
|
||||
queue_rwunlock(queue);
|
||||
moh_expanded = switch_channel_expand_variables(member_channel, cur_moh);
|
||||
|
||||
while (switch_channel_ready(member_channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
|
@ -2701,9 +2720,8 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
|
||||
switch_core_session_flush_private_events(member_session);
|
||||
|
||||
if (moh_valid && cur_moh) {
|
||||
switch_status_t status = switch_ivr_play_file(member_session, NULL, cur_moh, &args);
|
||||
|
||||
if (moh_valid && moh_expanded) {
|
||||
switch_status_t status = switch_ivr_play_file(member_session, NULL, moh_expanded, &args);
|
||||
if (status == SWITCH_STATUS_FALSE /* Invalid Recording */ && SWITCH_READ_ACCEPTABLE(status)) {
|
||||
/* Sadly, there doesn't seem to be a return to switch_ivr_play_file that tell you the file wasn't found. FALSE also mean that the channel got switch to BRAKE state, so we check for read acceptable */
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_WARNING, "Couldn't play file '%s', continuing wait with no audio\n", cur_moh);
|
||||
|
@ -2724,6 +2742,9 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
}
|
||||
switch_yield(1000);
|
||||
}
|
||||
if (moh_expanded != cur_moh) {
|
||||
switch_safe_free(moh_expanded);
|
||||
}
|
||||
|
||||
/* Make sure an agent was found, as we might break above without setting it */
|
||||
if (!agent_found && (p = switch_channel_get_variable(member_channel, "cc_agent_found"))) {
|
||||
|
|
|
@ -594,6 +594,7 @@ typedef struct conference_obj {
|
|||
struct conf_fps video_fps;
|
||||
int playing_video_file;
|
||||
int recording_members;
|
||||
uint32_t video_floor_packets;
|
||||
} conference_obj_t;
|
||||
|
||||
/* Relationship with another member */
|
||||
|
@ -682,6 +683,7 @@ struct conference_member {
|
|||
switch_frame_buffer_t *fb;
|
||||
switch_image_t *avatar_png_img;
|
||||
switch_image_t *video_mute_img;
|
||||
uint32_t floor_packets;
|
||||
int blanks;
|
||||
int managed_kps;
|
||||
int blackouts;
|
||||
|
@ -1882,6 +1884,26 @@ static void check_avatar(conference_member_t *member, switch_bool_t force)
|
|||
}
|
||||
}
|
||||
|
||||
static void check_flush(conference_member_t *member)
|
||||
{
|
||||
int flushed;
|
||||
|
||||
if (!member->channel || !switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
||||
return;
|
||||
}
|
||||
|
||||
flushed = flush_video_queue(member->video_queue);
|
||||
|
||||
if (flushed && member->auto_avatar) {
|
||||
switch_channel_video_sync(member->channel);
|
||||
|
||||
switch_img_free(&member->avatar_png_img);
|
||||
member->avatar_patched = 0;
|
||||
reset_video_bitrate_counters(member);
|
||||
member->blanks = 0;
|
||||
member->auto_avatar = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
|
@ -2028,7 +2050,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
|
|||
size = switch_queue_size(imember->video_queue);
|
||||
} while(size > 0);
|
||||
|
||||
if (switch_test_flag(imember, MFLAG_CAN_BE_SEEN) && imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
if (switch_test_flag(imember, MFLAG_CAN_BE_SEEN) && imember->video_layer_id > -1 && imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
if (img) {
|
||||
imember->good_img++;
|
||||
if ((imember->good_img % (int)(conference->video_fps.fps * 10)) == 0) {
|
||||
|
@ -2052,31 +2074,14 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
|
|||
//if (layer) {
|
||||
//layer->is_avatar = 1;
|
||||
//}
|
||||
|
||||
|
||||
imember->auto_avatar = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int flushed = flush_video_queue(imember->video_queue);
|
||||
|
||||
if (flushed && imember->auto_avatar) {
|
||||
switch_channel_video_sync(imember->channel);
|
||||
|
||||
switch_img_free(&imember->avatar_png_img);
|
||||
imember->avatar_patched = 0;
|
||||
reset_video_bitrate_counters(imember);
|
||||
|
||||
if (layer) {
|
||||
layer->is_avatar = 0;
|
||||
imember->auto_avatar = 0;
|
||||
}
|
||||
|
||||
imember->blanks = 0;
|
||||
} else {
|
||||
|
||||
}
|
||||
check_flush(imember);
|
||||
}
|
||||
|
||||
layer = NULL;
|
||||
|
@ -4439,6 +4444,7 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
|
|||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Adding video floor %s\n",
|
||||
switch_channel_get_name(member->channel));
|
||||
|
||||
check_flush(member);
|
||||
switch_core_session_video_reinit(member->session);
|
||||
conference->video_floor_holder = member->id;
|
||||
member_update_status_field(member);
|
||||
|
@ -4496,15 +4502,6 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference
|
|||
conference_member_t *old_member = NULL;
|
||||
int old_id = 0;
|
||||
|
||||
|
||||
if (((conference->video_floor_holder && !member && !switch_test_flag(conference, CFLAG_VID_FLOOR_LOCK)) ||
|
||||
(member && member->channel && (switch_channel_test_flag(member->channel, CF_VIDEO) || member->avatar_png_img)))) {
|
||||
|
||||
if (member && member->id != conference->video_floor_holder) {
|
||||
conference_set_video_floor_holder(conference, member, SWITCH_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (conference->floor_holder) {
|
||||
if (conference->floor_holder == member) {
|
||||
return;
|
||||
|
@ -4531,6 +4528,7 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference
|
|||
if (old_member) {
|
||||
old_id = old_member->id;
|
||||
member_update_status_field(old_member);
|
||||
old_member->floor_packets = 0;
|
||||
}
|
||||
|
||||
switch_set_flag(conference, CFLAG_FLOOR_CHANGE);
|
||||
|
@ -6330,6 +6328,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
|||
check_agc_levels(member);
|
||||
clear_avg(member);
|
||||
member->score_iir = 0;
|
||||
member->floor_packets = 0;
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
|
@ -6369,7 +6368,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
|||
if (member->volume_in_level) {
|
||||
switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->volume_in_level);
|
||||
}
|
||||
|
||||
|
||||
if (member->agc_volume_in_level) {
|
||||
switch_change_sln_volume_granular(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->agc_volume_in_level);
|
||||
}
|
||||
|
@ -6428,10 +6427,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
|||
member->score_iir = SCORE_MAX_IIR;
|
||||
}
|
||||
|
||||
if (member == member->conference->floor_holder && member->id != member->conference->video_floor_holder) {
|
||||
conference_set_video_floor_holder(member->conference, member, SWITCH_FALSE);
|
||||
}
|
||||
|
||||
if (noise_gate_check(member)) {
|
||||
uint32_t diff = member->score - member->energy_level;
|
||||
if (hangover_hits) {
|
||||
|
@ -6442,16 +6437,20 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
|||
member->nt_tally = 0;
|
||||
}
|
||||
|
||||
if (member == member->conference->floor_holder) {
|
||||
member->floor_packets++;
|
||||
}
|
||||
|
||||
if (diff >= diff_level || ++hangunder_hits >= hangunder) {
|
||||
|
||||
hangover_hits = hangunder_hits = 0;
|
||||
member->last_talking = switch_epoch_time_now(NULL);
|
||||
|
||||
|
||||
if (!switch_test_flag(member, MFLAG_TALKING)) {
|
||||
switch_set_flag_locked(member, MFLAG_TALKING);
|
||||
member_update_status_field(member);
|
||||
|
||||
member->floor_packets = 0;
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_START_TALKING) && switch_test_flag(member, MFLAG_CAN_SPEAK) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
|
@ -6504,6 +6503,13 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
|||
|
||||
|
||||
member->last_score = member->score;
|
||||
|
||||
if (member == member->conference->floor_holder) {
|
||||
if (member->id != member->conference->video_floor_holder &&
|
||||
(member->floor_packets > member->conference->video_floor_packets || member->energy_level == 0)) {
|
||||
conference_set_video_floor_holder(member->conference, member, SWITCH_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loops++;
|
||||
|
@ -11479,7 +11485,7 @@ static void clear_eflags(char *events, uint32_t *f)
|
|||
} else if (!strcmp(event, "play-file")) {
|
||||
*f &= ~EFLAG_PLAY_FILE;
|
||||
} else if (!strcmp(event, "play-file-done")) {
|
||||
*f &= ~EFLAG_PLAY_FILE;
|
||||
*f &= ~EFLAG_PLAY_FILE_DONE;
|
||||
} else if (!strcmp(event, "play-file-member")) {
|
||||
*f &= ~EFLAG_PLAY_FILE_MEMBER;
|
||||
} else if (!strcmp(event, "speak-text")) {
|
||||
|
@ -12563,7 +12569,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
|||
char *suppress_events = NULL;
|
||||
char *verbose_events = NULL;
|
||||
char *auto_record = NULL;
|
||||
int min_recording_participants = 2;
|
||||
int min_recording_participants = 1;
|
||||
char *conference_log_dir = NULL;
|
||||
char *cdr_event_mode = NULL;
|
||||
char *terminate_on_silence = NULL;
|
||||
|
@ -12573,7 +12579,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
|||
switch_codec_implementation_t read_impl = { 0 };
|
||||
switch_channel_t *channel = NULL;
|
||||
const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = NULL;
|
||||
uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = 0;
|
||||
uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = 0, video_auto_floor_msec = 0;
|
||||
|
||||
/* Validate the conference name */
|
||||
if (zstr(name)) {
|
||||
|
@ -12790,6 +12796,13 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
|||
} else if (switch_true(val)) {
|
||||
comfort_noise_level = 1400;
|
||||
}
|
||||
} else if (!strcasecmp(var, "video-auto-floor-msec") && !zstr(val)) {
|
||||
int tmp;
|
||||
tmp = atoi(val);
|
||||
|
||||
if (tmp > 0) {
|
||||
video_auto_floor_msec = tmp;
|
||||
}
|
||||
} else if (!strcasecmp(var, "sound-prefix") && !zstr(val)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "override sound-prefix with: %s\n", val);
|
||||
sound_prefix = val;
|
||||
|
@ -12819,9 +12832,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
|||
} else if (!strcasecmp(var, "auto-record") && !zstr(val)) {
|
||||
auto_record = val;
|
||||
} else if (!strcasecmp(var, "min-required-recording-participants") && !zstr(val)) {
|
||||
if (!strcmp(val, "1")) {
|
||||
min_recording_participants = 1;
|
||||
} else if (!strcmp(val, "2")) {
|
||||
if (!strcmp(val, "2")) {
|
||||
min_recording_participants = 2;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "min-required-recording-participants is invalid, leaving set to %d\n", min_recording_participants);
|
||||
|
@ -13170,6 +13181,10 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
|
|||
conference->ivr_dtmf_timeout = ivr_dtmf_timeout;
|
||||
conference->ivr_input_timeout = ivr_input_timeout;
|
||||
|
||||
if (video_auto_floor_msec) {
|
||||
conference->video_floor_packets = video_auto_floor_msec / conference->interval;
|
||||
}
|
||||
|
||||
conference->eflags = 0xFFFFFFFF;
|
||||
|
||||
if (!zstr(suppress_events)) {
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef struct {
|
||||
switch_time_t lastts; /* Last time we did any billing */
|
||||
|
@ -59,6 +60,7 @@ typedef struct {
|
|||
double bill_adjustments; /* Adjustments to make to the next billing, based on pause/resume events */
|
||||
|
||||
int lowbal_action_executed; /* Set to 1 once lowbal_action has been executed */
|
||||
int final_bill_done; /* Set to 1 one the final rounding has been done on a call to prevent spurious rebills on hangup */
|
||||
} nibble_data_t;
|
||||
|
||||
|
||||
|
@ -454,6 +456,12 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
|||
double nobal_amt = globals.nobal_amt;
|
||||
double lowbal_amt = globals.lowbal_amt;
|
||||
double balance;
|
||||
double minimum_charge = 0;
|
||||
double rounding_factor = 1;
|
||||
double excess = 0;
|
||||
double rounded_billed = 0;
|
||||
int billsecs = 0;
|
||||
double balance_check = 0;
|
||||
|
||||
if (!session) {
|
||||
/* Why are we here? */
|
||||
|
@ -480,6 +488,16 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
|||
lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt"));
|
||||
}
|
||||
|
||||
if (!zstr(switch_channel_get_variable(channel, "nibble_rounding"))) {
|
||||
rounding_factor = pow(10, atof(switch_channel_get_variable(channel, "nibble_rounding")));
|
||||
}
|
||||
|
||||
if (!zstr(switch_channel_get_variable(channel, "nibble_minimum"))) {
|
||||
minimum_charge = atof(switch_channel_get_variable(channel, "nibble_minimum"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return if there's no billing information on this session */
|
||||
if (!billrate || !billaccount) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
@ -501,8 +519,9 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
|||
|
||||
/* See if this person has enough money left to continue the call */
|
||||
balance = get_balance(billaccount, channel);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Comparing %f to hangup balance of %f\n", balance, nobal_amt);
|
||||
if (balance <= nobal_amt) {
|
||||
balance_check = balance - minimum_charge;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Comparing %f to hangup balance of %f, taking into account minimum charge of %f\n", balance, nobal_amt, minimum_charge);
|
||||
if (balance_check <= nobal_amt) {
|
||||
/* Not enough money - reroute call to nobal location */
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below allowed amount of %f! (Account %s)\n",
|
||||
balance, nobal_amt, billaccount);
|
||||
|
@ -530,6 +549,12 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
|||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (nibble_data && nibble_data->final_bill_done) {
|
||||
switch_mutex_lock(globals.mutex);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Received heartbeat, but final bill has been committed - ignoring\n");
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Have we done any billing on this channel yet? If no, set up vars for doing so */
|
||||
if (!nibble_data) {
|
||||
nibble_data = switch_core_session_alloc(session, sizeof(*nibble_data));
|
||||
|
@ -543,8 +568,10 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
|||
switch_time_exp_lt(&tm, nibble_data->lastts);
|
||||
switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm);
|
||||
|
||||
billsecs = (int) ((ts - nibble_data->lastts) / 1000000);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%d seconds passed since last bill time of %s\n",
|
||||
(int) ((ts - nibble_data->lastts) / 1000000), date);
|
||||
billsecs, date);
|
||||
|
||||
if ((ts - nibble_data->lastts) >= 0) {
|
||||
/* If billincrement is set we bill by it and not by time elapsed */
|
||||
|
@ -576,6 +603,29 @@ static switch_status_t do_billing(switch_core_session_t *session)
|
|||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n");
|
||||
}
|
||||
|
||||
/* Do Rounding and minimum charge during hangup */
|
||||
if (switch_channel_get_state(channel) == CS_HANGUP) {
|
||||
/* we're going to make an assumption that final billing is done here. So we'll see how this goes. */
|
||||
/* round total billed up as required */
|
||||
|
||||
rounded_billed = ceilf(nibble_data->total * rounding_factor) / rounding_factor;
|
||||
|
||||
if (rounded_billed < minimum_charge)
|
||||
{
|
||||
excess = minimum_charge - nibble_data->total;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Applying minimum charge of %f (%f excess)\n", minimum_charge, excess);
|
||||
}
|
||||
else if (nibble_data->total < rounded_billed)
|
||||
{
|
||||
excess = rounded_billed - nibble_data->total;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Rounding to precision %f, total %f (%f excess)\n", rounding_factor, rounded_billed, excess);
|
||||
}
|
||||
bill_event(excess, billaccount, channel);
|
||||
nibble_data->total += excess;
|
||||
switch_channel_set_variable_printf(channel, "nibble_total_billed", "%f", nibble_data->total);
|
||||
nibble_data->final_bill_done = 1;
|
||||
}
|
||||
} else {
|
||||
if (switch_strlen_zero(billincrement))
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", uuid);
|
||||
|
@ -951,10 +1001,11 @@ static switch_status_t process_hangup(switch_core_session_t *session)
|
|||
do_billing(session);
|
||||
|
||||
billaccount = switch_channel_get_variable(channel, globals.var_name_account);
|
||||
|
||||
if (billaccount) {
|
||||
switch_channel_set_variable_printf(channel, "nibble_current_balance", "%f", get_balance(billaccount, channel));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ static switch_status_t switch_codec2_encode(switch_codec_t *codec, switch_codec_
|
|||
fflush(context->encoder_out);
|
||||
#endif
|
||||
|
||||
*encoded_data_len = 8;
|
||||
*encoded_data_len = 6;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load)
|
|||
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
SWITCH_ADD_CODEC(codec_interface, "CODEC2 2550bps");
|
||||
SWITCH_ADD_CODEC(codec_interface, "CODEC2 2400bps");
|
||||
|
||||
switch_core_codec_add_implementation(pool, codec_interface,
|
||||
SWITCH_CODEC_TYPE_AUDIO,
|
||||
|
@ -239,7 +239,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load)
|
|||
NULL,
|
||||
8000, /* samples/sec */
|
||||
8000, /* samples/sec */
|
||||
2550, /* bps */
|
||||
2400, /* bps */
|
||||
20000, /* ptime */
|
||||
CODEC2_SAMPLES_PER_FRAME, /* samples decoded */
|
||||
CODEC2_SAMPLES_PER_FRAME*2, /* bytes decoded */
|
||||
|
|
|
@ -74,6 +74,7 @@ struct opus_context {
|
|||
OpusDecoder *decoder_object;
|
||||
uint32_t enc_frame_size;
|
||||
uint32_t dec_frame_size;
|
||||
uint32_t counter_plc_fec;
|
||||
};
|
||||
|
||||
struct {
|
||||
|
@ -338,7 +339,7 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
|
|||
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
context->counter_plc_fec = 0;
|
||||
}
|
||||
|
||||
codec->private_info = context;
|
||||
|
@ -352,6 +353,7 @@ static switch_status_t switch_opus_destroy(switch_codec_t *codec)
|
|||
|
||||
if (context) {
|
||||
if (context->decoder_object) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tried PLC or FEC %d times \n", context->counter_plc_fec);
|
||||
opus_decoder_destroy(context->decoder_object);
|
||||
context->decoder_object = NULL;
|
||||
}
|
||||
|
@ -400,9 +402,13 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
|
|||
unsigned int *flag)
|
||||
{
|
||||
struct opus_context *context = codec->private_info;
|
||||
switch_core_session_t *session = codec->session;
|
||||
stfu_instance_t *jb = NULL;
|
||||
stfu_frame_t next_frame;
|
||||
int samples = 0;
|
||||
uint32_t frame_size;
|
||||
uint32_t frame_samples;
|
||||
uint32_t found_frame;
|
||||
|
||||
if (!context) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
@ -411,7 +417,28 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
|
|||
frame_samples = *decoded_data_len / 2 / codec->implementation->number_of_channels;
|
||||
frame_size = frame_samples - (frame_samples % (codec->implementation->actual_samples_per_second / 400));
|
||||
|
||||
samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, frame_size, !!(*flag & SFF_PLC));
|
||||
/*FEC: shameless rip-off from mod_silk.c . OPUS only supports n+1 FEC , SILK is supposed to work with n+1, n+2*/
|
||||
if (*flag & SFF_PLC) {
|
||||
context->counter_plc_fec++;
|
||||
if (session) {
|
||||
jb = switch_core_session_get_jb(session, SWITCH_MEDIA_TYPE_AUDIO);
|
||||
}
|
||||
if (jb && codec->cur_frame) {
|
||||
found_frame = stfu_n_copy_next_frame(jb, (uint32_t)codec->cur_frame->timestamp, codec->cur_frame->seq, 1, &next_frame);
|
||||
if (found_frame) {
|
||||
samples = opus_decode(context->decoder_object, next_frame.data, next_frame.dlen, decoded_data, frame_size, 1); /* opus_decode() does PLC if there's no FEC in the packet*/
|
||||
if (samples < 0 ) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error (FEC): %s!\n", opus_strerror(samples));
|
||||
return SWITCH_STATUS_FALSE;
|
||||
} else {
|
||||
*decoded_data_len = samples * 2 * codec->implementation->number_of_channels;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, frame_size, 0);
|
||||
|
||||
if (samples < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error: %s fs:%u plc:%d!\n", opus_strerror(samples), frame_size, !!(*flag & SFF_PLC));
|
||||
|
@ -490,8 +517,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
|
|||
codec_interface->parse_fmtp = switch_opus_fmtp_parse;
|
||||
|
||||
settings = default_codec_settings;
|
||||
|
||||
|
||||
|
||||
if (opus_prefs.maxaveragebitrate){
|
||||
settings.maxaveragebitrate = opus_prefs.maxaveragebitrate;
|
||||
}
|
||||
if (opus_prefs.maxplaybackrate) {
|
||||
settings.maxplaybackrate = opus_prefs.maxplaybackrate;
|
||||
}
|
||||
|
||||
for (x = 0; x < 3; x++) {
|
||||
|
||||
settings.ptime = mss / 1000;
|
||||
|
|
|
@ -370,6 +370,12 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *
|
|||
if ((all && !fail) || (!all && pass)) {
|
||||
anti_action = SWITCH_FALSE;
|
||||
}
|
||||
if (all && total != pass) {
|
||||
proceed = 1;
|
||||
pass = 0;
|
||||
fail++;
|
||||
anti_action = SWITCH_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
switch_safe_free(field_expanded);
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
#define RTMP_DEFAULT_PORT 1935
|
||||
#define RTMP_TCP_READ_BUF 2048 * 16
|
||||
#define AMF_MAX_SIZE 2048 * 16
|
||||
#define AMF_MAX_SIZE 2048 * 16 * 2
|
||||
|
||||
#define SUPPORT_SND_NONE 0x0000
|
||||
#define SUPPORT_SND_ADPCM 0x0002
|
||||
|
|
|
@ -1464,6 +1464,86 @@ static int flush_listener_callback(void *pArg, int argc, char **argv, char **col
|
|||
return 0;
|
||||
}
|
||||
|
||||
void skinny_lock_device_name(listener_t *listener, char *device_name)
|
||||
{
|
||||
switch_time_t started = 0;
|
||||
unsigned int elapsed = 0;
|
||||
device_name_lock_t *dnl;
|
||||
|
||||
if ( listener->profile->debug >= 9 ) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "lock device name '%s'\n", device_name);
|
||||
}
|
||||
|
||||
started = switch_micro_time_now();
|
||||
|
||||
/* global mutex on hash operations */
|
||||
switch_mutex_lock(listener->profile->device_name_lock_mutex);
|
||||
|
||||
dnl = (device_name_lock_t *) switch_core_hash_find(listener->profile->device_name_lock_hash, device_name);
|
||||
if ( ! dnl ) {
|
||||
if ( listener->profile->debug >= 9 ) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "creating device name lock for device name '%s'\n", device_name);
|
||||
}
|
||||
dnl = switch_core_alloc(listener->profile->pool, sizeof(*dnl));
|
||||
switch_mutex_init(&dnl->flag_mutex, SWITCH_MUTEX_NESTED, listener->profile->pool);
|
||||
switch_core_hash_insert(listener->profile->device_name_lock_hash, device_name, dnl);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(listener->profile->device_name_lock_mutex);
|
||||
|
||||
if ( listener->profile->debug >= 9 ) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "setting device name lock for device name '%s'\n", device_name);
|
||||
}
|
||||
switch_set_flag_locked(dnl, DNLFLAG_INUSE);
|
||||
|
||||
if ((elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000)) > 5) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "device name lock took more than 5ms for '%s' (%d)\n", device_name, elapsed);
|
||||
}
|
||||
|
||||
if ( listener->profile->debug >= 9 ) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "locked device name '%s'\n", device_name);
|
||||
}
|
||||
}
|
||||
|
||||
void skinny_unlock_device_name(listener_t *listener, char *device_name)
|
||||
{
|
||||
switch_time_t started = 0;
|
||||
unsigned int elapsed = 0;
|
||||
device_name_lock_t *dnl;
|
||||
|
||||
if ( listener->profile->debug >= 9 ) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "unlock device name '%s'\n", device_name);
|
||||
}
|
||||
|
||||
started = switch_micro_time_now();
|
||||
|
||||
/* global mutex on hash operations */
|
||||
switch_mutex_lock(listener->profile->device_name_lock_mutex);
|
||||
dnl = (device_name_lock_t *) switch_core_hash_find(listener->profile->device_name_lock_hash, device_name);
|
||||
switch_mutex_unlock(listener->profile->device_name_lock_mutex);
|
||||
|
||||
if ( ! dnl ) {
|
||||
skinny_log_l(listener, SWITCH_LOG_WARNING, "request to unlock and no lock structure for '%s'\n", device_name);
|
||||
/* since it didn't exist, nothing to unlock, don't bother creating structure now */
|
||||
} else {
|
||||
if ( listener->profile->debug >= 9 ) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "clearing device name lock on '%s'\n", device_name);
|
||||
}
|
||||
switch_clear_flag_locked(dnl, DNLFLAG_INUSE);
|
||||
}
|
||||
|
||||
/* Should we clean up the lock structure here, or does it ever get reclaimed? I don't think memory is released
|
||||
so attempting to clear it up here likely would just result in a leak. */
|
||||
|
||||
if ((elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000)) > 5) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "device name unlock took more than 5ms for '%s' (%d)\n", device_name, elapsed);
|
||||
}
|
||||
|
||||
if ( listener->profile->debug >= 9 ) {
|
||||
skinny_log_l(listener, SWITCH_LOG_DEBUG, "unlocked device name '%s'\n", device_name);
|
||||
}
|
||||
}
|
||||
|
||||
void skinny_clean_device_from_db(listener_t *listener, char *device_name)
|
||||
{
|
||||
if(!zstr(device_name)) {
|
||||
|
@ -1579,7 +1659,9 @@ static void flush_listener(listener_t *listener)
|
|||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
skinny_lock_device_name(listener, listener->device_name);
|
||||
skinny_clean_listener_from_db(listener);
|
||||
skinny_unlock_device_name(listener, listener->device_name);
|
||||
|
||||
strcpy(listener->device_name, "");
|
||||
}
|
||||
|
@ -1658,7 +1740,7 @@ switch_status_t kill_listener(listener_t *listener, void *pvt)
|
|||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Killing listener %s:%d.\n",
|
||||
listener->device_name, listener->device_instance);
|
||||
switch_clear_flag(listener, LFLAG_RUNNING);
|
||||
switch_clear_flag_locked(listener, LFLAG_RUNNING);
|
||||
close_socket(&listener->sock, listener->profile);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -1740,11 +1822,12 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
|
|||
skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Connection Open\n");
|
||||
}
|
||||
|
||||
listener->connect_time = switch_epoch_time_now(NULL);
|
||||
|
||||
switch_set_flag_locked(listener, LFLAG_RUNNING);
|
||||
keepalive_listener(listener, NULL);
|
||||
add_listener(listener);
|
||||
|
||||
|
||||
while (listener_is_ready(listener)) {
|
||||
status = skinny_read_packet(listener, &request);
|
||||
|
||||
|
@ -2116,6 +2199,8 @@ static switch_status_t load_skinny_config(void)
|
|||
switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool);
|
||||
switch_mutex_init(&profile->flag_mutex, SWITCH_MUTEX_NESTED, profile->pool);
|
||||
|
||||
switch_mutex_init(&profile->device_name_lock_mutex, SWITCH_MUTEX_NESTED, profile->pool);
|
||||
|
||||
for (param = switch_xml_child(xsettings, "param"); param; param = param->next) {
|
||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||
|
@ -2233,6 +2318,8 @@ static switch_status_t load_skinny_config(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Device Name Locks */
|
||||
switch_core_hash_init(&profile->device_name_lock_hash);
|
||||
|
||||
/* Device types */
|
||||
switch_core_hash_init(&profile->device_type_params_hash);
|
||||
|
|
|
@ -127,6 +127,9 @@ struct skinny_profile {
|
|||
int non_blocking;
|
||||
switch_hash_t *soft_key_set_sets_hash;
|
||||
switch_hash_t *device_type_params_hash;
|
||||
/* lock on device names for multiple connection handling */
|
||||
switch_mutex_t *device_name_lock_mutex;
|
||||
switch_hash_t *device_name_lock_hash;
|
||||
/* extensions */
|
||||
char *ext_voicemail;
|
||||
char *ext_redial;
|
||||
|
@ -169,6 +172,23 @@ typedef enum {
|
|||
SKINNY_ACTION_WAIT
|
||||
} skinny_action_t;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* DEVICE NAME LOCK TYPES */
|
||||
/*****************************************************************************/
|
||||
typedef enum {
|
||||
DNLFLAG_INUSE = (1 << 0),
|
||||
} device_name_lock_flag_t;
|
||||
|
||||
struct device_name_lock {
|
||||
char device_name[16];
|
||||
switch_mutex_t *flag_mutex;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
typedef struct device_name_lock device_name_lock_t;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* LISTENERS TYPES */
|
||||
/*****************************************************************************/
|
||||
|
@ -197,6 +217,7 @@ struct listener {
|
|||
switch_mutex_t *flag_mutex;
|
||||
uint32_t flags;
|
||||
time_t expire_time;
|
||||
time_t connect_time;
|
||||
switch_time_t digit_timeout_time;
|
||||
struct listener *next;
|
||||
char *ext_voicemail;
|
||||
|
@ -301,6 +322,12 @@ switch_status_t keepalive_listener(listener_t *listener, void *pvt);
|
|||
void skinny_clean_listener_from_db(listener_t *listener);
|
||||
void skinny_clean_device_from_db(listener_t *listener, char *device_name);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* DEVICE NAME LOCK FUNCTIONS */
|
||||
/*****************************************************************************/
|
||||
void skinny_lock_device_name(listener_t *listener, char *device_name);
|
||||
void skinny_unlock_device_name(listener_t *listener, char *device_name);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CHANNEL FUNCTIONS */
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -1113,12 +1113,17 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r
|
|||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "action", "skinny-auth");
|
||||
|
||||
/* clean up all traces before adding to database */
|
||||
skinny_lock_device_name(listener, request->data.reg.device_name);
|
||||
skinny_clean_device_from_db(listener, request->data.reg.device_name);
|
||||
|
||||
if (switch_xml_locate_user("id", request->data.reg.device_name, profile->domain, "", &xroot, &xdomain, &xuser, &xgroup, params) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Can't find device [%s@%s]\n"
|
||||
"You must define a domain called '%s' in your directory and add a user with id=\"%s\".\n"
|
||||
, request->data.reg.device_name, profile->domain, profile->domain, request->data.reg.device_name);
|
||||
|
||||
/* unlock before trying to send response in case socket blocks */
|
||||
skinny_unlock_device_name(listener, request->data.reg.device_name);
|
||||
|
||||
send_register_reject(listener, "Device not found");
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
goto end;
|
||||
|
@ -1135,6 +1140,10 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r
|
|||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Device %s:%d is already registered on another listener.\n",
|
||||
request->data.reg.device_name, request->data.reg.instance);
|
||||
|
||||
/* unlock before trying to send response in case socket blocks */
|
||||
skinny_unlock_device_name(listener, request->data.reg.device_name);
|
||||
|
||||
send_register_reject(listener, "Device is already registered on another listener");
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
goto end;
|
||||
|
@ -1156,11 +1165,12 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r
|
|||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
|
||||
switch_copy_string(listener->device_name, request->data.reg.device_name, 16);
|
||||
listener->device_instance = request->data.reg.instance;
|
||||
listener->device_type = request->data.reg.device_type;
|
||||
|
||||
skinny_unlock_device_name(listener, request->data.reg.device_name);
|
||||
|
||||
xskinny = switch_xml_child(xuser, "skinny");
|
||||
if (xskinny) {
|
||||
if ((xparams = switch_xml_child(xskinny, "params"))) {
|
||||
|
|
|
@ -72,6 +72,7 @@ static switch_status_t sofia_kill_channel(switch_core_session_t *session, int si
|
|||
*/
|
||||
static switch_status_t sofia_on_init(switch_core_session_t *session)
|
||||
{
|
||||
const char *hval = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
@ -89,6 +90,23 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
|
|||
switch_core_media_absorb_sdp(session);
|
||||
}
|
||||
|
||||
if ((hval = switch_channel_get_variable(channel, "sip_watch_headers"))) {
|
||||
char *dupvar = NULL;
|
||||
char *watch_headers[10];
|
||||
unsigned int numhdrs = 0;
|
||||
int i = 0;
|
||||
dupvar = switch_core_session_strdup(session, hval);
|
||||
numhdrs = switch_separate_string(dupvar, ',', watch_headers, switch_arraylen(watch_headers));
|
||||
if (numhdrs) {
|
||||
char **wheaders = switch_core_session_alloc(session, ((numhdrs+1) * sizeof(wheaders[0])));
|
||||
for (i = 0; i < numhdrs; i++) {
|
||||
wheaders[i] = watch_headers[i];
|
||||
}
|
||||
wheaders[i] = NULL;
|
||||
tech_pvt->watch_headers = wheaders;
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING) || switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE)) {
|
||||
sofia_set_flag(tech_pvt, TFLAG_RECOVERED);
|
||||
}
|
||||
|
@ -2658,9 +2676,15 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
|
|||
stream->write_function(stream, "Dialplan \t%s\n", switch_str_nil(profile->dialplan));
|
||||
stream->write_function(stream, "Context \t%s\n", switch_str_nil(profile->context));
|
||||
stream->write_function(stream, "Challenge Realm \t%s\n", zstr(profile->challenge_realm) ? "auto_to" : profile->challenge_realm);
|
||||
|
||||
for (x = 0; x < profile->rtpip_index; x++) {
|
||||
stream->write_function(stream, "RTP-IP \t%s\n", switch_str_nil(profile->rtpip[x]));
|
||||
}
|
||||
|
||||
for (x = 0; x < profile->rtpip_index6; x++) {
|
||||
stream->write_function(stream, "RTP-IP \t%s\n", switch_str_nil(profile->rtpip6[x]));
|
||||
}
|
||||
|
||||
if (profile->extrtpip) {
|
||||
stream->write_function(stream, "Ext-RTP-IP \t%s\n", profile->extrtpip);
|
||||
}
|
||||
|
@ -2962,6 +2986,9 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl
|
|||
for (x = 0; x < profile->rtpip_index; x++) {
|
||||
stream->write_function(stream, " <rtp-ip>%s</rtp-ip>\n", switch_str_nil(profile->rtpip[x]));
|
||||
}
|
||||
for (x = 0; x < profile->rtpip_index6; x++) {
|
||||
stream->write_function(stream, " <rtp-ip>%s</rtp-ip>\n", switch_str_nil(profile->rtpip6[x]));
|
||||
}
|
||||
if (profile->extrtpip) {
|
||||
stream->write_function(stream, " <ext-rtp-ip>%s</ext-rtp-ip>\n", profile->extrtpip);
|
||||
}
|
||||
|
@ -5449,7 +5476,7 @@ static void general_event_handler(switch_event_t *event)
|
|||
}
|
||||
|
||||
if (!strcmp(profile->rtpip[x], old_ip6)) {
|
||||
profile->rtpip[x] = switch_core_strdup(profile->pool, new_ip6);
|
||||
profile->rtpip6[x] = switch_core_strdup(profile->pool, new_ip6);
|
||||
rb++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ typedef struct private_object private_object_t;
|
|||
#define MY_EVENT_RECOVERY_RECOVERED "sofia::recovery_recovered"
|
||||
#define MY_EVENT_ERROR "sofia::error"
|
||||
#define MY_EVENT_PROFILE_START "sofia::profile_start"
|
||||
#define MY_EVENT_NOTIFY_WATCHED_HEADER "sofia::notify_watched_header"
|
||||
|
||||
#define MULTICAST_EVENT "multicast::event"
|
||||
#define SOFIA_REPLACES_HEADER "_sofia_replaces_"
|
||||
|
@ -574,11 +575,14 @@ struct sofia_profile {
|
|||
char *shutdown_type;
|
||||
char *extrtpip;
|
||||
char *rtpip[MAX_RTPIP];
|
||||
char *rtpip6[MAX_RTPIP];
|
||||
char *jb_msec;
|
||||
switch_payload_t te;
|
||||
switch_payload_t recv_te;
|
||||
uint32_t rtpip_index;
|
||||
uint32_t rtpip_next;
|
||||
uint32_t rtpip_index6;
|
||||
uint32_t rtpip_next6;
|
||||
char *rtcp_audio_interval_msec;
|
||||
char *rtcp_video_interval_msec;
|
||||
|
||||
|
@ -805,6 +809,7 @@ struct private_object {
|
|||
sofia_cid_type_t cid_type;
|
||||
uint32_t session_timeout;
|
||||
enum nua_session_refresher session_refresher;
|
||||
char **watch_headers;
|
||||
char *respond_phrase;
|
||||
int respond_code;
|
||||
char *respond_dest;
|
||||
|
|
|
@ -1136,6 +1136,7 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
|
|||
}
|
||||
|
||||
if (!fs) {
|
||||
sip_remote_party_id_t *rpid;
|
||||
if ((passerted = sip_p_asserted_identity(sip))) {
|
||||
if (passerted->paid_url->url_user) {
|
||||
number = passerted->paid_url->url_user;
|
||||
|
@ -1151,6 +1152,21 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
|
|||
end_of(name) = '\0';
|
||||
}
|
||||
}
|
||||
} else if ((rpid = sip_remote_party_id(sip))) {
|
||||
if (rpid->rpid_url->url_user) {
|
||||
number = rpid->rpid_url->url_user;
|
||||
}
|
||||
if (!zstr(rpid->rpid_display)) {
|
||||
dup = strdup(rpid->rpid_display);
|
||||
if (*dup == '"') {
|
||||
name = dup + 1;
|
||||
} else {
|
||||
name = dup;
|
||||
}
|
||||
if (end_of(name) == '"') {
|
||||
end_of(name) = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1256,6 +1272,21 @@ static void tech_send_ack(nua_handle_t *nh, private_object_t *tech_pvt)
|
|||
|
||||
}
|
||||
|
||||
static void notify_watched_header(switch_core_session_t *session, const char *msgline, const char *hdrname, const char *hdrval)
|
||||
{
|
||||
switch_event_t *event = NULL;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Found known watched header in message '%s', %s: %s\n", msgline, hdrname, hdrval);
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_NOTIFY_WATCHED_HEADER) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Message", msgline);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Header-Name", hdrname);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Header-Value", hdrval);
|
||||
switch_channel_event_set_data(channel, event);
|
||||
switch_event_fire(&event);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed creating event of type %s!\n", MY_EVENT_NOTIFY_WATCHED_HEADER);
|
||||
}
|
||||
}
|
||||
|
||||
//sofia_dispatch_event_t *de
|
||||
static void our_sofia_event_callback(nua_event_t event,
|
||||
|
@ -1331,6 +1362,56 @@ static void our_sofia_event_callback(nua_event_t event,
|
|||
}
|
||||
}
|
||||
|
||||
if (session && tech_pvt && tech_pvt->watch_headers && sip) {
|
||||
char msgline[512];
|
||||
int hi;
|
||||
msg_header_t *h = NULL;
|
||||
if (sip->sip_request) {
|
||||
h = (msg_header_t *)sip->sip_request;
|
||||
msg_header_field_e(msgline, sizeof(msgline), h, 0);
|
||||
} else if (sip->sip_status) {
|
||||
h = (msg_header_t *)sip->sip_status;
|
||||
msg_header_field_e(msgline, sizeof(msgline), h, 0);
|
||||
}
|
||||
if (h) {
|
||||
sip_unknown_t *un = NULL;
|
||||
char buf[512];
|
||||
char *c = NULL;
|
||||
|
||||
msgline[sizeof(msgline)-1] = '\0';
|
||||
c = strchr(msgline, '\r');
|
||||
if (c) {
|
||||
*c = '\0';
|
||||
}
|
||||
|
||||
/* Faster (ie hash-based) search here would be nice? ie, make watch_headers a hash? */
|
||||
|
||||
/* Search first in the valid headers */
|
||||
for (h = h->sh_succ; h; h = h->sh_succ) {
|
||||
sip_header_t *sh = (sip_header_t *)h;
|
||||
if (!sh->sh_class->hc_name) {
|
||||
continue;
|
||||
}
|
||||
for (hi = 0; tech_pvt->watch_headers[hi]; hi++) {
|
||||
if (!strcasecmp(tech_pvt->watch_headers[hi], sh->sh_class->hc_name)) {
|
||||
msg_header_field_e(buf, sizeof(buf), h, 0);
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
notify_watched_header(session, msgline, sh->sh_class->hc_name, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Search now in the unknown headers */
|
||||
for (un = sip->sip_unknown; un; un = un->un_next) {
|
||||
for (hi = 0; tech_pvt->watch_headers[hi]; hi++) {
|
||||
if (!strcasecmp(tech_pvt->watch_headers[hi], un->un_name)) {
|
||||
notify_watched_header(session, msgline, un->un_name, un->un_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sofia_test_pflag(profile, PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip && (event < nua_r_set_params || event > nua_r_authenticate)) {
|
||||
sip_authorization_t const *authorization = NULL;
|
||||
|
||||
|
@ -1510,6 +1591,7 @@ static void our_sofia_event_callback(nua_event_t event,
|
|||
sofia_handle_sip_i_info(nua, profile, nh, session, sip, de, tags);
|
||||
break;
|
||||
case nua_i_update:
|
||||
sofia_update_callee_id(session, profile, sip, SWITCH_TRUE);
|
||||
break;
|
||||
case nua_r_update:
|
||||
if (session && tech_pvt && locked) {
|
||||
|
@ -4137,6 +4219,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
|
|||
profile->ob_failed_calls = 0;
|
||||
profile->shutdown_type = "false";
|
||||
profile->rtpip_index = 0;
|
||||
profile->rtpip_index6 = 0;
|
||||
|
||||
if (xprofiledomain) {
|
||||
profile->domain_name = switch_core_strdup(profile->pool, xprofiledomain);
|
||||
|
@ -4635,10 +4718,19 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
|
|||
} else {
|
||||
ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
|
||||
}
|
||||
if (profile->rtpip_index < MAX_RTPIP) {
|
||||
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, ip);
|
||||
|
||||
if (strchr(ip, ':')) {
|
||||
if (profile->rtpip_index < MAX_RTPIP) {
|
||||
profile->rtpip6[profile->rtpip_index6++] = switch_core_strdup(profile->pool, ip);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Max IPs configured for profile %s.\n", profile->name);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Max IPs configured for profile %s.\n", profile->name);
|
||||
if (profile->rtpip_index6 < MAX_RTPIP) {
|
||||
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, ip);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Max IPs configured for profile %s.\n", profile->name);
|
||||
}
|
||||
}
|
||||
} else if (!strcasecmp(var, "sip-ip")) {
|
||||
char *ip = mod_sofia_globals.guess_ip;
|
||||
|
@ -5373,7 +5465,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
|
|||
profile->sipip = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
|
||||
}
|
||||
|
||||
if (!profile->rtpip[0]) {
|
||||
if (!profile->rtpip[0] && !profile->rtpip6[0]) {
|
||||
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
|
||||
}
|
||||
|
||||
|
@ -5406,7 +5498,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
|
|||
profile->sdp_username = switch_core_strdup(profile->pool, "FreeSWITCH");
|
||||
}
|
||||
|
||||
if (!profile->rtpip[0]) {
|
||||
if (!profile->rtpip[0] && !profile->rtpip6[0]) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Setting ip to '127.0.0.1'\n");
|
||||
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, "127.0.0.1");
|
||||
}
|
||||
|
@ -7911,6 +8003,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
|
|||
|
||||
if ((a_session = switch_core_session_locate(br_a))) {
|
||||
const char *moh = profile->hold_music;
|
||||
switch_core_session_t *tmpsess = NULL;
|
||||
switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
|
||||
switch_caller_profile_t *prof = switch_channel_get_caller_profile(channel_b);
|
||||
const char *tmp;
|
||||
|
@ -7941,6 +8034,15 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
|
|||
} else {
|
||||
switch_ivr_session_transfer(a_session, "park", "inline", NULL);
|
||||
}
|
||||
if (switch_true(switch_channel_get_variable(channel_a, "recording_follow_transfer"))) {
|
||||
switch_core_media_bug_transfer_recordings(session, a_session);
|
||||
}
|
||||
if (switch_true(switch_channel_get_variable(channel_b, "recording_follow_transfer")) && (tmpsess = switch_core_session_locate(br_a))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE,
|
||||
"Early transfer detected with no media, moving recording bug to other leg\n");
|
||||
switch_core_media_bug_transfer_recordings(b_session, tmpsess);
|
||||
switch_core_session_rwunlock(tmpsess);
|
||||
}
|
||||
|
||||
switch_core_session_rwunlock(a_session);
|
||||
|
||||
|
@ -8024,6 +8126,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
|
|||
sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
|
||||
switch_channel_set_variable(channel_b, "park_timeout", "2:attended_transfer");
|
||||
switch_channel_set_state(channel_b, CS_PARK);
|
||||
switch_channel_wait_for_state_timeout(channel_b, CS_PARK, 5000);
|
||||
|
||||
} else {
|
||||
if (!br_a && !br_b) {
|
||||
|
|
|
@ -92,9 +92,25 @@ void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t *
|
|||
|
||||
tech_pvt->profile = profile;
|
||||
|
||||
tech_pvt->mparams.rtpip = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next++]);
|
||||
if (profile->rtpip_next >= profile->rtpip_index) {
|
||||
profile->rtpip_next = 0;
|
||||
if (!zstr(profile->rtpip[profile->rtpip_next])) {
|
||||
tech_pvt->mparams.rtpip4 = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next++]);
|
||||
tech_pvt->mparams.rtpip = tech_pvt->mparams.rtpip4;
|
||||
|
||||
if (profile->rtpip_next >= profile->rtpip_index) {
|
||||
profile->rtpip_next = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zstr(profile->rtpip[profile->rtpip_next6])) {
|
||||
tech_pvt->mparams.rtpip6 = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next6++]);
|
||||
|
||||
if (zstr(tech_pvt->mparams.rtpip)) {
|
||||
tech_pvt->mparams.rtpip = tech_pvt->mparams.rtpip6;
|
||||
}
|
||||
|
||||
if (profile->rtpip_next6 >= profile->rtpip_index6) {
|
||||
profile->rtpip_next6 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
profile->inuse++;
|
||||
|
|
|
@ -1252,6 +1252,7 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
|
|||
const char *agent = "unknown";
|
||||
const char *pres_on_reg = NULL;
|
||||
int send_pres = 0;
|
||||
int send_message_query = 0;
|
||||
int is_tls = 0, is_tcp = 0, is_ws = 0, is_wss = 0;
|
||||
char expbuf[35] = "";
|
||||
time_t reg_time = switch_epoch_time_now(NULL);
|
||||
|
@ -1265,6 +1266,7 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
|
|||
char *sw_reg_host;
|
||||
char *token_val = NULL;
|
||||
|
||||
|
||||
if (sofia_private_p) {
|
||||
sofia_private = *sofia_private_p;
|
||||
}
|
||||
|
@ -1761,6 +1763,7 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
|
|||
reg_meta = var;
|
||||
}
|
||||
|
||||
/* associated MWI account */
|
||||
if (v_event && *v_event && (mwi_account = switch_event_get_header(*v_event, "mwi-account"))) {
|
||||
dup_mwi_account = strdup(mwi_account);
|
||||
switch_assert(dup_mwi_account != NULL);
|
||||
|
@ -1774,6 +1777,26 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
|
|||
mwi_host = (char *) reg_host;
|
||||
}
|
||||
|
||||
/* per-profile unsolicited MWI on register */
|
||||
if (sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER)) {
|
||||
send_message_query = 2;
|
||||
} else if (sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER)) {
|
||||
send_message_query = 1;
|
||||
} else {
|
||||
send_message_query = 0;
|
||||
}
|
||||
|
||||
/* per-account unsolicited MWI on register */
|
||||
if (v_event && *v_event && (var = switch_event_get_header(*v_event, "send-message-query-on-register"))) {
|
||||
if (switch_true(var)) {
|
||||
send_message_query = 2;
|
||||
} else if (!strcasecmp(var, "first-only")) {
|
||||
send_message_query = 1;
|
||||
} else {
|
||||
send_message_query = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (regtype != REG_REGISTER) {
|
||||
switch_goto_int(r, 0, end);
|
||||
}
|
||||
|
@ -2027,10 +2050,9 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
|
|||
|
||||
switch_snprintf(exp_param, sizeof(exp_param), "expires=%ld", exptime);
|
||||
sip_contact_add_param(nua_handle_home(nh), sip->sip_contact, exp_param);
|
||||
|
||||
if ((sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER) ||
|
||||
(reg_count == 1 && sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER))) && debounce_ok) {
|
||||
|
||||
|
||||
/* send unsolicited MWI if configured */
|
||||
if (send_message_query == 2 || (reg_count == 1 && send_message_query == 1 && debounce_ok)) {
|
||||
if (switch_event_create(&s_mwi_event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(s_mwi_event, SWITCH_STACK_BOTTOM, "Message-Account", "%s:%s@%s", proto, mwi_user, mwi_host);
|
||||
switch_event_add_header_string(s_mwi_event, SWITCH_STACK_BOTTOM, "VM-Sofia-Profile", profile->name);
|
||||
|
|
|
@ -58,16 +58,29 @@
|
|||
int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, mcast_flag_t flags)
|
||||
{
|
||||
uint32_t one = 1;
|
||||
int family = AF_INET;
|
||||
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(AF_INET, SOCK_DGRAM, 0)) <= 0 ) {
|
||||
return -1;
|
||||
if (strchr(host, ':')) {
|
||||
family = AF_INET6;
|
||||
}
|
||||
|
||||
handle->send_addr.sin_family = AF_INET;
|
||||
handle->send_addr.sin_addr.s_addr = inet_addr(host);
|
||||
handle->send_addr.sin_port = htons(port);
|
||||
if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(family, SOCK_DGRAM, 0)) <= 0 ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (family == AF_INET6) {
|
||||
handle->send_addr6.sin6_family = AF_INET6;
|
||||
handle->send_addr6.sin6_port = htons(port);
|
||||
inet_pton(AF_INET6, host, &(handle->send_addr6.sin6_addr));
|
||||
handle->family = AF_INET6;
|
||||
} else {
|
||||
handle->send_addr.sin_family = AF_INET;
|
||||
handle->send_addr.sin_addr.s_addr = inet_addr(host);
|
||||
handle->send_addr.sin_port = htons(port);
|
||||
handle->family = AF_INET;
|
||||
}
|
||||
|
||||
if ( setsockopt(handle->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) != 0 ) {
|
||||
close(handle->sock);
|
||||
|
@ -76,28 +89,61 @@ int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle,
|
|||
|
||||
|
||||
if ((flags & MCAST_RECV)) {
|
||||
struct ip_mreq mreq;
|
||||
if (handle->family == AF_INET) {
|
||||
struct ip_mreq mreq;
|
||||
|
||||
handle->recv_addr.sin_family = AF_INET;
|
||||
handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
handle->recv_addr.sin_port = htons(port);
|
||||
|
||||
handle->recv_addr.sin_family = AF_INET;
|
||||
handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
handle->recv_addr.sin_port = htons(port);
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(host);
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(host);
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
|
||||
close(handle->sock);
|
||||
handle->sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
|
||||
close(handle->sock);
|
||||
handle->sock = -1;
|
||||
return -1;
|
||||
if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) {
|
||||
close(handle->sock);
|
||||
handle->sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
struct ipv6_mreq mreq;
|
||||
struct addrinfo addr_criteria;
|
||||
struct addrinfo *mcast_addr;
|
||||
char service[80] = "";
|
||||
|
||||
memset(&addr_criteria, 0, sizeof(addr_criteria));
|
||||
addr_criteria.ai_family = AF_UNSPEC;
|
||||
addr_criteria.ai_socktype = SOCK_DGRAM;
|
||||
addr_criteria.ai_protocol = IPPROTO_UDP;
|
||||
addr_criteria.ai_flags |= AI_NUMERICHOST;
|
||||
|
||||
snprintf(service, sizeof(service), "%d", port);
|
||||
getaddrinfo(host, service, &addr_criteria, &mcast_addr);
|
||||
|
||||
|
||||
memset(&handle->recv_addr6, 0, sizeof(handle->recv_addr6));
|
||||
handle->recv_addr6.sin6_family = AF_INET6;
|
||||
handle->recv_addr6.sin6_port = htons(port);
|
||||
inet_pton(AF_INET6, "::0", &(handle->recv_addr6.sin6_addr));
|
||||
|
||||
memcpy(&mreq.ipv6mr_multiaddr, &((struct sockaddr_in6 *)mcast_addr->ai_addr)->sin6_addr, sizeof(struct in6_addr));
|
||||
|
||||
mreq.ipv6mr_interface = 0;
|
||||
setsockopt(handle->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
|
||||
|
||||
if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr6, sizeof(handle->recv_addr6)) < 0) {
|
||||
printf("FUCK (%s) %s\n", host, strerror(errno));
|
||||
close(handle->sock);
|
||||
handle->sock = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) {
|
||||
close(handle->sock);
|
||||
handle->sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
handle->ttl = 1;
|
||||
|
@ -155,7 +201,11 @@ ssize_t mcast_socket_send(mcast_handle_t *handle, void *data, size_t datalen)
|
|||
datalen = sizeof(handle->buffer);
|
||||
}
|
||||
|
||||
return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr));
|
||||
if (handle->family == AF_INET6) {
|
||||
return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr6, sizeof(handle->send_addr6));
|
||||
} else {
|
||||
return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr));
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, int ms)
|
||||
|
@ -175,6 +225,9 @@ ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, in
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen);
|
||||
if (handle->family == AF_INET6) {
|
||||
return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr6, &addrlen);
|
||||
} else {
|
||||
return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,9 @@ typedef struct {
|
|||
unsigned char ttl;
|
||||
struct sockaddr_in send_addr;
|
||||
struct sockaddr_in recv_addr;
|
||||
struct sockaddr_in6 send_addr6;
|
||||
struct sockaddr_in6 recv_addr6;
|
||||
int family;
|
||||
unsigned char buffer[65536];
|
||||
int ready;
|
||||
} mcast_handle_t;
|
||||
|
|
|
@ -143,7 +143,7 @@ static void verto_deinit_ssl(verto_profile_t *profile)
|
|||
|
||||
static void close_file(ws_socket_t *sock)
|
||||
{
|
||||
if (*sock > -1) {
|
||||
if (*sock != ws_sock_invalid) {
|
||||
#ifndef WIN32
|
||||
close(*sock);
|
||||
#else
|
||||
|
@ -155,7 +155,7 @@ static void close_file(ws_socket_t *sock)
|
|||
|
||||
static void close_socket(ws_socket_t *sock)
|
||||
{
|
||||
if (*sock > -1) {
|
||||
if (*sock != ws_sock_invalid) {
|
||||
shutdown(*sock, 2);
|
||||
close_file(sock);
|
||||
}
|
||||
|
@ -1803,12 +1803,6 @@ error:
|
|||
|
||||
static void client_run(jsock_t *jsock)
|
||||
{
|
||||
|
||||
jsock->local_addr.sin_family = AF_INET;
|
||||
jsock->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
jsock->local_addr.sin_port = 0;
|
||||
|
||||
|
||||
if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1, !!jsock->profile->vhosts) < 0) {
|
||||
if (jsock->profile->vhosts) {
|
||||
http_run(jsock);
|
||||
|
@ -1920,7 +1914,7 @@ static void *SWITCH_THREAD_FUNC client_thread(switch_thread_t *thread, void *obj
|
|||
switch_event_destroy(&jsock->vars);
|
||||
switch_event_destroy(&jsock->user_vars);
|
||||
|
||||
if (jsock->client_socket > -1) {
|
||||
if (jsock->client_socket != ws_sock_invalid) {
|
||||
close_socket(&jsock->client_socket);
|
||||
}
|
||||
|
||||
|
@ -2259,10 +2253,30 @@ static void verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *prof
|
|||
{
|
||||
uint32_t i;
|
||||
|
||||
tech_pvt->mparams->rtpip = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]);
|
||||
if (!zstr(profile->rtpip[profile->rtpip_cur])) {
|
||||
tech_pvt->mparams->rtpip4 = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]);
|
||||
tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip4;
|
||||
if (profile->rtpip_cur == profile->rtpip_index) {
|
||||
profile->rtpip_cur = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (profile->rtpip_cur == profile->rtpip_index) {
|
||||
profile->rtpip_cur = 0;
|
||||
if (!zstr(profile->rtpip6[profile->rtpip_cur6])) {
|
||||
tech_pvt->mparams->rtpip6 = switch_core_session_strdup(tech_pvt->session, profile->rtpip6[profile->rtpip_cur6++]);
|
||||
|
||||
if (zstr(tech_pvt->mparams->rtpip)) {
|
||||
tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip6;
|
||||
}
|
||||
|
||||
if (profile->rtpip_cur6 == profile->rtpip_index6) {
|
||||
profile->rtpip_cur6 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (zstr(tech_pvt->mparams->rtpip)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "%s has no media ip, check your configuration\n",
|
||||
switch_channel_get_name(tech_pvt->channel));
|
||||
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
|
||||
}
|
||||
|
||||
tech_pvt->mparams->extrtpip = tech_pvt->mparams->extsipip = profile->extrtpip;
|
||||
|
@ -3376,7 +3390,7 @@ static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock
|
|||
switch_either(jsock->dialplan, jsock->profile->dialplan),
|
||||
caller_id_name,
|
||||
caller_id_number,
|
||||
inet_ntoa(jsock->remote_addr.sin_addr),
|
||||
jsock->remote_host,
|
||||
cJSON_GetObjectCstr(dialog, "ani"),
|
||||
cJSON_GetObjectCstr(dialog, "aniii"),
|
||||
cJSON_GetObjectCstr(dialog, "rdnis"),
|
||||
|
@ -3641,7 +3655,7 @@ static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, js
|
|||
jevent = cJSON_Duplicate(params, 1);
|
||||
switch_event_channel_broadcast(event_channel, &jevent, modname, globals.event_channel_id);
|
||||
|
||||
if (jsock->profile->mcast_pub.sock > -1) {
|
||||
if (jsock->profile->mcast_pub.sock != ws_sock_invalid) {
|
||||
if ((json_text = cJSON_PrintUnformatted(params))) {
|
||||
|
||||
if ( mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1) < 0 ) {
|
||||
|
@ -3778,7 +3792,7 @@ static void jrpc_init(void)
|
|||
|
||||
|
||||
|
||||
static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
|
||||
static int start_jsock(verto_profile_t *profile, ws_socket_t sock, int family)
|
||||
{
|
||||
jsock_t *jsock = NULL;
|
||||
int flag = 1;
|
||||
|
@ -3798,11 +3812,20 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
|
|||
|
||||
jsock = (jsock_t *) switch_core_alloc(pool, sizeof(*jsock));
|
||||
jsock->pool = pool;
|
||||
jsock->family = family;
|
||||
|
||||
len = sizeof(jsock->remote_addr);
|
||||
if (family == PF_INET) {
|
||||
len = sizeof(jsock->remote_addr);
|
||||
|
||||
if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) {
|
||||
die("ACCEPT FAILED\n");
|
||||
if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) {
|
||||
die("ACCEPT FAILED\n");
|
||||
}
|
||||
} else {
|
||||
len = sizeof(jsock->remote_addr6);
|
||||
|
||||
if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr6, &len)) < 0) {
|
||||
die("ACCEPT FAILED\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < profile->i; i++) {
|
||||
|
@ -3818,7 +3841,15 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
|
|||
jsock->profile = profile;
|
||||
|
||||
if (zstr(jsock->name)) {
|
||||
jsock->name = switch_core_sprintf(pool, "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port));
|
||||
if (family == PF_INET) {
|
||||
jsock->remote_port = ntohs(jsock->remote_addr.sin_port);
|
||||
inet_ntop(AF_INET, &jsock->remote_addr.sin_addr, jsock->remote_host, sizeof(jsock->remote_host));
|
||||
jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port);
|
||||
} else {
|
||||
jsock->remote_port = ntohs(jsock->remote_addr6.sin6_port);
|
||||
inet_ntop(AF_INET6, &jsock->remote_addr6.sin6_addr, jsock->remote_host, sizeof(jsock->remote_host));
|
||||
jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port);
|
||||
}
|
||||
}
|
||||
|
||||
jsock->ptype = ptype;
|
||||
|
@ -3826,7 +3857,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
|
|||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Client Connect.\n", jsock->name);
|
||||
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_CLIENT_CONNECT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_profile_name", profile->name);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port));
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s:%d", jsock->remote_host, jsock->remote_port);
|
||||
switch_event_fire(&s_event);
|
||||
}
|
||||
|
||||
|
@ -3863,7 +3894,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
|
|||
error:
|
||||
|
||||
if (jsock) {
|
||||
if (jsock->client_socket > -1) {
|
||||
if (jsock->client_socket != ws_sock_invalid) {
|
||||
close_socket(&jsock->client_socket);
|
||||
}
|
||||
|
||||
|
@ -3873,7 +3904,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static ws_socket_t prepare_socket(int ip, uint16_t port)
|
||||
static ws_socket_t prepare_socket(ips_t *ips)
|
||||
{
|
||||
ws_socket_t sock = ws_sock_invalid;
|
||||
#ifndef WIN32
|
||||
|
@ -3881,29 +3912,48 @@ static ws_socket_t prepare_socket(int ip, uint16_t port)
|
|||
#else
|
||||
char reuse_addr = 1;
|
||||
#endif
|
||||
int family;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_in6 addr6;
|
||||
|
||||
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
||||
if (strchr(ips->local_ip, ':')) {
|
||||
family = PF_INET6;
|
||||
} else {
|
||||
family = PF_INET;
|
||||
}
|
||||
|
||||
if ((sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
||||
die("Socket Error!\n");
|
||||
}
|
||||
|
||||
if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) {
|
||||
die("Socket setsockopt Error!\n");
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = ip;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
die("Bind Error!\n");
|
||||
}
|
||||
|
||||
if (family == PF_INET) {
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr(ips->local_ip);
|
||||
addr.sin_port = htons(ips->local_port);
|
||||
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
die("Bind Error!\n");
|
||||
}
|
||||
} else {
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(ips->local_port);
|
||||
inet_pton(AF_INET6, ips->local_ip, &(addr6.sin6_addr));
|
||||
if (bind(sock, (struct sockaddr *) &addr6, sizeof(addr6)) < 0) {
|
||||
die("Bind Error!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (listen(sock, MAXPENDING) < 0) {
|
||||
die("Listen error\n");
|
||||
}
|
||||
|
||||
ips->family = family;
|
||||
|
||||
return sock;
|
||||
|
||||
error:
|
||||
|
@ -3915,7 +3965,13 @@ static ws_socket_t prepare_socket(int ip, uint16_t port)
|
|||
|
||||
static void handle_mcast_sub(verto_profile_t *profile)
|
||||
{
|
||||
int bytes = mcast_socket_recv(&profile->mcast_sub, NULL, 0, 0);
|
||||
int bytes;
|
||||
|
||||
if (profile->mcast_sub.sock == ws_sock_invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
bytes = mcast_socket_recv(&profile->mcast_sub, NULL, 0, 0);
|
||||
|
||||
if (bytes > 0) {
|
||||
cJSON *json;
|
||||
|
@ -3979,7 +4035,7 @@ static int profile_one_loop(verto_profile_t *profile)
|
|||
if (profile->mcast_ip && pfds[x].sock == (switch_os_socket_t)profile->mcast_sub.sock) {
|
||||
handle_mcast_sub(profile);
|
||||
} else {
|
||||
start_jsock(profile, pfds[x].sock);
|
||||
start_jsock(profile, pfds[x].sock, profile->ip[x].family);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3991,52 +4047,6 @@ static int profile_one_loop(verto_profile_t *profile)
|
|||
}
|
||||
|
||||
|
||||
static int runtime(verto_profile_t *profile)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < profile->i; i++) {
|
||||
if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) {
|
||||
die("Client Socket Error!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (profile->mcast_ip) {
|
||||
if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) {
|
||||
die("mcast recv socket create");
|
||||
}
|
||||
|
||||
if (mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) {
|
||||
mcast_socket_close(&profile->mcast_sub);
|
||||
die("mcast send socket create");
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1);
|
||||
}
|
||||
|
||||
|
||||
while(profile->running) {
|
||||
if (profile_one_loop(profile) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (profile->mcast_sub.sock > -1) {
|
||||
mcast_socket_close(&profile->mcast_sub);
|
||||
}
|
||||
|
||||
if (profile->mcast_pub.sock > -1) {
|
||||
mcast_socket_close(&profile->mcast_pub);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static void kill_profile(verto_profile_t *profile)
|
||||
{
|
||||
jsock_t *p;
|
||||
|
@ -4092,6 +4102,67 @@ static void kill_profiles(void)
|
|||
}
|
||||
|
||||
|
||||
static int runtime(verto_profile_t *profile)
|
||||
{
|
||||
int i;
|
||||
int r = 0;
|
||||
int listeners = 0;
|
||||
|
||||
for (i = 0; i < profile->i; i++) {
|
||||
//if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) {
|
||||
if ((profile->server_socket[i] = prepare_socket(&profile->ip[i])) != ws_sock_invalid) {
|
||||
listeners++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!listeners) {
|
||||
die("Client Socket Error! No Listeners!\n");
|
||||
}
|
||||
|
||||
if (profile->mcast_ip) {
|
||||
int ok = 1;
|
||||
|
||||
if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) {
|
||||
ok++;
|
||||
}
|
||||
|
||||
if (ok && mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) {
|
||||
mcast_socket_close(&profile->mcast_sub);
|
||||
ok = 0;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Disabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while(profile->running) {
|
||||
if (profile_one_loop(profile) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
if (profile->mcast_sub.sock != ws_sock_invalid) {
|
||||
mcast_socket_close(&profile->mcast_sub);
|
||||
}
|
||||
|
||||
if (profile->mcast_pub.sock != ws_sock_invalid) {
|
||||
mcast_socket_close(&profile->mcast_pub);
|
||||
}
|
||||
|
||||
if (r) {
|
||||
kill_profile(profile);
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
static void do_shutdown(void)
|
||||
{
|
||||
globals.running = 0;
|
||||
|
@ -4105,20 +4176,35 @@ static void do_shutdown(void)
|
|||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Done\n");
|
||||
}
|
||||
|
||||
static void parse_ip(char *host, uint16_t *port, in_addr_t *addr, char *input)
|
||||
|
||||
static void parse_ip(char *host, switch_size_t host_len, uint16_t *port, char *input)
|
||||
{
|
||||
char *p;
|
||||
struct hostent *hent;
|
||||
//struct hostent *hent;
|
||||
|
||||
strncpy(host, input, 255);
|
||||
|
||||
host[255] = 0;
|
||||
|
||||
if ((p = strchr(host, ':')) != NULL) {
|
||||
*p++ = '\0';
|
||||
*port = (uint16_t)atoi(p);
|
||||
if ((p = strchr(input, '['))) {
|
||||
char *end = switch_find_end_paren(p, '[', ']');
|
||||
if (end) {
|
||||
p++;
|
||||
strncpy(host, p, end - p);
|
||||
if (*(end+1) == ':' && end + 2 < end_of_p(input)) {
|
||||
end += 2;
|
||||
if (end) {
|
||||
*port = (uint16_t)atoi(end);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
strncpy(host, "::", host_len);
|
||||
}
|
||||
} else {
|
||||
strncpy(host, input, host_len);
|
||||
if ((p = strrchr(host, ':')) != NULL) {
|
||||
*p++ = '\0';
|
||||
*port = (uint16_t)atoi(p);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ( host[0] < '0' || host[0] > '9' ) {
|
||||
// Non-numeric host (at least it doesn't start with one). Convert it to ip addr first
|
||||
if ((hent = gethostbyname(host)) != NULL) {
|
||||
|
@ -4130,8 +4216,10 @@ static void parse_ip(char *host, uint16_t *port, in_addr_t *addr, char *input)
|
|||
} else {
|
||||
*addr = inet_addr(host);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static verto_profile_t *find_profile(const char *name)
|
||||
{
|
||||
verto_profile_t *p, *r = NULL;
|
||||
|
@ -4264,7 +4352,7 @@ static switch_status_t parse_config(const char *cf)
|
|||
if (!strcasecmp(var, "bind-local")) {
|
||||
const char *secure = switch_xml_attr_soft(param, "secure");
|
||||
if (i < MAX_BIND) {
|
||||
parse_ip(profile->ip[profile->i].local_ip, &profile->ip[profile->i].local_port, &profile->ip[profile->i].local_ip_addr, val);
|
||||
parse_ip(profile->ip[profile->i].local_ip, sizeof(profile->ip[profile->i].local_ip), &profile->ip[profile->i].local_port, val);
|
||||
if (switch_true(secure)) {
|
||||
profile->ip[profile->i].secure = 1;
|
||||
}
|
||||
|
@ -4316,10 +4404,18 @@ static switch_status_t parse_config(const char *cf)
|
|||
if (zstr(val)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid RTP IP.\n");
|
||||
} else {
|
||||
if (profile->rtpip_index < MAX_RTPIP -1) {
|
||||
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val);
|
||||
if (strchr(val, ':')) {
|
||||
if (profile->rtpip_index6 < MAX_RTPIP -1) {
|
||||
profile->rtpip6[profile->rtpip_index6++] = switch_core_strdup(profile->pool, val);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
|
||||
if (profile->rtpip_index < MAX_RTPIP -1) {
|
||||
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!strcasecmp(var, "ext-rtp-ip")) {
|
||||
|
|
|
@ -106,9 +106,8 @@ struct jsock_s {
|
|||
unsigned char buf[65535];
|
||||
char *name;
|
||||
jsock_type_t ptype;
|
||||
struct sockaddr_in local_addr;
|
||||
struct sockaddr_in remote_addr;
|
||||
struct sockaddr_in send_addr;
|
||||
struct sockaddr_in6 remote_addr6;
|
||||
#ifndef WIN32
|
||||
struct passwd pw;
|
||||
#endif
|
||||
|
@ -132,6 +131,11 @@ struct jsock_s {
|
|||
char *dialplan;
|
||||
char *context;
|
||||
|
||||
|
||||
char remote_host[256];
|
||||
int remote_port;
|
||||
int family;
|
||||
|
||||
struct verto_profile_s *profile;
|
||||
switch_thread_rwlock_t *rwlock;
|
||||
|
||||
|
@ -155,12 +159,12 @@ typedef struct jsock_s jsock_t;
|
|||
#define MAX_BIND 25
|
||||
#define MAX_RTPIP 25
|
||||
|
||||
struct ips {
|
||||
typedef struct ips {
|
||||
char local_ip[256];
|
||||
in_addr_t local_ip_addr;
|
||||
uint16_t local_port;
|
||||
int secure;
|
||||
};
|
||||
int family;
|
||||
} ips_t;
|
||||
|
||||
typedef enum {
|
||||
TFLAG_SENT_MEDIA = (1 << 0),
|
||||
|
@ -240,6 +244,10 @@ struct verto_profile_s {
|
|||
int rtpip_index;
|
||||
int rtpip_cur;
|
||||
|
||||
char *rtpip6[MAX_RTPIP];
|
||||
int rtpip_index6;
|
||||
int rtpip_cur6;
|
||||
|
||||
char *cand_acl[SWITCH_MAX_CAND_ACL];
|
||||
uint32_t cand_acl_count;
|
||||
|
||||
|
|
|
@ -691,6 +691,7 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
|||
ssize_t need = 2;
|
||||
char *maskp;
|
||||
int ll = 0;
|
||||
int frag = 0;
|
||||
|
||||
again:
|
||||
need = 2;
|
||||
|
@ -741,8 +742,16 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
|||
case WSOC_PING:
|
||||
case WSOC_PONG:
|
||||
{
|
||||
//int fin = (wsh->buffer[0] >> 7) & 1;
|
||||
int fin = (wsh->buffer[0] >> 7) & 1;
|
||||
int mask = (wsh->buffer[1] >> 7) & 1;
|
||||
|
||||
if (fin) {
|
||||
if (*oc == WSOC_CONTINUATION) {
|
||||
frag = 1;
|
||||
} else {
|
||||
frag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask) {
|
||||
need += 4;
|
||||
|
@ -837,6 +846,10 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
|||
ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (frag) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
|
||||
*(wsh->payload+wsh->rplen) = '\0';
|
||||
|
|
|
@ -757,7 +757,10 @@ static switch_status_t check_attached_sessions(listener_t *listener, int *msgs_s
|
|||
sp->uuid_str, switch_channel_state_name(sp->channel_state));
|
||||
|
||||
ei_x_new_with_version(&ebuf);
|
||||
ei_x_encode_tuple_header(&ebuf, 2);
|
||||
ei_x_encode_atom(&ebuf, "call_hangup");
|
||||
_ei_x_encode_string(&ebuf, sp->uuid_str);
|
||||
|
||||
switch_mutex_lock(listener->sock_mutex);
|
||||
ei_sendto(listener->ec, listener->sockfd, &sp->process, &ebuf);
|
||||
(*msgs_sent)++;
|
||||
|
|
|
@ -401,8 +401,12 @@ SWITCH_STANDARD_APP(socket_function)
|
|||
listener_t *listener;
|
||||
int argc = 0, x = 0;
|
||||
char *argv[80] = { 0 };
|
||||
char *hosts[50] = { 0 };
|
||||
unsigned int hosts_count = 0;
|
||||
switch_status_t connected = SWITCH_STATUS_FALSE;
|
||||
char *mydata;
|
||||
switch_channel_t *channel = NULL;
|
||||
char errbuf[512] = {0};
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
|
||||
|
@ -415,47 +419,58 @@ SWITCH_STANDARD_APP(socket_function)
|
|||
return;
|
||||
}
|
||||
|
||||
host = argv[0];
|
||||
hosts_count = switch_split(argv[0], '|', hosts);
|
||||
|
||||
if (zstr(host)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing Host!\n");
|
||||
return;
|
||||
}
|
||||
for(x = 0; x < hosts_count; x++) {
|
||||
host = hosts[x];
|
||||
|
||||
if ((port_name = strrchr(host, ':'))) {
|
||||
*port_name++ = '\0';
|
||||
port = (switch_port_t) atoi(port_name);
|
||||
}
|
||||
if (zstr(host)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing Host!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((path = strchr((port_name ? port_name : host), '/'))) {
|
||||
*path++ = '\0';
|
||||
switch_channel_set_variable(channel, "socket_path", path);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Trying host: %s\n", host);
|
||||
|
||||
switch_channel_set_variable(channel, "socket_host", host);
|
||||
if ((port_name = strrchr(host, ':'))) {
|
||||
*port_name++ = '\0';
|
||||
port = (switch_port_t) atoi(port_name);
|
||||
}
|
||||
|
||||
if (switch_sockaddr_info_get(&sa, host, SWITCH_UNSPEC, port, 0, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
if ((path = strchr((port_name ? port_name : host), '/'))) {
|
||||
*path++ = '\0';
|
||||
switch_channel_set_variable(channel, "socket_path", path);
|
||||
}
|
||||
|
||||
switch_channel_set_variable(channel, "socket_host", host);
|
||||
|
||||
if (switch_sockaddr_info_get(&sa, host, SWITCH_UNSPEC, port, 0, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (switch_socket_create(&new_sock, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, switch_core_session_get_pool(session))
|
||||
!= SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch_socket_opt_set(new_sock, SWITCH_SO_KEEPALIVE, 1);
|
||||
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_NODELAY, 1);
|
||||
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_KEEPIDLE, 30);
|
||||
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_KEEPINTVL, 30);
|
||||
|
||||
if ((connected = switch_socket_connect(new_sock, sa)) == SWITCH_STATUS_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error: %s\n", switch_strerror(errno, errbuf, sizeof(errbuf)));
|
||||
}//end hosts loop
|
||||
|
||||
if (connected != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (switch_socket_create(&new_sock, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, switch_core_session_get_pool(session))
|
||||
!= SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch_socket_opt_set(new_sock, SWITCH_SO_KEEPALIVE, 1);
|
||||
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_NODELAY, 1);
|
||||
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_KEEPIDLE, 30);
|
||||
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_KEEPINTVL, 30);
|
||||
|
||||
if (switch_socket_connect(new_sock, sa) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!(listener = switch_core_session_alloc(session, sizeof(*listener)))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Memory Error\n");
|
||||
return;
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
<param name="mixer-conf-profile" value="sla"/>
|
||||
<!-- if true, to attribute in offer uses URI instead of name/number -->
|
||||
<param name="offer-uri" value="true"/>
|
||||
<!-- how offers are distributed to clients (all, first, random). -->
|
||||
<param name="offer-algorithm" value="all"/>
|
||||
<!-- If offer is not answered after timeout, next client is offered (based on algorithm picked).
|
||||
If no other clients are available, the call is rejected. Set to 0 to disable -->
|
||||
<param name="offer-timeout-ms" value="5000"/>
|
||||
<!-- if true, channel variables are added to rayo client offer -->
|
||||
<param name="add-variables-to-offer" value="false"/>
|
||||
<!-- if true, channel variables are added to offer, ringing, answered, and end events sent to rayo clients -->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2013-2014, Grasshopper
|
||||
* Copyright (C) 2013-2015, Grasshopper
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
|
@ -61,6 +61,10 @@ SWITCH_MODULE_DEFINITION(mod_rayo, mod_rayo_load, mod_rayo_shutdown, mod_rayo_ru
|
|||
#define JOINED_CALL 1
|
||||
#define JOINED_MIXER 2
|
||||
|
||||
#define OFFER_ALL 0
|
||||
#define OFFER_FIRST 1
|
||||
#define OFFER_RANDOM 2
|
||||
|
||||
struct rayo_actor;
|
||||
struct rayo_client;
|
||||
struct rayo_call;
|
||||
|
@ -123,8 +127,12 @@ struct rayo_call {
|
|||
struct rayo_actor base;
|
||||
/** Definitive controlling party JID */
|
||||
char *dcp_jid;
|
||||
/** Potential controlling parties */
|
||||
/** Potential controlling parties (have sent offers to) */
|
||||
switch_hash_t *pcps;
|
||||
/** Available controlling parties (not sent offers to) */
|
||||
switch_hash_t *acps;
|
||||
/** Number of available controlling parties */
|
||||
int num_acps;
|
||||
/** current idle start time */
|
||||
switch_time_t idle_start_time;
|
||||
/** true if fax is in progress */
|
||||
|
@ -223,6 +231,8 @@ static struct {
|
|||
int num_message_threads;
|
||||
/** message delivery queue */
|
||||
switch_queue_t *msg_queue;
|
||||
/** in progress offer queue */
|
||||
switch_queue_t *offer_queue;
|
||||
/** shutdown flag */
|
||||
int shutdown;
|
||||
/** prevents context shutdown until all threads are finished */
|
||||
|
@ -237,6 +247,10 @@ static struct {
|
|||
int add_variables_to_offer;
|
||||
/** if true, channel variables are added to answered, ringing, end events */
|
||||
int add_variables_to_events;
|
||||
/** How to distribute offers to clients */
|
||||
int offer_algorithm;
|
||||
/** How long to wait for offer response before retrying */
|
||||
int offer_timeout_us;
|
||||
} globals;
|
||||
|
||||
/**
|
||||
|
@ -866,12 +880,13 @@ static void start_deliver_message_thread(switch_memory_pool_t *pool)
|
|||
}
|
||||
|
||||
/**
|
||||
* Stop all message threads
|
||||
* Stop all threads
|
||||
*/
|
||||
static void stop_deliver_message_threads(void)
|
||||
static void stop_all_threads(void)
|
||||
{
|
||||
globals.shutdown = 1;
|
||||
switch_queue_interrupt_all(globals.msg_queue);
|
||||
switch_queue_interrupt_all(globals.offer_queue);
|
||||
switch_thread_rwlock_wrlock(globals.shutdown_rwlock);
|
||||
}
|
||||
|
||||
|
@ -1219,6 +1234,7 @@ done:
|
|||
switch_event_destroy(&call->answer_event);
|
||||
}
|
||||
switch_core_hash_destroy(&call->pcps);
|
||||
switch_core_hash_destroy(&call->acps);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1404,6 +1420,8 @@ static struct rayo_call *rayo_call_init(struct rayo_call *call, switch_memory_po
|
|||
call->rayo_app_started = 0;
|
||||
call->answer_event = NULL;
|
||||
switch_core_hash_init(&call->pcps);
|
||||
switch_core_hash_init(&call->acps);
|
||||
call->num_acps = 0;
|
||||
}
|
||||
|
||||
switch_safe_free(call_jid);
|
||||
|
@ -3825,6 +3843,171 @@ static int should_offer_to_client(struct rayo_client *rclient, char **offer_filt
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offered call information
|
||||
*/
|
||||
struct offered_call_info {
|
||||
/** Call JID */
|
||||
char *call_jid;
|
||||
/** Time this offer expires */
|
||||
switch_time_t offer_time;
|
||||
};
|
||||
|
||||
/**
|
||||
* Deliver offer message to next available client(s)
|
||||
*/
|
||||
static int send_offer_to_clients(struct rayo_call *from_call, switch_core_session_t *session)
|
||||
{
|
||||
int i = 0;
|
||||
int selection = 0;
|
||||
int sent = 0;
|
||||
switch_hash_index_t *hi = NULL;
|
||||
iks *offer = NULL;
|
||||
|
||||
if (from_call->num_acps <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (globals.offer_algorithm == OFFER_RANDOM) {
|
||||
/* pick client at (not really) random */
|
||||
selection = rand() % from_call->num_acps;
|
||||
} else if (globals.offer_algorithm == OFFER_FIRST) {
|
||||
/* send to first client */
|
||||
selection = 0;
|
||||
} else {
|
||||
/* send to all clients */
|
||||
selection = -1;
|
||||
}
|
||||
|
||||
for (hi = switch_core_hash_first(from_call->acps); hi; hi = switch_core_hash_next(&hi)) {
|
||||
if (i++ == selection || selection == -1) {
|
||||
const char *to_client_jid = NULL;
|
||||
const void *key;
|
||||
void *val;
|
||||
|
||||
/* get client jid to send to */
|
||||
switch_core_hash_this(hi, &key, NULL, &val);
|
||||
to_client_jid = (const char *)key;
|
||||
switch_assert(to_client_jid);
|
||||
|
||||
/* send offer to client, remembering jid as PCP */
|
||||
if (!offer) {
|
||||
offer = rayo_create_offer(from_call, session);
|
||||
}
|
||||
switch_core_hash_insert(from_call->pcps, to_client_jid, "1");
|
||||
iks_insert_attrib(offer, "to", to_client_jid);
|
||||
RAYO_SEND_MESSAGE_DUP(from_call, to_client_jid, offer);
|
||||
|
||||
/* remove client JID from list of available clients */
|
||||
switch_core_hash_delete(from_call->acps, to_client_jid);
|
||||
from_call->num_acps--;
|
||||
sent = 1;
|
||||
|
||||
if (selection != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_safe_free(hi);
|
||||
|
||||
/* queue offer information */
|
||||
if (globals.offer_timeout_us > 0 && sent) {
|
||||
struct offered_call_info *offered_call;
|
||||
switch_zmalloc(offered_call, sizeof(*offered_call));
|
||||
offered_call->offer_time = switch_micro_time_now();
|
||||
offered_call->call_jid = strdup(RAYO_JID(from_call));
|
||||
if (switch_queue_trypush(globals.offer_queue, offered_call) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Failed to queue offered call info! Offer timeout won't work on this call\n");
|
||||
switch_safe_free(offered_call->call_jid);
|
||||
switch_safe_free(offered_call);
|
||||
}
|
||||
}
|
||||
|
||||
if (offer) {
|
||||
iks_delete(offer);
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread that monitors for timed out offers
|
||||
* @param thread this thread
|
||||
* @param obj unused
|
||||
* @return NULL
|
||||
*/
|
||||
static void *SWITCH_THREAD_FUNC offer_timeout_thread(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
struct offered_call_info *next_offer;
|
||||
switch_thread_rwlock_rdlock(globals.shutdown_rwlock);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "New offer timeout thread\n");
|
||||
while (!globals.shutdown) {
|
||||
if (switch_queue_pop(globals.offer_queue, (void *)&next_offer) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_time_t now = switch_micro_time_now();
|
||||
switch_time_t offer_timeout = next_offer->offer_time + globals.offer_timeout_us;
|
||||
|
||||
/* wait for timeout */
|
||||
while (offer_timeout > now && !globals.shutdown) {
|
||||
switch_time_t remain = offer_timeout - now;
|
||||
remain = remain > 500000 ? 500000 : remain;
|
||||
switch_sleep(remain);
|
||||
now = switch_micro_time_now();
|
||||
}
|
||||
|
||||
/* check if offer was accepted - it is accepted if the call has a DCP (definitive controlling party) */
|
||||
if (!globals.shutdown) {
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE(next_offer->call_jid);
|
||||
if (call) {
|
||||
switch_mutex_lock(RAYO_ACTOR(call)->mutex);
|
||||
if (zstr(rayo_call_get_dcp_jid(call))) {
|
||||
switch_core_session_t *session = switch_core_session_locate(rayo_call_get_uuid(call));
|
||||
if (session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, offer timeout\n", RAYO_JID(call));
|
||||
if (!send_offer_to_clients(call, session)) {
|
||||
/* nobody to offer to, end call */
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, no more clients to offer, ending call\n", RAYO_JID(call));
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
|
||||
}
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
|
||||
RAYO_RELEASE(call);
|
||||
}
|
||||
}
|
||||
|
||||
switch_safe_free(next_offer->call_jid);
|
||||
switch_safe_free(next_offer);
|
||||
}
|
||||
}
|
||||
|
||||
/* clean up queue */
|
||||
while(switch_queue_trypop(globals.offer_queue, (void *)&next_offer) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_safe_free(next_offer->call_jid);
|
||||
switch_safe_free(next_offer);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Offer timeout thread finished\n");
|
||||
switch_thread_rwlock_unlock(globals.shutdown_rwlock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new offer timeout thread
|
||||
* @param pool to use
|
||||
*/
|
||||
static void start_offer_timeout_thread(switch_memory_pool_t *pool)
|
||||
{
|
||||
switch_thread_t *thread;
|
||||
switch_threadattr_t *thd_attr = NULL;
|
||||
switch_threadattr_create(&thd_attr, pool);
|
||||
switch_threadattr_detach_set(thd_attr, 1);
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
switch_thread_create(&thread, thd_attr, offer_timeout_thread, NULL, pool);
|
||||
}
|
||||
|
||||
#define RAYO_USAGE "[client username 1,client username n]"
|
||||
/**
|
||||
* Offer call and park channel
|
||||
|
@ -3874,7 +4057,6 @@ SWITCH_STANDARD_APP(rayo_app)
|
|||
if (!call) {
|
||||
/* offer control */
|
||||
switch_hash_index_t *hi = NULL;
|
||||
iks *offer = NULL;
|
||||
char *clients_to_offer[16] = { 0 };
|
||||
int clients_to_offer_count = 0;
|
||||
|
||||
|
@ -3888,7 +4070,6 @@ SWITCH_STANDARD_APP(rayo_app)
|
|||
|
||||
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_call_jid", RAYO_JID(call));
|
||||
|
||||
offer = rayo_create_offer(call, session);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Offering call for Rayo 3PCC\n");
|
||||
|
||||
if (!zstr(data)) {
|
||||
|
@ -3904,7 +4085,6 @@ SWITCH_STANDARD_APP(rayo_app)
|
|||
}
|
||||
|
||||
/* Offer call to all (or specified) ONLINE clients */
|
||||
/* TODO load balance offers so first session doesn't always get offer first? */
|
||||
switch_mutex_lock(globals.clients_mutex);
|
||||
for (hi = switch_core_hash_first(globals.clients_roster); hi; hi = switch_core_hash_next(&hi)) {
|
||||
struct rayo_client *rclient;
|
||||
|
@ -3914,16 +4094,15 @@ SWITCH_STANDARD_APP(rayo_app)
|
|||
rclient = (struct rayo_client *)val;
|
||||
switch_assert(rclient);
|
||||
|
||||
/* is session available to take call? */
|
||||
/* find clients available to take calls */
|
||||
if (should_offer_to_client(rclient, clients_to_offer, clients_to_offer_count)) {
|
||||
ok = 1;
|
||||
switch_core_hash_insert(call->pcps, RAYO_JID(rclient), "1");
|
||||
iks_insert_attrib(offer, "to", RAYO_JID(rclient));
|
||||
RAYO_SEND_MESSAGE_DUP(call, RAYO_JID(rclient), offer);
|
||||
switch_core_hash_insert(call->acps, RAYO_JID(rclient), "1");
|
||||
call->num_acps++;
|
||||
}
|
||||
}
|
||||
ok = send_offer_to_clients(call, session);
|
||||
|
||||
switch_mutex_unlock(globals.clients_mutex);
|
||||
iks_delete(offer);
|
||||
|
||||
/* nobody to offer to */
|
||||
if (!ok) {
|
||||
|
@ -4158,6 +4337,8 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_
|
|||
globals.pause_when_offline = 0;
|
||||
globals.add_variables_to_offer = 0;
|
||||
globals.add_variables_to_events = 0;
|
||||
globals.offer_timeout_us = 5000000;
|
||||
globals.offer_algorithm = OFFER_ALL;
|
||||
|
||||
/* get params */
|
||||
{
|
||||
|
@ -4203,6 +4384,25 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_
|
|||
globals.add_variables_to_offer = 1;
|
||||
globals.add_variables_to_events = 1;
|
||||
}
|
||||
} else if (!strcasecmp(var, "offer-timeout-ms")) {
|
||||
int offer_timeout_ms = 0;
|
||||
if (switch_is_number(val) && (offer_timeout_ms = atoi(val)) >= 0 && offer_timeout_ms < 120000) {
|
||||
globals.offer_timeout_us = offer_timeout_ms * 1000;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring invalid value for offer-timeout-ms \"%s\"\n", val);
|
||||
}
|
||||
} else if (!strcasecmp(var, "offer-algorithm")) {
|
||||
if (zstr(val)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No value for offer-algorithm\n");
|
||||
} else if (!strcasecmp(val, "all")) {
|
||||
globals.offer_algorithm = OFFER_ALL;
|
||||
} else if (!strcasecmp(val, "first")) {
|
||||
globals.offer_algorithm = OFFER_FIRST;
|
||||
} else if (!strcasecmp(val, "random")) {
|
||||
globals.offer_algorithm = OFFER_RANDOM;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring invalid value for offer-algorithm \"%s\"\n", val);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var);
|
||||
}
|
||||
|
@ -4881,6 +5081,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
|
|||
switch_core_hash_init(&globals.cmd_aliases);
|
||||
switch_thread_rwlock_create(&globals.shutdown_rwlock, pool);
|
||||
switch_queue_create(&globals.msg_queue, 25000, pool);
|
||||
switch_queue_create(&globals.offer_queue, 25000, pool);
|
||||
globals.offline_logged = 1;
|
||||
|
||||
/* server commands */
|
||||
|
@ -4930,6 +5131,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
|
|||
start_deliver_message_thread(pool);
|
||||
}
|
||||
}
|
||||
start_offer_timeout_thread(pool);
|
||||
|
||||
/* create admin client */
|
||||
globals.console = rayo_console_client_create();
|
||||
|
@ -4979,9 +5181,9 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rayo_shutdown)
|
|||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for XMPP threads to stop\n");
|
||||
xmpp_stream_context_destroy(globals.xmpp_context);
|
||||
|
||||
/* stop message threads */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for message threads to stop\n");
|
||||
stop_deliver_message_threads();
|
||||
/* stop threads */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for message and offer timeout threads to stop\n");
|
||||
stop_all_threads();
|
||||
|
||||
if (globals.console) {
|
||||
RAYO_RELEASE(globals.console);
|
||||
|
|
|
@ -272,7 +272,7 @@ static switch_status_t my_on_reporting(switch_core_session_t *session)
|
|||
memset(xml_text_escaped, 0, need_bytes);
|
||||
if (globals.encode == ENCODING_DEFAULT) {
|
||||
headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
|
||||
switch_url_encode(xml_text, xml_text_escaped, need_bytes);
|
||||
switch_url_encode_opt(xml_text, xml_text_escaped, need_bytes, SWITCH_TRUE);
|
||||
} else {
|
||||
headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded");
|
||||
switch_b64_encode((unsigned char *) xml_text, need_bytes / 3, (unsigned char *) xml_text_escaped, need_bytes);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<configuration name="xml_ldap.conf" description=" XML LDAP Gateway">
|
||||
<bindings>
|
||||
<binding name="directory">
|
||||
<!--%s is populated with the extension -->
|
||||
<!--filter example with custom objectClass -->
|
||||
<param name="filter" value="(&(objectClass=FSAccount)(fsuid=%s))" bindings="directory"/>
|
||||
<!--basedn for the searches %s is replaced with domain-->
|
||||
<param name="basedn" value="ou=%s,ou=customers,o=example" />
|
||||
<param name="url" value="ldap://1.2.3.4" />
|
||||
<param name="binddn" value="cn=admin,o=example" />
|
||||
<param name="bindpass" value="secret" />
|
||||
<trans>
|
||||
<!-- mapping of ldap attrs into FS attrs - fsaccount.schema -->
|
||||
<tran name="id" mapfrom="fsUid" />
|
||||
<tran name="cidr" mapfrom="fsCIDR" />
|
||||
<tran name="number-alias" mapfrom="fsNumberAlias" />
|
||||
<tran name="dial-string" mapfrom="fsDialString" />
|
||||
<tran name="password" mapfrom="fsPassword" />
|
||||
<tran name="a1-hash" mapfrom="fsA1Hash" />
|
||||
<tran name="reverse-auth-user" mapfrom="fsReverseAuthUser" />
|
||||
<tran name="reverse-auth-pass" mapfrom="fsReverseAuthPass" />
|
||||
<tran name="vm-enabled" mapfrom="fsVmEnabled" />
|
||||
<tran name="vm-password" mapfrom="fsVmPassword" />
|
||||
<tran name="vm-mailto" mapfrom="fsVmMailTo" />
|
||||
<tran name="vm-notify-mailto" mapfrom="fsVmNotifyMailTo" />
|
||||
<tran name="vm-attach-file" mapfrom="fsVmAttachFile" />
|
||||
<tran name="vm-message-ext" mapfrom="fsVmMessageExt" />
|
||||
<tran name="vm-email-all-messages" mapfrom="fsVmEmailAllMessages" />
|
||||
<tran name="vm-keep-local-after-email" mapfrom="fsVmKeepLocalAfterEmail" />
|
||||
<tran name="vm-notify-email-all-messages" mapfrom="fsVmNotifyEmailAllMessages" />
|
||||
<tran name="vm-skip-instructions" mapfrom="fsVmSkipInstructions" />
|
||||
<tran name="vm-cc" mapfrom="fsVmCc" />
|
||||
<tran name="vm-disk-quota" mapfrom="fsVmDiskQuota" />
|
||||
<tran name="accountcode" mapfrom="fsAccountCode" />
|
||||
<tran name="user_context" mapfrom="fsUserContext" />
|
||||
<tran name="vm_mailbox" mapfrom="fsVmMailbox" />
|
||||
<tran name="callgroup" mapfrom="fsCallGroup" />
|
||||
<tran name="toll_allow" mapfrom="fsTollAllow" />
|
||||
<tran name="effective_caller_id_number" mapfrom="fsEffectiveCallerIDNumber" />
|
||||
<tran name="effective_caller_id_name" mapfrom="fsEffectiveCallerIDName" />
|
||||
<tran name="outbound_caller_id_number" mapfrom="fsOutboundCallerIDNumber" />
|
||||
<tran name="outbound_caller_id_name" mapfrom="fsOutboundCallerIDName" />
|
||||
</trans>
|
||||
</binding>
|
||||
<!-- <binding name="configuration">
|
||||
<param name="filter" value="(%s=%s)" bindings="configuration"/>
|
||||
<param name="basedn" value=",ou=config,o=example" />
|
||||
<param name="url" value="ldap://ldapuri" />
|
||||
<param name="binddn" value="cn=admin,o=example" />
|
||||
<param name="bindpass" value="secret" />
|
||||
</binding>
|
||||
-->
|
||||
</bindings>
|
||||
</configuration>
|
|
@ -0,0 +1,225 @@
|
|||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.1 NAME 'fsUid'
|
||||
DESC 'FreeSWITCH directory user id'
|
||||
EQUALITY caseExactIA5Match
|
||||
SUBSTR caseExactIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.2 NAME 'fsCIDR'
|
||||
DESC 'FreeSWITCH directory user id cidr'
|
||||
EQUALITY caseExactIA5Match
|
||||
SUBSTR caseExactIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.3 NAME 'fsNumberAlias'
|
||||
DESC 'FreeSWITCH directory user id number-alias'
|
||||
EQUALITY numericStringMatch
|
||||
SUBSTR numericStringSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.4 NAME 'fsDialString'
|
||||
DESC 'FreeSWITCH directory dial-string param'
|
||||
EQUALITY caseExactIA5Match
|
||||
SUBSTR caseExactIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.5 NAME 'fsPassword'
|
||||
DESC 'FreeSWITCH directory password param'
|
||||
EQUALITY caseExactIA5Match
|
||||
SUBSTR caseExactIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.6 NAME 'fsReverseAuthUser'
|
||||
DESC 'FreeSWITCH directory reverse-auth-user param'
|
||||
EQUALITY caseExactIA5Match
|
||||
SUBSTR caseExactIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.7 NAME 'fsReverseAuthPass'
|
||||
DESC 'FreeSWITCH directory reverse-auth-pass param'
|
||||
EQUALITY caseExactIA5Match
|
||||
SUBSTR caseExactIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.8 NAME 'fsA1Hash'
|
||||
DESC 'FreeSWITCH directory a1-hash param'
|
||||
EQUALITY caseExactIA5Match
|
||||
SUBSTR caseExactIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.9 NAME 'fsVmPassword'
|
||||
DESC 'FreeSWITCH directory vm-password param'
|
||||
EQUALITY numericStringMatch
|
||||
SUBSTR numericStringSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.10 NAME 'fsVmEnabled'
|
||||
DESC 'FreeSWITCH directory vm-enabled param'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.11 NAME 'fsVmMailFrom'
|
||||
DESC 'FreeSWITCH directory vm-mailfrom param'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.12 NAME 'fsVmMailTo'
|
||||
DESC 'FreeSWITCH directory vm-mailto param'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.13 NAME 'fsVmNotifyMailTo'
|
||||
DESC 'FreeSWITCH directory vm-notify-mailto param'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.14 NAME 'fsVmAttachFile'
|
||||
DESC 'FreeSWITCH directory vm-attach-file param'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.15 NAME 'fsVmMessageExt'
|
||||
DESC 'FreeSWITCH directory vm-message-ext param'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.16 NAME 'fsVmEmailAllMessages'
|
||||
DESC 'FreeSWITCH directory vm-email-all-messages param'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.17 NAME 'fsVmKeepLocalAfterEmail'
|
||||
DESC 'FreeSWITCH directory vm-keep-local-after-email param'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.18 NAME 'fsVmNotifyEmailAllMessages'
|
||||
DESC 'FreeSWITCH directory vm-notify-email-all-messages param'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.19 NAME 'fsVmSkipInstructions'
|
||||
DESC 'FreeSWITCH directory vm-skip-instructions param'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.20 NAME 'fsVmCc'
|
||||
DESC 'FreeSWITCH directory vm-cc param'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.21 NAME 'fsVmDiskQuota'
|
||||
DESC 'FreeSWITCH directory vm-disk-quota param'
|
||||
EQUALITY numericStringMatch
|
||||
SUBSTR numericStringSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.22 NAME 'fsAccountCode'
|
||||
DESC 'FreeSWITCH directory accountcode variable'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.23 NAME 'fsUserContext'
|
||||
DESC 'FreeSWITCH directory user_context variable'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.24 NAME 'fsVmMailbox'
|
||||
DESC 'FreeSWITCH directory vm_mailbox variable'
|
||||
EQUALITY numericStringMatch
|
||||
SUBSTR numericStringSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.25 NAME 'fsCallGroup'
|
||||
DESC 'FreeSWITCH directory callgroup variable'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.26 NAME ('fsTollAllow' 'fsRuleSet')
|
||||
DESC 'FreeSWITCH directory toll_allow variable'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.27 NAME 'fsEffectiveCallerIDNumber'
|
||||
DESC 'FreeSWITCH directory effective_caller_id_number variable'
|
||||
EQUALITY numericStringMatch
|
||||
SUBSTR numericStringSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.28 NAME 'fsEffectiveCallerIDName'
|
||||
DESC 'FreeSWITCH directory effective_caller_id_name variable'
|
||||
EQUALITY caseExactMatch
|
||||
SUBSTR caseExactSubstringsMatch
|
||||
ORDERING caseExactOrderingMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.29 NAME 'fsOutboundCallerIDNumber'
|
||||
DESC 'FreeSWITCH directory outbound_caller_id_number variable'
|
||||
EQUALITY numericStringMatch
|
||||
SUBSTR numericStringSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.30 NAME 'fsOutboundCallerIDName'
|
||||
DESC 'FreeSWITCH directory outbound_caller_id_name variable'
|
||||
EQUALITY caseExactMatch
|
||||
SUBSTR caseExactSubstringsMatch
|
||||
ORDERING caseExactOrderingMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
|
||||
attributetype ( 1.3.6.1.4.1.27880.1003.1.1.31 NAME 'fsDomainName'
|
||||
DESC 'FreeSWITCH directory domain name'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||
SINGLE-VALUE )
|
||||
|
||||
objectclass (1.3.6.1.4.1.27880.1003.2.1 NAME 'FSAccount'
|
||||
SUP top AUXILIARY
|
||||
DESC 'FreeSWITCH Directory Account (v1.1)'
|
||||
MAY ( fsUid $ fsCIDR $ fsNumberAlias $ fsDialString $ fsPassword $
|
||||
fsReverseAuthUser $ fsReverseAuthPass $ fsA1Hash $ fsVmMessageExt $
|
||||
fsVmPassword $ fsVmEnabled $ fsVmMailFrom $ fsVmMailTo $
|
||||
fsVmNotifyMailTo $ fsVmAttachFile $ fsVmMessageExt $
|
||||
fsVmEmailAllMessages $ fsVmKeepLocalAfterEmail $ fsVmNotifyEmailAllMessages $
|
||||
fsVmSkipInstructions $ fsVmCc $ fsVmDiskQuota $ fsAccountCode $
|
||||
fsUserContext $ fsVmMailbox $ fsCallGroup $ fsTollAllow $
|
||||
fsEffectiveCallerIDNumber $ fsEffectiveCallerIDName $
|
||||
fsOutboundCallerIDNumber $ fsOutboundCallerIDName $ fsDomainName ))
|
|
@ -65,19 +65,36 @@ typedef struct xml_binding {
|
|||
typedef enum exten_types {
|
||||
LDAP_EXTEN_ID = 0,
|
||||
LDAP_EXTEN_CIDR,
|
||||
LDAP_EXTEN_NUMBER_ALIAS,
|
||||
LDAP_EXTEN_DIAL_STRING,
|
||||
LDAP_EXTEN_PASSWORD,
|
||||
LDAP_EXTEN_VM_ENABLED,
|
||||
LDAP_EXTEN_REV_AUTH_USER,
|
||||
LDAP_EXTEN_REV_AUTH_PASS,
|
||||
LDAP_EXTEN_A1_HASH,
|
||||
LDAP_EXTEN_VM_PASSWORD,
|
||||
LDAP_EXTEN_VM_ENABLED,
|
||||
LDAP_EXTEN_VM_MAILFROM,
|
||||
LDAP_EXTEN_VM_MAILTO,
|
||||
LDAP_EXTEN_VM_EMAILMSG,
|
||||
LDAP_EXTEN_VM_NOTEMAILMSG,
|
||||
LDAP_EXTEN_VM_ATTACHFILE,
|
||||
LDAP_EXTEN_USER_CONTEXT,
|
||||
LDAP_EXTEN_EFF_CLIDNAME,
|
||||
LDAP_EXTEN_EFF_CLIDNUM,
|
||||
LDAP_EXTEN_VM_NOTIFY_MAILTO,
|
||||
LDAP_EXTEN_VM_ATTACH_FILE,
|
||||
LDAP_EXTEN_VM_MESSAGE_EXT,
|
||||
LDAP_EXTEN_VM_EMAIL_ALL_MSGS,
|
||||
LDAP_EXTEN_VM_KEEP_LOCAL_AFTER_MAIL,
|
||||
LDAP_EXTEN_VM_NOTIFY_EMAIL_ALL_MSGS,
|
||||
LDAP_EXTEN_VM_SKIP_INSTRUCTIONS,
|
||||
LDAP_EXTEN_VM_CC,
|
||||
LDAP_EXTEN_VM_DISK_QUOTA,
|
||||
LDAP_EXTEN_ACCOUNTCODE,
|
||||
LDAP_EXTEN_RULESET,
|
||||
LDAP_EXTEN_USER_CONTEXT,
|
||||
LDAP_EXTEN_VM_MAILBOX,
|
||||
LDAP_EXTEN_CALLGROUP,
|
||||
LDAP_EXTEN_TOLL_ALLOW,
|
||||
LDAP_EXTEN_EFF_CLIDNUM,
|
||||
LDAP_EXTEN_EFF_CLIDNAME,
|
||||
LDAP_EXTEN_OUT_CLIDNUM,
|
||||
LDAP_EXTEN_OUT_CLIDNAME,
|
||||
LDAP_EXTEN_DOMAIN_NAME
|
||||
/* not used now
|
||||
LDAP_EXTEN_AREACODE,
|
||||
LDAP_EXTEN_CID_EXTNAME,
|
||||
LDAP_EXTEN_CID_EXTNUM,
|
||||
|
@ -99,6 +116,7 @@ typedef enum exten_types {
|
|||
LDAP_EXTEN_HOTLINE_ACTIVE,
|
||||
LDAP_EXTEN_HOTLINE_DEST,
|
||||
LDAP_EXTEN_CLASSOFSERVICE
|
||||
*/
|
||||
} exten_type_t;
|
||||
|
||||
struct xml_ldap_attribute {
|
||||
|
@ -236,6 +254,20 @@ static switch_status_t do_config(void)
|
|||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("number-alias", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_NUMBER_ALIAS;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("dial-string", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_DIAL_STRING;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("password", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_PASSWORD;
|
||||
attr_list->len = strlen(m);
|
||||
|
@ -243,8 +275,22 @@ static switch_status_t do_config(void)
|
|||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-enabled", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_ENABLED;
|
||||
} else if (!strncasecmp("reverse-auth-user", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_REV_AUTH_USER;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("reverse-auth-pass", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_REV_AUTH_PASS;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("a1-hash", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_A1_HASH;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
|
@ -257,6 +303,13 @@ static switch_status_t do_config(void)
|
|||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-enabled", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_ENABLED;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-mailfrom", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_MAILFROM;
|
||||
attr_list->len = strlen(m);
|
||||
|
@ -271,28 +324,77 @@ static switch_status_t do_config(void)
|
|||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-email-all-messages", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_EMAILMSG;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-notify-email-all-messages", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_NOTEMAILMSG;
|
||||
} else if (!strncasecmp("vm-notify-mailto", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_NOTIFY_MAILTO;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-attach-file", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_ATTACHFILE;
|
||||
attr_list->type = LDAP_EXTEN_VM_ATTACH_FILE;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-message-ext", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_MESSAGE_EXT;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-email-all-messages", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_EMAIL_ALL_MSGS;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-keep-local-after-mail", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_KEEP_LOCAL_AFTER_MAIL;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-notify-email-all-messages", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_NOTIFY_EMAIL_ALL_MSGS;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-skip-instructions", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_SKIP_INSTRUCTIONS;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-cc", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_CC;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("vm-disk-quota", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_DISK_QUOTA;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
/* Variables */
|
||||
} else if (!strncasecmp("accountcode", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_ACCOUNTCODE;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("user_context", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_USER_CONTEXT;
|
||||
attr_list->len = strlen(m);
|
||||
|
@ -300,8 +402,22 @@ static switch_status_t do_config(void)
|
|||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("effective_caller_id_name", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_EFF_CLIDNAME;
|
||||
} else if (!strncasecmp("vm_mailbox", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_VM_MAILBOX;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("callgroup", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_CALLGROUP;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("toll_allow", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_TOLL_ALLOW;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
|
@ -314,15 +430,22 @@ static switch_status_t do_config(void)
|
|||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("accountcode", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_ACCOUNTCODE;
|
||||
} else if (!strncasecmp("effective_caller_id_name", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_EFF_CLIDNAME;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("ruleset", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_RULESET;
|
||||
} else if (!strncasecmp("outbound_caller_id_number", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_OUT_CLIDNUM;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
|
||||
attr_list = attr_list->next;
|
||||
} else if (!strncasecmp("outbound_caller_id_name", n, strlen(n))) {
|
||||
attr_list->type = LDAP_EXTEN_OUT_CLIDNAME;
|
||||
attr_list->len = strlen(m);
|
||||
attr_list->val = strdup(m);
|
||||
attr_list->next = malloc(sizeof(*attr_list));
|
||||
|
@ -365,10 +488,13 @@ static switch_status_t trydir(switch_xml_t *pxml, int *xoff, LDAP * ld, char *di
|
|||
LDAPMessage *msg, *entry;
|
||||
xml_ldap_attribute_t *attr = NULL;
|
||||
static char *fsattr[] =
|
||||
{ "id", "cidr", "password", "vm-enabled", "vm-password", "vm-mailfrom", "vm-mailto",
|
||||
"vm-email-all-messages", "vm-notify-email-all-messages", "vm-attach-file",
|
||||
"user_context", "effective_caller_id_name", "effective_caller_id_number",
|
||||
"accountcode", "ruleset", NULL };
|
||||
{ "id", "cidr", "number-alias", "dial-string", "password", "reverse-auth-user",
|
||||
"reverse-auth-pass", "a1-hash", "vm-password", "vm-enabled", "vm-mailfrom",
|
||||
"vm-mailto", "vm-notify-mailto", "vm-attach-file", "vm-message-ext",
|
||||
"vm-email-all-messages", "vm-keep-local-after-mail", "vm-notify-email-all-messages",
|
||||
"vm-skip-instructions", "vm-cc", "vm-disk-quota", "accountcode", "user_context",
|
||||
"vm_mailbox", "callgroup", "effective_caller_id_number", "effective_caller_id_name",
|
||||
"outbound_caller_id_number", "outbound_caller_id_name", "toll_allow", NULL };
|
||||
|
||||
basedn = switch_mprintf(binding->basedn, dir_domain);
|
||||
filter = switch_mprintf(binding->filter, dir_exten);
|
||||
|
|
|
@ -864,11 +864,15 @@ SWITCH_DECLARE(const char *) switch_get_addr(char *buf, switch_size_t len, switc
|
|||
return SWITCH_BLANK_STRING;
|
||||
}
|
||||
|
||||
memset(buf, 0, len);
|
||||
|
||||
if (in->family == AF_INET) {
|
||||
return get_addr(buf, len, (struct sockaddr *) &in->sa, in->salen);
|
||||
get_addr(buf, len, (struct sockaddr *) &in->sa, in->salen);
|
||||
return buf;
|
||||
}
|
||||
|
||||
return get_addr6(buf, len, (struct sockaddr_in6 *) &in->sa, in->salen);
|
||||
get_addr6(buf, len, (struct sockaddr_in6 *) &in->sa, in->salen);
|
||||
return buf;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(uint16_t) switch_sockaddr_get_port(switch_sockaddr_t *sa)
|
||||
|
|
|
@ -1331,7 +1331,12 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_
|
|||
free(list_name_dup);
|
||||
} else {
|
||||
switch_parse_cidr(list_name, &net, &mask, &bits);
|
||||
ok = switch_test_subnet(ip.v4, net.v4, mask.v4);
|
||||
|
||||
if (ipv6) {
|
||||
ok = switch_testv6_subnet(ip, net, mask);
|
||||
} else {
|
||||
ok = switch_test_subnet(ip.v4, net.v4, mask.v4);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(runtime.global_mutex);
|
||||
|
@ -1395,6 +1400,40 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload)
|
|||
switch_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE);
|
||||
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
|
||||
|
||||
tmp_name = "wan_v6.auto";
|
||||
switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
|
||||
switch_network_list_add_cidr(rfc_list, "0.0.0.0/0", SWITCH_FALSE);
|
||||
switch_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE);
|
||||
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
|
||||
|
||||
|
||||
tmp_name = "wan_v4.auto";
|
||||
switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
|
||||
switch_network_list_add_cidr(rfc_list, "0.0.0.0/8", SWITCH_FALSE);
|
||||
switch_network_list_add_cidr(rfc_list, "10.0.0.0/8", SWITCH_FALSE);
|
||||
switch_network_list_add_cidr(rfc_list, "172.16.0.0/12", SWITCH_FALSE);
|
||||
switch_network_list_add_cidr(rfc_list, "192.168.0.0/16", SWITCH_FALSE);
|
||||
switch_network_list_add_cidr(rfc_list, "169.254.0.0/16", SWITCH_FALSE);
|
||||
switch_network_list_add_cidr(rfc_list, "::/0", SWITCH_FALSE);
|
||||
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
|
||||
|
||||
|
||||
tmp_name = "any_v6.auto";
|
||||
switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
|
||||
switch_network_list_add_cidr(rfc_list, "0.0.0.0/0", SWITCH_FALSE);
|
||||
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
|
||||
|
||||
|
||||
tmp_name = "any_v4.auto";
|
||||
switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
|
||||
switch_network_list_add_cidr(rfc_list, "::/0", SWITCH_FALSE);
|
||||
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
|
||||
|
||||
|
||||
tmp_name = "nat.auto";
|
||||
switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name);
|
||||
|
|
|
@ -216,8 +216,6 @@ struct switch_media_handle_s {
|
|||
|
||||
};
|
||||
|
||||
static switch_bool_t check_dtls(switch_core_session_t *session);
|
||||
|
||||
static switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID] = {
|
||||
{ "AEAD_AES_256_GCM_8", AEAD_AES_256_GCM_8, 44},
|
||||
{ "AEAD_AES_128_GCM_8", AEAD_AES_128_GCM_8, 28},
|
||||
|
@ -341,6 +339,9 @@ SWITCH_DECLARE(uint32_t) switch_core_media_get_video_fps(switch_core_session_t *
|
|||
fps = switch_round_to_step(smh->vid_frames / (now - smh->vid_started), 5);
|
||||
if (fps < 15) fps = 15;
|
||||
|
||||
smh->vid_started = switch_epoch_time_now(NULL);
|
||||
smh->vid_frames = 1;
|
||||
|
||||
return fps;
|
||||
}
|
||||
|
||||
|
@ -2885,7 +2886,10 @@ static void clear_ice(switch_core_session_t *session, switch_media_type_t type)
|
|||
|
||||
engine->ice_in.chosen[0] = 0;
|
||||
engine->ice_in.chosen[1] = 0;
|
||||
engine->ice_in.cand_idx = 0;
|
||||
engine->ice_in.is_chosen[0] = 0;
|
||||
engine->ice_in.is_chosen[1] = 0;
|
||||
engine->ice_in.cand_idx[0] = 0;
|
||||
engine->ice_in.cand_idx[1] = 0;
|
||||
memset(&engine->ice_in, 0, sizeof(engine->ice_in));
|
||||
engine->remote_rtcp_port = 0;
|
||||
|
||||
|
@ -3048,20 +3052,70 @@ SWITCH_DECLARE(switch_call_direction_t) switch_ice_direction(switch_core_session
|
|||
}
|
||||
|
||||
//?
|
||||
static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_session_t *sdp, sdp_media_t *m)
|
||||
static switch_status_t ip_choose_family(switch_media_handle_t *smh, const char *ip)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (zstr(ip)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (strchr(ip, ':')) {
|
||||
if (!zstr(smh->mparams->rtpip6)) {
|
||||
smh->mparams->rtpip = smh->mparams->rtpip6;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v6\n",
|
||||
switch_channel_get_name(smh->session->channel));
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
if (!zstr(smh->mparams->rtpip4)) {
|
||||
smh->mparams->rtpip = smh->mparams->rtpip4;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v4\n",
|
||||
switch_channel_get_name(smh->session->channel));
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//?
|
||||
static switch_bool_t ip_possible(switch_media_handle_t *smh, const char *ip)
|
||||
{
|
||||
switch_bool_t r = SWITCH_FALSE;
|
||||
|
||||
if (zstr(ip)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (strchr(ip, ':')) {
|
||||
r = (switch_bool_t) !zstr(smh->mparams->rtpip6);
|
||||
} else {
|
||||
r = (switch_bool_t) !zstr(smh->mparams->rtpip4);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//?
|
||||
static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_session_t *sdp, sdp_media_t *m)
|
||||
{
|
||||
switch_rtp_engine_t *engine = &smh->engines[type];
|
||||
sdp_attribute_t *attr;
|
||||
int i = 0, got_rtcp_mux = 0;
|
||||
const char *val;
|
||||
int ice_seen = 0, cid = 0, ai = 0;
|
||||
|
||||
if (engine->ice_in.chosen[0] && engine->ice_in.chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
|
||||
return;
|
||||
if (engine->ice_in.is_chosen[0] && engine->ice_in.is_chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
engine->ice_in.chosen[0] = 0;
|
||||
engine->ice_in.chosen[1] = 0;
|
||||
engine->ice_in.cand_idx = 0;
|
||||
engine->ice_in.is_chosen[0] = 0;
|
||||
engine->ice_in.is_chosen[1] = 0;
|
||||
engine->ice_in.cand_idx[0] = 0;
|
||||
engine->ice_in.cand_idx[1] = 0;
|
||||
|
||||
if (m) {
|
||||
attr = m->m_attributes;
|
||||
|
@ -3073,7 +3127,6 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
|
|||
char *data;
|
||||
char *fields[15];
|
||||
int argc = 0, j = 0;
|
||||
int cid = 0;
|
||||
|
||||
if (zstr(attr->a_name)) {
|
||||
continue;
|
||||
|
@ -3081,6 +3134,7 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
|
|||
|
||||
if (!strcasecmp(attr->a_name, "ice-ufrag")) {
|
||||
engine->ice_in.ufrag = switch_core_session_strdup(smh->session, attr->a_value);
|
||||
ice_seen++;
|
||||
} else if (!strcasecmp(attr->a_name, "ice-pwd")) {
|
||||
engine->ice_in.pwd = switch_core_session_strdup(smh->session, attr->a_value);
|
||||
} else if (!strcasecmp(attr->a_name, "ice-options")) {
|
||||
|
@ -3133,145 +3187,113 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
|
|||
}
|
||||
|
||||
data = switch_core_session_strdup(smh->session, attr->a_value);
|
||||
|
||||
|
||||
argc = switch_split(data, ' ', fields);
|
||||
|
||||
if (argc < 5 || engine->ice_in.cand_idx >= MAX_CAND - 1) {
|
||||
cid = fields[1] ? atoi(fields[1]) - 1 : 0;
|
||||
|
||||
if (argc < 5 || engine->ice_in.cand_idx[cid] >= MAX_CAND - 1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_WARNING, "Invalid data\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
cid = atoi(fields[1]) - 1;
|
||||
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG1, "CAND %d [%s]\n", i, fields[i]);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
|
||||
"Checking Candidate cid: %d proto: %s type: %s addr: %s:%s\n", cid+1, fields[2], fields[7], fields[4], fields[5]);
|
||||
if (!ip_possible(smh, fields[4])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
|
||||
"Drop %s Candidate cid: %d proto: %s type: %s addr: %s:%s (no network path)\n",
|
||||
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
|
||||
cid+1, fields[2], fields[7], fields[4], fields[5]);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
|
||||
"Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
|
||||
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
|
||||
cid+1, fields[2], fields[7], fields[4], fields[5]);
|
||||
}
|
||||
|
||||
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].foundation = switch_core_session_strdup(smh->session, fields[0]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].component_id = atoi(fields[1]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].transport = switch_core_session_strdup(smh->session, fields[2]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].priority = atol(fields[3]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_port = (switch_port_t)atoi(fields[5]);
|
||||
|
||||
j = 6;
|
||||
|
||||
|
||||
engine->ice_in.cand_idx++;
|
||||
|
||||
for (i = 0; i < engine->cand_acl_count; i++) {
|
||||
if (!engine->ice_in.chosen[cid] && !strchr(fields[4], ':') && switch_check_network_list_ip(fields[4], engine->cand_acl[i])) {
|
||||
engine->ice_in.chosen[cid] = engine->ice_in.cand_idx;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"Choose %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
|
||||
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
|
||||
cid+1, fields[2], fields[7], fields[4], fields[5]);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
|
||||
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
|
||||
cid+1, fields[2], fields[7], fields[4], fields[5]);
|
||||
while(j < argc && fields[j+1]) {
|
||||
if (!strcasecmp(fields[j], "typ")) {
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]);
|
||||
} else if (!strcasecmp(fields[j], "raddr")) {
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]);
|
||||
} else if (!strcasecmp(fields[j], "rport")) {
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].rport = (switch_port_t)atoi(fields[j+1]);
|
||||
} else if (!strcasecmp(fields[j], "generation")) {
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]);
|
||||
}
|
||||
|
||||
j += 2;
|
||||
}
|
||||
|
||||
engine->ice_in.cand_idx[cid]++;
|
||||
}
|
||||
}
|
||||
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].foundation = switch_core_session_strdup(smh->session, fields[0]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].component_id = atoi(fields[1]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].transport = switch_core_session_strdup(smh->session, fields[2]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].priority = atol(fields[3]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]);
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_port = (switch_port_t)atoi(fields[5]);
|
||||
if (!ice_seen) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
j = 6;
|
||||
for (cid = 0; cid < 2; cid++) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "Searching for %s candidate.\n", cid ? "rtcp" : "rtp");
|
||||
|
||||
while(j < argc && fields[j+1]) {
|
||||
if (!strcasecmp(fields[j], "typ")) {
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]);
|
||||
} else if (!strcasecmp(fields[j], "raddr")) {
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]);
|
||||
} else if (!strcasecmp(fields[j], "rport")) {
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].rport = (switch_port_t)atoi(fields[j+1]);
|
||||
} else if (!strcasecmp(fields[j], "generation")) {
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]);
|
||||
for (ai = 0; ai < engine->cand_acl_count; ai++) {
|
||||
for (i = 0; i < engine->ice_in.cand_idx[cid]; i++) {
|
||||
if (switch_check_network_list_ip(engine->ice_in.cands[i][cid].con_addr, engine->cand_acl[ai])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
|
||||
"Choose %s candidate, index %d, %s:%d\n", cid ? "rtcp" : "rtp", i,
|
||||
engine->ice_in.cands[i][cid].con_addr, engine->ice_in.cands[i][cid].con_port);
|
||||
|
||||
engine->ice_in.chosen[cid] = i;
|
||||
engine->ice_in.is_chosen[cid] = 1;
|
||||
engine->ice_in.cands[i][cid].ready++;
|
||||
ip_choose_family(smh, engine->ice_in.cands[i][cid].con_addr);
|
||||
|
||||
if (cid == 0 && got_rtcp_mux && engine->ice_in.cand_idx[1] < MAX_CAND) {
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
|
||||
"Choose same candidate, index %d, for rtcp based on rtcp-mux attribute %s:%d\n", engine->ice_in.cand_idx[1],
|
||||
engine->ice_in.cands[i][cid].con_addr, engine->ice_in.cands[i][cid].con_port);
|
||||
|
||||
|
||||
engine->ice_in.cands[engine->ice_in.cand_idx[1]][1] = engine->ice_in.cands[i][0];
|
||||
engine->ice_in.chosen[1] = engine->ice_in.cand_idx[1];
|
||||
engine->ice_in.is_chosen[1] = 1;
|
||||
engine->ice_in.cand_idx[1]++;
|
||||
|
||||
goto done_choosing;
|
||||
}
|
||||
|
||||
j += 2;
|
||||
}
|
||||
|
||||
|
||||
if (engine->ice_in.chosen[cid]) {
|
||||
engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++;
|
||||
goto next_cid;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* still no candidates, so start searching for some based on sane deduction */
|
||||
|
||||
/* look for candidates on the same network */
|
||||
if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
|
||||
for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
|
||||
if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1 &&
|
||||
!engine->ice_in.cands[i][0].rport && switch_check_network_list_ip(engine->ice_in.cands[i][0].con_addr, "localnet.auto")) {
|
||||
engine->ice_in.chosen[0] = i;
|
||||
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"No %s RTP candidate found; defaulting to the first local one.\n", type2str(type));
|
||||
}
|
||||
if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2 &&
|
||||
!engine->ice_in.cands[i][1].rport && switch_check_network_list_ip(engine->ice_in.cands[i][1].con_addr, "localnet.auto")) {
|
||||
engine->ice_in.chosen[1] = i;
|
||||
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session),SWITCH_LOG_NOTICE,
|
||||
"No %s RTCP candidate found; defaulting to the first local one.\n", type2str(type));
|
||||
}
|
||||
}
|
||||
next_cid:
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* look for candidates with srflx */
|
||||
if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
|
||||
for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
|
||||
if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1 && engine->ice_in.cands[i][0].rport) {
|
||||
engine->ice_in.chosen[0] = i;
|
||||
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"No %s RTP candidate found; defaulting to the first srflx one.\n", type2str(type));
|
||||
}
|
||||
if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2 && engine->ice_in.cands[i][1].rport) {
|
||||
engine->ice_in.chosen[1] = i;
|
||||
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session),SWITCH_LOG_NOTICE,
|
||||
"No %s RTCP candidate found; defaulting to the first srflx one.\n", type2str(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
done_choosing:
|
||||
|
||||
/* Got RTP but not RTCP, probably mux */
|
||||
if (engine->ice_in.chosen[0] && !engine->ice_in.chosen[1] && got_rtcp_mux) {
|
||||
engine->ice_in.chosen[1] = engine->ice_in.chosen[0];
|
||||
|
||||
memcpy(&engine->ice_in.cands[engine->ice_in.chosen[1]][1], &engine->ice_in.cands[engine->ice_in.chosen[0]][0],
|
||||
sizeof(engine->ice_in.cands[engine->ice_in.chosen[0]][0]));
|
||||
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"No %s RTCP candidate found; defaulting to the same as RTP [%s:%d]\n", type2str(type),
|
||||
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
|
||||
}
|
||||
|
||||
/* look for any candidates and hope for auto-adjust */
|
||||
if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
|
||||
for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
|
||||
if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1) {
|
||||
engine->ice_in.chosen[0] = i;
|
||||
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"No %s RTP candidate found; defaulting to the first one.\n", type2str(type));
|
||||
}
|
||||
if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2) {
|
||||
engine->ice_in.chosen[1] = i;
|
||||
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"No %s RTCP candidate found; defaulting to the first one.\n", type2str(type));
|
||||
}
|
||||
}
|
||||
if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) {
|
||||
/* PUNT */
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s no suitable candidates found.\n",
|
||||
switch_channel_get_name(smh->session->channel));
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
@ -3286,8 +3308,8 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
|
|||
if (engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr && engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port) {
|
||||
char tmp[80] = "";
|
||||
engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(smh->session, (char *) engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"setting remote %s ice addr to %s:%d based on candidate\n", type2str(type),
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
|
||||
"setting remote %s ice addr to index %d %s:%d based on candidate\n", type2str(type), engine->ice_in.chosen[0],
|
||||
engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port);
|
||||
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
|
||||
|
||||
|
@ -3301,29 +3323,19 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
|
|||
smh->mparams->remote_ip = engine->cur_payload_map->remote_sdp_ip;
|
||||
}
|
||||
|
||||
if (engine->remote_rtcp_port) {
|
||||
engine->remote_rtcp_port = engine->cur_payload_map->remote_sdp_port;
|
||||
}
|
||||
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", engine->cur_payload_map->remote_sdp_port);
|
||||
switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, engine->cur_payload_map->remote_sdp_ip);
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port);
|
||||
switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
|
||||
switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
|
||||
}
|
||||
|
||||
if (engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port) {
|
||||
if (engine->rtcp_mux) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"Asked by candidate to set remote rtcp %s addr to %s:%d but this is rtcp-mux so no thanks\n", type2str(type),
|
||||
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
|
||||
"Setting remote rtcp %s addr to %s:%d based on candidate\n", type2str(type),
|
||||
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
|
||||
engine->remote_rtcp_ice_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
|
||||
engine->remote_rtcp_ice_addr = switch_core_session_strdup(smh->session, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr);
|
||||
|
||||
engine->remote_rtcp_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
|
||||
"Setting remote rtcp %s addr to %s:%d based on candidate\n", type2str(type),
|
||||
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
|
||||
engine->remote_rtcp_ice_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
|
||||
engine->remote_rtcp_ice_addr = switch_core_session_strdup(smh->session, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr);
|
||||
|
||||
engine->remote_rtcp_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3411,6 +3423,8 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
return ice_seen ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_BREAK;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -3503,7 +3517,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
|
|||
const char *tmp;
|
||||
int m_idx = 0;
|
||||
int nm_idx = 0;
|
||||
|
||||
|
||||
switch_assert(session);
|
||||
|
||||
if (!(smh = session->media_handle)) {
|
||||
|
@ -4280,8 +4294,11 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
|
|||
}
|
||||
|
||||
if (switch_core_media_set_codec(session, 0, smh->mparams->codec_flags) == SWITCH_STATUS_SUCCESS) {
|
||||
got_audio = 1;
|
||||
check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m);
|
||||
if (check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m) == SWITCH_STATUS_FALSE) {
|
||||
match = 0;
|
||||
} else {
|
||||
got_audio = 1;
|
||||
}
|
||||
} else {
|
||||
match = 0;
|
||||
}
|
||||
|
@ -4554,7 +4571,9 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
|
|||
}
|
||||
|
||||
if (switch_core_media_set_video_codec(session, 0) == SWITCH_STATUS_SUCCESS) {
|
||||
check_ice(smh, SWITCH_MEDIA_TYPE_VIDEO, sdp, m);
|
||||
if (check_ice(smh, SWITCH_MEDIA_TYPE_VIDEO, sdp, m) == SWITCH_STATUS_FALSE) {
|
||||
vmatch = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4989,7 +5008,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_start_video_thread(switch_co
|
|||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s Starting Video thread\n", switch_core_session_get_name(session));
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Starting Video thread\n", switch_core_session_get_name(session));
|
||||
|
||||
if (v_engine->rtp_session) {
|
||||
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt);
|
||||
|
@ -5476,6 +5495,20 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_sessio
|
|||
SWITCH_DECLARE(switch_status_t) switch_core_media_choose_ports(switch_core_session_t *session, switch_bool_t audio, switch_bool_t video)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_media_handle_t *smh;
|
||||
|
||||
if (!(smh = session->media_handle)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (zstr(smh->mparams->rtpip)) {
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no media ip\n",
|
||||
switch_channel_get_name(smh->session->channel));
|
||||
switch_channel_hangup(smh->session->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (audio && (status = switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 0)) == SWITCH_STATUS_SUCCESS) {
|
||||
if (video) {
|
||||
|
@ -6316,7 +6349,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
|
|||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
|
||||
switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
|
||||
switch_channel_get_name(session->channel),
|
||||
a_engine->cur_payload_map->remote_sdp_ip,
|
||||
a_engine->local_sdp_ip,
|
||||
v_engine->local_sdp_port,
|
||||
v_engine->cur_payload_map->remote_sdp_ip,
|
||||
v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt,
|
||||
|
@ -6495,13 +6528,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
|
|||
|
||||
end:
|
||||
|
||||
|
||||
switch_channel_clear_flag(session->channel, CF_REINVITE);
|
||||
|
||||
switch_core_recovery_track(session);
|
||||
|
||||
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
@ -8555,7 +8585,7 @@ static int check_engine(switch_rtp_engine_t *engine)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static switch_bool_t check_dtls(switch_core_session_t *session)
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t *session)
|
||||
{
|
||||
switch_media_handle_t *smh;
|
||||
switch_rtp_engine_t *a_engine, *v_engine;
|
||||
|
@ -8567,7 +8597,7 @@ static switch_bool_t check_dtls(switch_core_session_t *session)
|
|||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
if (switch_channel_down(session->channel)) {
|
||||
if (!switch_channel_media_up(session->channel)) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
|
@ -8621,14 +8651,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se
|
|||
}
|
||||
break;
|
||||
|
||||
case SWITCH_MESSAGE_INDICATE_ANSWER:
|
||||
case SWITCH_MESSAGE_INDICATE_PROGRESS:
|
||||
case SWITCH_MESSAGE_ANSWER_EVENT:
|
||||
case SWITCH_MESSAGE_PROGRESS_EVENT:
|
||||
{
|
||||
check_dtls(session);
|
||||
}
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
|
||||
{
|
||||
if (v_engine->rtp_session) {
|
||||
|
|
|
@ -486,6 +486,10 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state > CS_INIT && switch_channel_media_up(session->channel)) {
|
||||
switch_core_media_check_dtls(session);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case CS_NEW: /* Just created, Waiting for first instructions */
|
||||
|
|
|
@ -530,7 +530,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *se
|
|||
elp = 1;
|
||||
}
|
||||
|
||||
if (lead_frames) {
|
||||
if (lead_frames && switch_channel_media_ready(channel)) {
|
||||
switch_frame_t *read_frame;
|
||||
int frame_count = atoi(lead_frames);
|
||||
int max_frames = frame_count * 2;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Eliot Gable <egable@gmail.com>
|
||||
* Seven Du <dujinfang@gmail.com>
|
||||
*
|
||||
* switch_pgsql.c -- PGSQL Driver
|
||||
*
|
||||
|
@ -465,7 +466,17 @@ SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_finish_results_real(const cha
|
|||
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Error executing query:\n%s\n", res->err);
|
||||
final_status = SWITCH_PGSQL_FAIL;
|
||||
}
|
||||
if (!res) done = 1;
|
||||
|
||||
if (!res) {
|
||||
done = 1;
|
||||
} else if (res->result) {
|
||||
char *affected_rows = PQcmdTuples(res->result);
|
||||
|
||||
if (!zstr(affected_rows)) {
|
||||
handle->affected_rows = atoi(affected_rows);
|
||||
}
|
||||
}
|
||||
|
||||
switch_pgsql_free_result(&res);
|
||||
} while (!done);
|
||||
return final_status;
|
||||
|
|
|
@ -887,7 +887,7 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
|
|||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "STUN PACKET TYPE: %s\n",
|
||||
switch_stun_value_to_name(SWITCH_STUN_TYPE_PACKET_TYPE, packet->header.type));
|
||||
do {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|---: STUN ATTR %s\n",
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|---: STUN ATTR %d %x %s\n", attr->type, attr->type,
|
||||
switch_stun_value_to_name(SWITCH_STUN_TYPE_ATTRIBUTE, attr->type));
|
||||
|
||||
switch (attr->type) {
|
||||
|
@ -928,6 +928,14 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
|
|||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|------: %s:%d\n", ip, port);
|
||||
}
|
||||
break;
|
||||
case SWITCH_STUN_ATTR_XOR_MAPPED_ADDRESS:
|
||||
if (attr->type) {
|
||||
char ip[16];
|
||||
uint16_t port;
|
||||
switch_stun_packet_attribute_get_xor_mapped_address(attr, packet->header.cookie, ip, &port);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|------: %s:%d\n", ip, port);
|
||||
}
|
||||
break;
|
||||
case SWITCH_STUN_ATTR_USERNAME:
|
||||
if (attr->type) {
|
||||
switch_stun_packet_attribute_get_username(attr, username, sizeof(username));
|
||||
|
@ -1030,7 +1038,7 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
|
|||
if (!icep[j] || !icep[j]->ice_params) {
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < icep[j]->ice_params->cand_idx; i++) {
|
||||
for (i = 0; i < icep[j]->ice_params->cand_idx[icep[j]->proto]; i++) {
|
||||
if (icep[j]->ice_params && icep[j]->ice_params->cands[i][icep[j]->proto].priority == *pri) {
|
||||
if (j == IPR_RTP) {
|
||||
icep[j]->ice_params->chosen[j] = i;
|
||||
|
@ -1183,7 +1191,7 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
|
|||
|
||||
|
||||
|
||||
for (i = 0; i <= ice->ice_params->cand_idx; i++) {
|
||||
for (i = 0; i <= ice->ice_params->cand_idx[ice->proto]; i++) {
|
||||
if (ice->ice_params->cands[i][ice->proto].con_port == port) {
|
||||
if (!strcmp(ice->ice_params->cands[i][ice->proto].con_addr, host) &&
|
||||
!strcmp(ice->ice_params->cands[i][ice->proto].cand_type, "relay")) {
|
||||
|
@ -2396,7 +2404,7 @@ static switch_status_t enable_remote_rtcp_socket(switch_rtp_t *rtp_session, cons
|
|||
host = switch_get_addr(bufa, sizeof(bufa), rtp_session->rtcp_remote_addr);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG,
|
||||
"Setting RTCP remote addr to %s:%d\n", host, rtp_session->remote_rtcp_port);
|
||||
"Setting RTCP remote addr to %s:%d %d\n", host, rtp_session->remote_rtcp_port, rtp_session->rtcp_remote_addr->family);
|
||||
}
|
||||
|
||||
if (rtp_session->rtcp_sock_input && switch_sockaddr_get_family(rtp_session->rtcp_remote_addr) ==
|
||||
|
@ -2838,23 +2846,24 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_
|
|||
}
|
||||
|
||||
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP] && !rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
|
||||
if (remote_rtcp_port) {
|
||||
rtp_session->remote_rtcp_port = remote_rtcp_port;
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP]) {
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
|
||||
rtp_session->rtcp_remote_addr = rtp_session->remote_addr;
|
||||
rtp_session->rtcp_sock_output = rtp_session->sock_output;
|
||||
} else {
|
||||
rtp_session->remote_rtcp_port = rtp_session->eff_remote_port + 1;
|
||||
if (remote_rtcp_port) {
|
||||
rtp_session->remote_rtcp_port = remote_rtcp_port;
|
||||
} else {
|
||||
rtp_session->remote_rtcp_port = rtp_session->eff_remote_port + 1;
|
||||
}
|
||||
status = enable_remote_rtcp_socket(rtp_session, err);
|
||||
|
||||
if (rtp_session->rtcp_dtls) {
|
||||
//switch_sockaddr_info_get(&rtp_session->rtcp_dtls->remote_addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool);
|
||||
rtp_session->rtcp_dtls->remote_addr = rtp_session->rtcp_remote_addr;
|
||||
rtp_session->rtcp_dtls->sock_output = rtp_session->rtcp_sock_output;
|
||||
}
|
||||
}
|
||||
status = enable_remote_rtcp_socket(rtp_session, err);
|
||||
|
||||
if (rtp_session->rtcp_dtls) {
|
||||
//switch_sockaddr_info_get(&rtp_session->rtcp_dtls->remote_addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool);
|
||||
rtp_session->rtcp_dtls->remote_addr = rtp_session->rtcp_remote_addr;
|
||||
rtp_session->rtcp_dtls->sock_output = rtp_session->rtcp_sock_output;
|
||||
}
|
||||
}
|
||||
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP] && rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
|
||||
rtp_session->rtcp_remote_addr = rtp_session->remote_addr;
|
||||
}
|
||||
|
||||
switch_mutex_unlock(rtp_session->write_mutex);
|
||||
|
@ -4104,8 +4113,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_sessi
|
|||
rtp_session->rtcp_sock_output = rtp_session->sock_output;
|
||||
|
||||
rtp_session->rtcp_recv_msg_p = (rtcp_msg_t *) &rtp_session->recv_msg;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
return enable_remote_rtcp_socket(rtp_session, &err);
|
||||
//return enable_remote_rtcp_socket(rtp_session, &err);
|
||||
} else {
|
||||
rtp_session->rtcp_recv_msg_p = (rtcp_msg_t *) &rtp_session->rtcp_recv_msg;
|
||||
}
|
||||
|
@ -5705,7 +5716,7 @@ static switch_status_t process_rtcp_packet(switch_rtp_t *rtp_session, switch_siz
|
|||
|
||||
if (msg->header.version != 2 || !(msg->header.type > 199 && msg->header.type < 208)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING,
|
||||
"INVALID RTCP PACKET TYPE %d VER %d LEN %ld\n", msg->header.type,
|
||||
"INVALID RTCP PACKET TYPE %d VER %d LEN %" SWITCH_SIZE_T_FMT "\n", msg->header.type,
|
||||
msg->header.version, len);
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
break;
|
||||
|
@ -7746,7 +7757,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_write_raw(switch_rtp_t *rtp_session,
|
|||
break;
|
||||
case zrtp_status_drop:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat);
|
||||
ret = SWITCH_STATUS_SUCCESS;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
goto end;
|
||||
break;
|
||||
case zrtp_status_fail:
|
||||
|
|
|
@ -60,6 +60,7 @@ static const struct value_mapping PACKET_TYPES[] = {
|
|||
|
||||
static const struct value_mapping ATTR_TYPES[] = {
|
||||
{SWITCH_STUN_ATTR_MAPPED_ADDRESS, "MAPPED_ADDRESS"},
|
||||
{SWITCH_STUN_ATTR_XOR_MAPPED_ADDRESS, "XOR_MAPPED_ADDRESS"},
|
||||
{SWITCH_STUN_ATTR_RESPONSE_ADDRESS, "RESPONSE_ADDRESS"},
|
||||
{SWITCH_STUN_ATTR_CHANGE_REQUEST, "CHANGE_REQUEST"},
|
||||
{SWITCH_STUN_ATTR_SOURCE_ADDRESS, "SOURCE_ADDRESS"},
|
||||
|
|
|
@ -431,7 +431,8 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_netw
|
|||
|
||||
for (node = list->node_head; node; node = node->next) {
|
||||
if (node->family == AF_INET) continue;
|
||||
if (node->bits > bits && switch_testv6_subnet(ip, node->ip, node->mask)) {
|
||||
|
||||
if (node->bits >= bits && switch_testv6_subnet(ip, node->ip, node->mask)) {
|
||||
if (node->ok) {
|
||||
ok = SWITCH_TRUE;
|
||||
} else {
|
||||
|
@ -457,7 +458,7 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo
|
|||
|
||||
for (node = list->node_head; node; node = node->next) {
|
||||
if (node->family == AF_INET6) continue; /* want AF_INET */
|
||||
if (node->bits > bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) {
|
||||
if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) {
|
||||
if (node->ok) {
|
||||
ok = SWITCH_TRUE;
|
||||
} else {
|
||||
|
@ -3161,7 +3162,7 @@ SWITCH_DECLARE(int) switch_socket_waitfor(switch_pollfd_t *poll, int ms)
|
|||
return nsds;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
|
||||
SWITCH_DECLARE(char *) switch_url_encode_opt(const char *url, char *buf, size_t len, switch_bool_t double_encode)
|
||||
{
|
||||
const char *p, *e = end_of_p(url);
|
||||
size_t x = 0;
|
||||
|
@ -3184,7 +3185,7 @@ SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
|
|||
break;
|
||||
}
|
||||
|
||||
if (*p == '%' && e-p > 1) {
|
||||
if (!double_encode && *p == '%' && e-p > 1) {
|
||||
if (strchr(hex, *(p+1)) && strchr(hex, *(p+2))) {
|
||||
ok = 1;
|
||||
}
|
||||
|
@ -3206,6 +3207,11 @@ SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
|
|||
return buf;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
|
||||
{
|
||||
return switch_url_encode_opt(url, buf, len, SWITCH_FALSE);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(char *) switch_url_decode(char *s)
|
||||
{
|
||||
char *o;
|
||||
|
|
Loading…
Reference in New Issue