mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-16 00:00:07 +01:00

Various kinds of input stashing were replaced with a single buflist before v3.0... this patch replaces the partial send arrangements with its own buflist in the same way. Buflists as the name says are growable lists of allocations in a linked-list that take care of book-keeping what's added and removed (even if what is removed is less than the current buffer on the list). The immediate result is that we no longer have to freak out if we had a partial buffered and new output is coming... we can just pile it on the end of the buflist and keep draining the front of it. Likewise we no longer need to be rabid about reporting multiple attempts to send stuff without going back to the event loop, although not doing that will introduce inefficiencies we don't have to term it "illegal" any more. Since buflists have proven reliable on the input side and the logic for dealing with truncated "non-network events" was already there this internal-only change should be relatively self-contained.
275 lines
6.3 KiB
C
275 lines
6.3 KiB
C
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
|
|
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
|
#endif
|
|
#include "core/private.h"
|
|
|
|
|
|
LWS_VISIBLE int
|
|
lws_send_pipe_choked(struct lws *wsi)
|
|
{ struct lws *wsi_eff = wsi;
|
|
|
|
#if defined(LWS_WITH_HTTP2)
|
|
wsi_eff = lws_get_network_wsi(wsi);
|
|
#endif
|
|
/* the fact we checked implies we avoided back-to-back writes */
|
|
wsi_eff->could_have_pending = 0;
|
|
|
|
/* treat the fact we got a truncated send pending as if we're choked */
|
|
if (lws_has_buffered_out(wsi_eff))
|
|
return 1;
|
|
|
|
return (int)wsi_eff->sock_send_blocking;
|
|
}
|
|
|
|
int
|
|
lws_poll_listen_fd(struct lws_pollfd *fd)
|
|
{
|
|
fd_set readfds;
|
|
struct timeval tv = { 0, 0 };
|
|
|
|
assert((fd->events & LWS_POLLIN) == LWS_POLLIN);
|
|
|
|
FD_ZERO(&readfds);
|
|
FD_SET(fd->fd, &readfds);
|
|
|
|
return select(((int)fd->fd) + 1, &readfds, NULL, NULL, &tv);
|
|
}
|
|
|
|
int
|
|
lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)
|
|
{
|
|
int optval = 1;
|
|
int optlen = sizeof(optval);
|
|
u_long optl = 1;
|
|
DWORD dwBytesRet;
|
|
struct tcp_keepalive alive;
|
|
int protonbr;
|
|
#ifndef _WIN32_WCE
|
|
struct protoent *tcp_proto;
|
|
#endif
|
|
|
|
if (vhost->ka_time) {
|
|
/* enable keepalive on this socket */
|
|
optval = 1;
|
|
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
|
|
(const char *)&optval, optlen) < 0)
|
|
return 1;
|
|
|
|
alive.onoff = TRUE;
|
|
alive.keepalivetime = vhost->ka_time;
|
|
alive.keepaliveinterval = vhost->ka_interval;
|
|
|
|
if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
|
|
NULL, 0, &dwBytesRet, NULL, NULL))
|
|
return 1;
|
|
}
|
|
|
|
/* Disable Nagle */
|
|
optval = 1;
|
|
#ifndef _WIN32_WCE
|
|
tcp_proto = getprotobyname("TCP");
|
|
if (!tcp_proto) {
|
|
lwsl_err("getprotobyname() failed with error %d\n", LWS_ERRNO);
|
|
return 1;
|
|
}
|
|
protonbr = tcp_proto->p_proto;
|
|
#else
|
|
protonbr = 6;
|
|
#endif
|
|
|
|
setsockopt(fd, protonbr, TCP_NODELAY, (const char *)&optval, optlen);
|
|
|
|
/* We are nonblocking... */
|
|
ioctlsocket(fd, FIONBIO, &optl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LWS_EXTERN int
|
|
lws_interface_to_sa(int ipv6,
|
|
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
|
|
{
|
|
#ifdef LWS_WITH_IPV6
|
|
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
|
|
|
|
if (ipv6) {
|
|
if (lws_plat_inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) {
|
|
return LWS_ITOSA_USABLE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
long long address = inet_addr(ifname);
|
|
|
|
if (address == INADDR_NONE) {
|
|
struct hostent *entry = gethostbyname(ifname);
|
|
if (entry)
|
|
address = ((struct in_addr *)entry->h_addr_list[0])->s_addr;
|
|
}
|
|
|
|
if (address == INADDR_NONE)
|
|
return LWS_ITOSA_NOT_EXIST;
|
|
|
|
addr->sin_addr.s_addr = (unsigned long)(lws_intptr_t)address;
|
|
|
|
return LWS_ITOSA_USABLE;
|
|
}
|
|
|
|
void
|
|
lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
|
{
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
|
|
|
pt->fds[pt->fds_count++].revents = 0;
|
|
WSAEventSelect(wsi->desc.sockfd, pt->events,
|
|
LWS_POLLIN | LWS_POLLHUP | FD_CONNECT);
|
|
}
|
|
|
|
void
|
|
lws_plat_delete_socket_from_fds(struct lws_context *context,
|
|
struct lws *wsi, int m)
|
|
{
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
|
|
|
pt->fds_count--;
|
|
}
|
|
|
|
|
|
int
|
|
lws_plat_check_connection_error(struct lws *wsi)
|
|
{
|
|
int optVal;
|
|
int optLen = sizeof(int);
|
|
|
|
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) {
|
|
lwsl_debug("Connect failed SO_ERROR=%d\n", optVal);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
lws_plat_change_pollfd(struct lws_context *context,
|
|
struct lws *wsi, struct lws_pollfd *pfd)
|
|
{
|
|
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
|
long networkevents = LWS_POLLHUP | FD_CONNECT;
|
|
|
|
if ((pfd->events & LWS_POLLIN))
|
|
networkevents |= LWS_POLLIN;
|
|
|
|
if ((pfd->events & LWS_POLLOUT))
|
|
networkevents |= LWS_POLLOUT;
|
|
|
|
if (WSAEventSelect(wsi->desc.sockfd, pt->events,
|
|
networkevents) != SOCKET_ERROR)
|
|
return 0;
|
|
|
|
lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO);
|
|
|
|
return 1;
|
|
}
|
|
|
|
const char *
|
|
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
|
{
|
|
WCHAR *buffer;
|
|
DWORD bufferlen = cnt;
|
|
BOOL ok = FALSE;
|
|
|
|
buffer = lws_malloc(bufferlen * 2, "inet_ntop");
|
|
if (!buffer) {
|
|
lwsl_err("Out of memory\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (af == AF_INET) {
|
|
struct sockaddr_in srcaddr;
|
|
bzero(&srcaddr, sizeof(srcaddr));
|
|
srcaddr.sin_family = AF_INET;
|
|
memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
|
|
|
|
if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
|
|
ok = TRUE;
|
|
#ifdef LWS_WITH_IPV6
|
|
} else if (af == AF_INET6) {
|
|
struct sockaddr_in6 srcaddr;
|
|
bzero(&srcaddr, sizeof(srcaddr));
|
|
srcaddr.sin6_family = AF_INET6;
|
|
memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));
|
|
|
|
if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
|
|
ok = TRUE;
|
|
#endif
|
|
} else
|
|
lwsl_err("Unsupported type\n");
|
|
|
|
if (!ok) {
|
|
int rv = WSAGetLastError();
|
|
lwsl_err("WSAAddressToString() : %d\n", rv);
|
|
} else {
|
|
if (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) <= 0)
|
|
ok = FALSE;
|
|
}
|
|
|
|
lws_free(buffer);
|
|
return ok ? dst : NULL;
|
|
}
|
|
|
|
int
|
|
lws_plat_inet_pton(int af, const char *src, void *dst)
|
|
{
|
|
WCHAR *buffer;
|
|
DWORD bufferlen = (int)strlen(src) + 1;
|
|
BOOL ok = FALSE;
|
|
|
|
buffer = lws_malloc(bufferlen * 2, "inet_pton");
|
|
if (!buffer) {
|
|
lwsl_err("Out of memory\n");
|
|
return -1;
|
|
}
|
|
|
|
if (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) <= 0) {
|
|
lwsl_err("Failed to convert multi byte to wide char\n");
|
|
lws_free(buffer);
|
|
return -1;
|
|
}
|
|
|
|
if (af == AF_INET) {
|
|
struct sockaddr_in dstaddr;
|
|
int dstaddrlen = sizeof(dstaddr);
|
|
bzero(&dstaddr, sizeof(dstaddr));
|
|
dstaddr.sin_family = AF_INET;
|
|
|
|
if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
|
|
ok = TRUE;
|
|
memcpy(dst, &dstaddr.sin_addr, sizeof(dstaddr.sin_addr));
|
|
}
|
|
#ifdef LWS_WITH_IPV6
|
|
} else if (af == AF_INET6) {
|
|
struct sockaddr_in6 dstaddr;
|
|
int dstaddrlen = sizeof(dstaddr);
|
|
bzero(&dstaddr, sizeof(dstaddr));
|
|
dstaddr.sin6_family = AF_INET6;
|
|
|
|
if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
|
|
ok = TRUE;
|
|
memcpy(dst, &dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr));
|
|
}
|
|
#endif
|
|
} else
|
|
lwsl_err("Unsupported type\n");
|
|
|
|
if (!ok) {
|
|
int rv = WSAGetLastError();
|
|
lwsl_err("WSAAddressToString() : %d\n", rv);
|
|
}
|
|
|
|
lws_free(buffer);
|
|
return ok ? 1 : -1;
|
|
}
|