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
commit 390ebac3c1
52 changed files with 1914 additions and 506 deletions

View File

@ -8,6 +8,11 @@
<param name="mixer-conf-profile" value="sla"/>
<!-- if true, to attribute in offer uses URI instead of name/number -->
<param name="offer-uri" value="true"/>
<!-- how offers are distributed to clients (all, first, random). -->
<param name="offer-algorithm" value="all"/>
<!-- If offer is not answered after timeout, next client is offered (based on algorithm picked).
If no other clients are available, the call is rejected. Set to 0 to disable -->
<param name="offer-timeout-ms" value="5000"/>
<!-- if true, channel variables are added to rayo client offer -->
<param name="add-variables-to-offer" value="false"/>
<!-- if true, channel variables are added to offer, ringing, answered, and end events sent to rayo clients -->

View File

@ -185,6 +185,7 @@
<!-- <param name="video-layout-bgcolor" value="#000000"/> -->
<!-- <param name="video-codec-bandwidth" value="2mb"/> -->
<!-- <param name="video-fps" value="15"/> -->
<!-- <param name="video-auto-floor-msec" value="100"/> -->
<!-- <param name="tts-engine" value="flite"/> -->

View File

@ -5,9 +5,11 @@
</settings>
<profiles>
<profile name="mine">
<param name="bind-local" value="0.0.0.0:8081"/>
<param name="bind-local" value="0.0.0.0:8082" secure="true"/>
<profile name="default">
<param name="bind-local" value="$${local_ip_v4}:8081"/>
<param name="bind-local" value="$${local_ip_v4}:8082" secure="true"/>
<param name="bind-local" value="[$${local_ip_v6}]:8081"/>
<param name="bind-local" value="[$${local_ip_v6}]:8082" secure="true"/>
<param name="force-register-domain" value="$${domain}"/>
<param name="secure-combined" value="$${certs_dir}/wss.pem"/>
<param name="secure-chain" value="$${certs_dir}/wss.pem"/>
@ -16,15 +18,20 @@
<param name="blind-reg" value="false"/>
<param name="mcast-ip" value="224.1.1.1"/>
<param name="mcast-port" value="1337"/>
<param name="rtp-ip" value="$${local_ip_v6}"/>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<!-- <param name="ext-rtp-ip" value=""/> -->
<param name="local-network" value="localnet.auto"/>
<param name="outbound-codec-string" value="opus,vp8"/>
<param name="inbound-codec-string" value="opus,vp8"/>
<param name="apply-candidate-acl" value="wan.auto"/>
<param name="apply-candidate-acl" value="localnet.auto"/>
<param name="apply-candidate-acl" value="wan_v6.auto"/>
<param name="apply-candidate-acl" value="wan_v4.auto"/>
<param name="apply-candidate-acl" value="rfc1918.auto"/>
<param name="apply-candidate-acl" value="any_v6.auto"/>
<param name="apply-candidate-acl" value="any_v4.auto"/>
<param name="timer-name" value="soft"/>
</profile>
</profiles>
</configuration>

View File

@ -413,8 +413,6 @@
openssl ciphers -v 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH'
Will show you what is available in your verion of openssl.
Freeswitch does not support non-Elliptic Curve Diffie Hellman key
exchange.
-->
<X-PRE-PROCESS cmd="set" data="sip_tls_ciphers=ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"/>

1
debian/bootstrap.sh vendored
View File

@ -30,7 +30,6 @@ avoid_mods=(
endpoints/mod_opal
endpoints/mod_reference
endpoints/mod_unicall
event_handlers/mod_amqp
sdk/autotools
xml_int/mod_xml_ldap
xml_int/mod_xml_radius

View File

@ -795,6 +795,7 @@ function refresh_devices()
//$("input[type='radio']).checkboxradio({});
$("input[type='radio']").checkboxradio("refresh");
$("input[type='checkbox']").checkboxradio("refresh");
//console.error($("#usecamera").find(":selected").val());
}

View File

