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 of 3b2d00f3e6 from verto to sip and refactor some code to keep sip working like verto
  add a bit to 2db8f94ab6
  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:
Sergey Safarov
2015-06-04 06:50:27 -05:00
52 changed files with 1914 additions and 506 deletions
+5
View File
@@ -8,6 +8,11 @@
<param name="mixer-conf-profile" value="sla"/> <param name="mixer-conf-profile" value="sla"/>
<!-- if true, to attribute in offer uses URI instead of name/number --> <!-- if true, to attribute in offer uses URI instead of name/number -->
<param name="offer-uri" value="true"/> <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 --> <!-- if true, channel variables are added to rayo client offer -->
<param name="add-variables-to-offer" value="false"/> <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 --> <!-- 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-layout-bgcolor" value="#000000"/> -->
<!-- <param name="video-codec-bandwidth" value="2mb"/> --> <!-- <param name="video-codec-bandwidth" value="2mb"/> -->
<!-- <param name="video-fps" value="15"/> --> <!-- <param name="video-fps" value="15"/> -->
<!-- <param name="video-auto-floor-msec" value="100"/> -->
<!-- <param name="tts-engine" value="flite"/> --> <!-- <param name="tts-engine" value="flite"/> -->
+12 -5
View File
@@ -5,9 +5,11 @@
</settings> </settings>
<profiles> <profiles>
<profile name="mine"> <profile name="default">
<param name="bind-local" value="0.0.0.0:8081"/> <param name="bind-local" value="$${local_ip_v4}:8081"/>
<param name="bind-local" value="0.0.0.0:8082" secure="true"/> <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="force-register-domain" value="$${domain}"/>
<param name="secure-combined" value="$${certs_dir}/wss.pem"/> <param name="secure-combined" value="$${certs_dir}/wss.pem"/>
<param name="secure-chain" 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="blind-reg" value="false"/>
<param name="mcast-ip" value="224.1.1.1"/> <param name="mcast-ip" value="224.1.1.1"/>
<param name="mcast-port" value="1337"/> <param name="mcast-port" value="1337"/>
<param name="rtp-ip" value="$${local_ip_v6}"/>
<param name="rtp-ip" value="$${local_ip_v4}"/> <param name="rtp-ip" value="$${local_ip_v4}"/>
<!-- <param name="ext-rtp-ip" value=""/> --> <!-- <param name="ext-rtp-ip" value=""/> -->
<param name="local-network" value="localnet.auto"/> <param name="local-network" value="localnet.auto"/>
<param name="outbound-codec-string" value="opus,vp8"/> <param name="outbound-codec-string" value="opus,vp8"/>
<param name="inbound-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"/> <param name="timer-name" value="soft"/>
</profile> </profile>
</profiles> </profiles>
</configuration> </configuration>
-2
View File
@@ -413,8 +413,6 @@
openssl ciphers -v 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' openssl ciphers -v 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH'
Will show you what is available in your verion of openssl. 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"/> <X-PRE-PROCESS cmd="set" data="sip_tls_ciphers=ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"/>
-1
View File
@@ -30,7 +30,6 @@ avoid_mods=(
endpoints/mod_opal endpoints/mod_opal
endpoints/mod_reference endpoints/mod_reference
endpoints/mod_unicall endpoints/mod_unicall
event_handlers/mod_amqp
sdk/autotools sdk/autotools
xml_int/mod_xml_ldap xml_int/mod_xml_ldap
xml_int/mod_xml_radius xml_int/mod_xml_radius
+1
View File
@@ -795,6 +795,7 @@ function refresh_devices()
//$("input[type='radio']).checkboxradio({}); //$("input[type='radio']).checkboxradio({});
$("input[type='radio']").checkboxradio("refresh"); $("input[type='radio']").checkboxradio("refresh");
$("input[type='checkbox']").checkboxradio("refresh");
//console.error($("#usecamera").find(":selected").val()); //console.error($("#usecamera").find(":selected").val());
} }
+37 -6
View File
@@ -99,6 +99,9 @@ static History *myhistory;
static HistEvent ev; static HistEvent ev;
#endif #endif
static esl_mutex_t *MUTEX = NULL;
static void _sleep_ns(int secs, long nsecs) { static void _sleep_ns(int secs, long nsecs) {
#ifndef WIN32 #ifndef WIN32
if (nsecs > 999999999) { if (nsecs > 999999999) {
@@ -720,8 +723,15 @@ static void *msg_thread_run(esl_thread_t *me, void *obj)
thread_running = 1; thread_running = 1;
while(thread_running && handle->connected) { while(thread_running && handle->connected) {
int aok = 1; int aok = 1;
esl_status_t status = esl_recv_event_timed(handle, 10, 1, NULL); esl_status_t status;
if (status == ESL_FAIL) {
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"); esl_log(ESL_LOG_WARNING, "Disconnected.\n");
running = -1; thread_running = 0; running = -1; thread_running = 0;
} else if (status == ESL_SUCCESS) { } 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) static int process_command(esl_handle_t *handle, const char *cmd)
{ {
int r = 0;
while (*cmd == ' ') cmd++; while (*cmd == ' ') cmd++;
esl_mutex_lock(MUTEX);
if ((*cmd == '/' && cmd++) || !strncasecmp(cmd, "...", 3)) { if ((*cmd == '/' && cmd++) || !strncasecmp(cmd, "...", 3)) {
if (!strcasecmp(cmd, "help")) { if (!strcasecmp(cmd, "help")) {
@@ -865,7 +878,7 @@ static int process_command(esl_handle_t *handle, const char *cmd)
!strcasecmp(cmd, "bye") !strcasecmp(cmd, "bye")
) { ) {
esl_log(ESL_LOG_INFO, "Goodbye!\nSee you at ClueCon http://www.cluecon.com/\n"); 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)) { } else if (!strncasecmp(cmd, "logfilter", 9)) {
cmd += 9; cmd += 9;
while (*cmd && *cmd == ' ') { 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); snprintf(cmd_str, sizeof(cmd_str), "api %s\nconsole_execute: true\n\n", cmd);
if (esl_send_recv(handle, cmd_str)) { if (esl_send_recv(handle, cmd_str)) {
output_printf("Socket interrupted, bye!\n"); output_printf("Socket interrupted, bye!\n");
return -1; r = -1; goto end;
} }
if (handle->last_sr_event) { if (handle->last_sr_event) {
if (handle->last_sr_event->body) { if (handle->last_sr_event->body) {
@@ -932,8 +945,12 @@ static int process_command(esl_handle_t *handle, const char *cmd)
} }
} }
} }
end: end:
return 0;
esl_mutex_unlock(MUTEX);
return r;
} }
static int get_profile(const char *name, cli_profile_t **profile) 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 { } else {
snprintf(cmd_str, sizeof(cmd_str), "api console_complete %s\n\n", buf); snprintf(cmd_str, sizeof(cmd_str), "api console_complete %s\n\n", buf);
} }
esl_send_recv(global_handle, cmd_str); esl_send_recv(global_handle, cmd_str);
if (global_handle->last_sr_event && global_handle->last_sr_event->body) { if (global_handle->last_sr_event && global_handle->last_sr_event->body) {
char *r = global_handle->last_sr_event->body; char *r = global_handle->last_sr_event->body;
char *w, *p1; 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) static unsigned char complete(EditLine *el, int ch)
{ {
const LineInfo *lf = el_line(el); 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 #endif
@@ -1378,6 +1403,9 @@ int main(int argc, char *argv[])
int loops = 2, reconnect = 0; int loops = 2, reconnect = 0;
char *ccheck; char *ccheck;
esl_mutex_create(&MUTEX);
#if HAVE_DECL_EL_PROMPT_ESC #if HAVE_DECL_EL_PROMPT_ESC
feature_level = 1; feature_level = 1;
#else #else
@@ -1755,6 +1783,9 @@ int main(int argc, char *argv[])
esl_disconnect(&handle); esl_disconnect(&handle);
global_handle = NULL; global_handle = NULL;
thread_running = 0; thread_running = 0;
esl_mutex_destroy(&MUTEX);
return 0; return 0;
} }
+2 -2
View File
@@ -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)) { if ((flags & ESL_POLL_ERROR)) {
pfds[0].events |= POLLERR; pfds[0].events |= POLLERR;
} }
s = poll(pfds, 1, ms);
s = poll(pfds, 1, ms);
if (s < 0) { if (s < 0) {
r = s; r = s;
} else if (s > 0) { } else if (s > 0) {
@@ -381,6 +381,27 @@ int tls_init_context(tls_t *tls, tls_issues_t const *ti)
#if require_client_certificate #if require_client_certificate
errno = EIO; errno = EIO;
return -1; 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 #endif
} }
+14 -1
View File
@@ -691,6 +691,7 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
ssize_t need = 2; ssize_t need = 2;
char *maskp; char *maskp;
int ll = 0; int ll = 0;
int frag = 0;
again: again:
need = 2; 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_PING:
case WSOC_PONG: case WSOC_PONG:
{ {
//int fin = (wsh->buffer[0] >> 7) & 1; int fin = (wsh->buffer[0] >> 7) & 1;
int mask = (wsh->buffer[1] >> 7) & 1; int mask = (wsh->buffer[1] >> 7) & 1;
if (fin) {
if (*oc == WSOC_CONTINUATION) {
frag = 1;
} else {
frag = 0;
}
}
if (mask) { if (mask) {
need += 4; 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); ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
goto again; goto again;
} }
if (frag) {
goto again;
}
*(wsh->payload+wsh->rplen) = '\0'; *(wsh->payload+wsh->rplen) = '\0';
+3 -3
View File
@@ -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; 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. /* This integrate and dump approach avoids rapid changes of the equalizer put step.
Rapid changes, without hysteresis, are bad. They degrade the equalizer performance Rapid changes, without hysteresis, are bad. They degrade the equalizer performance
when the true symbol boundary is close to a sample boundary. */ when the true symbol boundary is close to a sample boundary. */
//span_log(&s->logging, SPAN_LOG_FLOW, "Hop %d\n", s->gardner_integrate); //span_log(&s->logging, SPAN_LOG_FLOW, "Hop %d\n", s->gardner_integrate);
s->eq_put_step += (s->gardner_integrate/256); s->eq_put_step += (s->gardner_integrate/128);
s->total_baud_timing_correction += (s->gardner_integrate/256); s->total_baud_timing_correction += (s->gardner_integrate/128);
if (s->qam_report) if (s->qam_report)
s->qam_report(s->qam_user_data, NULL, NULL, s->gardner_integrate); s->qam_report(s->qam_user_data, NULL, NULL, s->gardner_integrate);
s->gardner_integrate = 0; s->gardner_integrate = 0;
+4
View File
@@ -125,6 +125,9 @@ typedef struct switch_core_media_params_s {
char *extrtpip; char *extrtpip;
char *rtpip; char *rtpip;
char *rtpip4;
char *rtpip6;
char *remote_ip; char *remote_ip;
int remote_port; 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_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_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_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 SWITCH_END_EXTERN_C
#endif #endif
+2 -1
View File
@@ -103,8 +103,9 @@ typedef struct icand_s {
typedef struct ice_s { typedef struct ice_s {
icand_t cands[MAX_CAND][2]; icand_t cands[MAX_CAND][2];
int cand_idx; int cand_idx[2];
int chosen[2]; int chosen[2];
int is_chosen[2];
char *ufrag; char *ufrag;
char *pwd; char *pwd;
char *options; char *options;
+2
View File
@@ -197,6 +197,8 @@ SWITCH_DECLARE(char *) switch_stun_host_lookup(const char *host, switch_memory_p
\return true or false \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_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 \brief Extract a username from a packet attribute
+1
View File
@@ -1052,6 +1052,7 @@ static inline int switch_needs_url_encode(const char *s)
return 0; 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_encode(const char *url, char *buf, size_t len);
SWITCH_DECLARE(char *) switch_url_decode(char *s); SWITCH_DECLARE(char *) switch_url_decode(char *s);
SWITCH_DECLARE(switch_bool_t) switch_simple_email(const char *to, SWITCH_DECLARE(switch_bool_t) switch_simple_email(const char *to,
@@ -25,7 +25,7 @@
* *
* Marc Olivier Chouinard <mochouinard@moctel.com> * Marc Olivier Chouinard <mochouinard@moctel.com>
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com> * Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
* * Ítalo Rossi <italorossib@gmail.com>
* *
* mod_callcenter.c -- Call Center Module * 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_number = NULL;
const char *cid_name_prefix = NULL; const char *cid_name_prefix = NULL;
if ((cid_name_prefix = switch_channel_get_variable(member_channel, "cc_outbound_cid_name_prefix"))) { if (!(cid_name = switch_channel_get_variable(member_channel, "effective_caller_id_name"))) {
cid_name_freeable = switch_mprintf("%s%s", cid_name_prefix, h->member_cid_name); cid_name = 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_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_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_queue", "%s", h->queue_name);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_uuid", "%s", h->member_uuid); 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; agent_callback_t cbt;
const char *member_state = NULL; const char *member_state = NULL;
const char *member_abandoned_epoch = NULL; const char *member_abandoned_epoch = NULL;
const char *serving_agent = NULL;
memset(&cbt, 0, sizeof(cbt)); memset(&cbt, 0, sizeof(cbt));
cbt.queue_name = argv[0]; 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]; cbt.member_score = argv[6];
member_state = argv[7]; member_state = argv[7];
member_abandoned_epoch = argv[8]; member_abandoned_epoch = argv[8];
serving_agent = argv[9];
if (!cbt.queue_name || !(queue = get_queue(cbt.queue_name))) { 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); 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 */ /* Skip this member */
goto end; 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 */ /* Check if member is in the queue waiting */
if (zstr(cbt.member_session_uuid)) { 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) { while (globals.running == 1) {
char *sql = NULL; 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", " WHERE state = '%q' OR state = '%q' OR (serving_agent = 'ring-all' AND state = '%q') ORDER BY score DESC",
local_epoch_time_now(NULL), 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)); 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"); const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score");
int cc_base_score_int = 0; int cc_base_score_int = 0;
const char *cur_moh = NULL; const char *cur_moh = NULL;
char *moh_expanded = NULL;
char start_epoch[64]; char start_epoch[64];
switch_event_t *event; switch_event_t *event;
switch_time_t t_member_called = local_epoch_time_now(NULL); 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); cur_moh = switch_core_session_strdup(member_session, queue->moh);
} }
queue_rwunlock(queue); queue_rwunlock(queue);
moh_expanded = switch_channel_expand_variables(member_channel, cur_moh);
while (switch_channel_ready(member_channel)) { while (switch_channel_ready(member_channel)) {
switch_input_args_t args = { 0 }; switch_input_args_t args = { 0 };
@@ -2701,9 +2720,8 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_core_session_flush_private_events(member_session); switch_core_session_flush_private_events(member_session);
if (moh_valid && cur_moh) { if (moh_valid && moh_expanded) {
switch_status_t status = switch_ivr_play_file(member_session, NULL, cur_moh, &args); 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)) { 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 */ /* 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); 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); 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 */ /* 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"))) { 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; struct conf_fps video_fps;
int playing_video_file; int playing_video_file;
int recording_members; int recording_members;
uint32_t video_floor_packets;
} conference_obj_t; } conference_obj_t;
/* Relationship with another member */ /* Relationship with another member */
@@ -682,6 +683,7 @@ struct conference_member {
switch_frame_buffer_t *fb; switch_frame_buffer_t *fb;
switch_image_t *avatar_png_img; switch_image_t *avatar_png_img;
switch_image_t *video_mute_img; switch_image_t *video_mute_img;
uint32_t floor_packets;
int blanks; int blanks;
int managed_kps; int managed_kps;
int blackouts; 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) 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); size = switch_queue_size(imember->video_queue);
} while(size > 0); } 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) { if (img) {
imember->good_img++; imember->good_img++;
if ((imember->good_img % (int)(conference->video_fps.fps * 10)) == 0) { 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) { //if (layer) {
//layer->is_avatar = 1; //layer->is_avatar = 1;
//} //}
imember->auto_avatar = 1; imember->auto_avatar = 1;
} }
} }
} }
} }
} else { } else {
int flushed = flush_video_queue(imember->video_queue); check_flush(imember);
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 {
}
} }
layer = NULL; 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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Adding video floor %s\n",
switch_channel_get_name(member->channel)); switch_channel_get_name(member->channel));
check_flush(member);
switch_core_session_video_reinit(member->session); switch_core_session_video_reinit(member->session);
conference->video_floor_holder = member->id; conference->video_floor_holder = member->id;
member_update_status_field(member); 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; conference_member_t *old_member = NULL;
int old_id = 0; 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) {
if (conference->floor_holder == member) { if (conference->floor_holder == member) {
return; return;
@@ -4531,6 +4528,7 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference
if (old_member) { if (old_member) {
old_id = old_member->id; old_id = old_member->id;
member_update_status_field(old_member); member_update_status_field(old_member);
old_member->floor_packets = 0;
} }
switch_set_flag(conference, CFLAG_FLOOR_CHANGE); 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); check_agc_levels(member);
clear_avg(member); clear_avg(member);
member->score_iir = 0; member->score_iir = 0;
member->floor_packets = 0;
if (test_eflag(member->conference, EFLAG_STOP_TALKING) && if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { 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) { if (member->volume_in_level) {
switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, 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) { 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); 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; 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)) { if (noise_gate_check(member)) {
uint32_t diff = member->score - member->energy_level; uint32_t diff = member->score - member->energy_level;
if (hangover_hits) { if (hangover_hits) {
@@ -6442,16 +6437,20 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
member->nt_tally = 0; member->nt_tally = 0;
} }
if (member == member->conference->floor_holder) {
member->floor_packets++;
}
if (diff >= diff_level || ++hangunder_hits >= hangunder) { if (diff >= diff_level || ++hangunder_hits >= hangunder) {
hangover_hits = hangunder_hits = 0; hangover_hits = hangunder_hits = 0;
member->last_talking = switch_epoch_time_now(NULL); member->last_talking = switch_epoch_time_now(NULL);
if (!switch_test_flag(member, MFLAG_TALKING)) { if (!switch_test_flag(member, MFLAG_TALKING)) {
switch_set_flag_locked(member, MFLAG_TALKING); switch_set_flag_locked(member, MFLAG_TALKING);
member_update_status_field(member); member_update_status_field(member);
member->floor_packets = 0;
if (test_eflag(member->conference, EFLAG_START_TALKING) && switch_test_flag(member, MFLAG_CAN_SPEAK) && 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) { switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_member_data(member, event); 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; 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++; loops++;
@@ -11479,7 +11485,7 @@ static void clear_eflags(char *events, uint32_t *f)
} else if (!strcmp(event, "play-file")) { } else if (!strcmp(event, "play-file")) {
*f &= ~EFLAG_PLAY_FILE; *f &= ~EFLAG_PLAY_FILE;
} else if (!strcmp(event, "play-file-done")) { } else if (!strcmp(event, "play-file-done")) {
*f &= ~EFLAG_PLAY_FILE; *f &= ~EFLAG_PLAY_FILE_DONE;
} else if (!strcmp(event, "play-file-member")) { } else if (!strcmp(event, "play-file-member")) {
*f &= ~EFLAG_PLAY_FILE_MEMBER; *f &= ~EFLAG_PLAY_FILE_MEMBER;
} else if (!strcmp(event, "speak-text")) { } 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 *suppress_events = NULL;
char *verbose_events = NULL; char *verbose_events = NULL;
char *auto_record = NULL; char *auto_record = NULL;
int min_recording_participants = 2; int min_recording_participants = 1;
char *conference_log_dir = NULL; char *conference_log_dir = NULL;
char *cdr_event_mode = NULL; char *cdr_event_mode = NULL;
char *terminate_on_silence = 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_codec_implementation_t read_impl = { 0 };
switch_channel_t *channel = NULL; switch_channel_t *channel = NULL;
const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = 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 */ /* Validate the conference name */
if (zstr(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)) { } else if (switch_true(val)) {
comfort_noise_level = 1400; 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)) { } else if (!strcasecmp(var, "sound-prefix") && !zstr(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "override sound-prefix with: %s\n", val); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "override sound-prefix with: %s\n", val);
sound_prefix = 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)) { } else if (!strcasecmp(var, "auto-record") && !zstr(val)) {
auto_record = val; auto_record = val;
} else if (!strcasecmp(var, "min-required-recording-participants") && !zstr(val)) { } else if (!strcasecmp(var, "min-required-recording-participants") && !zstr(val)) {
if (!strcmp(val, "1")) { if (!strcmp(val, "2")) {
min_recording_participants = 1;
} else if (!strcmp(val, "2")) {
min_recording_participants = 2; min_recording_participants = 2;
} else { } else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "min-required-recording-participants is invalid, leaving set to %d\n", min_recording_participants); 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_dtmf_timeout = ivr_dtmf_timeout;
conference->ivr_input_timeout = ivr_input_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; conference->eflags = 0xFFFFFFFF;
if (!zstr(suppress_events)) { if (!zstr(suppress_events)) {
@@ -50,6 +50,7 @@
*/ */
#include <switch.h> #include <switch.h>
#include <math.h>
typedef struct { typedef struct {
switch_time_t lastts; /* Last time we did any billing */ 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 */ 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 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; } 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 nobal_amt = globals.nobal_amt;
double lowbal_amt = globals.lowbal_amt; double lowbal_amt = globals.lowbal_amt;
double balance; 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) { if (!session) {
/* Why are we here? */ /* 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")); 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 */ /* Return if there's no billing information on this session */
if (!billrate || !billaccount) { if (!billrate || !billaccount) {
return SWITCH_STATUS_SUCCESS; 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 */ /* See if this person has enough money left to continue the call */
balance = get_balance(billaccount, channel); 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); balance_check = balance - minimum_charge;
if (balance <= nobal_amt) { 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 */ /* 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", 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); balance, nobal_amt, billaccount);
@@ -530,6 +549,12 @@ static switch_status_t do_billing(switch_core_session_t *session)
return SWITCH_STATUS_SUCCESS; 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 */ /* Have we done any billing on this channel yet? If no, set up vars for doing so */
if (!nibble_data) { if (!nibble_data) {
nibble_data = switch_core_session_alloc(session, sizeof(*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_time_exp_lt(&tm, nibble_data->lastts);
switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm); 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", 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 ((ts - nibble_data->lastts) >= 0) {
/* If billincrement is set we bill by it and not by time elapsed */ /* 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 { } else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n"); 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 { } else {
if (switch_strlen_zero(billincrement)) 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); 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); do_billing(session);
billaccount = switch_channel_get_variable(channel, globals.var_name_account); billaccount = switch_channel_get_variable(channel, globals.var_name_account);
if (billaccount) { if (billaccount) {
switch_channel_set_variable_printf(channel, "nibble_current_balance", "%f", get_balance(billaccount, channel)); switch_channel_set_variable_printf(channel, "nibble_current_balance", "%f", get_balance(billaccount, channel));
} }
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
+3 -3
View File
@@ -152,7 +152,7 @@ static switch_status_t switch_codec2_encode(switch_codec_t *codec, switch_codec_
fflush(context->encoder_out); fflush(context->encoder_out);
#endif #endif
*encoded_data_len = 8; *encoded_data_len = 6;
return SWITCH_STATUS_SUCCESS; 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); *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_core_codec_add_implementation(pool, codec_interface,
SWITCH_CODEC_TYPE_AUDIO, SWITCH_CODEC_TYPE_AUDIO,
@@ -239,7 +239,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load)
NULL, NULL,
8000, /* samples/sec */ 8000, /* samples/sec */
8000, /* samples/sec */ 8000, /* samples/sec */
2550, /* bps */ 2400, /* bps */
20000, /* ptime */ 20000, /* ptime */
CODEC2_SAMPLES_PER_FRAME, /* samples decoded */ CODEC2_SAMPLES_PER_FRAME, /* samples decoded */
CODEC2_SAMPLES_PER_FRAME*2, /* bytes decoded */ CODEC2_SAMPLES_PER_FRAME*2, /* bytes decoded */
+37 -4
View File
@@ -74,6 +74,7 @@ struct opus_context {
OpusDecoder *decoder_object; OpusDecoder *decoder_object;
uint32_t enc_frame_size; uint32_t enc_frame_size;
uint32_t dec_frame_size; uint32_t dec_frame_size;
uint32_t counter_plc_fec;
}; };
struct { struct {
@@ -338,7 +339,7 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
return SWITCH_STATUS_GENERR; return SWITCH_STATUS_GENERR;
} }
context->counter_plc_fec = 0;
} }
codec->private_info = context; codec->private_info = context;
@@ -352,6 +353,7 @@ static switch_status_t switch_opus_destroy(switch_codec_t *codec)
if (context) { if (context) {
if (context->decoder_object) { 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); opus_decoder_destroy(context->decoder_object);
context->decoder_object = NULL; context->decoder_object = NULL;
} }
@@ -400,9 +402,13 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
unsigned int *flag) unsigned int *flag)
{ {
struct opus_context *context = codec->private_info; 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; int samples = 0;
uint32_t frame_size; uint32_t frame_size;
uint32_t frame_samples; uint32_t frame_samples;
uint32_t found_frame;
if (!context) { if (!context) {
return SWITCH_STATUS_FALSE; 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_samples = *decoded_data_len / 2 / codec->implementation->number_of_channels;
frame_size = frame_samples - (frame_samples % (codec->implementation->actual_samples_per_second / 400)); 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) { 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)); 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; codec_interface->parse_fmtp = switch_opus_fmtp_parse;
settings = default_codec_settings; 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++) { for (x = 0; x < 3; x++) {
settings.ptime = mss / 1000; 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)) { if ((all && !fail) || (!all && pass)) {
anti_action = SWITCH_FALSE; anti_action = SWITCH_FALSE;
} }
if (all && total != pass) {
proceed = 1;
pass = 0;
fail++;
anti_action = SWITCH_TRUE;
}
} }
switch_safe_free(field_expanded); switch_safe_free(field_expanded);
+1 -1
View File
@@ -47,7 +47,7 @@
#define RTMP_DEFAULT_PORT 1935 #define RTMP_DEFAULT_PORT 1935
#define RTMP_TCP_READ_BUF 2048 * 16 #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_NONE 0x0000
#define SUPPORT_SND_ADPCM 0x0002 #define SUPPORT_SND_ADPCM 0x0002
+89 -2
View File
@@ -1464,6 +1464,86 @@ static int flush_listener_callback(void *pArg, int argc, char **argv, char **col
return 0; 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) void skinny_clean_device_from_db(listener_t *listener, char *device_name)
{ {
if(!zstr(device_name)) { if(!zstr(device_name)) {
@@ -1579,7 +1659,9 @@ static void flush_listener(listener_t *listener)
switch_safe_free(sql); switch_safe_free(sql);
} }
skinny_lock_device_name(listener, listener->device_name);
skinny_clean_listener_from_db(listener); skinny_clean_listener_from_db(listener);
skinny_unlock_device_name(listener, listener->device_name);
strcpy(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", switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Killing listener %s:%d.\n",
listener->device_name, listener->device_instance); 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); close_socket(&listener->sock, listener->profile);
return SWITCH_STATUS_SUCCESS; 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"); 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); switch_set_flag_locked(listener, LFLAG_RUNNING);
keepalive_listener(listener, NULL); keepalive_listener(listener, NULL);
add_listener(listener); add_listener(listener);
while (listener_is_ready(listener)) { while (listener_is_ready(listener)) {
status = skinny_read_packet(listener, &request); 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->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool);
switch_mutex_init(&profile->flag_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) { for (param = switch_xml_child(xsettings, "param"); param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name"); char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value"); char *val = (char *) switch_xml_attr_soft(param, "value");
@@ -2233,6 +2318,8 @@ static switch_status_t load_skinny_config(void)
continue; continue;
} }
/* Device Name Locks */
switch_core_hash_init(&profile->device_name_lock_hash);
/* Device types */ /* Device types */
switch_core_hash_init(&profile->device_type_params_hash); switch_core_hash_init(&profile->device_type_params_hash);
+27
View File
@@ -127,6 +127,9 @@ struct skinny_profile {
int non_blocking; int non_blocking;
switch_hash_t *soft_key_set_sets_hash; switch_hash_t *soft_key_set_sets_hash;
switch_hash_t *device_type_params_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 */ /* extensions */
char *ext_voicemail; char *ext_voicemail;
char *ext_redial; char *ext_redial;
@@ -169,6 +172,23 @@ typedef enum {
SKINNY_ACTION_WAIT SKINNY_ACTION_WAIT
} skinny_action_t; } 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 */ /* LISTENERS TYPES */
/*****************************************************************************/ /*****************************************************************************/
@@ -197,6 +217,7 @@ struct listener {
switch_mutex_t *flag_mutex; switch_mutex_t *flag_mutex;
uint32_t flags; uint32_t flags;
time_t expire_time; time_t expire_time;
time_t connect_time;
switch_time_t digit_timeout_time; switch_time_t digit_timeout_time;
struct listener *next; struct listener *next;
char *ext_voicemail; 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_listener_from_db(listener_t *listener);
void skinny_clean_device_from_db(listener_t *listener, char *device_name); 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 */ /* CHANNEL FUNCTIONS */
/*****************************************************************************/ /*****************************************************************************/
+11 -1
View File
@@ -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"); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "action", "skinny-auth");
/* clean up all traces before adding to database */ /* 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); 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) { 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" 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" "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); , 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"); send_register_reject(listener, "Device not found");
status = SWITCH_STATUS_FALSE; status = SWITCH_STATUS_FALSE;
goto end; 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, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Device %s:%d is already registered on another listener.\n", "Device %s:%d is already registered on another listener.\n",
request->data.reg.device_name, request->data.reg.instance); 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"); send_register_reject(listener, "Device is already registered on another listener");
status = SWITCH_STATUS_FALSE; status = SWITCH_STATUS_FALSE;
goto end; goto end;
@@ -1156,11 +1165,12 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r
switch_safe_free(sql); switch_safe_free(sql);
} }
switch_copy_string(listener->device_name, request->data.reg.device_name, 16); switch_copy_string(listener->device_name, request->data.reg.device_name, 16);
listener->device_instance = request->data.reg.instance; listener->device_instance = request->data.reg.instance;
listener->device_type = request->data.reg.device_type; listener->device_type = request->data.reg.device_type;
skinny_unlock_device_name(listener, request->data.reg.device_name);
xskinny = switch_xml_child(xuser, "skinny"); xskinny = switch_xml_child(xuser, "skinny");
if (xskinny) { if (xskinny) {
if ((xparams = switch_xml_child(xskinny, "params"))) { if ((xparams = switch_xml_child(xskinny, "params"))) {
+28 -1
View File
@@ -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) 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); switch_channel_t *channel = switch_core_session_get_channel(session);
private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
switch_status_t status = SWITCH_STATUS_SUCCESS; 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); 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)) { 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); 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, "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, "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); 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++) { for (x = 0; x < profile->rtpip_index; x++) {
stream->write_function(stream, "RTP-IP \t%s\n", switch_str_nil(profile->rtpip[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) { if (profile->extrtpip) {
stream->write_function(stream, "Ext-RTP-IP \t%s\n", 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++) { for (x = 0; x < profile->rtpip_index; x++) {
stream->write_function(stream, " <rtp-ip>%s</rtp-ip>\n", switch_str_nil(profile->rtpip[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) { if (profile->extrtpip) {
stream->write_function(stream, " <ext-rtp-ip>%s</ext-rtp-ip>\n", 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)) { 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++; rb++;
} }
} }
+5
View File
@@ -96,6 +96,7 @@ typedef struct private_object private_object_t;
#define MY_EVENT_RECOVERY_RECOVERED "sofia::recovery_recovered" #define MY_EVENT_RECOVERY_RECOVERED "sofia::recovery_recovered"
#define MY_EVENT_ERROR "sofia::error" #define MY_EVENT_ERROR "sofia::error"
#define MY_EVENT_PROFILE_START "sofia::profile_start" #define MY_EVENT_PROFILE_START "sofia::profile_start"
#define MY_EVENT_NOTIFY_WATCHED_HEADER "sofia::notify_watched_header"
#define MULTICAST_EVENT "multicast::event" #define MULTICAST_EVENT "multicast::event"
#define SOFIA_REPLACES_HEADER "_sofia_replaces_" #define SOFIA_REPLACES_HEADER "_sofia_replaces_"
@@ -574,11 +575,14 @@ struct sofia_profile {
char *shutdown_type; char *shutdown_type;
char *extrtpip; char *extrtpip;
char *rtpip[MAX_RTPIP]; char *rtpip[MAX_RTPIP];
char *rtpip6[MAX_RTPIP];
char *jb_msec; char *jb_msec;
switch_payload_t te; switch_payload_t te;
switch_payload_t recv_te; switch_payload_t recv_te;
uint32_t rtpip_index; uint32_t rtpip_index;
uint32_t rtpip_next; uint32_t rtpip_next;
uint32_t rtpip_index6;
uint32_t rtpip_next6;
char *rtcp_audio_interval_msec; char *rtcp_audio_interval_msec;
char *rtcp_video_interval_msec; char *rtcp_video_interval_msec;
@@ -805,6 +809,7 @@ struct private_object {
sofia_cid_type_t cid_type; sofia_cid_type_t cid_type;
uint32_t session_timeout; uint32_t session_timeout;
enum nua_session_refresher session_refresher; enum nua_session_refresher session_refresher;
char **watch_headers;
char *respond_phrase; char *respond_phrase;
int respond_code; int respond_code;
char *respond_dest; char *respond_dest;
+108 -5
View File
@@ -1136,6 +1136,7 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
} }
if (!fs) { if (!fs) {
sip_remote_party_id_t *rpid;
if ((passerted = sip_p_asserted_identity(sip))) { if ((passerted = sip_p_asserted_identity(sip))) {
if (passerted->paid_url->url_user) { if (passerted->paid_url->url_user) {
number = 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'; 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 //sofia_dispatch_event_t *de
static void our_sofia_event_callback(nua_event_t event, 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)) { 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; 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); sofia_handle_sip_i_info(nua, profile, nh, session, sip, de, tags);
break; break;
case nua_i_update: case nua_i_update:
sofia_update_callee_id(session, profile, sip, SWITCH_TRUE);
break; break;
case nua_r_update: case nua_r_update:
if (session && tech_pvt && locked) { 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->ob_failed_calls = 0;
profile->shutdown_type = "false"; profile->shutdown_type = "false";
profile->rtpip_index = 0; profile->rtpip_index = 0;
profile->rtpip_index6 = 0;
if (xprofiledomain) { if (xprofiledomain) {
profile->domain_name = switch_core_strdup(profile->pool, 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 { } else {
ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip; 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 { } 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")) { } else if (!strcasecmp(var, "sip-ip")) {
char *ip = mod_sofia_globals.guess_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); 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); 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"); 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"); 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"); 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))) { if ((a_session = switch_core_session_locate(br_a))) {
const char *moh = profile->hold_music; 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_channel_t *a_channel = switch_core_session_get_channel(a_session);
switch_caller_profile_t *prof = switch_channel_get_caller_profile(channel_b); switch_caller_profile_t *prof = switch_channel_get_caller_profile(channel_b);
const char *tmp; const char *tmp;
@@ -7941,6 +8034,15 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
} else { } else {
switch_ivr_session_transfer(a_session, "park", "inline", NULL); 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); 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); sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
switch_channel_set_variable(channel_b, "park_timeout", "2:attended_transfer"); switch_channel_set_variable(channel_b, "park_timeout", "2:attended_transfer");
switch_channel_set_state(channel_b, CS_PARK); switch_channel_set_state(channel_b, CS_PARK);
switch_channel_wait_for_state_timeout(channel_b, CS_PARK, 5000);
} else { } else {
if (!br_a && !br_b) { if (!br_a && !br_b) {
+19 -3
View File
@@ -92,9 +92,25 @@ void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t *
tech_pvt->profile = profile; tech_pvt->profile = profile;
tech_pvt->mparams.rtpip = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next++]); if (!zstr(profile->rtpip[profile->rtpip_next])) {
if (profile->rtpip_next >= profile->rtpip_index) { tech_pvt->mparams.rtpip4 = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next++]);
profile->rtpip_next = 0; 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++; profile->inuse++;
+26 -4
View File
@@ -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 *agent = "unknown";
const char *pres_on_reg = NULL; const char *pres_on_reg = NULL;
int send_pres = 0; int send_pres = 0;
int send_message_query = 0;
int is_tls = 0, is_tcp = 0, is_ws = 0, is_wss = 0; int is_tls = 0, is_tcp = 0, is_ws = 0, is_wss = 0;
char expbuf[35] = ""; char expbuf[35] = "";
time_t reg_time = switch_epoch_time_now(NULL); 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 *sw_reg_host;
char *token_val = NULL; char *token_val = NULL;
if (sofia_private_p) { if (sofia_private_p) {
sofia_private = *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; reg_meta = var;
} }
/* associated MWI account */
if (v_event && *v_event && (mwi_account = switch_event_get_header(*v_event, "mwi-account"))) { if (v_event && *v_event && (mwi_account = switch_event_get_header(*v_event, "mwi-account"))) {
dup_mwi_account = strdup(mwi_account); dup_mwi_account = strdup(mwi_account);
switch_assert(dup_mwi_account != NULL); 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; 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) { if (regtype != REG_REGISTER) {
switch_goto_int(r, 0, end); 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); switch_snprintf(exp_param, sizeof(exp_param), "expires=%ld", exptime);
sip_contact_add_param(nua_handle_home(nh), sip->sip_contact, exp_param); sip_contact_add_param(nua_handle_home(nh), sip->sip_contact, exp_param);
if ((sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER) || /* send unsolicited MWI if configured */
(reg_count == 1 && sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER))) && debounce_ok) { 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) { 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(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); switch_event_add_header_string(s_mwi_event, SWITCH_STACK_BOTTOM, "VM-Sofia-Profile", profile->name);
+79 -26
View File
@@ -58,16 +58,29 @@
int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, mcast_flag_t flags) int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, mcast_flag_t flags)
{ {
uint32_t one = 1; uint32_t one = 1;
int family = AF_INET;
memset(handle, 0, sizeof(*handle)); memset(handle, 0, sizeof(*handle));
if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(AF_INET, SOCK_DGRAM, 0)) <= 0 ) { if (strchr(host, ':')) {
return -1; family = AF_INET6;
} }
handle->send_addr.sin_family = AF_INET; if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(family, SOCK_DGRAM, 0)) <= 0 ) {
handle->send_addr.sin_addr.s_addr = inet_addr(host); return -1;
handle->send_addr.sin_port = htons(port); }
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 ) { if ( setsockopt(handle->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) != 0 ) {
close(handle->sock); 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)) { 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; mreq.imr_multiaddr.s_addr = inet_addr(host);
handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY); mreq.imr_interface.s_addr = htonl(INADDR_ANY);
handle->recv_addr.sin_port = htons(port);
mreq.imr_multiaddr.s_addr = inet_addr(host); if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
mreq.imr_interface.s_addr = htonl(INADDR_ANY); close(handle->sock);
handle->sock = -1;
return -1;
}
if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) {
close(handle->sock); close(handle->sock);
handle->sock = -1; handle->sock = -1;
return -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; 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); 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) 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
} }
} }
if (handle->family == AF_INET6) {
return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen); 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; unsigned char ttl;
struct sockaddr_in send_addr; struct sockaddr_in send_addr;
struct sockaddr_in recv_addr; struct sockaddr_in recv_addr;
struct sockaddr_in6 send_addr6;
struct sockaddr_in6 recv_addr6;
int family;
unsigned char buffer[65536]; unsigned char buffer[65536];
int ready; int ready;
} mcast_handle_t; } mcast_handle_t;
+189 -93
View File
@@ -143,7 +143,7 @@ static void verto_deinit_ssl(verto_profile_t *profile)
static void close_file(ws_socket_t *sock) static void close_file(ws_socket_t *sock)
{ {
if (*sock > -1) { if (*sock != ws_sock_invalid) {
#ifndef WIN32 #ifndef WIN32
close(*sock); close(*sock);
#else #else
@@ -155,7 +155,7 @@ static void close_file(ws_socket_t *sock)
static void close_socket(ws_socket_t *sock) static void close_socket(ws_socket_t *sock)
{ {
if (*sock > -1) { if (*sock != ws_sock_invalid) {
shutdown(*sock, 2); shutdown(*sock, 2);
close_file(sock); close_file(sock);
} }
@@ -1803,12 +1803,6 @@ error:
static void client_run(jsock_t *jsock) 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 (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) { if (jsock->profile->vhosts) {
http_run(jsock); 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->vars);
switch_event_destroy(&jsock->user_vars); switch_event_destroy(&jsock->user_vars);
if (jsock->client_socket > -1) { if (jsock->client_socket != ws_sock_invalid) {
close_socket(&jsock->client_socket); 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; 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) { if (!zstr(profile->rtpip6[profile->rtpip_cur6])) {
profile->rtpip_cur = 0; 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; 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), switch_either(jsock->dialplan, jsock->profile->dialplan),
caller_id_name, caller_id_name,
caller_id_number, caller_id_number,
inet_ntoa(jsock->remote_addr.sin_addr), jsock->remote_host,
cJSON_GetObjectCstr(dialog, "ani"), cJSON_GetObjectCstr(dialog, "ani"),
cJSON_GetObjectCstr(dialog, "aniii"), cJSON_GetObjectCstr(dialog, "aniii"),
cJSON_GetObjectCstr(dialog, "rdnis"), 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); jevent = cJSON_Duplicate(params, 1);
switch_event_channel_broadcast(event_channel, &jevent, modname, globals.event_channel_id); 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 ((json_text = cJSON_PrintUnformatted(params))) {
if ( mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1) < 0 ) { 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; jsock_t *jsock = NULL;
int flag = 1; 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 = (jsock_t *) switch_core_alloc(pool, sizeof(*jsock));
jsock->pool = pool; 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) { if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) {
die("ACCEPT FAILED\n"); 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++) { 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; jsock->profile = profile;
if (zstr(jsock->name)) { 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; 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); 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) { 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_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); switch_event_fire(&s_event);
} }
@@ -3863,7 +3894,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
error: error:
if (jsock) { if (jsock) {
if (jsock->client_socket > -1) { if (jsock->client_socket != ws_sock_invalid) {
close_socket(&jsock->client_socket); close_socket(&jsock->client_socket);
} }
@@ -3873,7 +3904,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
return -1; 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; ws_socket_t sock = ws_sock_invalid;
#ifndef WIN32 #ifndef WIN32
@@ -3881,29 +3912,48 @@ static ws_socket_t prepare_socket(int ip, uint16_t port)
#else #else
char reuse_addr = 1; char reuse_addr = 1;
#endif #endif
int family;
struct sockaddr_in addr; 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"); die("Socket Error!\n");
} }
if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) { if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) {
die("Socket setsockopt Error!\n"); 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) { if (listen(sock, MAXPENDING) < 0) {
die("Listen error\n"); die("Listen error\n");
} }
ips->family = family;
return sock; return sock;
error: 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) 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) { if (bytes > 0) {
cJSON *json; 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) { if (profile->mcast_ip && pfds[x].sock == (switch_os_socket_t)profile->mcast_sub.sock) {
handle_mcast_sub(profile); handle_mcast_sub(profile);
} else { } 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) static void kill_profile(verto_profile_t *profile)
{ {
jsock_t *p; 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) static void do_shutdown(void)
{ {
globals.running = 0; globals.running = 0;
@@ -4105,20 +4176,35 @@ static void do_shutdown(void)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Done\n"); 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; char *p;
struct hostent *hent; //struct hostent *hent;
strncpy(host, input, 255); if ((p = strchr(input, '['))) {
char *end = switch_find_end_paren(p, '[', ']');
host[255] = 0; if (end) {
p++;
if ((p = strchr(host, ':')) != NULL) { strncpy(host, p, end - p);
*p++ = '\0'; if (*(end+1) == ':' && end + 2 < end_of_p(input)) {
*port = (uint16_t)atoi(p); 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' ) { if ( host[0] < '0' || host[0] > '9' ) {
// Non-numeric host (at least it doesn't start with one). Convert it to ip addr first // Non-numeric host (at least it doesn't start with one). Convert it to ip addr first
if ((hent = gethostbyname(host)) != NULL) { 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 { } else {
*addr = inet_addr(host); *addr = inet_addr(host);
} }
#endif
} }
static verto_profile_t *find_profile(const char *name) static verto_profile_t *find_profile(const char *name)
{ {
verto_profile_t *p, *r = NULL; verto_profile_t *p, *r = NULL;
@@ -4264,7 +4352,7 @@ static switch_status_t parse_config(const char *cf)
if (!strcasecmp(var, "bind-local")) { if (!strcasecmp(var, "bind-local")) {
const char *secure = switch_xml_attr_soft(param, "secure"); const char *secure = switch_xml_attr_soft(param, "secure");
if (i < MAX_BIND) { 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)) { if (switch_true(secure)) {
profile->ip[profile->i].secure = 1; profile->ip[profile->i].secure = 1;
} }
@@ -4316,10 +4404,18 @@ static switch_status_t parse_config(const char *cf)
if (zstr(val)) { if (zstr(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid RTP IP.\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid RTP IP.\n");
} else { } else {
if (profile->rtpip_index < MAX_RTPIP -1) { if (strchr(val, ':')) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, 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 { } 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")) { } else if (!strcasecmp(var, "ext-rtp-ip")) {
+13 -5
View File
@@ -106,9 +106,8 @@ struct jsock_s {
unsigned char buf[65535]; unsigned char buf[65535];
char *name; char *name;
jsock_type_t ptype; jsock_type_t ptype;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr; struct sockaddr_in remote_addr;
struct sockaddr_in send_addr; struct sockaddr_in6 remote_addr6;
#ifndef WIN32 #ifndef WIN32
struct passwd pw; struct passwd pw;
#endif #endif
@@ -132,6 +131,11 @@ struct jsock_s {
char *dialplan; char *dialplan;
char *context; char *context;
char remote_host[256];
int remote_port;
int family;
struct verto_profile_s *profile; struct verto_profile_s *profile;
switch_thread_rwlock_t *rwlock; switch_thread_rwlock_t *rwlock;
@@ -155,12 +159,12 @@ typedef struct jsock_s jsock_t;
#define MAX_BIND 25 #define MAX_BIND 25
#define MAX_RTPIP 25 #define MAX_RTPIP 25
struct ips { typedef struct ips {
char local_ip[256]; char local_ip[256];
in_addr_t local_ip_addr;
uint16_t local_port; uint16_t local_port;
int secure; int secure;
}; int family;
} ips_t;
typedef enum { typedef enum {
TFLAG_SENT_MEDIA = (1 << 0), TFLAG_SENT_MEDIA = (1 << 0),
@@ -240,6 +244,10 @@ struct verto_profile_s {
int rtpip_index; int rtpip_index;
int rtpip_cur; int rtpip_cur;
char *rtpip6[MAX_RTPIP];
int rtpip_index6;
int rtpip_cur6;
char *cand_acl[SWITCH_MAX_CAND_ACL]; char *cand_acl[SWITCH_MAX_CAND_ACL];
uint32_t cand_acl_count; uint32_t cand_acl_count;
+14 -1
View File
@@ -691,6 +691,7 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
ssize_t need = 2; ssize_t need = 2;
char *maskp; char *maskp;
int ll = 0; int ll = 0;
int frag = 0;
again: again:
need = 2; 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_PING:
case WSOC_PONG: case WSOC_PONG:
{ {
//int fin = (wsh->buffer[0] >> 7) & 1; int fin = (wsh->buffer[0] >> 7) & 1;
int mask = (wsh->buffer[1] >> 7) & 1; int mask = (wsh->buffer[1] >> 7) & 1;
if (fin) {
if (*oc == WSOC_CONTINUATION) {
frag = 1;
} else {
frag = 0;
}
}
if (mask) { if (mask) {
need += 4; 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); ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
goto again; goto again;
} }
if (frag) {
goto again;
}
*(wsh->payload+wsh->rplen) = '\0'; *(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)); sp->uuid_str, switch_channel_state_name(sp->channel_state));
ei_x_new_with_version(&ebuf); ei_x_new_with_version(&ebuf);
ei_x_encode_tuple_header(&ebuf, 2);
ei_x_encode_atom(&ebuf, "call_hangup"); ei_x_encode_atom(&ebuf, "call_hangup");
_ei_x_encode_string(&ebuf, sp->uuid_str);
switch_mutex_lock(listener->sock_mutex); switch_mutex_lock(listener->sock_mutex);
ei_sendto(listener->ec, listener->sockfd, &sp->process, &ebuf); ei_sendto(listener->ec, listener->sockfd, &sp->process, &ebuf);
(*msgs_sent)++; (*msgs_sent)++;
@@ -401,8 +401,12 @@ SWITCH_STANDARD_APP(socket_function)
listener_t *listener; listener_t *listener;
int argc = 0, x = 0; int argc = 0, x = 0;
char *argv[80] = { 0 }; char *argv[80] = { 0 };
char *hosts[50] = { 0 };
unsigned int hosts_count = 0;
switch_status_t connected = SWITCH_STATUS_FALSE;
char *mydata; char *mydata;
switch_channel_t *channel = NULL; switch_channel_t *channel = NULL;
char errbuf[512] = {0};
channel = switch_core_session_get_channel(session); channel = switch_core_session_get_channel(session);
@@ -415,47 +419,58 @@ SWITCH_STANDARD_APP(socket_function)
return; return;
} }
host = argv[0]; hosts_count = switch_split(argv[0], '|', hosts);
if (zstr(host)) { for(x = 0; x < hosts_count; x++) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing Host!\n"); host = hosts[x];
return;
}
if ((port_name = strrchr(host, ':'))) { if (zstr(host)) {
*port_name++ = '\0'; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing Host!\n");
port = (switch_port_t) atoi(port_name); continue;
} }
if ((path = strchr((port_name ? port_name : host), '/'))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Trying host: %s\n", host);
*path++ = '\0';
switch_channel_set_variable(channel, "socket_path", path);
}
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"); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
return; 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)))) { if (!(listener = switch_core_session_alloc(session, sizeof(*listener)))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Memory Error\n"); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Memory Error\n");
return; return;
@@ -8,6 +8,11 @@
<param name="mixer-conf-profile" value="sla"/> <param name="mixer-conf-profile" value="sla"/>
<!-- if true, to attribute in offer uses URI instead of name/number --> <!-- if true, to attribute in offer uses URI instead of name/number -->
<param name="offer-uri" value="true"/> <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 --> <!-- if true, channel variables are added to rayo client offer -->
<param name="add-variables-to-offer" value="false"/> <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 --> <!-- if true, channel variables are added to offer, ringing, answered, and end events sent to rayo clients -->
+218 -16
View File
@@ -1,6 +1,6 @@
/* /*
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * 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 * 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_CALL 1
#define JOINED_MIXER 2 #define JOINED_MIXER 2
#define OFFER_ALL 0
#define OFFER_FIRST 1
#define OFFER_RANDOM 2
struct rayo_actor; struct rayo_actor;
struct rayo_client; struct rayo_client;
struct rayo_call; struct rayo_call;
@@ -123,8 +127,12 @@ struct rayo_call {
struct rayo_actor base; struct rayo_actor base;
/** Definitive controlling party JID */ /** Definitive controlling party JID */
char *dcp_jid; char *dcp_jid;
/** Potential controlling parties */ /** Potential controlling parties (have sent offers to) */
switch_hash_t *pcps; 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 */ /** current idle start time */
switch_time_t idle_start_time; switch_time_t idle_start_time;
/** true if fax is in progress */ /** true if fax is in progress */
@@ -223,6 +231,8 @@ static struct {
int num_message_threads; int num_message_threads;
/** message delivery queue */ /** message delivery queue */
switch_queue_t *msg_queue; switch_queue_t *msg_queue;
/** in progress offer queue */
switch_queue_t *offer_queue;
/** shutdown flag */ /** shutdown flag */
int shutdown; int shutdown;
/** prevents context shutdown until all threads are finished */ /** prevents context shutdown until all threads are finished */
@@ -237,6 +247,10 @@ static struct {
int add_variables_to_offer; int add_variables_to_offer;
/** if true, channel variables are added to answered, ringing, end events */ /** if true, channel variables are added to answered, ringing, end events */
int add_variables_to_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; } 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; globals.shutdown = 1;
switch_queue_interrupt_all(globals.msg_queue); switch_queue_interrupt_all(globals.msg_queue);
switch_queue_interrupt_all(globals.offer_queue);
switch_thread_rwlock_wrlock(globals.shutdown_rwlock); switch_thread_rwlock_wrlock(globals.shutdown_rwlock);
} }
@@ -1219,6 +1234,7 @@ done:
switch_event_destroy(&call->answer_event); switch_event_destroy(&call->answer_event);
} }
switch_core_hash_destroy(&call->pcps); 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->rayo_app_started = 0;
call->answer_event = NULL; call->answer_event = NULL;
switch_core_hash_init(&call->pcps); switch_core_hash_init(&call->pcps);
switch_core_hash_init(&call->acps);
call->num_acps = 0;
} }
switch_safe_free(call_jid); switch_safe_free(call_jid);
@@ -3825,6 +3843,171 @@ static int should_offer_to_client(struct rayo_client *rclient, char **offer_filt
return 0; 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]" #define RAYO_USAGE "[client username 1,client username n]"
/** /**
* Offer call and park channel * Offer call and park channel
@@ -3874,7 +4057,6 @@ SWITCH_STANDARD_APP(rayo_app)
if (!call) { if (!call) {
/* offer control */ /* offer control */
switch_hash_index_t *hi = NULL; switch_hash_index_t *hi = NULL;
iks *offer = NULL;
char *clients_to_offer[16] = { 0 }; char *clients_to_offer[16] = { 0 };
int clients_to_offer_count = 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)); 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"); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Offering call for Rayo 3PCC\n");
if (!zstr(data)) { if (!zstr(data)) {
@@ -3904,7 +4085,6 @@ SWITCH_STANDARD_APP(rayo_app)
} }
/* Offer call to all (or specified) ONLINE clients */ /* 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); switch_mutex_lock(globals.clients_mutex);
for (hi = switch_core_hash_first(globals.clients_roster); hi; hi = switch_core_hash_next(&hi)) { for (hi = switch_core_hash_first(globals.clients_roster); hi; hi = switch_core_hash_next(&hi)) {
struct rayo_client *rclient; struct rayo_client *rclient;
@@ -3914,16 +4094,15 @@ SWITCH_STANDARD_APP(rayo_app)
rclient = (struct rayo_client *)val; rclient = (struct rayo_client *)val;
switch_assert(rclient); 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)) { if (should_offer_to_client(rclient, clients_to_offer, clients_to_offer_count)) {
ok = 1; switch_core_hash_insert(call->acps, RAYO_JID(rclient), "1");
switch_core_hash_insert(call->pcps, RAYO_JID(rclient), "1"); call->num_acps++;
iks_insert_attrib(offer, "to", RAYO_JID(rclient));
RAYO_SEND_MESSAGE_DUP(call, RAYO_JID(rclient), offer);
} }
} }
ok = send_offer_to_clients(call, session);
switch_mutex_unlock(globals.clients_mutex); switch_mutex_unlock(globals.clients_mutex);
iks_delete(offer);
/* nobody to offer to */ /* nobody to offer to */
if (!ok) { 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.pause_when_offline = 0;
globals.add_variables_to_offer = 0; globals.add_variables_to_offer = 0;
globals.add_variables_to_events = 0; globals.add_variables_to_events = 0;
globals.offer_timeout_us = 5000000;
globals.offer_algorithm = OFFER_ALL;
/* get params */ /* 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_offer = 1;
globals.add_variables_to_events = 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 { } else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var); 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_core_hash_init(&globals.cmd_aliases);
switch_thread_rwlock_create(&globals.shutdown_rwlock, pool); switch_thread_rwlock_create(&globals.shutdown_rwlock, pool);
switch_queue_create(&globals.msg_queue, 25000, pool); switch_queue_create(&globals.msg_queue, 25000, pool);
switch_queue_create(&globals.offer_queue, 25000, pool);
globals.offline_logged = 1; globals.offline_logged = 1;
/* server commands */ /* server commands */
@@ -4930,6 +5131,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
start_deliver_message_thread(pool); start_deliver_message_thread(pool);
} }
} }
start_offer_timeout_thread(pool);
/* create admin client */ /* create admin client */
globals.console = rayo_console_client_create(); 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"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for XMPP threads to stop\n");
xmpp_stream_context_destroy(globals.xmpp_context); xmpp_stream_context_destroy(globals.xmpp_context);
/* stop message threads */ /* stop threads */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for message threads to stop\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for message and offer timeout threads to stop\n");
stop_deliver_message_threads(); stop_all_threads();
if (globals.console) { if (globals.console) {
RAYO_RELEASE(globals.console); RAYO_RELEASE(globals.console);
+1 -1
View File
@@ -272,7 +272,7 @@ static switch_status_t my_on_reporting(switch_core_session_t *session)
memset(xml_text_escaped, 0, need_bytes); memset(xml_text_escaped, 0, need_bytes);
if (globals.encode == ENCODING_DEFAULT) { if (globals.encode == ENCODING_DEFAULT) {
headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); 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 { } else {
headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded"); 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); 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="(&amp;(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 ))
+156 -30
View File
@@ -65,19 +65,36 @@ typedef struct xml_binding {
typedef enum exten_types { typedef enum exten_types {
LDAP_EXTEN_ID = 0, LDAP_EXTEN_ID = 0,
LDAP_EXTEN_CIDR, LDAP_EXTEN_CIDR,
LDAP_EXTEN_NUMBER_ALIAS,
LDAP_EXTEN_DIAL_STRING,
LDAP_EXTEN_PASSWORD, 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_PASSWORD,
LDAP_EXTEN_VM_ENABLED,
LDAP_EXTEN_VM_MAILFROM, LDAP_EXTEN_VM_MAILFROM,
LDAP_EXTEN_VM_MAILTO, LDAP_EXTEN_VM_MAILTO,
LDAP_EXTEN_VM_EMAILMSG, LDAP_EXTEN_VM_NOTIFY_MAILTO,
LDAP_EXTEN_VM_NOTEMAILMSG, LDAP_EXTEN_VM_ATTACH_FILE,
LDAP_EXTEN_VM_ATTACHFILE, LDAP_EXTEN_VM_MESSAGE_EXT,
LDAP_EXTEN_USER_CONTEXT, LDAP_EXTEN_VM_EMAIL_ALL_MSGS,
LDAP_EXTEN_EFF_CLIDNAME, LDAP_EXTEN_VM_KEEP_LOCAL_AFTER_MAIL,
LDAP_EXTEN_EFF_CLIDNUM, 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_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_AREACODE,
LDAP_EXTEN_CID_EXTNAME, LDAP_EXTEN_CID_EXTNAME,
LDAP_EXTEN_CID_EXTNUM, LDAP_EXTEN_CID_EXTNUM,
@@ -99,6 +116,7 @@ typedef enum exten_types {
LDAP_EXTEN_HOTLINE_ACTIVE, LDAP_EXTEN_HOTLINE_ACTIVE,
LDAP_EXTEN_HOTLINE_DEST, LDAP_EXTEN_HOTLINE_DEST,
LDAP_EXTEN_CLASSOFSERVICE LDAP_EXTEN_CLASSOFSERVICE
*/
} exten_type_t; } exten_type_t;
struct xml_ldap_attribute { 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 = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; 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))) { } else if (!strncasecmp("password", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_PASSWORD; attr_list->type = LDAP_EXTEN_PASSWORD;
attr_list->len = strlen(m); 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 = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; attr_list = attr_list->next;
} else if (!strncasecmp("vm-enabled", n, strlen(n))) { } else if (!strncasecmp("reverse-auth-user", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_ENABLED; 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->len = strlen(m);
attr_list->val = strdup(m); attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list)); 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 = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; 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))) { } else if (!strncasecmp("vm-mailfrom", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_MAILFROM; attr_list->type = LDAP_EXTEN_VM_MAILFROM;
attr_list->len = strlen(m); 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 = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; attr_list = attr_list->next;
} else if (!strncasecmp("vm-email-all-messages", n, strlen(n))) { } else if (!strncasecmp("vm-notify-mailto", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_EMAILMSG; 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-notify-email-all-messages", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_NOTEMAILMSG;
attr_list->len = strlen(m); attr_list->len = strlen(m);
attr_list->val = strdup(m); attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list)); attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; attr_list = attr_list->next;
} else if (!strncasecmp("vm-attach-file", n, strlen(n))) { } 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->len = strlen(m);
attr_list->val = strdup(m); attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list)); attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; attr_list = attr_list->next;
/* Variables */ /* 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))) { } else if (!strncasecmp("user_context", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_USER_CONTEXT; attr_list->type = LDAP_EXTEN_USER_CONTEXT;
attr_list->len = strlen(m); 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 = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; attr_list = attr_list->next;
} else if (!strncasecmp("effective_caller_id_name", n, strlen(n))) { } else if (!strncasecmp("vm_mailbox", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_EFF_CLIDNAME; 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->len = strlen(m);
attr_list->val = strdup(m); attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list)); 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 = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; attr_list = attr_list->next;
} else if (!strncasecmp("accountcode", n, strlen(n))) { } else if (!strncasecmp("effective_caller_id_name", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_ACCOUNTCODE; attr_list->type = LDAP_EXTEN_EFF_CLIDNAME;
attr_list->len = strlen(m); attr_list->len = strlen(m);
attr_list->val = strdup(m); attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list)); attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list)); attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next; attr_list = attr_list->next;
} else if (!strncasecmp("ruleset", n, strlen(n))) { } else if (!strncasecmp("outbound_caller_id_number", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_RULESET; 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->len = strlen(m);
attr_list->val = strdup(m); attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list)); 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; LDAPMessage *msg, *entry;
xml_ldap_attribute_t *attr = NULL; xml_ldap_attribute_t *attr = NULL;
static char *fsattr[] = static char *fsattr[] =
{ "id", "cidr", "password", "vm-enabled", "vm-password", "vm-mailfrom", "vm-mailto", { "id", "cidr", "number-alias", "dial-string", "password", "reverse-auth-user",
"vm-email-all-messages", "vm-notify-email-all-messages", "vm-attach-file", "reverse-auth-pass", "a1-hash", "vm-password", "vm-enabled", "vm-mailfrom",
"user_context", "effective_caller_id_name", "effective_caller_id_number", "vm-mailto", "vm-notify-mailto", "vm-attach-file", "vm-message-ext",
"accountcode", "ruleset", NULL }; "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); basedn = switch_mprintf(binding->basedn, dir_domain);
filter = switch_mprintf(binding->filter, dir_exten); filter = switch_mprintf(binding->filter, dir_exten);
+6 -2
View File
@@ -864,11 +864,15 @@ SWITCH_DECLARE(const char *) switch_get_addr(char *buf, switch_size_t len, switc
return SWITCH_BLANK_STRING; return SWITCH_BLANK_STRING;
} }
memset(buf, 0, len);
if (in->family == AF_INET) { 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) SWITCH_DECLARE(uint16_t) switch_sockaddr_get_port(switch_sockaddr_t *sa)
+40 -1
View File
@@ -1331,7 +1331,12 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_
free(list_name_dup); free(list_name_dup);
} else { } else {
switch_parse_cidr(list_name, &net, &mask, &bits); 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); 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_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE);
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list); 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"; tmp_name = "nat.auto";
switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool); 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); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name);
+183 -161
View File
@@ -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] = { static switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID] = {
{ "AEAD_AES_256_GCM_8", AEAD_AES_256_GCM_8, 44}, { "AEAD_AES_256_GCM_8", AEAD_AES_256_GCM_8, 44},
{ "AEAD_AES_128_GCM_8", AEAD_AES_128_GCM_8, 28}, { "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); fps = switch_round_to_step(smh->vid_frames / (now - smh->vid_started), 5);
if (fps < 15) fps = 15; if (fps < 15) fps = 15;
smh->vid_started = switch_epoch_time_now(NULL);
smh->vid_frames = 1;
return fps; 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[0] = 0;
engine->ice_in.chosen[1] = 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)); memset(&engine->ice_in, 0, sizeof(engine->ice_in));
engine->remote_rtcp_port = 0; 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]; switch_rtp_engine_t *engine = &smh->engines[type];
sdp_attribute_t *attr; sdp_attribute_t *attr;
int i = 0, got_rtcp_mux = 0; int i = 0, got_rtcp_mux = 0;
const char *val; 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)) { if (engine->ice_in.is_chosen[0] && engine->ice_in.is_chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
return; return SWITCH_STATUS_SUCCESS;
} }
engine->ice_in.chosen[0] = 0; engine->ice_in.chosen[0] = 0;
engine->ice_in.chosen[1] = 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) { if (m) {
attr = m->m_attributes; 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 *data;
char *fields[15]; char *fields[15];
int argc = 0, j = 0; int argc = 0, j = 0;
int cid = 0;
if (zstr(attr->a_name)) { if (zstr(attr->a_name)) {
continue; 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")) { if (!strcasecmp(attr->a_name, "ice-ufrag")) {
engine->ice_in.ufrag = switch_core_session_strdup(smh->session, attr->a_value); engine->ice_in.ufrag = switch_core_session_strdup(smh->session, attr->a_value);
ice_seen++;
} else if (!strcasecmp(attr->a_name, "ice-pwd")) { } else if (!strcasecmp(attr->a_name, "ice-pwd")) {
engine->ice_in.pwd = switch_core_session_strdup(smh->session, attr->a_value); engine->ice_in.pwd = switch_core_session_strdup(smh->session, attr->a_value);
} else if (!strcasecmp(attr->a_name, "ice-options")) { } 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); data = switch_core_session_strdup(smh->session, attr->a_value);
argc = switch_split(data, ' ', fields); 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"); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_WARNING, "Invalid data\n");
continue; continue;
} }
cid = atoi(fields[1]) - 1;
for (i = 0; i < argc; i++) { 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_DEBUG1, "CAND %d [%s]\n", i, fields[i]);
} }
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, if (!ip_possible(smh, fields[4])) {
"Checking Candidate cid: %d proto: %s type: %s addr: %s:%s\n", cid+1, fields[2], fields[7], fields[4], fields[5]); 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;
while(j < argc && fields[j+1]) {
engine->ice_in.cand_idx++; 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]);
for (i = 0; i < engine->cand_acl_count; i++) { } else if (!strcasecmp(fields[j], "raddr")) {
if (!engine->ice_in.chosen[cid] && !strchr(fields[4], ':') && switch_check_network_list_ip(fields[4], engine->cand_acl[i])) { engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]);
engine->ice_in.chosen[cid] = engine->ice_in.cand_idx; } else if (!strcasecmp(fields[j], "rport")) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].rport = (switch_port_t)atoi(fields[j+1]);
"Choose %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n", } else if (!strcasecmp(fields[j], "generation")) {
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio", engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]);
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]);
} }
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]); if (!ice_seen) {
engine->ice_in.cands[engine->ice_in.cand_idx][cid].component_id = atoi(fields[1]); return SWITCH_STATUS_SUCCESS;
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]);
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]) { for (ai = 0; ai < engine->cand_acl_count; ai++) {
if (!strcasecmp(fields[j], "typ")) { for (i = 0; i < engine->ice_in.cand_idx[cid]; i++) {
engine->ice_in.cands[engine->ice_in.cand_idx][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]); if (switch_check_network_list_ip(engine->ice_in.cands[i][cid].con_addr, engine->cand_acl[ai])) {
} else if (!strcasecmp(fields[j], "raddr")) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
engine->ice_in.cands[engine->ice_in.cand_idx][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]); "Choose %s candidate, index %d, %s:%d\n", cid ? "rtcp" : "rtp", i,
} else if (!strcasecmp(fields[j], "rport")) { 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][cid].rport = (switch_port_t)atoi(fields[j+1]);
} else if (!strcasecmp(fields[j], "generation")) { engine->ice_in.chosen[cid] = i;
engine->ice_in.cands[engine->ice_in.cand_idx][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]); 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; goto next_cid;
}
if (engine->ice_in.chosen[cid]) {
engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++;
} }
break;
} }
} }
}
/* still no candidates, so start searching for some based on sane deduction */
/* look for candidates on the same network */ next_cid:
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++) { continue;
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));
}
}
} }
/* look for candidates with srflx */ done_choosing:
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));
}
}
}
/* 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], if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) {
sizeof(engine->ice_in.cands[engine->ice_in.chosen[0]][0])); /* PUNT */
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++; 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));
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE, return SWITCH_STATUS_FALSE;
"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));
}
}
} }
for (i = 0; i < 2; i++) { 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) { 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] = ""; 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); 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, switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"setting remote %s ice addr to %s:%d based on candidate\n", type2str(type), "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].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++; 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; smh->mparams->remote_ip = engine->cur_payload_map->remote_sdp_ip;
} }
if (engine->remote_rtcp_port) { switch_snprintf(tmp, sizeof(tmp), "%d", engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port);
engine->remote_rtcp_port = engine->cur_payload_map->remote_sdp_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_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_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); 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->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_DEBUG,
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),
"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);
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;
} else { engine->remote_rtcp_ice_addr = switch_core_session_strdup(smh->session, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr);
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->remote_rtcp_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
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 #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@@ -3503,7 +3517,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
const char *tmp; const char *tmp;
int m_idx = 0; int m_idx = 0;
int nm_idx = 0; int nm_idx = 0;
switch_assert(session); switch_assert(session);
if (!(smh = session->media_handle)) { 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) { if (switch_core_media_set_codec(session, 0, smh->mparams->codec_flags) == SWITCH_STATUS_SUCCESS) {
got_audio = 1; if (check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m) == SWITCH_STATUS_FALSE) {
check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m); match = 0;
} else {
got_audio = 1;
}
} else { } else {
match = 0; 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) { 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; 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) { if (v_engine->rtp_session) {
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt); 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_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_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 (audio && (status = switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 0)) == SWITCH_STATUS_SUCCESS) {
if (video) { 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_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_test_flag(session->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
switch_channel_get_name(session->channel), 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->local_sdp_port,
v_engine->cur_payload_map->remote_sdp_ip, v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt, 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: end:
switch_channel_clear_flag(session->channel, CF_REINVITE); switch_channel_clear_flag(session->channel, CF_REINVITE);
switch_core_recovery_track(session); switch_core_recovery_track(session);
return status; return status;
} }
@@ -8555,7 +8585,7 @@ static int check_engine(switch_rtp_engine_t *engine)
return 1; 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_media_handle_t *smh;
switch_rtp_engine_t *a_engine, *v_engine; 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; return SWITCH_FALSE;
} }
if (switch_channel_down(session->channel)) { if (!switch_channel_media_up(session->channel)) {
return SWITCH_FALSE; return SWITCH_FALSE;
} }
@@ -8621,14 +8651,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se
} }
break; 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: case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
{ {
if (v_engine->rtp_session) { if (v_engine->rtp_session) {
+4
View File
@@ -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) { switch (state) {
case CS_NEW: /* Just created, Waiting for first instructions */ case CS_NEW: /* Just created, Waiting for first instructions */
+1 -1
View File
@@ -530,7 +530,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *se
elp = 1; elp = 1;
} }
if (lead_frames) { if (lead_frames && switch_channel_media_ready(channel)) {
switch_frame_t *read_frame; switch_frame_t *read_frame;
int frame_count = atoi(lead_frames); int frame_count = atoi(lead_frames);
int max_frames = frame_count * 2; int max_frames = frame_count * 2;
+12 -1
View File
@@ -25,6 +25,7 @@
* *
* Anthony Minessale II <anthm@freeswitch.org> * Anthony Minessale II <anthm@freeswitch.org>
* Eliot Gable <egable@gmail.com> * Eliot Gable <egable@gmail.com>
* Seven Du <dujinfang@gmail.com>
* *
* switch_pgsql.c -- PGSQL Driver * 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); 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; 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); switch_pgsql_free_result(&res);
} while (!done); } while (!done);
return final_status; return final_status;
+33 -22
View File
@@ -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_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)); switch_stun_value_to_name(SWITCH_STUN_TYPE_PACKET_TYPE, packet->header.type));
do { 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_stun_value_to_name(SWITCH_STUN_TYPE_ATTRIBUTE, attr->type));
switch (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); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|------: %s:%d\n", ip, port);
} }
break; 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: case SWITCH_STUN_ATTR_USERNAME:
if (attr->type) { if (attr->type) {
switch_stun_packet_attribute_get_username(attr, username, sizeof(username)); 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) { if (!icep[j] || !icep[j]->ice_params) {
continue; 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 (icep[j]->ice_params && icep[j]->ice_params->cands[i][icep[j]->proto].priority == *pri) {
if (j == IPR_RTP) { if (j == IPR_RTP) {
icep[j]->ice_params->chosen[j] = i; 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 (ice->ice_params->cands[i][ice->proto].con_port == port) {
if (!strcmp(ice->ice_params->cands[i][ice->proto].con_addr, host) && if (!strcmp(ice->ice_params->cands[i][ice->proto].con_addr, host) &&
!strcmp(ice->ice_params->cands[i][ice->proto].cand_type, "relay")) { !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); 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, 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) == 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 (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP]) {
if (remote_rtcp_port) { if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
rtp_session->remote_rtcp_port = remote_rtcp_port; rtp_session->rtcp_remote_addr = rtp_session->remote_addr;
rtp_session->rtcp_sock_output = rtp_session->sock_output;
} else { } 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); 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_sock_output = rtp_session->sock_output;
rtp_session->rtcp_recv_msg_p = (rtcp_msg_t *) &rtp_session->recv_msg; 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 { } else {
rtp_session->rtcp_recv_msg_p = (rtcp_msg_t *) &rtp_session->rtcp_recv_msg; 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)) { 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, 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); msg->header.version, len);
status = SWITCH_STATUS_BREAK; status = SWITCH_STATUS_BREAK;
break; break;
@@ -7746,7 +7757,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_write_raw(switch_rtp_t *rtp_session,
break; break;
case zrtp_status_drop: case zrtp_status_drop:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat); 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; goto end;
break; break;
case zrtp_status_fail: case zrtp_status_fail:
+1
View File
@@ -60,6 +60,7 @@ static const struct value_mapping PACKET_TYPES[] = {
static const struct value_mapping ATTR_TYPES[] = { static const struct value_mapping ATTR_TYPES[] = {
{SWITCH_STUN_ATTR_MAPPED_ADDRESS, "MAPPED_ADDRESS"}, {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_RESPONSE_ADDRESS, "RESPONSE_ADDRESS"},
{SWITCH_STUN_ATTR_CHANGE_REQUEST, "CHANGE_REQUEST"}, {SWITCH_STUN_ATTR_CHANGE_REQUEST, "CHANGE_REQUEST"},
{SWITCH_STUN_ATTR_SOURCE_ADDRESS, "SOURCE_ADDRESS"}, {SWITCH_STUN_ATTR_SOURCE_ADDRESS, "SOURCE_ADDRESS"},
+10 -4
View File
@@ -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) { for (node = list->node_head; node; node = node->next) {
if (node->family == AF_INET) continue; 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) { if (node->ok) {
ok = SWITCH_TRUE; ok = SWITCH_TRUE;
} else { } 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) { for (node = list->node_head; node; node = node->next) {
if (node->family == AF_INET6) continue; /* want AF_INET */ 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) { if (node->ok) {
ok = SWITCH_TRUE; ok = SWITCH_TRUE;
} else { } else {
@@ -3161,7 +3162,7 @@ SWITCH_DECLARE(int) switch_socket_waitfor(switch_pollfd_t *poll, int ms)
return nsds; 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); const char *p, *e = end_of_p(url);
size_t x = 0; size_t x = 0;
@@ -3184,7 +3185,7 @@ SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
break; break;
} }
if (*p == '%' && e-p > 1) { if (!double_encode && *p == '%' && e-p > 1) {
if (strchr(hex, *(p+1)) && strchr(hex, *(p+2))) { if (strchr(hex, *(p+1)) && strchr(hex, *(p+2))) {
ok = 1; ok = 1;
} }
@@ -3206,6 +3207,11 @@ SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
return buf; 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) SWITCH_DECLARE(char *) switch_url_decode(char *s)
{ {
char *o; char *o;