From 2081bf97b9836f5299c22edbb1ead077842ea2bc Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 16 Dec 2010 11:33:38 -0600 Subject: [PATCH] use a packet buffer for ESL --- Makefile.am | 6 +- libs/esl/Makefile | 6 +- libs/esl/src/esl.c | 155 ++++++++++++++++++++----------------- libs/esl/src/include/esl.h | 8 +- libs/esl/testclient.c | 41 ++++++++++ 5 files changed, 141 insertions(+), 75 deletions(-) diff --git a/Makefile.am b/Makefile.am index da89572c6f..df1ee2e0d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -276,7 +276,8 @@ bin_PROGRAMS = freeswitch fs_cli fs_ivrd tone2wav fs_encode ## ## fs_cli () ## -fs_cli_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c libs/esl/src/esl_threadmutex.c libs/esl/fs_cli.c libs/esl/src/esl_json.c +fs_cli_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c \ + libs/esl/src/esl_threadmutex.c libs/esl/fs_cli.c libs/esl/src/esl_json.c libs/esl/src/esl_buffer.c fs_cli_CFLAGS = $(AM_CFLAGS) -I$(switch_srcdir)/libs/esl/src/include fs_cli_LDFLAGS = $(AM_LDFLAGS) -lpthread $(ESL_LDFLAGS) -lm @@ -304,7 +305,8 @@ tone2wav_LDADD = libfreeswitch.la ## ## fs_ivrd () ## -fs_ivrd_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c libs/esl/src/esl_threadmutex.c libs/esl/ivrd.c libs/esl/src/esl_json.c +fs_ivrd_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c \ + libs/esl/src/esl_threadmutex.c libs/esl/ivrd.c libs/esl/src/esl_json.c libs/esl/src/esl_buffer.c fs_ivrd_CFLAGS = $(AM_CFLAGS) -I$(switch_srcdir)/libs/esl/src/include fs_ivrd_LDFLAGS = $(AM_LDFLAGS) -lpthread $(ESL_LDFLAGS) -lm diff --git a/libs/esl/Makefile b/libs/esl/Makefile index a180406bda..ab50bac4d9 100644 --- a/libs/esl/Makefile +++ b/libs/esl/Makefile @@ -9,9 +9,9 @@ CXXFLAGS=$(BASE_FLAGS) -Wall -Werror -Wno-unused-variable MYLIB=libesl.a LIBS=-lncurses -lpthread -lesl -lm LDFLAGS=-L. -OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o src/esl_json.o -SRC=src/esl.c src/esl_json.c src/esl_event.c src/esl_threadmutex.c src/esl_config.c src/esl_oop.cpp src/esl_json.c -HEADERS=src/include/esl_config.h src/include/esl_event.h src/include/esl.h src/include/esl_threadmutex.h src/include/esl_oop.h src/include/esl_json.h +OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o src/esl_json.o src/esl_buffer.o +SRC=src/esl.c src/esl_json.c src/esl_event.c src/esl_threadmutex.c src/esl_config.c src/esl_oop.cpp src/esl_json.c src/esl_buffer.c +HEADERS=src/include/esl_config.h src/include/esl_event.h src/include/esl.h src/include/esl_threadmutex.h src/include/esl_oop.h src/include/esl_json.h src/include/esl_buffer.h SOLINK=-shared -Xlinker -x # comment the next line to disable c++ (no swig mods for you then) OBJS += src/esl_oop.o diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index ce582d3837..3397dbfb55 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -428,6 +428,10 @@ ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t s esl_mutex_create(&handle->mutex); } + if (!handle->packet_buf) { + esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0); + } + handle->connected = 1; esl_send_recv(handle, "connect\n\n"); @@ -632,6 +636,10 @@ ESL_DECLARE(esl_status_t) esl_connect_timeout(esl_handle_t *handle, const char * if (!handle->mutex) { esl_mutex_create(&handle->mutex); } + + if (!handle->packet_buf) { + esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0); + } handle->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -805,6 +813,11 @@ ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle) esl_mutex_destroy(&mutex); } + if (handle->packet_buf) { + esl_buffer_destroy(&handle->packet_buf); + } + + return status; } @@ -825,7 +838,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms if (check_q) { esl_mutex_lock(handle->mutex); - if (handle->race_event) { + if (handle->race_event || esl_buffer_packet_count(handle->packet_buf)) { esl_mutex_unlock(handle->mutex); return esl_recv_event(handle, check_q, save_event); } @@ -894,12 +907,15 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms } +static esl_ssize_t handle_recv(esl_handle_t *handle, void *data, esl_size_t datalen) +{ + return recv(handle->sock, data, datalen, 0); +} 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; char *beg; char *hname, *hval; @@ -907,7 +923,6 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ char *cl; esl_ssize_t len; int zc = 0; - int bread = 0; if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) { return ESL_FAIL; @@ -916,9 +931,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ esl_mutex_lock(handle->mutex); if (!handle->connected || handle->sock == ESL_SOCK_INVALID) { - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_FAIL; + goto fail; } esl_event_safe_destroy(&handle->last_event); @@ -932,76 +945,62 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ goto parse_event; } - memset(handle->header_buf, 0, sizeof(handle->header_buf)); + + while(!revent && handle->connected) { + esl_size_t len; + + if ((len = esl_buffer_read_packet(handle->packet_buf, handle->socket_buf, sizeof(handle->socket_buf)))) { + char *data = (char *) handle->socket_buf; + char *p, *e; + + esl_event_create(&revent, ESL_EVENT_CLONE); + revent->event_id = ESL_EVENT_SOCKET_DATA; + esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA"); + + hname = p = data; + while(p) { + hname = p; + p = NULL; - c = handle->header_buf; - beg = c; + if ((hval = strchr(hname, ':'))) { + *hval++ = '\0'; + while(*hval == ' ' || *hval == '\t') hval++; - while(handle->connected) { - if (bread + 2 >= sizeof(handle->header_buf)) { - esl_log(ESL_LOG_CRIT, "OUT OF BUFFER SPACE!\n"); - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_DISCONNECTED; + if ((e = strchr(hval, '\n'))) { + *e++ = '\0'; + while(*e == '\n' || *e == '\r') e++; + + if (hname && hval) { + esl_url_decode(hval); + esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval); + esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); + } + + p = e; + } + } + } + + break; } - rrval = recv(handle->sock, c, 1, 0); + rrval = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf)); + if (rrval == 0) { if (++zc >= 100) { - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_DISCONNECTED; + goto fail; } + continue; } else if (rrval < 0) { strerror_r(handle->errnum, handle->err, sizeof(handle->err)); goto fail; - } else { - zc = 0; - - if (*c == '\n') { - - *(c+1) = '\0'; - - if (++crc == 2) { - break; - } - - if (!revent) { - esl_event_create(&revent, ESL_EVENT_CLONE); - revent->event_id = ESL_EVENT_SOCKET_DATA; - esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA"); - - } - - hname = beg; - hval = col = NULL; - - if (hname && (col = strchr(hname, ':'))) { - hval = col + 1; - *col = '\0'; - while(*hval == ' ') hval++; - } - - *c = '\0'; - - if (hname && hval) { - esl_url_decode(hval); - esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval); - esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); - } - - c = beg; - bread = 0; - continue; - - } else { - crc = 0; - } - - c++; } - } + zc = 0; + + esl_buffer_write(handle->packet_buf, handle->socket_buf, rrval); + } + if (!revent) { goto fail; } @@ -1016,12 +1015,28 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ *(body + len) = '\0'; do { - esl_ssize_t r; - if ((r = recv(handle->sock, body + sofar, len - sofar, 0)) < 0) { - strerror_r(handle->errnum, handle->err, sizeof(handle->err)); - goto fail; + esl_ssize_t r,s = esl_buffer_inuse(handle->packet_buf); + + if (s >= len) { + sofar = esl_buffer_read(handle->packet_buf, body, len); + } else { + r = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf)); + + if (r < 0) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + goto fail; + } else if (r == 0) { + if (++zc >= 100) { + goto fail; + } + continue; + } + + zc = 0; + + esl_buffer_write(handle->packet_buf, handle->socket_buf, r); } - sofar += r; + } while (sofar < len); revent->body = body; @@ -1123,6 +1138,8 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ fail: + esl_mutex_unlock(handle->mutex); + handle->connected = 0; return ESL_FAIL; diff --git a/libs/esl/src/include/esl.h b/libs/esl/src/include/esl.h index 9f28c3d925..99ab53ae95 100644 --- a/libs/esl/src/include/esl.h +++ b/libs/esl/src/include/esl.h @@ -251,6 +251,7 @@ typedef int esl_filehandle_t; #include "esl_json.h" typedef int16_t esl_port_t; +typedef size_t esl_size_t; typedef enum { ESL_SUCCESS, @@ -259,7 +260,11 @@ typedef enum { ESL_DISCONNECTED } esl_status_t; +#define BUF_CHUNK 65536 * 50 +#define BUF_START 65536 * 100 + #include +#include /*! \brief A handle that will hold the socket information and different events received. */ @@ -273,7 +278,8 @@ typedef struct { /*! The error number reported by the OS */ int errnum; /*! The inner contents received by the socket. Used only internally. */ - char header_buf[4196]; + esl_buffer_t *packet_buf; + char socket_buf[65536]; /*! Last command reply */ char last_reply[1024]; /*! Las command reply when called with esl_send_recv */ diff --git a/libs/esl/testclient.c b/libs/esl/testclient.c index 9fa271fd0b..a031836d50 100644 --- a/libs/esl/testclient.c +++ b/libs/esl/testclient.c @@ -6,6 +6,47 @@ int main(void) { esl_handle_t handle = {{0}}; + esl_buffer_t *buffer; + char doh[65536]; + + esl_buffer_create(&buffer, 32 * 1024, 32 * 1024, 0); + + snprintf(doh, sizeof(doh), "TEST 1 FOO BAR 1234\n"); + esl_buffer_write(buffer, doh, strlen(doh)); + esl_buffer_write(buffer, doh, strlen(doh)); + esl_buffer_write(buffer, doh, strlen(doh)); + snprintf(doh, sizeof(doh), "TEST 1 END\n\n"); + esl_buffer_write(buffer, doh, strlen(doh)); + + + + snprintf(doh, sizeof(doh), "TEST 2 BAR FOO 4321\n"); + esl_buffer_write(buffer, doh, strlen(doh)); + esl_buffer_write(buffer, doh, strlen(doh)); + esl_buffer_write(buffer, doh, strlen(doh)); + snprintf(doh, sizeof(doh), "TEST 2 END\n\n"); + esl_buffer_write(buffer, doh, strlen(doh)); + + snprintf(doh, sizeof(doh), "TEST 2 BAR FOO 4321\n"); + esl_buffer_write(buffer, doh, strlen(doh)); + esl_buffer_write(buffer, doh, strlen(doh)); + esl_buffer_write(buffer, doh, strlen(doh)); + snprintf(doh, sizeof(doh), "TEST 2 END\n\n"); + esl_buffer_write(buffer, doh, strlen(doh)); + + printf("COUNT %ld\n", esl_buffer_packet_count(buffer)); + + memset(doh, 0, sizeof(doh)); + esl_buffer_read_packet(buffer, doh, sizeof(doh)); + printf("TEST: [%s]\n", doh); + + memset(doh, 0, sizeof(doh)); + + + esl_buffer_read_packet(buffer, doh, sizeof(doh)); + printf("TEST2: [%s]\n", doh); + + return 0; esl_connect(&handle, "localhost", 8021, NULL, "ClueCon");