diff --git a/libc/calls/poll-nt.c b/libc/calls/poll-nt.c
index 9ea871b65..b8664c48a 100644
--- a/libc/calls/poll-nt.c
+++ b/libc/calls/poll-nt.c
@@ -160,7 +160,9 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) {
// we need to poll the socket handles separately because
// microsoft certainly loves to challenge us with coding
// please note that winsock will fail if we pass zero fd
+#if _NTTRACE
POLLTRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms);
+#endif
if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) {
return __winsockerr();
}
diff --git a/libc/sock/wsablock.c b/libc/sock/wsablock.c
index 53252e083..16883b76d 100644
--- a/libc/sock/wsablock.c
+++ b/libc/sock/wsablock.c
@@ -39,7 +39,9 @@ textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
return __winsockerr();
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
if (_check_interrupts(restartable, g_fds.p)) return eintr();
+#if _NTTRACE
POLLTRACE("WSAWaitForMultipleEvents...");
+#endif
} else {
break;
}
diff --git a/tool/net/demo/unix-webserver.lua b/tool/net/demo/unix-webserver.lua
new file mode 100644
index 000000000..3b399c37c
--- /dev/null
+++ b/tool/net/demo/unix-webserver.lua
@@ -0,0 +1,115 @@
+-- webserver within a webserver demo
+-- we must go deeper!
+
+local unix = require 'unix'
+
+function OnTerm(sig)
+ -- prevent redbean core from writing a response
+ unix.write(mainfd, 'redbean is shutting down\r\n')
+ unix.close(mainfd)
+end
+
+function main()
+ if IsClientUsingSsl() then
+ ServeError(400)
+ return
+ end
+
+ mainfd = GetClientFd()
+ mainip = GetRemoteAddr()
+ unix.sigaction(unix.SIGTERM, OnTerm)
+ unix.write(mainfd, 'HTTP/1.0 200 OK\r\n' ..
+ 'Date: '.. FormatHttpDateTime(GetDate()) ..'\r\n' ..
+ 'Content-Type: text/html; charset=utf-8\r\n' ..
+ 'Connection: close\r\n' ..
+ 'Server: redbean unix\r\n' ..
+ '\r\n' ..
+ '\r\n' ..
+ '
redbean\r\n' ..
+ 'webserver within a webserver demo
\r\n')
+
+ addrs = {}
+ servers = {}
+ pollfds = {}
+ pollfds[mainfd] = unix.POLLIN
+
+ ifs, errno = unix.siocgifconf()
+ for i = 1,#ifs do
+ if (IsLoopbackIp(mainip) and (IsPublicIp(ifs[i].ip) or
+ IsPrivateIp(ifs[i].ip) or
+ IsLoopbackIp(ifs[i].ip))) or
+ (IsPrivateIp(mainip) and (IsPublicIp(ifs[i].ip) or
+ IsPrivateIp(ifs[i].ip))) or
+ (IsPublicIp(mainip) and IsPublicIp(ifs[i].ip))
+ then
+ server = unix.socket()
+ unix.bind(server, ifs[i].ip)
+ unix.listen(server)
+ ip, port = unix.getsockname(server)
+ addr = string.format('%s:%d', FormatIp(ip), port)
+ url = string.format('http://%s', addr)
+ Log(kLogInfo, string.format('listening on %s', addr))
+ unix.write(mainfd, string.format(
+ 'listening on %s
\r\n',
+ url, url))
+ pollfds[server] = unix.POLLIN | unix.POLLHUP
+ servers[server] = true
+ addrs[server] = addr
+ end
+ end
+
+ while true do
+ evs, errno = unix.poll(pollfds)
+ if not evs then
+ break
+ end
+ for fd,revents in pairs(evs) do
+ if fd == mainfd then
+ data, errno = unix.read(mainfd)
+ if not data then
+ Log(kLogInfo, string.format('got %s from parent client', unix.strerrno(errno)))
+ -- prevent redbean core from writing a response
+ unix.exit(1)
+ end
+ if #data == 0 then
+ Log(kLogInfo, 'got hangup from parent client')
+ Log(kLogInfo, 'closing server')
+ -- prevent redbean core from writing a response
+ unix.exit(0)
+ end
+ -- echo it back for fun
+ unix.write(mainfd, data)
+ elseif servers[fd] then
+ unix.write(mainfd, string.format('preparing to accept from %d
\r\n', fd))
+ client, clientip, clientport = unix.accept(fd)
+ unix.write(mainfd, string.format('preparing to accept from %d
\r\n', fd))
+ addr = string.format('%s:%d', FormatIp(clientip), clientport)
+ addrs[client] = addr
+ unix.write(mainfd, string.format('got client %s
\r\n', addr))
+ pollfds[client] = unix.POLLIN
+ evs[server] = nil
+ else
+ unix.write(mainfd, string.format('preparing to read from %d
\r\n', fd))
+ data = unix.read(fd)
+ unix.write(mainfd, string.format('done reading from %d
\r\n', fd))
+ if data and #data ~= 0 then
+ unix.write(mainfd, string.format('got %d bytes from %s
\r\n', #data, addrs[fd]))
+ unix.write(fd, 'HTTP/1.0 200 OK\r\n' ..
+ 'Date: '.. FormatHttpDateTime(GetDate()) ..'\r\n' ..
+ 'Content-Type: text/html; charset=utf-8\r\n' ..
+ 'Connection: close\r\n' ..
+ 'Server: redbean unix\r\n' ..
+ '\r\n' ..
+ '\r\n' ..
+ 'redbean\r\n' ..
+ 'embedded webserver demo
\r\n' ..
+ 'hello! this is a web server embedded in a web server!\r\n')
+ end
+ unix.close(fd)
+ pollfds[fd] = nil
+ end
+ end
+ end
+
+end
+main()
diff --git a/tool/net/lunix.c b/tool/net/lunix.c
index 9c8a15f14..74d9013cc 100644
--- a/tool/net/lunix.c
+++ b/tool/net/lunix.c
@@ -54,6 +54,7 @@
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h"
+#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/rlim.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/consts/sa.h"
@@ -883,12 +884,15 @@ static int LuaUnixSocketpair(lua_State *L) {
// type defaults to SOCK_STREAM
// protocol defaults to IPPROTO_TCP
static int LuaUnixBind(lua_State *L) {
+ uint32_t x;
int rc, olderr, fd;
struct sockaddr_in sa;
bzero(&sa, sizeof(sa));
olderr = errno;
fd = luaL_checkinteger(L, 1);
- sa.sin_addr.s_addr = htonl(luaL_optinteger(L, 2, 0));
+ x = luaL_optinteger(L, 2, 0);
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = htonl(x);
sa.sin_port = htons(luaL_optinteger(L, 3, 0));
rc = bind(fd, &sa, sizeof(sa));
return ReturnRc(L, rc, olderr);
@@ -966,7 +970,7 @@ static int LuaUnixSiocgifconf(lua_State *L) {
if (!(data = malloc((n = 4096)))) {
return ReturnErrno(L, 1, olderr);
}
- if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+ if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
free(data);
return ReturnErrno(L, 1, olderr);
}
@@ -1840,6 +1844,19 @@ int LuaUnix(lua_State *L) {
LuaSetIntField(L, "DT_FIFO", DT_FIFO);
LuaSetIntField(L, "DT_SOCK", DT_SOCK);
+ // readdir() type
+ LuaSetIntField(L, "POLLIN", POLLIN);
+ LuaSetIntField(L, "POLLPRI", POLLPRI);
+ LuaSetIntField(L, "POLLOUT", POLLOUT);
+ LuaSetIntField(L, "POLLERR", POLLERR);
+ LuaSetIntField(L, "POLLHUP", POLLHUP);
+ LuaSetIntField(L, "POLLNVAL", POLLNVAL);
+ LuaSetIntField(L, "POLLRDBAND", POLLRDBAND);
+ LuaSetIntField(L, "POLLRDNORM", POLLRDNORM);
+ LuaSetIntField(L, "POLLWRBAND", POLLWRBAND);
+ LuaSetIntField(L, "POLLWRNORM", POLLWRNORM);
+ LuaSetIntField(L, "POLLRDHUP", POLLRDHUP);
+
// i/o options
LuaSetIntField(L, "AT_FDCWD", AT_FDCWD);
LuaSetIntField(L, "AT_SYMLINK_NOFOLLOW", AT_SYMLINK_NOFOLLOW);
diff --git a/tool/net/net.mk b/tool/net/net.mk
index 74c56ff93..1d1c39e8f 100644
--- a/tool/net/net.mk
+++ b/tool/net/net.mk
@@ -173,6 +173,7 @@ o/$(MODE)/tool/net/demo/.reload.lua.zip.o \
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
+o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
@@ -217,6 +218,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
+ o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
o/$(MODE)/tool/net/demo/hello.lua.zip.o \