#include <switch_json.h>
#include <switch_stun.h>
-
/* Prototypes */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_verto_shutdown);
SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load);
SWITCH_MODULE_DEFINITION(mod_verto, mod_verto_load, mod_verto_shutdown, mod_verto_runtime);
+#define HTTP_CHUNK_SIZE 1024 * 32
#define EP_NAME "verto.rtc"
//#define WSS_STANDALONE 1
-#include "ws.h"
+#include "ks.h"
-//////////////////////////
#include <mod_verto.h>
#ifndef WIN32
#include <sys/param.h>
}
}
-static void close_file(ws_socket_t *sock)
+static void close_file(ks_socket_t *sock)
{
- if (*sock != ws_sock_invalid) {
+ if (*sock != KS_SOCK_INVALID) {
#ifndef WIN32
close(*sock);
#else
closesocket(*sock);
#endif
- *sock = ws_sock_invalid;
+ *sock = KS_SOCK_INVALID;
}
}
-static void close_socket(ws_socket_t *sock)
+static void close_socket(ks_socket_t *sock)
{
- if (*sock != ws_sock_invalid) {
+ if (*sock != KS_SOCK_INVALID) {
shutdown(*sock, 2);
close_file(sock);
}
free(log_text);
}
switch_mutex_lock(jsock->write_mutex);
- r = ws_write_frame(&jsock->ws, WSOC_TEXT, json_text, strlen(json_text));
+ r = kws_write_frame(jsock->ws, WSOC_TEXT, json_text, strlen(json_text));
switch_mutex_unlock(jsock->write_mutex);
switch_safe_free(json_text);
}
/* DO NOT use this unless you know what you are doing, you are WARNNED!!! */
static uint8_t *http_stream_read(switch_stream_handle_t *handle, int *len)
{
- switch_http_request_t *r = (switch_http_request_t *) handle->data;
+ kws_request_t *r = (kws_request_t *) handle->data;
jsock_t *jsock = r->user_data;
- wsh_t *wsh = &jsock->ws;
+ kws_t *wsh = jsock->ws;
+ uint8_t *buffer = NULL;
if (!jsock->profile->running) {
*len = 0;
return NULL;
}
- *len = (int)(r->bytes_buffered - r->bytes_read);
-
- if (*len > 0) { // we already read part of the body
- uint8_t *data = (uint8_t *)wsh->buffer + r->bytes_read;
- r->bytes_read = r->bytes_buffered;
- return data;
- }
-
- if (r->content_length && (r->bytes_read - r->bytes_header) >= r->content_length) {
- *len = 0;
- return NULL;
- }
-
- *len = (int)(r->content_length - (r->bytes_read - r->bytes_header));
- *len = *len > sizeof(wsh->buffer) ? wsh->buflen : *len;
-
- if ((*len = (int)ws_raw_read(wsh, wsh->buffer, *len, wsh->block)) < 0) {
+ *len = HTTP_CHUNK_SIZE;
+ if ((*len = (int)kws_read_buffer(wsh, &buffer, *len, 1)) < 0) {
*len = 0;
return NULL;
}
- r->bytes_read += *len;
-
- return (uint8_t *)wsh->buffer;
+ return buffer;
}
static switch_status_t http_stream_raw_write(switch_stream_handle_t *handle, uint8_t *data, switch_size_t datalen)
{
- switch_http_request_t *r = (switch_http_request_t *) handle->data;
+ kws_request_t *r = (kws_request_t *) handle->data;
jsock_t *jsock = r->user_data;
- return ws_raw_write(&jsock->ws, data, (uint32_t)datalen) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
+ return kws_raw_write(jsock->ws, data, (uint32_t)datalen) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
}
static switch_status_t http_stream_write(switch_stream_handle_t *handle, const char *fmt, ...)
{
- switch_http_request_t *r = (switch_http_request_t *) handle->data;
+ kws_request_t *r = (kws_request_t *) handle->data;
jsock_t *jsock = r->user_data;
int ret = 1;
char *data;
if (data) {
if (ret) {
- ret =(int) ws_raw_write(&jsock->ws, data, (uint32_t)strlen(data));
+ ret =(int) kws_raw_write(jsock->ws, data, (uint32_t)strlen(data));
}
switch_safe_free(data);
}
return ret ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
}
-static void http_static_handler(switch_http_request_t *request, verto_vhost_t *vhost)
+static void http_static_handler(kws_request_t *request, verto_vhost_t *vhost)
{
jsock_t *jsock = request->user_data;
char path[512];
char *ext;
uint8_t chunk[4096];
const char *mime_type = "text/html", *new_type;
+ switch_time_exp_t tm;
+ char date[80] = "";
+ switch_time_t ts = switch_micro_time_now();
+ switch_time_exp_lt(&tm, ts);
+ switch_rfc822_date(date, ts);
if (strncmp(request->method, "GET", 3) && strncmp(request->method, "HEAD", 4)) {
char *data = "HTTP/1.1 415 Method Not Allowed\r\n"
"Content-Length: 0\r\n\r\n";
- ws_raw_write(&jsock->ws, data, strlen(data));
+ kws_raw_write(jsock->ws, data, strlen(data));
return;
}
"Server: FreeSWITCH-%s-mod_verto\r\n"
"Content-Type: %s\r\n"
"Content-Length: %" SWITCH_SIZE_T_FMT "\r\n\r\n",
- switch_event_get_header(request->headers, "Event-Date-GMT"),
+ date,
switch_version_full(),
mime_type,
flen);
- ws_raw_write(&jsock->ws, chunk, strlen((char *)chunk));
+ kws_raw_write(jsock->ws, chunk, strlen((char *)chunk));
for (;;) {
switch_status_t status;
break;
}
- ws_raw_write(&jsock->ws, chunk, flen);
+ kws_raw_write(jsock->ws, chunk, flen);
}
switch_file_close(fd);
} else {
char *data = "HTTP/1.1 404 Not Found\r\n"
"Content-Length: 0\r\n\r\n";
- ws_raw_write(&jsock->ws, data, strlen(data));
+ kws_raw_write(jsock->ws, data, strlen(data));
+ }
+}
+
+static void request_headers_to_event(switch_event_t *event, kws_request_t *request)
+{
+ int i;
+
+ for (i = 0; i < KWS_MAX_HEADERS; i++) {
+ if (!request->headers_k[i]) break;
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, request->headers_k[i], request->headers_v[i]);
}
}
static void http_run(jsock_t *jsock)
{
- switch_http_request_t request = { 0 };
+ kws_request_t *request = NULL;
switch_stream_handle_t stream = { 0 };
char *err = NULL;
char *ext;
verto_vhost_t *vhost;
- switch_bool_t keepalive;
+ ks_bool_t keepalive;
new_req:
-
- request.user_data = jsock;
-
if (switch_event_create(&stream.param_event, SWITCH_EVENT_CHANNEL_DATA) != SWITCH_STATUS_SUCCESS) {
goto err;
}
- request.headers = stream.param_event;
- if (switch_http_parse_header(jsock->ws.buffer, (uint32_t)jsock->ws.datalen, &request) != SWITCH_STATUS_SUCCESS) {
- switch_event_destroy(&stream.param_event);
+ if (kws_parse_header(jsock->ws, &request) != KS_STATUS_SUCCESS) {
goto err;
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s [%4" SWITCH_SIZE_T_FMT "] %s\n", jsock->name, jsock->ws.datalen, request.uri);
+ request->user_data = jsock;
- if (!strncmp(request.method, "OPTIONS", 7)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s %s\n", jsock->name, request->uri);
+
+ if (!strncmp(request->method, "OPTIONS", 7)) {
char data[512];
switch_snprintf(data, sizeof(data),
"HTTP/1.1 200 OK\r\n"
"Date: %s\r\n"
"Allow: HEAD,GET,POST,PUT,DELETE,PATCH,OPTIONS\r\n"
"Server: FreeSWITCH-%s-mod_verto\r\n\r\n",
- switch_event_get_header(request.headers, "Event-Date-GMT"),
+ switch_event_get_header(stream.param_event, "Event-Date-GMT"),
switch_version_full());
- ws_raw_write(&jsock->ws, data, strlen(data));
+ kws_raw_write(jsock->ws, data, strlen(data));
goto done;
}
- if (!strncmp(request.method, "POST", 4) && request.content_length && request.content_type &&
- !strncmp(request.content_type, "application/x-www-form-urlencoded", 33)) {
+ if (request->content_length && request->content_length > 5l * 1024 * 1024 * 1024 - 1) {
+ char *data = "HTTP/1.1 413 Request Entity Too Large\r\n"
+ "Content-Length: 0\r\n\r\n";
+ kws_raw_write(jsock->ws, data, strlen(data));
+ request->keepalive = 0;
+ goto done;
+ }
+
+ if (!strncmp(request->method, "POST", 4) && request->content_length && request->content_type &&
+ !strncmp(request->content_type, "application/x-www-form-urlencoded", 33)) {
char *buffer = NULL;
switch_ssize_t len = 0, bytes = 0;
- if (request.content_length > 2 * 1024 * 1024 - 1) {
+ if (request->content_length && request->content_length > 10 * 1024 * 1024 - 1) {
char *data = "HTTP/1.1 413 Request Entity Too Large\r\n"
"Content-Length: 0\r\n\r\n";
- ws_raw_write(&jsock->ws, data, strlen(data));
+ kws_raw_write(jsock->ws, data, strlen(data));
+ request->keepalive = 0;
goto done;
}
goto request_err;
}
- if ((bytes = request.bytes_buffered - request.bytes_read) > 0) {
- memcpy(buffer, jsock->ws.buffer + request.bytes_read, bytes);
- }
+ while(bytes < (switch_ssize_t)request->content_length) {
+ len = request->content_length - bytes;
- while(bytes < (switch_ssize_t)request.content_length) {
- len = request.content_length - bytes;
+#define WS_BLOCK 1
- if ((len = ws_raw_read(&jsock->ws, buffer + bytes, len, jsock->ws.block)) < 0) {
+ if ((len = kws_raw_read(jsock->ws, buffer + bytes, len, WS_BLOCK)) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Read error %" SWITCH_SSIZE_T_FMT"\n", len);
goto done;
}
*(buffer + bytes) = '\0';
- switch_http_parse_qs(&request, buffer);
+ kws_parse_qs(request, buffer);
free(buffer);
}
- // switch_http_dump_request(&request);
+ // kws_request_dump(request);
- stream.data = &request;
+ stream.data = request;
stream.read_function = http_stream_read;
stream.write_function = http_stream_write;
stream.raw_write_function = http_stream_raw_write;
+ request_headers_to_event(stream.param_event, request);
- switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "Request-Method", request.method);
- switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-Request-URI", request.uri);
+ switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Request-Method", request->method);
+ switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-Request-URI", request->uri);
if (!jsock->profile->vhosts) goto err;
int code = CODE_AUTH_REQUIRED;
char message[128] = "Authentication Required";
cJSON *params = NULL;
- char *www_auth;
+ const char *www_auth;
char auth_buffer[512];
char *auth_user = NULL, *auth_pass = NULL;
- www_auth = switch_event_get_header(request.headers, "Authorization");
+ www_auth = request->authorization;
if (zstr(www_auth)) {
switch_snprintf(auth_buffer, sizeof(auth_buffer),
"WWW-Authenticate: Basic realm=\"%s\"\r\n"
"Content-Length: 0\r\n\r\n",
vhost->auth_realm);
- ws_raw_write(&jsock->ws, auth_buffer, strlen(auth_buffer));
+ kws_raw_write(jsock->ws, auth_buffer, strlen(auth_buffer));
goto done;
}
"WWW-Authenticate: Basic realm=\"%s\"\r\n"
"Content-Length: 0\r\n\r\n",
vhost->auth_realm);
- ws_raw_write(&jsock->ws, auth_buffer, strlen(auth_buffer));
+ kws_raw_write(jsock->ws, auth_buffer, strlen(auth_buffer));
cJSON_Delete(params);
goto done;
} else {
authed:
switch_set_flag(jsock, JPFLAG_AUTHED);
- switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-USER", auth_user);
+ switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-USER", auth_user);
}
if (vhost->rewrites) {
while(rule) {
char *expression = rule->name;
- if ((proceed = switch_regex_perform(request.uri, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
+ if ((proceed = switch_regex_perform(request->uri, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
- "%d request [%s] matched expr [%s]\n", proceed, request.uri, expression);
- request.uri = rule->value;
+ "%d request [%s] matched expr [%s]\n", proceed, request->uri, expression);
+ request->uri = rule->value;
break;
}
}
}
- switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-URI", request.uri);
+ switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-URI", request->uri);
- if ((ext = strrchr(request.uri, '.'))) {
+ if ((ext = strrchr(request->uri, '.'))) {
char path[1024];
if (!strncmp(ext, ".lua", 4)) {
- switch_snprintf(path, sizeof(path), "%s%s", vhost->script_root, request.uri);
+ switch_snprintf(path, sizeof(path), "%s%s", vhost->script_root, request->uri);
switch_api_execute("lua", path, NULL, &stream);
} else {
- http_static_handler(&request, vhost);
+ http_static_handler(request, vhost);
}
-
} else {
- http_static_handler(&request, vhost);
+ http_static_handler(request, vhost);
}
done:
- keepalive = request.keepalive;
- switch_http_free_request(&request);
+ keepalive = request->keepalive;
+ kws_request_free(&request);
if (keepalive) {
- wsh_t *wsh = &jsock->ws;
-
- memset(&request, 0, sizeof(request));
- wsh->datalen = 0;
- *wsh->buffer = '\0';
+ kws_t *wsh = jsock->ws;
while(jsock->profile->running) {
- int pflags;
-
- if (wsh->ssl && SSL_pending(wsh->ssl) > 0) {
- pflags = SWITCH_POLL_READ;
- } else {
- pflags = switch_wait_sock(jsock->client_socket, 3000, SWITCH_POLL_READ | SWITCH_POLL_ERROR | SWITCH_POLL_HUP);
- }
+ int pflags = kws_wait_sock(wsh, 3000, KS_POLL_READ | KS_POLL_ERROR | KS_POLL_HUP);
if (jsock->drop) { die("%s Dropping Connection\n", jsock->name); }
if (pflags < 0 && (errno != EINTR)) { die_errnof("%s POLL FAILED with %d", jsock->name, pflags); }
if (pflags == 0) { /* keepalive socket poll timeout */ break; }
- if (pflags > 0 && (pflags & SWITCH_POLL_HUP)) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); }
- if (pflags > 0 && (pflags & SWITCH_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name); }
- if (pflags > 0 && (pflags & SWITCH_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); }
- if (pflags > 0 && (pflags & SWITCH_POLL_READ)) {
- ssize_t bytes;
-
- bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen - 1, wsh->block);
-
- if (bytes < 0) {
- die("%s BAD READ %" SWITCH_SIZE_T_FMT "\n", jsock->name, bytes);
- break;
- }
-
- if (bytes == 0) {
- bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen - 1, wsh->block);
-
- if (bytes < 0) {
- die("%s BAD READ %" SWITCH_SIZE_T_FMT "\n", jsock->name, bytes);
- break;
- }
-
- if (bytes == 0) { // socket broken ?
- break;
- }
- }
-
- wsh->datalen += bytes;
- *(wsh->buffer + wsh->datalen) = '\0';
-
- if (strstr(wsh->buffer, "\r\n\r\n") || strstr(wsh->buffer, "\n\n")) {
+ if (pflags > 0 && (pflags & KS_POLL_HUP)) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); }
+ if (pflags > 0 && (pflags & KS_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name); }
+ if (pflags > 0 && (pflags & KS_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); }
+ if (pflags > 0 && (pflags & KS_POLL_READ)) {
+ if (kws_keepalive(wsh) == KS_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "socket %s is going to handle a new request\n", jsock->name);
goto new_req;
+ } else {
+ // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Read Error\n");
+ break;
}
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unhandled flag: %d\n", pflags);
}
}
}
return;
request_err:
- switch_http_free_request(&request);
+ kws_request_free(&request);
err:
err = "HTTP/1.1 500 Internal Server Error\r\n"
"Content-Length: 0\r\n\r\n";
- ws_raw_write(&jsock->ws, err, strlen(err));
+ kws_raw_write(jsock->ws, err, strlen(err));
error:
return;
static void client_run(jsock_t *jsock)
{
- if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1, !!jsock->profile->vhosts) < 0) {
- if (jsock->profile->vhosts) {
- http_run(jsock);
- ws_close(&jsock->ws, WS_NONE);
- goto error;
- } else {
- log_and_exit(SWITCH_LOG_NOTICE, "%s WS SETUP FAILED\n", jsock->name);
- }
+ int flags = KWS_BLOCK;
+
+ if (jsock->profile->vhosts) {
+ flags |= KWS_STAY_OPEN;
+ flags |= KWS_HTTP;
+ }
+
+ ks_pool_open(&jsock->kpool);
+ if (kws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, flags, jsock->kpool) != KS_STATUS_SUCCESS) {
+ log_and_exit(SWITCH_LOG_NOTICE, "%s WS SETUP FAILED\n", jsock->name);
+ }
+
+ if (kws_test_flag(jsock->ws, KWS_HTTP)) {
+ http_run(jsock);
+ kws_close(jsock->ws, WS_NONE);
+ goto end;
}
while(jsock->profile->running) {
int pflags;
- if (jsock->ws.ssl && SSL_pending(jsock->ws.ssl) > 0) {
- pflags = SWITCH_POLL_READ;
- } else {
- pflags = switch_wait_sock(jsock->client_socket, 50, SWITCH_POLL_READ | SWITCH_POLL_ERROR | SWITCH_POLL_HUP);
- }
+ if (!jsock->ws) { die("%s Setup Error\n", jsock->name); }
+
+ pflags = kws_wait_sock(jsock->ws, 50, KS_POLL_READ | KS_POLL_ERROR | KS_POLL_HUP);
if (jsock->drop) { die("%s Dropping Connection\n", jsock->name); }
if (pflags < 0 && (errno != EINTR)) { die_errnof("%s POLL FAILED with %d", jsock->name, pflags); }
if (pflags == 0) {/* socket poll timeout */ jsock_check_event_queue(jsock); }
- if (pflags > 0 && (pflags & SWITCH_POLL_HUP)) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); }
- if (pflags > 0 && (pflags & SWITCH_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name); }
- if (pflags > 0 && (pflags & SWITCH_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); }
- if (pflags > 0 && (pflags & SWITCH_POLL_READ)) {
+ if (pflags > 0 && (pflags & KS_POLL_HUP)) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); }
+ if (pflags > 0 && (pflags & KS_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name); }
+ if (pflags > 0 && (pflags & KS_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); }
+ if (pflags > 0 && (pflags & KS_POLL_READ)) {
switch_ssize_t bytes;
- ws_opcode_t oc;
+ kws_opcode_t oc;
uint8_t *data;
- bytes = ws_read_frame(&jsock->ws, &oc, &data);
+ bytes = kws_read_frame(jsock->ws, &oc, &data);
if (bytes < 0) {
- if (bytes == -WS_RECV_CLOSE) {
+ if (bytes == -1000) {
log_and_exit(SWITCH_LOG_INFO, "%s Client sent close request\n", jsock->name);
} else {
die("%s BAD READ %" SWITCH_SSIZE_T_FMT "\n", jsock->name, bytes);
a = switch_time_now();
do {
- bytes = ws_read_frame(&jsock->ws, &oc, &data);
+ bytes = kws_read_frame(jsock->ws, &oc, &data);
s = (char *) data;
} while (bytes && data && s[0] == '#' && s[3] == 'B');
b = switch_time_now();
if (s[0] != '#') goto nm;
switch_snprintf(repl, sizeof(repl), "#SPU %ld", (long)((b - a) / 1000));
- ws_write_frame(&jsock->ws, WSOC_TEXT, repl, strlen(repl));
+ kws_write_frame(jsock->ws, WSOC_TEXT, repl, strlen(repl));
loops = size / 1024;
rem = size % 1024;
switch_snprintf(repl, sizeof(repl), "#SPB ");
int ddur = 0;
a = switch_time_now();
for (i = 0; i < loops; i++) {
- ws_write_frame(&jsock->ws, WSOC_TEXT, repl, 1024);
+ kws_write_frame(jsock->ws, WSOC_TEXT, repl, 1024);
}
if (rem) {
- ws_write_frame(&jsock->ws, WSOC_TEXT, repl, rem);
+ kws_write_frame(jsock->ws, WSOC_TEXT, repl, rem);
}
b = switch_time_now();
ddur += (int)((b - a) / 1000);
dur /= j+1;
switch_snprintf(repl, sizeof(repl), "#SPD %d", dur);
- ws_write_frame(&jsock->ws, WSOC_TEXT, repl, strlen(repl));
+ kws_write_frame(jsock->ws, WSOC_TEXT, repl, strlen(repl));
}
}
}
error:
-
+ end:
detach_jsock(jsock);
- ws_destroy(&jsock->ws);
-
+ kws_destroy(&jsock->ws);
+ ks_pool_close(&jsock->kpool);
return;
}
switch_event_destroy(&jsock->vars);
switch_event_destroy(&jsock->user_vars);
- if (jsock->client_socket != ws_sock_invalid) {
+ if (jsock->client_socket != KS_SOCK_INVALID) {
close_socket(&jsock->client_socket);
}
switch_event_channel_broadcast(event_channel, &jevent, modname, verto_globals.event_channel_id);
}
- if (jsock->profile->mcast_pub.sock != ws_sock_invalid) {
+ if (jsock->profile->mcast_pub.sock != KS_SOCK_INVALID) {
if ((json_text = cJSON_PrintUnformatted(params))) {
if (mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1) <= 0) {
-static int start_jsock(verto_profile_t *profile, ws_socket_t sock, int family)
+static int start_jsock(verto_profile_t *profile, ks_socket_t sock, int family)
{
jsock_t *jsock = NULL;
int flag = 1;
error:
if (jsock) {
- if (jsock->client_socket != ws_sock_invalid) {
+ if (jsock->client_socket != KS_SOCK_INVALID) {
close_socket(&jsock->client_socket);
}
return -1;
}
-static ws_socket_t prepare_socket(ips_t *ips)
+static ks_socket_t prepare_socket(ips_t *ips)
{
- ws_socket_t sock = ws_sock_invalid;
+ ks_socket_t sock = KS_SOCK_INVALID;
#ifndef WIN32
int reuse_addr = 1;
#else
close_file(&sock);
- return ws_sock_invalid;
+ return KS_SOCK_INVALID;
}
static void handle_mcast_sub(verto_profile_t *profile)
{
int bytes;
- if (profile->mcast_sub.sock == ws_sock_invalid) {
+ if (profile->mcast_sub.sock == KS_SOCK_INVALID) {
return;
}
for (i = 0; i < profile->i; i++) {
//if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) {
- if ((profile->server_socket[i] = prepare_socket(&profile->ip[i])) != ws_sock_invalid) {
+ if ((profile->server_socket[i] = prepare_socket(&profile->ip[i])) != KS_SOCK_INVALID) {
listeners++;
}
}
error:
- if (profile->mcast_sub.sock != ws_sock_invalid) {
+ if (profile->mcast_sub.sock != KS_SOCK_INVALID) {
mcast_socket_close(&profile->mcast_sub);
}
- if (profile->mcast_pub.sock != ws_sock_invalid) {
+ if (profile->mcast_pub.sock != KS_SOCK_INVALID) {
mcast_socket_close(&profile->mcast_pub);
}
profile->local_network = "localnet.auto";
- profile->mcast_sub.sock = ws_sock_invalid;
- profile->mcast_pub.sock = ws_sock_invalid;
+ profile->mcast_sub.sock = KS_SOCK_INVALID;
+ profile->mcast_pub.sock = KS_SOCK_INVALID;
for (param = switch_xml_child(xprofile, "param"); param; param = param->next) {
if (tmp > 0) {
verto_globals.detach_timeout = tmp;
}
+ } else if (!strcasecmp(var, "kslog")) {
+ if (val) {
+ verto_globals.kslog_on = switch_true(val);
+ }
}
}
}
for (i = 0; i < profile->i; i++) {
char *tmpurl = switch_mprintf(strchr(profile->ip[i].local_ip, ':') ? "%s:[%s]:%d" : "%s:%s:%d",
(profile->ip[i].secure == 1) ? "wss" : "ws", profile->ip[i].local_ip, profile->ip[i].local_port);
- stream->write_function(stream, "%25s\t%s\t %40s\t%s\n", profile->name, "profile", tmpurl, (profile->server_socket[i] != ws_sock_invalid) ? "RUNNING" : "DOWN");
+ stream->write_function(stream, "%25s\t%s\t %40s\t%s\n", profile->name, "profile", tmpurl, (profile->server_socket[i] != KS_SOCK_INVALID) ? "RUNNING" : "DOWN");
switch_safe_free(tmpurl);
}
cp++;
}
+static void mod_verto_ks_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ char fmt_buf[32768];
+ va_list ap;
+ size_t len;
+ va_start(ap, fmt);
+
+ len = snprintf(fmt_buf, sizeof(fmt_buf), "%s\n", fmt); // add return that is missing
+
+ if (level == SWITCH_LOG_DEBUG) level = SWITCH_LOG_DEBUG1;
+
+ if (len < sizeof(fmt_buf)) {
+ switch_log_vprintf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, level, fmt_buf, ap);
+ } else {
+ switch_log_vprintf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, level, fmt, ap);
+ }
+ va_end(ap);
+}
+
/* Macro expands to: switch_status_t mod_verto_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load)
{
switch_cache_db_handle_t *dbh;
//switch_application_interface_t *app_interface = NULL;
+ ks_ssl_init_skip(KS_TRUE);
+ ks_init();
if (switch_event_reserve_subclass(MY_EVENT_LOGIN) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_LOGIN);
if (r) return SWITCH_STATUS_TERM;
+ if (verto_globals.kslog_on == SWITCH_TRUE) {
+ ks_global_set_logger(mod_verto_ks_logger);
+ ks_log(KS_LOG_INFO, "ks log registered in mod_verto\n");
+ }
+
jrpc_init();
/* connect my internal structure to the blank pointer passed to me */
switch_core_hash_destroy(&verto_globals.event_channel_hash);
switch_core_hash_destroy(&verto_globals.jsock_hash);
+ ks_global_set_logger(NULL);
+ ks_shutdown();
+
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_TERM;
}
-
/* For Emacs:
* Local Variables:
* mode:c
+++ /dev/null
-#include <switch.h>
-#include "ws.h"
-#include <pthread.h>
-
-#ifndef _MSC_VER
-#include <fcntl.h>
-#endif
-
-#if defined(__linux__) || defined(__GLIBC__)
-#include <byteswap.h>
-#endif
-
-#ifndef _MSC_VER
-#define ms_sleep(x) usleep( x * 1000);
-#else
-#define ms_sleep(x) Sleep( x );
-#endif
-
-#ifdef _MSC_VER
-/* warning C4706: assignment within conditional expression*/
-#pragma warning(disable: 4706)
-#endif
-
-#define WS_BLOCK 1
-#define WS_NOBLOCK 0
-
-#define WS_INIT_SANITY 5000
-#define WS_WRITE_SANITY 200
-
-#define SHA1_HASH_SIZE 20
-static struct ws_globals_s ws_globals;
-
-#ifndef WSS_STANDALONE
-
-void init_ssl(void)
-{
- // SSL_library_init();
-}
-void deinit_ssl(void)
-{
- return;
-}
-
-#else
-static void pthreads_thread_id(CRYPTO_THREADID *id);
-static void pthreads_locking_callback(int mode, int type, const char *file, int line);
-
-static pthread_mutex_t *lock_cs;
-static long *lock_count;
-
-
-
-static void thread_setup(void)
-{
- int i;
-
- lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
- lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
-
- for (i = 0; i < CRYPTO_num_locks(); i++) {
- lock_count[i] = 0;
- pthread_mutex_init(&(lock_cs[i]), NULL);
- }
-
- CRYPTO_THREADID_set_callback(pthreads_thread_id);
- CRYPTO_set_locking_callback(pthreads_locking_callback);
-}
-
-static void thread_cleanup(void)
-{
- int i;
-
- CRYPTO_set_locking_callback(NULL);
-
- for (i=0; i<CRYPTO_num_locks(); i++) {
- pthread_mutex_destroy(&(lock_cs[i]));
- }
- OPENSSL_free(lock_cs);
- OPENSSL_free(lock_count);
-
-}
-
-static void pthreads_locking_callback(int mode, int type, const char *file, int line)
-{
-
- if (mode & CRYPTO_LOCK) {
- pthread_mutex_lock(&(lock_cs[type]));
- lock_count[type]++;
- } else {
- pthread_mutex_unlock(&(lock_cs[type]));
- }
-}
-
-
-
-static void pthreads_thread_id(CRYPTO_THREADID *id)
-{
- CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self());
-}
-
-
-void init_ssl(void) {
- SSL_library_init();
-
-
- OpenSSL_add_all_algorithms(); /* load & register cryptos */
- SSL_load_error_strings(); /* load all error messages */
- ws_globals.ssl_method = SSLv23_server_method(); /* create server instance */
- ws_globals.ssl_ctx = SSL_CTX_new(ws_globals.ssl_method); /* create context */
- assert(ws_globals.ssl_ctx);
-
- /* Disable SSLv2 */
- SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_SSLv2);
- /* Disable SSLv3 */
- SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_SSLv3);
- /* Disable TLSv1 */
- SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_TLSv1);
- /* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */
- SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_COMPRESSION);
- /* set the local certificate from CertFile */
- SSL_CTX_use_certificate_file(ws_globals.ssl_ctx, ws_globals.cert, SSL_FILETYPE_PEM);
- /* set the private key from KeyFile */
- SSL_CTX_use_PrivateKey_file(ws_globals.ssl_ctx, ws_globals.key, SSL_FILETYPE_PEM);
- /* verify private key */
- if ( !SSL_CTX_check_private_key(ws_globals.ssl_ctx) ) {
- abort();
- }
-
- SSL_CTX_set_cipher_list(ws_globals.ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH");
-
- thread_setup();
-}
-
-
-void deinit_ssl(void) {
- thread_cleanup();
-}
-
-#endif
-
-static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-
-static int cheezy_get_var(char *data, char *name, char *buf, size_t buflen)
-{
- char *p=data;
-
- /* the old way didnt make sure that variable values were used for the name hunt
- * and didnt ensure that only a full match of the variable name was used
- */
-
- do {
- if(!strncasecmp(p,name,strlen(name)) && *(p+strlen(name))==':') break;
- } while((p = (strstr(p,"\n")+1))!=(char *)1);
-
-
- if (p && p != (char *)1 && *p!='\0') {
- char *v, *e = 0;
-
- v = strchr(p, ':');
- if (v) {
- v++;
- while(v && *v == ' ') {
- v++;
- }
- if (v) {
- e = strchr(v, '\r');
- if (!e) {
- e = strchr(v, '\n');
- }
- }
-
- if (v && e) {
- int cplen;
- size_t len = e - v;
-
- if (len > buflen - 1) {
- cplen = buflen -1;
- } else {
- cplen = len;
- }
-
- strncpy(buf, v, cplen);
- *(buf+cplen) = '\0';
- return 1;
- }
-
- }
- }
- return 0;
-}
-
-static int b64encode(unsigned char *in, size_t ilen, unsigned char *out, size_t olen)
-{
- int y=0,bytes=0;
- size_t x=0;
- unsigned int b=0,l=0;
-
- if(olen) {
- }
-
- for(x=0;x<ilen;x++) {
- b = (b<<8) + in[x];
- l += 8;
- while (l >= 6) {
- out[bytes++] = c64[(b>>(l-=6))%64];
- if(++y!=72) {
- continue;
- }
- //out[bytes++] = '\n';
- y=0;
- }
- }
-
- if (l > 0) {
- out[bytes++] = c64[((b%16)<<(6-l))%64];
- }
- if (l != 0) while (l < 6) {
- out[bytes++] = '=', l += 2;
- }
-
- return 0;
-}
-
-#ifdef NO_OPENSSL
-static void sha1_digest(char *digest, unsigned char *in)
-{
- SHA1Context sha;
- char *p;
- int x;
-
-
- SHA1Init(&sha);
- SHA1Update(&sha, in, strlen(in));
- SHA1Final(&sha, digest);
-}
-#else
-
-static void sha1_digest(unsigned char *digest, char *in)
-{
- SHA_CTX sha;
-
- SHA1_Init(&sha);
- SHA1_Update(&sha, in, strlen(in));
- SHA1_Final(digest, &sha);
-
-}
-
-#endif
-
-int ws_handshake(wsh_t *wsh)
-{
- char key[256] = "";
- char version[5] = "";
- char proto[256] = "";
- char proto_buf[384] = "";
- char input[512] = "";
- unsigned char output[SHA1_HASH_SIZE] = "";
- char b64[256] = "";
- char respond[1024] = "";
- ssize_t bytes;
- char *p, *e = 0;
-
- if (wsh->sock == ws_sock_invalid) {
- return -3;
- }
-
- while((bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen, WS_BLOCK)) > 0) {
- wsh->datalen += bytes;
- if (strstr(wsh->buffer, "\r\n\r\n") || strstr(wsh->buffer, "\n\n")) {
- break;
- }
- }
-
- if (bytes < 0 || bytes > wsh->buflen -1) {
- goto err;
- }
-
- *(wsh->buffer + wsh->datalen) = '\0';
-
- if (strncasecmp(wsh->buffer, "GET ", 4)) {
- goto err;
- }
-
- p = wsh->buffer + 4;
-
- e = strchr(p, ' ');
- if (!e) {
- goto err;
- }
-
- wsh->uri = malloc((e-p) + 1);
-
- if (!wsh->uri) goto err;
-
- strncpy(wsh->uri, p, e-p);
- *(wsh->uri + (e-p)) = '\0';
-
- cheezy_get_var(wsh->buffer, "Sec-WebSocket-Key", key, sizeof(key));
- cheezy_get_var(wsh->buffer, "Sec-WebSocket-Version", version, sizeof(version));
- cheezy_get_var(wsh->buffer, "Sec-WebSocket-Protocol", proto, sizeof(proto));
-
- if (!*key) {
- goto err;
- }
-
- snprintf(input, sizeof(input), "%s%s", key, WEBSOCKET_GUID);
- sha1_digest(output, input);
- b64encode((unsigned char *)output, SHA1_HASH_SIZE, (unsigned char *)b64, sizeof(b64));
-
- if (*proto) {
- snprintf(proto_buf, sizeof(proto_buf), "Sec-WebSocket-Protocol: %s\r\n", proto);
- }
-
- snprintf(respond, sizeof(respond),
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: %s\r\n"
- "%s\r\n",
- b64,
- proto_buf);
- respond[511] = 0;
-
- if (ws_raw_write(wsh, respond, strlen(respond)) != (ssize_t)strlen(respond)) {
- goto err;
- }
-
- wsh->handshake = 1;
-
- return 0;
-
- err:
-
- if (!wsh->stay_open) {
-
- if (bytes > 0) {
- snprintf(respond, sizeof(respond), "HTTP/1.1 400 Bad Request\r\n"
- "Sec-WebSocket-Version: 13\r\n\r\n");
- respond[511] = 0;
-
- ws_raw_write(wsh, respond, strlen(respond));
- }
-
- ws_close(wsh, WS_NONE);
- }
-
- return -1;
-
-}
-
-#define SSL_WANT_READ_WRITE(err) (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
-
-ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block)
-{
- ssize_t r;
- int ssl_err = 0;
-
- wsh->x++;
- if (wsh->x > 250) ms_sleep(1);
-
- if (wsh->ssl) {
- do {
- r = SSL_read(wsh->ssl, data, bytes);
-
- if (r < 0) {
- ssl_err = SSL_get_error(wsh->ssl, r);
-
- if (SSL_WANT_READ_WRITE(ssl_err)) {
- if (!block) {
- r = -2;
- goto end;
- }
- wsh->x++;
- ms_sleep(10);
- } else {
- r = -1;
- goto end;
- }
- }
-
- } while (r < 0 && SSL_WANT_READ_WRITE(ssl_err) && wsh->x < 1000);
-
- goto end;
- }
-
- do {
-
- r = recv(wsh->sock, data, bytes, 0);
-
- if (r == -1) {
- if (!block && xp_is_blocking(xp_errno())) {
- r = -2;
- goto end;
- }
-
- if (block) {
- wsh->x++;
- ms_sleep(10);
- }
- }
- } while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 1000);
-
- end:
-
- if (wsh->x >= 10000 || (block && wsh->x >= 1000)) {
- r = -1;
- }
-
- if (r > 0) {
- *((char *)data + r) = '\0';
- }
-
- if (r >= 0) {
- wsh->x = 0;
- }
-
- return r;
-}
-
-/*
- * Blocking read until bytes have been received, failure, or too many retries.
- */
-static ssize_t ws_raw_read_blocking(wsh_t *wsh, char *data, size_t max_bytes, int max_retries)
-{
- ssize_t total_bytes_read = 0;
- while (total_bytes_read < max_bytes && max_retries-- > 0) {
- ssize_t bytes_read = ws_raw_read(wsh, data + total_bytes_read, max_bytes - total_bytes_read, WS_BLOCK);
- if (bytes_read < 0) {
- break;
- }
- total_bytes_read += bytes_read;
- }
- return total_bytes_read;
-}
-
-
-ssize_t ws_raw_write(wsh_t *wsh, void *data, size_t bytes)
-{
- ssize_t r;
- int sanity = WS_WRITE_SANITY;
- int ssl_err = 0;
- size_t wrote = 0;
-
- if (wsh->ssl) {
- do {
- r = SSL_write(wsh->ssl, (void *)((unsigned char *)data + wrote), bytes - wrote);
-
- if (r == 0) {
- ssl_err = 42;
- break;
- }
-
- if (r > 0) {
- wrote += r;
- }
-
- if (sanity < WS_WRITE_SANITY) {
- int ms = 1;
-
- if (wsh->block) {
- if (sanity < WS_WRITE_SANITY / 2) {
- ms = 25;
- } else if (sanity < WS_WRITE_SANITY * 3 / 4) {
- ms = 50;
- }
- }
- ms_sleep(ms);
- }
-
- if (r < 0) {
- ssl_err = SSL_get_error(wsh->ssl, r);
-
- if (!SSL_WANT_READ_WRITE(ssl_err)) {
- break;
- }
- ssl_err = 0;
- }
-
- } while (--sanity > 0 && wrote < bytes);
-
- if (!sanity) ssl_err = 56;
-
- if (ssl_err) {
- r = ssl_err * -1;
- }
-
- return r;
- }
-
- do {
- r = send(wsh->sock, (void *)((unsigned char *)data + wrote), bytes - wrote, 0);
-
- if (r > 0) {
- wrote += r;
- }
-
- if (sanity < WS_WRITE_SANITY) {
- int ms = 1;
-
- if (wsh->block) {
- if (sanity < WS_WRITE_SANITY / 2) {
- ms = 25;
- } else if (sanity < WS_WRITE_SANITY * 3 / 4) {
- ms = 50;
- }
- }
- ms_sleep(ms);
- }
-
- if (r == -1) {
- if (!xp_is_blocking(xp_errno())) {
- break;
- }
- }
-
- } while (--sanity > 0 && wrote < bytes);
-
- //if (r<0) {
- //printf("wRITE FAIL: %s\n", strerror(errno));
- //}
-
- return r < 0 ? r : wrote;
-}
-
-#ifdef _MSC_VER
-static int setup_socket(ws_socket_t sock)
-{
- unsigned long v = 1;
-
- if (ioctlsocket(sock, FIONBIO, &v) == SOCKET_ERROR) {
- return -1;
- }
-
- return 0;
-
-}
-
-static int restore_socket(ws_socket_t sock)
-{
- unsigned long v = 0;
-
- if (ioctlsocket(sock, FIONBIO, &v) == SOCKET_ERROR) {
- return -1;
- }
-
- return 0;
-
-}
-
-#else
-
-static int setup_socket(ws_socket_t sock)
-{
- int flags = fcntl(sock, F_GETFL, 0);
- return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
-}
-
-static int restore_socket(ws_socket_t sock)
-{
- int flags = fcntl(sock, F_GETFL, 0);
-
- flags &= ~O_NONBLOCK;
-
- return fcntl(sock, F_SETFL, flags);
-
-}
-
-#endif
-
-
-int establish_logical_layer(wsh_t *wsh)
-{
-
- if (!wsh->sanity) {
- return -1;
- }
-
- if (wsh->logical_established) {
- return 0;
- }
-
- if (wsh->secure && !wsh->secure_established) {
- int code;
-
- if (!wsh->ssl) {
- wsh->ssl = SSL_new(wsh->ssl_ctx);
- assert(wsh->ssl);
-
- SSL_set_fd(wsh->ssl, wsh->sock);
- }
-
- do {
- code = SSL_accept(wsh->ssl);
-
- if (code == 1) {
- wsh->secure_established = 1;
- break;
- }
-
- if (code == 0) {
- return -1;
- }
-
- if (code < 0) {
- int ssl_err = SSL_get_error(wsh->ssl, code);
- if (!SSL_WANT_READ_WRITE(ssl_err)) {
- return -1;
- }
- }
-
- if (wsh->block) {
- ms_sleep(10);
- } else {
- ms_sleep(1);
- }
-
- wsh->sanity--;
-
- if (!wsh->block) {
- return -2;
- }
-
- } while (wsh->sanity > 0);
-
- if (!wsh->sanity) {
- return -1;
- }
-
- }
-
- while (!wsh->down && !wsh->handshake) {
- int r = ws_handshake(wsh);
-
- if (r < 0) {
- wsh->down = 1;
- return -1;
- }
-
- if (!wsh->handshake && !wsh->block) {
- return -2;
- }
-
- }
-
- wsh->logical_established = 1;
-
- return 0;
-}
-
-
-int ws_init(wsh_t *wsh, ws_socket_t sock, SSL_CTX *ssl_ctx, int close_sock, int block, int stay_open)
-{
- memset(wsh, 0, sizeof(*wsh));
-
- wsh->sock = sock;
- wsh->block = block;
- wsh->sanity = WS_INIT_SANITY;
- wsh->ssl_ctx = ssl_ctx;
- wsh->stay_open = stay_open;
-
- if (!ssl_ctx) {
- ssl_ctx = ws_globals.ssl_ctx;
- }
-
- if (close_sock) {
- wsh->close_sock = 1;
- }
-
- wsh->buflen = 1024 * 64;
- wsh->bbuflen = wsh->buflen;
-
- wsh->buffer = malloc(wsh->buflen);
- wsh->bbuffer = malloc(wsh->bbuflen);
- //printf("init %p %ld\n", (void *) wsh->bbuffer, wsh->bbuflen);
- //memset(wsh->buffer, 0, wsh->buflen);
- //memset(wsh->bbuffer, 0, wsh->bbuflen);
-
- wsh->secure = ssl_ctx ? 1 : 0;
-
- setup_socket(sock);
-
- if (establish_logical_layer(wsh) == -1) {
- return -1;
- }
-
- if (wsh->down) {
- return -1;
- }
-
- return 0;
-}
-
-void ws_destroy(wsh_t *wsh)
-{
-
- if (!wsh) {
- return;
- }
-
- if (!wsh->down) {
- ws_close(wsh, WS_NONE);
- }
-
- if (wsh->down > 1) {
- return;
- }
-
- wsh->down = 2;
-
- if (wsh->write_buffer) {
- free(wsh->write_buffer);
- wsh->write_buffer = NULL;
- wsh->write_buffer_len = 0;
- }
-
- if (wsh->ssl) {
- SSL_free(wsh->ssl);
- wsh->ssl = NULL;
- }
-
- if (wsh->buffer) free(wsh->buffer);
- if (wsh->bbuffer) free(wsh->bbuffer);
-
- wsh->buffer = wsh->bbuffer = NULL;
-
-}
-
-ssize_t ws_close(wsh_t *wsh, int16_t reason)
-{
-
- if (wsh->down) {
- return -1;
- }
-
- wsh->down = 1;
-
- if (wsh->uri) {
- free(wsh->uri);
- wsh->uri = NULL;
- }
-
- if (reason && wsh->sock != ws_sock_invalid) {
- uint16_t *u16;
- uint8_t fr[4] = {WSOC_CLOSE | 0x80, 2, 0};
-
- u16 = (uint16_t *) &fr[2];
- *u16 = htons((int16_t)reason);
- ws_raw_write(wsh, fr, 4);
- }
-
- if (wsh->ssl && wsh->sock != ws_sock_invalid) {
- /* first invocation of SSL_shutdown() would normally return 0 and just try to send SSL protocol close request.
- we just slightly polite, since we want to close socket fast and
- not bother waiting for SSL protocol close response before closing socket,
- since we want cleanup to be done fast for scenarios like:
- client change NAT (like jump from one WiFi to another) and now unreachable from old ip:port, however
- immidiately reconnect with new ip:port but old session id (and thus should replace the old session/channel)
- */
- SSL_shutdown(wsh->ssl);
- }
-
- /* restore to blocking here, so any further read/writes will block */
- restore_socket(wsh->sock);
-
- if (wsh->close_sock && wsh->sock != ws_sock_invalid) {
- /* signal socket to shutdown() before close(): FIN-ACK-FIN-ACK insead of RST-RST
- do not really handle errors here since it all going to die anyway.
- all buffered writes if any(like SSL_shutdown() ones) will still be sent.
- */
-#ifndef WIN32
- shutdown(wsh->sock, SHUT_RDWR);
- close(wsh->sock);
-#else
- shutdown(wsh->sock, SD_BOTH);
- closesocket(wsh->sock);
-#endif
- }
-
- wsh->sock = ws_sock_invalid;
-
- return reason * -1;
-
-}
-
-
-uint64_t hton64(uint64_t val)
-{
- if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
- else return __bswap_64(val);
-}
-
-uint64_t ntoh64(uint64_t val)
-{
- if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
- else return __bswap_64(val);
-}
-
-
-ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
-{
-
- ssize_t need = 2;
- char *maskp;
- int ll = 0;
- int frag = 0;
- int blen;
-
- wsh->body = wsh->bbuffer;
- wsh->packetlen = 0;
-
- again:
- need = 2;
- maskp = NULL;
- *data = NULL;
-
- ll = establish_logical_layer(wsh);
-
- if (ll < 0) {
- return ll;
- }
-
- if (wsh->down) {
- return -1;
- }
-
- if (!wsh->handshake) {
- return ws_close(wsh, WS_NONE);
- }
-
- if ((wsh->datalen = ws_raw_read(wsh, wsh->buffer, 9, wsh->block)) < 0) {
- if (wsh->datalen == -2) {
- return -2;
- }
- return ws_close(wsh, WS_NONE);
- }
-
- if (wsh->datalen < need) {
- ssize_t bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, 9 - wsh->datalen, WS_BLOCK);
- if (bytes < 0 || (wsh->datalen += bytes) < need) {
- /* too small - protocol err */
- return ws_close(wsh, WS_NONE);
- }
- }
-
- *oc = *wsh->buffer & 0xf;
-
- switch(*oc) {
- case WSOC_CLOSE:
- {
- wsh->plen = wsh->buffer[1] & 0x7f;
- *data = (uint8_t *) &wsh->buffer[2];
- return ws_close(wsh, WS_RECV_CLOSE);
- }
- break;
- case WSOC_CONTINUATION:
- case WSOC_TEXT:
- case WSOC_BINARY:
- case WSOC_PING:
- case WSOC_PONG:
- {
- int fin = (wsh->buffer[0] >> 7) & 1;
- int mask = (wsh->buffer[1] >> 7) & 1;
-
-
- if (!fin && *oc != WSOC_CONTINUATION) {
- frag = 1;
- } else if (fin && *oc == WSOC_CONTINUATION) {
- frag = 0;
- }
-
- if (mask) {
- need += 4;
-
- if (need > wsh->datalen) {
- ssize_t bytes = ws_raw_read_blocking(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, 10);
- if (bytes < 0 || (wsh->datalen += bytes) < need) {
- /* too small - protocol err */
- *oc = WSOC_CLOSE;
- return ws_close(wsh, WS_NONE);
- }
- }
- }
-
- wsh->plen = wsh->buffer[1] & 0x7f;
- wsh->payload = &wsh->buffer[2];
-
- if (wsh->plen == 127) {
- uint64_t *u64;
-
- need += 8;
-
- if (need > wsh->datalen) {
- ssize_t bytes = ws_raw_read_blocking(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, 10);
- if (bytes < 0 || (wsh->datalen += bytes) < need) {
- /* too small - protocol err */
- *oc = WSOC_CLOSE;
- return ws_close(wsh, WS_NONE);
- }
- }
-
- u64 = (uint64_t *) wsh->payload;
- wsh->payload += 8;
- wsh->plen = ntoh64(*u64);
- } else if (wsh->plen == 126) {
- uint16_t *u16;
-
- need += 2;
-
- if (need > wsh->datalen) {
- ssize_t bytes = ws_raw_read_blocking(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, 10);
- if (bytes < 0 || (wsh->datalen += bytes) < need) {
- /* too small - protocol err */
- *oc = WSOC_CLOSE;
- return ws_close(wsh, WS_NONE);
- }
- }
-
- u16 = (uint16_t *) wsh->payload;
- wsh->payload += 2;
- wsh->plen = ntohs(*u16);
- }
-
- if (mask) {
- maskp = (char *)wsh->payload;
- wsh->payload += 4;
- }
-
- need = (wsh->plen - (wsh->datalen - need));
-
- if (need < 0) {
- /* invalid read - protocol err .. */
- *oc = WSOC_CLOSE;
- return ws_close(wsh, WS_NONE);
- }
-
- blen = wsh->body - wsh->bbuffer;
-
- if (need + blen > (ssize_t)wsh->bbuflen) {
- void *tmp;
-
- wsh->bbuflen = need + blen + wsh->rplen;
-
- if ((tmp = realloc(wsh->bbuffer, wsh->bbuflen))) {
- wsh->bbuffer = tmp;
- } else {
- abort();
- }
-
- wsh->body = wsh->bbuffer + blen;
- }
-
- wsh->rplen = wsh->plen - need;
-
- if (wsh->rplen) {
- memcpy(wsh->body, wsh->payload, wsh->rplen);
- }
-
- while(need) {
- ssize_t r = ws_raw_read(wsh, wsh->body + wsh->rplen, need, WS_BLOCK);
-
- if (r < 1) {
- /* invalid read - protocol err .. */
- *oc = WSOC_CLOSE;
- return ws_close(wsh, WS_NONE);
- }
-
- wsh->datalen += r;
- wsh->rplen += r;
- need -= r;
- }
-
- if (mask && maskp) {
- ssize_t i;
-
- for (i = 0; i < wsh->datalen; i++) {
- wsh->body[i] ^= maskp[i % 4];
- }
- }
-
-
- if (*oc == WSOC_PING) {
- ws_write_frame(wsh, WSOC_PONG, wsh->body, wsh->rplen);
- goto again;
- }
-
- *(wsh->body+wsh->rplen) = '\0';
- wsh->packetlen += wsh->rplen;
- wsh->body += wsh->rplen;
-
- if (frag) {
- goto again;
- }
-
- *data = (uint8_t *)wsh->bbuffer;
-
- //printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->packetlen, *oc, (char *)*data);
-
-
- return wsh->packetlen;
- }
- break;
- default:
- {
- /* invalid op code - protocol err .. */
- *oc = WSOC_CLOSE;
- return ws_close(wsh, WS_PROTO_ERR);
- }
- break;
- }
-}
-
-ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
-{
- uint8_t hdr[14] = { 0 };
- size_t hlen = 2;
- uint8_t *bp;
- ssize_t raw_ret = 0;
-
- if (wsh->down) {
- return -1;
- }
-
- //printf("WRITE[%ld]-----------------------------:\n[%s]\n-----------------------------------\n", bytes, (char *) data);
-
- hdr[0] = (uint8_t)(oc | 0x80);
-
- if (bytes < 126) {
- hdr[1] = (uint8_t)bytes;
- } else if (bytes < 0x10000) {
- uint16_t *u16;
-
- hdr[1] = 126;
- hlen += 2;
-
- u16 = (uint16_t *) &hdr[2];
- *u16 = htons((uint16_t) bytes);
-
- } else {
- uint64_t *u64;
-
- hdr[1] = 127;
- hlen += 8;
-
- u64 = (uint64_t *) &hdr[2];
- *u64 = hton64(bytes);
- }
-
- if (wsh->write_buffer_len < (hlen + bytes + 1)) {
- void *tmp;
-
- wsh->write_buffer_len = hlen + bytes + 1;
- if ((tmp = realloc(wsh->write_buffer, wsh->write_buffer_len))) {
- wsh->write_buffer = tmp;
- } else {
- abort();
- }
- }
-
- bp = (uint8_t *) wsh->write_buffer;
- memcpy(bp, (void *) &hdr[0], hlen);
- memcpy(bp + hlen, data, bytes);
-
- raw_ret = ws_raw_write(wsh, bp, (hlen + bytes));
-
- if (raw_ret != (ssize_t) (hlen + bytes)) {
- return raw_ret;
- }
-
- return bytes;
-}
-
-#ifdef _MSC_VER
-
-int xp_errno(void)
-{
- return WSAGetLastError();
-}
-
-int xp_is_blocking(int errcode)
-{
- return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS;
-}
-
-#else
-
-int xp_errno(void)
-{
- return errno;
-}
-
-int xp_is_blocking(int errcode)
-{
- return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EINTR || errcode == ETIMEDOUT;
-}
-
-#endif