From: Mathieu Parent Date: Fri, 16 Apr 2010 13:03:37 +0000 (+0200) Subject: Skinny: Initial implementation of VersionReq X-Git-Tag: git2svn-syncpoint-master~169^2~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4263dda2de1fe45a5795c19b7fd71e1ac6423b6c;p=thirdparty%2Ffreeswitch.git Skinny: Initial implementation of VersionReq And reordering --- diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index c6daed417f..975007279c 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -1389,6 +1389,15 @@ switch_status_t send_capabilities_req(listener_t *listener) return skinny_send_reply(listener, message); } +switch_status_t send_version(listener_t *listener, + char *version) +{ + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.version)); + strncpy(message->data.version.version, version, 16); + return skinny_send_reply(listener, message); +} + switch_status_t send_register_reject(listener_t *listener, char *error) { @@ -1579,25 +1588,18 @@ switch_status_t send_reset(listener_t *listener, uint32_t reset_type) return skinny_send_reply(listener, message); } -/* Message handling */ -switch_status_t skinny_handle_alarm(listener_t *listener, skinny_message_t *request) +/*****************************************************************************/ +/* SKINNY MESSAGE HANDLERS */ +/*****************************************************************************/ +switch_status_t skinny_handle_keep_alive_message(listener_t *listener, skinny_message_t *request) { - switch_event_t *event = NULL; - - skinny_check_data_length(request, sizeof(request->data.alarm)); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - "Received alarm: Severity=%d, DisplayMessage=%s, Param1=%d, Param2=%d.\n", - request->data.alarm.alarm_severity, request->data.alarm.display_message, - request->data.alarm.alarm_param1, request->data.alarm.alarm_param2); - /* skinny::alarm event */ - skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_ALARM); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Severity", "%d", request->data.alarm.alarm_severity); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-DisplayMessage", "%s", request->data.alarm.display_message); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param1", "%d", request->data.alarm.alarm_param1); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param2", "%d", request->data.alarm.alarm_param2); - switch_event_fire(&event); + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12); + message->type = KEEP_ALIVE_ACK_MESSAGE; + message->length = 4; + keepalive_listener(listener, NULL); + skinny_send_reply(listener, message); return SWITCH_STATUS_SUCCESS; } @@ -1733,11 +1735,231 @@ end: return status; } -switch_status_t skinny_headset_status_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_port_message(listener_t *listener, skinny_message_t *request) { - skinny_check_data_length(request, sizeof(request->data.headset_status)); + char *sql; + skinny_profile_t *profile; + + switch_assert(listener->profile); + switch_assert(listener->device_name); + + profile = listener->profile; + + skinny_check_data_length(request, sizeof(request->data.as_uint16)); + + if ((sql = switch_mprintf( + "UPDATE skinny_devices SET port=%d WHERE name='%s' and instance=%d", + request->data.port.port, + listener->device_name, + listener->device_instance + ))) { + skinny_execute_sql(profile, sql, profile->sql_mutex); + switch_safe_free(sql); + } + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny_message_t *request) +{ + uint32_t line_instance = 0; + switch_core_session_t *session; + + skinny_check_data_length(request, sizeof(request->data.keypad_button)); + + if(request->data.keypad_button.line_instance) { + line_instance = request->data.keypad_button.line_instance; + } else { + line_instance = 1; + } + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.keypad_button.call_id); + + if(session) { + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + char digit = '\0'; + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SEND DTMF ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); + + if (request->data.keypad_button.button == 14) { + digit = '*'; + } else if (request->data.keypad_button.button == 15) { + digit = '#'; + } else if (request->data.keypad_button.button >= 0 && request->data.keypad_button.button <= 9) { + digit = '0' + request->data.keypad_button.button; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); + } + + /* TODO check call_id and line */ + + if((skinny_line_get_state(listener, line_instance, tech_pvt->call_id) == SKINNY_OFF_HOOK)) { + + skinny_session_process_dest(session, listener, line_instance, NULL, digit, 0); + } else { + if(digit != '\0') { + switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0)}; + dtmf.digit = digit; + switch_channel_queue_dtmf(channel, &dtmf); + } + } + } + + if(session) { + switch_core_session_rwunlock(session); + } + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + struct speed_dial_stat_res_message *button = NULL; + uint32_t line_instance = 0; + uint32_t call_id = 0; + switch_core_session_t *session = NULL; + + skinny_check_data_length(request, sizeof(request->data.stimulus)-sizeof(request->data.stimulus.call_id)); + + if(skinny_check_data_length_soft(request, sizeof(request->data.stimulus))) { + call_id = request->data.stimulus.call_id; + } + + switch(request->data.stimulus.instance_type) { + case SKINNY_BUTTON_LAST_NUMBER_REDIAL: + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); + break; + case SKINNY_BUTTON_SPEED_DIAL: + skinny_speed_dial_get(listener, request->data.stimulus.instance, &button); + if(strlen(button->line) > 0) { + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0); + } + break; + case SKINNY_BUTTON_HOLD: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id); + + if(session) { + status = skinny_session_hold_line(session, listener, line_instance); + } + break; + case SKINNY_BUTTON_VOICEMAIL: + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0); + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type); + } + + if(session) { + switch_core_session_rwunlock(session); + } + + return status; +} + +switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_message_t *request) +{ + uint32_t line_instance; + switch_core_session_t *session = NULL; + private_t *tech_pvt = NULL; + + skinny_check_data_length(request, sizeof(request->data.off_hook)); + + if(request->data.off_hook.line_instance > 0) { + line_instance = request->data.off_hook.line_instance; + } else { + line_instance = 1; + } + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.off_hook.call_id); + + if(session) { /*answering a call */ + skinny_session_answer(session, listener, line_instance); + } else { /* start a new call */ + skinny_create_ingoing_session(listener, &line_instance, &session); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); + } + + if(session) { + switch_core_session_rwunlock(session); + } + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_message_t *request) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_core_session_t *session = NULL; + uint32_t line_instance = 0; + + skinny_check_data_length(request, sizeof(request->data.on_hook)); + + line_instance = request->data.on_hook.line_instance; + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.on_hook.call_id); + + if(session) { + switch_channel_t *channel = NULL; + + channel = switch_core_session_get_channel(session); + + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + } + + if(session) { + switch_core_session_rwunlock(session); + } + + return status; +} + +switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skinny_message_t *request) +{ + skinny_message_t *message; + struct speed_dial_stat_res_message *button = NULL; + + skinny_check_data_length(request, sizeof(request->data.speed_dial_req)); + + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.speed_dial_res)); + message->type = SPEED_DIAL_STAT_RES_MESSAGE; + message->length = 4 + sizeof(message->data.speed_dial_res); + + skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button); + + memcpy(&message->data.speed_dial_res, button, sizeof(struct speed_dial_stat_res_message)); + + skinny_send_reply(listener, message); + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_message_t *request) +{ + skinny_message_t *message; + struct line_stat_res_message *button = NULL; + + skinny_check_data_length(request, sizeof(request->data.line_req)); + + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.line_res)); + message->type = LINE_STAT_RES_MESSAGE; + message->length = 4 + sizeof(message->data.line_res); + + skinny_line_get(listener, request->data.line_req.number, &button); + + memcpy(&message->data.line_res, button, sizeof(struct line_stat_res_message)); + + skinny_send_reply(listener, message); - /* Nothing to do */ return SWITCH_STATUS_SUCCESS; } @@ -1798,88 +2020,9 @@ switch_status_t skinny_handle_config_stat_request(listener_t *listener, skinny_m return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny_message_t *request) -{ - char *sql; - skinny_profile_t *profile; - - uint32_t i = 0; - uint32_t n = 0; - char *codec_order[SWITCH_MAX_CODECS]; - char *codec_string; - - size_t string_len, string_pos, pos; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; - - skinny_check_data_length(request, sizeof(request->data.cap_res.count)); - - n = request->data.cap_res.count; - if (n > SWITCH_MAX_CODECS) { - n = SWITCH_MAX_CODECS; - } - string_len = -1; - - skinny_check_data_length(request, sizeof(request->data.cap_res.count) + n * sizeof(request->data.cap_res.caps[0])); - - for (i = 0; i < n; i++) { - char *codec = skinny_codec2string(request->data.cap_res.caps[i].codec); - codec_order[i] = codec; - string_len += strlen(codec)+1; - } - i = 0; - pos = 0; - codec_string = switch_core_alloc(listener->pool, string_len+1); - for (string_pos = 0; string_pos < string_len; string_pos++) { - char *codec = codec_order[i]; - switch_assert(i < n); - if(pos == strlen(codec)) { - codec_string[string_pos] = ','; - i++; - pos = 0; - } else { - codec_string[string_pos] = codec[pos++]; - } - } - codec_string[string_len] = '\0'; - if ((sql = switch_mprintf( - "UPDATE skinny_devices SET codec_string='%s' WHERE name='%s'", - codec_string, - listener->device_name - ))) { - skinny_execute_sql(profile, sql, profile->sql_mutex); - switch_safe_free(sql); - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "Codecs %s supported.\n", codec_string); - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_port_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_time_date_request(listener_t *listener, skinny_message_t *request) { - char *sql; - skinny_profile_t *profile; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; - - skinny_check_data_length(request, sizeof(request->data.as_uint16)); - - if ((sql = switch_mprintf( - "UPDATE skinny_devices SET port=%d WHERE name='%s' and instance=%d", - request->data.port.port, - listener->device_name, - listener->device_instance - ))) { - skinny_execute_sql(profile, sql, profile->sql_mutex); - switch_safe_free(sql); - } - return SWITCH_STATUS_SUCCESS; + return send_define_current_time_date(listener); } struct button_template_helper { @@ -1968,38 +2111,187 @@ switch_status_t skinny_handle_button_template_request(listener_t *listener, skin } } - skinny_send_reply(listener, message); + + + return skinny_send_reply(listener, message);; +} +switch_status_t skinny_handle_version_request(listener_t *listener, skinny_message_t *request) +{ + /* TODO */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "VersionReqMessage not implemented yet.\n"); return SWITCH_STATUS_SUCCESS; + /* return send_version(listener, ""); */ } -switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny_message_t *request) { - skinny_message_t *message; + char *sql; skinny_profile_t *profile; + uint32_t i = 0; + uint32_t n = 0; + char *codec_order[SWITCH_MAX_CODECS]; + char *codec_string; + + size_t string_len, string_pos, pos; + switch_assert(listener->profile); switch_assert(listener->device_name); profile = listener->profile; - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_template)); - message->type = SOFT_KEY_TEMPLATE_RES_MESSAGE; - message->length = 4 + sizeof(message->data.soft_key_template); + skinny_check_data_length(request, sizeof(request->data.cap_res.count)); - message->data.soft_key_template.soft_key_offset = 0; - message->data.soft_key_template.soft_key_count = 21; - message->data.soft_key_template.total_soft_key_count = 21; + n = request->data.cap_res.count; + if (n > SWITCH_MAX_CODECS) { + n = SWITCH_MAX_CODECS; + } + string_len = -1; - memcpy(message->data.soft_key_template.soft_key, - soft_key_template_default, - sizeof(soft_key_template_default)); + skinny_check_data_length(request, sizeof(request->data.cap_res.count) + n * sizeof(request->data.cap_res.caps[0])); - skinny_send_reply(listener, message); + for (i = 0; i < n; i++) { + char *codec = skinny_codec2string(request->data.cap_res.caps[i].codec); + codec_order[i] = codec; + string_len += strlen(codec)+1; + } + i = 0; + pos = 0; + codec_string = switch_core_alloc(listener->pool, string_len+1); + for (string_pos = 0; string_pos < string_len; string_pos++) { + char *codec = codec_order[i]; + switch_assert(i < n); + if(pos == strlen(codec)) { + codec_string[string_pos] = ','; + i++; + pos = 0; + } else { + codec_string[string_pos] = codec[pos++]; + } + } + codec_string[string_len] = '\0'; + if ((sql = switch_mprintf( + "UPDATE skinny_devices SET codec_string='%s' WHERE name='%s'", + codec_string, + listener->device_name + ))) { + skinny_execute_sql(profile, sql, profile->sql_mutex); + switch_safe_free(sql); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Codecs %s supported.\n", codec_string); + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_alarm(listener_t *listener, skinny_message_t *request) +{ + switch_event_t *event = NULL; + + skinny_check_data_length(request, sizeof(request->data.alarm)); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Received alarm: Severity=%d, DisplayMessage=%s, Param1=%d, Param2=%d.\n", + request->data.alarm.alarm_severity, request->data.alarm.display_message, + request->data.alarm.alarm_param1, request->data.alarm.alarm_param2); + /* skinny::alarm event */ + skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_ALARM); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Severity", "%d", request->data.alarm.alarm_severity); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-DisplayMessage", "%s", request->data.alarm.display_message); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param1", "%d", request->data.alarm.alarm_param1); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param2", "%d", request->data.alarm.alarm_param2); + switch_event_fire(&event); return SWITCH_STATUS_SUCCESS; } +switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *listener, skinny_message_t *request) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + uint32_t line_instance = 0; + switch_core_session_t *session; + + skinny_check_data_length(request, sizeof(request->data.open_receive_channel_ack)); + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.open_receive_channel_ack.pass_thru_party_id); + + if(session) { + const char *err = NULL; + private_t *tech_pvt = NULL; + switch_channel_t *channel = NULL; + struct in_addr addr; + + tech_pvt = switch_core_session_get_private(session); + channel = switch_core_session_get_channel(session); + + /* Codec */ + tech_pvt->iananame = "PCMU"; /* TODO */ + tech_pvt->codec_ms = 10; /* TODO */ + tech_pvt->rm_rate = 8000; /* TODO */ + tech_pvt->rm_fmtp = NULL; /* TODO */ + tech_pvt->agreed_pt = (switch_payload_t) 0; /* TODO */ + tech_pvt->rm_encoding = switch_core_strdup(switch_core_session_get_pool(session), ""); + skinny_tech_set_codec(tech_pvt, 0); + if ((status = skinny_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) { + goto end; + } + + /* Request a local port from the core's allocator */ + if (!(tech_pvt->local_sdp_audio_port = switch_rtp_request_port(listener->profile->ip))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_CRIT, "No RTP ports available!\n"); + return SWITCH_STATUS_FALSE; + } + tech_pvt->local_sdp_audio_ip = switch_core_strdup(switch_core_session_get_pool(session), listener->profile->ip); + + tech_pvt->remote_sdp_audio_ip = inet_ntoa(request->data.open_receive_channel_ack.ip); + tech_pvt->remote_sdp_audio_port = request->data.open_receive_channel_ack.port; + + tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip, + tech_pvt->local_sdp_audio_port, + tech_pvt->remote_sdp_audio_ip, + tech_pvt->remote_sdp_audio_port, + tech_pvt->agreed_pt, + tech_pvt->read_impl.samples_per_packet, + tech_pvt->codec_ms * 1000, + (switch_rtp_flag_t) 0, "soft", &err, + switch_core_session_get_pool(session)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, + "AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n", + switch_channel_get_name(channel), + tech_pvt->local_sdp_audio_ip, + tech_pvt->local_sdp_audio_port, + tech_pvt->remote_sdp_audio_ip, + tech_pvt->remote_sdp_audio_port, + tech_pvt->agreed_pt, + tech_pvt->read_impl.microseconds_per_packet / 1000, + switch_rtp_ready(tech_pvt->rtp_session) ? "SUCCESS" : err); + inet_aton(tech_pvt->local_sdp_audio_ip, &addr); + send_start_media_transmission(listener, + tech_pvt->call_id, /* uint32_t conference_id, */ + tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ + addr.s_addr, /* uint32_t remote_ip, */ + tech_pvt->local_sdp_audio_port, /* uint32_t remote_port, */ + 20, /* uint32_t ms_per_packet, */ + SKINNY_CODEC_ULAW_64K, /* uint32_t payload_capacity, */ + 184, /* uint32_t precedence, */ + 0, /* uint32_t silence_suppression, */ + 0, /* uint16_t max_frames_per_packet, */ + 0 /* uint32_t g723_bitrate */ + ); + + if (switch_channel_get_state(channel) == CS_NEW) { + switch_channel_set_state(channel, CS_INIT); + } + switch_channel_mark_answered(channel); + } +end: + if(session) { + switch_core_session_rwunlock(session); + } + return status; +} + switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_message_t *request) { skinny_message_t *message; @@ -2052,112 +2344,7 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_ return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - struct line_stat_res_message *button = NULL; - - skinny_check_data_length(request, sizeof(request->data.line_req)); - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.line_res)); - message->type = LINE_STAT_RES_MESSAGE; - message->length = 4 + sizeof(message->data.line_res); - - skinny_line_get(listener, request->data.line_req.number, &button); - - memcpy(&message->data.line_res, button, sizeof(struct line_stat_res_message)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - struct speed_dial_stat_res_message *button = NULL; - - skinny_check_data_length(request, sizeof(request->data.speed_dial_req)); - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.speed_dial_res)); - message->type = SPEED_DIAL_STAT_RES_MESSAGE; - message->length = 4 + sizeof(message->data.speed_dial_res); - - skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button); - - memcpy(&message->data.speed_dial_res, button, sizeof(struct speed_dial_stat_res_message)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - struct service_url_stat_res_message *button = NULL; - - skinny_check_data_length(request, sizeof(request->data.service_url_req)); - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.service_url_res)); - message->type = SERVICE_URL_STAT_RES_MESSAGE; - message->length = 4 + sizeof(message->data.service_url_res); - - skinny_service_url_get(listener, request->data.service_url_req.service_url_index, &button); - - memcpy(&message->data.service_url_res, button, sizeof(struct service_url_stat_res_message)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - struct feature_stat_res_message *button = NULL; - - skinny_check_data_length(request, sizeof(request->data.feature_req)); - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.feature_res)); - message->type = FEATURE_STAT_RES_MESSAGE; - message->length = 4 + sizeof(message->data.feature_res); - - skinny_feature_get(listener, request->data.feature_req.feature_index, &button); - - memcpy(&message->data.feature_res, button, sizeof(struct feature_stat_res_message)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_register_available_lines_message(listener_t *listener, skinny_message_t *request) -{ - skinny_check_data_length(request, sizeof(request->data.reg_lines)); - - /* Do nothing */ - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_time_date_request(listener_t *listener, skinny_message_t *request) -{ - return send_define_current_time_date(listener); -} - -switch_status_t skinny_handle_keep_alive_message(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - - message = switch_core_alloc(listener->pool, 12); - message->type = KEEP_ALIVE_ACK_MESSAGE; - message->length = 4; - keepalive_listener(listener, NULL); - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinny_message_t *request) { switch_status_t status = SWITCH_STATUS_SUCCESS; uint32_t line_instance = 0; @@ -2240,273 +2427,106 @@ switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinn return status; } -switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_unregister(listener_t *listener, skinny_message_t *request) { - uint32_t line_instance; - switch_core_session_t *session = NULL; - private_t *tech_pvt = NULL; - - skinny_check_data_length(request, sizeof(request->data.off_hook)); - - if(request->data.off_hook.line_instance > 0) { - line_instance = request->data.off_hook.line_instance; - } else { - line_instance = 1; - } - - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.off_hook.call_id); + switch_event_t *event = NULL; + skinny_message_t *message; - if(session) { /*answering a call */ - skinny_session_answer(session, listener, line_instance); - } else { /* start a new call */ - skinny_create_ingoing_session(listener, &line_instance, &session); - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); + /* skinny::unregister event */ + skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_UNREGISTER); + switch_event_fire(&event); - skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); - } + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.unregister_ack)); + message->type = UNREGISTER_ACK_MESSAGE; + message->length = 4 + sizeof(message->data.unregister_ack); + message->data.unregister_ack.unregister_status = 0; /* OK */ + skinny_send_reply(listener, message); - if(session) { - switch_core_session_rwunlock(session); - } + /* Close socket */ + switch_clear_flag_locked(listener, LFLAG_RUNNING); return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, skinny_message_t *request) { - switch_status_t status = SWITCH_STATUS_SUCCESS; - struct speed_dial_stat_res_message *button = NULL; - uint32_t line_instance = 0; - uint32_t call_id = 0; - switch_core_session_t *session = NULL; + skinny_message_t *message; + skinny_profile_t *profile; - skinny_check_data_length(request, sizeof(request->data.stimulus)-sizeof(request->data.stimulus.call_id)); + switch_assert(listener->profile); + switch_assert(listener->device_name); - if(skinny_check_data_length_soft(request, sizeof(request->data.stimulus))) { - call_id = request->data.stimulus.call_id; - } + profile = listener->profile; - switch(request->data.stimulus.instance_type) { - case SKINNY_BUTTON_LAST_NUMBER_REDIAL: - skinny_create_ingoing_session(listener, &line_instance, &session); - skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); - break; - case SKINNY_BUTTON_SPEED_DIAL: - skinny_speed_dial_get(listener, request->data.stimulus.instance, &button); - if(strlen(button->line) > 0) { - skinny_create_ingoing_session(listener, &line_instance, &session); - skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0); - } - break; - case SKINNY_BUTTON_HOLD: - session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id); + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_template)); + message->type = SOFT_KEY_TEMPLATE_RES_MESSAGE; + message->length = 4 + sizeof(message->data.soft_key_template); - if(session) { - status = skinny_session_hold_line(session, listener, line_instance); - } - break; - case SKINNY_BUTTON_VOICEMAIL: - skinny_create_ingoing_session(listener, &line_instance, &session); - skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0); - break; - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type); - } + message->data.soft_key_template.soft_key_offset = 0; + message->data.soft_key_template.soft_key_count = 21; + message->data.soft_key_template.total_soft_key_count = 21; - if(session) { - switch_core_session_rwunlock(session); - } + memcpy(message->data.soft_key_template.soft_key, + soft_key_template_default, + sizeof(soft_key_template_default)); - return status; + skinny_send_reply(listener, message); + + return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_headset_status_message(listener_t *listener, skinny_message_t *request) { - switch_status_t status = SWITCH_STATUS_SUCCESS; - uint32_t line_instance = 0; - switch_core_session_t *session; - - skinny_check_data_length(request, sizeof(request->data.open_receive_channel_ack)); - - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.open_receive_channel_ack.pass_thru_party_id); - - if(session) { - const char *err = NULL; - private_t *tech_pvt = NULL; - switch_channel_t *channel = NULL; - struct in_addr addr; - - tech_pvt = switch_core_session_get_private(session); - channel = switch_core_session_get_channel(session); - - /* Codec */ - tech_pvt->iananame = "PCMU"; /* TODO */ - tech_pvt->codec_ms = 10; /* TODO */ - tech_pvt->rm_rate = 8000; /* TODO */ - tech_pvt->rm_fmtp = NULL; /* TODO */ - tech_pvt->agreed_pt = (switch_payload_t) 0; /* TODO */ - tech_pvt->rm_encoding = switch_core_strdup(switch_core_session_get_pool(session), ""); - skinny_tech_set_codec(tech_pvt, 0); - if ((status = skinny_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) { - goto end; - } - - /* Request a local port from the core's allocator */ - if (!(tech_pvt->local_sdp_audio_port = switch_rtp_request_port(listener->profile->ip))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_CRIT, "No RTP ports available!\n"); - return SWITCH_STATUS_FALSE; - } - tech_pvt->local_sdp_audio_ip = switch_core_strdup(switch_core_session_get_pool(session), listener->profile->ip); - - tech_pvt->remote_sdp_audio_ip = inet_ntoa(request->data.open_receive_channel_ack.ip); - tech_pvt->remote_sdp_audio_port = request->data.open_receive_channel_ack.port; - - tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip, - tech_pvt->local_sdp_audio_port, - tech_pvt->remote_sdp_audio_ip, - tech_pvt->remote_sdp_audio_port, - tech_pvt->agreed_pt, - tech_pvt->read_impl.samples_per_packet, - tech_pvt->codec_ms * 1000, - (switch_rtp_flag_t) 0, "soft", &err, - switch_core_session_get_pool(session)); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, - "AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n", - switch_channel_get_name(channel), - tech_pvt->local_sdp_audio_ip, - tech_pvt->local_sdp_audio_port, - tech_pvt->remote_sdp_audio_ip, - tech_pvt->remote_sdp_audio_port, - tech_pvt->agreed_pt, - tech_pvt->read_impl.microseconds_per_packet / 1000, - switch_rtp_ready(tech_pvt->rtp_session) ? "SUCCESS" : err); - inet_aton(tech_pvt->local_sdp_audio_ip, &addr); - send_start_media_transmission(listener, - tech_pvt->call_id, /* uint32_t conference_id, */ - tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ - addr.s_addr, /* uint32_t remote_ip, */ - tech_pvt->local_sdp_audio_port, /* uint32_t remote_port, */ - 20, /* uint32_t ms_per_packet, */ - SKINNY_CODEC_ULAW_64K, /* uint32_t payload_capacity, */ - 184, /* uint32_t precedence, */ - 0, /* uint32_t silence_suppression, */ - 0, /* uint16_t max_frames_per_packet, */ - 0 /* uint32_t g723_bitrate */ - ); + skinny_check_data_length(request, sizeof(request->data.headset_status)); - if (switch_channel_get_state(channel) == CS_NEW) { - switch_channel_set_state(channel, CS_INIT); - } - switch_channel_mark_answered(channel); - } -end: - if(session) { - switch_core_session_rwunlock(session); - } - return status; + /* Nothing to do */ + return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_register_available_lines_message(listener_t *listener, skinny_message_t *request) { - uint32_t line_instance = 0; - switch_core_session_t *session; - - skinny_check_data_length(request, sizeof(request->data.keypad_button)); - - if(request->data.keypad_button.line_instance) { - line_instance = request->data.keypad_button.line_instance; - } else { - line_instance = 1; - } - - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.keypad_button.call_id); - - if(session) { - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; - char digit = '\0'; - - channel = switch_core_session_get_channel(session); - tech_pvt = switch_core_session_get_private(session); - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SEND DTMF ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); - - if (request->data.keypad_button.button == 14) { - digit = '*'; - } else if (request->data.keypad_button.button == 15) { - digit = '#'; - } else if (request->data.keypad_button.button >= 0 && request->data.keypad_button.button <= 9) { - digit = '0' + request->data.keypad_button.button; - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); - } - - /* TODO check call_id and line */ - - if((skinny_line_get_state(listener, line_instance, tech_pvt->call_id) == SKINNY_OFF_HOOK)) { - - skinny_session_process_dest(session, listener, line_instance, NULL, digit, 0); - } else { - if(digit != '\0') { - switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0)}; - dtmf.digit = digit; - switch_channel_queue_dtmf(channel, &dtmf); - } - } - } - - if(session) { - switch_core_session_rwunlock(session); - } + skinny_check_data_length(request, sizeof(request->data.reg_lines)); + /* Do nothing */ return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, skinny_message_t *request) { - switch_status_t status = SWITCH_STATUS_SUCCESS; - switch_core_session_t *session = NULL; - uint32_t line_instance = 0; - - skinny_check_data_length(request, sizeof(request->data.on_hook)); + skinny_message_t *message; + struct service_url_stat_res_message *button = NULL; - line_instance = request->data.on_hook.line_instance; - - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.on_hook.call_id); + skinny_check_data_length(request, sizeof(request->data.service_url_req)); - if(session) { - switch_channel_t *channel = NULL; + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.service_url_res)); + message->type = SERVICE_URL_STAT_RES_MESSAGE; + message->length = 4 + sizeof(message->data.service_url_res); - channel = switch_core_session_get_channel(session); + skinny_service_url_get(listener, request->data.service_url_req.service_url_index, &button); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - } + memcpy(&message->data.service_url_res, button, sizeof(struct service_url_stat_res_message)); - if(session) { - switch_core_session_rwunlock(session); - } + skinny_send_reply(listener, message); - return status; + return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_unregister(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_message_t *request) { - switch_event_t *event = NULL; skinny_message_t *message; + struct feature_stat_res_message *button = NULL; - /* skinny::unregister event */ - skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_UNREGISTER); - switch_event_fire(&event); + skinny_check_data_length(request, sizeof(request->data.feature_req)); - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.unregister_ack)); - message->type = UNREGISTER_ACK_MESSAGE; - message->length = 4 + sizeof(message->data.unregister_ack); - message->data.unregister_ack.unregister_status = 0; /* OK */ - skinny_send_reply(listener, message); + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.feature_res)); + message->type = FEATURE_STAT_RES_MESSAGE; + message->length = 4 + sizeof(message->data.feature_res); - /* Close socket */ - switch_clear_flag_locked(listener, LFLAG_RUNNING); + skinny_feature_get(listener, request->data.feature_req.feature_index, &button); + + memcpy(&message->data.feature_res, button, sizeof(struct feature_stat_res_message)); + + skinny_send_reply(listener, message); return SWITCH_STATUS_SUCCESS; } @@ -2545,6 +2565,8 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re return skinny_handle_time_date_request(listener, request); case BUTTON_TEMPLATE_REQ_MESSAGE: return skinny_handle_button_template_request(listener, request); + case VERSION_REQ_MESSAGE: + return skinny_handle_version_request(listener, request); case CAPABILITIES_RES_MESSAGE: return skinny_handle_capabilities_response(listener, request); case ALARM_MESSAGE: diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index 994462684f..aeaa42f09e 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -114,6 +114,9 @@ struct line_stat_req_message { /* ButtonTemplateReqMessage */ #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E +/* VersionReqMessage */ +#define VERSION_REQ_MESSAGE 0x000F + /* CapabilitiesResMessage */ #define CAPABILITIES_RES_MESSAGE 0x0010 struct station_capabilities { @@ -343,6 +346,12 @@ struct button_template_message { struct button_definition btn[SKINNY_MAX_BUTTON_COUNT]; }; +/* VersionMessage */ +#define VERSION_MESSAGE 0x0098 +struct version_message { + char version[16]; +}; + /* CapabilitiesReqMessage */ #define CAPABILITIES_REQ_MESSAGE 0x009B @@ -535,6 +544,7 @@ union skinny_data { struct config_stat_res_message config_res; struct define_time_date_message define_time_date; struct button_template_message button_template; + struct version_message version; struct register_reject_message reg_rej; struct reset_message reset; struct open_receive_channel_message open_receive_channel; @@ -724,6 +734,10 @@ switch_status_t send_define_time_date(listener_t *listener, uint32_t milliseconds, uint32_t timestamp); switch_status_t send_define_current_time_date(listener_t *listener); +switch_status_t send_version(listener_t *listener, + char *version); +switch_status_t send_register_reject(listener_t *listener, + char *error); switch_status_t send_open_receive_channel(listener_t *listener, uint32_t conference_id, uint32_t pass_thru_party_id, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c index a9bf84431f..42e8bb96b3 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.c +++ b/src/mod/endpoints/mod_skinny/skinny_tables.c @@ -47,6 +47,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = { {"ConfigStatReqMessage", CONFIG_STAT_REQ_MESSAGE}, {"TimeDateReqMessage", TIME_DATE_REQ_MESSAGE}, {"ButtonTemplateReqMessage", BUTTON_TEMPLATE_REQ_MESSAGE}, + {"VersionReqMessage", VERSION_REQ_MESSAGE}, {"CapabilitiesReqMessage", CAPABILITIES_RES_MESSAGE}, {"AlarmMessage", ALARM_MESSAGE}, {"OpenReceiveChannelAckMessage", OPEN_RECEIVE_CHANNEL_ACK_MESSAGE}, @@ -72,6 +73,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = { {"ConfigStatResMessage", CONFIG_STAT_RES_MESSAGE}, {"DefineTimeDateMessage", DEFINE_TIME_DATE_MESSAGE}, {"ButtonTemplateResMessage", BUTTON_TEMPLATE_RES_MESSAGE}, + {"VersionMessage", VERSION_MESSAGE}, {"CapabilitiesReqMessage", CAPABILITIES_REQ_MESSAGE}, {"RegisterRejectMessage", REGISTER_REJECT_MESSAGE}, {"ResetMessage", RESET_MESSAGE}, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h index f3755b5c2f..90bc45ef91 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.h +++ b/src/mod/endpoints/mod_skinny/skinny_tables.h @@ -84,7 +84,7 @@ uint32_t func(const char *str)\ } -struct skinny_table SKINNY_MESSAGE_TYPES[57]; +struct skinny_table SKINNY_MESSAGE_TYPES[59]; const char *skinny_message_type2str(uint32_t id); uint32_t skinny_str2message_type(const char *str); #define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES)