From 43715831860b2c1939268c5597bf1f813d3e1fa9 Mon Sep 17 00:00:00 2001 From: Leon de Rooij Date: Fri, 24 Apr 2009 15:53:07 +0200 Subject: [PATCH] freeswitch plugin: Copied all esl libs in libesl and modified Makefile --- src/libesl/esl.c | 1078 ++++++++++++++++++++++++++++++++++++ src/{ => libesl}/esl.h | 2 + src/libesl/esl_config.c | 256 +++++++++ src/{ => libesl}/esl_config.h | 0 src/libesl/esl_event.c | 551 ++++++++++++++++++ src/{ => libesl}/esl_event.h | 2 + src/libesl/esl_oop.cpp | 427 ++++++++++++++ src/{ => libesl}/esl_oop.h | 0 src/libesl/esl_threadmutex.c | 237 ++++++++ src/{ => libesl}/esl_threadmutex.h | 0 10 files changed, 2553 insertions(+) create mode 100644 src/libesl/esl.c rename src/{ => libesl}/esl.h (99%) create mode 100644 src/libesl/esl_config.c rename src/{ => libesl}/esl_config.h (100%) create mode 100644 src/libesl/esl_event.c rename src/{ => libesl}/esl_event.h (99%) create mode 100644 src/libesl/esl_oop.cpp rename src/{ => libesl}/esl_oop.h (100%) create mode 100644 src/libesl/esl_threadmutex.c rename src/{ => libesl}/esl_threadmutex.h (100%) diff --git a/src/libesl/esl.c b/src/libesl/esl.c new file mode 100644 index 00000000..2d2600a3 --- /dev/null +++ b/src/libesl/esl.c @@ -0,0 +1,1078 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifndef WIN32 +#define closesocket(x) close(x) +#endif + + +/* Written by Marc Espie, public domain */ +#define ESL_CTYPE_NUM_CHARS 256 + +const short _esl_C_toupper_[1 + ESL_CTYPE_NUM_CHARS] = { + EOF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const short *_esl_toupper_tab_ = _esl_C_toupper_; + +ESL_DECLARE(int) esl_toupper(int c) +{ + if ((unsigned int)c > 255) + return(c); + if (c < -1) + return EOF; + return((_esl_toupper_tab_ + 1)[c]); +} + +const short _esl_C_tolower_[1 + ESL_CTYPE_NUM_CHARS] = { + EOF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const short *_esl_tolower_tab_ = _esl_C_tolower_; + +ESL_DECLARE(int) esl_tolower(int c) +{ + if ((unsigned int)c > 255) + return(c); + if (c < -1) + return EOF; + return((_esl_tolower_tab_ + 1)[c]); +} + +ESL_DECLARE(const char *)esl_stristr(const char *instr, const char *str) +{ +/* +** Rev History: 16/07/97 Greg Thayer Optimized +** 07/04/95 Bob Stout ANSI-fy +** 02/03/94 Fred Cole Original +** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback +** +** Hereby donated to public domain. +*/ + const char *pptr, *sptr, *start; + + if (!str || !instr) + return NULL; + + for (start = str; *start; start++) { + /* find start of pattern in string */ + for (; ((*start) && (esl_toupper(*start) != esl_toupper(*instr))); start++); + + if (!*start) + return NULL; + + pptr = instr; + sptr = start; + + while (esl_toupper(*sptr) == esl_toupper(*pptr)) { + sptr++; + pptr++; + + /* if end of pattern then pattern was found */ + if (!*pptr) + return (start); + + if (!*sptr) + return NULL; + } + } + return NULL; +} + +#ifdef WIN32 +#ifndef vsnprintf +#define vsnprintf _vsnprintf +#endif +#endif + + +int vasprintf(char **ret, const char *format, va_list ap); + +ESL_DECLARE(int) esl_vasprintf(char **ret, const char *fmt, va_list ap) +{ +#if !defined(WIN32) && !defined(__sun) + return vasprintf(ret, fmt, ap); +#else + char *buf; + int len; + size_t buflen; + va_list ap2; + char *tmp = NULL; + +#ifdef _MSC_VER +#if _MSC_VER >= 1500 + /* hack for incorrect assumption in msvc header files for code analysis */ + __analysis_assume(tmp); +#endif + ap2 = ap; +#else + va_copy(ap2, ap); +#endif + + len = vsnprintf(tmp, 0, fmt, ap2); + + if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) { + len = vsnprintf(buf, buflen, fmt, ap); + *ret = buf; + } else { + *ret = NULL; + len = -1; + } + + va_end(ap2); + return len; +#endif +} + + + + +ESL_DECLARE(int) esl_snprintf(char *buffer, size_t count, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsnprintf(buffer, count-1, fmt, ap); + if (ret < 0) + buffer[count-1] = '\0'; + va_end(ap); + return ret; +} + +static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + if (file && func && line && level && fmt) { + return; + } + return; +} + + +static const char *LEVEL_NAMES[] = { + "EMERG", + "ALERT", + "CRIT", + "ERROR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG", + NULL +}; + +static int esl_log_level = 7; + +static const char *cut_path(const char *in) +{ + const char *p, *ret = in; + char delims[] = "/\\"; + char *i; + + for (i = delims; *i; i++) { + p = in; + while ((p = strchr(p, *i)) != 0) { + ret = ++p; + } + } + return ret; +} + + +static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + const char *fp; + char *data; + va_list ap; + int ret; + + if (level < 0 || level > 7) { + level = 7; + } + if (level > esl_log_level) { + return; + } + + fp = cut_path(file); + + va_start(ap, fmt); + + ret = esl_vasprintf(&data, fmt, ap); + + if (ret != -1) { + fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data); + free(data); + } + + va_end(ap); + +} + +esl_logger_t esl_log = null_logger; + +ESL_DECLARE(void) esl_global_set_logger(esl_logger_t logger) +{ + if (logger) { + esl_log = logger; + } else { + esl_log = null_logger; + } +} + +ESL_DECLARE(void) esl_global_set_default_logger(int level) +{ + if (level < 0 || level > 7) { + level = 7; + } + + esl_log = default_logger; + esl_log_level = level; +} + +ESL_DECLARE(size_t) esl_url_encode(const char *url, char *buf, size_t len) +{ + const char *p; + size_t x = 0; + const char urlunsafe[] = "\r\n \"#%&+:;<=>?@[\\]^`{|}"; + const char hex[] = "0123456789ABCDEF"; + + if (!buf) { + return 0; + } + + if (!url) { + return 0; + } + + len--; + + for (p = url; *p; p++) { + if (x >= len) { + break; + } + if (*p < ' ' || *p > '~' || strchr(urlunsafe, *p)) { + if ((x + 3) >= len) { + break; + } + buf[x++] = '%'; + buf[x++] = hex[*p >> 4]; + buf[x++] = hex[*p & 0x0f]; + } else { + buf[x++] = *p; + } + } + buf[x] = '\0'; + + return x; +} + +ESL_DECLARE(char *)esl_url_decode(char *s) +{ + char *o; + unsigned int tmp; + + for (o = s; *s; s++, o++) { + if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { + *o = (char) tmp; + s += 2; + } else { + *o = *s; + } + } + *o = '\0'; + return s; +} + +static void sock_setup(esl_handle_t *handle) +{ +#ifdef WIN32 + BOOL bOptVal = TRUE; + int bOptLen = sizeof(BOOL); + setsockopt(handle->sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&bOptVal, bOptLen); +#else + int x = 1; + setsockopt(handle->sock, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x)); +#endif +} + +ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t socket, struct sockaddr_in *addr) +{ + handle->sock = socket; + if (addr) { + handle->addr = *addr; + } + + if (handle->sock == ESL_SOCK_INVALID) { + return ESL_FAIL; + } + + + if (!handle->mutex) { + esl_mutex_create(&handle->mutex); + } + + handle->connected = 1; + + sock_setup(handle); + + esl_send_recv(handle, "connect\n\n"); + + + if (handle->last_sr_event) { + handle->info_event = handle->last_sr_event; + handle->last_sr_event = NULL; + return ESL_SUCCESS; + } + + handle->connected = 0; + + return ESL_FAIL; +} + +ESL_DECLARE(esl_status_t) esl_sendevent(esl_handle_t *handle, esl_event_t *event) +{ + char *txt; + char event_buf[256] = ""; + + if (!handle->connected || !event) { + return ESL_FAIL; + } + + esl_event_serialize(event, &txt, ESL_FALSE); + + esl_log(ESL_LOG_DEBUG, "SEND EVENT\n%s\n", txt); + + snprintf(event_buf, sizeof(event_buf), "sendevent %s\n", esl_event_name(event->event_id)); + + send(handle->sock, event_buf, strlen(event_buf), 0); + send(handle->sock, txt, strlen(txt), 0); + send(handle->sock, "\n\n", 2, 0); + + free(txt); + + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_execute(esl_handle_t *handle, const char *app, const char *arg, const char *uuid) +{ + char cmd_buf[128] = "sendmsg"; + char app_buf[512] = ""; + char arg_buf[512] = ""; + const char *el_buf = "event-lock: true\n"; + const char *bl_buf = "async: true\n"; + char send_buf[1292] = ""; + + if (!handle->connected) { + return ESL_FAIL; + } + + if (uuid) { + snprintf(cmd_buf, sizeof(cmd_buf), "sendmsg %s", uuid); + } + + if (app) { + snprintf(app_buf, sizeof(app_buf), "execute-app-name: %s\n", app); + } + + if (arg) { + snprintf(arg_buf, sizeof(arg_buf), "execute-app-arg: %s\n", arg); + } + + snprintf(send_buf, sizeof(send_buf), "%s\ncall-command: execute\n%s%s%s%s\n", + cmd_buf, app_buf, arg_buf, handle->event_lock ? el_buf : "", handle->async_execute ? bl_buf : ""); + + return esl_send_recv(handle, send_buf); +} + + +ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value) +{ + char send_buf[1024] = ""; + + if (!handle->connected) { + return ESL_FAIL; + } + + snprintf(send_buf, sizeof(send_buf), "filter %s %s\n\n", header, value); + + return esl_send_recv(handle, send_buf); +} + + +ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etype, const char *value) +{ + char send_buf[1024] = ""; + const char *type = "plain"; + + if (!handle->connected) { + return ESL_FAIL; + } + + if (etype == ESL_EVENT_TYPE_XML) { + type = "xml"; + } + + snprintf(send_buf, sizeof(send_buf), "event %s %s\n\n", type, value); + + return esl_send_recv(handle, send_buf); +} + +static int esl_socket_reuseaddr(esl_socket_t socket) +{ +#ifdef WIN32 + BOOL reuse_addr = TRUE; + return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse_addr, sizeof(reuse_addr)); +#else + int reuse_addr = 1; + return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); +#endif +} + +ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback) +{ + esl_socket_t server_sock = ESL_SOCK_INVALID; + struct sockaddr_in addr; + esl_status_t status = ESL_SUCCESS; + + if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + return ESL_FAIL; + } + + esl_socket_reuseaddr(server_sock); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + status = ESL_FAIL; + goto end; + } + + if (listen(server_sock, 10000) < 0) { + status = ESL_FAIL; + goto end; + } + + for (;;) { + int client_sock; + struct sockaddr_in echoClntAddr; +#ifdef WIN32 + int clntLen; +#else + unsigned int clntLen; +#endif + + clntLen = sizeof(echoClntAddr); + + if ((client_sock = accept(server_sock, (struct sockaddr *) &echoClntAddr, &clntLen)) == ESL_SOCK_INVALID) { + status = ESL_FAIL; + goto end; + } + + callback(server_sock, client_sock, &echoClntAddr); + } + + end: + + if (server_sock != ESL_SOCK_INVALID) { + closesocket(server_sock); + server_sock = ESL_SOCK_INVALID; + } + + return status; + +} + +ESL_DECLARE(esl_status_t) esl_connect(esl_handle_t *handle, const char *host, esl_port_t port, const char *password) +{ + + struct hostent *result; + char sendbuf[256]; + int rval = 0; + const char *hval; +#ifdef WIN32 + WORD wVersionRequested = MAKEWORD(2, 0); + WSADATA wsaData; + int err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + snprintf(handle->err, sizeof(handle->err), "WSAStartup Error"); + return ESL_FAIL; + } + +#endif + + if (!handle->mutex) { + esl_mutex_create(&handle->mutex); + } + + handle->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (handle->sock == ESL_SOCK_INVALID) { + snprintf(handle->err, sizeof(handle->err), "Socket Error"); + return ESL_FAIL; + } + + memset(&handle->sockaddr, 0, sizeof(handle->sockaddr)); + handle->sockaddr.sin_family = AF_INET; + handle->sockaddr.sin_port = htons(port); + + memset(&handle->hostent, 0, sizeof(handle->hostent)); + + if ((result = gethostbyname(host))) { + handle->hostent = *result; + } else { + rval = -1; + } + + if (rval) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + goto fail; + } + + memcpy(&handle->sockaddr.sin_addr, result->h_addr_list[0], result->h_length); + + rval = connect(handle->sock, (struct sockaddr *) &handle->sockaddr, sizeof(handle->sockaddr)); + + if (rval) { + snprintf(handle->err, sizeof(handle->err), "Socket Connection Error"); + goto fail; + } + + sock_setup(handle); + + handle->connected = 1; + + if (esl_recv(handle)) { + snprintf(handle->err, sizeof(handle->err), "Connection Error"); + goto fail; + } + + hval = esl_event_get_header(handle->last_event, "content-type"); + + if (esl_safe_strcasecmp(hval, "auth/request")) { + snprintf(handle->err, sizeof(handle->err), "Connection Error"); + goto fail; + } + + snprintf(sendbuf, sizeof(sendbuf), "auth %s\n\n", password); + esl_send(handle, sendbuf); + + + if (esl_recv(handle)) { + snprintf(handle->err, sizeof(handle->err), "Authentication Error"); + goto fail; + } + + + hval = esl_event_get_header(handle->last_event, "reply-text"); + + if (esl_safe_strcasecmp(hval, "+OK accepted")) { + snprintf(handle->err, sizeof(handle->err), "Authentication Error"); + goto fail; + } + + return ESL_SUCCESS; + + fail: + + esl_disconnect(handle); + + return ESL_FAIL; +} + +ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle) +{ + esl_mutex_t *mutex = handle->mutex; + esl_status_t status = ESL_FAIL; + + if (mutex) { + 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); + esl_event_safe_destroy(&handle->info_event); + + if (handle->sock != ESL_SOCK_INVALID) { + closesocket(handle->sock); + handle->sock = ESL_SOCK_INVALID; + status = ESL_SUCCESS; + } + + handle->connected = 0; + + if (mutex) { + esl_mutex_unlock(mutex); + esl_mutex_destroy(&mutex); + } + + + return status; +} + +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; + + + FD_ZERO(&rfds); + FD_ZERO(&efds); + +#ifdef WIN32 +#pragma warning( push ) +#pragma warning( disable : 4127 ) + FD_SET(handle->sock, &rfds); + FD_SET(handle->sock, &efds); +#pragma warning( pop ) +#else + FD_SET(handle->sock, &rfds); + FD_SET(handle->sock, &efds); +#endif + + max = handle->sock + 1; + + if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) { + 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, check_q, save_event)) { + status = ESL_FAIL; + } + } else { + status = ESL_BREAK; + } + + if (handle->mutex) esl_mutex_unlock(handle->mutex); + + return status; + +} + + +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, *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)); + + c = handle->header_buf; + beg = c; + + while(handle->connected) { + rrval = recv(handle->sock, c, 1, 0); + if (rrval == 0) { + if (++zc >= 100) { + esl_disconnect(handle); + esl_mutex_unlock(handle->mutex); + return ESL_DISCONNECTED; + } + } else if (rrval < 0) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + goto fail; + } else { + zc = 0; + + if (*c == '\n') { + if (++crc == 2) { + break; + } + + if (!revent) { + esl_event_create(&revent, ESL_EVENT_COMMAND); + } + + 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); + } + + beg = c+1; + + + } else { + crc = 0; + } + + c++; + } + } + + if (!revent) { + goto fail; + } + + if ((cl = esl_event_get_header(revent, "content-length"))) { + char *body; + esl_ssize_t sofar = 0; + + len = atol(cl); + body = malloc(len+1); + esl_assert(body); + *(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; + } + sofar += r; + } while (sofar < len); + + revent->body = body; + } + + if (save_event) { + *save_event = revent; + revent = NULL; + } else { + handle->last_event = revent; + } + + if (revent) { + hval = esl_event_get_header(revent, "reply-text"); + + if (!esl_strlen_zero(hval)) { + strncpy(handle->last_reply, hval, sizeof(handle->last_reply)); + } + + hval = esl_event_get_header(revent, "content-type"); + + if (!esl_safe_strcasecmp(hval, "text/disconnect-notice") && revent->body) { + goto fail; + } + + if (!esl_safe_strcasecmp(hval, "text/event-plain") && revent->body) { + esl_event_types_t et = ESL_EVENT_COMMAND; + char *body = strdup(revent->body); + + esl_event_safe_destroy(&handle->last_ievent); + + esl_event_create(&handle->last_ievent, et); + + beg = body; + + while(beg) { + if (!(c = strchr(beg, '\n'))) { + break; + } + + 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 INNER HEADER [%s] = [%s]\n", hname, hval); + if (!strcasecmp(hname, "event-name")) { + esl_event_del_header(handle->last_ievent, "event-name"); + } + esl_event_add_header_string(handle->last_ievent, ESL_STACK_BOTTOM, hname, hval); + esl_name_event(hval, &handle->last_ievent->event_id); + } + + beg = c + 1; + + if (*beg == '\n') { + beg++; + break; + } + } + + if ((cl = esl_event_get_header(handle->last_ievent, "content-length"))) { + handle->last_ievent->body = strdup(beg); + } + + free(body); + + if (esl_log_level >= 7) { + char *foo; + esl_event_serialize(handle->last_ievent, &foo, ESL_FALSE); + esl_log(ESL_LOG_DEBUG, "RECV EVENT\n%s\n", foo); + free(foo); + } + } + + if (esl_log_level >= 7) { + char *foo; + esl_event_serialize(revent, &foo, ESL_FALSE); + esl_log(ESL_LOG_DEBUG, "RECV MESSAGE\n%s\n", foo); + free(foo); + } + } + + esl_mutex_unlock(handle->mutex); + + return ESL_SUCCESS; + + fail: + + esl_disconnect(handle); + return ESL_FAIL; + +} + +ESL_DECLARE(esl_status_t) esl_send(esl_handle_t *handle, const char *cmd) +{ + const char *e = cmd + strlen(cmd) -1; + + if (!handle->connected) { + return ESL_FAIL; + } + + esl_log(ESL_LOG_DEBUG, "SEND\n%s\n", cmd); + + if (send(handle->sock, cmd, strlen(cmd), 0) != (int)strlen(cmd)) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + return ESL_FAIL; + } + + if (!(*e == '\n' && *(e-1) == '\n')) { + if (send(handle->sock, "\n\n", 2, 0) != 2) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + return ESL_FAIL; + } + } + + return ESL_SUCCESS; + +} + + +ESL_DECLARE(esl_status_t) esl_send_recv(esl_handle_t *handle, const char *cmd) +{ + const char *hval; + esl_status_t status; + + if (!handle->connected) { + 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; + } + + recv: + + 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)); + } + } + } + + esl_mutex_unlock(handle->mutex); + + return status; +} + + + + diff --git a/src/esl.h b/src/libesl/esl.h similarity index 99% rename from src/esl.h rename to src/libesl/esl.h index ecca1908..db86abb7 100644 --- a/src/esl.h +++ b/src/libesl/esl.h @@ -174,6 +174,8 @@ typedef enum { #include #include #ifndef WIN32 +#include +#include #include #include #include diff --git a/src/libesl/esl_config.c b/src/libesl/esl_config.c new file mode 100644 index 00000000..b781d83e --- /dev/null +++ b/src/libesl/esl_config.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "esl.h" +#include "esl_config.h" + +ESL_DECLARE(int) esl_config_open_file(esl_config_t *cfg, const char *file_path) +{ + FILE *f; + const char *path = NULL; + char path_buf[1024]; + + if (file_path[0] == '/') { + path = file_path; + } else { + esl_snprintf(path_buf, sizeof(path_buf), "%s%s%s", ESL_CONFIG_DIR, ESL_PATH_SEPARATOR, file_path); + path = path_buf; + } + + if (!path) { + return 0; + } + + memset(cfg, 0, sizeof(*cfg)); + cfg->lockto = -1; + esl_log(ESL_LOG_DEBUG, "Configuration file is %s.\n", path); + f = fopen(path, "r"); + + if (!f) { + if (file_path[0] != '/') { + int last = -1; + char *var, *val; + + esl_snprintf(path_buf, sizeof(path_buf), "%s%sopenesl.conf", ESL_CONFIG_DIR, ESL_PATH_SEPARATOR); + path = path_buf; + + if ((f = fopen(path, "r")) == 0) { + return 0; + } + + cfg->file = f; + esl_set_string(cfg->path, path); + + while (esl_config_next_pair(cfg, &var, &val)) { + if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) { + cfg->lockto = cfg->sectno; + return 1; + } + } + + esl_config_close_file(cfg); + memset(cfg, 0, sizeof(*cfg)); + return 0; + } + + return 0; + } else { + cfg->file = f; + esl_set_string(cfg->path, path); + return 1; + } +} + +ESL_DECLARE(void) esl_config_close_file(esl_config_t *cfg) +{ + + if (cfg->file) { + fclose(cfg->file); + } + + memset(cfg, 0, sizeof(*cfg)); +} + + + +ESL_DECLARE(int) esl_config_next_pair(esl_config_t *cfg, char **var, char **val) +{ + int ret = 0; + char *p, *end; + + *var = *val = NULL; + + if (!cfg->path) { + return 0; + } + + for (;;) { + cfg->lineno++; + + if (!fgets(cfg->buf, sizeof(cfg->buf), cfg->file)) { + ret = 0; + break; + } + *var = cfg->buf; + + if (**var == '[' && (end = strchr(*var, ']')) != 0) { + *end = '\0'; + (*var)++; + if (**var == '+') { + (*var)++; + esl_copy_string(cfg->section, *var, sizeof(cfg->section)); + cfg->sectno++; + + if (cfg->lockto > -1 && cfg->sectno != cfg->lockto) { + break; + } + cfg->catno = 0; + cfg->lineno = 0; + *var = (char *) ""; + *val = (char *) ""; + return 1; + } else { + esl_copy_string(cfg->category, *var, sizeof(cfg->category)); + cfg->catno++; + } + continue; + } + + + + if (**var == '#' || **var == ';' || **var == '\n' || **var == '\r') { + continue; + } + + if (!strncmp(*var, "__END__", 7)) { + break; + } + + + if ((end = strchr(*var, ';')) && *(end+1) == *end) { + *end = '\0'; + end--; + } else if ((end = strchr(*var, '\n')) != 0) { + if (*(end - 1) == '\r') { + end--; + } + *end = '\0'; + } + + p = *var; + while ((*p == ' ' || *p == '\t') && p != end) { + *p = '\0'; + p++; + } + *var = p; + + + if ((*val = strchr(*var, '=')) == 0) { + ret = -1; + /* log_printf(0, server.log, "Invalid syntax on %s: line %d\n", cfg->path, cfg->lineno); */ + continue; + } else { + p = *val - 1; + *(*val) = '\0'; + (*val)++; + if (*(*val) == '>') { + *(*val) = '\0'; + (*val)++; + } + + while ((*p == ' ' || *p == '\t') && p != *var) { + *p = '\0'; + p--; + } + + p = *val; + while ((*p == ' ' || *p == '\t') && p != end) { + *p = '\0'; + p++; + } + *val = p; + ret = 1; + break; + } + } + + + return ret; + +} + +ESL_DECLARE(int) esl_config_get_cas_bits(char *strvalue, unsigned char *outbits) +{ + char cas_bits[5]; + unsigned char bit = 0x8; + char *double_colon = strchr(strvalue, ':'); + int x = 0; + + if (!double_colon) { + esl_log(ESL_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon); + return -1; + } + + double_colon++; + *outbits = 0; + cas_bits[4] = 0; + + if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) { + esl_log(ESL_LOG_ERROR, "Invalid CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon); + return -1; + } + + esl_log(ESL_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits); + + for (; cas_bits[x]; x++) { + if ('1' == cas_bits[x]) { + *outbits |= bit; + } else if ('0' != cas_bits[x]) { + esl_log(ESL_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n"); + return -1; + } + bit >>= 1; + } + return 0; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */ diff --git a/src/esl_config.h b/src/libesl/esl_config.h similarity index 100% rename from src/esl_config.h rename to src/libesl/esl_config.h diff --git a/src/libesl/esl_event.c b/src/libesl/esl_event.c new file mode 100644 index 00000000..65bcb341 --- /dev/null +++ b/src/libesl/esl_event.c @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include + +static char *my_dup(const char *s) +{ + size_t len = strlen(s) + 1; + void *new = malloc(len); + esl_assert(new); + + return (char *) memcpy(new, s, len); +} + +#ifndef ALLOC +#define ALLOC(size) malloc(size) +#endif +#ifndef DUP +#define DUP(str) my_dup(str) +#endif +#ifndef FREE +#define FREE(ptr) esl_safe_free(ptr) +#endif + +/* make sure this is synced with the esl_event_types_t enum in esl_types.h + also never put any new ones before EVENT_ALL +*/ +static const char *EVENT_NAMES[] = { + "CUSTOM", + "CLONE", + "CHANNEL_CREATE", + "CHANNEL_DESTROY", + "CHANNEL_STATE", + "CHANNEL_ANSWER", + "CHANNEL_HANGUP", + "CHANNEL_EXECUTE", + "CHANNEL_EXECUTE_COMPLETE", + "CHANNEL_BRIDGE", + "CHANNEL_UNBRIDGE", + "CHANNEL_PROGRESS", + "CHANNEL_PROGRESS_MEDIA", + "CHANNEL_OUTGOING", + "CHANNEL_PARK", + "CHANNEL_UNPARK", + "CHANNEL_APPLICATION", + "CHANNEL_ORIGINATE", + "CHANNEL_UUID", + "API", + "LOG", + "INBOUND_CHAN", + "OUTBOUND_CHAN", + "STARTUP", + "SHUTDOWN", + "PUBLISH", + "UNPUBLISH", + "TALK", + "NOTALK", + "SESSION_CRASH", + "MODULE_LOAD", + "MODULE_UNLOAD", + "DTMF", + "MESSAGE", + "PRESENCE_IN", + "NOTIFY_IN", + "PRESENCE_OUT", + "PRESENCE_PROBE", + "MESSAGE_WAITING", + "MESSAGE_QUERY", + "ROSTER", + "CODEC", + "BACKGROUND_JOB", + "DETECTED_SPEECH", + "DETECTED_TONE", + "PRIVATE_COMMAND", + "HEARTBEAT", + "TRAP", + "ADD_SCHEDULE", + "DEL_SCHEDULE", + "EXE_SCHEDULE", + "RE_SCHEDULE", + "RELOADXML", + "NOTIFY", + "SEND_MESSAGE", + "RECV_MESSAGE", + "REQUEST_PARAMS", + "CHANNEL_DATA", + "GENERAL", + "COMMAND", + "SESSION_HEARTBEAT", + "CLIENT_DISCONNECTED", + "SERVER_DISCONNECTED", + "SEND_INFO", + "RECV_INFO", + "ALL" +}; + +ESL_DECLARE(const char *)esl_event_name(esl_event_types_t event) +{ + return EVENT_NAMES[event]; +} + +ESL_DECLARE(esl_status_t) esl_name_event(const char *name, esl_event_types_t *type) +{ + esl_event_types_t x; + + for (x = 0; x <= ESL_EVENT_ALL; x++) { + if ((strlen(name) > 13 && !strcasecmp(name + 13, EVENT_NAMES[x])) || !strcasecmp(name, EVENT_NAMES[x])) { + *type = x; + return ESL_SUCCESS; + } + } + + return ESL_FAIL; +} + + +ESL_DECLARE(esl_status_t) esl_event_create_subclass(esl_event_t **event, esl_event_types_t event_id, const char *subclass_name) +{ + *event = NULL; + + if ((event_id != ESL_EVENT_CLONE && event_id != ESL_EVENT_CUSTOM) && subclass_name) { + return ESL_FAIL; + } + + *event = ALLOC(sizeof(esl_event_t)); + esl_assert(*event); + + + memset(*event, 0, sizeof(esl_event_t)); + + if (event_id != ESL_EVENT_CLONE) { + (*event)->event_id = event_id; + esl_event_add_header_string(*event, ESL_STACK_BOTTOM, "Event-Name", esl_event_name((*event)->event_id)); + } + + if (subclass_name) { + (*event)->subclass_name = DUP(subclass_name); + esl_event_add_header_string(*event, ESL_STACK_BOTTOM, "Event-Subclass", subclass_name); + } + + return ESL_SUCCESS; +} + + +ESL_DECLARE(const char *)esl_priority_name(esl_priority_t priority) +{ + switch (priority) { /*lol */ + case ESL_PRIORITY_NORMAL: + return "NORMAL"; + case ESL_PRIORITY_LOW: + return "LOW"; + case ESL_PRIORITY_HIGH: + return "HIGH"; + default: + return "INVALID"; + } +} + +ESL_DECLARE(esl_status_t) esl_event_set_priority(esl_event_t *event, esl_priority_t priority) +{ + event->priority = priority; + esl_event_add_header_string(event, ESL_STACK_TOP, "priority", esl_priority_name(priority)); + return ESL_SUCCESS; +} + +#define ESL_HASH_KEY_STRING -1 + +static unsigned int esl_ci_hashfunc_default(const char *char_key, esl_ssize_t *klen) + +{ + unsigned int hash = 0; + const unsigned char *key = (const unsigned char *)char_key; + const unsigned char *p; + esl_ssize_t i; + + if (*klen == ESL_HASH_KEY_STRING) { + for (p = key; *p; p++) { + hash = hash * 33 + tolower(*p); + } + *klen = p - key; + } + else { + for (p = key, i = *klen; i; i--, p++) { + hash = hash * 33 + tolower(*p); + } + } + + return hash; +} + + +ESL_DECLARE(char *)esl_event_get_header(esl_event_t *event, const char *header_name) +{ + esl_event_header_t *hp; + esl_ssize_t hlen = -1; + unsigned long hash = 0; + + esl_assert(event); + + if (!header_name) return NULL; + + hash = esl_ci_hashfunc_default(header_name, &hlen); + + for (hp = event->headers; hp; hp = hp->next) { + if ((!hp->hash || hash == hp->hash) && !strcasecmp(hp->name, header_name) ) { + return hp->value; + } + } + return NULL; +} + +ESL_DECLARE(char *)esl_event_get_body(esl_event_t *event) +{ + return (event ? event->body : NULL); +} + +ESL_DECLARE(esl_status_t) esl_event_del_header(esl_event_t *event, const char *header_name) +{ + esl_event_header_t *hp, *lp = NULL, *tp; + esl_status_t status = ESL_FAIL; + int x = 0; + esl_ssize_t hlen = -1; + unsigned long hash = 0; + + tp = event->headers; + while (tp) { + hp = tp; + tp = tp->next; + + x++; + esl_assert(x < 1000); + hash = esl_ci_hashfunc_default(header_name, &hlen); + + if (hp->name && (!hp->hash || hash == hp->hash) && !strcasecmp(header_name, hp->name)) { + if (lp) { + lp->next = hp->next; + } else { + event->headers = hp->next; + } + if (hp == event->last_header || !hp->next) { + event->last_header = lp; + } + FREE(hp->name); + FREE(hp->value); + memset(hp, 0, sizeof(*hp)); + FREE(hp); + + status = ESL_SUCCESS; + } else { + lp = hp; + } + } + + return status; +} + +static esl_status_t esl_event_base_add_header(esl_event_t *event, esl_stack_t stack, const char *header_name, char *data) +{ + esl_event_header_t *header; + esl_ssize_t hlen = -1; + + header = ALLOC(sizeof(*header)); + esl_assert(header); + + memset(header, 0, sizeof(*header)); + + header->name = DUP(header_name); + header->value = data; + header->hash = esl_ci_hashfunc_default(header->name, &hlen); + + if (stack == ESL_STACK_TOP) { + header->next = event->headers; + event->headers = header; + if (!event->last_header) { + event->last_header = header; + } + } else { + if (event->last_header) { + event->last_header->next = header; + } else { + event->headers = header; + header->next = NULL; + } + event->last_header = header; + } + + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_event_add_header(esl_event_t *event, esl_stack_t stack, const char *header_name, const char *fmt, ...) +{ + int ret = 0; + char *data; + va_list ap; + + va_start(ap, fmt); + ret = esl_vasprintf(&data, fmt, ap); + va_end(ap); + + if (ret == -1) { + return ESL_FAIL; + } + + return esl_event_base_add_header(event, stack, header_name, data); +} + +ESL_DECLARE(esl_status_t) esl_event_add_header_string(esl_event_t *event, esl_stack_t stack, const char *header_name, const char *data) +{ + if (data) { + return esl_event_base_add_header(event, stack, header_name, DUP(data)); + } + return ESL_FAIL; +} + +ESL_DECLARE(esl_status_t) esl_event_add_body(esl_event_t *event, const char *fmt, ...) +{ + int ret = 0; + char *data; + + va_list ap; + if (fmt) { + va_start(ap, fmt); + ret = esl_vasprintf(&data, fmt, ap); + va_end(ap); + + if (ret == -1) { + return ESL_FAIL; + } else { + esl_safe_free(event->body); + event->body = data; + return ESL_SUCCESS; + } + } else { + return ESL_FAIL; + } +} + +ESL_DECLARE(void) esl_event_destroy(esl_event_t **event) +{ + esl_event_t *ep = *event, *this_event; + esl_event_header_t *hp, *this_header; + + for (ep = *event ; ep ;) { + this_event = ep; + ep = ep->next; + + for (hp = this_event->headers; hp;) { + this_header = hp; + hp = hp->next; + FREE(this_header->name); + FREE(this_header->value); + memset(this_header, 0, sizeof(*this_header)); + FREE(this_header); + } + FREE(this_event->body); + FREE(this_event->subclass_name); + memset(this_event, 0, sizeof(*this_event)); + FREE(this_event); + } + *event = NULL; +} + + + +ESL_DECLARE(esl_status_t) esl_event_dup(esl_event_t **event, esl_event_t *todup) +{ + esl_event_header_t *hp; + + if (esl_event_create_subclass(event, ESL_EVENT_CLONE, todup->subclass_name) != ESL_SUCCESS) { + return ESL_FAIL; + } + + (*event)->event_id = todup->event_id; + + (*event)->event_user_data = todup->event_user_data; + (*event)->bind_user_data = todup->bind_user_data; + + for (hp = todup->headers; hp; hp = hp->next) { + esl_event_add_header_string(*event, ESL_STACK_BOTTOM, hp->name, hp->value); + } + + if (todup->body) { + (*event)->body = DUP(todup->body); + } + + (*event)->key = todup->key; + + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, esl_bool_t encode) +{ + size_t len = 0; + esl_event_header_t *hp; + size_t llen = 0, dlen = 0, blocksize = 512, encode_len = 1536, new_len = 0; + char *buf; + char *encode_buf = NULL; /* used for url encoding of variables to make sure unsafe things stay out of the serialized copy */ + + *str = NULL; + + dlen = blocksize * 2; + + if (!(buf = malloc(dlen))) { + return ESL_FAIL; + } + + /* go ahead and give ourselves some space to work with, should save a few reallocs */ + if (!(encode_buf = malloc(encode_len))) { + esl_safe_free(buf); + return ESL_FAIL; + } + + /* esl_log_printf(ESL_CHANNEL_LOG, ESL_LOG_INFO, "hit serialized!.\n"); */ + for (hp = event->headers; hp; hp = hp->next) { + /* + * grab enough memory to store 3x the string (url encode takes one char and turns it into %XX) + * so we could end up with a string that is 3 times the originals length, unlikely but rather + * be safe than destroy the string, also add one for the null. And try to be smart about using + * the memory, allocate and only reallocate if we need more. This avoids an alloc, free CPU + * destroying loop. + */ + + + new_len = (strlen(hp->value) * 3) + 1; + + if (encode_len < new_len) { + char *tmp; + /* esl_log_printf(ESL_CHANNEL_LOG, ESL_LOG_INFO, "Allocing %d was %d.\n", ((strlen(hp->value) * 3) + 1), encode_len); */ + /* we can use realloc for initial alloc as well, if encode_buf is zero it treats it as a malloc */ + + /* keep track of the size of our allocation */ + encode_len = new_len; + + if (!(tmp = realloc(encode_buf, encode_len))) { + /* oh boy, ram's gone, give back what little we grabbed and bail */ + esl_safe_free(buf); + esl_safe_free(encode_buf); + return ESL_FAIL; + } + + encode_buf = tmp; + } + + /* handle any bad things in the string like newlines : etc that screw up the serialized format */ + if (encode) { + esl_url_encode(hp->value, encode_buf, encode_len); + } else { + esl_snprintf(encode_buf, encode_len, "%s", hp->value); + } + + llen = strlen(hp->name) + strlen(encode_buf) + 8; + + if ((len + llen) > dlen) { + char *m; + dlen += (blocksize + (len + llen)); + if ((m = realloc(buf, dlen))) { + buf = m; + } else { + /* we seem to be out of memory trying to resize the serialize string, give back what we already have and give up */ + esl_safe_free(buf); + esl_safe_free(encode_buf); + return ESL_FAIL; + } + } + + snprintf(buf + len, dlen - len, "%s: %s\n", hp->name, *encode_buf == '\0' ? "_undef_" : encode_buf); + len = strlen(buf); + } + + /* we are done with the memory we used for encoding, give it back */ + esl_safe_free(encode_buf); + + if (event->body) { + int blen = (int) strlen(event->body); + llen = blen; + + if (blen) { + llen += 25; + } else { + llen += 5; + } + + if ((len + llen) > dlen) { + char *m; + dlen += (blocksize + (len + llen)); + if ((m = realloc(buf, dlen))) { + buf = m; + } else { + esl_safe_free(buf); + return ESL_FAIL; + } + } + + if (blen) { + snprintf(buf + len, dlen - len, "\n%s", event->body); + } else { + snprintf(buf + len, dlen - len, "\n"); + } + } else { + snprintf(buf + len, dlen - len, "\n"); + } + + + *str = buf; + + return ESL_SUCCESS; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/esl_event.h b/src/libesl/esl_event.h similarity index 99% rename from src/esl_event.h rename to src/libesl/esl_event.h index d9e7a3e4..cfc93104 100644 --- a/src/esl_event.h +++ b/src/libesl/esl_event.h @@ -109,6 +109,8 @@ typedef enum { ESL_EVENT_SESSION_HEARTBEAT, ESL_EVENT_CLIENT_DISCONNECTED, ESL_EVENT_SERVER_DISCONNECTED, + ESL_EVENT_SEND_INFO, + ESL_EVENT_RECV_INFO, ESL_EVENT_ALL } esl_event_types_t; diff --git a/src/libesl/esl_oop.cpp b/src/libesl/esl_oop.cpp new file mode 100644 index 00000000..e7168938 --- /dev/null +++ b/src/libesl/esl_oop.cpp @@ -0,0 +1,427 @@ +#include +#include + +#define connection_construct_common() memset(&handle, 0, sizeof(handle)); last_event_obj = NULL +#define event_construct_common() event = NULL; serialized_string = NULL; mine = 0; hp = NULL + +void eslSetLogLevel(int level) +{ + esl_global_set_default_logger(level); +} + +ESLconnection::ESLconnection(const char *host, const char *port, const char *password) +{ + connection_construct_common(); + int x_port = atoi(port); + + esl_connect(&handle, host, x_port, password); +} + + +ESLconnection::ESLconnection(int socket) +{ + connection_construct_common(); + memset(&handle, 0, sizeof(handle)); + esl_attach_handle(&handle, (esl_socket_t)socket, NULL); +} + +ESLconnection::~ESLconnection() +{ + if (handle.connected) { + esl_disconnect(&handle); + } + +} + +int ESLconnection::disconnect() +{ + if (handle.connected) { + return esl_disconnect(&handle); + } + + return 0; +} + +int ESLconnection::connected() +{ + return handle.connected; +} + +int ESLconnection::send(const char *cmd) +{ + return esl_send(&handle, cmd); +} + +ESLevent *ESLconnection::sendRecv(const char *cmd) +{ + if (esl_send_recv(&handle, cmd) == ESL_SUCCESS) { + esl_event_t *event; + esl_event_dup(&event, handle.last_sr_event); + return new ESLevent(event, 1); + } + + return NULL; +} + +ESLevent *ESLconnection::api(const char *cmd, const char *arg) +{ + size_t len; + char *cmd_buf; + + if (!cmd) { + return NULL; + } + + len = strlen(cmd) + (arg ? strlen(arg) : 0) + 10; + + cmd_buf = (char *) malloc(len + 1); + assert(cmd_buf); + + snprintf(cmd_buf, len, "api %s %s", cmd, arg ? arg : ""); + *(cmd_buf + (len)) = '\0'; + + + if (esl_send_recv(&handle, cmd_buf) == ESL_SUCCESS) { + esl_event_t *event; + esl_event_dup(&event, handle.last_sr_event); + return new ESLevent(event, 1); + } + + free(cmd_buf); + + return NULL; +} + +ESLevent *ESLconnection::bgapi(const char *cmd, const char *arg) +{ + size_t len; + char *cmd_buf; + + if (!cmd) { + return NULL; + } + + len = strlen(cmd) + (arg ? strlen(arg) : 0) + 10; + + cmd_buf = (char *) malloc(len + 1); + assert(cmd_buf); + + snprintf(cmd_buf, len, "bgapi %s %s", cmd, arg ? arg : ""); + *(cmd_buf + (len)) = '\0'; + + if (esl_send_recv(&handle, cmd_buf) == ESL_SUCCESS) { + esl_event_t *event; + esl_event_dup(&event, handle.last_sr_event); + return new ESLevent(event, 1); + } + + free(cmd_buf); + + return NULL; +} + +ESLevent *ESLconnection::getInfo() +{ + if (handle.connected && handle.info_event) { + esl_event_t *event; + esl_event_dup(&event, handle.info_event); + return new ESLevent(event, 1); + } + + return NULL; +} + +int ESLconnection::setAsyncExecute(const char *val) +{ + if (val) { + handle.async_execute = esl_true(val); + } + return handle.async_execute; +} + +int ESLconnection::setEventLock(const char *val) +{ + if (val) { + handle.event_lock = esl_true(val); + } + return handle.event_lock; +} + +int ESLconnection::execute(const char *app, const char *arg, const char *uuid) +{ + return esl_execute(&handle, app, arg, uuid); +} + + +int ESLconnection::executeAsync(const char *app, const char *arg, const char *uuid) +{ + int async = handle.async_execute; + int r; + + handle.async_execute = 1; + r = esl_execute(&handle, app, arg, uuid); + handle.async_execute = async; + + return r; +} + +int ESLconnection::sendEvent(ESLevent *send_me) +{ + return esl_sendevent(&handle, send_me->event); +} + +ESLevent *ESLconnection::recvEvent() +{ + if (last_event_obj) { + delete last_event_obj; + } + + 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; + esl_event_dup(&event, e); + last_event_obj = new ESLevent(event, 1); + return last_event_obj; + } + } + + last_event_obj = new ESLevent("server_disconnected"); + + return last_event_obj; +} + +ESLevent *ESLconnection::recvEventTimed(int ms) +{ + if (last_event_obj) { + delete last_event_obj; + last_event_obj = NULL; + } + + 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; + esl_event_dup(&event, e); + last_event_obj = new ESLevent(event, 1); + return last_event_obj; + } + } + + return NULL; +} + +ESLevent *ESLconnection::filter(const char *header, const char *value) +{ + esl_status_t status = esl_filter(&handle, header, value); + + if (status == ESL_SUCCESS && handle.last_sr_event) { + esl_event_t *event; + esl_event_dup(&event, handle.last_sr_event); + return new ESLevent(event, 1); + } + + return NULL; + +} + +int ESLconnection::events(const char *etype, const char *value) +{ + esl_event_type_t type_id = ESL_EVENT_TYPE_PLAIN; + + if (!strcmp(etype, "xml")) { + type_id = ESL_EVENT_TYPE_XML; + } + + return esl_events(&handle, type_id, value); +} + +// ESLevent +/////////////////////////////////////////////////////////////////////// + +ESLevent::ESLevent(const char *type, const char *subclass_name) +{ + esl_event_types_t event_id; + + event_construct_common(); + + if (esl_name_event(type, &event_id) != ESL_SUCCESS) { + event_id = ESL_EVENT_MESSAGE; + } + + if (!esl_strlen_zero(subclass_name) && event_id != ESL_EVENT_CUSTOM) { + esl_log(ESL_LOG_WARNING, "Changing event type to custom because you specified a subclass name!\n"); + event_id = ESL_EVENT_CUSTOM; + } + + if (esl_event_create_subclass(&event, event_id, subclass_name) != ESL_SUCCESS) { + esl_log(ESL_LOG_ERROR, "Failed to create event!\n"); + event = NULL; + } + + serialized_string = NULL; + mine = 1; +} + +ESLevent::ESLevent(esl_event_t *wrap_me, int free_me) +{ + event_construct_common(); + event = wrap_me; + mine = free_me; + serialized_string = NULL; +} + + +ESLevent::ESLevent(ESLevent *me) +{ + /* workaround for silly php thing */ + event = me->event; + mine = me->mine; + serialized_string = NULL; + me->event = NULL; + me->mine = 0; + esl_safe_free(me->serialized_string); +} + +ESLevent::~ESLevent() +{ + + if (serialized_string) { + free(serialized_string); + } + + if (event && mine) { + esl_event_destroy(&event); + } +} + +const char *ESLevent::nextHeader(void) +{ + const char *name = NULL; + + if (hp) { + name = hp->name; + hp = hp->next; + } + + return name; +} + +const char *ESLevent::firstHeader(void) +{ + if (event) { + hp = event->headers; + } + + return nextHeader(); +} + +const char *ESLevent::serialize(const char *format) +{ + this_check(""); + + esl_safe_free(serialized_string); + + if (!event) { + return ""; + } + + if (esl_event_serialize(event, &serialized_string, ESL_TRUE) == ESL_SUCCESS) { + return serialized_string; + } + + return ""; + +} + +bool ESLevent::setPriority(esl_priority_t priority) +{ + this_check(false); + + if (event) { + esl_event_set_priority(event, priority); + return true; + } else { + esl_log(ESL_LOG_ERROR, "Trying to setPriority an event that does not exist!\n"); + } + return false; +} + +const char *ESLevent::getHeader(const char *header_name) +{ + this_check(""); + + if (event) { + return esl_event_get_header(event, header_name); + } else { + esl_log(ESL_LOG_ERROR, "Trying to getHeader an event that does not exist!\n"); + } + return NULL; +} + +bool ESLevent::addHeader(const char *header_name, const char *value) +{ + this_check(false); + + if (event) { + return esl_event_add_header_string(event, ESL_STACK_BOTTOM, header_name, value) == ESL_SUCCESS ? true : false; + } else { + esl_log(ESL_LOG_ERROR, "Trying to addHeader an event that does not exist!\n"); + } + + return false; +} + +bool ESLevent::delHeader(const char *header_name) +{ + this_check(false); + + if (event) { + return esl_event_del_header(event, header_name) == ESL_SUCCESS ? true : false; + } else { + esl_log(ESL_LOG_ERROR, "Trying to delHeader an event that does not exist!\n"); + } + + return false; +} + + +bool ESLevent::addBody(const char *value) +{ + this_check(false); + + if (event) { + return esl_event_add_body(event, "%s", value) == ESL_SUCCESS ? true : false; + } else { + esl_log(ESL_LOG_ERROR, "Trying to addBody an event that does not exist!\n"); + } + + return false; +} + +char *ESLevent::getBody(void) +{ + + this_check((char *)""); + + if (event) { + return esl_event_get_body(event); + } else { + esl_log(ESL_LOG_ERROR, "Trying to getBody an event that does not exist!\n"); + } + + return NULL; +} + +const char *ESLevent::getType(void) +{ + this_check(""); + + if (event) { + return esl_event_name(event->event_id); + } else { + esl_log(ESL_LOG_ERROR, "Trying to getType an event that does not exist!\n"); + } + + return (char *) "invalid"; +} diff --git a/src/esl_oop.h b/src/libesl/esl_oop.h similarity index 100% rename from src/esl_oop.h rename to src/libesl/esl_oop.h diff --git a/src/libesl/esl_threadmutex.c b/src/libesl/esl_threadmutex.c new file mode 100644 index 00000000..2aed18ad --- /dev/null +++ b/src/libesl/esl_threadmutex.c @@ -0,0 +1,237 @@ +/* + * Cross Platform Thread/Mutex abstraction + * Copyright(C) 2007 Michael Jerris + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so. + * + * This work is provided under this license on an "as is" basis, without warranty of any kind, + * either expressed or implied, including, without limitation, warranties that the covered code + * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire + * risk as to the quality and performance of the covered code is with you. Should any covered + * code prove defective in any respect, you (not the initial developer or any other contributor) + * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty + * constitutes an essential part of this license. No use of any covered code is authorized hereunder + * except under this disclaimer. + * + */ + +#ifdef WIN32 +/* required for TryEnterCriticalSection definition. Must be defined before windows.h include */ +#define _WIN32_WINNT 0x0400 +#endif + +#include "esl.h" +#include "esl_threadmutex.h" + +#ifdef WIN32 +#include + +#define ESL_THREAD_CALLING_CONVENTION __stdcall + +struct esl_mutex { + CRITICAL_SECTION mutex; +}; + +#else + +#include + +#define ESL_THREAD_CALLING_CONVENTION + +struct esl_mutex { + pthread_mutex_t mutex; +}; + +#endif + +struct esl_thread { +#ifdef WIN32 + void *handle; +#else + pthread_t handle; +#endif + void *private_data; + esl_thread_function_t function; + size_t stack_size; +#ifndef WIN32 + pthread_attr_t attribute; +#endif +}; + +size_t thread_default_stacksize = 0; + +void esl_thread_override_default_stacksize(size_t size) +{ + thread_default_stacksize = size; +} + +static void * ESL_THREAD_CALLING_CONVENTION thread_launch(void *args) +{ + void *exit_val; + esl_thread_t *thread = (esl_thread_t *)args; + exit_val = thread->function(thread, thread->private_data); +#ifndef WIN32 + pthread_attr_destroy(&thread->attribute); +#endif + free(thread); + + return exit_val; +} + +ESL_DECLARE(esl_status_t) esl_thread_create_detached(esl_thread_function_t func, void *data) +{ + return esl_thread_create_detached_ex(func, data, thread_default_stacksize); +} + +esl_status_t esl_thread_create_detached_ex(esl_thread_function_t func, void *data, size_t stack_size) +{ + esl_thread_t *thread = NULL; + esl_status_t status = ESL_FAIL; + + if (!func || !(thread = (esl_thread_t *)malloc(sizeof(esl_thread_t)))) { + goto done; + } + + thread->private_data = data; + thread->function = func; + thread->stack_size = stack_size; + +#if defined(WIN32) + thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL); + if (!thread->handle) { + goto fail; + } + CloseHandle(thread->handle); + + status = ESL_SUCCESS; + goto done; +#else + + if (pthread_attr_init(&thread->attribute) != 0) goto fail; + + if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread; + + if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread; + + if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread; + + status = ESL_SUCCESS; + goto done; + failpthread: + pthread_attr_destroy(&thread->attribute); +#endif + + fail: + if (thread) { + free(thread); + } + done: + return status; +} + + +ESL_DECLARE(esl_status_t) esl_mutex_create(esl_mutex_t **mutex) +{ + esl_status_t status = ESL_FAIL; +#ifndef WIN32 + pthread_mutexattr_t attr; +#endif + esl_mutex_t *check = NULL; + + check = (esl_mutex_t *)malloc(sizeof(**mutex)); + if (!check) + goto done; +#ifdef WIN32 + InitializeCriticalSection(&check->mutex); +#else + if (pthread_mutexattr_init(&attr)) + goto done; + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) + goto fail; + + if (pthread_mutex_init(&check->mutex, &attr)) + goto fail; + + goto success; + + fail: + pthread_mutexattr_destroy(&attr); + goto done; + + success: +#endif + *mutex = check; + status = ESL_SUCCESS; + + done: + return status; +} + +ESL_DECLARE(esl_status_t) esl_mutex_destroy(esl_mutex_t **mutex) +{ + esl_mutex_t *mp = *mutex; + *mutex = NULL; + if (!mp) { + return ESL_FAIL; + } +#ifdef WIN32 + DeleteCriticalSection(&mp->mutex); +#else + if (pthread_mutex_destroy(&mp->mutex)) + return ESL_FAIL; +#endif + free(mp); + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_mutex_lock(esl_mutex_t *mutex) +{ +#ifdef WIN32 + EnterCriticalSection(&mutex->mutex); +#else + if (pthread_mutex_lock(&mutex->mutex)) + return ESL_FAIL; +#endif + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_mutex_trylock(esl_mutex_t *mutex) +{ +#ifdef WIN32 + if (!TryEnterCriticalSection(&mutex->mutex)) + return ESL_FAIL; +#else + if (pthread_mutex_trylock(&mutex->mutex)) + return ESL_FAIL; +#endif + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_mutex_unlock(esl_mutex_t *mutex) +{ +#ifdef WIN32 + LeaveCriticalSection(&mutex->mutex); +#else + if (pthread_mutex_unlock(&mutex->mutex)) + return ESL_FAIL; +#endif + return ESL_SUCCESS; +} + + + + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */ diff --git a/src/esl_threadmutex.h b/src/libesl/esl_threadmutex.h similarity index 100% rename from src/esl_threadmutex.h rename to src/libesl/esl_threadmutex.h -- 2.11.0