@ -99,6 +99,9 @@ static History *myhistory;
static HistEvent ev;
#endif
static esl_mutex_t *MUTEX = NULL;
static void _sleep_ns(int secs, long nsecs) {
#ifndef WIN32
if (nsecs > 999999999) {
@ -720,8 +723,15 @@ static void *msg_thread_run(esl_thread_t *me, void *obj)
thread_running = 1;
while(thread_running && handle->connected) {
int aok = 1;
esl_status_t status = esl_recv_event_timed(handle, 10, 1, NULL);
if (status == ESL_FAIL) {
esl_status_t status;
esl_mutex_lock(MUTEX);
status = esl_recv_event_timed(handle, 10, 1, NULL);
esl_mutex_unlock(MUTEX);
if (status == ESL_BREAK) {
sleep_ms(1);
} else if (status == ESL_FAIL) {
esl_log(ESL_LOG_WARNING, "Disconnected.\n");
running = -1; thread_running = 0;
} else if (status == ESL_SUCCESS) {
@ -851,8 +861,11 @@ static const char *cli_usage =
static int process_command(esl_handle_t *handle, const char *cmd)
{
int r = 0;
while (*cmd == ' ') cmd++;
esl_mutex_lock(MUTEX);
if ((*cmd == '/' && cmd++) || !strncasecmp(cmd, "...", 3)) {
if (!strcasecmp(cmd, "help")) {
@ -865,7 +878,7 @@ static int process_command(esl_handle_t *handle, const char *cmd)
!strcasecmp(cmd, "bye")
) {
esl_log(ESL_LOG_INFO, "Goodbye!\nSee you at ClueCon http://www.cluecon.com/\n");
return -1;
r = -1; goto end;
} else if (!strncasecmp(cmd, "logfilter", 9)) {
cmd += 9;
while (*cmd && *cmd == ' ') {
@ -922,7 +935,7 @@ static int process_command(esl_handle_t *handle, const char *cmd)
snprintf(cmd_str, sizeof(cmd_str), "api %s\nconsole_execute: true\n\n", cmd);
if (esl_send_recv(handle, cmd_str)) {
output_printf("Socket interrupted, bye!\n");
return -1;
r = -1; goto end;
}
if (handle->last_sr_event) {
if (handle->last_sr_event->body) {
@ -932,8 +945,12 @@ static int process_command(esl_handle_t *handle, const char *cmd)
}
}
}
end:
return 0;
esl_mutex_unlock(MUTEX);
return r;
}
static int get_profile(const char *name, cli_profile_t **profile)
@ -1142,7 +1159,9 @@ static unsigned char esl_console_complete(const char *buffer, const char *cursor
} else {
snprintf(cmd_str, sizeof(cmd_str), "api console_complete %s\n\n", buf);
}
esl_send_recv(global_handle, cmd_str);
if (global_handle->last_sr_event && global_handle->last_sr_event->body) {
char *r = global_handle->last_sr_event->body;
char *w, *p1;
@ -1183,7 +1202,13 @@ static unsigned char esl_console_complete(const char *buffer, const char *cursor
static unsigned char complete(EditLine *el, int ch)
{
const LineInfo *lf = el_line(el);
return esl_console_complete(lf->buffer, lf->cursor, lf->lastchar);
int r;
esl_mutex_lock(MUTEX);
r = esl_console_complete(lf->buffer, lf->cursor, lf->lastchar);
esl_mutex_unlock(MUTEX);
return r;
}
#endif
@ -1378,6 +1403,9 @@ int main(int argc, char *argv[])
int loops = 2, reconnect = 0;
char *ccheck;
esl_mutex_create(&MUTEX);
#if HAVE_DECL_EL_PROMPT_ESC
feature_level = 1;
#else
@ -1755,6 +1783,9 @@ int main(int argc, char *argv[])
esl_disconnect(&handle);
global_handle = NULL;
thread_running = 0;
esl_mutex_destroy(&MUTEX);
return 0;
}

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)) {
pfds[0].events |= POLLERR;
}
s = poll(pfds, 1, ms);
s = poll(pfds, 1, ms);
if (s < 0) {
r = s;
} else if (s > 0) {

View File

@ -381,6 +381,27 @@ int tls_init_context(tls_t *tls, tls_issues_t const *ti)
#if require_client_certificate
errno = EIO;
return -1;
#endif
#ifndef OPENSSL_NO_DH
} else {
BIO *bio = BIO_new_file(ti->key, "r");
if (bio != NULL) {
DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
if (dh != NULL) {
if (!SSL_CTX_set_tmp_dh(tls->ctx, dh)) {
SU_DEBUG_1(("%s: invalid DH parameters (PFS) because %s: %s\n",
"tls_init_context",
ERR_reason_error_string(ERR_get_error()),
ti->key));
} else {
long options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE;
options = SSL_CTX_set_options(tls->ctx, options);
SU_DEBUG_3(("%s\n", "tls: initialized DHE"));
}
DH_free(dh);
}
BIO_free(bio);
}
#endif
}

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;
char *maskp;
int ll = 0;
int frag = 0;
again:
need = 2;
@ -741,8 +742,16 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
case WSOC_PING:
case WSOC_PONG:
{
//int fin = (wsh->buffer[0] >> 7) & 1;
int fin = (wsh->buffer[0] >> 7) & 1;
int mask = (wsh->buffer[1] >> 7) & 1;
if (fin) {
if (*oc == WSOC_CONTINUATION) {
frag = 1;
} else {
frag = 0;
}
}
if (mask) {
need += 4;
@ -837,6 +846,10 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
goto again;
}
if (frag) {
goto again;
}
*(wsh->payload+wsh->rplen) = '\0';

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;
if (abs(s->gardner_integrate) >= 256)
if (abs(s->gardner_integrate) >= 128)
{
/* This integrate and dump approach avoids rapid changes of the equalizer put step.
Rapid changes, without hysteresis, are bad. They degrade the equalizer performance
when the true symbol boundary is close to a sample boundary. */
//span_log(&s->logging, SPAN_LOG_FLOW, "Hop %d\n", s->gardner_integrate);
s->eq_put_step += (s->gardner_integrate/256);
s->total_baud_timing_correction += (s->gardner_integrate/256);
s->eq_put_step += (s->gardner_integrate/128);
s->total_baud_timing_correction += (s->gardner_integrate/128);
if (s->qam_report)
s->qam_report(s->qam_user_data, NULL, NULL, s->gardner_integrate);
s->gardner_integrate = 0;

View File

@ -125,6 +125,9 @@ typedef struct switch_core_media_params_s {
char *extrtpip;
char *rtpip;
char *rtpip4;
char *rtpip6;
char *remote_ip;
int remote_port;
@ -329,6 +332,7 @@ SWITCH_DECLARE(switch_media_flow_t) switch_core_session_media_flow(switch_core_s
SWITCH_DECLARE(switch_status_t) switch_core_media_get_vid_params(switch_core_session_t *session, switch_vid_params_t *vid_params);
SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh, switch_rw_t rw);
SWITCH_DECLARE(switch_bool_t) switch_core_session_in_video_thread(switch_core_session_t *session);
SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t *session);
SWITCH_END_EXTERN_C
#endif

View File

@ -103,8 +103,9 @@ typedef struct icand_s {
typedef struct ice_s {
icand_t cands[MAX_CAND][2];
int cand_idx;
int cand_idx[2];
int chosen[2];
int is_chosen[2];
char *ufrag;
char *pwd;
char *options;

View File

@ -197,6 +197,8 @@ SWITCH_DECLARE(char *) switch_stun_host_lookup(const char *host, switch_memory_p
\return true or false
*/
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_get_mapped_address(switch_stun_packet_attribute_t *attribute, char *ipstr, uint16_t *port);
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_get_xor_mapped_address(switch_stun_packet_attribute_t *attribute, uint32_t cookie, char *ipstr, uint16_t *port);
/*!
\brief Extract a username from a packet attribute

View File

@ -1052,6 +1052,7 @@ static inline int switch_needs_url_encode(const char *s)
return 0;
}
SWITCH_DECLARE(char *) switch_url_encode_opt(const char *url, char *buf, size_t len, switch_bool_t double_encode);
SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len);
SWITCH_DECLARE(char *) switch_url_decode(char *s);
SWITCH_DECLARE(switch_bool_t) switch_simple_email(const char *to,

View File

@ -25,7 +25,7 @@
*
* Marc Olivier Chouinard <mochouinard@moctel.com>
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
*
* Ítalo Rossi <italorossib@gmail.com>
*
* mod_callcenter.c -- Call Center Module
*
@ -1506,19 +1506,18 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
const char *cid_number = NULL;
const char *cid_name_prefix = NULL;
if ((cid_name_prefix = switch_channel_get_variable(member_channel, "cc_outbound_cid_name_prefix"))) {
cid_name_freeable = switch_mprintf("%s%s", cid_name_prefix, h->member_cid_name);
cid_name = cid_name_freeable;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Setting outbound caller_id_name to: %s\n", cid_name);
} else {
if (!(cid_name = switch_channel_get_variable(member_channel, "effective_caller_id_name"))) {
cid_name = h->member_cid_name;
}
if (!(cid_number = switch_channel_get_variable(member_channel, "effective_caller_id_number"))) {
cid_number = h->member_cid_number;
}
if (!(cid_name = switch_channel_get_variable(member_channel, "effective_caller_id_name"))) {
cid_name = h->member_cid_name;
}
if (!(cid_number = switch_channel_get_variable(member_channel, "effective_caller_id_number"))) {
cid_number = h->member_cid_number;
}
if ((cid_name_prefix = switch_channel_get_variable(member_channel, "cc_outbound_cid_name_prefix"))) {
cid_name_freeable = switch_mprintf("%s%s", cid_name_prefix, cid_name);
cid_name = cid_name_freeable;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_DEBUG, "Setting outbound caller_id_name to: %s\n", cid_name);
switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue_name);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_uuid", "%s", h->member_uuid);
@ -2108,6 +2107,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
agent_callback_t cbt;
const char *member_state = NULL;
const char *member_abandoned_epoch = NULL;
const char *serving_agent = NULL;
memset(&cbt, 0, sizeof(cbt));
cbt.queue_name = argv[0];
@ -2119,6 +2119,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
cbt.member_score = argv[6];
member_state = argv[7];
member_abandoned_epoch = argv[8];
serving_agent = argv[9];
if (!cbt.queue_name || !(queue = get_queue(cbt.queue_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, skip this member\n", cbt.queue_name);
@ -2153,7 +2154,23 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
}
/* Skip this member */
goto end;
}
}
/* Tracking queue strategy changes */
/* member is ring-all but not the queue */
if (!strcasecmp(serving_agent, "ring-all") && (strcasecmp(queue_strategy, "ring-all") != 0)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Queue '%s' changed strategy, adjusting member parameters", queue_name);
sql = switch_mprintf("UPDATE members SET serving_agent = '', state = '%s' WHERE uuid = '%s' AND state = '%s' AND serving_agent = 'ring-all'", cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt.member_uuid, cc_member_state2str(CC_MEMBER_STATE_TRYING));
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
}
/* Queue is now ring-all and not the member */
else if (!strcasecmp(queue_strategy, "ring-all") && (strcasecmp(serving_agent, "ring-all") != 0)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Queue '%s' changed strategy, adjusting member parameters", queue_name);
sql = switch_mprintf("UPDATE members SET serving_agent = 'ring-all', state = '%s' WHERE uuid = '%s' AND state = '%s' AND serving_agent = ''", cc_member_state2str(CC_MEMBER_STATE_TRYING), cbt.member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING));
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
}
/* Check if member is in the queue waiting */
if (zstr(cbt.member_session_uuid)) {
@ -2307,7 +2324,7 @@ void *SWITCH_THREAD_FUNC cc_agent_dispatch_thread_run(switch_thread_t *thread, v
while (globals.running == 1) {
char *sql = NULL;
sql = switch_mprintf("SELECT queue,uuid,session_uuid,cid_number,cid_name,joined_epoch,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score, state, abandoned_epoch FROM members"
sql = switch_mprintf("SELECT queue,uuid,session_uuid,cid_number,cid_name,joined_epoch,(%" SWITCH_TIME_T_FMT "-joined_epoch)+base_score+skill_score AS score, state, abandoned_epoch, serving_agent FROM members"
" WHERE state = '%q' OR state = '%q' OR (serving_agent = 'ring-all' AND state = '%q') ORDER BY score DESC",
local_epoch_time_now(NULL),
cc_member_state2str(CC_MEMBER_STATE_WAITING), cc_member_state2str(CC_MEMBER_STATE_ABANDONED), cc_member_state2str(CC_MEMBER_STATE_TRYING));
@ -2518,6 +2535,7 @@ SWITCH_STANDARD_APP(callcenter_function)
const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score");
int cc_base_score_int = 0;
const char *cur_moh = NULL;
char *moh_expanded = NULL;
char start_epoch[64];
switch_event_t *event;
switch_time_t t_member_called = local_epoch_time_now(NULL);
@ -2679,6 +2697,7 @@ SWITCH_STANDARD_APP(callcenter_function)
cur_moh = switch_core_session_strdup(member_session, queue->moh);
}
queue_rwunlock(queue);
moh_expanded = switch_channel_expand_variables(member_channel, cur_moh);
while (switch_channel_ready(member_channel)) {
switch_input_args_t args = { 0 };
@ -2701,9 +2720,8 @@ SWITCH_STANDARD_APP(callcenter_function)
switch_core_session_flush_private_events(member_session);
if (moh_valid && cur_moh) {
switch_status_t status = switch_ivr_play_file(member_session, NULL, cur_moh, &args);
if (moh_valid && moh_expanded) {
switch_status_t status = switch_ivr_play_file(member_session, NULL, moh_expanded, &args);
if (status == SWITCH_STATUS_FALSE /* Invalid Recording */ && SWITCH_READ_ACCEPTABLE(status)) {
/* Sadly, there doesn't seem to be a return to switch_ivr_play_file that tell you the file wasn't found. FALSE also mean that the channel got switch to BRAKE state, so we check for read acceptable */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member_session), SWITCH_LOG_WARNING, "Couldn't play file '%s', continuing wait with no audio\n", cur_moh);
@ -2724,6 +2742,9 @@ SWITCH_STANDARD_APP(callcenter_function)
}
switch_yield(1000);
}
if (moh_expanded != cur_moh) {
switch_safe_free(moh_expanded);
}
/* Make sure an agent was found, as we might break above without setting it */
if (!agent_found && (p = switch_channel_get_variable(member_channel, "cc_agent_found"))) {

View File

@ -594,6 +594,7 @@ typedef struct conference_obj {
struct conf_fps video_fps;
int playing_video_file;
int recording_members;
uint32_t video_floor_packets;
} conference_obj_t;
/* Relationship with another member */
@ -682,6 +683,7 @@ struct conference_member {
switch_frame_buffer_t *fb;
switch_image_t *avatar_png_img;
switch_image_t *video_mute_img;
uint32_t floor_packets;
int blanks;
int managed_kps;
int blackouts;
@ -1882,6 +1884,26 @@ static void check_avatar(conference_member_t *member, switch_bool_t force)
}
}
static void check_flush(conference_member_t *member)
{
int flushed;
if (!member->channel || !switch_channel_test_flag(member->channel, CF_VIDEO)) {
return;
}
flushed = flush_video_queue(member->video_queue);
if (flushed && member->auto_avatar) {
switch_channel_video_sync(member->channel);
switch_img_free(&member->avatar_png_img);
member->avatar_patched = 0;
reset_video_bitrate_counters(member);
member->blanks = 0;
member->auto_avatar = 0;
}
}
static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj)
{
@ -2028,7 +2050,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
size = switch_queue_size(imember->video_queue);
} while(size > 0);
if (switch_test_flag(imember, MFLAG_CAN_BE_SEEN) && imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) {
if (switch_test_flag(imember, MFLAG_CAN_BE_SEEN) && imember->video_layer_id > -1 && imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) {
if (img) {
imember->good_img++;
if ((imember->good_img % (int)(conference->video_fps.fps * 10)) == 0) {
@ -2052,31 +2074,14 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
//if (layer) {
//layer->is_avatar = 1;
//}
imember->auto_avatar = 1;
}
}
}
}
} else {
int flushed = flush_video_queue(imember->video_queue);
if (flushed && imember->auto_avatar) {
switch_channel_video_sync(imember->channel);
switch_img_free(&imember->avatar_png_img);
imember->avatar_patched = 0;
reset_video_bitrate_counters(imember);
if (layer) {
layer->is_avatar = 0;
imember->auto_avatar = 0;
}
imember->blanks = 0;
} else {
}
check_flush(imember);
}
layer = NULL;
@ -4439,6 +4444,7 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Adding video floor %s\n",
switch_channel_get_name(member->channel));
check_flush(member);
switch_core_session_video_reinit(member->session);
conference->video_floor_holder = member->id;
member_update_status_field(member);
@ -4496,15 +4502,6 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference
conference_member_t *old_member = NULL;
int old_id = 0;
if (((conference->video_floor_holder && !member && !switch_test_flag(conference, CFLAG_VID_FLOOR_LOCK)) ||
(member && member->channel && (switch_channel_test_flag(member->channel, CF_VIDEO) || member->avatar_png_img)))) {
if (member && member->id != conference->video_floor_holder) {
conference_set_video_floor_holder(conference, member, SWITCH_FALSE);
}
}
if (conference->floor_holder) {
if (conference->floor_holder == member) {
return;
@ -4531,6 +4528,7 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference
if (old_member) {
old_id = old_member->id;
member_update_status_field(old_member);
old_member->floor_packets = 0;
}
switch_set_flag(conference, CFLAG_FLOOR_CHANGE);
@ -6330,6 +6328,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
check_agc_levels(member);
clear_avg(member);
member->score_iir = 0;
member->floor_packets = 0;
if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
@ -6369,7 +6368,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
if (member->volume_in_level) {
switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->volume_in_level);
}
if (member->agc_volume_in_level) {
switch_change_sln_volume_granular(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->agc_volume_in_level);
}
@ -6428,10 +6427,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
member->score_iir = SCORE_MAX_IIR;
}
if (member == member->conference->floor_holder && member->id != member->conference->video_floor_holder) {
conference_set_video_floor_holder(member->conference, member, SWITCH_FALSE);
}
if (noise_gate_check(member)) {
uint32_t diff = member->score - member->energy_level;
if (hangover_hits) {
@ -6442,16 +6437,20 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
member->nt_tally = 0;
}
if (member == member->conference->floor_holder) {
member->floor_packets++;
}
if (diff >= diff_level || ++hangunder_hits >= hangunder) {
hangover_hits = hangunder_hits = 0;
member->last_talking = switch_epoch_time_now(NULL);
if (!switch_test_flag(member, MFLAG_TALKING)) {
switch_set_flag_locked(member, MFLAG_TALKING);
member_update_status_field(member);
member->floor_packets = 0;
if (test_eflag(member->conference, EFLAG_START_TALKING) && switch_test_flag(member, MFLAG_CAN_SPEAK) &&
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_member_data(member, event);
@ -6504,6 +6503,13 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
member->last_score = member->score;
if (member == member->conference->floor_holder) {
if (member->id != member->conference->video_floor_holder &&
(member->floor_packets > member->conference->video_floor_packets || member->energy_level == 0)) {
conference_set_video_floor_holder(member->conference, member, SWITCH_FALSE);
}
}
}
loops++;
@ -11479,7 +11485,7 @@ static void clear_eflags(char *events, uint32_t *f)
} else if (!strcmp(event, "play-file")) {
*f &= ~EFLAG_PLAY_FILE;
} else if (!strcmp(event, "play-file-done")) {
*f &= ~EFLAG_PLAY_FILE;
*f &= ~EFLAG_PLAY_FILE_DONE;
} else if (!strcmp(event, "play-file-member")) {
*f &= ~EFLAG_PLAY_FILE_MEMBER;
} else if (!strcmp(event, "speak-text")) {
@ -12563,7 +12569,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
char *suppress_events = NULL;
char *verbose_events = NULL;
char *auto_record = NULL;
int min_recording_participants = 2;
int min_recording_participants = 1;
char *conference_log_dir = NULL;
char *cdr_event_mode = NULL;
char *terminate_on_silence = NULL;
@ -12573,7 +12579,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
switch_codec_implementation_t read_impl = { 0 };
switch_channel_t *channel = NULL;
const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = NULL;
uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = 0;
uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = 0, video_auto_floor_msec = 0;
/* Validate the conference name */
if (zstr(name)) {
@ -12790,6 +12796,13 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
} else if (switch_true(val)) {
comfort_noise_level = 1400;
}
} else if (!strcasecmp(var, "video-auto-floor-msec") && !zstr(val)) {
int tmp;
tmp = atoi(val);
if (tmp > 0) {
video_auto_floor_msec = tmp;
}
} else if (!strcasecmp(var, "sound-prefix") && !zstr(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "override sound-prefix with: %s\n", val);
sound_prefix = val;
@ -12819,9 +12832,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
} else if (!strcasecmp(var, "auto-record") && !zstr(val)) {
auto_record = val;
} else if (!strcasecmp(var, "min-required-recording-participants") && !zstr(val)) {
if (!strcmp(val, "1")) {
min_recording_participants = 1;
} else if (!strcmp(val, "2")) {
if (!strcmp(val, "2")) {
min_recording_participants = 2;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "min-required-recording-participants is invalid, leaving set to %d\n", min_recording_participants);
@ -13170,6 +13181,10 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
conference->ivr_dtmf_timeout = ivr_dtmf_timeout;
conference->ivr_input_timeout = ivr_input_timeout;
if (video_auto_floor_msec) {
conference->video_floor_packets = video_auto_floor_msec / conference->interval;
}
conference->eflags = 0xFFFFFFFF;
if (!zstr(suppress_events)) {

View File

@ -50,6 +50,7 @@
*/
#include <switch.h>
#include <math.h>
typedef struct {
switch_time_t lastts; /* Last time we did any billing */
@ -59,6 +60,7 @@ typedef struct {
double bill_adjustments; /* Adjustments to make to the next billing, based on pause/resume events */
int lowbal_action_executed; /* Set to 1 once lowbal_action has been executed */
int final_bill_done; /* Set to 1 one the final rounding has been done on a call to prevent spurious rebills on hangup */
} nibble_data_t;
@ -454,6 +456,12 @@ static switch_status_t do_billing(switch_core_session_t *session)
double nobal_amt = globals.nobal_amt;
double lowbal_amt = globals.lowbal_amt;
double balance;
double minimum_charge = 0;
double rounding_factor = 1;
double excess = 0;
double rounded_billed = 0;
int billsecs = 0;
double balance_check = 0;
if (!session) {
/* Why are we here? */
@ -480,6 +488,16 @@ static switch_status_t do_billing(switch_core_session_t *session)
lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt"));
}
if (!zstr(switch_channel_get_variable(channel, "nibble_rounding"))) {
rounding_factor = pow(10, atof(switch_channel_get_variable(channel, "nibble_rounding")));
}
if (!zstr(switch_channel_get_variable(channel, "nibble_minimum"))) {
minimum_charge = atof(switch_channel_get_variable(channel, "nibble_minimum"));
}
/* Return if there's no billing information on this session */
if (!billrate || !billaccount) {
return SWITCH_STATUS_SUCCESS;
@ -501,8 +519,9 @@ static switch_status_t do_billing(switch_core_session_t *session)
/* See if this person has enough money left to continue the call */
balance = get_balance(billaccount, channel);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Comparing %f to hangup balance of %f\n", balance, nobal_amt);
if (balance <= nobal_amt) {
balance_check = balance - minimum_charge;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Comparing %f to hangup balance of %f, taking into account minimum charge of %f\n", balance, nobal_amt, minimum_charge);
if (balance_check <= nobal_amt) {
/* Not enough money - reroute call to nobal location */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below allowed amount of %f! (Account %s)\n",
balance, nobal_amt, billaccount);
@ -530,6 +549,12 @@ static switch_status_t do_billing(switch_core_session_t *session)
return SWITCH_STATUS_SUCCESS;
}
if (nibble_data && nibble_data->final_bill_done) {
switch_mutex_lock(globals.mutex);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Received heartbeat, but final bill has been committed - ignoring\n");
return SWITCH_STATUS_SUCCESS;
}
/* Have we done any billing on this channel yet? If no, set up vars for doing so */
if (!nibble_data) {
nibble_data = switch_core_session_alloc(session, sizeof(*nibble_data));
@ -543,8 +568,10 @@ static switch_status_t do_billing(switch_core_session_t *session)
switch_time_exp_lt(&tm, nibble_data->lastts);
switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm);
billsecs = (int) ((ts - nibble_data->lastts) / 1000000);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%d seconds passed since last bill time of %s\n",
(int) ((ts - nibble_data->lastts) / 1000000), date);
billsecs, date);
if ((ts - nibble_data->lastts) >= 0) {
/* If billincrement is set we bill by it and not by time elapsed */
@ -576,6 +603,29 @@ static switch_status_t do_billing(switch_core_session_t *session)
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n");
}
/* Do Rounding and minimum charge during hangup */
if (switch_channel_get_state(channel) == CS_HANGUP) {
/* we're going to make an assumption that final billing is done here. So we'll see how this goes. */
/* round total billed up as required */
rounded_billed = ceilf(nibble_data->total * rounding_factor) / rounding_factor;
if (rounded_billed < minimum_charge)
{
excess = minimum_charge - nibble_data->total;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Applying minimum charge of %f (%f excess)\n", minimum_charge, excess);
}
else if (nibble_data->total < rounded_billed)
{
excess = rounded_billed - nibble_data->total;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Rounding to precision %f, total %f (%f excess)\n", rounding_factor, rounded_billed, excess);
}
bill_event(excess, billaccount, channel);
nibble_data->total += excess;
switch_channel_set_variable_printf(channel, "nibble_total_billed", "%f", nibble_data->total);
nibble_data->final_bill_done = 1;
}
} else {
if (switch_strlen_zero(billincrement))
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", uuid);
@ -951,10 +1001,11 @@ static switch_status_t process_hangup(switch_core_session_t *session)
do_billing(session);
billaccount = switch_channel_get_variable(channel, globals.var_name_account);
if (billaccount) {
switch_channel_set_variable_printf(channel, "nibble_current_balance", "%f", get_balance(billaccount, channel));
}
}
return SWITCH_STATUS_SUCCESS;
}

View File

@ -152,7 +152,7 @@ static switch_status_t switch_codec2_encode(switch_codec_t *codec, switch_codec_
fflush(context->encoder_out);
#endif
*encoded_data_len = 8;
*encoded_data_len = 6;
return SWITCH_STATUS_SUCCESS;
}
@ -230,7 +230,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load)
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_CODEC(codec_interface, "CODEC2 2550bps");
SWITCH_ADD_CODEC(codec_interface, "CODEC2 2400bps");
switch_core_codec_add_implementation(pool, codec_interface,
SWITCH_CODEC_TYPE_AUDIO,
@ -239,7 +239,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load)
NULL,
8000, /* samples/sec */
8000, /* samples/sec */
2550, /* bps */
2400, /* bps */
20000, /* ptime */
CODEC2_SAMPLES_PER_FRAME, /* samples decoded */
CODEC2_SAMPLES_PER_FRAME*2, /* bytes decoded */

View File

@ -74,6 +74,7 @@ struct opus_context {
OpusDecoder *decoder_object;
uint32_t enc_frame_size;
uint32_t dec_frame_size;
uint32_t counter_plc_fec;
};
struct {
@ -338,7 +339,7 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
return SWITCH_STATUS_GENERR;
}
context->counter_plc_fec = 0;
}
codec->private_info = context;
@ -352,6 +353,7 @@ static switch_status_t switch_opus_destroy(switch_codec_t *codec)
if (context) {
if (context->decoder_object) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tried PLC or FEC %d times \n", context->counter_plc_fec);
opus_decoder_destroy(context->decoder_object);
context->decoder_object = NULL;
}
@ -400,9 +402,13 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
unsigned int *flag)
{
struct opus_context *context = codec->private_info;
switch_core_session_t *session = codec->session;
stfu_instance_t *jb = NULL;
stfu_frame_t next_frame;
int samples = 0;
uint32_t frame_size;
uint32_t frame_samples;
uint32_t found_frame;
if (!context) {
return SWITCH_STATUS_FALSE;
@ -411,7 +417,28 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
frame_samples = *decoded_data_len / 2 / codec->implementation->number_of_channels;
frame_size = frame_samples - (frame_samples % (codec->implementation->actual_samples_per_second / 400));
samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, frame_size, !!(*flag & SFF_PLC));
/*FEC: shameless rip-off from mod_silk.c . OPUS only supports n+1 FEC , SILK is supposed to work with n+1, n+2*/
if (*flag & SFF_PLC) {
context->counter_plc_fec++;
if (session) {
jb = switch_core_session_get_jb(session, SWITCH_MEDIA_TYPE_AUDIO);
}
if (jb && codec->cur_frame) {
found_frame = stfu_n_copy_next_frame(jb, (uint32_t)codec->cur_frame->timestamp, codec->cur_frame->seq, 1, &next_frame);
if (found_frame) {
samples = opus_decode(context->decoder_object, next_frame.data, next_frame.dlen, decoded_data, frame_size, 1); /* opus_decode() does PLC if there's no FEC in the packet*/
if (samples < 0 ) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error (FEC): %s!\n", opus_strerror(samples));
return SWITCH_STATUS_FALSE;
} else {
*decoded_data_len = samples * 2 * codec->implementation->number_of_channels;
return SWITCH_STATUS_SUCCESS;
}
}
}
}
samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, frame_size, 0);
if (samples < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error: %s fs:%u plc:%d!\n", opus_strerror(samples), frame_size, !!(*flag & SFF_PLC));
@ -490,8 +517,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
codec_interface->parse_fmtp = switch_opus_fmtp_parse;
settings = default_codec_settings;
if (opus_prefs.maxaveragebitrate){
settings.maxaveragebitrate = opus_prefs.maxaveragebitrate;
}
if (opus_prefs.maxplaybackrate) {
settings.maxplaybackrate = opus_prefs.maxplaybackrate;
}
for (x = 0; x < 3; x++) {
settings.ptime = mss / 1000;

View File

@ -370,6 +370,12 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *
if ((all && !fail) || (!all && pass)) {
anti_action = SWITCH_FALSE;
}
if (all && total != pass) {
proceed = 1;
pass = 0;
fail++;
anti_action = SWITCH_TRUE;
}
}
switch_safe_free(field_expanded);

View File

@ -47,7 +47,7 @@
#define RTMP_DEFAULT_PORT 1935
#define RTMP_TCP_READ_BUF 2048 * 16
#define AMF_MAX_SIZE 2048 * 16
#define AMF_MAX_SIZE 2048 * 16 * 2
#define SUPPORT_SND_NONE 0x0000
#define SUPPORT_SND_ADPCM 0x0002

View File

@ -1464,6 +1464,86 @@ static int flush_listener_callback(void *pArg, int argc, char **argv, char **col
return 0;
}
void skinny_lock_device_name(listener_t *listener, char *device_name)
{
switch_time_t started = 0;
unsigned int elapsed = 0;
device_name_lock_t *dnl;
if ( listener->profile->debug >= 9 ) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "lock device name '%s'\n", device_name);
}
started = switch_micro_time_now();
/* global mutex on hash operations */
switch_mutex_lock(listener->profile->device_name_lock_mutex);
dnl = (device_name_lock_t *) switch_core_hash_find(listener->profile->device_name_lock_hash, device_name);
if ( ! dnl ) {
if ( listener->profile->debug >= 9 ) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "creating device name lock for device name '%s'\n", device_name);
}
dnl = switch_core_alloc(listener->profile->pool, sizeof(*dnl));
switch_mutex_init(&dnl->flag_mutex, SWITCH_MUTEX_NESTED, listener->profile->pool);
switch_core_hash_insert(listener->profile->device_name_lock_hash, device_name, dnl);
}
switch_mutex_unlock(listener->profile->device_name_lock_mutex);
if ( listener->profile->debug >= 9 ) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "setting device name lock for device name '%s'\n", device_name);
}
switch_set_flag_locked(dnl, DNLFLAG_INUSE);
if ((elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000)) > 5) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "device name lock took more than 5ms for '%s' (%d)\n", device_name, elapsed);
}
if ( listener->profile->debug >= 9 ) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "locked device name '%s'\n", device_name);
}
}
void skinny_unlock_device_name(listener_t *listener, char *device_name)
{
switch_time_t started = 0;
unsigned int elapsed = 0;
device_name_lock_t *dnl;
if ( listener->profile->debug >= 9 ) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "unlock device name '%s'\n", device_name);
}
started = switch_micro_time_now();
/* global mutex on hash operations */
switch_mutex_lock(listener->profile->device_name_lock_mutex);
dnl = (device_name_lock_t *) switch_core_hash_find(listener->profile->device_name_lock_hash, device_name);
switch_mutex_unlock(listener->profile->device_name_lock_mutex);
if ( ! dnl ) {
skinny_log_l(listener, SWITCH_LOG_WARNING, "request to unlock and no lock structure for '%s'\n", device_name);
/* since it didn't exist, nothing to unlock, don't bother creating structure now */
} else {
if ( listener->profile->debug >= 9 ) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "clearing device name lock on '%s'\n", device_name);
}
switch_clear_flag_locked(dnl, DNLFLAG_INUSE);
}
/* Should we clean up the lock structure here, or does it ever get reclaimed? I don't think memory is released
so attempting to clear it up here likely would just result in a leak. */
if ((elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000)) > 5) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "device name unlock took more than 5ms for '%s' (%d)\n", device_name, elapsed);
}
if ( listener->profile->debug >= 9 ) {
skinny_log_l(listener, SWITCH_LOG_DEBUG, "unlocked device name '%s'\n", device_name);
}
}
void skinny_clean_device_from_db(listener_t *listener, char *device_name)
{
if(!zstr(device_name)) {
@ -1579,7 +1659,9 @@ static void flush_listener(listener_t *listener)
switch_safe_free(sql);
}
skinny_lock_device_name(listener, listener->device_name);
skinny_clean_listener_from_db(listener);
skinny_unlock_device_name(listener, listener->device_name);
strcpy(listener->device_name, "");
}
@ -1658,7 +1740,7 @@ switch_status_t kill_listener(listener_t *listener, void *pvt)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Killing listener %s:%d.\n",
listener->device_name, listener->device_instance);
switch_clear_flag(listener, LFLAG_RUNNING);
switch_clear_flag_locked(listener, LFLAG_RUNNING);
close_socket(&listener->sock, listener->profile);
return SWITCH_STATUS_SUCCESS;
}
@ -1740,11 +1822,12 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Connection Open\n");
}
listener->connect_time = switch_epoch_time_now(NULL);
switch_set_flag_locked(listener, LFLAG_RUNNING);
keepalive_listener(listener, NULL);
add_listener(listener);
while (listener_is_ready(listener)) {
status = skinny_read_packet(listener, &request);
@ -2116,6 +2199,8 @@ static switch_status_t load_skinny_config(void)
switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool);
switch_mutex_init(&profile->flag_mutex, SWITCH_MUTEX_NESTED, profile->pool);
switch_mutex_init(&profile->device_name_lock_mutex, SWITCH_MUTEX_NESTED, profile->pool);
for (param = switch_xml_child(xsettings, "param"); param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value");
@ -2233,6 +2318,8 @@ static switch_status_t load_skinny_config(void)
continue;
}
/* Device Name Locks */
switch_core_hash_init(&profile->device_name_lock_hash);
/* Device types */
switch_core_hash_init(&profile->device_type_params_hash);

