From 73e738ab9d2f15b5b8dc8eecd7542e3758b5f354 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 14 Mar 2009 19:23:07 +0000 Subject: [PATCH] fix socket race git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@12605 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- libs/esl/fs_cli.c | 10 ++-- libs/esl/src/esl.c | 95 ++++++++++++++++++++++++++++++-------- libs/esl/src/esl_event.c | 29 ++++++------ libs/esl/src/esl_oop.cpp | 4 +- libs/esl/src/include/esl.h | 9 ++-- 5 files changed, 106 insertions(+), 41 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 55b43fa820..a721e33762 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -193,8 +193,7 @@ static void *msg_thread_run(esl_thread_t *me, void *obj) thread_running = 1; while(thread_running && handle->connected) { - esl_status_t status = esl_recv_timed(handle, 10); - + esl_status_t status = esl_recv_event_timed(handle, 10, 1, NULL); if (status == ESL_FAIL) { esl_log(ESL_LOG_WARNING, "Disconnected.\n"); running = thread_running = 0; @@ -240,7 +239,11 @@ static void *msg_thread_run(esl_thread_t *me, void *obj) } if (!known) { - printf("INCOMING DATA [%s]\n%s", type, handle->last_event->body); + printf("INCOMING DATA [%s]\n%s\n", type, handle->last_event->body ? handle->last_event->body : ""); + char *foo; + esl_event_serialize(handle->last_event, &foo, ESL_FALSE); + printf("RECV EVENT\n%s\n", foo); + free(foo); } } } @@ -724,6 +727,7 @@ int main(int argc, char *argv[]) print_banner(stdout); esl_log(ESL_LOG_INFO, "FS CLI Ready.\nenter /help for a list of commands.\n"); + printf("%s\n", handle.last_sr_reply); while (running) { diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index 3a3df31956..a0f360e320 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -683,6 +683,7 @@ ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle) esl_mutex_lock(mutex); } + esl_event_safe_destroy(&handle->race_event); esl_event_safe_destroy(&handle->last_event); esl_event_safe_destroy(&handle->last_sr_event); esl_event_safe_destroy(&handle->last_ievent); @@ -705,20 +706,29 @@ ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle) return status; } -ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, esl_event_t **save_event) +ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, int check_q, esl_event_t **save_event) { fd_set rfds, efds; struct timeval tv = { 0 }; int max, activity; esl_status_t status = ESL_SUCCESS; + if (check_q) { + esl_mutex_lock(handle->mutex); + if (handle->race_event) { + esl_mutex_unlock(handle->mutex); + return esl_recv_event(handle, check_q, save_event); + } + esl_mutex_unlock(handle->mutex); + } + if (!handle || !handle->connected || handle->sock == -1) { return ESL_FAIL; } tv.tv_usec = ms * 1000; - esl_mutex_lock(handle->mutex); + FD_ZERO(&rfds); FD_ZERO(&efds); @@ -736,21 +746,21 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms max = handle->sock + 1; if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) { - status = ESL_FAIL; - goto done; + return ESL_FAIL; + } + + if (esl_mutex_trylock(handle->mutex) != ESL_SUCCESS) { + return ESL_BREAK; } if (activity && FD_ISSET(handle->sock, &rfds)) { - if (esl_recv_event(handle, save_event)) { + if (esl_recv_event(handle, check_q, save_event)) { status = ESL_FAIL; - goto done; } } else { status = ESL_BREAK; } - done: - if (handle->mutex) esl_mutex_unlock(handle->mutex); return status; @@ -758,26 +768,41 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms } -ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, esl_event_t **save_event) +ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event) { char *c; esl_ssize_t rrval; int crc = 0; - esl_event_t *revent = NULL; + esl_event_t *revent = NULL, *qevent = NULL; char *beg; char *hname, *hval; char *col; char *cl; esl_ssize_t len; int zc = 0; - if (!handle->connected) { return ESL_FAIL; } - + esl_mutex_lock(handle->mutex); + if (check_q && handle->race_event) { + qevent = handle->race_event; + handle->race_event = handle->race_event->next; + qevent->next = NULL; + + if (save_event) { + *save_event = qevent; + qevent = NULL; + } else { + handle->last_event = qevent; + } + + esl_mutex_unlock(handle->mutex); + return ESL_SUCCESS; + } + esl_event_safe_destroy(&handle->last_event); memset(handle->header_buf, 0, sizeof(handle->header_buf)); @@ -834,7 +859,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, esl_event_t **sav c++; } } - + if (!revent) { goto fail; } @@ -862,6 +887,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, esl_event_t **sav if (save_event) { *save_event = revent; + revent = NULL; } else { handle->last_event = revent; } @@ -992,19 +1018,50 @@ ESL_DECLARE(esl_status_t) esl_send_recv(esl_handle_t *handle, const char *cmd) return ESL_FAIL; } + esl_mutex_lock(handle->mutex); + esl_event_safe_destroy(&handle->last_event); + esl_event_safe_destroy(&handle->last_sr_event); + + *handle->last_sr_reply = '\0'; + if ((status = esl_send(handle, cmd))) { + esl_mutex_unlock(handle->mutex); return status; } - status = esl_recv_event(handle, &handle->last_sr_event); - - if (handle->last_sr_event) { - hval = esl_event_get_header(handle->last_sr_event, "reply-text"); + recv: - if (!esl_strlen_zero(hval)) { - strncpy(handle->last_sr_reply, hval, sizeof(handle->last_sr_reply)); + status = esl_recv_event(handle, 0, &handle->last_sr_event); + + if (handle->last_sr_event) { + char *ct = esl_event_get_header(handle->last_sr_event,"content-type"); + + if (strcasecmp(ct, "api/response") && strcasecmp(ct, "command/reply")) { + esl_event_t *ep; + + for(ep = handle->race_event; ep && ep->next; ep = ep->next); + + if (ep) { + ep->next = handle->last_sr_event; + } else { + handle->race_event = handle->last_sr_event; + } + + handle->last_sr_event = NULL; + + esl_mutex_unlock(handle->mutex); + esl_mutex_lock(handle->mutex); + goto recv; + } + + if (handle->last_sr_event) { + hval = esl_event_get_header(handle->last_sr_event, "reply-text"); + + if (!esl_strlen_zero(hval)) { + strncpy(handle->last_sr_reply, hval, sizeof(handle->last_sr_reply)); + } } } diff --git a/libs/esl/src/esl_event.c b/libs/esl/src/esl_event.c index 2c4cfec5b2..b683488ba0 100644 --- a/libs/esl/src/esl_event.c +++ b/libs/esl/src/esl_event.c @@ -367,22 +367,25 @@ ESL_DECLARE(esl_status_t) esl_event_add_body(esl_event_t *event, const char *fmt ESL_DECLARE(void) esl_event_destroy(esl_event_t **event) { - esl_event_t *ep = *event; - esl_event_header_t *hp, *this; + esl_event_t *ep = *event, *this_event; + esl_event_header_t *hp, *this_header; - if (ep) { - for (hp = ep->headers; hp;) { - this = hp; + for (ep = *event ; ep ;) { + this_event = ep; + ep = ep->next; + + for (hp = this_event->headers; hp;) { + this_header = hp; hp = hp->next; - FREE(this->name); - FREE(this->value); - memset(this, 0, sizeof(*this)); - FREE(this); + FREE(this_header->name); + FREE(this_header->value); + memset(this_header, 0, sizeof(*this_header)); + FREE(this_header); } - FREE(ep->body); - FREE(ep->subclass_name); - memset(ep, 0, sizeof(*ep)); - FREE(ep); + FREE(this_event->body); + FREE(this_event->subclass_name); + memset(this_event, 0, sizeof(*this_event)); + FREE(this_event); } *event = NULL; } diff --git a/libs/esl/src/esl_oop.cpp b/libs/esl/src/esl_oop.cpp index 8328c2e416..164fec14ee 100644 --- a/libs/esl/src/esl_oop.cpp +++ b/libs/esl/src/esl_oop.cpp @@ -154,7 +154,7 @@ ESLevent *ESLconnection::recvEvent() delete last_event_obj; } - if (esl_recv_event(&handle, NULL) == ESL_SUCCESS) { + if (esl_recv_event(&handle, 1, NULL) == ESL_SUCCESS) { esl_event_t *e = handle.last_ievent ? handle.last_ievent : handle.last_event; if (e) { esl_event_t *event; @@ -176,7 +176,7 @@ ESLevent *ESLconnection::recvEventTimed(int ms) last_event_obj = NULL; } - if (esl_recv_event_timed(&handle, ms, NULL) == ESL_SUCCESS) { + if (esl_recv_event_timed(&handle, ms, 1, NULL) == ESL_SUCCESS) { esl_event_t *e = handle.last_ievent ? handle.last_ievent : handle.last_event; if (e) { esl_event_t *event; diff --git a/libs/esl/src/include/esl.h b/libs/esl/src/include/esl.h index e7b1c4528e..a43ff6db22 100644 --- a/libs/esl/src/include/esl.h +++ b/libs/esl/src/include/esl.h @@ -266,6 +266,7 @@ typedef struct { char last_sr_reply[1024]; esl_event_t *last_event; esl_event_t *last_sr_event; + esl_event_t *race_event; esl_event_t *last_ievent; esl_event_t *info_event; int connected; @@ -334,14 +335,14 @@ ESL_DECLARE(esl_status_t) esl_sendevent(esl_handle_t *handle, esl_event_t *event ESL_DECLARE(esl_status_t) esl_connect(esl_handle_t *handle, const char *host, esl_port_t port, const char *password); ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle); ESL_DECLARE(esl_status_t) esl_send(esl_handle_t *handle, const char *cmd); -ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, esl_event_t **save_event); -ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, esl_event_t **save_event); +ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event); +ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, int check_q, esl_event_t **save_event); ESL_DECLARE(esl_status_t) esl_send_recv(esl_handle_t *handle, const char *cmd); ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value); ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etype, const char *value); -#define esl_recv(_h) esl_recv_event(_h, NULL) -#define esl_recv_timed(_h, _ms) esl_recv_event_timed(_h, _ms, NULL) +#define esl_recv(_h) esl_recv_event(_h, 0, NULL) +#define esl_recv_timed(_h, _ms) esl_recv_event_timed(_h, _ms, 0, NULL) static __inline__ int esl_safe_strcasecmp(const char *s1, const char *s2) {