123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638 |
- /*
- * Copyright (c) 2007-2014, 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.
- */
- /* Use select on windows and poll everywhere else.
- Select is the devil. Especially if you are doing a lot of small socket connections.
- If your FD number is bigger than 1024 you will silently create memory corruption.
- If you have build errors on your platform because you don't have poll find a way to detect it and #define ESL_USE_SELECT and #undef ESL_USE_POLL
- All of this will be upgraded to autoheadache eventually.
- */
- /* TBD for win32 figure out how to tell if you have WSAPoll (vista or higher) and use it when available by #defining ESL_USE_WSAPOLL (see below) */
- #ifdef _MSC_VER
- #define FD_SETSIZE 8192
- #define ESL_USE_SELECT
- #else
- #define ESL_USE_POLL
- #endif
- #include <esl.h>
- #ifndef WIN32
- #define closesocket(x) shutdown(x, 2); close(x)
- #include <fcntl.h>
- #include <errno.h>
- #else
- #pragma warning (disable:6386)
- /* These warnings need to be ignored warning in sdk header */
- #include <Ws2tcpip.h>
- #include <windows.h>
- #include <errno.h>
- #ifndef errno
- #define errno WSAGetLastError()
- #endif
- #ifndef EINTR
- #define EINTR WSAEINTR
- #endif
- #pragma warning (default:6386)
- #endif
- #ifdef ESL_USE_POLL
- #include <poll.h>
- #endif
- #ifndef ESL_MIN
- #define ESL_MIN(x,y) ((x) < (y) ? (x) : (y))
- #endif
- #ifndef ESL_MAX
- #define ESL_MAX(x,y) ((x) > (y) ? (x) : (y))
- #endif
- #ifndef ESL_CLAMP
- #define ESL_CLAMP(min,max,val) (ESL_MIN(max,ESL_MAX(val,min)))
- #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], fp, 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 int sock_setup(esl_handle_t *handle)
- {
- if (handle->sock == ESL_SOCK_INVALID) {
- return ESL_FAIL;
- }
- #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
- return ESL_SUCCESS;
- }
- ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t socket, struct sockaddr_in *addr)
- {
- if (!handle || socket == ESL_SOCK_INVALID) {
- return ESL_FAIL;
- }
- handle->sock = socket;
- if (addr) {
- handle->addr = *addr;
- }
- if (sock_setup(handle) != ESL_SUCCESS) {
- return ESL_FAIL;
- }
- if (!handle->mutex) {
- 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");
-
- if (handle->last_sr_event) {
- handle->info_event = handle->last_sr_event;
- handle->last_sr_event = NULL;
- return ESL_SUCCESS;
- }
-
- esl_disconnect(handle);
-
- return ESL_FAIL;
- }
- ESL_DECLARE(esl_status_t) esl_sendevent(esl_handle_t *handle, esl_event_t *event)
- {
- char *txt;
- char *event_buf = NULL;
- esl_status_t status = ESL_FAIL;
- size_t len = 0;
- 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);
-
- len = strlen(txt) + 100;
- event_buf = malloc(len);
- assert(event_buf);
- if (!event_buf) {
- return ESL_FAIL;
- }
- memset(event_buf, 0, len);
-
- snprintf(event_buf, len, "sendevent %s\n%s", esl_event_name(event->event_id), txt);
-
- status = esl_send_recv(handle, event_buf);
- free(txt);
- free(event_buf);
- return status;
- }
- 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[4096] = "";
- const char *el_buf = "event-lock: true\n";
- const char *bl_buf = "async: true\n";
- char send_buf[5120] = "";
-
- if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
- 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_sendmsg(esl_handle_t *handle, esl_event_t *event, const char *uuid)
- {
- char *cmd_buf = NULL;
- char *txt;
- size_t len = 0;
- esl_status_t status = ESL_FAIL;
- if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
- return ESL_FAIL;
- }
- esl_event_serialize(event, &txt, ESL_FALSE);
- len = strlen(txt) + 100;
- cmd_buf = malloc(len);
- assert(cmd_buf);
- if (!cmd_buf) {
- return ESL_FAIL;
- }
- memset(cmd_buf, 0, len);
- if (uuid) {
- snprintf(cmd_buf, len, "sendmsg %s\n%s", uuid, txt);
- } else {
- snprintf(cmd_buf, len, "sendmsg\n%s", txt);
- }
-
- esl_log(ESL_LOG_DEBUG, "%s%s\n", cmd_buf, txt);
- status = esl_send_recv(handle, cmd_buf);
- free(txt);
- free(cmd_buf);
- return status;
- }
- ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value)
- {
- char send_buf[1024] = "";
-
- if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
- 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 || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
- return ESL_FAIL;
- }
- if (etype == ESL_EVENT_TYPE_XML) {
- type = "xml";
- } else if (etype == ESL_EVENT_TYPE_JSON) {
- type = "json";
- }
- 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
- }
- struct thread_handler {
- esl_listen_callback_t callback;
- esl_socket_t server_sock;
- esl_socket_t client_sock;
- struct sockaddr_in addr;
- void *user_data;
- };
- static void *client_thread(esl_thread_t *me, void *obj)
- {
- struct thread_handler *handler = (struct thread_handler *) obj;
- handler->callback(handler->server_sock, handler->client_sock, &handler->addr, handler->user_data);
- free(handler);
- return NULL;
- }
- static int prepare_sock(esl_socket_t sock)
- {
- int r = 0;
- #ifdef WIN32
- u_long arg = 1;
- if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR) {
- r = -1;
- }
- #else
- int fd_flags = fcntl(sock, F_GETFL, 0);
- if (fcntl(sock, F_SETFL, fd_flags | O_NONBLOCK)) {
- r = -1;
- }
- #endif
- return r;
-
- }
- ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback, void *user_data, esl_socket_t *server_sockP)
- {
- 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;
- }
- if (server_sockP) {
- *server_sockP = server_sock;
- }
-
- 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 && errno != EINTR) {
- status = ESL_FAIL;
- goto end;
- }
- prepare_sock(client_sock);
- callback(server_sock, client_sock, &echoClntAddr, user_data);
- }
- end:
- if (server_sock != ESL_SOCK_INVALID) {
- closesocket(server_sock);
- }
- return status;
- }
- ESL_DECLARE(esl_status_t) esl_listen_threaded(const char *host, esl_port_t port, esl_listen_callback_t callback, void *user_data, int max)
- {
- esl_socket_t server_sock = ESL_SOCK_INVALID;
- struct sockaddr_in addr;
- esl_status_t status = ESL_SUCCESS;
- struct thread_handler *handler = NULL;
- 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, max) < 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 && errno != EINTR) {
- status = ESL_FAIL;
- goto end;
- }
-
- prepare_sock(client_sock);
- handler = malloc(sizeof(*handler));
- esl_assert(handler);
- memset(handler, 0, sizeof(*handler));
- handler->callback = callback;
- handler->server_sock = server_sock;
- handler->client_sock = client_sock;
- handler->addr = echoClntAddr;
- handler->user_data = user_data;
- esl_thread_create_detached(client_thread, handler);
- }
- end:
- if (server_sock != ESL_SOCK_INVALID) {
- closesocket(server_sock);
- }
- return status;
- }
- /* USE WSAPoll on vista or higher */
- #ifdef ESL_USE_WSAPOLL
- ESL_DECLARE(int) esl_wait_sock(esl_socket_t sock, uint32_t ms, esl_poll_t flags)
- {
- }
- #endif
- #ifdef ESL_USE_SELECT
- #ifdef WIN32
- #pragma warning( push )
- #pragma warning( disable : 6262 ) /* warning C6262: Function uses '98348' bytes of stack: exceeds /analyze:stacksize'16384'. Consider moving some data to heap */
- #endif
- ESL_DECLARE(int) esl_wait_sock(esl_socket_t sock, uint32_t ms, esl_poll_t flags)
- {
- int s = 0, r = 0;
- fd_set rfds;
- fd_set wfds;
- fd_set efds;
- struct timeval tv;
- if (sock == ESL_SOCK_INVALID) {
- return ESL_SOCK_INVALID;
- }
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&efds);
- #ifndef WIN32
- /* Wouldn't you rather know?? */
- assert(sock <= FD_SETSIZE);
- #endif
-
- if ((flags & ESL_POLL_READ)) {
- #ifdef WIN32
- #pragma warning( push )
- #pragma warning( disable : 4127 )
- FD_SET(sock, &rfds);
- #pragma warning( pop )
- #else
- FD_SET(sock, &rfds);
- #endif
- }
- if ((flags & ESL_POLL_WRITE)) {
- #ifdef WIN32
- #pragma warning( push )
- #pragma warning( disable : 4127 )
- FD_SET(sock, &wfds);
- #pragma warning( pop )
- #else
- FD_SET(sock, &wfds);
- #endif
- }
- if ((flags & ESL_POLL_ERROR)) {
- #ifdef WIN32
- #pragma warning( push )
- #pragma warning( disable : 4127 )
- FD_SET(sock, &efds);
- #pragma warning( pop )
- #else
- FD_SET(sock, &efds);
- #endif
- }
- tv.tv_sec = ms / 1000;
- tv.tv_usec = (ms % 1000) * ms;
-
- s = select(sock + 1, (flags & ESL_POLL_READ) ? &rfds : NULL, (flags & ESL_POLL_WRITE) ? &wfds : NULL, (flags & ESL_POLL_ERROR) ? &efds : NULL, &tv);
- if (s < 0) {
- r = s;
- } else if (s > 0) {
- if ((flags & ESL_POLL_READ) && FD_ISSET(sock, &rfds)) {
- r |= ESL_POLL_READ;
- }
- if ((flags & ESL_POLL_WRITE) && FD_ISSET(sock, &wfds)) {
- r |= ESL_POLL_WRITE;
- }
- if ((flags & ESL_POLL_ERROR) && FD_ISSET(sock, &efds)) {
- r |= ESL_POLL_ERROR;
- }
- }
- return r;
- }
- #ifdef WIN32
- #pragma warning( pop )
- #endif
- #endif
- #ifdef ESL_USE_POLL
- ESL_DECLARE(int) esl_wait_sock(esl_socket_t sock, uint32_t ms, esl_poll_t flags)
- {
- struct pollfd pfds[2] = { { 0 } };
- int s = 0, r = 0;
- if (sock == ESL_SOCK_INVALID) {
- return ESL_SOCK_INVALID;
- }
- pfds[0].fd = sock;
- if ((flags & ESL_POLL_READ)) {
- pfds[0].events |= POLLIN;
- }
- if ((flags & ESL_POLL_WRITE)) {
- pfds[0].events |= POLLOUT;
- }
- if ((flags & ESL_POLL_ERROR)) {
- pfds[0].events |= POLLERR;
- }
-
- s = poll(pfds, 1, ms);
- if (s < 0) {
- r = s;
- } else if (s > 0) {
- if ((pfds[0].revents & POLLIN)) {
- r |= ESL_POLL_READ;
- }
- if ((pfds[0].revents & POLLOUT)) {
- r |= ESL_POLL_WRITE;
- }
- if ((pfds[0].revents & POLLERR)) {
- r |= ESL_POLL_ERROR;
- }
- }
- return r;
- }
- #endif
- ESL_DECLARE(esl_status_t) esl_connect_timeout(esl_handle_t *handle, const char *host, esl_port_t port, const char *user, const char *password, uint32_t timeout)
- {
- char sendbuf[256];
- int rval = 0;
- const char *hval;
- struct addrinfo hints = { 0 }, *result;
- struct sockaddr_in *sockaddr_in;
- struct sockaddr_in6 *sockaddr_in6;
- socklen_t socklen;
- #ifndef WIN32
- int fd_flags = 0;
- #else
- WORD wVersionRequested = MAKEWORD(2, 0);
- WSADATA wsaData;
- int err = WSAStartup(wVersionRequested, &wsaData);
- if (err != 0) {
- snprintf(handle->err, sizeof(handle->err), "WSAStartup Error");
- goto fail;
- }
- #endif
- if (!handle->mutex) {
- esl_mutex_create(&handle->mutex);
- }
- if (!handle->packet_buf) {
- esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0);
- }
- hints.ai_socktype = SOCK_STREAM;
- if (getaddrinfo(host, NULL, &hints, &result)) {
- strncpy(handle->err, "Cannot resolve host", sizeof(handle->err));
- goto fail;
- }
- memcpy(&handle->sockaddr, result->ai_addr, result->ai_addrlen);
- switch(handle->sockaddr.ss_family) {
- case AF_INET:
- sockaddr_in = (struct sockaddr_in*)&(handle->sockaddr);
- sockaddr_in->sin_port = htons(port);
- socklen = sizeof(struct sockaddr_in);
- break;
- case AF_INET6:
- sockaddr_in6 = (struct sockaddr_in6*)&(handle->sockaddr);
- sockaddr_in6->sin6_port = htons(port);
- socklen = sizeof(struct sockaddr_in6);
- break;
- default:
- strncpy(handle->err, "Host resolves to unsupported address family", sizeof(handle->err));
- goto fail;
- }
- freeaddrinfo(result);
-
- handle->sock = socket(handle->sockaddr.ss_family, SOCK_STREAM, IPPROTO_TCP);
-
- if (handle->sock == ESL_SOCK_INVALID) {
- snprintf(handle->err, sizeof(handle->err), "Socket Error");
- goto fail;
- }
- if (timeout) {
- #ifdef WIN32
- u_long arg = 1;
- if (ioctlsocket(handle->sock, FIONBIO, &arg) == SOCKET_ERROR) {
- snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
- goto fail;
- }
- #else
- fd_flags = fcntl(handle->sock, F_GETFL, 0);
- if (fcntl(handle->sock, F_SETFL, fd_flags | O_NONBLOCK)) {
- snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
- goto fail;
- }
- #endif
- }
- rval = connect(handle->sock, (struct sockaddr*)&handle->sockaddr, socklen);
-
- if (timeout) {
- int r;
- r = esl_wait_sock(handle->sock, timeout, ESL_POLL_WRITE);
-
- if (r <= 0) {
- snprintf(handle->err, sizeof(handle->err), "Connection timed out");
- goto fail;
- }
- if (!(r & ESL_POLL_WRITE)) {
- snprintf(handle->err, sizeof(handle->err), "Connection timed out");
- goto fail;
- }
- #ifdef WIN32
- {
- u_long arg = 0;
- if (ioctlsocket(handle->sock, FIONBIO, &arg) == SOCKET_ERROR) {
- snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
- goto fail;
- }
- }
- #else
- fcntl(handle->sock, F_SETFL, fd_flags);
- #endif
- rval = 0;
- }
-
- result = NULL;
-
- if (rval) {
- snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
- goto fail;
- }
- sock_setup(handle);
- handle->connected = 1;
- if (esl_recv_timed(handle, timeout)) {
- 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;
- }
- if (esl_strlen_zero(user)) {
- snprintf(sendbuf, sizeof(sendbuf), "auth %s\n\n", password);
- } else {
- snprintf(sendbuf, sizeof(sendbuf), "userauth %s:%s\n\n", user, password);
- }
- esl_send(handle, sendbuf);
-
- if (esl_recv_timed(handle, timeout)) {
- 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:
- handle->connected = 0;
- 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;
- esl_event_t *ep;
- if (handle->destroyed) {
- return ESL_FAIL;
- }
- if (handle->sock != ESL_SOCK_INVALID) {
- closesocket(handle->sock);
- handle->sock = ESL_SOCK_INVALID;
- status = ESL_SUCCESS;
- }
- if (mutex) {
- esl_mutex_lock(mutex);
- }
- handle->connected = 0;
- ep = handle->race_event;
- while(ep) {
- esl_event_t *e = ep;
- ep = ep->next;
- if (e) {
- esl_event_destroy(&e);
- }
- }
- 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 (mutex) {
- esl_mutex_unlock(mutex);
- esl_mutex_lock(mutex);
- esl_mutex_unlock(mutex);
- esl_mutex_destroy(&mutex);
- }
-
- if (handle->packet_buf) {
- esl_buffer_destroy(&handle->packet_buf);
- }
- memset(handle, 0, sizeof(*handle));
- handle->destroyed = 1;
- 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)
- {
- int activity;
- esl_status_t status = ESL_SUCCESS;
-
- if (!ms) {
- return esl_recv_event(handle, check_q, save_event);
- }
- if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
- return ESL_FAIL;
- }
- if (check_q) {
- esl_mutex_lock(handle->mutex);
- 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);
- }
- esl_mutex_unlock(handle->mutex);
- }
- if (handle->packet_buf && esl_buffer_inuse(handle->packet_buf)) {
- activity = ESL_POLL_READ;
- } else {
- activity = esl_wait_sock(handle->sock, ms, ESL_POLL_READ|ESL_POLL_ERROR);
- }
-
- if (activity < 0) {
- handle->connected = 0;
- return ESL_FAIL;
- }
- if (activity == 0 || !(activity & ESL_POLL_READ) || (esl_mutex_trylock(handle->mutex) != ESL_SUCCESS)) {
- return ESL_BREAK;
- }
- if (activity < 0) {
- handle->connected = 0;
- status = ESL_FAIL;
- } else if (activity > 0 && (activity & ESL_POLL_READ)) {
- 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;
- }
- static esl_ssize_t handle_recv(esl_handle_t *handle, void *data, esl_size_t datalen)
- {
- esl_ssize_t activity = -1;
-
- if (handle->connected) {
- if ((activity = esl_wait_sock(handle->sock, 1000, ESL_POLL_READ|ESL_POLL_ERROR)) > 0) {
- if (activity < 0) {
- activity = -1;
- } else if ((activity & ESL_POLL_ERROR)) {
- activity = -1;
- } else if ((activity & ESL_POLL_READ)) {
- if (!(activity = recv(handle->sock, data, datalen, 0))) {
- activity = -1;
- } else if (activity < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
- activity = 0;
- }
- }
- }
- }
- return activity;
- }
- 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;
- esl_event_t *revent = NULL;
- char *beg;
- char *hname, *hval;
- char *col;
- char *cl;
- esl_ssize_t len;
- if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
- return ESL_FAIL;
- }
- esl_mutex_lock(handle->mutex);
- if (!handle->connected || handle->sock == ESL_SOCK_INVALID) {
- goto fail;
- }
- esl_event_safe_destroy(&handle->last_ievent);
-
- if (check_q && handle->race_event) {
- revent = handle->race_event;
- handle->race_event = handle->race_event->next;
- revent->next = NULL;
- goto parse_event;
- }
- while(!revent && handle->connected) {
- esl_size_t len1;
-
- if ((len1 = esl_buffer_read_packet(handle->packet_buf, handle->socket_buf, sizeof(handle->socket_buf) - 1))) {
- char *data = (char *) handle->socket_buf;
- char *p, *e;
- *(data + len1) = '\0';
-
- 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");
-
- p = data;
- while(p) {
- hname = p;
- p = NULL;
- if ((hval = strchr(hname, ':'))) {
- *hval++ = '\0';
- while(*hval == ' ' || *hval == '\t') hval++;
- 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);
- if (!strncmp(hval, "ARRAY::", 7)) {
- esl_event_add_array(revent, hname, hval);
- } else {
- esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval);
- }
- }
-
- p = e;
- }
- }
- }
- break;
- }
-
- rrval = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf) - 1);
- if (rrval == 0) {
- continue;
- } else if (rrval < 0) {
- if (!(strerror_r(handle->errnum, handle->err, sizeof(handle->err))))
- *(handle->err)=0;
- goto fail;
- }
- *((char *)handle->socket_buf + ESL_CLAMP(0, sizeof(handle->socket_buf) - 1, rrval)) = '\0';
- esl_buffer_write(handle->packet_buf, handle->socket_buf, rrval);
- }
-
- 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,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) - 1);
-
- if (r < 0) {
- if (!(strerror_r(handle->errnum, handle->err, sizeof(handle->err))))
- *(handle->err)=0;
- free(body);
- goto fail;
- } else if (r == 0) {
- continue;
- }
- *((char *)handle->socket_buf + ESL_CLAMP(0, sizeof(handle->socket_buf) - 1, r)) = '\0';
- esl_buffer_write(handle->packet_buf, handle->socket_buf, r);
- }
-
- } while (sofar < len);
-
- revent->body = body;
- }
- parse_event:
- if (save_event) {
- *save_event = revent;
- revent = NULL;
- } else {
- esl_event_safe_destroy(&handle->last_event);
- 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) {
- const char *dval = esl_event_get_header(revent, "content-disposition");
- if (esl_strlen_zero(dval) || strcasecmp(dval, "linger")) {
- goto fail;
- }
- }
-
- if (revent->body) {
- if (!esl_safe_strcasecmp(hval, "text/event-plain")) {
- esl_event_types_t et = ESL_EVENT_CLONE;
- char *body = strdup(revent->body);
-
- 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_name_event(hval, &handle->last_ievent->event_id);
- }
- if (!strncmp(hval, "ARRAY::", 7)) {
- esl_event_add_array(handle->last_ievent, hname, hval);
- } else {
- esl_event_add_header_string(handle->last_ievent, ESL_STACK_BOTTOM, hname, hval);
- }
- }
-
- 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);
- }
- } else if (!esl_safe_strcasecmp(hval, "text/event-json")) {
- esl_event_create_json(&handle->last_ievent, revent->body);
- }
- }
- 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_mutex_unlock(handle->mutex);
- handle->connected = 0;
- 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 || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
- return ESL_FAIL;
- }
- esl_log(ESL_LOG_DEBUG, "SEND\n%s\n", cmd);
-
- if (send(handle->sock, cmd, strlen(cmd), 0) != (int)strlen(cmd)) {
- handle->connected = 0;
- if (!(strerror_r(handle->errnum, handle->err, sizeof(handle->err))))
- *(handle->err)=0;
- return ESL_FAIL;
- }
-
- if (!(*e == '\n' && *(e-1) == '\n')) {
- if (send(handle->sock, "\n\n", 2, 0) != 2) {
- handle->connected = 0;
- if (!(strerror_r(handle->errnum, handle->err, sizeof(handle->err))))
- *(handle->err)=0;
- return ESL_FAIL;
- }
- }
-
- return ESL_SUCCESS;
- }
- ESL_DECLARE(esl_status_t) esl_send_recv_timed(esl_handle_t *handle, const char *cmd, uint32_t ms)
- {
- const char *hval;
- esl_status_t status;
-
- if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
- return ESL_FAIL;
- }
- esl_mutex_lock(handle->mutex);
- if (!handle->connected || handle->sock == ESL_SOCK_INVALID) {
- handle->connected = 0;
- esl_mutex_unlock(handle->mutex);
- return ESL_FAIL;
- }
- 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:
-
- esl_event_safe_destroy(&handle->last_sr_event);
- *handle->last_sr_reply = '\0';
- status = esl_recv_event_timed(handle, ms, 0, &handle->last_sr_event);
- if (handle->last_sr_event) {
- char *ct = esl_event_get_header(handle->last_sr_event,"content-type");
- if (ct && 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);
- if (!handle->connected || handle->sock == ESL_SOCK_INVALID) {
- handle->connected = 0;
- esl_mutex_unlock(handle->mutex);
- return ESL_FAIL;
- }
- 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;
- }
- ESL_DECLARE(unsigned int) esl_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen)
- {
- unsigned int count = 0;
- char *d;
- size_t dlen = strlen(delim);
- array[count++] = buf;
- while (count < arraylen && array[count - 1]) {
- if ((d = strstr(array[count - 1], delim))) {
- *d = '\0';
- d += dlen;
- array[count++] = d;
- } else
- break;
- }
- return count;
- }
- /* 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 noet:
- */
|