This lets lws support adopting raw file FDs and raw socket fds.
A test plugin creates a FIFO and prints data sent on it, using
the lws event loop.
"plugins/protocol_post_demo.c" "" "")
create_plugin(protocol_lws_table_dirlisting
"plugins/generic-table/protocol_table_dirlisting.c" "" "")
+ if (NOT WIN32)
+ create_plugin(protocol_lws_raw_test
+ "plugins/protocol_lws_raw_test.c" "" "")
+ endif()
if (LWS_WITH_SERVER_STATUS)
create_plugin(protocol_lws_server_status
freeaddrinfo(result);
}
- if (!lws_socket_is_valid(wsi->sock)) {
+ if (!lws_socket_is_valid(wsi->desc.sockfd)) {
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(wsi->vhost))
- wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
+ wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
else
#endif
- wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
+ wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (!lws_socket_is_valid(wsi->sock)) {
+ if (!lws_socket_is_valid(wsi->desc.sockfd)) {
lwsl_warn("Unable to open socket\n");
cce = "unable to open socket";
goto oom4;
}
- if (lws_plat_set_socket_options(wsi->vhost, wsi->sock)) {
+ if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd)) {
lwsl_err("Failed to set wsi socket options\n");
- compatible_close(wsi->sock);
+ compatible_close(wsi->desc.sockfd);
cce = "set socket opts failed";
goto oom4;
}
wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
- lws_libev_accept(wsi, wsi->sock);
- lws_libuv_accept(wsi, wsi->sock);
+ lws_libev_accept(wsi, wsi->desc);
+ lws_libuv_accept(wsi, wsi->desc);
if (insert_wsi_socket_into_fds(context, wsi)) {
- compatible_close(wsi->sock);
+ compatible_close(wsi->desc.sockfd);
cce = "insert wsi failed";
goto oom4;
}
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
AWAITING_TIMEOUT);
- n = lws_socket_bind(wsi->vhost, wsi->sock, 0, wsi->vhost->iface);
+ n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, wsi->vhost->iface);
if (n < 0) {
cce = "unable to bind socket";
goto failed;
n = sizeof(struct sockaddr);
}
- if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
+ if (connect(wsi->desc.sockfd, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
if (LWS_ERRNO == LWS_EALREADY ||
LWS_ERRNO == LWS_EINPROGRESS ||
LWS_ERRNO == LWS_EWOULDBLOCK
goto failed;
wsi->c_port = wsi->vhost->http_proxy_port;
- n = send(wsi->sock, (char *)pt->serv_buf, plen,
+ n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
MSG_NOSIGNAL);
if (n < 0) {
lwsl_debug("ERROR writing to proxy socket\n");
AWAITING_TIMEOUT);
wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
- pfd.fd = wsi->sock;
+ pfd.fd = wsi->desc.sockfd;
pfd.events = LWS_POLLIN;
pfd.revents = LWS_POLLIN;
/* close the connection by hand */
- compatible_close(wsi->sock);
+ compatible_close(wsi->desc.sockfd);
remove_wsi_socket_from_fds(wsi);
- wsi->sock = LWS_SOCK_INVALID;
+ wsi->desc.sockfd = LWS_SOCK_INVALID;
wsi->state = LWSS_CLIENT_UNCONNECTED;
wsi->protocol = NULL;
wsi->pending_timeout = NO_PENDING_TIMEOUT;
wsi->context = i->context;
/* assert the mode and union status (hdr) clearly */
lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
- wsi->sock = LWS_SOCK_INVALID;
+ wsi->desc.sockfd = LWS_SOCK_INVALID;
/* 1) fill up the wsi with stuff from the connect_info as far as it
* can go. It's because not only is our connection async, we might
return 0;
}
- n = recv(wsi->sock, sb, context->pt_serv_buf_size, 0);
+ n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
if (n < 0) {
if (LWS_ERRNO == LWS_EAGAIN) {
lwsl_debug("Proxy read returned EAGAIN... retrying\n");
wsi->u.ws.rx_ubuf_alloc = n;
lwsl_info("Allocating client RX buffer %d\n", n);
- if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n,
+ if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&n,
sizeof n)) {
lwsl_warn("Failed to set SNDBUF to %d", n);
cce = "HS: SO_SNDBUF failed";
while (vh) {
if (vh->lserv_wsi) {
vh->lserv_wsi->w_read.context = context;
- ev_io_init(w_accept, lws_accept_cb, vh->lserv_wsi->sock,
+ ev_io_init(w_accept, lws_accept_cb, vh->lserv_wsi->desc.sockfd,
EV_READ);
}
vh = vh->vhost_next;
}
LWS_VISIBLE void
-lws_libev_accept(struct lws *new_wsi, int accept_fd)
+lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)
{
struct lws_context *context = lws_get_context(new_wsi);
struct ev_io *r = &new_wsi->w_read.ev_watcher;
struct ev_io *w = &new_wsi->w_write.ev_watcher;
+ int fd;
if (!LWS_LIBEV_ENABLED(context))
return;
+ if (wsi->mode == LWSCM_RAW_FILEDESC)
+ fd = desc.filefd;
+ else
+ fd = desc.sockfd;
+
new_wsi->w_read.context = context;
new_wsi->w_write.context = context;
- ev_io_init(r, lws_accept_cb, accept_fd, EV_READ);
- ev_io_init(w, lws_accept_cb, accept_fd, EV_WRITE);
+ ev_io_init(r, lws_accept_cb, fd, EV_READ);
+ ev_io_init(w, lws_accept_cb, fd, EV_WRITE);
}
LWS_VISIBLE void
wsi->w_read.context = vh->context;
n = uv_poll_init_socket(pt->io_loop_uv,
- &wsi->w_read.uv_watcher, wsi->sock);
+ &wsi->w_read.uv_watcher, wsi->desc.sockfd);
if (n) {
lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
- n, (void *)(long)wsi->sock);
+ n, (void *)(long)wsi->desc.sockfd);
return -1;
}
}
void
-lws_libuv_accept(struct lws *wsi, lws_sockfd_type accept_fd)
+lws_libuv_accept(struct lws *wsi, lws_sock_file_fd_type desc)
{
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
lwsl_debug("%s: new wsi %p\n", __func__, wsi);
wsi->w_read.context = context;
-
- uv_poll_init_socket(pt->io_loop_uv, &wsi->w_read.uv_watcher, accept_fd);
+ if (wsi->mode == LWSCM_RAW_FILEDESC)
+ uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher,
+ desc.filefd);
+ else
+ uv_poll_init_socket(pt->io_loop_uv, &wsi->w_read.uv_watcher,
+ desc.sockfd);
}
void
if (!wsi)
return;
+ if (wsi->mode == LWSCM_RAW_FILEDESC) {
+ remove_wsi_socket_from_fds(wsi);
+ wsi->protocol->callback(wsi,
+ LWS_CALLBACK_RAW_CLOSE_FILE, wsi->user_space, NULL, 0);
+ lws_free_wsi(wsi);
+
+ return;
+ }
+
lws_access_log(wsi);
#if defined(LWS_WITH_ESP8266)
if (wsi->premature_rx)
#endif
if (wsi->mode == LWSCM_RAW) {
- wsi->vhost->protocols->callback(wsi,
+ wsi->protocol->callback(wsi,
LWS_CALLBACK_RAW_CLOSE, wsi->user_space, NULL, 0);
wsi->socket_is_permanently_unusable = 1;
goto just_kill_connection;
#ifdef LWS_OPENSSL_SUPPORT
if (lws_is_ssl(wsi) && wsi->ssl)
{
- lwsl_info("%s: shutting down SSL connection: %p (ssl %p, sock %d, state %d)\n", __func__, wsi, wsi->ssl, (int)(long)wsi->sock, wsi->state);
+ lwsl_info("%s: shutting down SSL connection: %p (ssl %p, sock %d, state %d)\n", __func__, wsi, wsi->ssl, (int)(long)wsi->desc.sockfd, wsi->state);
n = SSL_shutdown(wsi->ssl);
if (n == 0) /* Complete bidirectional SSL shutdown */
n = SSL_shutdown(wsi->ssl);
- n = shutdown(wsi->sock, SHUT_WR);
+ n = shutdown(wsi->desc.sockfd, SHUT_WR);
}
else
#endif
{
- lwsl_info("%s: shutting down connection: %p (sock %d, state %d)\n", __func__, wsi, (int)(long)wsi->sock, wsi->state);
- n = shutdown(wsi->sock, SHUT_WR);
+ lwsl_info("%s: shutting down connection: %p (sock %d, state %d)\n", __func__, wsi, (int)(long)wsi->desc.sockfd, wsi->state);
+ n = shutdown(wsi->desc.sockfd, SHUT_WR);
}
if (n)
lwsl_debug("closing: shutdown (state %d) ret %d\n", wsi->state, LWS_ERRNO);
#endif
lwsl_info("%s: real just_kill_connection: %p (sockfd %d)\n", __func__,
- wsi, wsi->sock);
+ wsi, wsi->desc.sockfd);
#ifdef LWS_WITH_HTTP_PROXY
if (wsi->rw) {
lws_remove_from_timeout_list(wsi);
/* checking return redundant since we anyway close */
- if (wsi->sock != LWS_SOCK_INVALID)
+ if (wsi->desc.sockfd != LWS_SOCK_INVALID)
remove_wsi_socket_from_fds(wsi);
#if defined(LWS_WITH_ESP8266)
- espconn_disconnect(wsi->sock);
+ espconn_disconnect(wsi->desc.sockfd);
#endif
wsi->state = LWSS_DEAD_SOCKET;
{
int n;
- if (!lws_ssl_close(wsi) && lws_socket_is_valid(wsi->sock)) {
+ if (!lws_ssl_close(wsi) && lws_socket_is_valid(wsi->desc.sockfd)) {
#if LWS_POSIX
- //lwsl_err("*** closing sockfd %d\n", wsi->sock);
- n = compatible_close(wsi->sock);
+ //lwsl_err("*** closing sockfd %d\n", wsi->desc.sockfd);
+ n = compatible_close(wsi->desc.sockfd);
if (n)
lwsl_debug("closing: close ret %d\n", LWS_ERRNO);
#else
- compatible_close(wsi->sock);
+ compatible_close(wsi->desc.sockfd);
(void)n;
#endif
- wsi->sock = LWS_SOCK_INVALID;
+ wsi->desc.sockfd = LWS_SOCK_INVALID;
}
/* outermost destroy notification for wsi (user_space still intact) */
}
olen = len;
- if (getpeername(wsi->sock, p, &len) < 0 || len > olen) {
+ if (getpeername(wsi->desc.sockfd, p, &len) < 0 || len > olen) {
lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
return NULL;
}
LWS_VISIBLE int
lws_get_socket_fd(struct lws *wsi)
{
- return wsi->sock;
+ return wsi->desc.sockfd;
}
#endif
new_wsi->protocol = context->vhost_list->protocols;
new_wsi->user_space = NULL;
new_wsi->ietf_spec_revision = 0;
- new_wsi->sock = LWS_SOCK_INVALID;
+ new_wsi->desc.sockfd = LWS_SOCK_INVALID;
context->count_wsi_allocated++;
return new_wsi;
// cgi->pipe_fds[n][!!(n == 0)], cgi->pipe_fds[n][!(n == 0)]);
/* read side is 0, stdin we want the write side, others read */
- cgi->stdwsi[n]->sock = cgi->pipe_fds[n][!!(n == 0)];
+ cgi->stdwsi[n]->desc.sockfd = cgi->pipe_fds[n][!!(n == 0)];
if (fcntl(cgi->pipe_fds[n][!!(n == 0)], F_SETFL, O_NONBLOCK) < 0) {
lwsl_err("%s: setting NONBLOCK failed\n", __func__);
goto bail2;
}
for (n = 0; n < 3; n++) {
- lws_libuv_accept(cgi->stdwsi[n], cgi->stdwsi[n]->sock);
+ lws_libuv_accept(cgi->stdwsi[n], cgi->stdwsi[n]->desc);
if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
goto bail3;
cgi->stdwsi[n]->parent = wsi;
lws_change_pollfd(cgi->stdwsi[LWS_STDERR], LWS_POLLOUT, LWS_POLLIN);
lwsl_debug("%s: fds in %d, out %d, err %d\n", __func__,
- cgi->stdwsi[LWS_STDIN]->sock, cgi->stdwsi[LWS_STDOUT]->sock,
- cgi->stdwsi[LWS_STDERR]->sock);
+ cgi->stdwsi[LWS_STDIN]->desc.sockfd,
+ cgi->stdwsi[LWS_STDOUT]->desc.sockfd,
+ cgi->stdwsi[LWS_STDERR]->desc.sockfd);
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);
LWS_CALLBACK_RAW_WRITEABLE = 61,
/**< RAW mode connection may be written */
LWS_CALLBACK_RAW_ADOPT = 62,
- /**< RAW mode connection was adopted (equivalent to 'created') */
+ /**< RAW mode connection was adopted (equivalent to 'wsi created') */
+ LWS_CALLBACK_RAW_ADOPT_FILE = 63,
+ /**< RAW mode file was adopted (equivalent to 'wsi created') */
+ LWS_CALLBACK_RAW_RX_FILE = 64,
+ /**< RAW mode file has something to read */
+ LWS_CALLBACK_RAW_WRITEABLE_FILE = 65,
+ /**< RAW mode file is writeable */
+ LWS_CALLBACK_RAW_CLOSE_FILE = 66,
+ /**< RAW mode wsi that adopted a file is closing */
/****** add new things just above ---^ ******/
LWS_CALLBACK_USER = 1000,
- /**< user code can use any including / above without fear of clashes */
+ /**< user code can use any including above without fear of clashes */
};
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
+
+typedef enum {
+ LWS_ADOPT_HTTP = 1, /* absent implies RAW */
+ LWS_ADOPT_SOCKET = 2, /* absent implies file descriptor */
+ LWS_ADOPT_ALLOW_SSL = 4 /* if set requires LWS_ADOPT_SOCKET */
+} lws_adoption_type;
+
+typedef union {
+ lws_sockfd_type sockfd;
+ lws_filefd_type filefd;
+} lws_sock_file_fd_type;
+
/*
-* lws_adopt_socket_vhost2() - adopt foreign socket as if listen socket accepted it
-* for vhost, allow control over defeat SSL and raw transport mode
+* lws_adopt_descriptor_vhost() - adopt foreign socket or file descriptor
+* if socket descriptor, should already have been accepted from listen socket
+*
* \param vhost: lws vhost
-* \param accept_fd: fd of already-accepted socket to adopt
-* \param allow_ssl: 0 = no SSL even if vhost supports, 1 = SSL if vhost supports
-* \param raw: 0 = http[s]/wss[s], 1 = raw mode semantics
+* \param type: OR-ed combinations of lws_adoption_type flags
+* \param fd: union with either .sockfd or .filefd set
+* \param vh_prot_name: NULL or vh protocol name to bind raw connection to
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
-* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
-* to ws or just serve http.
+* If LWS_ADOPT_SOCKET is set, LWS adopts the socket in http serving mode, it's
+* ready to accept an upgrade to ws or just serve http.
*/
LWS_VISIBLE struct lws *
-lws_adopt_socket_vhost2(struct lws_vhost *vh, lws_sockfd_type accept_fd,
- int allow_ssl, int raw);
+lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
+ lws_sock_file_fd_type fd, const char *vh_prot_name);
+
/**
* lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
};
#if defined(WIN32) || defined(_WIN32)
/* ... */
+#if !defined(ssize_t)
typedef SSIZE_T ssize_t;
+#endif
/* !!! >:-[ */
typedef unsigned __int32 uint32_t;
typedef unsigned __int8 uint8_t;
return 1;
FD_ZERO(&writefds);
- FD_SET(wsi->sock, &writefds);
+ FD_SET(wsi->desc.sockfd, &writefds);
- if (select(wsi->sock + 1, NULL, &writefds, NULL, &tv) < 1)
+ if (select(wsi->desc.sockfd + 1, NULL, &writefds, NULL, &tv) < 1)
return 1;
return 0;
//lwsl_notice("%s: wsi %p: len %d\n", __func__, wsi, len);
wsi->pending_send_completion++;
- espconn_send(wsi->sock, buf, len);
+ espconn_send(wsi->desc.sockfd, buf, len);
return len;
}
const char *
lws_plat_get_peer_simple(struct lws *wsi, char *name, int namelen)
{
- unsigned char *p = wsi->sock->proto.tcp->remote_ip;
+ unsigned char *p = wsi->desc.sockfd->proto.tcp->remote_ip;
lws_snprintf(name, namelen, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
fd->reverse = wsi;
for (n = 0; n < wsi->context->max_fds ; n++)
- if (wsi->context->connpool[n] == wsi->sock)
+ if (wsi->context->connpool[n] == wsi->desc.sockfd)
wsi->position_in_fds_table = n;
}
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
context->connpool[wsi->position_in_fds_table + context->max_fds] = (lws_sockfd_type)wsi;
- wsi->sock->reverse = wsi;
+ wsi->desc.sockfd->reverse = wsi;
pt->fds_count++;
}
int n;
for (n = 0; n < wsi->context->max_fds; n++)
- if (wsi->context->connpool[n] == wsi->sock) {
+ if (wsi->context->connpool[n] == wsi->desc.sockfd) {
wsi->context->connpool[n] = NULL;
wsi->context->connpool[n + wsi->context->max_fds] = NULL;
lwsl_notice(" freed connpool %d\n", n);
}
- wsi->sock->reverse = NULL;
+ wsi->desc.sockfd->reverse = NULL;
pt->fds_count--;
}
lwsl_notice("replaying buffered rx: wsi %p\n", wsi);
p = wsi->premature_rx;
wsi->premature_rx = NULL;
- esp8266_cb_rx(wsi->sock,
+ esp8266_cb_rx(wsi->desc.sockfd,
(char *)p + wsi->prem_rx_pos,
wsi->prem_rx_size - wsi->prem_rx_pos);
wsi->prem_rx_size = 0;
wsi->prem_rx_pos = 0;
lws_free(p);
}
- if (espconn_recv_unhold(wsi->sock) < 0)
+ if (espconn_recv_unhold(wsi->desc.sockfd) < 0)
return -1;
} else
- if (espconn_recv_hold(wsi->sock) < 0)
+ if (espconn_recv_hold(wsi->desc.sockfd) < 0)
return -1;
if (!(pfd->events & LWS_POLLOUT))
if (wsi->trunc_len)
return 1;
- fds.fd = wsi->sock;
+ fds.fd = wsi->desc.sockfd;
fds.events = POLLOUT;
fds.revents = 0;
if (wsi->trunc_len)
return 1;
- fds.fd = wsi->sock;
+ fds.fd = wsi->desc.sockfd;
fds.events = POLLOUT;
fds.revents = 0;
int n = 0;
for (n = 0; n < context->fd_hashtable[h].length; n++)
- if (context->fd_hashtable[h].wsi[n]->sock == fd)
+ if (context->fd_hashtable[h].wsi[n]->desc.sockfd == fd)
return context->fd_hashtable[h].wsi[n];
return NULL;
int
insert_wsi(struct lws_context *context, struct lws *wsi)
{
- int h = LWS_FD_HASH(wsi->sock);
+ int h = LWS_FD_HASH(wsi->desc.sockfd);
if (context->fd_hashtable[h].length == (getdtablesize() - 1)) {
lwsl_err("hash table overflow\n");
int n = 0;
for (n = 0; n < context->fd_hashtable[h].length; n++)
- if (context->fd_hashtable[h].wsi[n]->sock == fd) {
+ if (context->fd_hashtable[h].wsi[n]->desc.sockfd == fd) {
while (n < context->fd_hashtable[h].length) {
context->fd_hashtable[h].wsi[n] =
context->fd_hashtable[h].wsi[n + 1];
pt->fds[pt->fds_count++].revents = 0;
pt->events[pt->fds_count] = pt->events[0];
- WSAEventSelect(wsi->sock, pt->events[0],
+ WSAEventSelect(wsi->desc.sockfd, pt->events[0],
LWS_POLLIN | LWS_POLLHUP | FD_CONNECT);
}
int optVal;
int optLen = sizeof(int);
- if (getsockopt(wsi->sock, SOL_SOCKET, SO_ERROR,
+ if (getsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_ERROR,
(char*)&optVal, &optLen) != SOCKET_ERROR && optVal &&
optVal != LWS_EALREADY && optVal != LWS_EINPROGRESS &&
optVal != LWS_EWOULDBLOCK && optVal != WSAEINVAL) {
if ((pfd->events & LWS_POLLOUT))
networkevents |= LWS_POLLOUT;
- if (WSAEventSelect(wsi->sock,
+ if (WSAEventSelect(wsi->desc.sockfd,
pt->events[0],
networkevents) != SOCKET_ERROR)
return 0;
goto handle_truncated_send;
}
- if (!lws_socket_is_valid(wsi->sock))
+ if (!lws_socket_is_valid(wsi->desc.sockfd))
lwsl_warn("** error invalid sock but expected to send\n");
/* limit sending */
{
int n;
- n = recv(wsi->sock, (char *)buf, len, 0);
+ n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
if (n >= 0) {
if (wsi->vhost)
wsi->vhost->conn_stats.rx += n;
int n = 0;
#if LWS_POSIX
- n = send(wsi->sock, (char *)buf, len, MSG_NOSIGNAL);
+ n = send(wsi->desc.sockfd, (char *)buf, len, MSG_NOSIGNAL);
// lwsl_info("%s: sent len %d result %d", __func__, len, n);
if (n >= 0)
return n;
// !!!
#endif
- lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n", len, wsi->sock, n, LWS_ERRNO);
+ lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n", len, wsi->desc.sockfd, n, LWS_ERRNO);
return LWS_SSL_CAPABLE_ERROR;
}
#endif
wsi->position_in_fds_table < pt->fds_count);
pfd = &pt->fds[wsi->position_in_fds_table];
- pa->fd = wsi->sock;
+ pa->fd = wsi->desc.sockfd;
pa->prev_events = pfd->events;
pa->events = pfd->events = (pfd->events & ~_and) | _or;
int
insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
{
- struct lws_pollargs pa = { wsi->sock, LWS_POLLIN, 0 };
+ struct lws_pollargs pa = { wsi->desc.sockfd, LWS_POLLIN, 0 };
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
int ret = 0;
lwsl_debug("%s: %p: tsi=%d, sock=%d, pos-in-fds=%d\n",
- __func__, wsi, wsi->tsi, wsi->sock, pt->fds_count);
+ __func__, wsi, wsi->tsi, wsi->desc.sockfd, pt->fds_count);
if ((unsigned int)pt->fds_count >= context->fd_limit_per_thread) {
lwsl_err("Too many fds (%d vs %d)\n", context->max_fds,
}
#if !defined(_WIN32) && !defined(LWS_WITH_ESP8266)
- if (wsi->sock >= context->max_fds) {
+ if (wsi->desc.sockfd >= context->max_fds) {
lwsl_err("Socket fd %d is too high (%d)\n",
- wsi->sock, context->max_fds);
+ wsi->desc.sockfd, context->max_fds);
return 1;
}
#endif
assert(wsi);
assert(wsi->vhost);
- assert(lws_socket_is_valid(wsi->sock));
+ assert(lws_socket_is_valid(wsi->desc.sockfd));
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
wsi->user_space, (void *) &pa, 1))
// lwsl_notice("%s: %p: setting posinfds %d\n", __func__, wsi, wsi->position_in_fds_table);
- pt->fds[wsi->position_in_fds_table].fd = wsi->sock;
+ pt->fds[wsi->position_in_fds_table].fd = wsi->desc.sockfd;
#if LWS_POSIX
pt->fds[wsi->position_in_fds_table].events = LWS_POLLIN;
#else
remove_wsi_socket_from_fds(struct lws *wsi)
{
struct lws_context *context = wsi->context;
- struct lws_pollargs pa = { wsi->sock, 0, 0 };
+ struct lws_pollargs pa = { wsi->desc.sockfd, 0, 0 };
#if !defined(LWS_WITH_ESP8266)
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
struct lws *end_wsi;
int m, ret = 0;
#if !defined(_WIN32) && !defined(LWS_WITH_ESP8266)
- if (wsi->sock > context->max_fds) {
- lwsl_err("fd %d too high (%d)\n", wsi->sock, context->max_fds);
+ if (wsi->desc.sockfd > context->max_fds) {
+ lwsl_err("fd %d too high (%d)\n", wsi->desc.sockfd, context->max_fds);
return 1;
}
#endif
lws_pt_lock(pt);
lwsl_debug("%s: wsi=%p, sock=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
- __func__, wsi, wsi->sock, wsi->position_in_fds_table,
+ __func__, wsi, wsi->desc.sockfd, wsi->position_in_fds_table,
pt->fds_count, pt->fds[pt->fds_count].fd);
/* have the last guy take up the now vacant slot */
end_wsi->position_in_fds_table = m;
/* deletion guy's lws_lookup entry needs nuking */
- delete_from_fd(context, wsi->sock);
+ delete_from_fd(context, wsi->desc.sockfd);
/* removed wsi has no position any more */
wsi->position_in_fds_table = -1;
/* remove also from external POLL support via protocol 0 */
- if (lws_socket_is_valid(wsi->sock))
+ if (lws_socket_is_valid(wsi->desc.sockfd))
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_DEL_POLL_FD,
wsi->user_space, (void *) &pa, 0))
ret = -1;
return 1;
if (wsi->position_in_fds_table < 0) {
- lwsl_err("%s: failed to find socket %d\n", __func__, wsi->sock);
+ lwsl_err("%s: failed to find socket %d\n", __func__, wsi->desc.sockfd);
return -1;
}
/* special internal types */
LWSCM_SERVER_LISTENER,
LWSCM_CGI, /* stdin, stdout, stderr for another cgi master wsi */
- LWSCM_RAW, /* raw */
+ LWSCM_RAW, /* raw with bulk handling */
+ LWSCM_RAW_FILEDESC, /* raw without bulk handling */
/* HTTP Client related */
LWSCM_HTTP_CLIENT = LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP,
#if defined(LWS_USE_LIBEV)
LWS_EXTERN void
-lws_libev_accept(struct lws *new_wsi, lws_sockfd_type accept_fd);
-LWS_EXTERN void
+lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
lws_libev_io(struct lws *wsi, int flags);
LWS_EXTERN int
lws_libev_init_fd_table(struct lws_context *context);
#if defined(LWS_USE_LIBUV)
LWS_EXTERN void
-lws_libuv_accept(struct lws *new_wsi, lws_sockfd_type accept_fd);
+lws_libuv_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
LWS_EXTERN void
lws_libuv_io(struct lws *wsi, int flags);
LWS_EXTERN int
unsigned long action_start;
unsigned long latency_start;
#endif
- /* pointer / int */
- lws_sockfd_type sock;
+ lws_sock_file_fd_type desc; /* .filefd / .sockfd */
/* ints */
int position_in_fds_table;
delete_from_fd(struct lws_context *context, lws_sockfd_type fd);
#else
#define wsi_from_fd(A,B) A->lws_lookup[B]
-#define insert_wsi(A,B) assert(A->lws_lookup[B->sock] == 0); A->lws_lookup[B->sock]=B
+#define insert_wsi(A,B) assert(A->lws_lookup[B->desc.sockfd] == 0); A->lws_lookup[B->desc.sockfd]=B
#define delete_from_fd(A,B) A->lws_lookup[B]=0
#endif
goto bail;
}
wsi->context = vhost->context;
- wsi->sock = sockfd;
+ wsi->desc.sockfd = sockfd;
wsi->mode = LWSCM_SERVER_LISTENER;
wsi->protocol = vhost->protocols;
wsi->tsi = m;
vhost->lserv_wsi = wsi;
#if LWS_POSIX
- n = listen(wsi->sock, LWS_SOMAXCONN);
+ n = listen(wsi->desc.sockfd, LWS_SOMAXCONN);
if (n < 0) {
lwsl_err("listen failed with error %d\n", LWS_ERRNO);
vhost->lserv_wsi = NULL;
} /* for each thread able to independently listen */
#else
#if defined(LWS_WITH_ESP8266)
- esp8266_tcp_stream_bind(wsi->sock, info->port, wsi);
+ esp8266_tcp_stream_bind(wsi->desc.sockfd, info->port, wsi);
#endif
#endif
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
wsi->u.ws.rx_ubuf_alloc = n;
lwsl_debug("Allocating RX buffer %d\n", n);
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
- if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF,
+ if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
(const char *)&n, sizeof n)) {
lwsl_warn("Failed to set SNDBUF to %d", n);
return 1;
new_wsi->protocol = vhost->protocols;
new_wsi->user_space = NULL;
new_wsi->ietf_spec_revision = 0;
- new_wsi->sock = LWS_SOCK_INVALID;
+ new_wsi->desc.sockfd = LWS_SOCK_INVALID;
vhost->context->count_wsi_allocated++;
/*
return 0;
}
+/* if not a socket, it's a raw, non-ssl file descriptor */
+
LWS_VISIBLE struct lws *
-lws_adopt_socket_vhost2(struct lws_vhost *vh, lws_sockfd_type accept_fd,
- int allow_ssl, int raw)
+lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
+ lws_sock_file_fd_type fd, const char *vh_prot_name)
{
struct lws_context *context = vh->context;
struct lws *new_wsi = lws_create_new_server_wsi(vh);
- int n;
+ int n, ssl = 0;
if (!new_wsi) {
- compatible_close(accept_fd);
+ if (type & LWS_ADOPT_SOCKET)
+ compatible_close(fd.sockfd);
return NULL;
}
- lwsl_debug("%s: new wsi %p, sockfd %d, cb %p\n", __func__, new_wsi,
- accept_fd, context->vhost_list->protocols[0].callback);
+ new_wsi->desc = fd;
+ new_wsi->protocol = &context->vhost_list->
+ protocols[vh->default_protocol_index];
+
+ if (!(type & LWS_ADOPT_SOCKET)) {
+ new_wsi->protocol = lws_vhost_name_to_protocol(new_wsi->vhost,
+ vh_prot_name);
+ if (!new_wsi->protocol) {
+ lwsl_err("Protocol %s not enabled on vhost %s\n",
+ vh_prot_name, new_wsi->vhost->name);
+ lws_free(new_wsi);
+
+ return NULL;
+ }
+ }
+ if (type & LWS_ADOPT_SOCKET) {
+
+ lwsl_debug("%s: new wsi %p, sockfd %d\n", __func__, new_wsi,
+ (int)(size_t)fd.sockfd);
- new_wsi->sock = accept_fd;
- /* the transport is accepted... give him time to negotiate */
- lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
- context->timeout_secs);
+ /* the transport is accepted... give him time to negotiate */
+ lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
+ context->timeout_secs);
#if LWS_POSIX == 0
#if defined(LWS_WITH_ESP8266)
- esp8266_tcp_stream_accept(accept_fd, new_wsi);
+ esp8266_tcp_stream_accept(accept_fd, new_wsi);
#endif
#endif
+ } else //* file desc */
+ lwsl_debug("%s: new wsi %p, filefd %d\n", __func__, new_wsi,
+ (int)(size_t)fd.filefd);
+
/*
* A new connection was accepted. Give the user a chance to
* set properties of the newly created wsi. There's no protocol
* itself by default protocols[0]
*/
n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
- if (raw)
- n = LWS_CALLBACK_RAW_ADOPT;
- if ((context->vhost_list->protocols[vh->default_protocol_index].callback)(
+ if (!(type & LWS_ADOPT_HTTP)) {
+ if (!(type & LWS_ADOPT_SOCKET))
+ n = LWS_CALLBACK_RAW_ADOPT_FILE;
+ else
+ n = LWS_CALLBACK_RAW_ADOPT;
+ }
+ if ((new_wsi->protocol->callback)(
new_wsi, n, NULL, NULL, 0)) {
- /* force us off the timeout list by hand */
- lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0);
- compatible_close(new_wsi->sock);
+ if (type & LWS_ADOPT_SOCKET) {
+ /* force us off the timeout list by hand */
+ lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0);
+ compatible_close(new_wsi->desc.sockfd);
+ }
lws_free(new_wsi);
return NULL;
}
- lws_libev_accept(new_wsi, new_wsi->sock);
- lws_libuv_accept(new_wsi, new_wsi->sock);
-
- if (!LWS_SSL_ENABLED(new_wsi->vhost) || allow_ssl == 0) {
- if (raw)
- new_wsi->mode = LWSCM_RAW;
- if (insert_wsi_socket_into_fds(context, new_wsi)) {
- lwsl_err("%s: fail inserting socket\n", __func__);
- goto fail;
+ if (!LWS_SSL_ENABLED(new_wsi->vhost) || !(type & LWS_ADOPT_ALLOW_SSL) ||
+ !(type & LWS_ADOPT_SOCKET)) {
+ /* non-SSL */
+ if (!(type & LWS_ADOPT_HTTP)) {
+ if (!(type & LWS_ADOPT_SOCKET))
+ new_wsi->mode = LWSCM_RAW_FILEDESC;
+ else
+ new_wsi->mode = LWSCM_RAW;
}
} else {
- if (raw)
+ /* SSL */
+ if (!(type & LWS_ADOPT_HTTP))
new_wsi->mode = LWSCM_SSL_INIT_RAW;
else
new_wsi->mode = LWSCM_SSL_INIT;
- if (lws_server_socket_service_ssl(new_wsi, accept_fd)) {
+
+ ssl = 1;
+ }
+
+ lws_libev_accept(new_wsi, new_wsi->desc);
+ lws_libuv_accept(new_wsi, new_wsi->desc);
+
+ if (!ssl) {
+ if (insert_wsi_socket_into_fds(context, new_wsi)) {
+ lwsl_err("%s: fail inserting socket\n", __func__);
+ goto fail;
+ }
+ } else
+ if (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {
lwsl_err("%s: fail ssl negotiation\n", __func__);
goto fail;
}
- }
- if (!lws_header_table_attach(new_wsi, 0))
- lwsl_debug("Attached ah immediately\n");
+ if (type & LWS_ADOPT_HTTP)
+ if (!lws_header_table_attach(new_wsi, 0))
+ lwsl_debug("Attached ah immediately\n");
return new_wsi;
fail:
- lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);
+ if (type & LWS_ADOPT_SOCKET)
+ lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);
return NULL;
}
LWS_VISIBLE struct lws *
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
{
- return lws_adopt_socket_vhost2(vh, accept_fd, 1, 0);
+ lws_sock_file_fd_type fd;
+
+ fd.sockfd = accept_fd;
+ return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
+ LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL);
}
LWS_VISIBLE struct lws *
lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
{
- return lws_adopt_socket_vhost2(context->vhost_list, accept_fd, 1, 0);
+ return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
}
/* Common read-buffer adoption for lws_adopt_*_readbuf */
case LWSCM_RAW:
n = LWS_CALLBACK_RAW_WRITEABLE;
break;
+ case LWSCM_RAW_FILEDESC:
+ n = LWS_CALLBACK_RAW_WRITEABLE_FILE;
+ break;
case LWSCM_WS_CLIENT:
n = LWS_CALLBACK_CLIENT_WRITEABLE;
break;
*/
ret = 1;
- if (wsi->mode == LWSCM_RAW)
+ if (wsi->mode == LWSCM_RAW || wsi->mode == LWSCM_RAW_FILEDESC)
ret = 0;
while (ret == 1) {
*/
if ((time_t)sec > wsi->pending_timeout_limit) {
//#if LWS_POSIX
- if (wsi->sock != LWS_SOCK_INVALID && wsi->position_in_fds_table >= 0)
+ if (wsi->desc.sockfd != LWS_SOCK_INVALID && wsi->position_in_fds_table >= 0)
n = pt->fds[wsi->position_in_fds_table].events;
/* no need to log normal idle keepalive timeout */
while (wsi) {
/* we have to take copies, because he may be deleted */
wsi1 = wsi->timeout_list;
- tmp_fd = wsi->sock;
+ tmp_fd = wsi->desc.sockfd;
if (lws_service_timeout_check(wsi, (unsigned int)now)) {
/* he did time out... */
if (tmp_fd == our_fd)
return 1;
goto handled;
+ case LWSCM_RAW_FILEDESC:
+ case LWSCM_RAW:
+ if (pollfd->revents & LWS_POLLOUT) {
+ n = lws_calllback_as_writeable(wsi);
+ if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
+ lwsl_info("failed at set pollfd\n");
+ return 1;
+ }
+ if (n)
+ goto close_and_handled;
+ }
+ n = LWS_CALLBACK_RAW_RX;
+ if (wsi->mode == LWSCM_RAW_FILEDESC)
+ n = LWS_CALLBACK_RAW_RX_FILE;
+
+ if (pollfd->revents & LWS_POLLIN) {
+ if (user_callback_handle_rxflow(
+ wsi->protocol->callback,
+ wsi, n,
+ wsi->user_space, NULL, 0)) {
+ lwsl_debug("raw rx callback closed it\n");
+ goto close_and_handled;
+ }
+ }
+ n = 0;
+ goto handled;
+
case LWSCM_WS_SERVING:
case LWSCM_WS_CLIENT:
case LWSCM_HTTP2_SERVING:
case LWSCM_HTTP_CLIENT_ACCEPTED:
- case LWSCM_RAW:
/* 1: something requested a callback when it was OK to write */
if ((pollfd->revents & LWS_POLLOUT) &&
- ((wsi->mode == LWSCM_RAW) ||
- (wsi->state == LWSS_ESTABLISHED ||
+ ((wsi->state == LWSS_ESTABLISHED ||
wsi->state == LWSS_HTTP2_ESTABLISHED ||
wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS ||
wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
#endif
#endif /* USE_WOLFSSL */
- wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
+ wsi->client_bio = BIO_new_socket(wsi->desc.sockfd, BIO_NOCLOSE);
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
#ifdef USE_WOLFSSL
lws_latency_pre(context, wsi);
- n = recv(wsi->sock, (char *)pt->serv_buf, context->pt_serv_buf_size,
+ n = recv(wsi->desc.sockfd, (char *)pt->serv_buf, context->pt_serv_buf_size,
MSG_PEEK);
/*
break;
}
- lwsl_err("SSL_accept failed socket %u: %s\n", wsi->sock,
+ lwsl_err("SSL_accept failed socket %u: %s\n", wsi->desc.sockfd,
lws_ssl_get_error_string(m, n, buf, sizeof(buf)));
lws_ssl_elaborate_error();
goto fail;
--- /dev/null
+/*
+ * ws protocol handler plugin for testing raw file and raw socket
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The person who associated a work with this deed has dedicated
+ * the work to the public domain by waiving all of his or her rights
+ * to the work worldwide under copyright law, including all related
+ * and neighboring rights, to the extent allowed by law. You can copy,
+ * modify, distribute and perform the work, even for commercial purposes,
+ * all without asking permission.
+ *
+ * These test plugins are intended to be adapted for use in your code, which
+ * may be proprietary. So unlike the library itself, they are licensed
+ * Public Domain.
+ *
+ * Enable on a vhost like this
+ *
+ * "protocol-lws-raw-test": {
+ * "status": "ok",
+ * "fifo-path": "/tmp/lws-test-raw"
+ * },
+ *
+ * Then you can feed it data through the FIFO like this
+ *
+ * $ sudo sh -c "echo hello > /tmp/lws-test-raw"
+ *
+ * This plugin simply prints the data. But it does it through the lws event loop /
+ * service poll.
+ */
+
+#if !defined (LWS_PLUGIN_STATIC)
+#define LWS_DLL
+#define LWS_INTERNAL
+#include "../lib/libwebsockets.h"
+#endif
+
+#include <string.h>
+
+struct per_vhost_data__raw_test {
+ struct lws_context *context;
+ struct lws_vhost *vhost;
+ const struct lws_protocols *protocol;
+ char fifo_path[100];
+ int fifo;
+ char zero_length_read;
+};
+
+struct per_session_data__raw_test {
+ int number;
+};
+
+static int
+callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
+ void *user, void *in, size_t len)
+{
+ struct per_session_data__raw_test *pss =
+ (struct per_session_data__raw_test *)user;
+ struct per_vhost_data__raw_test *vhd =
+ (struct per_vhost_data__raw_test *)
+ lws_protocol_vh_priv_get(lws_get_vhost(wsi),
+ lws_get_protocol(wsi));
+ lws_sock_file_fd_type u;
+
+ (void)pss;
+
+ switch (reason) {
+ case LWS_CALLBACK_PROTOCOL_INIT:
+ vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+ lws_get_protocol(wsi),
+ sizeof(struct per_vhost_data__raw_test));
+ vhd->context = lws_get_context(wsi);
+ vhd->protocol = lws_get_protocol(wsi);
+ vhd->vhost = lws_get_vhost(wsi);
+ {
+ const struct lws_protocol_vhost_options *pvo =
+ (const struct lws_protocol_vhost_options *)in;
+ while (pvo) {
+ if (!strcmp(pvo->name, "fifo-path"))
+ strncpy(vhd->fifo_path, pvo->value, sizeof(vhd->fifo_path) - 1);
+ pvo = pvo->next;
+ }
+ if (vhd->fifo_path[0] == '\0') {
+ lwsl_err("Missing pvo \"fifo-path\"\n");
+ return 1;
+ }
+ }
+ unlink(vhd->fifo_path);
+ if (mkfifo(vhd->fifo_path, 0666)) {
+ lwsl_err("mkfifo failed\n");
+ return 1;
+ }
+ vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
+ if (vhd->fifo == -1) {
+ lwsl_err("opening fifo failed\n");
+ unlink(vhd->fifo_path);
+ return 1;
+ }
+ lwsl_notice("FIFO %s created\n", vhd->fifo_path);
+ u.filefd = vhd->fifo;
+ if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test")) {
+ lwsl_err("Failed to adopt fifo descriptor\n");
+ close(vhd->fifo);
+ unlink(vhd->fifo_path);
+ return 1;
+ }
+ break;
+
+ case LWS_CALLBACK_PROTOCOL_DESTROY:
+ if (!vhd)
+ break;
+ if (vhd->fifo >- 0) {
+ close(vhd->fifo);
+ unlink(vhd->fifo_path);
+ }
+ break;
+
+ case LWS_CALLBACK_RAW_ADOPT_FILE:
+ lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n");
+ break;
+
+
+ case LWS_CALLBACK_RAW_RX_FILE:
+ lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n");
+ {
+ char buf[256];
+ int n;
+
+ n = read(vhd->fifo, buf, sizeof(buf) - 1);
+ if (n < 0) {
+ lwsl_err("FIFO read failed\n");
+ return 1;
+ }
+ /*
+ * When nobody opened the other side of the FIFO, the FIFO fd acts well and
+ * only signals POLLIN when somebody opened and wrote to it.
+ *
+ * But if the other side of the FIFO closed it, we will see an endless
+ * POLLIN and 0 available to read.
+ *
+ * The only way to handle it is to reopen the FIFO our side and wait for a
+ * new peer. This is a quirk of FIFOs not of LWS.
+ */
+ if (n == 0) { /* peer closed - do reopen in close processing */
+ vhd->zero_length_read = 1;
+ return 1;
+ }
+ buf[n] = '\0';
+ lwsl_info("read %d\n", n);
+ puts(buf);
+ }
+ break;
+
+ case LWS_CALLBACK_RAW_CLOSE_FILE:
+ lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n");
+ if (vhd->zero_length_read) {
+ vhd->zero_length_read = 0;
+ close(vhd->fifo);
+ /* the wsi that adopted the fifo file is closing... reopen the fifo and readopt */
+ vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
+ if (vhd->fifo == -1) {
+ lwsl_err("opening fifo failed\n");
+ return 1;
+ }
+ lwsl_notice("FIFO %s reopened\n", vhd->fifo_path);
+ u.filefd = vhd->fifo;
+ if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test")) {
+ lwsl_err("Failed to adopt fifo descriptor\n");
+ close(vhd->fifo);
+ return 1;
+ }
+ }
+ break;
+
+ case LWS_CALLBACK_RAW_WRITEABLE_FILE:
+ lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n");
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+#define LWS_PLUGIN_PROTOCOL_RAW_TEST \
+ { \
+ "protocol-lws-raw-test", \
+ callback_raw_test, \
+ sizeof(struct per_session_data__raw_test), \
+ 1024, /* rx buf size must be >= permessage-deflate rx size */ \
+ }
+
+#if !defined (LWS_PLUGIN_STATIC)
+
+static const struct lws_protocols protocols[] = {
+ LWS_PLUGIN_PROTOCOL_RAW_TEST
+};
+
+LWS_EXTERN LWS_VISIBLE int
+init_protocol_lws_raw_test(struct lws_context *context,
+ struct lws_plugin_capability *c)
+{
+ if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
+ lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
+ c->api_magic);
+ return 1;
+ }
+
+ c->protocols = protocols;
+ c->count_protocols = ARRAY_SIZE(protocols);
+ c->extensions = NULL;
+ c->count_extensions = 0;
+
+ return 0;
+}
+
+LWS_EXTERN LWS_VISIBLE int
+destroy_protocol_lws_raw_test(struct lws_context *context)
+{
+ return 0;
+}
+
+#endif