diff --git a/include/dap_client_pvt.h b/include/dap_client_pvt.h index e8e6b2551cf39715464290735ebbd850d4712d97..5a75234f1affac684556ecc46911f32b75cb00e1 100755 --- a/include/dap_client_pvt.h +++ b/include/dap_client_pvt.h @@ -99,3 +99,5 @@ void dap_client_pvt_request_enc(dap_client_pvt_t * a_client_internal, const char void dap_client_pvt_new(dap_client_pvt_t * a_client_internal); void dap_client_pvt_delete(dap_client_pvt_t * a_client_pvts); +int dap_client_pvt_ref(dap_client_pvt_t * a_client_internal); +int dap_client_pvt_unref(dap_client_pvt_t * a_client_internal); diff --git a/src/dap_client.c b/src/dap_client.c index e5c4f5a7787a55cff30bee5a9180147df1b446d2..da44cfe8885f2828d33051734a692997b859189a 100644 --- a/src/dap_client.c +++ b/src/dap_client.c @@ -191,14 +191,19 @@ void dap_client_delete(dap_client_t * a_client) pthread_mutex_lock(&a_client->mutex); dap_client_disconnect(a_client); + //dap_client_reset(a_client); - dap_client_reset(a_client); - if (DAP_CLIENT_PVT(a_client) ) - dap_client_pvt_delete(DAP_CLIENT_PVT(a_client)); + //dap_client_pvt_t *l_client_pvt = DAP_CLIENT_PVT(a_client); + // reset l_client_pvt (before removal) + //memset(l_client_pvt, 0, sizeof(dap_client_pvt_t)); + //a_client->_internal = NULL; - pthread_mutex_t *l_mutex = &a_client->mutex; - memset(a_client, 0, sizeof(dap_client_t)); - pthread_mutex_unlock(l_mutex); + dap_client_pvt_delete(DAP_CLIENT_PVT(a_client)); + + //pthread_mutex_t *l_mutex = &a_client->mutex; + //memset(a_client, 0, sizeof(dap_client_t)); + //pthread_mutex_unlock(l_mutex); + pthread_mutex_unlock(&a_client->mutex); // a_client will be deleted in dap_events_socket_delete() -> free( a_es->_inheritor ); //DAP_DELETE(a_client); } diff --git a/src/dap_client_pvt.c b/src/dap_client_pvt.c index 961e60bfb1705e8f75701da59e7b9b37f106306d..809fabe27f14ca18b796da7e5684b712e29a5f38 100644 --- a/src/dap_client_pvt.c +++ b/src/dap_client_pvt.c @@ -125,11 +125,117 @@ void dap_client_pvt_new(dap_client_pvt_t * a_client_internal) a_client_internal->uplink_protocol_version = DAP_PROTOCOL_VERSION; } +typedef struct dap_client_pvt_ref_count { + dap_client_pvt_t *client_internal; + uint32_t ref_count; + UT_hash_handle hh; +} dap_client_pvt_ref_count_t; + +static dap_client_pvt_ref_count_t *s_client_pvt_ref = NULL; +static pthread_mutex_t s_mutex_ref = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t s_cond_ref = PTHREAD_COND_INITIALIZER; + +int dap_client_pvt_ref(dap_client_pvt_t * a_client_internal) +{ + int l_ret = 0; + dap_client_pvt_ref_count_t *l_client_pvt_ref; + pthread_mutex_lock(&s_mutex_ref); + HASH_FIND(hh, s_client_pvt_ref, &a_client_internal, sizeof(dap_client_pvt_t*), l_client_pvt_ref); + if(!l_client_pvt_ref) { + l_client_pvt_ref = DAP_NEW_Z(dap_client_pvt_ref_count_t); + l_client_pvt_ref->client_internal = a_client_internal; + l_client_pvt_ref->ref_count = 1; + HASH_ADD(hh, s_client_pvt_ref, client_internal, sizeof(dap_client_pvt_t*), l_client_pvt_ref); + } + else { + l_client_pvt_ref->ref_count++; + } + l_ret = l_client_pvt_ref->ref_count; + //printf("** ref %d %x\n\n", l_client_pvt_ref->ref_count, a_client_internal); + pthread_mutex_unlock(&s_mutex_ref); + + return l_ret; +} + +int dap_client_pvt_unref(dap_client_pvt_t * a_client_internal) +{ + int l_ret = -1; + dap_client_pvt_ref_count_t *l_client_pvt_ref; + pthread_mutex_lock(&s_mutex_ref); + HASH_FIND(hh, s_client_pvt_ref, &a_client_internal, sizeof(dap_client_pvt_t*), l_client_pvt_ref); + if(l_client_pvt_ref) { + if(l_client_pvt_ref->ref_count <= 1) { + HASH_DELETE(hh, s_client_pvt_ref, l_client_pvt_ref); + DAP_DELETE(l_client_pvt_ref); + pthread_cond_broadcast(&s_cond_ref); + l_ret = 0; + } + else { + l_client_pvt_ref->ref_count--; + l_ret = l_client_pvt_ref->ref_count; + } + } + else{ + l_ret = -1; + } + //printf("** unref %d %x\n\n", l_ret, a_client_internal); + pthread_mutex_unlock(&s_mutex_ref); + return l_ret; +} + +/** + * @brief dap_client_pvt_wait + * @param a_client_internal + */ +int dap_client_pvt_wait_unref(dap_client_pvt_t * a_client_internal, int a_timeout_ms) +{ + if(!a_client_internal) + return -1; + int l_ret = 0; + dap_client_pvt_ref_count_t *l_client_pvt_ref; + do { + pthread_mutex_lock(&s_mutex_ref); + HASH_FIND(hh, s_client_pvt_ref, &a_client_internal, sizeof(dap_client_pvt_t*), l_client_pvt_ref); + // wait for release a_client_internal + if(l_client_pvt_ref) { + struct timeval now; + struct timespec l_to; + gettimeofday(&now, 0); + l_to.tv_sec = now.tv_sec; // sec + l_to.tv_nsec = now.tv_usec * 1000; // nsec + int64_t l_nsec_new = l_to.tv_nsec + a_timeout_ms * 1000000ll; + // if the new number of nanoseconds is more than a second + if(l_nsec_new > (long) 1e9) { + l_to.tv_sec += l_nsec_new / (long) 1e9; + l_to.tv_nsec = l_nsec_new % (long) 1e9; + } + else + l_to.tv_nsec = (long) l_nsec_new; + int l_res = pthread_cond_timedwait(&s_cond_ref, &s_mutex_ref, &l_to); + if(l_res == ETIMEDOUT) { + l_ret = -1; + } + else { + //a_timeout_ms = 0; + pthread_mutex_unlock(&s_mutex_ref); + continue; + } + } + else + l_ret = 0; + + //printf("** end wait %x\n\n", a_client_internal); + pthread_mutex_unlock(&s_mutex_ref); + } + while(l_client_pvt_ref); + return l_ret; +} + /** * @brief dap_client_pvt_delete * @param a_client_pvt */ -void dap_client_pvt_delete(dap_client_pvt_t * a_client_pvt) +static void dap_client_pvt_delete_in(dap_client_pvt_t * a_client_pvt) { if(!a_client_pvt) return; @@ -152,6 +258,28 @@ void dap_client_pvt_delete(dap_client_pvt_t * a_client_pvt) DAP_DELETE(a_client_pvt); } +static void* dap_client_pvt_delete_proc(void *a_arg) +{ + dap_client_pvt_t * l_client_pvt = (dap_client_pvt_t*)a_arg; + // wait for release l_client_pvt + dap_client_pvt_wait_unref(l_client_pvt, 20000000); + + //dap_client_reset(l_client_pvt->client); + dap_client_pvt_delete_in(l_client_pvt); + //DAP_DELETE(l_client_pvt->client); + pthread_exit(0); +} + +/** + * @brief dap_client_pvt_delete + * @param a_client_pvt + */ +void dap_client_pvt_delete(dap_client_pvt_t * a_client_pvt) +{ + pthread_t l_thread = NULL; + pthread_create(&l_thread, NULL, dap_client_pvt_delete_proc, a_client_pvt); +} + /** * Make socket non-blocking / blocking * is_nonblock - (true) non-blocking / (false) blocking @@ -179,6 +307,8 @@ static void s_set_sock_nonblock(int sockfd, bool is_nonblock) */ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt) { + bool l_is_unref = false; + switch (a_client_pvt->stage_status) { case STAGE_STATUS_IN_PROGRESS: { switch (a_client_pvt->stage) { @@ -357,6 +487,8 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt) if(a_client_pvt->stage_target == STAGE_STREAM_ABORT) { a_client_pvt->stage = STAGE_STREAM_ABORT; a_client_pvt->stage_status = STAGE_STATUS_ABORTING; + // unref pvt + l_is_unref = true; } else { if(!l_is_last_attempt) { @@ -370,11 +502,14 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt) a_client_pvt->stage = STAGE_ENC_INIT; // Trying the step again a_client_pvt->stage_status = STAGE_STATUS_IN_PROGRESS; + //dap_client_pvt_ref(a_client_pvt); s_stage_status_after(a_client_pvt); } else{ log_it(L_INFO, "Too many connection attempts. Tries are over."); //a_client_pvt->stage_status = STAGE_STATUS_DONE; + // unref pvt + l_is_unref = true; } } } @@ -401,6 +536,7 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt) } else{ log_it(L_ERROR, "!! dap_CLIENT_STAGE_STATUS_DONE but not l_is_last_stage (cur stage=%d, target=%d)!!",a_client_pvt->stage, a_client_pvt->stage_target); } + l_is_unref = true; } break; default: @@ -410,6 +546,10 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt) if(a_client_pvt->stage_status_callback) a_client_pvt->stage_status_callback(a_client_pvt->client, NULL); + if(l_is_unref) { + // unref pvt + dap_client_pvt_unref(a_client_pvt); + } } /** @@ -424,6 +564,8 @@ void dap_client_pvt_stage_transaction_begin(dap_client_pvt_t * a_client_internal a_client_internal->stage_status_done_callback = a_done_callback; a_client_internal->stage = a_stage_next; a_client_internal->stage_status = STAGE_STATUS_IN_PROGRESS; + // ref pvt client + dap_client_pvt_ref(a_client_internal); s_stage_status_after(a_client_internal); } @@ -446,7 +588,7 @@ void dap_client_pvt_request(dap_client_pvt_t * a_client_internal, const char * a size_t l_url_size_max = 0; char *l_url = NULL; if(a_path) { - l_url_size_max = strlen(a_client_internal->uplink_addr) + strlen(a_path) + 15; + l_url_size_max = dap_strlen(a_client_internal->uplink_addr) + strlen(a_path) + 15; l_url = DAP_NEW_Z_SIZE(char, l_url_size_max); snprintf(l_url, l_url_size_max, "http://%s:%u/%s", a_client_internal->uplink_addr, @@ -588,7 +730,12 @@ void m_request_error(int a_err_code, void * a_obj) { dap_client_pvt_t * a_client_internal = (dap_client_pvt_t *) a_obj; if(a_client_internal && a_client_internal->request_error_callback && a_client_internal->client) - a_client_internal->request_error_callback(a_client_internal->client, a_err_code); + { + if(a_client_internal && a_client_internal->request_error_callback && a_client_internal->client && a_client_internal->client->_internal) + a_client_internal->request_error_callback(a_client_internal->client, a_err_code); + } + // unref pvt client + //dap_client_pvt_unref(a_client_internal); } /** @@ -600,6 +747,9 @@ void m_request_error(int a_err_code, void * a_obj) void m_request_response(void * a_response, size_t a_response_size, void * a_obj) { dap_client_pvt_t * a_client_internal = (dap_client_pvt_t *) a_obj; + if(!a_client_internal || !a_client_internal->client) + return; + if(a_client_internal->is_encrypted) { size_t l_response_dec_size_max = a_response_size ? a_response_size * 2 + 16 : 0; char * l_response_dec = a_response_size ? DAP_NEW_Z_SIZE(char, l_response_dec_size_max) : NULL; @@ -617,6 +767,9 @@ void m_request_response(void * a_response, size_t a_response_size, void * a_obj) } else { a_client_internal->request_response_callback(a_client_internal->client, a_response, a_response_size); } + + // unref pvt client + dap_client_pvt_unref(DAP_CLIENT_PVT(a_client_internal->client)); } /**