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