diff --git a/conf/rayo/autoload_configs/rayo.conf.xml b/conf/rayo/autoload_configs/rayo.conf.xml index 54aa388675..2ebcdbcffd 100644 --- a/conf/rayo/autoload_configs/rayo.conf.xml +++ b/conf/rayo/autoload_configs/rayo.conf.xml @@ -8,6 +8,11 @@ + + + + diff --git a/conf/vanilla/autoload_configs/conference.conf.xml b/conf/vanilla/autoload_configs/conference.conf.xml index ccde59f7f1..9dfb75b22d 100644 --- a/conf/vanilla/autoload_configs/conference.conf.xml +++ b/conf/vanilla/autoload_configs/conference.conf.xml @@ -185,6 +185,7 @@ + diff --git a/conf/vanilla/autoload_configs/verto.conf.xml b/conf/vanilla/autoload_configs/verto.conf.xml index a62fd706d7..73037325cd 100644 --- a/conf/vanilla/autoload_configs/verto.conf.xml +++ b/conf/vanilla/autoload_configs/verto.conf.xml @@ -5,9 +5,11 @@ - - - + + + + + @@ -16,15 +18,20 @@ + - + + + + + + - diff --git a/conf/vanilla/vars.xml b/conf/vanilla/vars.xml index 89c8a95f3b..c3e216361a 100644 --- a/conf/vanilla/vars.xml +++ b/conf/vanilla/vars.xml @@ -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. --> diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index b77589baf1..a4dc996f2c 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -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 diff --git a/html5/verto/video_demo/verto.js b/html5/verto/video_demo/verto.js index b53e5eee70..b9e458f3c9 100644 --- a/html5/verto/video_demo/verto.js +++ b/html5/verto/video_demo/verto.js @@ -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()); } diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 32fb77111c..7a74a042c4 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -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; } diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index 6ac5bcf8ce..ab89b4c822 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -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) { diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c index 5689d582c8..976a88dede 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_tls.c @@ -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 } diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/ws.c b/libs/sofia-sip/libsofia-sip-ua/tport/ws.c index 8a46b65502..6e9a69d025 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/ws.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/ws.c @@ -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'; diff --git a/libs/spandsp/src/v27ter_rx.c b/libs/spandsp/src/v27ter_rx.c index 6959d27ef2..93d3b4680d 100644 --- a/libs/spandsp/src/v27ter_rx.c +++ b/libs/spandsp/src/v27ter_rx.c @@ -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; diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 37631fce70..31bf08387b 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -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 diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 6dfa1e2531..5a9e3d6003 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -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; diff --git a/src/include/switch_stun.h b/src/include/switch_stun.h index eb4274457b..9db0aadd84 100644 --- a/src/include/switch_stun.h +++ b/src/include/switch_stun.h @@ -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 diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 5d85353669..c6768d5860 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -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, diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 6db5f8a2cd..136bb98220 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -25,7 +25,7 @@ * * Marc Olivier Chouinard * Emmanuel Schmidbauer - * + * Ítalo Rossi * * 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"))) { diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 532e827c3c..30272d92d4 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -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)) { diff --git a/src/mod/applications/mod_nibblebill/mod_nibblebill.c b/src/mod/applications/mod_nibblebill/mod_nibblebill.c index 39a799c1ec..a06e0c8d94 100644 --- a/src/mod/applications/mod_nibblebill/mod_nibblebill.c +++ b/src/mod/applications/mod_nibblebill/mod_nibblebill.c @@ -50,6 +50,7 @@ */ #include +#include 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; } diff --git a/src/mod/codecs/mod_codec2/mod_codec2.c b/src/mod/codecs/mod_codec2/mod_codec2.c index bb70bf8c46..cee954499a 100644 --- a/src/mod/codecs/mod_codec2/mod_codec2.c +++ b/src/mod/codecs/mod_codec2/mod_codec2.c @@ -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 */ diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index 21dc569c6b..38f6981665 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -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; diff --git a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c index b4af4a3579..c5f7810c1a 100644 --- a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c +++ b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c @@ -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); diff --git a/src/mod/endpoints/mod_rtmp/mod_rtmp.h b/src/mod/endpoints/mod_rtmp/mod_rtmp.h index e53cb95d94..8571aedafa 100644 --- a/src/mod/endpoints/mod_rtmp/mod_rtmp.h +++ b/src/mod/endpoints/mod_rtmp/mod_rtmp.h @@ -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 diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 7ef5aec3e2..59d1b4ef69 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -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); diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index 425710dae4..b0f6abf1be 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -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 */ /*****************************************************************************/ diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c index 5a581de463..7d4facfcf7 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.c +++ b/src/mod/endpoints/mod_skinny/skinny_server.c @@ -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"))) { diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 267286daf8..f80318f459 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -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, " %s\n", switch_str_nil(profile->rtpip[x])); } + for (x = 0; x < profile->rtpip_index6; x++) { + stream->write_function(stream, " %s\n", switch_str_nil(profile->rtpip6[x])); + } if (profile->extrtpip) { stream->write_function(stream, " %s\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++; } } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index eecde673fd..df52655ab2 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -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; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 230f3789be..b6b597f61e 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -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) { diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index cfa01c34f2..52b8b5256f 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -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++; diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 8c3e4b6fab..df238245b4 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -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); diff --git a/src/mod/endpoints/mod_verto/mcast/mcast.c b/src/mod/endpoints/mod_verto/mcast/mcast.c index e37ac08efc..617553bcc4 100644 --- a/src/mod/endpoints/mod_verto/mcast/mcast.c +++ b/src/mod/endpoints/mod_verto/mcast/mcast.c @@ -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); + } } diff --git a/src/mod/endpoints/mod_verto/mcast/mcast.h b/src/mod/endpoints/mod_verto/mcast/mcast.h index 915f803fe8..bc9114abce 100644 --- a/src/mod/endpoints/mod_verto/mcast/mcast.h +++ b/src/mod/endpoints/mod_verto/mcast/mcast.h @@ -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; diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 1d422a53ad..68b75d505a 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -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")) { diff --git a/src/mod/endpoints/mod_verto/mod_verto.h b/src/mod/endpoints/mod_verto/mod_verto.h index 11614926a6..eccd095369 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.h +++ b/src/mod/endpoints/mod_verto/mod_verto.h @@ -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; diff --git a/src/mod/endpoints/mod_verto/ws.c b/src/mod/endpoints/mod_verto/ws.c index 8a46b65502..6e9a69d025 100644 --- a/src/mod/endpoints/mod_verto/ws.c +++ b/src/mod/endpoints/mod_verto/ws.c @@ -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'; diff --git a/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c b/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c index 28575f0b8e..a9dc0743f9 100644 --- a/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c +++ b/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c @@ -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)++; diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index ae64880216..b845cfd7c3 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -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; diff --git a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml index 54aa388675..2ebcdbcffd 100644 --- a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml +++ b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml @@ -8,6 +8,11 @@ + + + + diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index aa213ff168..28d7ae1013 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -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); diff --git a/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c b/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c index 71f51d30ce..968e16e4ad 100644 --- a/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c +++ b/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c @@ -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); diff --git a/src/mod/xml_int/mod_xml_ldap/conf/autoload_configs/xml_ldap.conf.xml b/src/mod/xml_int/mod_xml_ldap/conf/autoload_configs/xml_ldap.conf.xml new file mode 100644 index 0000000000..84a9673171 --- /dev/null +++ b/src/mod/xml_int/mod_xml_ldap/conf/autoload_configs/xml_ldap.conf.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/xml_int/mod_xml_ldap/fsaccount.schema b/src/mod/xml_int/mod_xml_ldap/fsaccount.schema new file mode 100644 index 0000000000..367741a903 --- /dev/null +++ b/src/mod/xml_int/mod_xml_ldap/fsaccount.schema @@ -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 )) diff --git a/src/mod/xml_int/mod_xml_ldap/mod_xml_ldap.c b/src/mod/xml_int/mod_xml_ldap/mod_xml_ldap.c index a3d805495c..2de9a72158 100644 --- a/src/mod/xml_int/mod_xml_ldap/mod_xml_ldap.c +++ b/src/mod/xml_int/mod_xml_ldap/mod_xml_ldap.c @@ -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); diff --git a/src/switch_apr.c b/src/switch_apr.c index 5e7dc52dbd..a2ce5074b2 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -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) diff --git a/src/switch_core.c b/src/switch_core.c index 753dfa5a26..d585addbd3 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -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); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 7a469575d4..df872dfa30 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -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) { diff --git a/src/switch_core_state_machine.c b/src/switch_core_state_machine.c index c066cd00b7..26750ff58e 100644 --- a/src/switch_core_state_machine.c +++ b/src/switch_core_state_machine.c @@ -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 */ diff --git a/src/switch_ivr.c b/src/switch_ivr.c index beca50c3fa..11ece76f70 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -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; diff --git a/src/switch_pgsql.c b/src/switch_pgsql.c index 4d955f1f45..d51312e866 100644 --- a/src/switch_pgsql.c +++ b/src/switch_pgsql.c @@ -25,6 +25,7 @@ * * Anthony Minessale II * Eliot Gable + * Seven Du * * 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; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 438a3dabd5..46f3dca55d 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -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: diff --git a/src/switch_stun.c b/src/switch_stun.c index 1dd35d9bc5..d1f43c3244 100644 --- a/src/switch_stun.c +++ b/src/switch_stun.c @@ -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"}, diff --git a/src/switch_utils.c b/src/switch_utils.c index e53c66d079..0b415492dc 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -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;