View File

@ -127,6 +127,9 @@ struct skinny_profile {
int non_blocking;
switch_hash_t *soft_key_set_sets_hash;
switch_hash_t *device_type_params_hash;
/* lock on device names for multiple connection handling */
switch_mutex_t *device_name_lock_mutex;
switch_hash_t *device_name_lock_hash;
/* extensions */
char *ext_voicemail;
char *ext_redial;
@ -169,6 +172,23 @@ typedef enum {
SKINNY_ACTION_WAIT
} skinny_action_t;
/*****************************************************************************/
/* DEVICE NAME LOCK TYPES */
/*****************************************************************************/
typedef enum {
DNLFLAG_INUSE = (1 << 0),
} device_name_lock_flag_t;
struct device_name_lock {
char device_name[16];
switch_mutex_t *flag_mutex;
uint32_t flags;
};
typedef struct device_name_lock device_name_lock_t;
/*****************************************************************************/
/* LISTENERS TYPES */
/*****************************************************************************/
@ -197,6 +217,7 @@ struct listener {
switch_mutex_t *flag_mutex;
uint32_t flags;
time_t expire_time;
time_t connect_time;
switch_time_t digit_timeout_time;
struct listener *next;
char *ext_voicemail;
@ -301,6 +322,12 @@ switch_status_t keepalive_listener(listener_t *listener, void *pvt);
void skinny_clean_listener_from_db(listener_t *listener);
void skinny_clean_device_from_db(listener_t *listener, char *device_name);
/*****************************************************************************/
/* DEVICE NAME LOCK FUNCTIONS */
/*****************************************************************************/
void skinny_lock_device_name(listener_t *listener, char *device_name);
void skinny_unlock_device_name(listener_t *listener, char *device_name);
/*****************************************************************************/
/* CHANNEL FUNCTIONS */
/*****************************************************************************/

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");
/* clean up all traces before adding to database */
skinny_lock_device_name(listener, request->data.reg.device_name);
skinny_clean_device_from_db(listener, request->data.reg.device_name);
if (switch_xml_locate_user("id", request->data.reg.device_name, profile->domain, "", &xroot, &xdomain, &xuser, &xgroup, params) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Can't find device [%s@%s]\n"
"You must define a domain called '%s' in your directory and add a user with id=\"%s\".\n"
, request->data.reg.device_name, profile->domain, profile->domain, request->data.reg.device_name);
/* unlock before trying to send response in case socket blocks */
skinny_unlock_device_name(listener, request->data.reg.device_name);
send_register_reject(listener, "Device not found");
status = SWITCH_STATUS_FALSE;
goto end;
@ -1135,6 +1140,10 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Device %s:%d is already registered on another listener.\n",
request->data.reg.device_name, request->data.reg.instance);
/* unlock before trying to send response in case socket blocks */
skinny_unlock_device_name(listener, request->data.reg.device_name);
send_register_reject(listener, "Device is already registered on another listener");
status = SWITCH_STATUS_FALSE;
goto end;
@ -1156,11 +1165,12 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r
switch_safe_free(sql);
}
switch_copy_string(listener->device_name, request->data.reg.device_name, 16);
listener->device_instance = request->data.reg.instance;
listener->device_type = request->data.reg.device_type;
skinny_unlock_device_name(listener, request->data.reg.device_name);
xskinny = switch_xml_child(xuser, "skinny");
if (xskinny) {
if ((xparams = switch_xml_child(xskinny, "params"))) {

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)
{
const char *hval = NULL;
switch_channel_t *channel = switch_core_session_get_channel(session);
private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
switch_status_t status = SWITCH_STATUS_SUCCESS;
@ -89,6 +90,23 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
switch_core_media_absorb_sdp(session);
}
if ((hval = switch_channel_get_variable(channel, "sip_watch_headers"))) {
char *dupvar = NULL;
char *watch_headers[10];
unsigned int numhdrs = 0;
int i = 0;
dupvar = switch_core_session_strdup(session, hval);
numhdrs = switch_separate_string(dupvar, ',', watch_headers, switch_arraylen(watch_headers));
if (numhdrs) {
char **wheaders = switch_core_session_alloc(session, ((numhdrs+1) * sizeof(wheaders[0])));
for (i = 0; i < numhdrs; i++) {
wheaders[i] = watch_headers[i];
}
wheaders[i] = NULL;
tech_pvt->watch_headers = wheaders;
}
}
if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING) || switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE)) {
sofia_set_flag(tech_pvt, TFLAG_RECOVERED);
}
@ -2658,9 +2676,15 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
stream->write_function(stream, "Dialplan \t%s\n", switch_str_nil(profile->dialplan));
stream->write_function(stream, "Context \t%s\n", switch_str_nil(profile->context));
stream->write_function(stream, "Challenge Realm \t%s\n", zstr(profile->challenge_realm) ? "auto_to" : profile->challenge_realm);
for (x = 0; x < profile->rtpip_index; x++) {
stream->write_function(stream, "RTP-IP \t%s\n", switch_str_nil(profile->rtpip[x]));
}
for (x = 0; x < profile->rtpip_index6; x++) {
stream->write_function(stream, "RTP-IP \t%s\n", switch_str_nil(profile->rtpip6[x]));
}
if (profile->extrtpip) {
stream->write_function(stream, "Ext-RTP-IP \t%s\n", profile->extrtpip);
}
@ -2962,6 +2986,9 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl
for (x = 0; x < profile->rtpip_index; x++) {
stream->write_function(stream, " <rtp-ip>%s</rtp-ip>\n", switch_str_nil(profile->rtpip[x]));
}
for (x = 0; x < profile->rtpip_index6; x++) {
stream->write_function(stream, " <rtp-ip>%s</rtp-ip>\n", switch_str_nil(profile->rtpip6[x]));
}
if (profile->extrtpip) {
stream->write_function(stream, " <ext-rtp-ip>%s</ext-rtp-ip>\n", profile->extrtpip);
}
@ -5449,7 +5476,7 @@ static void general_event_handler(switch_event_t *event)
}
if (!strcmp(profile->rtpip[x], old_ip6)) {
profile->rtpip[x] = switch_core_strdup(profile->pool, new_ip6);
profile->rtpip6[x] = switch_core_strdup(profile->pool, new_ip6);
rb++;
}
}

View File

@ -96,6 +96,7 @@ typedef struct private_object private_object_t;
#define MY_EVENT_RECOVERY_RECOVERED "sofia::recovery_recovered"
#define MY_EVENT_ERROR "sofia::error"
#define MY_EVENT_PROFILE_START "sofia::profile_start"
#define MY_EVENT_NOTIFY_WATCHED_HEADER "sofia::notify_watched_header"
#define MULTICAST_EVENT "multicast::event"
#define SOFIA_REPLACES_HEADER "_sofia_replaces_"
@ -574,11 +575,14 @@ struct sofia_profile {
char *shutdown_type;
char *extrtpip;
char *rtpip[MAX_RTPIP];
char *rtpip6[MAX_RTPIP];
char *jb_msec;
switch_payload_t te;
switch_payload_t recv_te;
uint32_t rtpip_index;
uint32_t rtpip_next;
uint32_t rtpip_index6;
uint32_t rtpip_next6;
char *rtcp_audio_interval_msec;
char *rtcp_video_interval_msec;
@ -805,6 +809,7 @@ struct private_object {
sofia_cid_type_t cid_type;
uint32_t session_timeout;
enum nua_session_refresher session_refresher;
char **watch_headers;
char *respond_phrase;
int respond_code;
char *respond_dest;

View File

@ -1136,6 +1136,7 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
}
if (!fs) {
sip_remote_party_id_t *rpid;
if ((passerted = sip_p_asserted_identity(sip))) {
if (passerted->paid_url->url_user) {
number = passerted->paid_url->url_user;
@ -1151,6 +1152,21 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
end_of(name) = '\0';
}
}
} else if ((rpid = sip_remote_party_id(sip))) {
if (rpid->rpid_url->url_user) {
number = rpid->rpid_url->url_user;
}
if (!zstr(rpid->rpid_display)) {
dup = strdup(rpid->rpid_display);
if (*dup == '"') {
name = dup + 1;
} else {
name = dup;
}
if (end_of(name) == '"') {
end_of(name) = '\0';
}
}
}
}
@ -1256,6 +1272,21 @@ static void tech_send_ack(nua_handle_t *nh, private_object_t *tech_pvt)
}
static void notify_watched_header(switch_core_session_t *session, const char *msgline, const char *hdrname, const char *hdrval)
{
switch_event_t *event = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Found known watched header in message '%s', %s: %s\n", msgline, hdrname, hdrval);
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_NOTIFY_WATCHED_HEADER) == SWITCH_STATUS_SUCCESS) {
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Message", msgline);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Header-Name", hdrname);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Header-Value", hdrval);
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed creating event of type %s!\n", MY_EVENT_NOTIFY_WATCHED_HEADER);
}
}
//sofia_dispatch_event_t *de
static void our_sofia_event_callback(nua_event_t event,
@ -1331,6 +1362,56 @@ static void our_sofia_event_callback(nua_event_t event,
}
}
if (session && tech_pvt && tech_pvt->watch_headers && sip) {
char msgline[512];
int hi;
msg_header_t *h = NULL;
if (sip->sip_request) {
h = (msg_header_t *)sip->sip_request;
msg_header_field_e(msgline, sizeof(msgline), h, 0);
} else if (sip->sip_status) {
h = (msg_header_t *)sip->sip_status;
msg_header_field_e(msgline, sizeof(msgline), h, 0);
}
if (h) {
sip_unknown_t *un = NULL;
char buf[512];
char *c = NULL;
msgline[sizeof(msgline)-1] = '\0';
c = strchr(msgline, '\r');
if (c) {
*c = '\0';
}
/* Faster (ie hash-based) search here would be nice? ie, make watch_headers a hash? */
/* Search first in the valid headers */
for (h = h->sh_succ; h; h = h->sh_succ) {
sip_header_t *sh = (sip_header_t *)h;
if (!sh->sh_class->hc_name) {
continue;
}
for (hi = 0; tech_pvt->watch_headers[hi]; hi++) {
if (!strcasecmp(tech_pvt->watch_headers[hi], sh->sh_class->hc_name)) {
msg_header_field_e(buf, sizeof(buf), h, 0);
buf[sizeof(buf)-1] = '\0';
notify_watched_header(session, msgline, sh->sh_class->hc_name, buf);
}
}
}
/* Search now in the unknown headers */
for (un = sip->sip_unknown; un; un = un->un_next) {
for (hi = 0; tech_pvt->watch_headers[hi]; hi++) {
if (!strcasecmp(tech_pvt->watch_headers[hi], un->un_name)) {
notify_watched_header(session, msgline, un->un_name, un->un_value);
}
}
}
}
}
if (sofia_test_pflag(profile, PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip && (event < nua_r_set_params || event > nua_r_authenticate)) {
sip_authorization_t const *authorization = NULL;
@ -1510,6 +1591,7 @@ static void our_sofia_event_callback(nua_event_t event,
sofia_handle_sip_i_info(nua, profile, nh, session, sip, de, tags);
break;
case nua_i_update:
sofia_update_callee_id(session, profile, sip, SWITCH_TRUE);
break;
case nua_r_update:
if (session && tech_pvt && locked) {
@ -4137,6 +4219,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
profile->ob_failed_calls = 0;
profile->shutdown_type = "false";
profile->rtpip_index = 0;
profile->rtpip_index6 = 0;
if (xprofiledomain) {
profile->domain_name = switch_core_strdup(profile->pool, xprofiledomain);
@ -4635,10 +4718,19 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
} else {
ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
}
if (profile->rtpip_index < MAX_RTPIP) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, ip);
if (strchr(ip, ':')) {
if (profile->rtpip_index < MAX_RTPIP) {
profile->rtpip6[profile->rtpip_index6++] = switch_core_strdup(profile->pool, ip);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Max IPs configured for profile %s.\n", profile->name);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Max IPs configured for profile %s.\n", profile->name);
if (profile->rtpip_index6 < MAX_RTPIP) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, ip);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Max IPs configured for profile %s.\n", profile->name);
}
}
} else if (!strcasecmp(var, "sip-ip")) {
char *ip = mod_sofia_globals.guess_ip;
@ -5373,7 +5465,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
profile->sipip = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
}
if (!profile->rtpip[0]) {
if (!profile->rtpip[0] && !profile->rtpip6[0]) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
}
@ -5406,7 +5498,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
profile->sdp_username = switch_core_strdup(profile->pool, "FreeSWITCH");
}
if (!profile->rtpip[0]) {
if (!profile->rtpip[0] && !profile->rtpip6[0]) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Setting ip to '127.0.0.1'\n");
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, "127.0.0.1");
}
@ -7911,6 +8003,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
if ((a_session = switch_core_session_locate(br_a))) {
const char *moh = profile->hold_music;
switch_core_session_t *tmpsess = NULL;
switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
switch_caller_profile_t *prof = switch_channel_get_caller_profile(channel_b);
const char *tmp;
@ -7941,6 +8034,15 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
} else {
switch_ivr_session_transfer(a_session, "park", "inline", NULL);
}
if (switch_true(switch_channel_get_variable(channel_a, "recording_follow_transfer"))) {
switch_core_media_bug_transfer_recordings(session, a_session);
}
if (switch_true(switch_channel_get_variable(channel_b, "recording_follow_transfer")) && (tmpsess = switch_core_session_locate(br_a))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE,
"Early transfer detected with no media, moving recording bug to other leg\n");
switch_core_media_bug_transfer_recordings(b_session, tmpsess);
switch_core_session_rwunlock(tmpsess);
}
switch_core_session_rwunlock(a_session);
@ -8024,6 +8126,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
switch_channel_set_variable(channel_b, "park_timeout", "2:attended_transfer");
switch_channel_set_state(channel_b, CS_PARK);
switch_channel_wait_for_state_timeout(channel_b, CS_PARK, 5000);
} else {
if (!br_a && !br_b) {

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->mparams.rtpip = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next++]);
if (profile->rtpip_next >= profile->rtpip_index) {
profile->rtpip_next = 0;
if (!zstr(profile->rtpip[profile->rtpip_next])) {
tech_pvt->mparams.rtpip4 = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next++]);
tech_pvt->mparams.rtpip = tech_pvt->mparams.rtpip4;
if (profile->rtpip_next >= profile->rtpip_index) {
profile->rtpip_next = 0;
}
}
if (!zstr(profile->rtpip[profile->rtpip_next6])) {
tech_pvt->mparams.rtpip6 = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next6++]);
if (zstr(tech_pvt->mparams.rtpip)) {
tech_pvt->mparams.rtpip = tech_pvt->mparams.rtpip6;
}
if (profile->rtpip_next6 >= profile->rtpip_index6) {
profile->rtpip_next6 = 0;
}
}
profile->inuse++;

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 *pres_on_reg = NULL;
int send_pres = 0;
int send_message_query = 0;
int is_tls = 0, is_tcp = 0, is_ws = 0, is_wss = 0;
char expbuf[35] = "";
time_t reg_time = switch_epoch_time_now(NULL);
@ -1265,6 +1266,7 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
char *sw_reg_host;
char *token_val = NULL;
if (sofia_private_p) {
sofia_private = *sofia_private_p;
}
@ -1761,6 +1763,7 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
reg_meta = var;
}
/* associated MWI account */
if (v_event && *v_event && (mwi_account = switch_event_get_header(*v_event, "mwi-account"))) {
dup_mwi_account = strdup(mwi_account);
switch_assert(dup_mwi_account != NULL);
@ -1774,6 +1777,26 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
mwi_host = (char *) reg_host;
}
/* per-profile unsolicited MWI on register */
if (sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER)) {
send_message_query = 2;
} else if (sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER)) {
send_message_query = 1;
} else {
send_message_query = 0;
}
/* per-account unsolicited MWI on register */
if (v_event && *v_event && (var = switch_event_get_header(*v_event, "send-message-query-on-register"))) {
if (switch_true(var)) {
send_message_query = 2;
} else if (!strcasecmp(var, "first-only")) {
send_message_query = 1;
} else {
send_message_query = 0;
}
}
if (regtype != REG_REGISTER) {
switch_goto_int(r, 0, end);
}
@ -2027,10 +2050,9 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
switch_snprintf(exp_param, sizeof(exp_param), "expires=%ld", exptime);
sip_contact_add_param(nua_handle_home(nh), sip->sip_contact, exp_param);
if ((sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER) ||
(reg_count == 1 && sofia_test_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER))) && debounce_ok) {
/* send unsolicited MWI if configured */
if (send_message_query == 2 || (reg_count == 1 && send_message_query == 1 && debounce_ok)) {
if (switch_event_create(&s_mwi_event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(s_mwi_event, SWITCH_STACK_BOTTOM, "Message-Account", "%s:%s@%s", proto, mwi_user, mwi_host);
switch_event_add_header_string(s_mwi_event, SWITCH_STACK_BOTTOM, "VM-Sofia-Profile", profile->name);

View File

@ -58,16 +58,29 @@
int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, mcast_flag_t flags)
{
uint32_t one = 1;
int family = AF_INET;
memset(handle, 0, sizeof(*handle));
if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(AF_INET, SOCK_DGRAM, 0)) <= 0 ) {
return -1;
if (strchr(host, ':')) {
family = AF_INET6;
}
handle->send_addr.sin_family = AF_INET;
handle->send_addr.sin_addr.s_addr = inet_addr(host);
handle->send_addr.sin_port = htons(port);
if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(family, SOCK_DGRAM, 0)) <= 0 ) {
return -1;
}
if (family == AF_INET6) {
handle->send_addr6.sin6_family = AF_INET6;
handle->send_addr6.sin6_port = htons(port);
inet_pton(AF_INET6, host, &(handle->send_addr6.sin6_addr));
handle->family = AF_INET6;
} else {
handle->send_addr.sin_family = AF_INET;
handle->send_addr.sin_addr.s_addr = inet_addr(host);
handle->send_addr.sin_port = htons(port);
handle->family = AF_INET;
}
if ( setsockopt(handle->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) != 0 ) {
close(handle->sock);
@ -76,28 +89,61 @@ int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle,
if ((flags & MCAST_RECV)) {
struct ip_mreq mreq;
if (handle->family == AF_INET) {
struct ip_mreq mreq;
handle->recv_addr.sin_family = AF_INET;
handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
handle->recv_addr.sin_port = htons(port);
handle->recv_addr.sin_family = AF_INET;
handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
handle->recv_addr.sin_port = htons(port);
mreq.imr_multiaddr.s_addr = inet_addr(host);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_multiaddr.s_addr = inet_addr(host);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
close(handle->sock);
handle->sock = -1;
return -1;
}
if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
close(handle->sock);
handle->sock = -1;
return -1;
if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) {
close(handle->sock);
handle->sock = -1;
return -1;
}
} else {
struct ipv6_mreq mreq;
struct addrinfo addr_criteria;
struct addrinfo *mcast_addr;
char service[80] = "";
memset(&addr_criteria, 0, sizeof(addr_criteria));
addr_criteria.ai_family = AF_UNSPEC;
addr_criteria.ai_socktype = SOCK_DGRAM;
addr_criteria.ai_protocol = IPPROTO_UDP;
addr_criteria.ai_flags |= AI_NUMERICHOST;
snprintf(service, sizeof(service), "%d", port);
getaddrinfo(host, service, &addr_criteria, &mcast_addr);
memset(&handle->recv_addr6, 0, sizeof(handle->recv_addr6));
handle->recv_addr6.sin6_family = AF_INET6;
handle->recv_addr6.sin6_port = htons(port);
inet_pton(AF_INET6, "::0", &(handle->recv_addr6.sin6_addr));
memcpy(&mreq.ipv6mr_multiaddr, &((struct sockaddr_in6 *)mcast_addr->ai_addr)->sin6_addr, sizeof(struct in6_addr));
mreq.ipv6mr_interface = 0;
setsockopt(handle->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr6, sizeof(handle->recv_addr6)) < 0) {
printf("FUCK (%s) %s\n", host, strerror(errno));
close(handle->sock);
handle->sock = -1;
return -1;
}
}
if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) {
close(handle->sock);
handle->sock = -1;
return -1;
}
}
handle->ttl = 1;
@ -155,7 +201,11 @@ ssize_t mcast_socket_send(mcast_handle_t *handle, void *data, size_t datalen)
datalen = sizeof(handle->buffer);
}
return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr));
if (handle->family == AF_INET6) {
return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr6, sizeof(handle->send_addr6));
} else {
return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr));
}
}
ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, int ms)
@ -175,6 +225,9 @@ ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, in
}
}
return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen);
if (handle->family == AF_INET6) {
return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr6, &addrlen);
} else {
return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen);
}
}

View File

@ -71,6 +71,9 @@ typedef struct {
unsigned char ttl;
struct sockaddr_in send_addr;
struct sockaddr_in recv_addr;
struct sockaddr_in6 send_addr6;
struct sockaddr_in6 recv_addr6;
int family;
unsigned char buffer[65536];
int ready;
} mcast_handle_t;

View File

