skypiax: ubermegapatch, more stability, robustness, scalability. Memory leaks not yet investigated, we'll do next

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14517 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Giovanni Maruzzelli 2009-08-14 17:12:09 +00:00
parent cbb2b89f0a
commit fd2bf49b7c
3 changed files with 318 additions and 96 deletions

View File

@ -148,6 +148,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
static switch_status_t skypiax_tech_init(private_t * tech_pvt, switch_core_session_t *session);
static switch_status_t skypiax_codec(private_t * tech_pvt, int sample_rate, int codec_ms)
{
@ -173,30 +174,40 @@ static switch_status_t skypiax_codec(private_t * tech_pvt, int sample_rate, int
session = switch_core_session_locate(tech_pvt->session_uuid_str);
switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
switch_core_session_rwunlock(session);
if(session){
switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
switch_core_session_rwunlock(session);
} else {
ERRORA("no session\n", SKYPIAX_P_LOG);
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
}
void skypiax_tech_init(private_t * tech_pvt, switch_core_session_t *session)
switch_status_t skypiax_tech_init(private_t * tech_pvt, switch_core_session_t *session)
{
switch_assert(tech_pvt != NULL);
switch_assert(session != NULL);
tech_pvt->read_frame.data = tech_pvt->databuf;
tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
switch_core_session_set_private(session, tech_pvt);
switch_copy_string(tech_pvt->session_uuid_str, switch_core_session_get_uuid(session), sizeof(tech_pvt->session_uuid_str));
if(!strlen(tech_pvt->session_uuid_str)){
ERRORA("no tech_pvt->session_uuid_str\n", SKYPIAX_P_LOG);
return SWITCH_STATUS_FALSE;
}
if (skypiax_codec(tech_pvt, SAMPLERATE_SKYPIAX, 20) != SWITCH_STATUS_SUCCESS) {
ERRORA("skypiax_codec FAILED\n", SKYPIAX_P_LOG);
} else {
DEBUGA_SKYPE("skypiax_codec SUCCESS\n", SKYPIAX_P_LOG);
return SWITCH_STATUS_FALSE;
}
DEBUGA_SKYPE("skypiax_codec SUCCESS\n", SKYPIAX_P_LOG);
return SWITCH_STATUS_SUCCESS;
}
/* BEGIN: Changes here */
@ -364,7 +375,8 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
channel = switch_core_session_get_channel(session);
switch_assert(channel != NULL);
switch_set_flag_locked(tech_pvt, TFLAG_IO);
DEBUGA_SKYPE("%s CHANNEL INIT\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
switch_set_flag(tech_pvt, TFLAG_IO);
/* Move channel's state machine to ROUTING. This means the call is trying
to get from the initial start where the call because, to the point
@ -376,7 +388,6 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
switch_mutex_unlock(globals.mutex);
DEBUGA_SKYPE("%s CHANNEL INIT\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
return SWITCH_STATUS_SUCCESS;
}
@ -394,6 +405,7 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session)
if (switch_core_codec_ready(&tech_pvt->write_codec)) {
switch_core_codec_destroy(&tech_pvt->write_codec);
}
*tech_pvt->session_uuid_str = '\0';
switch_core_session_set_private(session, NULL);
}
@ -406,15 +418,16 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
private_t *tech_pvt = NULL;
char msg_to_skype[256];
channel = switch_core_session_get_channel(session);
switch_assert(channel != NULL);
tech_pvt = switch_core_session_get_private(session);
switch_assert(tech_pvt != NULL);
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
switch_clear_flag_locked(tech_pvt, TFLAG_VOICE);
//switch_set_flag_locked(tech_pvt, TFLAG_HANGUP);
switch_clear_flag(tech_pvt, TFLAG_IO);
switch_clear_flag(tech_pvt, TFLAG_VOICE);
//switch_set_flag(tech_pvt, TFLAG_HANGUP);
if (strlen(tech_pvt->skype_call_id)) {
//switch_thread_cond_signal(tech_pvt->cond);
@ -423,7 +436,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
skypiax_signaling_write(tech_pvt, msg_to_skype);
}
//memset(tech_pvt->session_uuid_str, '\0', sizeof(tech_pvt->session_uuid_str));
*tech_pvt->session_uuid_str = '\0';
//*tech_pvt->session_uuid_str = '\0';
DEBUGA_SKYPE("%s CHANNEL HANGUP\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
switch_mutex_lock(globals.mutex);
globals.calls--;
@ -482,13 +495,18 @@ static switch_status_t channel_kill_channel(switch_core_session_t *session, int
switch (sig) {
case SWITCH_SIG_KILL:
DEBUGA_SKYPE("%s CHANNEL got SWITCH_SIG_KILL\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
switch_clear_flag_locked(tech_pvt, TFLAG_VOICE);
switch_set_flag_locked(tech_pvt, TFLAG_HANGUP);
//switch_mutex_lock(tech_pvt->flag_mutex);
switch_clear_flag(tech_pvt, TFLAG_IO);
switch_clear_flag(tech_pvt, TFLAG_VOICE);
switch_set_flag(tech_pvt, TFLAG_HANGUP);
//switch_mutex_unlock(tech_pvt->flag_mutex);
break;
case SWITCH_SIG_BREAK:
DEBUGA_SKYPE("%s CHANNEL got SWITCH_SIG_BREAK\n", SKYPIAX_P_LOG, switch_channel_get_name(channel));
switch_set_flag_locked(tech_pvt, TFLAG_BREAK);
//switch_set_flag(tech_pvt, TFLAG_BREAK);
//switch_mutex_lock(tech_pvt->flag_mutex);
switch_set_flag(tech_pvt, TFLAG_BREAK);
//switch_mutex_unlock(tech_pvt->flag_mutex);
break;
default:
break;
@ -536,7 +554,8 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
switch_assert(tech_pvt != NULL);
if (!switch_channel_ready(channel) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
ERRORA("CIAPA \n", SKYPIAX_P_LOG);
ERRORA("channel not ready \n", SKYPIAX_P_LOG);
//TODO: kill the bastard
return SWITCH_STATUS_FALSE;
}
@ -548,7 +567,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
ERRORA("skypiax_audio_read ERROR\n", SKYPIAX_P_LOG);
} else {
switch_set_flag_locked(tech_pvt, TFLAG_VOICE);
switch_set_flag(tech_pvt, TFLAG_VOICE);
}
while (switch_test_flag(tech_pvt, TFLAG_IO)) {
@ -564,7 +583,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
}
if (switch_test_flag(tech_pvt, TFLAG_IO) && switch_test_flag(tech_pvt, TFLAG_VOICE)) {
switch_clear_flag_locked(tech_pvt, TFLAG_VOICE);
switch_clear_flag(tech_pvt, TFLAG_VOICE);
if (!tech_pvt->read_frame.datalen) {
DEBUGA_SKYPE("CHANNEL READ CONTINUE\n", SKYPIAX_P_LOG);
continue;
@ -610,7 +629,8 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
switch_assert(tech_pvt != NULL);
if (!switch_channel_ready(channel) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
ERRORA("CIAPA \n", SKYPIAX_P_LOG);
ERRORA("channel not ready \n", SKYPIAX_P_LOG);
//TODO: kill the bastard
return SWITCH_STATUS_FALSE;
}
#ifdef BIGENDIAN
@ -721,9 +741,9 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
switch_caller_profile_t *outbound_profile,
switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags)
{
if ((*new_session = switch_core_session_request(skypiax_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
private_t *tech_pvt = NULL;
switch_channel_t *channel;
if ((*new_session = switch_core_session_request(skypiax_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
switch_channel_t *channel = NULL;
switch_caller_profile_t *caller_profile;
char *rdest;
int found = 0;
@ -741,16 +761,16 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
*slash = '\0';
switch_mutex_lock(globals.mutex);
if (strncmp("ANY", interface_name, strlen(interface_name)) == 0) {
if (strncmp("ANY", interface_name, strlen(interface_name)) == 0 || strncmp("RR", interface_name, strlen(interface_name)) == 0) {
/* we've been asked for the "ANY" interface, let's find the first idle interface */
DEBUGA_SKYPE("Finding one available skype interface\n", SKYPIAX_P_LOG);
tech_pvt = find_available_skypiax_interface(NULL);
if (tech_pvt)
found = 1;
} else if (strncmp("RR", interface_name, strlen(interface_name)) == 0) {
//DEBUGA_SKYPE("Finding one available skype interface\n", SKYPIAX_P_LOG);
//tech_pvt = find_available_skypiax_interface(NULL);
//if (tech_pvt)
//found = 1;
//} else if (strncmp("RR", interface_name, strlen(interface_name)) == 0) {
/* Find the first idle interface using Round Robin */
DEBUGA_SKYPE("Finding one available skype interface RR\n", SKYPIAX_P_LOG);
tech_pvt = find_available_skypiax_interface_rr();
tech_pvt = find_available_skypiax_interface_rr(NULL);
if (tech_pvt)
found = 1;
}
@ -765,7 +785,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
SKYPIAX_P_LOG, i, globals.SKYPIAX_INTERFACES[i].name, globals.SKYPIAX_INTERFACES[i].session_uuid_str);
switch_core_session_destroy(new_session);
switch_mutex_unlock(globals.mutex);
return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE;
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
}
DEBUGA_SKYPE("globals.SKYPIAX_INTERFACES[%d].name=|||%s|||?\n", SKYPIAX_P_LOG, i, globals.SKYPIAX_INTERFACES[i].name);
@ -783,14 +803,26 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
}
if (!found) {
ERRORA("Doh! no matching interface for |||%s|||?\n", SKYPIAX_P_LOG, interface_name);
DEBUGA_SKYPE("Doh! no available interface for |||%s|||?\n", SKYPIAX_P_LOG, interface_name);
switch_core_session_destroy(new_session);
switch_mutex_unlock(globals.mutex);
//return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
return SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
}
channel = switch_core_session_get_channel(*new_session);
if(!channel){
ERRORA("Doh! no channel?\n", SKYPIAX_P_LOG);
switch_core_session_destroy(new_session);
switch_mutex_unlock(globals.mutex);
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
}
if( skypiax_tech_init(tech_pvt, *new_session) != SWITCH_STATUS_SUCCESS){
ERRORA("Doh! no tech_init?\n", SKYPIAX_P_LOG);
switch_core_session_destroy(new_session);
switch_mutex_unlock(globals.mutex);
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
}
channel = switch_core_session_get_channel(*new_session);
skypiax_tech_init(tech_pvt, *new_session);
if (outbound_profile) {
@ -812,19 +844,21 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
rdest = strchr(caller_profile->destination_number, '/');
*rdest++ = '\0';
skypiax_call(tech_pvt, rdest, 30);
//skypiax_call(tech_pvt, rdest, 30);
switch_copy_string(tech_pvt->session_uuid_str, switch_core_session_get_uuid(*new_session), sizeof(tech_pvt->session_uuid_str));
caller_profile = tech_pvt->caller_profile;
caller_profile->destination_number = rdest;
switch_channel_set_flag(channel, CF_OUTBOUND);
switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
switch_channel_set_state(channel, CS_INIT);
skypiax_call(tech_pvt, rdest, 30);
switch_mutex_unlock(globals.mutex);
return SWITCH_CAUSE_SUCCESS;
}
ERRORA("Doh! no new_session\n", SKYPIAX_P_LOG);
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
}
@ -849,29 +883,35 @@ static void *SWITCH_THREAD_FUNC skypiax_signaling_thread_func(switch_thread_t *
res = skypiax_signaling_read(tech_pvt);
if (res == CALLFLOW_INCOMING_HANGUP) {
switch_core_session_t *session = NULL;
//private_t *tech_pvt = NULL;
switch_channel_t *channel = NULL;
//private_t *tech_pvt = NULL;
DEBUGA_SKYPE("skype call ended\n", SKYPIAX_P_LOG);
if (tech_pvt) {
session = switch_core_session_locate(tech_pvt->session_uuid_str);
if (session) {
channel = switch_core_session_get_channel(session);
if (channel) {
switch_channel_state_t state = switch_channel_get_state(channel);
if(state < CS_EXECUTE){
usleep(10000);//10 msec, let the state evolve from CS_NEW
}
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
switch_core_session_rwunlock(session);
} else {
ERRORA("no channel?\n", SKYPIAX_P_LOG);
switch_core_session_rwunlock(session);
}
switch_core_session_rwunlock(session);
} else {
DEBUGA_SKYPE("no session\n", SKYPIAX_P_LOG);
}
tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
*tech_pvt->session_uuid_str = '\0';
//memset(tech_pvt->session_uuid_str, '\0', sizeof(tech_pvt->session_uuid_str));
*tech_pvt->skype_call_id = '\0';
//ERRORA("LET'S WAIT\n", SKYPIAX_P_LOG);
usleep(300000); //0.3 sec
//ERRORA("WAIT'S OVER\n", SKYPIAX_P_LOG);
tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
} else {
ERRORA("no tech_pvt?\n", SKYPIAX_P_LOG);
}
@ -1389,16 +1429,29 @@ int start_audio_threads(private_t * tech_pvt)
switch_threadattr_create(&thd_attr, skypiax_module_pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&tech_pvt->tcp_srv_thread, thd_attr, skypiax_do_tcp_srv_thread, tech_pvt, skypiax_module_pool);
if (switch_thread_create(&tech_pvt->tcp_srv_thread, thd_attr, skypiax_do_tcp_srv_thread, tech_pvt, skypiax_module_pool) == SWITCH_STATUS_SUCCESS) {
DEBUGA_SKYPE("started tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
} else {
ERRORA("failed to start tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
return -1;
}
switch_threadattr_create(&thd_attr, skypiax_module_pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&tech_pvt->tcp_cli_thread, thd_attr, skypiax_do_tcp_cli_thread, tech_pvt, skypiax_module_pool);
if(switch_thread_create(&tech_pvt->tcp_cli_thread, thd_attr, skypiax_do_tcp_cli_thread, tech_pvt, skypiax_module_pool) == SWITCH_STATUS_SUCCESS) {
DEBUGA_SKYPE("started tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
}else{
ERRORA("failed to start tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
return -1;
}
switch_sleep(100000);
if(tech_pvt->tcp_cli_thread == NULL || tech_pvt->tcp_srv_thread == NULL) {
ERRORA("tcp_cli_thread or tcp_srv_thread exited\n", SKYPIAX_P_LOG);
return -1;
}
return 0;
}
@ -1410,7 +1463,16 @@ int new_inbound_channel(private_t * tech_pvt)
if ((session = switch_core_session_request(skypiax_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL)) != 0) {
switch_core_session_add_stream(session, NULL);
channel = switch_core_session_get_channel(session);
skypiax_tech_init(tech_pvt, session);
if(!channel){
ERRORA("Doh! no channel?\n", SKYPIAX_P_LOG);
switch_core_session_destroy(&session);
return 0;
}
if( skypiax_tech_init(tech_pvt, session) != SWITCH_STATUS_SUCCESS){
ERRORA("Doh! no tech_init?\n", SKYPIAX_P_LOG);
switch_core_session_destroy(&session);
return 0;
}
if ((tech_pvt->caller_profile =
switch_caller_profile_new(switch_core_session_get_pool(session), "skypiax",
@ -1426,11 +1488,14 @@ int new_inbound_channel(private_t * tech_pvt)
if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
ERRORA("Error spawning thread\n", SKYPIAX_P_LOG);
switch_core_session_destroy(&session);
return 0;
}
}
switch_channel_mark_answered(channel);
if(channel){
switch_channel_mark_answered(channel);
}
DEBUGA_SKYPE("Here\n", SKYPIAX_P_LOG);
DEBUGA_SKYPE("new_inbound_channel\n", SKYPIAX_P_LOG);
return 0;
}
@ -1457,7 +1522,6 @@ int remote_party_is_ringing(private_t * tech_pvt)
DEBUGA_SKYPE("skype_call: REMOTE PARTY RINGING\n", SKYPIAX_P_LOG);
} else {
ERRORA("No channel???\n", SKYPIAX_P_LOG);
goto done;
}
switch_core_session_rwunlock(session);
@ -1474,7 +1538,8 @@ int remote_party_is_early_media(private_t * tech_pvt)
if (!switch_strlen_zero(tech_pvt->session_uuid_str)) {
session = switch_core_session_locate(tech_pvt->session_uuid_str);
} else {
ERRORA("No session???\n", SKYPIAX_P_LOG);
ERRORA("No session???\n\n\n", SKYPIAX_P_LOG);
//TODO: kill the bastard
goto done;
}
if (session) {
@ -1482,6 +1547,7 @@ int remote_party_is_early_media(private_t * tech_pvt)
switch_core_session_add_stream(session, NULL);
} else {
ERRORA("No session???\n", SKYPIAX_P_LOG);
//TODO: kill the bastard
goto done;
}
if (channel) {
@ -1489,7 +1555,7 @@ int remote_party_is_early_media(private_t * tech_pvt)
DEBUGA_SKYPE("skype_call: REMOTE PARTY EARLY MEDIA\n", SKYPIAX_P_LOG);
} else {
ERRORA("No channel???\n", SKYPIAX_P_LOG);
goto done;
//TODO: kill the bastard
}
switch_core_session_rwunlock(session);
@ -1512,7 +1578,7 @@ int outbound_channel_answered(private_t * tech_pvt)
if (session) {
channel = switch_core_session_get_channel(session);
} else {
ERRORA("No session???\n", SKYPIAX_P_LOG);
ERRORA("No channel???\n", SKYPIAX_P_LOG);
goto done;
}
if (channel) {
@ -1520,17 +1586,17 @@ int outbound_channel_answered(private_t * tech_pvt)
//DEBUGA_SKYPE("skype_call: %s, answered\n", SKYPIAX_P_LOG, id);
} else {
ERRORA("No channel???\n", SKYPIAX_P_LOG);
goto done;
}
switch_core_session_rwunlock(session);
done:
DEBUGA_SKYPE("HERE!\n", SKYPIAX_P_LOG);
DEBUGA_SKYPE("outbound_channel_answered!\n", SKYPIAX_P_LOG);
return 0;
}
#if 0
private_t *find_available_skypiax_interface(private_t * tech_pvt)
{
private_t *tech_pvt2 = NULL;
@ -1559,8 +1625,9 @@ private_t *find_available_skypiax_interface(private_t * tech_pvt)
else
return NULL;
}
#endif
private_t *find_available_skypiax_interface_rr(void)
private_t *find_available_skypiax_interface_rr(private_t * tech_pvt_calling)
{
private_t *tech_pvt = NULL;
int i;
@ -1585,12 +1652,14 @@ private_t *find_available_skypiax_interface_rr(void)
tech_pvt = &globals.SKYPIAX_INTERFACES[interface_id];
skype_state = tech_pvt->interface_state;
DEBUGA_SKYPE("skype interface: %d, name: %s, state: %d\n", SKYPIAX_P_LOG, interface_id,
globals.SKYPIAX_INTERFACES[interface_id].name, skype_state);
if (SKYPIAX_STATE_DOWN == skype_state || 0 == skype_state) {
//DEBUGA_SKYPE("skype interface: %d, name: %s, state: %d\n", SKYPIAX_P_LOG, interface_id, globals.SKYPIAX_INTERFACES[interface_id].name, skype_state);
if ((tech_pvt_calling ? strcmp(tech_pvt->skype_user, tech_pvt_calling->skype_user) : 1) && (SKYPIAX_STATE_DOWN == skype_state || 0 == skype_state) && (tech_pvt->skype_callflow ==CALLFLOW_STATUS_FINISHED || 0 == tech_pvt->skype_callflow )) {
DEBUGA_SKYPE("returning as available skype interface name: %s, state: %d callflow: %d\n", SKYPIAX_P_LOG, tech_pvt->name, skype_state, tech_pvt->skype_callflow);
/*set to Dialing state to avoid other thread fint it, don't know if it is safe */
//XXX no, it's not safe
//tech_pvt->interface_state = SKYPIAX_STATE_DIALING ;
if(tech_pvt_calling == NULL){
tech_pvt->interface_state = SKYPIAX_STATE_SELECTED ;
}
switch_mutex_unlock(globals.mutex);
return tech_pvt;
@ -1796,6 +1865,8 @@ int skypiax_answer(private_t * tech_pvt, char *id, char *value)
if (found) {
//tech_pvt->callid_number[0]='\0';
//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
//skypiax_signaling_write(tech_pvt, msg_to_skype);
switch_mutex_unlock(globals.mutex);
return 0;
}
@ -1822,7 +1893,9 @@ int skypiax_answer(private_t * tech_pvt, char *id, char *value)
} else if (!tech_pvt || !tech_pvt->skype_call_id) {
ERRORA("No Call ID?\n", SKYPIAX_P_LOG);
} else {
ERRORA("We're in a call now %s\n", SKYPIAX_P_LOG, tech_pvt->skype_call_id);
DEBUGA_SKYPE("We're in a call now (%s), let's refuse this one (%s)\n", SKYPIAX_P_LOG, tech_pvt->skype_call_id, id);
sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
skypiax_signaling_write(tech_pvt, msg_to_skype);
}
switch_mutex_unlock(globals.mutex);
@ -1858,6 +1931,8 @@ int skypiax_transfer(private_t * tech_pvt, char *id, char *value)
if (found) {
//tech_pvt->callid_number[0]='\0';
//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
//skypiax_signaling_write(tech_pvt, msg_to_skype);
switch_mutex_unlock(globals.mutex);
return 0;
}
@ -1899,12 +1974,14 @@ int skypiax_transfer(private_t * tech_pvt, char *id, char *value)
if (found) {
//tech_pvt->callid_number[0]='\0';
//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
//skypiax_signaling_write(tech_pvt, msg_to_skype);
switch_mutex_unlock(globals.mutex);
return 0;
}
DEBUGA_SKYPE("NOT FOUND\n", SKYPIAX_P_LOG);
available_skypiax_interface = find_available_skypiax_interface(tech_pvt);
available_skypiax_interface = find_available_skypiax_interface_rr(tech_pvt);
if (available_skypiax_interface) {
/* there is a skypiax interface idle, let's transfer the call to it */
@ -1922,14 +1999,15 @@ int skypiax_transfer(private_t * tech_pvt, char *id, char *value)
} else {
/* no skypiax interfaces idle, do nothing */
DEBUGA_SKYPE
("Not answering the skype_call %s, because we are already in a skypiax call(%s) and no other skypiax interfaces are available OR another interface is answering this call\n",
SKYPIAX_P_LOG, tech_pvt->skype_call_id, id);
//sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
("Not answering the skype_call %s, because we are already in a skypiax call(%s) and not transferring, because no other skypiax interfaces are available\n",
SKYPIAX_P_LOG, id, tech_pvt->skype_call_id);
sprintf(msg_to_skype, "ALTER CALL %s END HANGUP", id);
skypiax_signaling_write(tech_pvt, msg_to_skype);
}
switch_sleep(10000);
DEBUGA_SKYPE
("We (%s) have NOT answered a Skype RING on skype_call %s, because we are already in a skypiax call\n",
SKYPIAX_P_LOG, tech_pvt->skype_call_id, id);
("We have NOT answered a Skype RING from skype_call %s, because we are already in a skypiax call (%s)\n",
SKYPIAX_P_LOG, id, tech_pvt->skype_call_id);
switch_mutex_unlock(globals.mutex);
}

View File

@ -98,6 +98,8 @@ typedef enum {
#define SKYPIAX_STATE_UP 5
#define SKYPIAX_STATE_RINGING 6
#define SKYPIAX_STATE_PRERING 7
#define SKYPIAX_STATE_ERROR_DOUBLE_CALL 8
#define SKYPIAX_STATE_SELECTED 9
/*********************************/
/* call flow from the device */
#define CALLFLOW_CALL_IDLE SKYPIAX_STATE_DOWN
@ -244,7 +246,6 @@ struct private_object {
typedef struct private_object private_t;
void *SWITCH_THREAD_FUNC skypiax_api_thread_func(switch_thread_t * thread, void *obj);
void skypiax_tech_init(private_t * tech_pvt, switch_core_session_t *session);
int skypiax_audio_read(private_t * tech_pvt);
int skypiax_audio_init(private_t * tech_pvt);
int skypiax_signaling_write(private_t * tech_pvt, char *msg_to_skype);
@ -277,8 +278,9 @@ int skypiax_pipe_write(int pipe, short *buf, int howmany);
#endif /* WIN32 */
int skypiax_close_socket(unsigned int fd);
private_t *find_available_skypiax_interface(private_t * tech_pvt);
private_t *find_available_skypiax_interface_rr(void);
private_t *find_available_skypiax_interface_rr(private_t * tech_pvt_calling);
int remote_party_is_ringing(private_t * tech_pvt);
int remote_party_is_early_media(private_t * tech_pvt);
int skypiax_answer(private_t * tech_pvt, char *id, char *value);
int skypiax_transfer(private_t * tech_pvt, char *id, char *value);
int skypiax_socket_create_and_bind(private_t * tech_pvt, int * which_port);

View File

@ -25,6 +25,47 @@ XErrorHandler old_handler = 0;
int xerror = 0;
#endif /* WIN32 */
/*************************************/
int skypiax_socket_create_and_bind(private_t * tech_pvt, int * which_port)
{
int s=-1;
struct sockaddr_in my_addr;
int start_port = 6001;
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl(0x7f000001); /* use the localhost */
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
ERRORA("socket Error\n", SKYPIAX_P_LOG);
return -1;
}
if(*which_port != 0)
start_port = *which_port;
my_addr.sin_port = htons(start_port);
//tech_pvt->tcp_cli_port = start_port;
*which_port = start_port;
while (bind(s, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) < 0) {
DEBUGA_SKYPE("*which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port, tech_pvt->tcp_srv_port);
DEBUGA_SKYPE("EADDRINUSE=%d, bind errno=%d, error: %s\n", SKYPIAX_P_LOG, EADDRINUSE, errno, strerror(errno));
start_port++;
my_addr.sin_port = htons(start_port);
*which_port = start_port;
DEBUGA_SKYPE("*which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port, tech_pvt->tcp_srv_port);
if(start_port > 65000){
ERRORA("NO MORE PORTS! *which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port, tech_pvt->tcp_srv_port);
return -1;
}
//usleep(100);
}
DEBUGA_SKYPE("SUCCESS! *which_port=%d, tech_pvt->tcp_cli_port=%d, tech_pvt->tcp_srv_port=%d\n", SKYPIAX_P_LOG, *which_port, tech_pvt->tcp_cli_port, tech_pvt->tcp_srv_port);
return s;
}
int skypiax_signaling_read(private_t * tech_pvt)
{
char read_from_pipe[4096];
@ -49,9 +90,9 @@ int skypiax_signaling_read(private_t * tech_pvt)
if (read_from_pipe[i] == '\0') {
if (!strstr(message, "DURATION")) {
//if (!strstr(message, "DURATION")) {
DEBUGA_SKYPE("READING: |||%s||| \n", SKYPIAX_P_LOG, message);
}
//}
if (!strcasecmp(message, "ERROR 68")) {
DEBUGA_SKYPE
@ -75,20 +116,48 @@ int skypiax_signaling_read(private_t * tech_pvt)
tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
}
}
skypiax_strncpy(message_2, message, sizeof(message) - 1);
buf = message;
stringp = &buf;
where = strsep(stringp, " ");
if (!where) {
WARNINGA("Skype MSG without spaces: %s\n", SKYPIAX_P_LOG, message);
}
if (!strcasecmp(message, "ERROR")) {
if (!strncasecmp(message, "ERROR 592 ALTER CALL", 19)) {
ERRORA("Skype got ERROR about TRANSFERRING, no problem: |||%s|||\n", SKYPIAX_P_LOG, message);
/*
if (!strncasecmp(message, "ERROR 96 CALL", 12) ) {
ERRORA("Skype got ERROR: |||%s|||, we are trying to use this interface to make or receive a call, but another call is half-active on this interface. We abort this attenpt and leave the previous one to continue.\n", SKYPIAX_P_LOG, message);
tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
DEBUGA_SKYPE("skype_call now is DOWN\n", SKYPIAX_P_LOG);
tech_pvt->skype_call_id[0] = '\0';
if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
return CALLFLOW_INCOMING_HANGUP;
} else {
DEBUGA_SKYPE("Skype got ERROR: |||%s|||\n", SKYPIAX_P_LOG, message);
tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
}
}
*/
/*
if (!strncasecmp(message, "ERROR 99 CALL", 12) ) {
//TODO: let's kill the call
ERRORA("Skype got ERROR: |||%s|||, another call is active on this interface\n\n\n", SKYPIAX_P_LOG, message);
//tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
//DEBUGA_SKYPE("skype_call now is DOWN\n", SKYPIAX_P_LOG);
//tech_pvt->skype_call_id[0] = '\0';
tech_pvt->interface_state = SKYPIAX_STATE_ERROR_DOUBLE_CALL;
}
*/
if (!strncasecmp(message, "ERROR", 4)) {
if (!strncasecmp(message, "ERROR 96 CALL", 12) ) {
DEBUGA_SKYPE("Skype got ERROR: |||%s|||, we are trying to use this interface to make or receive a call, but another call is half-active on this interface. Let's the previous one to continue.\n", SKYPIAX_P_LOG, message);
} else if (!strncasecmp(message, "ERROR 99 CALL", 12) ) {
ERRORA("Skype got ERROR: |||%s|||, another call is active on this interface\n\n\n", SKYPIAX_P_LOG, message);
tech_pvt->interface_state = SKYPIAX_STATE_ERROR_DOUBLE_CALL;
} else if (!strncasecmp(message, "ERROR 592 ALTER CALL", 19)) {
ERRORA("Skype got ERROR about TRANSFERRING, no problem: |||%s|||\n", SKYPIAX_P_LOG, message);
} else if (!strncasecmp(message, "ERROR 559 CALL", 13)) {
DEBUGA_SKYPE("Skype got ERROR about a failed action (probably TRYING to HANGUP A CALL), no problem: |||%s|||\n", SKYPIAX_P_LOG, message);
} else {
ERRORA("Skype got ERROR: |||%s|||\n", SKYPIAX_P_LOG, message);
tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
DEBUGA_SKYPE("skype_call now is DOWN\n", SKYPIAX_P_LOG);
ERRORA("skype_call now is DOWN\n", SKYPIAX_P_LOG);
tech_pvt->skype_call_id[0] = '\0';
if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
@ -99,6 +168,25 @@ int skypiax_signaling_read(private_t * tech_pvt)
}
}
}
skypiax_strncpy(message_2, message, sizeof(message) - 1);
buf = message;
stringp = &buf;
where = strsep(stringp, " ");
if (!where) {
WARNINGA("Skype MSG without spaces: %s\n", SKYPIAX_P_LOG, message);
}
if (!strcasecmp(message, "CURRENTUSERHANDLE")) {
skypiax_strncpy(obj, where, sizeof(obj) - 1);
where = strsep(stringp, " ");
@ -163,7 +251,8 @@ int skypiax_signaling_read(private_t * tech_pvt)
//SKYPIAX_P_LOG, message, obj, id, prop, value, where ? where : "NULL");
if (!strcasecmp(prop, "PARTNER_HANDLE")) {
if (!strlen(tech_pvt->skype_call_id)) {
if (!strlen(tech_pvt->skype_call_id) || !strlen(tech_pvt->session_uuid_str)) {
//if (!strlen(tech_pvt->skype_call_id)) {
/* we are NOT inside an active call */
DEBUGA_SKYPE("Call %s TRY ANSWER\n", SKYPIAX_P_LOG, id);
skypiax_answer(tech_pvt, id, value);
@ -171,7 +260,7 @@ int skypiax_signaling_read(private_t * tech_pvt)
/* we are inside an active call */
if (!strcasecmp(tech_pvt->skype_call_id, id)) {
/* this is the call in which we are calling out */
DEBUGA_SKYPE("Call %s NOTHING\n", SKYPIAX_P_LOG, id);
DEBUGA_SKYPE("Call %s DO NOTHING\n", SKYPIAX_P_LOG, id);
} else {
skypiax_sleep(400000); //0.4 seconds
DEBUGA_SKYPE("Call %s TRY TRANSFER\n", SKYPIAX_P_LOG, id);
@ -208,12 +297,25 @@ int skypiax_signaling_read(private_t * tech_pvt)
DEBUGA_SKYPE("We called a Skype contact and he answered us on skype_call: %s.\n", SKYPIAX_P_LOG, id);
}
}
if (!strcasecmp(prop, "DURATION") && (tech_pvt->interface_state == SKYPIAX_STATE_ERROR_DOUBLE_CALL)) {
char msg_to_skype[1024];
skypiax_strncpy(tech_pvt->skype_call_id, id, sizeof(tech_pvt->skype_call_id) - 1);
ERRORA("We are in a double call situation, trying to get out hanging up call id: %s.\n", SKYPIAX_P_LOG, id);
sprintf(msg_to_skype, "ALTER CALL %s HANGUP", id);
skypiax_signaling_write(tech_pvt, msg_to_skype);
skypiax_sleep(10000);
//return CALLFLOW_INCOMING_HANGUP;
}
if (!strcasecmp(prop, "STATUS")) {
if (!strcasecmp(value, "RINGING")) {
char msg_to_skype[1024];
if (!strlen(tech_pvt->skype_call_id)) {
if ( (tech_pvt->interface_state != SKYPIAX_STATE_SELECTED && tech_pvt->interface_state != SKYPIAX_STATE_DIALING ) && (!strlen(tech_pvt->skype_call_id) || !strlen(tech_pvt->session_uuid_str)) ) {
/* we are NOT inside an active call */
DEBUGA_SKYPE("NO ACTIVE calls in this moment, skype_call %s is RINGING, to ask PARTNER_HANDLE\n", SKYPIAX_P_LOG, id);
sprintf(msg_to_skype, "GET CALL %s PARTNER_HANDLE", id);
skypiax_signaling_write(tech_pvt, msg_to_skype);
skypiax_sleep(10000);
@ -227,6 +329,7 @@ int skypiax_signaling_read(private_t * tech_pvt)
DEBUGA_SKYPE("Our remote party in skype_call %s is RINGING\n", SKYPIAX_P_LOG, id);
remote_party_is_ringing(tech_pvt);
} else {
DEBUGA_SKYPE("We are in another call, but skype_call %s is RINGING on us, let's ask PARTNER_HANDLE, so maybe we'll TRANSFER\n", SKYPIAX_P_LOG, id);
sprintf(msg_to_skype, "GET CALL %s PARTNER_HANDLE", id);
skypiax_signaling_write(tech_pvt, msg_to_skype);
skypiax_sleep(10000);
@ -237,7 +340,10 @@ int skypiax_signaling_read(private_t * tech_pvt)
tech_pvt->skype_callflow = CALLFLOW_STATUS_EARLYMEDIA;
tech_pvt->interface_state = SKYPIAX_STATE_DIALING;
DEBUGA_SKYPE("Our remote party in skype_call %s is EARLYMEDIA\n", SKYPIAX_P_LOG, id);
start_audio_threads(tech_pvt);
if (start_audio_threads(tech_pvt)){
ERRORA("start_audio_threads FAILED\n", SKYPIAX_P_LOG);
return CALLFLOW_INCOMING_HANGUP;
}
skypiax_sleep(1000);
sprintf(msg_to_skype, "ALTER CALL %s SET_INPUT PORT=\"%d\"", id, tech_pvt->tcp_cli_port);
skypiax_signaling_write(tech_pvt, msg_to_skype);
@ -251,9 +357,9 @@ int skypiax_signaling_read(private_t * tech_pvt)
//DEBUGA_SKYPE("skype_call %s now is DOWN\n", SKYPIAX_P_LOG, id);
//usleep(150000);//150msec, let's give the TCP sockets time to timeout
if (!strcasecmp(tech_pvt->skype_call_id, id)) {
tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
//tech_pvt->skype_callflow = CALLFLOW_STATUS_FINISHED;
DEBUGA_SKYPE("skype_call %s is MY call, now I'm going DOWN\n", SKYPIAX_P_LOG, id);
tech_pvt->skype_call_id[0] = '\0';
//tech_pvt->skype_call_id[0] = '\0';
if (tech_pvt->interface_state != SKYPIAX_STATE_HANGUP_REQUESTED) {
//tech_pvt->interface_state = SKYPIAX_STATE_DOWN;
return CALLFLOW_INCOMING_HANGUP;
@ -311,6 +417,9 @@ int skypiax_signaling_read(private_t * tech_pvt)
} else if (!strcasecmp(value, "INPROGRESS")) {
char msg_to_skype[1024];
if (!strlen(tech_pvt->session_uuid_str)) {
DEBUGA_SKYPE("no tech_pvt->session_uuid_str\n", SKYPIAX_P_LOG);
}
if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) {
if (!strlen(tech_pvt->session_uuid_str) || !strlen(tech_pvt->skype_call_id)
|| !strcasecmp(tech_pvt->skype_call_id, id)) {
@ -320,7 +429,11 @@ int skypiax_signaling_read(private_t * tech_pvt)
if (tech_pvt->skype_callflow != CALLFLOW_STATUS_EARLYMEDIA) {
tech_pvt->skype_callflow = CALLFLOW_STATUS_INPROGRESS;
tech_pvt->interface_state = SKYPIAX_STATE_UP;
start_audio_threads(tech_pvt);
if (start_audio_threads(tech_pvt)){
ERRORA("start_audio_threads FAILED\n", SKYPIAX_P_LOG);
return CALLFLOW_INCOMING_HANGUP;
}
skypiax_sleep(1000); //FIXME
sprintf(msg_to_skype, "ALTER CALL %s SET_INPUT PORT=\"%d\"", id, tech_pvt->tcp_cli_port);
skypiax_signaling_write(tech_pvt, msg_to_skype);
@ -330,7 +443,7 @@ int skypiax_signaling_read(private_t * tech_pvt)
}
tech_pvt->skype_callflow = SKYPIAX_STATE_UP;
if (!strlen(tech_pvt->session_uuid_str)) {
DEBUGA_SKYPE("New Inbound Channel!\n", SKYPIAX_P_LOG);
DEBUGA_SKYPE("New Inbound Channel!\n\n\n\n", SKYPIAX_P_LOG);
new_inbound_channel(tech_pvt);
} else {
DEBUGA_SKYPE("Outbound Channel Answered!\n", SKYPIAX_P_LOG);
@ -413,13 +526,14 @@ void *skypiax_do_tcp_srv_thread_func(void *obj)
unsigned int fd;
short srv_in[SAMPLES_PER_FRAME];
short srv_out[SAMPLES_PER_FRAME / 2];
struct sockaddr_in my_addr;
//struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
//int exit = 0;
unsigned int kill_cli_size;
short kill_cli_buff[SAMPLES_PER_FRAME];
short totalbuf[SAMPLES_PER_FRAME];
#ifdef NOTDEF
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl(0x7f000001); /* use the localhost */
@ -427,11 +541,21 @@ void *skypiax_do_tcp_srv_thread_func(void *obj)
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
ERRORA("socket Error\n", SKYPIAX_P_LOG);
tech_pvt->tcp_srv_thread = NULL;
return NULL;
}
if (bind(s, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) < 0) {
ERRORA("bind Error\n", SKYPIAX_P_LOG);
ERRORA("bind error: %s\n", SKYPIAX_P_LOG, strerror(errno));
tech_pvt->tcp_srv_thread = NULL;
return NULL;
}
#endif //NOTDEF
s = skypiax_socket_create_and_bind(tech_pvt, &tech_pvt->tcp_srv_port);
if(s < 0)
{
ERRORA("skypiax_socket_create_and_bind error!\n", SKYPIAX_P_LOG);
return NULL;
}
DEBUGA_SKYPE("started tcp_srv_thread thread.\n", SKYPIAX_P_LOG);
@ -546,7 +670,7 @@ void *skypiax_do_tcp_srv_thread_func(void *obj)
} else if (len == 0) {
skypiax_sleep(1000);
} else {
ERRORA("len=%d, expected 320\n", SKYPIAX_P_LOG, len);
DEBUGA_SKYPE("len=%d, expected 320\n", SKYPIAX_P_LOG, len);
}
} else {
@ -578,6 +702,7 @@ void *skypiax_do_tcp_srv_thread_func(void *obj)
DEBUGA_SKYPE("incoming audio server (I am it) EXITING\n", SKYPIAX_P_LOG);
skypiax_close_socket(s);
tech_pvt->tcp_srv_thread = NULL;
return NULL;
}
@ -585,7 +710,7 @@ void *skypiax_do_tcp_cli_thread_func(void *obj)
{
private_t *tech_pvt = obj;
int s;
struct sockaddr_in my_addr;
//struct sockaddr_in my_addr;
struct sockaddr_in remote_addr;
unsigned int got;
unsigned int len;
@ -600,6 +725,7 @@ void *skypiax_do_tcp_cli_thread_func(void *obj)
unsigned int sin_size;
#endif /* WIN32 */
#ifdef NOTDEF
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = htonl(0x7f000001); /* use the localhost */
@ -607,14 +733,29 @@ void *skypiax_do_tcp_cli_thread_func(void *obj)
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
ERRORA("socket Error\n", SKYPIAX_P_LOG);
tech_pvt->tcp_cli_thread = NULL;
return NULL;
}
if (bind(s, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) < 0) {
ERRORA("bind Error\n", SKYPIAX_P_LOG);
//ERRORA("bind Error\n", SKYPIAX_P_LOG);
ERRORA("bind error: %s\n", SKYPIAX_P_LOG, strerror(errno));
skypiax_close_socket(s);
tech_pvt->tcp_cli_thread = NULL;
return NULL;
}
#endif // NOTDEF
s = skypiax_socket_create_and_bind(tech_pvt, &tech_pvt->tcp_cli_port);
if(s < 0)
{
ERRORA("skypiax_socket_create_and_bind error!\n", SKYPIAX_P_LOG);
return NULL;
}
DEBUGA_SKYPE("started tcp_cli_thread thread.\n", SKYPIAX_P_LOG);
listen(s, 6);
@ -764,6 +905,7 @@ void *skypiax_do_tcp_cli_thread_func(void *obj)
DEBUGA_SKYPE("outbound audio server (I am it) EXITING\n", SKYPIAX_P_LOG);
skypiax_close_socket(s);
tech_pvt->tcp_cli_thread = NULL;
return NULL;
}