1 /*
2 * Copyright (c) 2007-2014, Anthony Minessale II
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of the original author; nor the names of any contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34
35 /* Use select on windows and poll everywhere else.
36 Select is the devil. Especially if you are doing a lot of small socket connections.
37 If your FD number is bigger than 1024 you will silently create memory corruption.
38
39 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
40 All of this will be upgraded to autoheadache eventually.
41 */
42
43 /* 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) */
44
45 #ifdef _MSC_VER
46 #define FD_SETSIZE 8192
47 #define ESL_USE_SELECT
48 #else
49 #define ESL_USE_POLL
50 #endif
51
52 #include <esl.h>
53 #ifndef WIN32
54 #define closesocket(x) shutdown(x, 2); close(x)
55 #include <fcntl.h>
56 #include <errno.h>
57 #else
58 #pragma warning (disable:6386)
59 /* These warnings need to be ignored warning in sdk header */
60 #include <Ws2tcpip.h>
61 #include <windows.h>
62 #include <errno.h>
63 #ifndef errno
64 #define errno WSAGetLastError()
65 #endif
66 #ifndef EINTR
67 #define EINTR WSAEINTR
68 #endif
69 #pragma warning (default:6386)
70 #endif
71
72 #ifdef ESL_USE_POLL
73 #include <poll.h>
74 #endif
75
76 #ifndef ESL_MIN
77 #define ESL_MIN(x,y) ((x) < (y) ? (x) : (y))
78 #endif
79 #ifndef ESL_MAX
80 #define ESL_MAX(x,y) ((x) > (y) ? (x) : (y))
81 #endif
82 #ifndef ESL_CLAMP
83 #define ESL_CLAMP(min,max,val) (ESL_MIN(max,ESL_MAX(val,min)))
84 #endif
85
86
87 /* Written by Marc Espie, public domain */
88 #define ESL_CTYPE_NUM_CHARS 256
89
90 const short _esl_C_toupper_[1 + ESL_CTYPE_NUM_CHARS] = {
91 EOF,
92 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
93 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
94 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
95 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
96 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
97 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
98 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
99 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
100 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
101 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
102 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
103 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
104 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
105 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
106 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
107 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
108 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
109 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
110 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
111 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
112 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
113 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
114 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
115 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
116 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
117 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
118 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
119 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
120 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
121 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
122 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
123 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
124 };
125
126 const short *_esl_toupper_tab_ = _esl_C_toupper_;
127
esl_toupper(int c)128 ESL_DECLARE(int) esl_toupper(int c)
129 {
130 if ((unsigned int)c > 255)
131 return(c);
132 if (c < -1)
133 return EOF;
134 return((_esl_toupper_tab_ + 1)[c]);
135 }
136
137 const short _esl_C_tolower_[1 + ESL_CTYPE_NUM_CHARS] = {
138 EOF,
139 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
140 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
141 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
142 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
143 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
144 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
145 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
146 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
147 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
148 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
149 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
150 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
151 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
152 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
153 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
154 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
155 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
156 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
157 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
158 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
159 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
160 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
161 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
162 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
163 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
164 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
165 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
166 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
167 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
168 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
169 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
170 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
171 };
172
173 const short *_esl_tolower_tab_ = _esl_C_tolower_;
174
esl_tolower(int c)175 ESL_DECLARE(int) esl_tolower(int c)
176 {
177 if ((unsigned int)c > 255)
178 return(c);
179 if (c < -1)
180 return EOF;
181 return((_esl_tolower_tab_ + 1)[c]);
182 }
183
esl_stristr(const char * instr,const char * str)184 ESL_DECLARE(const char *)esl_stristr(const char *instr, const char *str)
185 {
186 /*
187 ** Rev History: 16/07/97 Greg Thayer Optimized
188 ** 07/04/95 Bob Stout ANSI-fy
189 ** 02/03/94 Fred Cole Original
190 ** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback
191 **
192 ** Hereby donated to public domain.
193 */
194 const char *pptr, *sptr, *start;
195
196 if (!str || !instr)
197 return NULL;
198
199 for (start = str; *start; start++) {
200 /* find start of pattern in string */
201 for (; ((*start) && (esl_toupper(*start) != esl_toupper(*instr))); start++);
202
203 if (!*start)
204 return NULL;
205
206 pptr = instr;
207 sptr = start;
208
209 while (esl_toupper(*sptr) == esl_toupper(*pptr)) {
210 sptr++;
211 pptr++;
212
213 /* if end of pattern then pattern was found */
214 if (!*pptr)
215 return (start);
216
217 if (!*sptr)
218 return NULL;
219 }
220 }
221 return NULL;
222 }
223
224 #ifdef WIN32
225 #ifndef vsnprintf
226 #define vsnprintf _vsnprintf
227 #endif
228 #endif
229
230
231 int vasprintf(char **ret, const char *format, va_list ap);
232
esl_vasprintf(char ** ret,const char * fmt,va_list ap)233 ESL_DECLARE(int) esl_vasprintf(char **ret, const char *fmt, va_list ap)
234 {
235 #if !defined(WIN32) && !defined(__sun)
236 return vasprintf(ret, fmt, ap);
237 #else
238 char *buf;
239 int len;
240 size_t buflen;
241 va_list ap2;
242 char *tmp = NULL;
243
244 #ifdef _MSC_VER
245 #if _MSC_VER >= 1500
246 /* hack for incorrect assumption in msvc header files for code analysis */
247 __analysis_assume(tmp);
248 #endif
249 ap2 = ap;
250 #else
251 va_copy(ap2, ap);
252 #endif
253
254 len = vsnprintf(tmp, 0, fmt, ap2);
255
256 if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) {
257 len = vsnprintf(buf, buflen, fmt, ap);
258 *ret = buf;
259 } else {
260 *ret = NULL;
261 len = -1;
262 }
263
264 va_end(ap2);
265 return len;
266 #endif
267 }
268
269
270
271
esl_snprintf(char * buffer,size_t count,const char * fmt,...)272 ESL_DECLARE(int) esl_snprintf(char *buffer, size_t count, const char *fmt, ...)
273 {
274 va_list ap;
275 int ret;
276
277 va_start(ap, fmt);
278 ret = vsnprintf(buffer, count-1, fmt, ap);
279 if (ret < 0)
280 buffer[count-1] = '\0';
281 va_end(ap);
282 return ret;
283 }
284
null_logger(const char * file,const char * func,int line,int level,const char * fmt,...)285 static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
286 {
287 if (file && func && line && level && fmt) {
288 return;
289 }
290 return;
291 }
292
293
294 static const char *LEVEL_NAMES[] = {
295 "EMERG",
296 "ALERT",
297 "CRIT",
298 "ERROR",
299 "WARNING",
300 "NOTICE",
301 "INFO",
302 "DEBUG",
303 NULL
304 };
305
306 static int esl_log_level = 7;
307
cut_path(const char * in)308 static const char *cut_path(const char *in)
309 {
310 const char *p, *ret = in;
311 char delims[] = "/\\";
312 char *i;
313
314 for (i = delims; *i; i++) {
315 p = in;
316 while ((p = strchr(p, *i)) != 0) {
317 ret = ++p;
318 }
319 }
320 return ret;
321 }
322
323
default_logger(const char * file,const char * func,int line,int level,const char * fmt,...)324 static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
325 {
326 const char *fp;
327 char *data;
328 va_list ap;
329 int ret;
330
331 if (level < 0 || level > 7) {
332 level = 7;
333 }
334 if (level > esl_log_level) {
335 return;
336 }
337
338 fp = cut_path(file);
339
340 va_start(ap, fmt);
341
342 ret = esl_vasprintf(&data, fmt, ap);
343
344 if (ret != -1) {
345 fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], fp, line, func, data);
346 free(data);
347 }
348
349 va_end(ap);
350
351 }
352
353 esl_logger_t esl_log = null_logger;
354
esl_global_set_logger(esl_logger_t logger)355 ESL_DECLARE(void) esl_global_set_logger(esl_logger_t logger)
356 {
357 if (logger) {
358 esl_log = logger;
359 } else {
360 esl_log = null_logger;
361 }
362 }
363
esl_global_set_default_logger(int level)364 ESL_DECLARE(void) esl_global_set_default_logger(int level)
365 {
366 if (level < 0 || level > 7) {
367 level = 7;
368 }
369
370 esl_log = default_logger;
371 esl_log_level = level;
372 }
373
esl_url_encode(const char * url,char * buf,size_t len)374 ESL_DECLARE(size_t) esl_url_encode(const char *url, char *buf, size_t len)
375 {
376 const char *p;
377 size_t x = 0;
378 const char urlunsafe[] = "\r\n \"#%&+:;<=>?@[\\]^`{|}";
379 const char hex[] = "0123456789ABCDEF";
380
381 if (!buf) {
382 return 0;
383 }
384
385 if (!url) {
386 return 0;
387 }
388
389 len--;
390
391 for (p = url; *p; p++) {
392 if (x >= len) {
393 break;
394 }
395 if (*p < ' ' || *p > '~' || strchr(urlunsafe, *p)) {
396 if ((x + 3) >= len) {
397 break;
398 }
399 buf[x++] = '%';
400 buf[x++] = hex[*p >> 4];
401 buf[x++] = hex[*p & 0x0f];
402 } else {
403 buf[x++] = *p;
404 }
405 }
406 buf[x] = '\0';
407
408 return x;
409 }
410
esl_url_decode(char * s)411 ESL_DECLARE(char *)esl_url_decode(char *s)
412 {
413 char *o;
414 unsigned int tmp;
415
416 for (o = s; *s; s++, o++) {
417 if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) {
418 *o = (char) tmp;
419 s += 2;
420 } else {
421 *o = *s;
422 }
423 }
424 *o = '\0';
425 return s;
426 }
427
sock_setup(esl_handle_t * handle)428 static int sock_setup(esl_handle_t *handle)
429 {
430
431 if (handle->sock == ESL_SOCK_INVALID) {
432 return ESL_FAIL;
433 }
434
435 #ifdef WIN32
436 {
437 BOOL bOptVal = TRUE;
438 int bOptLen = sizeof(BOOL);
439 setsockopt(handle->sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&bOptVal, bOptLen);
440 }
441 #else
442 {
443 int x = 1;
444 setsockopt(handle->sock, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x));
445 }
446 #endif
447
448 return ESL_SUCCESS;
449 }
450
esl_attach_handle(esl_handle_t * handle,esl_socket_t socket,struct sockaddr_in * addr)451 ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t socket, struct sockaddr_in *addr)
452 {
453
454 if (!handle || socket == ESL_SOCK_INVALID) {
455 return ESL_FAIL;
456 }
457
458 handle->sock = socket;
459
460 if (addr) {
461 handle->addr = *addr;
462 }
463
464 if (sock_setup(handle) != ESL_SUCCESS) {
465 return ESL_FAIL;
466 }
467
468 if (!handle->mutex) {
469 esl_mutex_create(&handle->mutex);
470 }
471
472 if (!handle->packet_buf) {
473 esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0);
474 }
475
476 handle->connected = 1;
477
478 esl_send_recv(handle, "connect\n\n");
479
480 if (handle->last_sr_event) {
481 handle->info_event = handle->last_sr_event;
482 handle->last_sr_event = NULL;
483 return ESL_SUCCESS;
484 }
485
486 esl_disconnect(handle);
487
488 return ESL_FAIL;
489 }
490
esl_sendevent(esl_handle_t * handle,esl_event_t * event)491 ESL_DECLARE(esl_status_t) esl_sendevent(esl_handle_t *handle, esl_event_t *event)
492 {
493 char *txt;
494 char *event_buf = NULL;
495 esl_status_t status = ESL_FAIL;
496 size_t len = 0;
497
498 if (!handle->connected || !event) {
499 return ESL_FAIL;
500 }
501
502 esl_event_serialize(event, &txt, ESL_FALSE);
503
504 esl_log(ESL_LOG_DEBUG, "SEND EVENT\n%s\n", txt);
505
506 len = strlen(txt) + 100;
507 event_buf = malloc(len);
508 assert(event_buf);
509
510 if (!event_buf) {
511 return ESL_FAIL;
512 }
513
514 memset(event_buf, 0, len);
515
516 snprintf(event_buf, len, "sendevent %s\n%s", esl_event_name(event->event_id), txt);
517
518 status = esl_send_recv(handle, event_buf);
519
520 free(txt);
521 free(event_buf);
522
523 return status;
524
525 }
526
esl_execute(esl_handle_t * handle,const char * app,const char * arg,const char * uuid)527 ESL_DECLARE(esl_status_t) esl_execute(esl_handle_t *handle, const char *app, const char *arg, const char *uuid)
528 {
529 char cmd_buf[128] = "sendmsg";
530 char app_buf[512] = "";
531 char arg_buf[4096] = "";
532 const char *el_buf = "event-lock: true\n";
533 const char *bl_buf = "async: true\n";
534 char send_buf[5120] = "";
535
536 if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
537 return ESL_FAIL;
538 }
539
540 if (uuid) {
541 snprintf(cmd_buf, sizeof(cmd_buf), "sendmsg %s", uuid);
542 }
543
544 if (app) {
545 snprintf(app_buf, sizeof(app_buf), "execute-app-name: %s\n", app);
546 }
547
548 if (arg) {
549 snprintf(arg_buf, sizeof(arg_buf), "execute-app-arg: %s\n", arg);
550 }
551
552 snprintf(send_buf, sizeof(send_buf), "%s\ncall-command: execute\n%s%s%s%s\n",
553 cmd_buf, app_buf, arg_buf, handle->event_lock ? el_buf : "", handle->async_execute ? bl_buf : "");
554
555 return esl_send_recv(handle, send_buf);
556 }
557
558
esl_sendmsg(esl_handle_t * handle,esl_event_t * event,const char * uuid)559 ESL_DECLARE(esl_status_t) esl_sendmsg(esl_handle_t *handle, esl_event_t *event, const char *uuid)
560 {
561 char *cmd_buf = NULL;
562 char *txt;
563 size_t len = 0;
564 esl_status_t status = ESL_FAIL;
565
566 if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
567 return ESL_FAIL;
568 }
569
570 esl_event_serialize(event, &txt, ESL_FALSE);
571 len = strlen(txt) + 100;
572 cmd_buf = malloc(len);
573 assert(cmd_buf);
574
575 if (!cmd_buf) {
576 return ESL_FAIL;
577 }
578
579 memset(cmd_buf, 0, len);
580
581 if (uuid) {
582 snprintf(cmd_buf, len, "sendmsg %s\n%s", uuid, txt);
583 } else {
584 snprintf(cmd_buf, len, "sendmsg\n%s", txt);
585 }
586
587 esl_log(ESL_LOG_DEBUG, "%s%s\n", cmd_buf, txt);
588
589 status = esl_send_recv(handle, cmd_buf);
590
591 free(txt);
592 free(cmd_buf);
593
594 return status;
595 }
596
597
esl_filter(esl_handle_t * handle,const char * header,const char * value)598 ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value)
599 {
600 char send_buf[1024] = "";
601
602 if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
603 return ESL_FAIL;
604 }
605
606 snprintf(send_buf, sizeof(send_buf), "filter %s %s\n\n", header, value);
607
608 return esl_send_recv(handle, send_buf);
609 }
610
611
esl_events(esl_handle_t * handle,esl_event_type_t etype,const char * value)612 ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etype, const char *value)
613 {
614 char send_buf[1024] = "";
615 const char *type = "plain";
616
617 if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
618 return ESL_FAIL;
619 }
620
621 if (etype == ESL_EVENT_TYPE_XML) {
622 type = "xml";
623 } else if (etype == ESL_EVENT_TYPE_JSON) {
624 type = "json";
625 }
626
627 snprintf(send_buf, sizeof(send_buf), "event %s %s\n\n", type, value);
628
629 return esl_send_recv(handle, send_buf);
630 }
631
esl_socket_reuseaddr(esl_socket_t socket)632 static int esl_socket_reuseaddr(esl_socket_t socket)
633 {
634 #ifdef WIN32
635 BOOL reuse_addr = TRUE;
636 return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse_addr, sizeof(reuse_addr));
637 #else
638 int reuse_addr = 1;
639 return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
640 #endif
641 }
642
643 struct thread_handler {
644 esl_listen_callback_t callback;
645 esl_socket_t server_sock;
646 esl_socket_t client_sock;
647 struct sockaddr_in addr;
648 void *user_data;
649 };
650
client_thread(esl_thread_t * me,void * obj)651 static void *client_thread(esl_thread_t *me, void *obj)
652 {
653 struct thread_handler *handler = (struct thread_handler *) obj;
654
655 handler->callback(handler->server_sock, handler->client_sock, &handler->addr, handler->user_data);
656 free(handler);
657
658 return NULL;
659
660 }
661
prepare_sock(esl_socket_t sock)662 static int prepare_sock(esl_socket_t sock)
663 {
664 int r = 0;
665
666 #ifdef WIN32
667 u_long arg = 1;
668 if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR) {
669 r = -1;
670 }
671 #else
672 int fd_flags = fcntl(sock, F_GETFL, 0);
673 if (fcntl(sock, F_SETFL, fd_flags | O_NONBLOCK)) {
674 r = -1;
675 }
676 #endif
677
678 return r;
679
680 }
681
682
esl_listen(const char * host,esl_port_t port,esl_listen_callback_t callback,void * user_data,esl_socket_t * server_sockP)683 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)
684 {
685 esl_socket_t server_sock = ESL_SOCK_INVALID;
686 struct sockaddr_in addr;
687 esl_status_t status = ESL_SUCCESS;
688
689
690 if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
691 return ESL_FAIL;
692 }
693
694 if (server_sockP) {
695 *server_sockP = server_sock;
696 }
697
698
699 esl_socket_reuseaddr(server_sock);
700
701 memset(&addr, 0, sizeof(addr));
702 addr.sin_family = AF_INET;
703 addr.sin_addr.s_addr = htonl(INADDR_ANY);
704 addr.sin_port = htons(port);
705
706 if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
707 status = ESL_FAIL;
708 goto end;
709 }
710
711 if (listen(server_sock, 10000) < 0) {
712 status = ESL_FAIL;
713 goto end;
714 }
715
716 for (;;) {
717 int client_sock;
718 struct sockaddr_in echoClntAddr;
719 #ifdef WIN32
720 int clntLen;
721 #else
722 unsigned int clntLen;
723 #endif
724
725 clntLen = sizeof(echoClntAddr);
726
727 if ((client_sock = accept(server_sock, (struct sockaddr *) &echoClntAddr, &clntLen)) == ESL_SOCK_INVALID && errno != EINTR) {
728 status = ESL_FAIL;
729 goto end;
730 }
731 prepare_sock(client_sock);
732 callback(server_sock, client_sock, &echoClntAddr, user_data);
733 }
734
735 end:
736
737 closesocket(server_sock);
738
739 return status;
740
741 }
742
esl_listen_threaded(const char * host,esl_port_t port,esl_listen_callback_t callback,void * user_data,int max)743 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)
744 {
745 esl_socket_t server_sock = ESL_SOCK_INVALID;
746 struct sockaddr_in addr;
747 esl_status_t status = ESL_SUCCESS;
748 struct thread_handler *handler = NULL;
749
750 if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
751 return ESL_FAIL;
752 }
753
754 esl_socket_reuseaddr(server_sock);
755
756 memset(&addr, 0, sizeof(addr));
757 addr.sin_family = AF_INET;
758 addr.sin_addr.s_addr = htonl(INADDR_ANY);
759 addr.sin_port = htons(port);
760
761 if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
762 status = ESL_FAIL;
763 goto end;
764 }
765
766 if (listen(server_sock, max) < 0) {
767 status = ESL_FAIL;
768 goto end;
769 }
770
771 for (;;) {
772 int client_sock;
773 struct sockaddr_in echoClntAddr;
774 #ifdef WIN32
775 int clntLen;
776 #else
777 unsigned int clntLen;
778 #endif
779
780 clntLen = sizeof(echoClntAddr);
781
782 if ((client_sock = accept(server_sock, (struct sockaddr *) &echoClntAddr, &clntLen)) == ESL_SOCK_INVALID && errno != EINTR) {
783 status = ESL_FAIL;
784 goto end;
785 }
786
787 prepare_sock(client_sock);
788
789 handler = malloc(sizeof(*handler));
790 esl_assert(handler);
791
792 memset(handler, 0, sizeof(*handler));
793 handler->callback = callback;
794 handler->server_sock = server_sock;
795 handler->client_sock = client_sock;
796 handler->addr = echoClntAddr;
797 handler->user_data = user_data;
798 esl_thread_create_detached(client_thread, handler);
799 }
800
801 end:
802
803 closesocket(server_sock);
804
805 return status;
806
807 }
808
809
810 /* USE WSAPoll on vista or higher */
811 #ifdef ESL_USE_WSAPOLL
esl_wait_sock(esl_socket_t sock,uint32_t ms,esl_poll_t flags)812 ESL_DECLARE(int) esl_wait_sock(esl_socket_t sock, uint32_t ms, esl_poll_t flags)
813 {
814 }
815 #endif
816
817
818 #ifdef ESL_USE_SELECT
819 #ifdef WIN32
820 #pragma warning( push )
821 #pragma warning( disable : 6262 ) /* warning C6262: Function uses '98348' bytes of stack: exceeds /analyze:stacksize'16384'. Consider moving some data to heap */
822 #endif
esl_wait_sock(esl_socket_t sock,uint32_t ms,esl_poll_t flags)823 ESL_DECLARE(int) esl_wait_sock(esl_socket_t sock, uint32_t ms, esl_poll_t flags)
824 {
825 int s = 0, r = 0;
826 fd_set rfds;
827 fd_set wfds;
828 fd_set efds;
829 struct timeval tv;
830
831 if (sock == ESL_SOCK_INVALID) {
832 return ESL_SOCK_INVALID;
833 }
834
835 FD_ZERO(&rfds);
836 FD_ZERO(&wfds);
837 FD_ZERO(&efds);
838
839 #ifndef WIN32
840 /* Wouldn't you rather know?? */
841 assert(sock <= FD_SETSIZE);
842 #endif
843
844 if ((flags & ESL_POLL_READ)) {
845
846 #ifdef WIN32
847 #pragma warning( push )
848 #pragma warning( disable : 4127 )
849 FD_SET(sock, &rfds);
850 #pragma warning( pop )
851 #else
852 FD_SET(sock, &rfds);
853 #endif
854 }
855
856 if ((flags & ESL_POLL_WRITE)) {
857
858 #ifdef WIN32
859 #pragma warning( push )
860 #pragma warning( disable : 4127 )
861 FD_SET(sock, &wfds);
862 #pragma warning( pop )
863 #else
864 FD_SET(sock, &wfds);
865 #endif
866 }
867
868 if ((flags & ESL_POLL_ERROR)) {
869
870 #ifdef WIN32
871 #pragma warning( push )
872 #pragma warning( disable : 4127 )
873 FD_SET(sock, &efds);
874 #pragma warning( pop )
875 #else
876 FD_SET(sock, &efds);
877 #endif
878 }
879
880 tv.tv_sec = ms / 1000;
881 tv.tv_usec = (ms % 1000) * ms;
882
883 s = select(sock + 1, (flags & ESL_POLL_READ) ? &rfds : NULL, (flags & ESL_POLL_WRITE) ? &wfds : NULL, (flags & ESL_POLL_ERROR) ? &efds : NULL, &tv);
884
885 if (s < 0) {
886 r = s;
887 } else if (s > 0) {
888 if ((flags & ESL_POLL_READ) && FD_ISSET(sock, &rfds)) {
889 r |= ESL_POLL_READ;
890 }
891
892 if ((flags & ESL_POLL_WRITE) && FD_ISSET(sock, &wfds)) {
893 r |= ESL_POLL_WRITE;
894 }
895
896 if ((flags & ESL_POLL_ERROR) && FD_ISSET(sock, &efds)) {
897 r |= ESL_POLL_ERROR;
898 }
899 }
900
901 return r;
902
903 }
904 #ifdef WIN32
905 #pragma warning( pop )
906 #endif
907 #endif
908
909 #ifdef ESL_USE_POLL
esl_wait_sock(esl_socket_t sock,uint32_t ms,esl_poll_t flags)910 ESL_DECLARE(int) esl_wait_sock(esl_socket_t sock, uint32_t ms, esl_poll_t flags)
911 {
912 struct pollfd pfds[2] = { { 0 } };
913 int s = 0, r = 0;
914
915 if (sock == ESL_SOCK_INVALID) {
916 return ESL_SOCK_INVALID;
917 }
918
919 pfds[0].fd = sock;
920
921 if ((flags & ESL_POLL_READ)) {
922 pfds[0].events |= POLLIN;
923 }
924
925 if ((flags & ESL_POLL_WRITE)) {
926 pfds[0].events |= POLLOUT;
927 }
928
929 if ((flags & ESL_POLL_ERROR)) {
930 pfds[0].events |= POLLERR;
931 }
932
933 s = poll(pfds, 1, ms);
934
935 if (s < 0) {
936 r = s;
937 } else if (s > 0) {
938 if ((pfds[0].revents & POLLIN)) {
939 r |= ESL_POLL_READ;
940 }
941 if ((pfds[0].revents & POLLOUT)) {
942 r |= ESL_POLL_WRITE;
943 }
944 if ((pfds[0].revents & POLLERR)) {
945 r |= ESL_POLL_ERROR;
946 }
947 }
948
949 return r;
950
951 }
952 #endif
953
954
esl_connect_timeout(esl_handle_t * handle,const char * host,esl_port_t port,const char * user,const char * password,uint32_t timeout)955 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)
956 {
957 char sendbuf[256];
958 int rval = 0;
959 const char *hval;
960 struct addrinfo hints = { 0 }, *result;
961 struct sockaddr_in *sockaddr_in;
962 struct sockaddr_in6 *sockaddr_in6;
963 socklen_t socklen;
964 #ifndef WIN32
965 int fd_flags = 0;
966 #else
967 WORD wVersionRequested = MAKEWORD(2, 0);
968 WSADATA wsaData;
969 int err = WSAStartup(wVersionRequested, &wsaData);
970 if (err != 0) {
971 snprintf(handle->err, sizeof(handle->err), "WSAStartup Error");
972 goto fail;
973 }
974
975 #endif
976
977 if (!handle->mutex) {
978 esl_mutex_create(&handle->mutex);
979 }
980
981 if (!handle->packet_buf) {
982 esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0);
983 }
984
985 hints.ai_socktype = SOCK_STREAM;
986
987 if (getaddrinfo(host, NULL, &hints, &result)) {
988 strncpy(handle->err, "Cannot resolve host", sizeof(handle->err));
989 goto fail;
990 }
991
992 memcpy(&handle->sockaddr, result->ai_addr, result->ai_addrlen);
993 switch(handle->sockaddr.ss_family) {
994 case AF_INET:
995 sockaddr_in = (struct sockaddr_in*)&(handle->sockaddr);
996 sockaddr_in->sin_port = htons(port);
997 socklen = sizeof(struct sockaddr_in);
998 break;
999 case AF_INET6:
1000 sockaddr_in6 = (struct sockaddr_in6*)&(handle->sockaddr);
1001 sockaddr_in6->sin6_port = htons(port);
1002 socklen = sizeof(struct sockaddr_in6);
1003 break;
1004 default:
1005 strncpy(handle->err, "Host resolves to unsupported address family", sizeof(handle->err));
1006 goto fail;
1007 }
1008 freeaddrinfo(result);
1009
1010 handle->sock = socket(handle->sockaddr.ss_family, SOCK_STREAM, IPPROTO_TCP);
1011
1012 if (handle->sock == ESL_SOCK_INVALID) {
1013 snprintf(handle->err, sizeof(handle->err), "Socket Error");
1014 goto fail;
1015 }
1016
1017 handle->destroyed = 0;
1018
1019 if (timeout) {
1020 #ifdef WIN32
1021 u_long arg = 1;
1022 if (ioctlsocket(handle->sock, FIONBIO, &arg) == SOCKET_ERROR) {
1023 snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
1024 goto fail;
1025 }
1026 #else
1027 fd_flags = fcntl(handle->sock, F_GETFL, 0);
1028 if (fcntl(handle->sock, F_SETFL, fd_flags | O_NONBLOCK)) {
1029 snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
1030 goto fail;
1031 }
1032 #endif
1033 }
1034
1035 rval = connect(handle->sock, (struct sockaddr*)&handle->sockaddr, socklen);
1036
1037 if (timeout) {
1038 int r;
1039
1040
1041 r = esl_wait_sock(handle->sock, timeout, ESL_POLL_WRITE);
1042
1043 if (r <= 0) {
1044 snprintf(handle->err, sizeof(handle->err), "Connection timed out");
1045 goto fail;
1046 }
1047
1048 if (!(r & ESL_POLL_WRITE)) {
1049 snprintf(handle->err, sizeof(handle->err), "Connection timed out");
1050 goto fail;
1051 }
1052
1053 #ifdef WIN32
1054 {
1055 u_long arg = 0;
1056 if (ioctlsocket(handle->sock, FIONBIO, &arg) == SOCKET_ERROR) {
1057 snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
1058 goto fail;
1059 }
1060 }
1061 #else
1062 fcntl(handle->sock, F_SETFL, fd_flags);
1063 #endif
1064 rval = 0;
1065 }
1066
1067 result = NULL;
1068
1069 if (rval) {
1070 snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
1071 goto fail;
1072 }
1073
1074 sock_setup(handle);
1075
1076 handle->connected = 1;
1077
1078 if (esl_recv_timed(handle, timeout)) {
1079 snprintf(handle->err, sizeof(handle->err), "Connection Error");
1080 goto fail;
1081 }
1082
1083 hval = esl_event_get_header(handle->last_event, "content-type");
1084
1085 if (esl_safe_strcasecmp(hval, "auth/request")) {
1086 snprintf(handle->err, sizeof(handle->err), "Connection Error");
1087 goto fail;
1088 }
1089
1090 if (esl_strlen_zero(user)) {
1091 snprintf(sendbuf, sizeof(sendbuf), "auth %s\n\n", password);
1092 } else {
1093 snprintf(sendbuf, sizeof(sendbuf), "userauth %s:%s\n\n", user, password);
1094 }
1095
1096 esl_send(handle, sendbuf);
1097
1098
1099 if (esl_recv_timed(handle, timeout)) {
1100 snprintf(handle->err, sizeof(handle->err), "Authentication Error");
1101 goto fail;
1102 }
1103
1104
1105 hval = esl_event_get_header(handle->last_event, "reply-text");
1106
1107 if (esl_safe_strcasecmp(hval, "+OK accepted")) {
1108 snprintf(handle->err, sizeof(handle->err), "Authentication Error");
1109 goto fail;
1110 }
1111
1112 return ESL_SUCCESS;
1113
1114 fail:
1115
1116 esl_disconnect(handle);
1117
1118 return ESL_FAIL;
1119 }
1120
esl_disconnect(esl_handle_t * handle)1121 ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle)
1122 {
1123 esl_mutex_t *mutex = handle->mutex;
1124 esl_status_t status = ESL_FAIL;
1125 esl_event_t *ep;
1126
1127 if (handle->destroyed) {
1128 return ESL_FAIL;
1129 }
1130
1131 if (handle->sock != ESL_SOCK_INVALID) {
1132 closesocket(handle->sock);
1133 handle->sock = ESL_SOCK_INVALID;
1134 status = ESL_SUCCESS;
1135 }
1136
1137 if (mutex) {
1138 esl_mutex_lock(mutex);
1139 }
1140
1141
1142 handle->connected = 0;
1143
1144 ep = handle->race_event;
1145
1146 while(ep) {
1147 esl_event_t *e = ep;
1148 ep = ep->next;
1149 esl_event_destroy(&e);
1150 }
1151
1152 esl_event_safe_destroy(&handle->last_event);
1153 esl_event_safe_destroy(&handle->last_sr_event);
1154 esl_event_safe_destroy(&handle->last_ievent);
1155 esl_event_safe_destroy(&handle->info_event);
1156
1157 if (mutex) {
1158 esl_mutex_unlock(mutex);
1159 esl_mutex_lock(mutex);
1160 esl_mutex_unlock(mutex);
1161 esl_mutex_destroy(&mutex);
1162 }
1163
1164 if (handle->packet_buf) {
1165 esl_buffer_destroy(&handle->packet_buf);
1166 }
1167
1168 memset(handle, 0, sizeof(*handle));
1169 handle->destroyed = 1;
1170
1171 return status;
1172 }
1173
esl_recv_event_timed(esl_handle_t * handle,uint32_t ms,int check_q,esl_event_t ** save_event)1174 ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, int check_q, esl_event_t **save_event)
1175 {
1176 int activity;
1177 esl_status_t status = ESL_SUCCESS;
1178
1179 if (!ms) {
1180 return esl_recv_event(handle, check_q, save_event);
1181 }
1182
1183 if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
1184 return ESL_FAIL;
1185 }
1186
1187 if (check_q) {
1188 esl_mutex_lock(handle->mutex);
1189 if (handle->race_event || esl_buffer_packet_count(handle->packet_buf)) {
1190 esl_mutex_unlock(handle->mutex);
1191 return esl_recv_event(handle, check_q, save_event);
1192 }
1193 esl_mutex_unlock(handle->mutex);
1194 }
1195
1196 if (handle->packet_buf && esl_buffer_inuse(handle->packet_buf)) {
1197 activity = ESL_POLL_READ;
1198 } else {
1199 activity = esl_wait_sock(handle->sock, ms, ESL_POLL_READ|ESL_POLL_ERROR);
1200 }
1201
1202 if (activity < 0) {
1203 handle->connected = 0;
1204 return ESL_FAIL;
1205 }
1206
1207 if (activity == 0 || !(activity & ESL_POLL_READ) || (esl_mutex_trylock(handle->mutex) != ESL_SUCCESS)) {
1208 return ESL_BREAK;
1209 }
1210
1211 if ((activity & ESL_POLL_READ)) {
1212 if (esl_recv_event(handle, check_q, save_event)) {
1213 status = ESL_FAIL;
1214 }
1215 } else {
1216 status = ESL_BREAK;
1217 }
1218
1219 if (handle->mutex) esl_mutex_unlock(handle->mutex);
1220
1221 return status;
1222
1223 }
1224
handle_recv(esl_handle_t * handle,void * data,esl_size_t datalen)1225 static esl_ssize_t handle_recv(esl_handle_t *handle, void *data, esl_size_t datalen)
1226 {
1227 esl_ssize_t activity = -1;
1228
1229 if (handle->connected) {
1230 if ((activity = esl_wait_sock(handle->sock, 1000, ESL_POLL_READ|ESL_POLL_ERROR)) > 0) {
1231 if ((activity & ESL_POLL_ERROR)) {
1232 activity = -1;
1233 } else if ((activity & ESL_POLL_READ)) {
1234 if (!(activity = recv(handle->sock, data, datalen, 0))) {
1235 activity = -1;
1236 } else if (activity < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
1237 activity = 0;
1238 }
1239 }
1240 }
1241
1242 }
1243
1244 return activity;
1245 }
1246
esl_recv_event(esl_handle_t * handle,int check_q,esl_event_t ** save_event)1247 ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event)
1248 {
1249 char *c;
1250 esl_ssize_t rrval;
1251 esl_event_t *revent = NULL;
1252 char *beg;
1253 char *hname, *hval;
1254 char *col;
1255 char *cl;
1256 esl_ssize_t len;
1257
1258 if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
1259 return ESL_FAIL;
1260 }
1261
1262 esl_mutex_lock(handle->mutex);
1263
1264 esl_event_safe_destroy(&handle->last_ievent);
1265
1266 if (check_q && handle->race_event) {
1267 revent = handle->race_event;
1268 handle->race_event = handle->race_event->next;
1269 revent->next = NULL;
1270
1271 goto parse_event;
1272 }
1273
1274 while(!revent && handle->connected) {
1275 esl_size_t len1;
1276
1277 if ((len1 = esl_buffer_read_packet(handle->packet_buf, handle->socket_buf, sizeof(handle->socket_buf) - 1))) {
1278 char *data = (char *) handle->socket_buf;
1279 char *p, *e;
1280
1281 *(data + len1) = '\0';
1282
1283 esl_event_create(&revent, ESL_EVENT_CLONE);
1284 revent->event_id = ESL_EVENT_SOCKET_DATA;
1285 esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA");
1286
1287 p = data;
1288
1289 while(p) {
1290 hname = p;
1291 p = NULL;
1292
1293 if ((hval = strchr(hname, ':'))) {
1294 *hval++ = '\0';
1295 while(*hval == ' ' || *hval == '\t') hval++;
1296
1297 if ((e = strchr(hval, '\n'))) {
1298 *e++ = '\0';
1299 while(*e == '\n' || *e == '\r') e++;
1300
1301 if (hval) {
1302 esl_url_decode(hval);
1303 esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval);
1304 if (!strncmp(hval, "ARRAY::", 7)) {
1305 esl_event_add_array(revent, hname, hval);
1306 } else {
1307 esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval);
1308 }
1309 }
1310
1311 p = e;
1312 }
1313 }
1314 }
1315
1316 break;
1317 }
1318
1319 rrval = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf) - 1);
1320
1321 if (rrval == 0) {
1322 continue;
1323 } else if (rrval < 0) {
1324 if (!(strerror_r(handle->errnum, handle->err, sizeof(handle->err))))
1325 *(handle->err)=0;
1326 goto fail;
1327 }
1328
1329 *((char *)handle->socket_buf + ESL_CLAMP(0, sizeof(handle->socket_buf) - 1, rrval)) = '\0';
1330
1331 esl_buffer_write(handle->packet_buf, handle->socket_buf, rrval);
1332 }
1333
1334 if (!revent) {
1335 goto fail;
1336 }
1337
1338 if ((cl = esl_event_get_header(revent, "content-length"))) {
1339 char *body;
1340 esl_ssize_t sofar = 0;
1341
1342 len = atol(cl);
1343 body = malloc(len+1);
1344 esl_assert(body);
1345 *(body + len) = '\0';
1346
1347 do {
1348 esl_ssize_t r,s = esl_buffer_inuse(handle->packet_buf);
1349
1350 if (s >= len) {
1351 sofar = esl_buffer_read(handle->packet_buf, body, len);
1352 } else {
1353 r = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf) - 1);
1354
1355 if (r < 0) {
1356 if (!(strerror_r(handle->errnum, handle->err, sizeof(handle->err))))
1357 *(handle->err)=0;
1358 free(body);
1359 goto fail;
1360 } else if (r == 0) {
1361 continue;
1362 }
1363
1364 *((char *)handle->socket_buf + ESL_CLAMP(0, sizeof(handle->socket_buf) - 1, r)) = '\0';
1365 esl_buffer_write(handle->packet_buf, handle->socket_buf, r);
1366 }
1367
1368 } while (sofar < len);
1369
1370 revent->body = body;
1371 }
1372
1373 parse_event:
1374
1375 if (save_event) {
1376 *save_event = revent;
1377 revent = NULL;
1378 } else {
1379 esl_event_safe_destroy(&handle->last_event);
1380 handle->last_event = revent;
1381 }
1382
1383 if (revent) {
1384 hval = esl_event_get_header(revent, "reply-text");
1385
1386 if (!esl_strlen_zero(hval)) {
1387 snprintf(handle->last_reply, sizeof(handle->last_reply), "%s", hval);
1388 }
1389
1390 hval = esl_event_get_header(revent, "content-type");
1391
1392 if (!esl_safe_strcasecmp(hval, "text/disconnect-notice") && revent->body) {
1393 const char *dval = esl_event_get_header(revent, "content-disposition");
1394 if (esl_strlen_zero(dval) || strcasecmp(dval, "linger")) {
1395 goto fail;
1396 }
1397 }
1398
1399 if (revent->body) {
1400 if (!esl_safe_strcasecmp(hval, "text/event-plain")) {
1401 esl_event_types_t et = ESL_EVENT_CLONE;
1402 char *body = strdup(revent->body);
1403
1404 esl_event_create(&handle->last_ievent, et);
1405
1406 beg = body;
1407
1408 while(beg) {
1409 if (!(c = strchr(beg, '\n'))) {
1410 break;
1411 }
1412
1413 hname = beg;
1414 hval = col = NULL;
1415
1416 if ((col = strchr(hname, ':'))) {
1417 hval = col + 1;
1418 *col = '\0';
1419 while(*hval == ' ') hval++;
1420 }
1421
1422 *c = '\0';
1423
1424 if (hval) {
1425 esl_url_decode(hval);
1426 esl_log(ESL_LOG_DEBUG, "RECV INNER HEADER [%s] = [%s]\n", hname, hval);
1427 if (!strcasecmp(hname, "event-name")) {
1428 esl_event_del_header(handle->last_ievent, "event-name");
1429 esl_name_event(hval, &handle->last_ievent->event_id);
1430 }
1431
1432 if (!strncmp(hval, "ARRAY::", 7)) {
1433 esl_event_add_array(handle->last_ievent, hname, hval);
1434 } else {
1435 esl_event_add_header_string(handle->last_ievent, ESL_STACK_BOTTOM, hname, hval);
1436 }
1437 }
1438
1439 beg = c + 1;
1440
1441 if (*beg == '\n') {
1442 beg++;
1443 break;
1444 }
1445 }
1446
1447 if (beg && (cl = esl_event_get_header(handle->last_ievent, "content-length"))) {
1448 handle->last_ievent->body = strdup(beg);
1449 }
1450
1451 free(body);
1452
1453 if (esl_log_level >= 7) {
1454 char *foo;
1455 esl_event_serialize(handle->last_ievent, &foo, ESL_FALSE);
1456 esl_log(ESL_LOG_DEBUG, "RECV EVENT\n%s\n", foo);
1457 free(foo);
1458 }
1459 } else if (!esl_safe_strcasecmp(hval, "text/event-json")) {
1460 esl_event_create_json(&handle->last_ievent, revent->body);
1461 }
1462 }
1463
1464 if (esl_log_level >= 7) {
1465 char *foo;
1466 esl_event_serialize(revent, &foo, ESL_FALSE);
1467 esl_log(ESL_LOG_DEBUG, "RECV MESSAGE\n%s\n", foo);
1468 free(foo);
1469 }
1470 }
1471
1472 esl_mutex_unlock(handle->mutex);
1473
1474 return ESL_SUCCESS;
1475
1476 fail:
1477
1478 esl_mutex_unlock(handle->mutex);
1479
1480 handle->connected = 0;
1481
1482 return ESL_FAIL;
1483
1484 }
1485
esl_send(esl_handle_t * handle,const char * cmd)1486 ESL_DECLARE(esl_status_t) esl_send(esl_handle_t *handle, const char *cmd)
1487 {
1488 const char *e = cmd + strlen(cmd) -1;
1489
1490
1491 if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
1492 return ESL_FAIL;
1493 }
1494
1495 esl_log(ESL_LOG_DEBUG, "SEND\n%s\n", cmd);
1496
1497 if (send(handle->sock, cmd, strlen(cmd), 0) != (int)strlen(cmd)) {
1498 handle->connected = 0;
1499 if (!(strerror_r(handle->errnum, handle->err, sizeof(handle->err))))
1500 *(handle->err)=0;
1501 return ESL_FAIL;
1502 }
1503
1504 if (!(*e == '\n' && *(e-1) == '\n')) {
1505 if (send(handle->sock, "\n\n", 2, 0) != 2) {
1506 handle->connected = 0;
1507 if (!(strerror_r(handle->errnum, handle->err, sizeof(handle->err))))
1508 *(handle->err)=0;
1509 return ESL_FAIL;
1510 }
1511 }
1512
1513 return ESL_SUCCESS;
1514
1515 }
1516
1517
esl_send_recv_timed(esl_handle_t * handle,const char * cmd,uint32_t ms)1518 ESL_DECLARE(esl_status_t) esl_send_recv_timed(esl_handle_t *handle, const char *cmd, uint32_t ms)
1519 {
1520 const char *hval;
1521 esl_status_t status;
1522
1523 if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
1524 return ESL_FAIL;
1525 }
1526
1527 esl_mutex_lock(handle->mutex);
1528
1529 esl_event_safe_destroy(&handle->last_sr_event);
1530
1531 *handle->last_sr_reply = '\0';
1532
1533 if ((status = esl_send(handle, cmd))) {
1534 esl_mutex_unlock(handle->mutex);
1535 return status;
1536 }
1537
1538 recv:
1539
1540 esl_event_safe_destroy(&handle->last_sr_event);
1541
1542 *handle->last_sr_reply = '\0';
1543
1544 status = esl_recv_event_timed(handle, ms, 0, &handle->last_sr_event);
1545
1546 if (handle->last_sr_event) {
1547 char *ct = esl_event_get_header(handle->last_sr_event,"content-type");
1548
1549 if (ct && strcasecmp(ct, "api/response") && strcasecmp(ct, "command/reply")) {
1550 esl_event_t *ep;
1551
1552 for(ep = handle->race_event; ep && ep->next; ep = ep->next);
1553
1554 if (ep) {
1555 ep->next = handle->last_sr_event;
1556 } else {
1557 handle->race_event = handle->last_sr_event;
1558 }
1559
1560 handle->last_sr_event = NULL;
1561
1562 esl_mutex_unlock(handle->mutex);
1563 esl_mutex_lock(handle->mutex);
1564
1565 if (!handle->connected || handle->sock == ESL_SOCK_INVALID) {
1566 handle->connected = 0;
1567 esl_mutex_unlock(handle->mutex);
1568 return ESL_FAIL;
1569 }
1570
1571 goto recv;
1572 }
1573
1574 hval = esl_event_get_header(handle->last_sr_event, "reply-text");
1575
1576 if (!esl_strlen_zero(hval)) {
1577 snprintf(handle->last_sr_reply, sizeof(handle->last_sr_reply), "%s", hval);
1578 }
1579 }
1580
1581 esl_mutex_unlock(handle->mutex);
1582
1583 return status;
1584 }
1585
1586
esl_separate_string_string(char * buf,const char * delim,char ** array,unsigned int arraylen)1587 ESL_DECLARE(unsigned int) esl_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen)
1588 {
1589 unsigned int count = 0;
1590 char *d;
1591 size_t dlen = strlen(delim);
1592
1593 array[count++] = buf;
1594
1595 while (count < arraylen && array[count - 1]) {
1596 if ((d = strstr(array[count - 1], delim))) {
1597 *d = '\0';
1598 d += dlen;
1599 array[count++] = d;
1600 } else
1601 break;
1602 }
1603
1604 return count;
1605 }
1606
1607 /* For Emacs:
1608 * Local Variables:
1609 * mode:c
1610 * indent-tabs-mode:t
1611 * tab-width:4
1612 * c-basic-offset:4
1613 * End:
1614 * For VIM:
1615 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
1616 */
1617