@ -143,7 +143,7 @@ static void verto_deinit_ssl(verto_profile_t *profile)
static void close_file(ws_socket_t *sock)
{
if (*sock > -1) {
if (*sock != ws_sock_invalid) {
#ifndef WIN32
close(*sock);
#else
@ -155,7 +155,7 @@ static void close_file(ws_socket_t *sock)
static void close_socket(ws_socket_t *sock)
{
if (*sock > -1) {
if (*sock != ws_sock_invalid) {
shutdown(*sock, 2);
close_file(sock);
}
@ -1803,12 +1803,6 @@ error:
static void client_run(jsock_t *jsock)
{
jsock->local_addr.sin_family = AF_INET;
jsock->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
jsock->local_addr.sin_port = 0;
if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1, !!jsock->profile->vhosts) < 0) {
if (jsock->profile->vhosts) {
http_run(jsock);
@ -1920,7 +1914,7 @@ static void *SWITCH_THREAD_FUNC client_thread(switch_thread_t *thread, void *obj
switch_event_destroy(&jsock->vars);
switch_event_destroy(&jsock->user_vars);
if (jsock->client_socket > -1) {
if (jsock->client_socket != ws_sock_invalid) {
close_socket(&jsock->client_socket);
}
@ -2259,10 +2253,30 @@ static void verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *prof
{
uint32_t i;
tech_pvt->mparams->rtpip = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]);
if (!zstr(profile->rtpip[profile->rtpip_cur])) {
tech_pvt->mparams->rtpip4 = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]);
tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip4;
if (profile->rtpip_cur == profile->rtpip_index) {
profile->rtpip_cur = 0;
}
}
if (profile->rtpip_cur == profile->rtpip_index) {
profile->rtpip_cur = 0;
if (!zstr(profile->rtpip6[profile->rtpip_cur6])) {
tech_pvt->mparams->rtpip6 = switch_core_session_strdup(tech_pvt->session, profile->rtpip6[profile->rtpip_cur6++]);
if (zstr(tech_pvt->mparams->rtpip)) {
tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip6;
}
if (profile->rtpip_cur6 == profile->rtpip_index6) {
profile->rtpip_cur6 = 0;
}
}
if (zstr(tech_pvt->mparams->rtpip)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "%s has no media ip, check your configuration\n",
switch_channel_get_name(tech_pvt->channel));
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
}
tech_pvt->mparams->extrtpip = tech_pvt->mparams->extsipip = profile->extrtpip;
@ -3376,7 +3390,7 @@ static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock
switch_either(jsock->dialplan, jsock->profile->dialplan),
caller_id_name,
caller_id_number,
inet_ntoa(jsock->remote_addr.sin_addr),
jsock->remote_host,
cJSON_GetObjectCstr(dialog, "ani"),
cJSON_GetObjectCstr(dialog, "aniii"),
cJSON_GetObjectCstr(dialog, "rdnis"),
@ -3641,7 +3655,7 @@ static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, js
jevent = cJSON_Duplicate(params, 1);
switch_event_channel_broadcast(event_channel, &jevent, modname, globals.event_channel_id);
if (jsock->profile->mcast_pub.sock > -1) {
if (jsock->profile->mcast_pub.sock != ws_sock_invalid) {
if ((json_text = cJSON_PrintUnformatted(params))) {
if ( mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1) < 0 ) {
@ -3778,7 +3792,7 @@ static void jrpc_init(void)
static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
static int start_jsock(verto_profile_t *profile, ws_socket_t sock, int family)
{
jsock_t *jsock = NULL;
int flag = 1;
@ -3798,11 +3812,20 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
jsock = (jsock_t *) switch_core_alloc(pool, sizeof(*jsock));
jsock->pool = pool;
jsock->family = family;
len = sizeof(jsock->remote_addr);
if (family == PF_INET) {
len = sizeof(jsock->remote_addr);
if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) {
die("ACCEPT FAILED\n");
if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) {
die("ACCEPT FAILED\n");
}
} else {
len = sizeof(jsock->remote_addr6);
if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr6, &len)) < 0) {
die("ACCEPT FAILED\n");
}
}
for (i = 0; i < profile->i; i++) {
@ -3818,7 +3841,15 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
jsock->profile = profile;
if (zstr(jsock->name)) {
jsock->name = switch_core_sprintf(pool, "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port));
if (family == PF_INET) {
jsock->remote_port = ntohs(jsock->remote_addr.sin_port);
inet_ntop(AF_INET, &jsock->remote_addr.sin_addr, jsock->remote_host, sizeof(jsock->remote_host));
jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port);
} else {
jsock->remote_port = ntohs(jsock->remote_addr6.sin6_port);
inet_ntop(AF_INET6, &jsock->remote_addr6.sin6_addr, jsock->remote_host, sizeof(jsock->remote_host));
jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port);
}
}
jsock->ptype = ptype;
@ -3826,7 +3857,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Client Connect.\n", jsock->name);
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_CLIENT_CONNECT) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_profile_name", profile->name);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port));
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s:%d", jsock->remote_host, jsock->remote_port);
switch_event_fire(&s_event);
}
@ -3863,7 +3894,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
error:
if (jsock) {
if (jsock->client_socket > -1) {
if (jsock->client_socket != ws_sock_invalid) {
close_socket(&jsock->client_socket);
}
@ -3873,7 +3904,7 @@ static int start_jsock(verto_profile_t *profile, ws_socket_t sock)
return -1;
}
static ws_socket_t prepare_socket(int ip, uint16_t port)
static ws_socket_t prepare_socket(ips_t *ips)
{
ws_socket_t sock = ws_sock_invalid;
#ifndef WIN32
@ -3881,29 +3912,48 @@ static ws_socket_t prepare_socket(int ip, uint16_t port)
#else
char reuse_addr = 1;
#endif
int family;
struct sockaddr_in addr;
struct sockaddr_in6 addr6;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
if (strchr(ips->local_ip, ':')) {
family = PF_INET6;
} else {
family = PF_INET;
}
if ((sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
die("Socket Error!\n");
}
if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) {
die("Socket setsockopt Error!\n");
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ip;
addr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
die("Bind Error!\n");
}
if (family == PF_INET) {
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ips->local_ip);
addr.sin_port = htons(ips->local_port);
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
die("Bind Error!\n");
}
} else {
memset(&addr6, 0, sizeof(addr6));
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(ips->local_port);
inet_pton(AF_INET6, ips->local_ip, &(addr6.sin6_addr));
if (bind(sock, (struct sockaddr *) &addr6, sizeof(addr6)) < 0) {
die("Bind Error!\n");
}
}
if (listen(sock, MAXPENDING) < 0) {
die("Listen error\n");
}
ips->family = family;
return sock;
error:
@ -3915,7 +3965,13 @@ static ws_socket_t prepare_socket(int ip, uint16_t port)
static void handle_mcast_sub(verto_profile_t *profile)
{
int bytes = mcast_socket_recv(&profile->mcast_sub, NULL, 0, 0);
int bytes;
if (profile->mcast_sub.sock == ws_sock_invalid) {
return;
}
bytes = mcast_socket_recv(&profile->mcast_sub, NULL, 0, 0);
if (bytes > 0) {
cJSON *json;
@ -3979,7 +4035,7 @@ static int profile_one_loop(verto_profile_t *profile)
if (profile->mcast_ip && pfds[x].sock == (switch_os_socket_t)profile->mcast_sub.sock) {
handle_mcast_sub(profile);
} else {
start_jsock(profile, pfds[x].sock);
start_jsock(profile, pfds[x].sock, profile->ip[x].family);
}
}
}
@ -3991,52 +4047,6 @@ static int profile_one_loop(verto_profile_t *profile)
}
static int runtime(verto_profile_t *profile)
{
int i;
for (i = 0; i < profile->i; i++) {
if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) {
die("Client Socket Error!\n");
}
}
if (profile->mcast_ip) {
if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) {
die("mcast recv socket create");
}
if (mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) {
mcast_socket_close(&profile->mcast_sub);
die("mcast send socket create");
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1);
}
while(profile->running) {
if (profile_one_loop(profile) < 0) {
goto error;
}
}
if (profile->mcast_sub.sock > -1) {
mcast_socket_close(&profile->mcast_sub);
}
if (profile->mcast_pub.sock > -1) {
mcast_socket_close(&profile->mcast_pub);
}
return 0;
error:
return -1;
}
static void kill_profile(verto_profile_t *profile)
{
jsock_t *p;
@ -4092,6 +4102,67 @@ static void kill_profiles(void)
}
static int runtime(verto_profile_t *profile)
{
int i;
int r = 0;
int listeners = 0;
for (i = 0; i < profile->i; i++) {
//if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) {
if ((profile->server_socket[i] = prepare_socket(&profile->ip[i])) != ws_sock_invalid) {
listeners++;
}
}
if (!listeners) {
die("Client Socket Error! No Listeners!\n");
}
if (profile->mcast_ip) {
int ok = 1;
if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) {
ok++;
}
if (ok && mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) {
mcast_socket_close(&profile->mcast_sub);
ok = 0;
}
if (ok) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Disabled\n");
}
}
while(profile->running) {
if (profile_one_loop(profile) < 0) {
goto error;
}
}
error:
if (profile->mcast_sub.sock != ws_sock_invalid) {
mcast_socket_close(&profile->mcast_sub);
}
if (profile->mcast_pub.sock != ws_sock_invalid) {
mcast_socket_close(&profile->mcast_pub);
}
if (r) {
kill_profile(profile);
}
return r;
}
static void do_shutdown(void)
{
globals.running = 0;
@ -4105,20 +4176,35 @@ static void do_shutdown(void)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Done\n");
}
static void parse_ip(char *host, uint16_t *port, in_addr_t *addr, char *input)
static void parse_ip(char *host, switch_size_t host_len, uint16_t *port, char *input)
{
char *p;
struct hostent *hent;
//struct hostent *hent;
strncpy(host, input, 255);
host[255] = 0;
if ((p = strchr(host, ':')) != NULL) {
*p++ = '\0';
*port = (uint16_t)atoi(p);
if ((p = strchr(input, '['))) {
char *end = switch_find_end_paren(p, '[', ']');
if (end) {
p++;
strncpy(host, p, end - p);
if (*(end+1) == ':' && end + 2 < end_of_p(input)) {
end += 2;
if (end) {
*port = (uint16_t)atoi(end);
}
}
} else {
strncpy(host, "::", host_len);
}
} else {
strncpy(host, input, host_len);
if ((p = strrchr(host, ':')) != NULL) {
*p++ = '\0';
*port = (uint16_t)atoi(p);
}
}
#if 0
if ( host[0] < '0' || host[0] > '9' ) {
// Non-numeric host (at least it doesn't start with one). Convert it to ip addr first
if ((hent = gethostbyname(host)) != NULL) {
@ -4130,8 +4216,10 @@ static void parse_ip(char *host, uint16_t *port, in_addr_t *addr, char *input)
} else {
*addr = inet_addr(host);
}
#endif
}
static verto_profile_t *find_profile(const char *name)
{
verto_profile_t *p, *r = NULL;
@ -4264,7 +4352,7 @@ static switch_status_t parse_config(const char *cf)
if (!strcasecmp(var, "bind-local")) {
const char *secure = switch_xml_attr_soft(param, "secure");
if (i < MAX_BIND) {
parse_ip(profile->ip[profile->i].local_ip, &profile->ip[profile->i].local_port, &profile->ip[profile->i].local_ip_addr, val);
parse_ip(profile->ip[profile->i].local_ip, sizeof(profile->ip[profile->i].local_ip), &profile->ip[profile->i].local_port, val);
if (switch_true(secure)) {
profile->ip[profile->i].secure = 1;
}
@ -4316,10 +4404,18 @@ static switch_status_t parse_config(const char *cf)
if (zstr(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid RTP IP.\n");
} else {
if (profile->rtpip_index < MAX_RTPIP -1) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val);
if (strchr(val, ':')) {
if (profile->rtpip_index6 < MAX_RTPIP -1) {
profile->rtpip6[profile->rtpip_index6++] = switch_core_strdup(profile->pool, val);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
if (profile->rtpip_index < MAX_RTPIP -1) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
}
}
}
} else if (!strcasecmp(var, "ext-rtp-ip")) {

View File

@ -106,9 +106,8 @@ struct jsock_s {
unsigned char buf[65535];
char *name;
jsock_type_t ptype;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
struct sockaddr_in send_addr;
struct sockaddr_in6 remote_addr6;
#ifndef WIN32
struct passwd pw;
#endif
@ -132,6 +131,11 @@ struct jsock_s {
char *dialplan;
char *context;
char remote_host[256];
int remote_port;
int family;
struct verto_profile_s *profile;
switch_thread_rwlock_t *rwlock;
@ -155,12 +159,12 @@ typedef struct jsock_s jsock_t;
#define MAX_BIND 25
#define MAX_RTPIP 25
struct ips {
typedef struct ips {
char local_ip[256];
in_addr_t local_ip_addr;
uint16_t local_port;
int secure;
};
int family;
} ips_t;
typedef enum {
TFLAG_SENT_MEDIA = (1 << 0),
@ -240,6 +244,10 @@ struct verto_profile_s {
int rtpip_index;
int rtpip_cur;
char *rtpip6[MAX_RTPIP];
int rtpip_index6;
int rtpip_cur6;
char *cand_acl[SWITCH_MAX_CAND_ACL];
uint32_t cand_acl_count;

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;
char *maskp;
int ll = 0;
int frag = 0;
again:
need = 2;
@ -741,8 +742,16 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
case WSOC_PING:
case WSOC_PONG:
{
//int fin = (wsh->buffer[0] >> 7) & 1;
int fin = (wsh->buffer[0] >> 7) & 1;
int mask = (wsh->buffer[1] >> 7) & 1;
if (fin) {
if (*oc == WSOC_CONTINUATION) {
frag = 1;
} else {
frag = 0;
}
}
if (mask) {
need += 4;
@ -837,6 +846,10 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
goto again;
}
if (frag) {
goto again;
}
*(wsh->payload+wsh->rplen) = '\0';

View File

@ -757,7 +757,10 @@ static switch_status_t check_attached_sessions(listener_t *listener, int *msgs_s
sp->uuid_str, switch_channel_state_name(sp->channel_state));
ei_x_new_with_version(&ebuf);
ei_x_encode_tuple_header(&ebuf, 2);
ei_x_encode_atom(&ebuf, "call_hangup");
_ei_x_encode_string(&ebuf, sp->uuid_str);
switch_mutex_lock(listener->sock_mutex);
ei_sendto(listener->ec, listener->sockfd, &sp->process, &ebuf);
(*msgs_sent)++;

View File

@ -401,8 +401,12 @@ SWITCH_STANDARD_APP(socket_function)
listener_t *listener;
int argc = 0, x = 0;
char *argv[80] = { 0 };
char *hosts[50] = { 0 };
unsigned int hosts_count = 0;
switch_status_t connected = SWITCH_STATUS_FALSE;
char *mydata;
switch_channel_t *channel = NULL;
char errbuf[512] = {0};
channel = switch_core_session_get_channel(session);
@ -415,47 +419,58 @@ SWITCH_STANDARD_APP(socket_function)
return;
}
host = argv[0];
hosts_count = switch_split(argv[0], '|', hosts);
if (zstr(host)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing Host!\n");
return;
}
for(x = 0; x < hosts_count; x++) {
host = hosts[x];
if ((port_name = strrchr(host, ':'))) {
*port_name++ = '\0';
port = (switch_port_t) atoi(port_name);
}
if (zstr(host)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing Host!\n");
continue;
}
if ((path = strchr((port_name ? port_name : host), '/'))) {
*path++ = '\0';
switch_channel_set_variable(channel, "socket_path", path);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Trying host: %s\n", host);
switch_channel_set_variable(channel, "socket_host", host);
if ((port_name = strrchr(host, ':'))) {
*port_name++ = '\0';
port = (switch_port_t) atoi(port_name);
}
if (switch_sockaddr_info_get(&sa, host, SWITCH_UNSPEC, port, 0, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
if ((path = strchr((port_name ? port_name : host), '/'))) {
*path++ = '\0';
switch_channel_set_variable(channel, "socket_path", path);
}
switch_channel_set_variable(channel, "socket_host", host);
if (switch_sockaddr_info_get(&sa, host, SWITCH_UNSPEC, port, 0, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
continue;
}
if (switch_socket_create(&new_sock, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, switch_core_session_get_pool(session))
!= SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
continue;
}
switch_socket_opt_set(new_sock, SWITCH_SO_KEEPALIVE, 1);
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_NODELAY, 1);
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_KEEPIDLE, 30);
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_KEEPINTVL, 30);
if ((connected = switch_socket_connect(new_sock, sa)) == SWITCH_STATUS_SUCCESS) {
break;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error: %s\n", switch_strerror(errno, errbuf, sizeof(errbuf)));
}//end hosts loop
if (connected != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
return;
}
if (switch_socket_create(&new_sock, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, switch_core_session_get_pool(session))
!= SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
return;
}
switch_socket_opt_set(new_sock, SWITCH_SO_KEEPALIVE, 1);
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_NODELAY, 1);
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_KEEPIDLE, 30);
switch_socket_opt_set(new_sock, SWITCH_SO_TCP_KEEPINTVL, 30);
if (switch_socket_connect(new_sock, sa) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Socket Error!\n");
return;
}
if (!(listener = switch_core_session_alloc(session, sizeof(*listener)))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Memory Error\n");
return;

View File

@ -8,6 +8,11 @@
<param name="mixer-conf-profile" value="sla"/>
<!-- if true, to attribute in offer uses URI instead of name/number -->
<param name="offer-uri" value="true"/>
<!-- how offers are distributed to clients (all, first, random). -->
<param name="offer-algorithm" value="all"/>
<!-- If offer is not answered after timeout, next client is offered (based on algorithm picked).
If no other clients are available, the call is rejected. Set to 0 to disable -->
<param name="offer-timeout-ms" value="5000"/>
<!-- if true, channel variables are added to rayo client offer -->
<param name="add-variables-to-offer" value="false"/>
<!-- if true, channel variables are added to offer, ringing, answered, and end events sent to rayo clients -->

View File

@ -1,6 +1,6 @@
/*
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013-2014, Grasshopper
* Copyright (C) 2013-2015, Grasshopper
*
* Version: MPL 1.1
*
@ -61,6 +61,10 @@ SWITCH_MODULE_DEFINITION(mod_rayo, mod_rayo_load, mod_rayo_shutdown, mod_rayo_ru
#define JOINED_CALL 1
#define JOINED_MIXER 2
#define OFFER_ALL 0
#define OFFER_FIRST 1
#define OFFER_RANDOM 2
struct rayo_actor;
struct rayo_client;
struct rayo_call;
@ -123,8 +127,12 @@ struct rayo_call {
struct rayo_actor base;
/** Definitive controlling party JID */
char *dcp_jid;
/** Potential controlling parties */
/** Potential controlling parties (have sent offers to) */
switch_hash_t *pcps;
/** Available controlling parties (not sent offers to) */
switch_hash_t *acps;
/** Number of available controlling parties */
int num_acps;
/** current idle start time */
switch_time_t idle_start_time;
/** true if fax is in progress */
@ -223,6 +231,8 @@ static struct {
int num_message_threads;
/** message delivery queue */
switch_queue_t *msg_queue;
/** in progress offer queue */
switch_queue_t *offer_queue;
/** shutdown flag */
int shutdown;
/** prevents context shutdown until all threads are finished */
@ -237,6 +247,10 @@ static struct {
int add_variables_to_offer;
/** if true, channel variables are added to answered, ringing, end events */
int add_variables_to_events;
/** How to distribute offers to clients */
int offer_algorithm;
/** How long to wait for offer response before retrying */
int offer_timeout_us;
} globals;
/**
@ -866,12 +880,13 @@ static void start_deliver_message_thread(switch_memory_pool_t *pool)
}
/**
* Stop all message threads
* Stop all threads
*/
static void stop_deliver_message_threads(void)
static void stop_all_threads(void)
{
globals.shutdown = 1;
switch_queue_interrupt_all(globals.msg_queue);
switch_queue_interrupt_all(globals.offer_queue);
switch_thread_rwlock_wrlock(globals.shutdown_rwlock);
}
@ -1219,6 +1234,7 @@ done:
switch_event_destroy(&call->answer_event);
}
switch_core_hash_destroy(&call->pcps);
switch_core_hash_destroy(&call->acps);
}
/**
@ -1404,6 +1420,8 @@ static struct rayo_call *rayo_call_init(struct rayo_call *call, switch_memory_po
call->rayo_app_started = 0;
call->answer_event = NULL;
switch_core_hash_init(&call->pcps);
switch_core_hash_init(&call->acps);
call->num_acps = 0;
}
switch_safe_free(call_jid);
@ -3825,6 +3843,171 @@ static int should_offer_to_client(struct rayo_client *rclient, char **offer_filt
return 0;
}
/**
* Offered call information
*/
struct offered_call_info {
/** Call JID */
char *call_jid;
/** Time this offer expires */
switch_time_t offer_time;
};
/**
* Deliver offer message to next available client(s)
*/
static int send_offer_to_clients(struct rayo_call *from_call, switch_core_session_t *session)
{
int i = 0;
int selection = 0;
int sent = 0;
switch_hash_index_t *hi = NULL;
iks *offer = NULL;
if (from_call->num_acps <= 0) {
return 0;
}
if (globals.offer_algorithm == OFFER_RANDOM) {
/* pick client at (not really) random */
selection = rand() % from_call->num_acps;
} else if (globals.offer_algorithm == OFFER_FIRST) {
/* send to first client */
selection = 0;
} else {
/* send to all clients */
selection = -1;
}
for (hi = switch_core_hash_first(from_call->acps); hi; hi = switch_core_hash_next(&hi)) {
if (i++ == selection || selection == -1) {
const char *to_client_jid = NULL;
const void *key;
void *val;
/* get client jid to send to */
switch_core_hash_this(hi, &key, NULL, &val);
to_client_jid = (const char *)key;
switch_assert(to_client_jid);
/* send offer to client, remembering jid as PCP */
if (!offer) {
offer = rayo_create_offer(from_call, session);
}
switch_core_hash_insert(from_call->pcps, to_client_jid, "1");
iks_insert_attrib(offer, "to", to_client_jid);
RAYO_SEND_MESSAGE_DUP(from_call, to_client_jid, offer);
/* remove client JID from list of available clients */
switch_core_hash_delete(from_call->acps, to_client_jid);
from_call->num_acps--;
sent = 1;
if (selection != -1) {
break;
}
}
}
switch_safe_free(hi);
/* queue offer information */
if (globals.offer_timeout_us > 0 && sent) {
struct offered_call_info *offered_call;
switch_zmalloc(offered_call, sizeof(*offered_call));
offered_call->offer_time = switch_micro_time_now();
offered_call->call_jid = strdup(RAYO_JID(from_call));
if (switch_queue_trypush(globals.offer_queue, offered_call) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Failed to queue offered call info! Offer timeout won't work on this call\n");
switch_safe_free(offered_call->call_jid);
switch_safe_free(offered_call);
}
}
if (offer) {
iks_delete(offer);
}
return sent;
}
/**
* Thread that monitors for timed out offers
* @param thread this thread
* @param obj unused
* @return NULL
*/
static void *SWITCH_THREAD_FUNC offer_timeout_thread(switch_thread_t *thread, void *obj)
{
struct offered_call_info *next_offer;
switch_thread_rwlock_rdlock(globals.shutdown_rwlock);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "New offer timeout thread\n");
while (!globals.shutdown) {
if (switch_queue_pop(globals.offer_queue, (void *)&next_offer) == SWITCH_STATUS_SUCCESS) {
switch_time_t now = switch_micro_time_now();
switch_time_t offer_timeout = next_offer->offer_time + globals.offer_timeout_us;
/* wait for timeout */
while (offer_timeout > now && !globals.shutdown) {
switch_time_t remain = offer_timeout - now;
remain = remain > 500000 ? 500000 : remain;
switch_sleep(remain);
now = switch_micro_time_now();
}
/* check if offer was accepted - it is accepted if the call has a DCP (definitive controlling party) */
if (!globals.shutdown) {
struct rayo_call *call = RAYO_CALL_LOCATE(next_offer->call_jid);
if (call) {
switch_mutex_lock(RAYO_ACTOR(call)->mutex);
if (zstr(rayo_call_get_dcp_jid(call))) {
switch_core_session_t *session = switch_core_session_locate(rayo_call_get_uuid(call));
if (session) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, offer timeout\n", RAYO_JID(call));
if (!send_offer_to_clients(call, session)) {
/* nobody to offer to, end call */
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, no more clients to offer, ending call\n", RAYO_JID(call));
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
}
switch_core_session_rwunlock(session);
}
}
switch_mutex_unlock(RAYO_ACTOR(call)->mutex);
RAYO_RELEASE(call);
}
}
switch_safe_free(next_offer->call_jid);
switch_safe_free(next_offer);
}
}
/* clean up queue */
while(switch_queue_trypop(globals.offer_queue, (void *)&next_offer) == SWITCH_STATUS_SUCCESS) {
switch_safe_free(next_offer->call_jid);
switch_safe_free(next_offer);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Offer timeout thread finished\n");
switch_thread_rwlock_unlock(globals.shutdown_rwlock);
return NULL;
}
/**
* Create a new offer timeout thread
* @param pool to use
*/
static void start_offer_timeout_thread(switch_memory_pool_t *pool)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, offer_timeout_thread, NULL, pool);
}
#define RAYO_USAGE "[client username 1,client username n]"
/**
* Offer call and park channel
@ -3874,7 +4057,6 @@ SWITCH_STANDARD_APP(rayo_app)
if (!call) {
/* offer control */
switch_hash_index_t *hi = NULL;
iks *offer = NULL;
char *clients_to_offer[16] = { 0 };
int clients_to_offer_count = 0;
@ -3888,7 +4070,6 @@ SWITCH_STANDARD_APP(rayo_app)
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_call_jid", RAYO_JID(call));
offer = rayo_create_offer(call, session);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Offering call for Rayo 3PCC\n");
if (!zstr(data)) {
@ -3904,7 +4085,6 @@ SWITCH_STANDARD_APP(rayo_app)
}
/* Offer call to all (or specified) ONLINE clients */
/* TODO load balance offers so first session doesn't always get offer first? */
switch_mutex_lock(globals.clients_mutex);
for (hi = switch_core_hash_first(globals.clients_roster); hi; hi = switch_core_hash_next(&hi)) {
struct rayo_client *rclient;
@ -3914,16 +4094,15 @@ SWITCH_STANDARD_APP(rayo_app)
rclient = (struct rayo_client *)val;
switch_assert(rclient);
/* is session available to take call? */
/* find clients available to take calls */
if (should_offer_to_client(rclient, clients_to_offer, clients_to_offer_count)) {
ok = 1;
switch_core_hash_insert(call->pcps, RAYO_JID(rclient), "1");
iks_insert_attrib(offer, "to", RAYO_JID(rclient));
RAYO_SEND_MESSAGE_DUP(call, RAYO_JID(rclient), offer);
switch_core_hash_insert(call->acps, RAYO_JID(rclient), "1");
call->num_acps++;
}
}
ok = send_offer_to_clients(call, session);
switch_mutex_unlock(globals.clients_mutex);
iks_delete(offer);
/* nobody to offer to */
if (!ok) {
@ -4158,6 +4337,8 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_
globals.pause_when_offline = 0;
globals.add_variables_to_offer = 0;
globals.add_variables_to_events = 0;
globals.offer_timeout_us = 5000000;
globals.offer_algorithm = OFFER_ALL;
/* get params */
{
@ -4203,6 +4384,25 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_
globals.add_variables_to_offer = 1;
globals.add_variables_to_events = 1;
}
} else if (!strcasecmp(var, "offer-timeout-ms")) {
int offer_timeout_ms = 0;
if (switch_is_number(val) && (offer_timeout_ms = atoi(val)) >= 0 && offer_timeout_ms < 120000) {
globals.offer_timeout_us = offer_timeout_ms * 1000;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring invalid value for offer-timeout-ms \"%s\"\n", val);
}
} else if (!strcasecmp(var, "offer-algorithm")) {
if (zstr(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No value for offer-algorithm\n");
} else if (!strcasecmp(val, "all")) {
globals.offer_algorithm = OFFER_ALL;
} else if (!strcasecmp(val, "first")) {
globals.offer_algorithm = OFFER_FIRST;
} else if (!strcasecmp(val, "random")) {
globals.offer_algorithm = OFFER_RANDOM;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring invalid value for offer-algorithm \"%s\"\n", val);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var);
}
@ -4881,6 +5081,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
switch_core_hash_init(&globals.cmd_aliases);
switch_thread_rwlock_create(&globals.shutdown_rwlock, pool);
switch_queue_create(&globals.msg_queue, 25000, pool);
switch_queue_create(&globals.offer_queue, 25000, pool);
globals.offline_logged = 1;
/* server commands */
@ -4930,6 +5131,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
start_deliver_message_thread(pool);
}
}
start_offer_timeout_thread(pool);
/* create admin client */
globals.console = rayo_console_client_create();
@ -4979,9 +5181,9 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rayo_shutdown)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for XMPP threads to stop\n");
xmpp_stream_context_destroy(globals.xmpp_context);
/* stop message threads */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for message threads to stop\n");
stop_deliver_message_threads();
/* stop threads */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for message and offer timeout threads to stop\n");
stop_all_threads();
if (globals.console) {
RAYO_RELEASE(globals.console);

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);
if (globals.encode == ENCODING_DEFAULT) {
headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
switch_url_encode(xml_text, xml_text_escaped, need_bytes);
switch_url_encode_opt(xml_text, xml_text_escaped, need_bytes, SWITCH_TRUE);
} else {
headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded");
switch_b64_encode((unsigned char *) xml_text, need_bytes / 3, (unsigned char *) xml_text_escaped, need_bytes);

View File

@ -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>

View File

@ -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 ))

View File

@ -65,19 +65,36 @@ typedef struct xml_binding {
typedef enum exten_types {
LDAP_EXTEN_ID = 0,
LDAP_EXTEN_CIDR,
LDAP_EXTEN_NUMBER_ALIAS,
LDAP_EXTEN_DIAL_STRING,
LDAP_EXTEN_PASSWORD,
LDAP_EXTEN_VM_ENABLED,
LDAP_EXTEN_REV_AUTH_USER,
LDAP_EXTEN_REV_AUTH_PASS,
LDAP_EXTEN_A1_HASH,
LDAP_EXTEN_VM_PASSWORD,
LDAP_EXTEN_VM_ENABLED,
LDAP_EXTEN_VM_MAILFROM,
LDAP_EXTEN_VM_MAILTO,
LDAP_EXTEN_VM_EMAILMSG,
LDAP_EXTEN_VM_NOTEMAILMSG,
LDAP_EXTEN_VM_ATTACHFILE,
LDAP_EXTEN_USER_CONTEXT,
LDAP_EXTEN_EFF_CLIDNAME,
LDAP_EXTEN_EFF_CLIDNUM,
LDAP_EXTEN_VM_NOTIFY_MAILTO,
LDAP_EXTEN_VM_ATTACH_FILE,
LDAP_EXTEN_VM_MESSAGE_EXT,
LDAP_EXTEN_VM_EMAIL_ALL_MSGS,
LDAP_EXTEN_VM_KEEP_LOCAL_AFTER_MAIL,
LDAP_EXTEN_VM_NOTIFY_EMAIL_ALL_MSGS,
LDAP_EXTEN_VM_SKIP_INSTRUCTIONS,
LDAP_EXTEN_VM_CC,
LDAP_EXTEN_VM_DISK_QUOTA,
LDAP_EXTEN_ACCOUNTCODE,
LDAP_EXTEN_RULESET,
LDAP_EXTEN_USER_CONTEXT,
LDAP_EXTEN_VM_MAILBOX,
LDAP_EXTEN_CALLGROUP,
LDAP_EXTEN_TOLL_ALLOW,
LDAP_EXTEN_EFF_CLIDNUM,
LDAP_EXTEN_EFF_CLIDNAME,
LDAP_EXTEN_OUT_CLIDNUM,
LDAP_EXTEN_OUT_CLIDNAME,
LDAP_EXTEN_DOMAIN_NAME
/* not used now
LDAP_EXTEN_AREACODE,
LDAP_EXTEN_CID_EXTNAME,
LDAP_EXTEN_CID_EXTNUM,
@ -99,6 +116,7 @@ typedef enum exten_types {
LDAP_EXTEN_HOTLINE_ACTIVE,
LDAP_EXTEN_HOTLINE_DEST,
LDAP_EXTEN_CLASSOFSERVICE
*/
} exten_type_t;
struct xml_ldap_attribute {
@ -236,6 +254,20 @@ static switch_status_t do_config(void)
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("number-alias", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_NUMBER_ALIAS;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("dial-string", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_DIAL_STRING;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("password", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_PASSWORD;
attr_list->len = strlen(m);
@ -243,8 +275,22 @@ static switch_status_t do_config(void)
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-enabled", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_ENABLED;
} else if (!strncasecmp("reverse-auth-user", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_REV_AUTH_USER;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("reverse-auth-pass", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_REV_AUTH_PASS;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("a1-hash", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_A1_HASH;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
@ -257,6 +303,13 @@ static switch_status_t do_config(void)
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-enabled", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_ENABLED;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-mailfrom", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_MAILFROM;
attr_list->len = strlen(m);
@ -271,28 +324,77 @@ static switch_status_t do_config(void)
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-email-all-messages", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_EMAILMSG;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-notify-email-all-messages", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_NOTEMAILMSG;
} else if (!strncasecmp("vm-notify-mailto", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_NOTIFY_MAILTO;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-attach-file", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_ATTACHFILE;
attr_list->type = LDAP_EXTEN_VM_ATTACH_FILE;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-message-ext", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_MESSAGE_EXT;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-email-all-messages", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_EMAIL_ALL_MSGS;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-keep-local-after-mail", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_KEEP_LOCAL_AFTER_MAIL;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-notify-email-all-messages", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_NOTIFY_EMAIL_ALL_MSGS;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-skip-instructions", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_SKIP_INSTRUCTIONS;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-cc", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_CC;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("vm-disk-quota", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_DISK_QUOTA;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
/* Variables */
} else if (!strncasecmp("accountcode", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_ACCOUNTCODE;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("user_context", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_USER_CONTEXT;
attr_list->len = strlen(m);
@ -300,8 +402,22 @@ static switch_status_t do_config(void)
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("effective_caller_id_name", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_EFF_CLIDNAME;
} else if (!strncasecmp("vm_mailbox", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_VM_MAILBOX;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("callgroup", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_CALLGROUP;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("toll_allow", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_TOLL_ALLOW;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
@ -314,15 +430,22 @@ static switch_status_t do_config(void)
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("accountcode", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_ACCOUNTCODE;
} else if (!strncasecmp("effective_caller_id_name", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_EFF_CLIDNAME;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("ruleset", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_RULESET;
} else if (!strncasecmp("outbound_caller_id_number", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_OUT_CLIDNUM;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
attr_list->next = memset(attr_list->next, 0, sizeof(*attr_list));
attr_list = attr_list->next;
} else if (!strncasecmp("outbound_caller_id_name", n, strlen(n))) {
attr_list->type = LDAP_EXTEN_OUT_CLIDNAME;
attr_list->len = strlen(m);
attr_list->val = strdup(m);
attr_list->next = malloc(sizeof(*attr_list));
@ -365,10 +488,13 @@ static switch_status_t trydir(switch_xml_t *pxml, int *xoff, LDAP * ld, char *di
LDAPMessage *msg, *entry;
xml_ldap_attribute_t *attr = NULL;
static char *fsattr[] =
{ "id", "cidr", "password", "vm-enabled", "vm-password", "vm-mailfrom", "vm-mailto",
"vm-email-all-messages", "vm-notify-email-all-messages", "vm-attach-file",
"user_context", "effective_caller_id_name", "effective_caller_id_number",
"accountcode", "ruleset", NULL };
{ "id", "cidr", "number-alias", "dial-string", "password", "reverse-auth-user",
"reverse-auth-pass", "a1-hash", "vm-password", "vm-enabled", "vm-mailfrom",
"vm-mailto", "vm-notify-mailto", "vm-attach-file", "vm-message-ext",
"vm-email-all-messages", "vm-keep-local-after-mail", "vm-notify-email-all-messages",
"vm-skip-instructions", "vm-cc", "vm-disk-quota", "accountcode", "user_context",
"vm_mailbox", "callgroup", "effective_caller_id_number", "effective_caller_id_name",
"outbound_caller_id_number", "outbound_caller_id_name", "toll_allow", NULL };
basedn = switch_mprintf(binding->basedn, dir_domain);
filter = switch_mprintf(binding->filter, dir_exten);

View File

@ -864,11 +864,15 @@ SWITCH_DECLARE(const char *) switch_get_addr(char *buf, switch_size_t len, switc
return SWITCH_BLANK_STRING;
}
memset(buf, 0, len);
if (in->family == AF_INET) {
return get_addr(buf, len, (struct sockaddr *) &in->sa, in->salen);
get_addr(buf, len, (struct sockaddr *) &in->sa, in->salen);
return buf;
}
return get_addr6(buf, len, (struct sockaddr_in6 *) &in->sa, in->salen);
get_addr6(buf, len, (struct sockaddr_in6 *) &in->sa, in->salen);
return buf;
}
SWITCH_DECLARE(uint16_t) switch_sockaddr_get_port(switch_sockaddr_t *sa)

View File

@ -1331,7 +1331,12 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_
free(list_name_dup);
} else {
switch_parse_cidr(list_name, &net, &mask, &bits);
ok = switch_test_subnet(ip.v4, net.v4, mask.v4);
if (ipv6) {
ok = switch_testv6_subnet(ip, net, mask);
} else {
ok = switch_test_subnet(ip.v4, net.v4, mask.v4);
}
}
}
switch_mutex_unlock(runtime.global_mutex);
@ -1395,6 +1400,40 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload)
switch_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE);
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
tmp_name = "wan_v6.auto";
switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
switch_network_list_add_cidr(rfc_list, "0.0.0.0/0", SWITCH_FALSE);
switch_network_list_add_cidr(rfc_list, "fe80::/10", SWITCH_FALSE);
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
tmp_name = "wan_v4.auto";
switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
switch_network_list_add_cidr(rfc_list, "0.0.0.0/8", SWITCH_FALSE);
switch_network_list_add_cidr(rfc_list, "10.0.0.0/8", SWITCH_FALSE);
switch_network_list_add_cidr(rfc_list, "172.16.0.0/12", SWITCH_FALSE);
switch_network_list_add_cidr(rfc_list, "192.168.0.0/16", SWITCH_FALSE);
switch_network_list_add_cidr(rfc_list, "169.254.0.0/16", SWITCH_FALSE);
switch_network_list_add_cidr(rfc_list, "::/0", SWITCH_FALSE);
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
tmp_name = "any_v6.auto";
switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
switch_network_list_add_cidr(rfc_list, "0.0.0.0/0", SWITCH_FALSE);
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
tmp_name = "any_v4.auto";
switch_network_list_create(&rfc_list, tmp_name, SWITCH_TRUE, IP_LIST.pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (allow)\n", tmp_name);
switch_network_list_add_cidr(rfc_list, "::/0", SWITCH_FALSE);
switch_core_hash_insert(IP_LIST.hash, tmp_name, rfc_list);
tmp_name = "nat.auto";
switch_network_list_create(&rfc_list, tmp_name, SWITCH_FALSE, IP_LIST.pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (deny)\n", tmp_name);

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] = {
{ "AEAD_AES_256_GCM_8", AEAD_AES_256_GCM_8, 44},
{ "AEAD_AES_128_GCM_8", AEAD_AES_128_GCM_8, 28},
@ -341,6 +339,9 @@ SWITCH_DECLARE(uint32_t) switch_core_media_get_video_fps(switch_core_session_t *
fps = switch_round_to_step(smh->vid_frames / (now - smh->vid_started), 5);
if (fps < 15) fps = 15;
smh->vid_started = switch_epoch_time_now(NULL);
smh->vid_frames = 1;
return fps;
}
@ -2885,7 +2886,10 @@ static void clear_ice(switch_core_session_t *session, switch_media_type_t type)
engine->ice_in.chosen[0] = 0;
engine->ice_in.chosen[1] = 0;
engine->ice_in.cand_idx = 0;
engine->ice_in.is_chosen[0] = 0;
engine->ice_in.is_chosen[1] = 0;
engine->ice_in.cand_idx[0] = 0;
engine->ice_in.cand_idx[1] = 0;
memset(&engine->ice_in, 0, sizeof(engine->ice_in));
engine->remote_rtcp_port = 0;
@ -3048,20 +3052,70 @@ SWITCH_DECLARE(switch_call_direction_t) switch_ice_direction(switch_core_session
}
//?
static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_session_t *sdp, sdp_media_t *m)
static switch_status_t ip_choose_family(switch_media_handle_t *smh, const char *ip)
{
switch_status_t status = SWITCH_STATUS_FALSE;
if (zstr(ip)) {
return status;
}
if (strchr(ip, ':')) {
if (!zstr(smh->mparams->rtpip6)) {
smh->mparams->rtpip = smh->mparams->rtpip6;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v6\n",
switch_channel_get_name(smh->session->channel));
status = SWITCH_STATUS_SUCCESS;
}
} else {
if (!zstr(smh->mparams->rtpip4)) {
smh->mparams->rtpip = smh->mparams->rtpip4;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s choosing family v4\n",
switch_channel_get_name(smh->session->channel));
status = SWITCH_STATUS_SUCCESS;
}
}
return status;
}
//?
static switch_bool_t ip_possible(switch_media_handle_t *smh, const char *ip)
{
switch_bool_t r = SWITCH_FALSE;
if (zstr(ip)) {
return r;
}
if (strchr(ip, ':')) {
r = (switch_bool_t) !zstr(smh->mparams->rtpip6);
} else {
r = (switch_bool_t) !zstr(smh->mparams->rtpip4);
}
return r;
}
//?
static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_session_t *sdp, sdp_media_t *m)
{
switch_rtp_engine_t *engine = &smh->engines[type];
sdp_attribute_t *attr;
int i = 0, got_rtcp_mux = 0;
const char *val;
int ice_seen = 0, cid = 0, ai = 0;
if (engine->ice_in.chosen[0] && engine->ice_in.chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
return;
if (engine->ice_in.is_chosen[0] && engine->ice_in.is_chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
return SWITCH_STATUS_SUCCESS;
}
engine->ice_in.chosen[0] = 0;
engine->ice_in.chosen[1] = 0;
engine->ice_in.cand_idx = 0;
engine->ice_in.is_chosen[0] = 0;
engine->ice_in.is_chosen[1] = 0;
engine->ice_in.cand_idx[0] = 0;
engine->ice_in.cand_idx[1] = 0;
if (m) {
attr = m->m_attributes;
@ -3073,7 +3127,6 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
char *data;
char *fields[15];
int argc = 0, j = 0;
int cid = 0;
if (zstr(attr->a_name)) {
continue;
@ -3081,6 +3134,7 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
if (!strcasecmp(attr->a_name, "ice-ufrag")) {
engine->ice_in.ufrag = switch_core_session_strdup(smh->session, attr->a_value);
ice_seen++;
} else if (!strcasecmp(attr->a_name, "ice-pwd")) {
engine->ice_in.pwd = switch_core_session_strdup(smh->session, attr->a_value);
} else if (!strcasecmp(attr->a_name, "ice-options")) {
@ -3133,145 +3187,113 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
}
data = switch_core_session_strdup(smh->session, attr->a_value);
argc = switch_split(data, ' ', fields);
if (argc < 5 || engine->ice_in.cand_idx >= MAX_CAND - 1) {
cid = fields[1] ? atoi(fields[1]) - 1 : 0;
if (argc < 5 || engine->ice_in.cand_idx[cid] >= MAX_CAND - 1) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_WARNING, "Invalid data\n");
continue;
}
cid = atoi(fields[1]) - 1;
for (i = 0; i < argc; i++) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG1, "CAND %d [%s]\n", i, fields[i]);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Checking Candidate cid: %d proto: %s type: %s addr: %s:%s\n", cid+1, fields[2], fields[7], fields[4], fields[5]);
if (!ip_possible(smh, fields[4])) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Drop %s Candidate cid: %d proto: %s type: %s addr: %s:%s (no network path)\n",
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
cid+1, fields[2], fields[7], fields[4], fields[5]);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
cid+1, fields[2], fields[7], fields[4], fields[5]);
}
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].foundation = switch_core_session_strdup(smh->session, fields[0]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].component_id = atoi(fields[1]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].transport = switch_core_session_strdup(smh->session, fields[2]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].priority = atol(fields[3]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]);
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].con_port = (switch_port_t)atoi(fields[5]);
j = 6;
engine->ice_in.cand_idx++;
for (i = 0; i < engine->cand_acl_count; i++) {
if (!engine->ice_in.chosen[cid] && !strchr(fields[4], ':') && switch_check_network_list_ip(fields[4], engine->cand_acl[i])) {
engine->ice_in.chosen[cid] = engine->ice_in.cand_idx;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"Choose %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
cid+1, fields[2], fields[7], fields[4], fields[5]);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n",
type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio",
cid+1, fields[2], fields[7], fields[4], fields[5]);
while(j < argc && fields[j+1]) {
if (!strcasecmp(fields[j], "typ")) {
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]);
} else if (!strcasecmp(fields[j], "raddr")) {
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]);
} else if (!strcasecmp(fields[j], "rport")) {
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].rport = (switch_port_t)atoi(fields[j+1]);
} else if (!strcasecmp(fields[j], "generation")) {
engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]);
}
j += 2;
}
engine->ice_in.cand_idx[cid]++;
}
}
engine->ice_in.cands[engine->ice_in.cand_idx][cid].foundation = switch_core_session_strdup(smh->session, fields[0]);
engine->ice_in.cands[engine->ice_in.cand_idx][cid].component_id = atoi(fields[1]);
engine->ice_in.cands[engine->ice_in.cand_idx][cid].transport = switch_core_session_strdup(smh->session, fields[2]);
engine->ice_in.cands[engine->ice_in.cand_idx][cid].priority = atol(fields[3]);
engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]);
engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_port = (switch_port_t)atoi(fields[5]);
if (!ice_seen) {
return SWITCH_STATUS_SUCCESS;
}
j = 6;
for (cid = 0; cid < 2; cid++) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "Searching for %s candidate.\n", cid ? "rtcp" : "rtp");
while(j < argc && fields[j+1]) {
if (!strcasecmp(fields[j], "typ")) {
engine->ice_in.cands[engine->ice_in.cand_idx][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]);
} else if (!strcasecmp(fields[j], "raddr")) {
engine->ice_in.cands[engine->ice_in.cand_idx][cid].raddr = switch_core_session_strdup(smh->session, fields[j+1]);
} else if (!strcasecmp(fields[j], "rport")) {
engine->ice_in.cands[engine->ice_in.cand_idx][cid].rport = (switch_port_t)atoi(fields[j+1]);
} else if (!strcasecmp(fields[j], "generation")) {
engine->ice_in.cands[engine->ice_in.cand_idx][cid].generation = switch_core_session_strdup(smh->session, fields[j+1]);
for (ai = 0; ai < engine->cand_acl_count; ai++) {
for (i = 0; i < engine->ice_in.cand_idx[cid]; i++) {
if (switch_check_network_list_ip(engine->ice_in.cands[i][cid].con_addr, engine->cand_acl[ai])) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Choose %s candidate, index %d, %s:%d\n", cid ? "rtcp" : "rtp", i,
engine->ice_in.cands[i][cid].con_addr, engine->ice_in.cands[i][cid].con_port);
engine->ice_in.chosen[cid] = i;
engine->ice_in.is_chosen[cid] = 1;
engine->ice_in.cands[i][cid].ready++;
ip_choose_family(smh, engine->ice_in.cands[i][cid].con_addr);
if (cid == 0 && got_rtcp_mux && engine->ice_in.cand_idx[1] < MAX_CAND) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Choose same candidate, index %d, for rtcp based on rtcp-mux attribute %s:%d\n", engine->ice_in.cand_idx[1],
engine->ice_in.cands[i][cid].con_addr, engine->ice_in.cands[i][cid].con_port);
engine->ice_in.cands[engine->ice_in.cand_idx[1]][1] = engine->ice_in.cands[i][0];
engine->ice_in.chosen[1] = engine->ice_in.cand_idx[1];
engine->ice_in.is_chosen[1] = 1;
engine->ice_in.cand_idx[1]++;
goto done_choosing;
}
j += 2;
}
if (engine->ice_in.chosen[cid]) {
engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++;
goto next_cid;
}
break;
}
}
}
/* still no candidates, so start searching for some based on sane deduction */
/* look for candidates on the same network */
if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1 &&
!engine->ice_in.cands[i][0].rport && switch_check_network_list_ip(engine->ice_in.cands[i][0].con_addr, "localnet.auto")) {
engine->ice_in.chosen[0] = i;
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTP candidate found; defaulting to the first local one.\n", type2str(type));
}
if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2 &&
!engine->ice_in.cands[i][1].rport && switch_check_network_list_ip(engine->ice_in.cands[i][1].con_addr, "localnet.auto")) {
engine->ice_in.chosen[1] = i;
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session),SWITCH_LOG_NOTICE,
"No %s RTCP candidate found; defaulting to the first local one.\n", type2str(type));
}
}
next_cid:
continue;
}
/* look for candidates with srflx */
if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1 && engine->ice_in.cands[i][0].rport) {
engine->ice_in.chosen[0] = i;
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTP candidate found; defaulting to the first srflx one.\n", type2str(type));
}
if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2 && engine->ice_in.cands[i][1].rport) {
engine->ice_in.chosen[1] = i;
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session),SWITCH_LOG_NOTICE,
"No %s RTCP candidate found; defaulting to the first srflx one.\n", type2str(type));
}
}
}
done_choosing:
/* Got RTP but not RTCP, probably mux */
if (engine->ice_in.chosen[0] && !engine->ice_in.chosen[1] && got_rtcp_mux) {
engine->ice_in.chosen[1] = engine->ice_in.chosen[0];
memcpy(&engine->ice_in.cands[engine->ice_in.chosen[1]][1], &engine->ice_in.cands[engine->ice_in.chosen[0]][0],
sizeof(engine->ice_in.cands[engine->ice_in.chosen[0]][0]));
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTCP candidate found; defaulting to the same as RTP [%s:%d]\n", type2str(type),
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
}
/* look for any candidates and hope for auto-adjust */
if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
if (!engine->ice_in.chosen[0] && engine->ice_in.cands[i][0].component_id == 1) {
engine->ice_in.chosen[0] = i;
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTP candidate found; defaulting to the first one.\n", type2str(type));
}
if (!engine->ice_in.chosen[1] && engine->ice_in.cands[i][1].component_id == 2) {
engine->ice_in.chosen[1] = i;
engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"No %s RTCP candidate found; defaulting to the first one.\n", type2str(type));
}
}
if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) {
/* PUNT */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s no suitable candidates found.\n",
switch_channel_get_name(smh->session->channel));
return SWITCH_STATUS_FALSE;
}
for (i = 0; i < 2; i++) {
@ -3286,8 +3308,8 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
if (engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr && engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port) {
char tmp[80] = "";
engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(smh->session, (char *) engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"setting remote %s ice addr to %s:%d based on candidate\n", type2str(type),
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"setting remote %s ice addr to index %d %s:%d based on candidate\n", type2str(type), engine->ice_in.chosen[0],
engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port);
engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready++;
@ -3301,29 +3323,19 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
smh->mparams->remote_ip = engine->cur_payload_map->remote_sdp_ip;
}
if (engine->remote_rtcp_port) {
engine->remote_rtcp_port = engine->cur_payload_map->remote_sdp_port;
}
switch_snprintf(tmp, sizeof(tmp), "%d", engine->cur_payload_map->remote_sdp_port);
switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, engine->cur_payload_map->remote_sdp_ip);
switch_snprintf(tmp, sizeof(tmp), "%d", engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port);
switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
}
if (engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port) {
if (engine->rtcp_mux) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"Asked by candidate to set remote rtcp %s addr to %s:%d but this is rtcp-mux so no thanks\n", type2str(type),
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
"Setting remote rtcp %s addr to %s:%d based on candidate\n", type2str(type),
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
engine->remote_rtcp_ice_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
engine->remote_rtcp_ice_addr = switch_core_session_strdup(smh->session, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr);
engine->remote_rtcp_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG,
"Setting remote rtcp %s addr to %s:%d based on candidate\n", type2str(type),
engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
engine->remote_rtcp_ice_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
engine->remote_rtcp_ice_addr = switch_core_session_strdup(smh->session, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr);
engine->remote_rtcp_port = engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port;
}
@ -3411,6 +3423,8 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
}
}
return ice_seen ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_BREAK;
}
#ifdef _MSC_VER
#pragma warning(pop)
@ -3503,7 +3517,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
const char *tmp;
int m_idx = 0;
int nm_idx = 0;
switch_assert(session);
if (!(smh = session->media_handle)) {
@ -4280,8 +4294,11 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
if (switch_core_media_set_codec(session, 0, smh->mparams->codec_flags) == SWITCH_STATUS_SUCCESS) {
got_audio = 1;
check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m);
if (check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m) == SWITCH_STATUS_FALSE) {
match = 0;
} else {
got_audio = 1;
}
} else {
match = 0;
}
@ -4554,7 +4571,9 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
if (switch_core_media_set_video_codec(session, 0) == SWITCH_STATUS_SUCCESS) {
check_ice(smh, SWITCH_MEDIA_TYPE_VIDEO, sdp, m);
if (check_ice(smh, SWITCH_MEDIA_TYPE_VIDEO, sdp, m) == SWITCH_STATUS_FALSE) {
vmatch = 0;
}
}
}
}
@ -4989,7 +5008,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_start_video_thread(switch_co
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s Starting Video thread\n", switch_core_session_get_name(session));
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Starting Video thread\n", switch_core_session_get_name(session));
if (v_engine->rtp_session) {
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt);
@ -5476,6 +5495,20 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_sessio
SWITCH_DECLARE(switch_status_t) switch_core_media_choose_ports(switch_core_session_t *session, switch_bool_t audio, switch_bool_t video)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_media_handle_t *smh;
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
if (zstr(smh->mparams->rtpip)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s has no media ip\n",
switch_channel_get_name(smh->session->channel));
switch_channel_hangup(smh->session->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
return SWITCH_STATUS_FALSE;
}
if (audio && (status = switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 0)) == SWITCH_STATUS_SUCCESS) {
if (video) {
@ -6316,7 +6349,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) ? "PROXY " : "",
switch_channel_get_name(session->channel),
a_engine->cur_payload_map->remote_sdp_ip,
a_engine->local_sdp_ip,
v_engine->local_sdp_port,
v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt,
@ -6495,13 +6528,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
end:
switch_channel_clear_flag(session->channel, CF_REINVITE);
switch_core_recovery_track(session);
return status;
}
@ -8555,7 +8585,7 @@ static int check_engine(switch_rtp_engine_t *engine)
return 1;
}
static switch_bool_t check_dtls(switch_core_session_t *session)
SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t *session)
{
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine, *v_engine;
@ -8567,7 +8597,7 @@ static switch_bool_t check_dtls(switch_core_session_t *session)
return SWITCH_FALSE;
}
if (switch_channel_down(session->channel)) {
if (!switch_channel_media_up(session->channel)) {
return SWITCH_FALSE;
}
@ -8621,14 +8651,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se
}
break;
case SWITCH_MESSAGE_INDICATE_ANSWER:
case SWITCH_MESSAGE_INDICATE_PROGRESS:
case SWITCH_MESSAGE_ANSWER_EVENT:
case SWITCH_MESSAGE_PROGRESS_EVENT:
{
check_dtls(session);
}
break;
case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
{
if (v_engine->rtp_session) {

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) {
case CS_NEW: /* Just created, Waiting for first instructions */

View File

@ -530,7 +530,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *se
elp = 1;
}
if (lead_frames) {
if (lead_frames && switch_channel_media_ready(channel)) {
switch_frame_t *read_frame;
int frame_count = atoi(lead_frames);
int max_frames = frame_count * 2;

View File

@ -25,6 +25,7 @@
*
* Anthony Minessale II <anthm@freeswitch.org>
* Eliot Gable <egable@gmail.com>
* Seven Du <dujinfang@gmail.com>
*
* switch_pgsql.c -- PGSQL Driver
*
@ -465,7 +466,17 @@ SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_finish_results_real(const cha
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Error executing query:\n%s\n", res->err);
final_status = SWITCH_PGSQL_FAIL;
}
if (!res) done = 1;
if (!res) {
done = 1;
} else if (res->result) {
char *affected_rows = PQcmdTuples(res->result);
if (!zstr(affected_rows)) {
handle->affected_rows = atoi(affected_rows);
}
}
switch_pgsql_free_result(&res);
} while (!done);
return final_status;

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_stun_value_to_name(SWITCH_STUN_TYPE_PACKET_TYPE, packet->header.type));
do {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|---: STUN ATTR %s\n",
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|---: STUN ATTR %d %x %s\n", attr->type, attr->type,
switch_stun_value_to_name(SWITCH_STUN_TYPE_ATTRIBUTE, attr->type));
switch (attr->type) {
@ -928,6 +928,14 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|------: %s:%d\n", ip, port);
}
break;
case SWITCH_STUN_ATTR_XOR_MAPPED_ADDRESS:
if (attr->type) {
char ip[16];
uint16_t port;
switch_stun_packet_attribute_get_xor_mapped_address(attr, packet->header.cookie, ip, &port);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG8, "|------: %s:%d\n", ip, port);
}
break;
case SWITCH_STUN_ATTR_USERNAME:
if (attr->type) {
switch_stun_packet_attribute_get_username(attr, username, sizeof(username));
@ -1030,7 +1038,7 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
if (!icep[j] || !icep[j]->ice_params) {
continue;
}
for (i = 0; i < icep[j]->ice_params->cand_idx; i++) {
for (i = 0; i < icep[j]->ice_params->cand_idx[icep[j]->proto]; i++) {
if (icep[j]->ice_params && icep[j]->ice_params->cands[i][icep[j]->proto].priority == *pri) {
if (j == IPR_RTP) {
icep[j]->ice_params->chosen[j] = i;
@ -1183,7 +1191,7 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
for (i = 0; i <= ice->ice_params->cand_idx; i++) {
for (i = 0; i <= ice->ice_params->cand_idx[ice->proto]; i++) {
if (ice->ice_params->cands[i][ice->proto].con_port == port) {
if (!strcmp(ice->ice_params->cands[i][ice->proto].con_addr, host) &&
!strcmp(ice->ice_params->cands[i][ice->proto].cand_type, "relay")) {
@ -2396,7 +2404,7 @@ static switch_status_t enable_remote_rtcp_socket(switch_rtp_t *rtp_session, cons
host = switch_get_addr(bufa, sizeof(bufa), rtp_session->rtcp_remote_addr);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG,
"Setting RTCP remote addr to %s:%d\n", host, rtp_session->remote_rtcp_port);
"Setting RTCP remote addr to %s:%d %d\n", host, rtp_session->remote_rtcp_port, rtp_session->rtcp_remote_addr->family);
}
if (rtp_session->rtcp_sock_input && switch_sockaddr_get_family(rtp_session->rtcp_remote_addr) ==
@ -2838,23 +2846,24 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_
}
if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP] && !rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
if (remote_rtcp_port) {
rtp_session->remote_rtcp_port = remote_rtcp_port;
if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP]) {
if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
rtp_session->rtcp_remote_addr = rtp_session->remote_addr;
rtp_session->rtcp_sock_output = rtp_session->sock_output;
} else {
rtp_session->remote_rtcp_port = rtp_session->eff_remote_port + 1;
if (remote_rtcp_port) {
rtp_session->remote_rtcp_port = remote_rtcp_port;
} else {
rtp_session->remote_rtcp_port = rtp_session->eff_remote_port + 1;
}
status = enable_remote_rtcp_socket(rtp_session, err);
if (rtp_session->rtcp_dtls) {
//switch_sockaddr_info_get(&rtp_session->rtcp_dtls->remote_addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool);
rtp_session->rtcp_dtls->remote_addr = rtp_session->rtcp_remote_addr;
rtp_session->rtcp_dtls->sock_output = rtp_session->rtcp_sock_output;
}
}
status = enable_remote_rtcp_socket(rtp_session, err);
if (rtp_session->rtcp_dtls) {
//switch_sockaddr_info_get(&rtp_session->rtcp_dtls->remote_addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool);
rtp_session->rtcp_dtls->remote_addr = rtp_session->rtcp_remote_addr;
rtp_session->rtcp_dtls->sock_output = rtp_session->rtcp_sock_output;
}
}
if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP] && rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
rtp_session->rtcp_remote_addr = rtp_session->remote_addr;
}
switch_mutex_unlock(rtp_session->write_mutex);
@ -4104,8 +4113,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_sessi
rtp_session->rtcp_sock_output = rtp_session->sock_output;
rtp_session->rtcp_recv_msg_p = (rtcp_msg_t *) &rtp_session->recv_msg;
return SWITCH_STATUS_SUCCESS;
return enable_remote_rtcp_socket(rtp_session, &err);
//return enable_remote_rtcp_socket(rtp_session, &err);
} else {
rtp_session->rtcp_recv_msg_p = (rtcp_msg_t *) &rtp_session->rtcp_recv_msg;
}
@ -5705,7 +5716,7 @@ static switch_status_t process_rtcp_packet(switch_rtp_t *rtp_session, switch_siz
if (msg->header.version != 2 || !(msg->header.type > 199 && msg->header.type < 208)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING,
"INVALID RTCP PACKET TYPE %d VER %d LEN %ld\n", msg->header.type,
"INVALID RTCP PACKET TYPE %d VER %d LEN %" SWITCH_SIZE_T_FMT "\n", msg->header.type,
msg->header.version, len);
status = SWITCH_STATUS_BREAK;
break;
@ -7746,7 +7757,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_write_raw(switch_rtp_t *rtp_session,
break;
case zrtp_status_drop:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat);
ret = SWITCH_STATUS_SUCCESS;
status = SWITCH_STATUS_SUCCESS;
goto end;
break;
case zrtp_status_fail:

View File

@ -60,6 +60,7 @@ static const struct value_mapping PACKET_TYPES[] = {
static const struct value_mapping ATTR_TYPES[] = {
{SWITCH_STUN_ATTR_MAPPED_ADDRESS, "MAPPED_ADDRESS"},
{SWITCH_STUN_ATTR_XOR_MAPPED_ADDRESS, "XOR_MAPPED_ADDRESS"},
{SWITCH_STUN_ATTR_RESPONSE_ADDRESS, "RESPONSE_ADDRESS"},
{SWITCH_STUN_ATTR_CHANGE_REQUEST, "CHANGE_REQUEST"},
{SWITCH_STUN_ATTR_SOURCE_ADDRESS, "SOURCE_ADDRESS"},

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) {
if (node->family == AF_INET) continue;
if (node->bits > bits && switch_testv6_subnet(ip, node->ip, node->mask)) {
if (node->bits >= bits && switch_testv6_subnet(ip, node->ip, node->mask)) {
if (node->ok) {
ok = SWITCH_TRUE;
} else {
@ -457,7 +458,7 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo
for (node = list->node_head; node; node = node->next) {
if (node->family == AF_INET6) continue; /* want AF_INET */
if (node->bits > bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) {
if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) {
if (node->ok) {
ok = SWITCH_TRUE;
} else {
@ -3161,7 +3162,7 @@ SWITCH_DECLARE(int) switch_socket_waitfor(switch_pollfd_t *poll, int ms)
return nsds;
}
SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
SWITCH_DECLARE(char *) switch_url_encode_opt(const char *url, char *buf, size_t len, switch_bool_t double_encode)
{
const char *p, *e = end_of_p(url);
size_t x = 0;
@ -3184,7 +3185,7 @@ SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
break;
}
if (*p == '%' && e-p > 1) {
if (!double_encode && *p == '%' && e-p > 1) {
if (strchr(hex, *(p+1)) && strchr(hex, *(p+2))) {
ok = 1;
}
@ -3206,6 +3207,11 @@ SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
return buf;
}
SWITCH_DECLARE(char *) switch_url_encode(const char *url, char *buf, size_t len)
{
return switch_url_encode_opt(url, buf, len, SWITCH_FALSE);
}
SWITCH_DECLARE(char *) switch_url_decode(char *s)
{
char *o;