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 \