diff --git a/CMakeLists.txt b/CMakeLists.txt index 403bbf6b9..b8d9c3556 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,26 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "NetB list(APPEND EVENT_LOOP_DEFINES "KQUEUE") set(USE_S2N ON) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + option(USE_VSOCK + "Build in support for VSOCK sockets" + OFF) + + file(GLOB AWS_IO_OS_HEADERS + ) + file(GLOB AWS_IO_OS_SRC + "source/emscripten/*.c" + "source/linux/*.c" + "source/posix/*.c" + ) + + set(EPOLL_SHIM_INCLUDE "source/emscripten") + + set(PLATFORM_LIBS "") + + set(EVENT_LOOP_DEFINE "EPOLL") + set(USE_S2N ON) endif() if (BYO_CRYPTO) @@ -215,6 +234,7 @@ endif() target_include_directories(${PROJECT_NAME} PUBLIC $ $) +target_include_directories(${PROJECT_NAME} PRIVATE ${EPOLL_SHIM_INCLUDE}) aws_use_package(aws-c-common) aws_use_package(aws-c-cal) diff --git a/source/emscripten/epoll.c b/source/emscripten/epoll.c new file mode 100644 index 000000000..db281f47a --- /dev/null +++ b/source/emscripten/epoll.c @@ -0,0 +1,35 @@ +#include +#include +#include + +#include + +static upoll_t* ups[OPEN_MAX]; +static int index = 1; + +int +epoll_create(int size) +{ + if (index >= OPEN_MAX) { + errno = ENFILE; + return -1; + } + ups[index++] = upoll_create(size); + return index - 1; +} + +int +epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) +{ + upoll_t* upq = ups[epfd]; + upoll_event_t* uevent = (upoll_event_t*) event; + return upoll_ctl(upq, op, fd, uevent); +} + +int +epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) +{ + upoll_t* upq = ups[epfd]; + upoll_event_t* uevents = (upoll_event_t*) events; + return upoll_wait(upq, uevents, maxevents, timeout); +} diff --git a/source/emscripten/sys/epoll.h b/source/emscripten/sys/epoll.h new file mode 100644 index 000000000..54ba3deba --- /dev/null +++ b/source/emscripten/sys/epoll.h @@ -0,0 +1,73 @@ +/* epoll.h + Copyright (c) fd0, All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library.*/ + +#ifndef _SYS_EPOLL_H +#define _SYS_EPOLL_H 1 + +#include +#include + +#ifndef OPEN_MAX +#define OPEN_MAX 256 +#endif + +#ifndef __EPOLL_PACKED +# define __EPOLL_PACKED __attribute__ ((__packed__)) +#endif + +#define EPOLLIN 0x01 +#define EPOLLOUT 0x02 +#define EPOLLERR 0x04 +#define EPOLLET 0x08 +#define EPOLLHUP 0x010 + +/* Valid opcodes ( "op" parameter ) to issue to epoll_ctl(). */ +#define EPOLL_CTL_ADD 1 /* Add a file descriptor to the interface. */ +#define EPOLL_CTL_DEL 2 /* Remove a file descriptor from the interface. */ +#define EPOLL_CTL_MOD 3 /* Change file descriptor epoll_event structure. */ + +typedef union epoll_data +{ + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; +} epoll_data_t; + +struct epoll_event +{ + uint32_t events; /* Epoll events */ + epoll_data_t data; /* User data variable */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int +epoll_create (int size); + +int +epoll_ctl (int epfd, int op, int fd, struct epoll_event *event); + +int +epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* sys/epoll.h */ diff --git a/source/emscripten/up.h b/source/emscripten/up.h new file mode 100644 index 000000000..2cea964b1 --- /dev/null +++ b/source/emscripten/up.h @@ -0,0 +1,48 @@ +#ifndef _UP_H_ +#define _UP_H_ + +#include +#include +#include + +#define UPOLL_CTL_ADD 1 +#define UPOLL_CTL_DEL 2 +#define UPOLL_CTL_MOD 3 + +#define UPOLLIN 0x01 +#define UPOLLOUT 0x02 +#define UPOLLERR 0x04 +#define UPOLLET 0x08 + +typedef struct upoll upoll_t; + +typedef union upoll_data { + void *ptr; + intptr_t fd; + uint32_t u32; + uint64_t u64; +} upoll_data_t; + +typedef struct upoll_event { + uint32_t events; + upoll_data_t data; +} upoll_event_t; + +upoll_t* upoll_create(uint32_t size); +int upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t *event); +int upoll_wait(upoll_t* upq, upoll_event_t *events, int maxevents, int timeout); +void upoll_destroy(upoll_t* upq); + +intptr_t usocket(int domain, int type, int proto); +intptr_t uaccept(intptr_t sock); + +int ubind(intptr_t sock, const char* name, const char* serv); +int ulisten(intptr_t sock, int backlog); +int uconnect(intptr_t sock, const char* name, const char* serv); +int uclose(intptr_t sock); +int uread(intptr_t fd, char* buf, size_t len); +int uwrite(intptr_t fd, const char* buf, size_t len); +int usocketpair(intptr_t socks[2], int async); + +#endif /* _UP_H_ */ + diff --git a/source/emscripten/upoll.c b/source/emscripten/upoll.c new file mode 100644 index 000000000..c7196fdf2 --- /dev/null +++ b/source/emscripten/upoll.c @@ -0,0 +1,632 @@ +#include "upoll.h" + +#define uhash_slot(K,S) (((K) ^ (K >> 8)) & (S - 1)) + +static uhash_t* uhash_create(uint32_t size) { + int i; + size--; + size |= size >> 1; + size |= size >> 2; + size |= size >> 4; + size |= size >> 8; + size |= size >> 16; + size++; + + uhash_t* hash = (uhash_t*)calloc(1, sizeof(uhash_t) + size * sizeof(ulist_t)); + hash->count = 0; + hash->size = size; + hash->items = (ulist_t*)(((char*)hash) + sizeof(uhash_t)); + + for (i = 0; i < size; i++) { + ulist_init(&hash->items[i]); + } + + return hash; +} + +static void* uhash_lookup(uhash_t* hash, intptr_t key) { + uint32_t slot = uhash_slot(key, hash->size); + ulist_t* q; + ulist_scan(q, &hash->items[slot]) { + uitem_t* i = ulist_data(q, uitem_t, list); + if (i->key == key) return i->val; + } + return NULL; +} +static void uhash_insert(uhash_t* hash, intptr_t key, void* val) { + uint32_t slot = uhash_slot(key, hash->size); + + uitem_t* item = (uitem_t*)calloc(1, sizeof(uitem_t)); + ulist_init(&item->list); + item->key = key; + item->val = val; + + ulist_append(&hash->items[slot], &item->list); +} +static int uhash_delete(uhash_t* hash, intptr_t key) { + uint32_t slot = uhash_slot(key, hash->size); + ulist_t* q; + ulist_scan(q, &hash->items[slot]) { + uitem_t* i = ulist_data(q, uitem_t, list); + if (i->key == key) { + ulist_remove(q); + free(q); + return 1; + } + } + return 0; +} +static int uhash_destroy(uhash_t* hash) { + int i; + for (i = 0; i < hash->size; i++) { + while (!ulist_empty(&hash->items[i])) { + ulist_t* q = ulist_next(&hash->items[i]); + uitem_t* n = ulist_data(q, uitem_t, list); + ulist_remove(q); + free(n); + } + } + return 0; +} + +upoll_t* upoll_create(uint32_t size) { + assert(size > 0); + upoll_t* upq = (upoll_t*)calloc(1, sizeof(upoll_t)); + + ulist_init(&upq->alive); + + upq->table = uhash_create(size); +#if defined(HAVE_EPOLL) + upq->fd = epoll_create(1); + assert(upq->fd >= 0); +#endif + return upq; +} + +void upoll_destroy(upoll_t* upq) { + assert(upq != NULL); + uhash_destroy(upq->table); + ulist_t* q; + unote_t* n; + while (!ulist_empty(&upq->alive)) { + q = ulist_next(&upq->alive); + n = ulist_data(n, unote_t, queue); + ulist_remove(q); + free(n); + } +#if defined(HAVE_EPOLL) + close(upq->fd); +#endif + free(upq); +} + +#if defined(HAVE_EPOLL) +int upoll_ctl_epoll(upoll_t* upq, int op, unote_t* note, upoll_event_t* event) { + assert(upq->fd >= 0); + struct epoll_event evt; + + evt.events = 0; + evt.data.ptr = note; + + if (event->events & UPOLLIN) { + evt.events |= EPOLLIN; + } + if (event->events & UPOLLOUT) { + evt.events |= EPOLLOUT; + } + if (event->events & UPOLLET) { + evt.events |= EPOLLET; + } + + int rc = 0; + switch (op) { + case UPOLL_CTL_ADD: { + rc = epoll_ctl(upq->fd, EPOLL_CTL_ADD, note->fd, &evt); + break; + } + case UPOLL_CTL_DEL: { + rc = epoll_ctl(upq->fd, EPOLL_CTL_DEL, note->fd, &evt); + break; + } + case UPOLL_CTL_MOD: { + rc = epoll_ctl(upq->fd, EPOLL_CTL_MOD, note->fd, &evt); + break; + } + } + if (rc < 0) return -errno; + return rc; +} +#endif + +int upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event) { + if (fd < 0) return -EBADF; + + unote_t* note = NULL; + switch (op) { + case UPOLL_CTL_ADD: { + note = (unote_t*)uhash_lookup(upq->table, fd); + if (!note) { + note = (unote_t*)calloc(1, sizeof(unote_t)); + note->upoll = upq; + ulist_init(¬e->queue); + note->event = *event; + note->fd = fd; + ulist_append(&upq->alive, ¬e->queue); + uhash_insert(upq->table, fd, (void*)note); + } + break; + } + case UPOLL_CTL_DEL: { + note = (unote_t*)uhash_lookup(upq->table, fd); + if (!note) return -ENOENT; + event = ¬e->event; + ulist_remove(¬e->queue); + uhash_delete(upq->table, fd); + free(note); + break; + } + case UPOLL_CTL_MOD: { + note = (unote_t*)uhash_lookup(upq->table, fd); + if (!note) return -ENOENT; + note->event = *event; + break; + } + default: { + return -EINVAL; + } + } +#if defined(HAVE_EPOLL) + return upoll_ctl_epoll(upq, op, note, event); +#else + return 0; +#endif +} + +#if defined(HAVE_EPOLL) +int upoll_wait_epoll(upoll_t* upq, upoll_event_t* evs, int nev, int timeout) { + struct epoll_event evts[nev]; + int i, n; + + n = epoll_wait(upq->fd, evts, nev, timeout); + if (n < 0) return -errno; + + for (i = 0; i < n; i++) { + uint32_t hint = 0; + unote_t* note = (unote_t*)evts[i].data.ptr; + if (evts[i].events & EPOLLIN) hint |= UPOLLIN; + if (evts[i].events & EPOLLOUT) hint |= UPOLLOUT; + if (evts[i].events & (EPOLLERR|EPOLLHUP)) hint |= (UPOLLERR|UPOLLIN); + + evs[i].data = note->event.data; + evs[i].events = hint; + } + return n; +} +#elif defined(HAVE_POLL) +int upoll_wait_poll(upoll_t* upq, upoll_event_t* evs, int nev, int timeout) { + /* FD_SETSIZE should be smaller than OPEN_MAX, but OPEN_MAX isn't portable */ + if (nev > FD_SETSIZE) nev = FD_SETSIZE; + + unote_t* nvec[nev]; + int r, i, nfds = 0; + uint32_t hint; + struct pollfd pfds[nev]; + + unote_t* n = NULL; + ulist_t* s = ulist_mark(&upq->alive); + ulist_t* q = ulist_next(&upq->alive); + + while (q != s && nfds < nev) { + n = ulist_data(q, unote_t, queue); + q = ulist_next(q); + + ulist_remove(&n->queue); + ulist_insert(&upq->alive, &n->queue); + + nvec[nfds] = n; + pfds[nfds].events = 0; + pfds[nfds].fd = n->fd; + if (n->event.events & UPOLLIN) { + pfds[nfds].events |= POLLIN; + } + if (n->event.events & UPOLLOUT) { + pfds[nfds].events |= POLLOUT; + } + nfds++; + } + + r = poll(pfds, nfds, timeout); + if (r < 0) return -errno; + + int e = 0; + for (i = 0; i < nfds && e < nev; i++) { + hint = 0; + if (pfds[i].revents) { + n = nvec[i]; + if (pfds[i].revents & POLLIN ) hint |= UPOLLIN; + if (pfds[i].revents & POLLOUT) hint |= UPOLLOUT; + if (pfds[i].revents & (POLLERR|POLLNVAL|POLLHUP)) hint |= (UPOLLERR|UPOLLIN); + + if (hint & UPOLLERR) hint &= ~UPOLLOUT; + + evs[e].data = n->event.data; + evs[e].events = hint; + ++e; + } + } + + return e; +} +#else +int upoll_wait_select(upoll_t* upq, upoll_event_t* evs, int nev, int timeout) { + if (nev > FD_SETSIZE) nev = FD_SETSIZE; + + unote_t* nvec[nev]; + int i, maxfd = 0, e = 0, nfds = 0; + + fd_set pollin, pollout, pollerr; + + FD_ZERO(&pollin); + FD_ZERO(&pollout); + FD_ZERO(&pollerr); + + struct timeval tv; + struct timeval* tvp = &tv; + + tv.tv_usec = 0; + if (timeout < 0) { + tvp = NULL; + } + else if (timeout == 0) + tv.tv_sec = 0; + else { + tv.tv_sec = (timeout / 1000); + tv.tv_usec = (timeout % 1000) * 1000; + } + + unote_t* n = NULL; + ulist_t* s = ulist_mark(&upq->alive); + ulist_t* q = ulist_next(&upq->alive); + + while (q != s && nfds < nev) { + n = ulist_data(q, unote_t, queue); + q = ulist_next(q); + + ulist_remove(&n->queue); + ulist_insert(&upq->alive, &n->queue); + + nvec[nfds] = n; + if (n->event.events & UPOLLIN) { + FD_SET(n->fd, &pollin); + } + if (n->event.events & UPOLLOUT) { + FD_SET(n->fd, &pollout); + } + FD_SET(n->fd, &pollerr); + if (maxfd < n->fd) maxfd = n->fd; + nfds++; + } + +# if defined(__WINDOWS__) + int rc = select(0, &pollin, &pollout, &pollerr, tvp); + if (rc == SOCKET_ERROR) { + assert(WSAGetLastError() == WSAENOTSOCK); + return -WSAGetLastError(); + } +# else + int rc = select(maxfd + 1, &pollin, &pollout, &pollerr, tvp); + if (rc == -1) { + assert(errno == EINTR || errno == EBADF); + return -errno; + } +# endif + e = 0; + for (i = 0; i < nfds && e < nev; i++) { + uint32_t hint = 0; + unote_t* n = nvec[i]; + if (FD_ISSET(n->fd, &pollin)) { + hint |= UPOLLIN; + } + + if (FD_ISSET(n->fd, &pollerr)) { + hint |= (UPOLLERR | UPOLLIN); + } + else if (FD_ISSET(n->fd, &pollout)) { + hint |= UPOLLOUT; + } + + if (hint) { + evs[e].data = n->event.data; + evs[e].events = hint; + ++e; + } + } + return e; +} +#endif + +int upoll_wait(upoll_t* upq, upoll_event_t *evs, int nev, int timeout) { + int r = 0; +#if defined(HAVE_EPOLL) + r = upoll_wait_epoll(upq, evs, nev, timeout); +#elif defined(HAVE_POLL) + r = upoll_wait_poll(upq, evs, nev, timeout); +#else + r = upoll_wait_select(upq, evs, nev, timeout); +#endif + return r; +} + +intptr_t usocket(int domain, int type, int proto) { + intptr_t fd = (intptr_t)socket(domain, type, proto); + +#if defined(__WINDOWS__) + if (fd < 0) return -WSAGetLastError(); + unsigned long flags = 1; + int rc = ioctlsocket((SOCKET)fd, FIONBIO, &flags); + if (rc < 0) return -WSAGetLastError(); +#else + if (fd < 0) return -errno; + int rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + if (rc < 0) return -errno; +#endif + + return fd; +} + +int ubind(intptr_t fd, const char* host, const char* serv) { + struct addrinfo* info; + struct addrinfo hint; + memset(&hint, 0, sizeof(hint)); + + int optval = 0; + unsigned int optlen = sizeof(optval); +#if defined(__WINDOWS__) + int rc = getsockopt((SOCKET)fd, SOL_SOCKET, SO_TYPE, (char*)&optval, &optlen); +#else + int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen); +#endif + + hint.ai_family = AF_INET; + hint.ai_socktype = optval; + + rc = getaddrinfo(host, serv, &hint, &info); + + optval = 1; + if (!rc) { +#if defined(__WINDOWS__) + rc = setsockopt( + (SOCKET)fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof(optval) + ); +#else + rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); +#endif + if (!rc) rc = bind(fd, info->ai_addr, info->ai_addrlen); + } + + freeaddrinfo(info); + if (rc) { +#if defined(__WINDOWS__) + return WSAGetLastError(); +#else + return errno; +#endif + } + return 0; +} + +int uconnect(intptr_t fd, const char* host, const char* serv) { + struct addrinfo* info; + + struct addrinfo hint; + memset(&hint, 0, sizeof(hint)); + + int optval = 0; + unsigned int optlen; + +#if defined(__WINDOWS__) + int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, (char*)&optval, &optlen); +#else + int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen); +#endif + + hint.ai_family = AF_INET; + hint.ai_socktype = optval; + + rc = getaddrinfo(host, serv, &hint, &info); + + if (!rc) { +#if defined(__WINDOWS__) + rc = connect((SOCKET)fd, info->ai_addr, info->ai_addrlen); +#else + rc = connect(fd, info->ai_addr, info->ai_addrlen); +#endif + } + + freeaddrinfo(info); + + if (rc) { +#if defined(__WINDOWS__) + if (WSAGetLastError() != WSAEWOULDBLOCK) return WSAGetLastError(); +#else + if (errno != EINPROGRESS) return errno; +#endif + } + return 0; +} + +int ulisten(intptr_t sock, int backlog) { + return listen(sock, backlog); +} + +intptr_t uaccept(intptr_t sock) { + struct sockaddr addr; + + addr.sa_family = AF_INET; + socklen_t addr_len; + +#if defined(__WINDOWS__) + intptr_t fd = (intptr_t)accept((SOCKET)sock, &addr, &addr_len); + if (fd == INVALID_SOCKET) return WSAGetLastError(); +#else + intptr_t fd = accept(sock, &addr, &addr_len); + if (fd < 0) return errno; +#endif + + return fd; +} + +int uclose(intptr_t sock) { +#if defined(__WINDOWS__) + return closesocket((SOCKET)sock); +#else + return close(sock); +#endif +} + +int uread(intptr_t fd, char* buf, size_t len) { + return recv(fd, buf, len, 0); +} +int uwrite(intptr_t fd, const char* buf, size_t len) { + return send(fd, buf, len, 0); +} + +/* adapted from (renamed make_overlapped to async for allergy reasons): */ +/* socketpair.c +Copyright 2007, 2010 by Nathan C. Myers +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + The name of the author must not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Changes: + * 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements + * git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54 + * github.com/GerHobbelt/selectable-socketpair + * always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64 + * and UNIX/other platforms + * 2013-07-18: Change to BSD 3-clause license + * 2010-03-31: + * set addr to 127.0.0.1 because win32 getsockname does not always set it. + * 2010-02-25: + * set SO_REUSEADDR option to avoid leaking some windows resource. + * Windows System Error 10049, "Event ID 4226 TCP/IP has reached + * the security limit imposed on the number of concurrent TCP connect + * attempts." Bleah. + * 2007-04-25: + * preserve value of WSAGetLastError() on all error returns. + * 2007-04-22: (Thanks to Matthew Gregan ) + * s/EINVAL/WSAEINVAL/ fix trivial compile failure + * s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout + * of a child process. + * add argument make_overlapped + */ + +#if defined(__WINDOWS__) +int usocketpair(intptr_t socks[2], int async) { + union { + struct sockaddr_in inaddr; + struct sockaddr addr; + } a; + SOCKET listener; + int e; + socklen_t addrlen = sizeof(a.inaddr); + DWORD flags = (async ? WSA_FLAG_OVERLAPPED : 0); + int reuse = 1; + + if (socks == 0) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + socks[0] = socks[1] = -1; + + listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listener == -1) + return SOCKET_ERROR; + + memset(&a, 0, sizeof(a)); + a.inaddr.sin_family = AF_INET; + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_port = 0; + + for (;;) { + + if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, + (char*) &reuse, (socklen_t) sizeof(reuse)) == -1) + break; + + if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + memset(&a, 0, sizeof(a)); + if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) + break; + // win32 getsockname may only set the port number, p=0.0005. + // ( http://msdn.microsoft.com/library/ms738543.aspx ): + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_family = AF_INET; + + if (listen(listener, 1) == SOCKET_ERROR) + break; + + socks[0] = (intptr_t)WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags); + if (socks[0] == -1) + break; + if (connect((SOCKET)socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + socks[1] = (intptr_t)accept(listener, NULL, NULL); + if (socks[1] == -1) + break; + + closesocket(listener); + return 0; + } + + e = WSAGetLastError(); + closesocket(listener); + closesocket((SOCKET)socks[0]); + closesocket((SOCKET)socks[1]); + WSASetLastError(e); + socks[0] = socks[1] = -1; + return SOCKET_ERROR; +} +#else +int usocketpair(intptr_t socks[2], int dummy) { + int sovec[2]; + if (socks == 0) { + errno = EINVAL; + return -1; + } + dummy = socketpair(AF_LOCAL, SOCK_STREAM, 0, sovec); + if (dummy) { + socks[0] = socks[1] = -1; + } + else { + socks[0] = sovec[0]; + socks[1] = sovec[1]; + } + return dummy; +} +#endif + diff --git a/source/emscripten/upoll.h b/source/emscripten/upoll.h new file mode 100644 index 000000000..186a48f8a --- /dev/null +++ b/source/emscripten/upoll.h @@ -0,0 +1,134 @@ +#ifndef _UPOLL_H_ +#define _UPOLL_H_ + +#include "up.h" + +#if (defined (__64BIT__) || defined (__x86_64__)) +# define __IS_64BIT__ +#else +# define __IS_32BIT__ +#endif + +#if (defined WIN32 || defined _WIN32) +# undef __WINDOWS__ +# define __WINDOWS__ +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0501 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined (__WINDOWS__) +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#if defined(__linux__) +# undef HAVE_EPOLL +# define HAVE_EPOLL 1 +#elif defined(__unix__) || (defined (__APPLE__) && defined (__MACH__)) +# undef HAVE_POLL +# define HAVE_POLL 1 +#else +# undef HAVE_SELECT +# define HAVE_SELECT 1 +#endif + +#if defined(HAVE_EPOLL) +# include +#elif defined(HAVE_POLL) +# include +#endif + +typedef struct unote unote_t; +typedef struct ulist ulist_t; +typedef struct uitem uitem_t; +typedef struct uhash uhash_t; + +struct ulist { + ulist_t* next; + ulist_t* prev; +}; + +struct uitem { + ulist_t list; + intptr_t key; + void* val; +}; + +struct uhash { + uint16_t count; + uint16_t size; + ulist_t* items; +}; + +struct upoll { + int fd; /* backend fd (epoll, kqueue) */ + ulist_t alive; /* all notes this queue knows about */ + uhash_t* table; +}; + +struct unote { + upoll_event_t event; + intptr_t fd; + ulist_t queue; /* handle for the queue's notes */ + upoll_t* upoll; +}; + +#define container_of(ptr, type, member) \ + ((type*) ((char*)(ptr) - offsetof(type, member))) + +#define ulist_init(q) (q)->prev = q; (q)->next = q + +#define ulist_head(h) (h)->next +#define ulist_next(q) (q)->next + +#define ulist_tail(h) (h)->prev +#define ulist_prev(q) (q)->prev + +#define ulist_empty(h) (h == (h)->prev) + +#define ulist_append(h, x) \ + (x)->prev = (h)->prev; \ + (x)->prev->next = x; \ + (x)->next = h; (h)->prev = x + +#define ulist_insert(h, x) \ + (x)->next = (h)->next; \ + (x)->next->prev = x; \ + (x)->prev = h; (h)->next = x + +#define ulist_remove(x) \ + (x)->next->prev = (x)->prev; \ + (x)->prev->next = (x)->next; \ + (x)->prev = x; (x)->next = x + +#define ulist_mark(h) (h) + +#define ulist_scan(q, h) \ + for ((q) = ulist_head(h); (q) != ulist_mark(h); (q) = ulist_next(q)) + +#define ulist_data(q, type, link) \ + container_of(q, type, link) + +#endif /* _UPOLL_H_ */