diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index 403aafada5..02451dfdb0 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -37,7 +37,6 @@ #endif - /* Written by Marc Espie, public domain */ #define ESL_CTYPE_NUM_CHARS 256 @@ -181,6 +180,48 @@ ESL_DECLARE(const char *)esl_stristr(const char *instr, const char *str) #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; @@ -236,9 +277,10 @@ static const char *cut_path(const char *in) static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) { const char *fp; - char data[1024]; + char *data; va_list ap; - + int ret; + if (level < 0 || level > 7) { level = 7; } @@ -250,10 +292,12 @@ static void default_logger(const char *file, const char *func, int line, int lev va_start(ap, fmt); - vsnprintf(data, sizeof(data), fmt, ap); + ret = esl_vasprintf(&data, fmt, ap); - - fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data); + if (ret != -1) { + fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data); + free(data); + } va_end(ap); @@ -334,6 +378,14 @@ ESL_DECLARE(char *)esl_url_decode(char *s) return s; } +static void sock_setup(esl_handle_t *handle) +{ + int x = 1; + + setsockopt(handle->sock, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x)); + +} + ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t socket, struct sockaddr_in addr) { handle->sock = socket; @@ -350,9 +402,11 @@ ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t s handle->connected = 1; + sock_setup(handle); + esl_send_recv(handle, "connect\n\n"); - + if (handle->last_sr_event) { handle->info_event = handle->last_sr_event; handle->last_sr_event = NULL; @@ -413,6 +467,39 @@ ESL_DECLARE(esl_status_t) esl_execute(esl_handle_t *handle, const char *app, con return esl_send_recv(handle, send_buf); } + +ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value) +{ + char send_buf[1024] = ""; + + if (!handle->connected) { + return ESL_FAIL; + } + + snprintf(send_buf, sizeof(send_buf), "filter %s %s\n\n", header, value); + + return esl_send_recv(handle, send_buf); +} + + +ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etype, const char *value) +{ + char send_buf[1024] = ""; + const char *type = "plain"; + + if (!handle->connected) { + return ESL_FAIL; + } + + if (etype == ESL_EVENT_TYPE_XML) { + type = "xml"; + } + + snprintf(send_buf, sizeof(send_buf), "event %s %s\n\n", type, value); + + return esl_send_recv(handle, send_buf); +} + static int esl_socket_reuseaddr(esl_socket_t socket) { #ifdef WIN32 @@ -536,6 +623,8 @@ ESL_DECLARE(esl_status_t) esl_connect(esl_handle_t *handle, const char *host, es goto fail; } + sock_setup(handle); + handle->connected = 1; if (esl_recv(handle)) { diff --git a/libs/esl/src/esl_event.c b/libs/esl/src/esl_event.c index cb3af9c97b..92b1ff69ca 100644 --- a/libs/esl/src/esl_event.c +++ b/libs/esl/src/esl_event.c @@ -311,45 +311,6 @@ static esl_status_t esl_event_base_add_header(esl_event_t *event, esl_stack_t st return ESL_SUCCESS; } -int vasprintf(char **ret, const char *format, va_list ap); - -static 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(esl_status_t) esl_event_add_header(esl_event_t *event, esl_stack_t stack, const char *header_name, const char *fmt, ...) { int ret = 0; @@ -496,6 +457,8 @@ ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, es * the memory, allocate and only reallocate if we need more. This avoids an alloc, free CPU * destroying loop. */ + + new_len = (strlen(hp->value) * 3) + 1; if (encode_len < new_len) { @@ -575,6 +538,7 @@ ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, es snprintf(buf + len, dlen - len, "\n"); } + *str = buf; return ESL_SUCCESS; diff --git a/libs/esl/src/include/esl.h b/libs/esl/src/include/esl.h index 2905fc2f17..2abe03329b 100644 --- a/libs/esl/src/include/esl.h +++ b/libs/esl/src/include/esl.h @@ -42,6 +42,12 @@ typedef struct esl_event_header esl_event_header_t; typedef struct esl_event esl_event_t; + +typedef enum { + ESL_EVENT_TYPE_PLAIN, + ESL_EVENT_TYPE_XML +} esl_event_type_t; + #ifdef WIN32 #define ESL_SEQ_FWHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY #define ESL_SEQ_FRED FOREGROUND_RED | FOREGROUND_INTENSITY @@ -164,6 +170,7 @@ typedef struct esl_event esl_event_t; #include #include #ifndef WIN32 +#include #include #include #include @@ -290,6 +297,9 @@ typedef enum { #define ESL_LOG_EMERG ESL_PRE, ESL_LOG_LEVEL_EMERG typedef void (*esl_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...); + +ESL_DECLARE(int) esl_vasprintf(char **ret, const char *fmt, va_list ap); + ESL_DECLARE_DATA extern esl_logger_t esl_log; ESL_DECLARE(void) esl_global_set_logger(esl_logger_t logger); @@ -320,6 +330,9 @@ ESL_DECLARE(esl_status_t) esl_send(esl_handle_t *handle, const char *cmd); ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, esl_event_t **save_event); ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, esl_event_t **save_event); ESL_DECLARE(esl_status_t) esl_send_recv(esl_handle_t *handle, const char *cmd); +ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value); +ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etype, const char *value); + #define esl_recv(_h) esl_recv_event(_h, NULL) #define esl_recv_timed(_h, _ms) esl_recv_event_timed(_h, _ms, NULL) diff --git a/libs/esl/testserver.c b/libs/esl/testserver.c index 5f3a413665..c3e24f4ce0 100644 --- a/libs/esl/testserver.c +++ b/libs/esl/testserver.c @@ -5,23 +5,24 @@ static void mycallback(esl_socket_t server_sock, esl_socket_t client_sock, struct sockaddr_in addr) { esl_handle_t handle = {{0}}; - + if (fork()) { close(client_sock); return; } - esl_attach_handle(&handle, client_sock, addr); printf("Connected! %d\n", handle.sock); - + esl_filter(&handle, "unique-id", esl_event_get_header(handle.info_event, "caller-unique-id")); + esl_events(&handle, ESL_EVENT_TYPE_PLAIN, "SESSION_HEARTBEAT CHANNEL_ANSWER CHANNEL_ORIGINATE CHANNEL_PROGRESS CHANNEL_HANGUP " + "CHANNEL_BRIDGE CHANNEL_UNBRIDGE CHANNEL_OUTGOING CHANNEL_EXECUTE CHANNEL_EXECUTE_COMPLETE DTMF CUSTOM conference::maintenance"); esl_execute(&handle, "answer", NULL, NULL); - esl_execute(&handle, "playback", "/ram/swimp.raw", NULL); + esl_execute(&handle, "conference", "3000@default", NULL); - sleep(30); + while(esl_recv(&handle) == ESL_SUCCESS); esl_disconnect(&handle); } diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index a0a2dffc31..7a1d8b8462 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -946,6 +946,8 @@ SWITCH_DECLARE(switch_status_t) switch_thread_create(switch_thread_t **new_threa #define SWITCH_SO_SNDBUF 64 #define SWITCH_SO_RCVBUF 128 #define SWITCH_SO_DISCONNECTED 256 +#define SWITCH_SO_TCP_NODELAY 512 + /** * @def SWITCH_INET diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index cb9da8ba68..c586161ba2 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -74,7 +74,6 @@ struct listener { switch_core_session_t *session; int lost_events; int lost_logs; - int hup; time_t last_flush; uint32_t timeout; uint32_t id; @@ -385,6 +384,7 @@ SWITCH_STANDARD_APP(socket_function) } switch_socket_opt_set(new_sock, SWITCH_SO_KEEPALIVE, 1); + switch_socket_opt_set(new_sock, SWITCH_SO_TCP_NODELAY, 1); if (switch_socket_connect(new_sock, sa) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error!\n"); @@ -978,17 +978,6 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event, return SWITCH_STATUS_FALSE; } - if (switch_test_flag(listener, LFLAG_MYEVENTS) && !listener->hup && channel && !switch_channel_ready(channel)) { - listener->hup = 1; - } - - if (listener->hup == 2 || - ((!switch_test_flag(listener, LFLAG_MYEVENTS) && !switch_test_flag(listener, LFLAG_EVENTS)) && - channel && !switch_channel_ready(channel)) ) { - status = SWITCH_STATUS_FALSE; - break; - } - if (mlen) { bytes += mlen; do_sleep = 0; @@ -1124,9 +1113,9 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event, do_sleep = 0; } } - + if (switch_test_flag(listener, LFLAG_EVENTS)) { - if (switch_queue_trypop(listener->event_queue, &pop) == SWITCH_STATUS_SUCCESS) { + while (switch_queue_trypop(listener->event_queue, &pop) == SWITCH_STATUS_SUCCESS) { char hbuf[512]; switch_event_t *pevent = (switch_event_t *) pop; char *etype; @@ -1148,11 +1137,8 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event, } } - if (!listener->ebuf) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No event data (allocation error?)\n"); - goto endloop; - } - + switch_assert(listener->ebuf); + len = strlen(listener->ebuf); switch_snprintf(hbuf, sizeof(hbuf), "Content-Length: %" SWITCH_SSIZE_T_FMT "\n" "Content-Type: text/event-%s\n" "\n", len, etype); @@ -1162,22 +1148,21 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event, len = strlen(listener->ebuf); switch_socket_send(listener->sock, listener->ebuf, &len); - + switch_safe_free(listener->ebuf); - endloop: + endloop: - if (listener->hup == 1 && pevent->event_id == SWITCH_EVENT_CHANNEL_HANGUP) { - char *uuid = switch_event_get_header(pevent, "unique-id"); - if (!strcmp(uuid, switch_core_session_get_uuid(listener->session))) { - listener->hup = 2; - } - } - switch_event_destroy(&pevent); } } } + + if (channel && !switch_channel_ready(channel)) { + status = SWITCH_STATUS_FALSE; + break; + } + if (do_sleep) { switch_cond_next(); } @@ -1775,6 +1760,9 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) } } + switch_socket_opt_set(listener->sock, SWITCH_SO_TCP_NODELAY, TRUE); + switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE); + if (prefs.acl_count && listener->sa && !switch_strlen_zero(listener->remote_ip)) { uint32_t x = 0; @@ -1932,10 +1920,18 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) switch_mutex_unlock(listener->filter_mutex); if (listener->sock) { char disco_buf[512] = ""; - const char message[] = "Disconnected, goodbye!\nSee you at ClueCon http://www.cluecon.com/ !!!\n"; + const char message[] = "Disconnected, goodbye.\nSee you at ClueCon! http://www.cluecon.com/\n"; int mlen = strlen(message); - switch_snprintf(disco_buf, sizeof(disco_buf), "Content-Type: text/disconnect-notice\nContent-Length: %d\n\n", mlen); + if (listener->session) { + switch_snprintf(disco_buf, sizeof(disco_buf), "Content-Type: text/disconnect-notice\n" + "Controlled-Session-UUID: %s\n" + "Content-Length: %d\n\n", + switch_core_session_get_uuid(listener->session), mlen); + } else { + switch_snprintf(disco_buf, sizeof(disco_buf), "Content-Type: text/disconnect-notice\nContent-Length: %d\n\n", mlen); + } + len = strlen(disco_buf); switch_socket_send(listener->sock, disco_buf, &len); len = mlen; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index dfc7c8d1cc..34bd416ff4 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -453,7 +453,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *se switch_time_t b4, aftr; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Command Execute %s(%s)\n", - switch_channel_get_name(channel), app_name, app_arg); + switch_channel_get_name(channel), app_name, switch_str_nil(app_arg)); b4 = switch_timestamp_now(); switch_core_session_exec(session, application_interface, app_arg); aftr = switch_timestamp_now();