#ifdef WIN32
#include <tchar.h>
#include <io.h>
+#include <mstcpip.h>
#else
#ifdef LWS_BUILTIN_GETIFADDRS
#include <getifaddrs.h>
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
-static const char *log_level_names[] = {
+static const char * const log_level_names[] = {
"ERR",
"WARN",
"NOTICE",
"LATENCY",
};
+#ifndef LWS_NO_CLIENT
+ extern int lws_client_socket_service(
+ struct libwebsocket_context *context,
+ struct libwebsocket *wsi, struct pollfd *pollfd);
+#endif
+#ifndef LWS_NO_SERVER
+ extern int lws_server_socket_service(
+ struct libwebsocket_context *context,
+ struct libwebsocket *wsi, struct pollfd *pollfd);
+#endif
+
/**
* lws_get_library_version: get version and git hash library built from
*
}
int
-insert_wsi_socket_into_fds(struct libwebsocket_context *context, struct libwebsocket *wsi)
+insert_wsi_socket_into_fds(struct libwebsocket_context *context,
+ struct libwebsocket *wsi)
{
if (context->fds_count >= context->max_fds) {
- lwsl_err("Reached limit of fds tracking (%d)\n", context->max_fds);
+ lwsl_err("Too many fds (%d)\n", context->max_fds);
return 1;
}
if (wsi->sock > context->max_fds) {
- lwsl_err("Socket fd %d is beyond what we can index (%d)\n", wsi->sock, context->max_fds);
+ lwsl_err("Socket fd %d is too high (%d)\n",
+ wsi->sock, context->max_fds);
return 1;
}
assert(wsi);
assert(wsi->sock);
- lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n", wsi, wsi->sock, context->fds_count);
+ lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n",
+ wsi, wsi->sock, context->fds_count);
context->lws_lookup[wsi->sock] = wsi;
wsi->position_in_fds_table = context->fds_count;
/* external POLL support via protocol 0 */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_ADD_POLL_FD,
- (void *)(long)wsi->sock, NULL, POLLIN);
+ wsi->user_space, (void *)(long)wsi->sock, POLLIN);
return 0;
}
static int
-remove_wsi_socket_from_fds(struct libwebsocket_context *context, struct libwebsocket *wsi)
+remove_wsi_socket_from_fds(struct libwebsocket_context *context,
+ struct libwebsocket *wsi)
{
int m;
goto do_ext;
if (wsi->sock > context->max_fds) {
- lwsl_err("Socket fd %d is beyond what we can index (%d)\n", wsi->sock, context->max_fds);
+ lwsl_err("Socket fd %d too high (%d)\n",
+ wsi->sock, context->max_fds);
return 1;
}
- lwsl_info("remove_wsi_socket_from_fds: wsi=%p, sock=%d, fds pos=%d\n", wsi, wsi->sock, wsi->position_in_fds_table);
+ lwsl_info("remove_wsi_socket_from_fds: wsi=%p, sock=%d, fds pos=%d\n",
+ wsi, wsi->sock, wsi->position_in_fds_table);
m = wsi->position_in_fds_table; /* replace the contents for this */
/* have the last guy take up the vacant slot */
- context->fds[m] = context->fds[context->fds_count]; /* vacant fds slot filled with end one */
- /* end guy's fds_lookup entry remains unchanged (still same fd pointing to same wsi) */
+ context->fds[m] = context->fds[context->fds_count];
+ /*
+ * end guy's fds_lookup entry remains unchanged
+ * (still same fd pointing to same wsi)
+ */
/* end guy's "position in fds table" changed */
- context->lws_lookup[context->fds[context->fds_count].fd]->position_in_fds_table = m;
+ context->lws_lookup[context->fds[context->fds_count].fd]->
+ position_in_fds_table = m;
/* deletion guy's lws_lookup entry needs nuking */
- context->lws_lookup[wsi->sock] = NULL; /* no WSI for the socket of the wsi being removed*/
- wsi->position_in_fds_table = -1; /* removed wsi has no position any more */
+ context->lws_lookup[wsi->sock] = NULL;
+ /* removed wsi has no position any more */
+ wsi->position_in_fds_table = -1;
do_ext:
/* remove also from external POLL support via protocol 0 */
if (wsi->sock)
context->protocols[0].callback(context, wsi,
- LWS_CALLBACK_DEL_POLL_FD, (void *)(long)wsi->sock, NULL, 0);
+ LWS_CALLBACK_DEL_POLL_FD, wsi->user_space,
+ (void *)(long)wsi->sock, 0);
return 0;
}
if (old_state == WSI_STATE_DEAD_SOCKET)
return;
+ /* we tried the polite way... */
+ if (old_state == WSI_STATE_AWAITING_CLOSE_ACK)
+ goto just_kill_connection;
+
wsi->u.ws.close_reason = reason;
if (wsi->mode == LWS_CONNMODE_HTTP_SERVING && wsi->u.http.fd) {
if (eff_buf.token_len)
if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
- eff_buf.token_len)) {
- lwsl_debug("close: sending final extension spill had problems\n");
+ eff_buf.token_len) != eff_buf.token_len) {
+ lwsl_debug("close: ext spill failed\n");
goto just_kill_connection;
}
}
lwsl_debug("sending close indication...\n");
- n = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING],
+ /* make valgrind happy */
+ memset(buf, 0, sizeof(buf));
+ n = libwebsocket_write(wsi,
+ &buf[LWS_SEND_BUFFER_PRE_PADDING + 2],
0, LWS_WRITE_CLOSE);
- if (!n) {
+ if (n >= 0) {
/*
* we have sent a nice protocol level indication we
* now wish to close, we should not send anything more
wsi->state = WSI_STATE_AWAITING_CLOSE_ACK;
- /* and we should wait for a reply for a bit out of politeness */
+ /*
+ * ...and we should wait for a reply for a bit
+ * out of politeness
+ */
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_CLOSE_ACK, 1);
return;
}
- lwsl_info("close: sending the close packet failed, hanging up\n");
+ lwsl_info("close: sending close packet failed, hanging up\n");
/* else, the send failed and we should just hang up */
}
-#ifndef LWS_NO_EXTENSIONS
just_kill_connection:
-#endif
- lwsl_debug("libwebsocket_close_and_free_session: just_kill_connection\n");
+ lwsl_debug("close: just_kill_connection\n");
/*
* we won't be servicing or receiving anything further from this guy
wsi->state = WSI_STATE_DEAD_SOCKET;
- if (old_state == WSI_STATE_ESTABLISHED && wsi->u.ws.rx_user_buffer) {
- free(wsi->u.ws.rx_user_buffer);
- wsi->u.ws.rx_user_buffer = NULL;
+ if ((old_state == WSI_STATE_ESTABLISHED ||
+ wsi->mode == LWS_CONNMODE_WS_SERVING ||
+ wsi->mode == LWS_CONNMODE_WS_CLIENT)) {
+
+ if (wsi->u.ws.rx_user_buffer) {
+ free(wsi->u.ws.rx_user_buffer);
+ wsi->u.ws.rx_user_buffer = NULL;
+ }
+ if (wsi->u.ws.rxflow_buffer) {
+ free(wsi->u.ws.rxflow_buffer);
+ wsi->u.ws.rxflow_buffer = NULL;
+ }
}
/* tell the user it's all over for this guy */
wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED,
wsi->user_space, NULL, 0);
} else
- lwsl_debug("not calling back closed, old_state=%d\n", old_state);
+ lwsl_debug("not calling back closed\n");
#ifndef LWS_NO_EXTENSIONS
/* deallocate any active extension contexts */
}
#endif
-#ifndef LWS_NO_CLIENT
- if (wsi->c_address)
- free(wsi->c_address);
-#endif
- if (wsi->u.ws.rxflow_buffer)
- free(wsi->u.ws.rxflow_buffer);
-
/* lwsl_info("closing fd=%d\n", wsi->sock); */
#ifdef LWS_OPENSSL_SUPPORT
if (wsi->sock) {
n = shutdown(wsi->sock, SHUT_RDWR);
if (n)
- lwsl_debug("closing: shutdown returned %d\n", errno);
+ lwsl_debug("closing: shutdown returned %d\n",
+ errno);
n = compatible_close(wsi->sock);
if (n)
- lwsl_debug("closing: close returned %d\n", errno);
+ lwsl_debug("closing: close returned %d\n",
+ errno);
}
#ifdef LWS_OPENSSL_SUPPORT
}
#endif
- if (wsi->protocol && wsi->protocol->per_session_data_size && wsi->user_space) /* user code may own */
+ if (wsi->protocol && wsi->protocol->per_session_data_size &&
+ wsi->user_space) /* user code may own */
free(wsi->user_space);
free(wsi);
}
/**
- * libwebsockets_hangup_on_client() - Server calls to terminate client
- * connection
- * @context: libwebsockets context
- * @fd: Connection socket descriptor
- */
-
-void
-libwebsockets_hangup_on_client(struct libwebsocket_context *context, int fd)
-{
- struct libwebsocket *wsi = context->lws_lookup[fd];
-
- if (wsi) {
- lwsl_info("closing connection at libwebsockets_hangup_on_client:\n");
- libwebsocket_close_and_free_session(context,
- wsi, LWS_CLOSE_STATUS_NOSTATUS);
- } else
- close(fd);
-}
-
-
-/**
* libwebsockets_get_peer_addresses() - Get client address information
* @context: Libwebsockets context
* @wsi: Local struct libwebsocket associated with
int n;
int ret = -1;
#ifdef AF_LOCAL
- struct sockaddr_un *un;
+ struct sockaddr_un *un;
#endif
rip[0] = '\0';
lws_latency_pre(context, wsi);
- len = sizeof sin;
+ len = sizeof(sin);
if (getpeername(fd, (struct sockaddr *) &sin, &len) < 0) {
perror("getpeername");
goto bail;
}
- host = gethostbyaddr((char *) &sin.sin_addr, sizeof sin.sin_addr,
+ host = gethostbyaddr((char *) &sin.sin_addr, sizeof(sin.sin_addr),
AF_INET);
if (host == NULL) {
perror("gethostbyaddr");
(const void *)&optval, optlen) < 0)
return 1;
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+
+ /*
+ * didn't find a way to set these per-socket, need to
+ * tune kernel systemwide values
+ */
+#elif WIN32
+ {
+ DWORD dwBytesRet;
+ struct tcp_keepalive alive;
+ alive.onoff = TRUE;
+ alive.keepalivetime = context->ka_time;
+ alive.keepaliveinterval = context->ka_interval;
+
+ if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
+ NULL, 0, &dwBytesRet, NULL, NULL))
+ return 1;
+ }
+#else
/* set the keepalive conditions we want on it too */
optval = context->ka_time;
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE,
(const void *)&optval, optlen) < 0)
return 1;
- optval = context->ka_probes;
+ optval = context->ka_interval;
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
(const void *)&optval, optlen) < 0)
return 1;
- optval = context->ka_interval;
+ optval = context->ka_probes;
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
(const void *)&optval, optlen) < 0)
return 1;
+#endif
}
/* Disable Nagle */
/* assuming they gave us something to send, send it */
if (eff_buf.token_len) {
- if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
- eff_buf.token_len))
+ n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
+ eff_buf.token_len);
+ if (n < 0)
+ return -1;
+ /*
+ * Keep amount spilled small to minimize chance of this
+ */
+ if (n != eff_buf.token_len) {
+ lwsl_err("Unable to spill ext %d vs %s\n",
+ eff_buf.token_len, n);
return -1;
+ }
} else
continue;
/* external POLL support via protocol 0 */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLEAR_MODE_POLL_FD,
- (void *)(long)wsi->sock, NULL, POLLOUT);
+ wsi->user_space, (void *)(long)wsi->sock, POLLOUT);
}
#ifndef LWS_NO_EXTENSIONS
notify_action:
n = LWS_CALLBACK_SERVER_WRITEABLE;
return user_callback_handle_rxflow(wsi->protocol->callback, context,
- wsi, (enum libwebsocket_callback_reasons) n, wsi->user_space, NULL, 0);
+ wsi, (enum libwebsocket_callback_reasons) n,
+ wsi->user_space, NULL, 0);
}
-void
+int
libwebsocket_service_timeout_check(struct libwebsocket_context *context,
struct libwebsocket *wsi, unsigned int sec)
{
#endif
if (!wsi->pending_timeout)
- return;
+ return 0;
/*
* if we went beyond the allowed time, kill the
lwsl_info("TIMEDOUT WAITING\n");
libwebsocket_close_and_free_session(context,
wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ return 1;
}
+
+ return 0;
}
/**
* happened.
*
* This function takes a pollfd that has POLLIN or POLLOUT activity and
- * services it according to the state of the associated struct libwebsocket.
+ * services it according to the state of the associated
+ * struct libwebsocket.
*
* The one call deals with all "service" that might happen on a socket
* including listen accepts, http files as well as websocket protocol.
struct libwebsocket *wsi;
int n;
int m;
+ int listen_socket_fds_index = 0;
struct timeval tv;
-#ifdef LWS_OPENSSL_SUPPORT
- char ssl_err_buf[512];
-#endif
+ int timed_out = 0;
+ int our_fd = 0;
#ifndef LWS_NO_EXTENSIONS
int more = 1;
#endif
struct lws_tokens eff_buf;
-#ifndef LWS_NO_CLIENT
- extern int lws_client_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct pollfd *pollfd);
-#endif
-#ifndef LWS_NO_SERVER
- extern int lws_server_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct pollfd *pollfd);
-#endif
+
+ if (context->listen_service_fd)
+ listen_socket_fds_index = context->lws_lookup[
+ context->listen_service_fd]->position_in_fds_table;
+
/*
* you can call us with pollfd = NULL to just allow the once-per-second
* global timeout checks; if less than a second since the last check
#ifndef WIN32
/* if our parent went down, don't linger around */
- if (context->started_with_parent && kill(context->started_with_parent, 0) < 0)
+ if (context->started_with_parent &&
+ kill(context->started_with_parent, 0) < 0)
kill(getpid(), SIGTERM);
#endif
/* global timeout check once per second */
+ if (pollfd)
+ our_fd = pollfd->fd;
+
for (n = 0; n < context->fds_count; n++) {
- struct libwebsocket *new_wsi = context->lws_lookup[context->fds[n].fd];
- if (!new_wsi)
+ m = context->fds[n].fd;
+ wsi = context->lws_lookup[m];
+ if (!wsi)
continue;
- libwebsocket_service_timeout_check(context,
- new_wsi, tv.tv_sec);
+
+ if (libwebsocket_service_timeout_check(context, wsi,
+ tv.tv_sec))
+ /* he did time out... */
+ if (m == our_fd)
+ /* it was the guy we came to service! */
+ timed_out = 1;
}
}
+ /* the socket we came to service timed out, nothing to do */
+ if (timed_out)
+ return 0;
+
/* just here for timeout management? */
if (pollfd == NULL)
* pending connection here, it causes us to check again next time.
*/
- if (context->listen_service_fd && pollfd->fd != context->listen_service_fd) {
+ if (context->listen_service_fd && pollfd !=
+ &context->fds[listen_socket_fds_index]) {
context->listen_service_count++;
if (context->listen_service_extraseen ||
- context->listen_service_count == context->listen_service_modulo) {
+ context->listen_service_count ==
+ context->listen_service_modulo) {
context->listen_service_count = 0;
m = 1;
if (context->listen_service_extraseen > 5)
m = 2;
while (m--) {
- /* even with extpoll, we prepared this internal fds for listen */
- n = poll(&context->fds[0], 1, 0);
- if (n > 0) { /* there's a connection waiting for us */
- libwebsocket_service_fd(context, &context->fds[0]);
+ /*
+ * even with extpoll, we prepared this
+ * internal fds for listen
+ */
+ n = poll(&context->fds[listen_socket_fds_index],
+ 1, 0);
+ if (n > 0) { /* there's a conn waiting for us */
+ libwebsocket_service_fd(context,
+ &context->
+ fds[listen_socket_fds_index]);
context->listen_service_extraseen++;
} else {
if (context->listen_service_extraseen)
- context->listen_service_extraseen--;
+ context->
+ listen_service_extraseen--;
break;
}
}
wsi = context->lws_lookup[pollfd->fd];
if (wsi == NULL) {
if (pollfd->fd > 11)
- lwsl_err("unexpected NULL wsi fd=%d fds_count=%d\n", pollfd->fd, context->fds_count);
+ lwsl_err("unexpected NULL wsi fd=%d fds_count=%d\n",
+ pollfd->fd, context->fds_count);
return 0;
}
/* handle session socket closed */
- if (pollfd->revents & (POLLERR | POLLHUP)) {
+ if ((!pollfd->revents & POLLIN) &&
+ (pollfd->revents & (POLLERR | POLLHUP))) {
lwsl_debug("Session Socket %p (fd=%d) dead\n",
(void *)wsi, pollfd->fd);
wsi->state == WSI_STATE_ESTABLISHED)
if (lws_handle_POLLOUT_event(context, wsi,
pollfd) < 0) {
+ lwsl_info("libwebsocket_service_fd: closing\n");
libwebsocket_close_and_free_session(
- context, wsi, LWS_CLOSE_STATUS_NORMAL);
+ context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
return 0;
}
if (wsi->ssl) {
eff_buf.token_len = SSL_read(wsi->ssl,
context->service_buffer,
- sizeof context->service_buffer);
+ sizeof(context->service_buffer));
if (!eff_buf.token_len) {
n = SSL_get_error(wsi->ssl, eff_buf.token_len);
lwsl_err("SSL_read returned 0 with reason %s\n",
- ERR_error_string(n, ssl_err_buf));
+ ERR_error_string(n,
+ (char *)context->service_buffer));
}
} else
#endif
eff_buf.token_len = recv(pollfd->fd,
- context->service_buffer,
- sizeof context->service_buffer, 0);
+ context->service_buffer,
+ sizeof(context->service_buffer), 0);
if (eff_buf.token_len < 0) {
lwsl_debug("Socket read returned %d\n",
return 0;
}
if (!eff_buf.token_len) {
- lwsl_info("closing connection due to zero length read\n");
+ lwsl_info("closing connection due to 0 length read\n");
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return 0;
int n;
int m;
struct libwebsocket_extension *ext;
+ struct libwebsocket_protocols *protocol = context->protocols;
#ifdef LWS_LATENCY
if (context->worst_latency_info[0])
#endif
for (n = 0; n < context->fds_count; n++) {
- struct libwebsocket *wsi = context->lws_lookup[context->fds[n].fd];
+ struct libwebsocket *wsi =
+ context->lws_lookup[context->fds[n].fd];
libwebsocket_close_and_free_session(context,
- wsi, LWS_CLOSE_STATUS_GOINGAWAY);
+ wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */);
+ n--;
}
/*
if (context->listen_port)
m = LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT;
while (ext && ext->callback) {
- ext->callback(context, ext, NULL, (enum libwebsocket_extension_callback_reasons)m, NULL, NULL, 0);
+ ext->callback(context, ext, NULL,
+ (enum libwebsocket_extension_callback_reasons)m,
+ NULL, NULL, 0);
ext++;
}
+
+ /*
+ * inform all the protocols that they are done and will have no more
+ * callbacks
+ */
+
+ while (protocol->callback) {
+ protocol->callback(context, NULL, LWS_CALLBACK_PROTOCOL_DESTROY,
+ NULL, NULL, 0);
+ protocol++;
+ }
+
#endif
#ifdef WIN32
SSL_CTX_free(context->ssl_ctx);
if (context->ssl_client_ctx)
SSL_CTX_free(context->ssl_client_ctx);
+
+ ERR_remove_state(0);
+ ERR_free_strings();
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
#endif
+ if (context->fds)
+ free(context->fds);
+ if (context->lws_lookup)
+ free(context->lws_lookup);
+
free(context);
#ifdef WIN32
}
/**
- * libwebsocket_context_user() - get the user data associated with the whole context
+ * libwebsocket_context_user() - get the user data associated with the context
* @context: Websocket context
*
* This returns the optional user allocation that can be attached to
* to let all sockets serviced in the same context share data without
* using globals statics in the user code.
*/
-
-
LWS_EXTERN void *
libwebsocket_context_user(struct libwebsocket_context *context)
{
- return context->user_space;
+ return context->user_space;
}
/**
* nothing is pending, or as soon as it services whatever was pending.
*/
-
int
libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
{
return 1;
#endif
if (wsi->position_in_fds_table < 0) {
- lwsl_err("libwebsocket_callback_on_writable: "
- "failed to find socket %d\n", wsi->sock);
+ lwsl_err("libwebsocket_callback_on_writable: failed to find socket %d\n",
+ wsi->sock);
return -1;
}
/* external POLL support via protocol 0 */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_SET_MODE_POLL_FD,
- (void *)(long)wsi->sock, NULL, POLLOUT);
+ wsi->user_space, (void *)(long)wsi->sock, POLLOUT);
return 1;
}
#ifdef LWS_LATENCY
void
-lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi, const char *action, int ret, int completed)
+lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi,
+ const char *action, int ret, int completed)
{
struct timeval tv;
unsigned long u;
if (action) {
if (completed) {
if (wsi->action_start == wsi->latency_start)
- sprintf(buf, "Completion first try lat %luus: %p: ret %d: %s\n", u - wsi->latency_start, (void *)wsi, ret, action);
+ sprintf(buf,
+ "Completion first try lat %luus: %p: ret %d: %s\n",
+ u - wsi->latency_start,
+ (void *)wsi, ret, action);
else
- sprintf(buf, "Completion %luus: lat %luus: %p: ret %d: %s\n", u - wsi->action_start, u - wsi->latency_start, (void *)wsi, ret, action);
+ sprintf(buf,
+ "Completion %luus: lat %luus: %p: ret %d: %s\n",
+ u - wsi->action_start,
+ u - wsi->latency_start,
+ (void *)wsi, ret, action);
wsi->action_start = 0;
} else
- sprintf(buf, "lat %luus: %p: ret %d: %s\n", u - wsi->latency_start, (void *)wsi, ret, action);
+ sprintf(buf, "lat %luus: %p: ret %d: %s\n",
+ u - wsi->latency_start,
+ (void *)wsi, ret, action);
if (u - wsi->latency_start > context->worst_latency) {
context->worst_latency = u - wsi->latency_start;
strcpy(context->worst_latency_info, buf);
wsi->u.ws.rxflow_change_to &= ~2;
- lwsl_info("rxflow: wsi %p change_to %d\n", wsi, wsi->u.ws.rxflow_change_to);
+ lwsl_info("rxflow: wsi %p change_to %d\n",
+ wsi, wsi->u.ws.rxflow_change_to);
/* if we're letting it come again, did we interrupt anything? */
if ((wsi->u.ws.rxflow_change_to & 1) && wsi->u.ws.rxflow_buffer) {
n = libwebsocket_interpret_incoming_packet(wsi, NULL, 0);
if (n < 0) {
- lwsl_info("closing connection at libwebsocket_rx_flow_control:\n");
- libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ lwsl_info("libwebsocket_rx_flow_control: close req\n");
return -1;
}
if (n)
/* external POLL support via protocol 0 */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_SET_MODE_POLL_FD,
- (void *)(long)wsi->sock, NULL, POLLIN);
+ wsi->user_space, (void *)(long)wsi->sock, POLLIN);
else
/* external POLL support via protocol 0 */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLEAR_MODE_POLL_FD,
- (void *)(long)wsi->sock, NULL, POLLIN);
+ wsi->user_space, (void *)(long)wsi->sock, POLLIN);
return 1;
}
#endif
int user_callback_handle_rxflow(callback_function callback_function,
- struct libwebsocket_context * context,
+ struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len)
int n;
n = callback_function(context, wsi, reason, user, in, len);
- if (n) {
- libwebsocket_close_and_free_session(context, wsi,
- LWS_CLOSE_STATUS_NOSTATUS);
- return n;
- }
-
- _libwebsocket_rx_flow_control(wsi);
+ if (!n)
+ n = _libwebsocket_rx_flow_control(wsi);
- return 0;
+ return n;
}
struct libwebsocket_context *
libwebsocket_create_context(struct lws_context_creation_info *info)
{
- int n;
struct libwebsocket_context *context = NULL;
char *p;
+ int n;
#ifndef LWS_NO_SERVER
int opt = 1;
struct libwebsocket *wsi;
#ifdef LWS_OPENSSL_SUPPORT
SSL_METHOD *method;
- char ssl_err_buf[512];
#endif
#ifndef LWS_NO_DAEMONIZE
- extern int get_daemonize_pid();
int pid_daemon = get_daemonize_pid();
#endif
lwsl_notice("Initial logging level %d\n", log_level);
lwsl_notice("Library version: %s\n", library_version);
- lwsl_info(" LWS_MAX_HEADER_NAME_LENGTH: %u\n", LWS_MAX_HEADER_NAME_LENGTH);
lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN);
- lwsl_info(" LWS_INITIAL_HDR_ALLOC: %u\n", LWS_INITIAL_HDR_ALLOC);
- lwsl_info(" LWS_ADDITIONAL_HDR_ALLOC: %u\n", LWS_ADDITIONAL_HDR_ALLOC);
lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS);
#ifndef LWS_NO_EXTENSIONS
- lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE);
+ lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n",
+ LWS_MAX_EXTENSIONS_ACTIVE);
#else
lwsl_notice(" Configured without extension support\n");
#endif
lwsl_info(" SPEC_LATEST_SUPPORTED: %u\n", SPEC_LATEST_SUPPORTED);
lwsl_info(" AWAITING_TIMEOUT: %u\n", AWAITING_TIMEOUT);
- lwsl_info(" CIPHERS_LIST_STRING: '%s'\n", CIPHERS_LIST_STRING);
+ if (info->ssl_cipher_list)
+ lwsl_info(" SSL ciphers: '%s'\n", info->ssl_cipher_list);
lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
lwsl_info(" LWS_MAX_ZLIB_CONN_BUFFER: %u\n", LWS_MAX_ZLIB_CONN_BUFFER);
}
#endif
- context = (struct libwebsocket_context *) malloc(sizeof(struct libwebsocket_context));
+ context = (struct libwebsocket_context *)
+ malloc(sizeof(struct libwebsocket_context));
if (!context) {
lwsl_err("No memory for websocket context\n");
return NULL;
context->started_with_parent = pid_daemon;
lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
#endif
-
+
context->listen_service_extraseen = 0;
context->protocols = info->protocols;
context->listen_port = info->port;
context->options = info->options;
/* to reduce this allocation, */
context->max_fds = getdtablesize();
- lwsl_notice(" max fd tracked: %u\n", context->max_fds);
- lwsl_notice(" static allocation: %u bytes\n",
+ lwsl_notice(" static allocation: %u + (%u x %u fds) = %u bytes\n",
+ sizeof(struct libwebsocket_context),
+ sizeof(struct pollfd) + sizeof(struct libwebsocket *),
+ context->max_fds,
sizeof(struct libwebsocket_context) +
- (sizeof(struct pollfd) * context->max_fds) +
- (sizeof(struct libwebsocket *) * context->max_fds));
+ ((sizeof(struct pollfd) + sizeof(struct libwebsocket *)) *
+ context->max_fds));
- context->fds = (struct pollfd *)malloc(sizeof(struct pollfd) * context->max_fds);
+ context->fds = (struct pollfd *)malloc(sizeof(struct pollfd) *
+ context->max_fds);
if (context->fds == NULL) {
- lwsl_err("Unable to allocate fds array for %d connections\n", context->max_fds);
+ lwsl_err("Unable to allocate fds array for %d connections\n",
+ context->max_fds);
free(context);
return NULL;
}
- context->lws_lookup = (struct libwebsocket **)malloc(sizeof(struct libwebsocket *) * context->max_fds);
+ context->lws_lookup = (struct libwebsocket **)
+ malloc(sizeof(struct libwebsocket *) * context->max_fds);
if (context->lws_lookup == NULL) {
- lwsl_err("Unable to allocate lws_lookup array for %d connections\n", context->max_fds);
+ lwsl_err(
+ "Unable to allocate lws_lookup array for %d connections\n",
+ context->max_fds);
free(context->fds);
free(context);
return NULL;
#ifndef LWS_NO_SERVER
if (!(info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) {
- struct sockaddr sa;
- char hostname[1024] = "";
-
/* find canonical hostname */
+ gethostname((char *)context->canonical_hostname,
+ sizeof(context->canonical_hostname) - 1);
- hostname[(sizeof hostname) - 1] = '\0';
- memset(&sa, 0, sizeof(sa));
- sa.sa_family = AF_INET;
- sa.sa_data[(sizeof sa.sa_data) - 1] = '\0';
- gethostname(hostname, (sizeof hostname) - 1);
-
- n = 0;
-
- if (strlen(hostname) < sizeof(sa.sa_data) - 1) {
- strcpy(sa.sa_data, hostname);
- lwsl_debug("my host name is %s\n", sa.sa_data);
- n = getnameinfo(&sa, sizeof(sa), hostname,
- (sizeof hostname) - 1, NULL, 0, NI_NAMEREQD);
- }
-
- if (!n) {
- strncpy(context->canonical_hostname, hostname,
- sizeof context->canonical_hostname - 1);
- context->canonical_hostname[
- sizeof context->canonical_hostname - 1] = '\0';
- } else
- strncpy(context->canonical_hostname, hostname,
- sizeof context->canonical_hostname - 1);
-
- lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname);
+ lwsl_notice(" canonical_hostname = %s\n",
+ context->canonical_hostname);
}
#endif
p = getenv("http_proxy");
if (p) {
strncpy(context->http_proxy_address, p,
- sizeof context->http_proxy_address - 1);
+ sizeof(context->http_proxy_address) - 1);
context->http_proxy_address[
- sizeof context->http_proxy_address - 1] = '\0';
+ sizeof(context->http_proxy_address) - 1] = '\0';
p = strchr(context->http_proxy_address, ':');
if (p == NULL) {
lwsl_notice(" Using non-SSL mode\n");
#else
- if (ssl_cert_filepath != NULL &&
- ssl_private_key_filepath != NULL) {
+ if (info->ssl_cert_filepath != NULL &&
+ info->ssl_private_key_filepath != NULL) {
lwsl_notice(" Not compiled for OpenSSl support!\n");
goto bail;
}
- lwsl_notice(" Compiled without SSL support, "
- "serving unencrypted\n");
+ lwsl_notice(" Compiled without SSL support\n");
#endif
- lwsl_notice(" per-connection allocation: %u + headers during handshake + frame buffer set by protocol\n", sizeof(struct libwebsocket));
+ lwsl_notice(
+ " per-conn mem: %u + %u headers + protocol rx buf\n",
+ sizeof(struct libwebsocket),
+ sizeof(struct allocated_headers));
}
#endif
method = (SSL_METHOD *)SSLv23_server_method();
if (!method) {
- lwsl_err("problem creating ssl method: %s\n",
- ERR_error_string(ERR_get_error(), ssl_err_buf));
+ lwsl_err("problem creating ssl method %lu: %s\n",
+ ERR_get_error(),
+ ERR_error_string(ERR_get_error(),
+ (char *)context->service_buffer));
goto bail;
}
context->ssl_ctx = SSL_CTX_new(method); /* create context */
if (!context->ssl_ctx) {
- lwsl_err("problem creating ssl context: %s\n",
- ERR_error_string(ERR_get_error(), ssl_err_buf));
+ lwsl_err("problem creating ssl context %lu: %s\n",
+ ERR_get_error(),
+ ERR_error_string(ERR_get_error(),
+ (char *)context->service_buffer));
goto bail;
}
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
- SSL_CTX_set_cipher_list(context->ssl_ctx, CIPHERS_LIST_STRING);
+ if (info->ssl_cipher_list)
+ SSL_CTX_set_cipher_list(context->ssl_ctx,
+ info->ssl_cipher_list);
#ifndef LWS_NO_CLIENT
if (info->port == CONTEXT_PORT_NO_LISTEN) {
method = (SSL_METHOD *)SSLv23_client_method();
if (!method) {
- lwsl_err("problem creating ssl method: %s\n",
- ERR_error_string(ERR_get_error(), ssl_err_buf));
+ lwsl_err("problem creating ssl method %lu: %s\n",
+ ERR_get_error(),
+ ERR_error_string(ERR_get_error(),
+ (char *)context->service_buffer));
goto bail;
}
/* create context */
context->ssl_client_ctx = SSL_CTX_new(method);
if (!context->ssl_client_ctx) {
- lwsl_err("problem creating ssl context: %s\n",
- ERR_error_string(ERR_get_error(), ssl_err_buf));
+ lwsl_err("problem creating ssl context %lu: %s\n",
+ ERR_get_error(),
+ ERR_error_string(ERR_get_error(),
+ (char *)context->service_buffer));
goto bail;
}
#ifdef SSL_OP_NO_COMPRESSION
- SSL_CTX_set_options(context->ssl_client_ctx, SSL_OP_NO_COMPRESSION);
+ SSL_CTX_set_options(context->ssl_client_ctx,
+ SSL_OP_NO_COMPRESSION);
#endif
- SSL_CTX_set_options(context->ssl_client_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
- SSL_CTX_set_cipher_list(context->ssl_client_ctx, CIPHERS_LIST_STRING);
+ SSL_CTX_set_options(context->ssl_client_ctx,
+ SSL_OP_CIPHER_SERVER_PREFERENCE);
+ if (info->ssl_cipher_list)
+ SSL_CTX_set_cipher_list(context->ssl_client_ctx,
+ info->ssl_cipher_list);
/* openssl init for cert verification (for client sockets) */
if (!info->ssl_ca_filepath) {
context->ssl_client_ctx, NULL,
LWS_OPENSSL_CLIENT_CERTS))
lwsl_err(
- "Unable to load SSL Client certs from %s "
- "(set by --with-client-cert-dir= in configure) -- "
- " client ssl isn't going to work",
- LWS_OPENSSL_CLIENT_CERTS);
+ "Unable to load SSL Client certs from %s "
+ "(set by --with-client-cert-dir= "
+ "in configure) -- client ssl isn't "
+ "going to work", LWS_OPENSSL_CLIENT_CERTS);
} else
if (!SSL_CTX_load_verify_locations(
context->ssl_client_ctx, info->ssl_ca_filepath,
/* as a server, are we requiring clients to identify themselves? */
- if (info->options & LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
+ if (info->options &
+ LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
/* absolutely require the client cert */
n = SSL_CTX_use_certificate_chain_file(context->ssl_ctx,
info->ssl_cert_filepath);
if (n != 1) {
- lwsl_err("problem getting cert '%s': %s\n",
+ lwsl_err("problem getting cert '%s' %lu: %s\n",
info->ssl_cert_filepath,
- ERR_error_string(ERR_get_error(), ssl_err_buf));
+ ERR_get_error(),
+ ERR_error_string(ERR_get_error(),
+ (char *)context->service_buffer));
goto bail;
}
/* set the private key from KeyFile */
if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx,
info->ssl_private_key_filepath,
SSL_FILETYPE_PEM) != 1) {
- lwsl_err("ssl problem getting key '%s': %s\n",
- info->ssl_private_key_filepath,
- ERR_error_string(ERR_get_error(), ssl_err_buf));
+ lwsl_err("ssl problem getting key '%s' %lu: %s\n",
+ info->ssl_private_key_filepath,
+ ERR_get_error(),
+ ERR_error_string(ERR_get_error(),
+ (char *)context->service_buffer));
goto bail;
}
/* verify private key */
/* set up our external listening socket we serve on */
if (info->port) {
- extern int interface_to_sa(const char *ifname, struct sockaddr_in *addr, size_t addrlen);
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
}
#ifndef WIN32
- /* allow us to restart even if old sockets in TIME_WAIT
- * (REUSEADDR on Unix means, "don't hang on to this address after the
- * listener is closed." On Windows, though, it means "don't keep other
- * processes from binding to this address while we're using it) */
+ /*
+ * allow us to restart even if old sockets in TIME_WAIT
+ * (REUSEADDR on Unix means, "don't hang on to this
+ * address after the listener is closed." On Windows, though,
+ * it means "don't keep other processes from binding to
+ * this address while we're using it)
+ */
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&opt, sizeof(opt));
#endif
#ifdef WIN32
opt = 0;
- ioctlsocket(sockfd, FIONBIO, (unsigned long *)&opt );
+ ioctlsocket(sockfd, FIONBIO, (unsigned long *)&opt);
#else
fcntl(sockfd, F_SETFL, O_NONBLOCK);
#endif
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
- if (info->interface == NULL)
+ if (info->iface == NULL)
serv_addr.sin_addr.s_addr = INADDR_ANY;
else
- interface_to_sa(info->interface, &serv_addr,
+ interface_to_sa(info->iface, &serv_addr,
sizeof(serv_addr));
serv_addr.sin_port = htons(info->port);
goto bail;
}
- wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
+ wsi = (struct libwebsocket *)malloc(
+ sizeof(struct libwebsocket));
if (wsi == NULL) {
lwsl_err("Out of mem\n");
close(sockfd);
goto bail;
}
- memset(wsi, 0, sizeof (struct libwebsocket));
+ memset(wsi, 0, sizeof(struct libwebsocket));
wsi->sock = sockfd;
#ifndef LWS_NO_EXTENSIONS
wsi->count_active_extensions = 0;
context;
info->protocols[context->count_protocols].protocol_index =
context->count_protocols;
+
+ /*
+ * inform all the protocols that they are doing their one-time
+ * initialization if they want to
+ */
+ info->protocols[context->count_protocols].callback(context,
+ NULL, LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
}
#ifndef LWS_NO_EXTENSIONS
m = LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT;
if (info->port)
m = LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT;
-
+
if (info->extensions) {
ext = info->extensions;
while (ext->callback) {
return wsi->u.ws.rsv;
}
-void *
+int
libwebsocket_ensure_user_space(struct libwebsocket *wsi)
{
+ if (!wsi->protocol)
+ return 1;
+
/* allocate the per-connection user memory (if any) */
if (wsi->protocol->per_session_data_size && !wsi->user_space) {
wsi->protocol->per_session_data_size);
if (wsi->user_space == NULL) {
lwsl_err("Out of memory for conn user space\n");
- return NULL;
+ return 1;
}
memset(wsi->user_space, 0,
wsi->protocol->per_session_data_size);
}
- return wsi->user_space;
+ return 0;
}
static void lwsl_emit_stderr(int level, const char *line)
for (n = 0; n < LLL_COUNT; n++)
if (level == (1 << n)) {
sprintf(buf, "[%ld:%04d] %s: ", tv.tv_sec,
- (int)(tv.tv_usec / 100), log_level_names[n]);
+ (int)(tv.tv_usec / 100), log_level_names[n]);
break;
}
-
+
fprintf(stderr, "%s%s", buf, line);
}
return;
va_start(ap, format);
- vsnprintf(buf, (sizeof buf), format, ap);
- buf[(sizeof buf) - 1] = '\0';
+ vsnprintf(buf, sizeof(buf), format, ap);
+ buf[sizeof(buf) - 1] = '\0';
va_end(ap);
lwsl_emit(filter, buf);
* function to perform log string emission instead of
* the default stderr one.
*
- * log level defaults to "err" and "warn" contexts enabled only and
+ * log level defaults to "err", "warn" and "notice" contexts enabled and
* emission on stderr.
*/
-void lws_set_log_level(int level, void (*log_emit_function)(int level, const char *line))
+void lws_set_log_level(int level, void (*log_emit_function)(int level,
+ const char *line))
{
log_level = level;
if (log_emit_function)