mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Add poll() embedded webserver demo to redbean
This commit is contained in:
parent
0dca4c5799
commit
38728cef79
5 changed files with 140 additions and 2 deletions
|
@ -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
|
// we need to poll the socket handles separately because
|
||||||
// microsoft certainly loves to challenge us with coding
|
// microsoft certainly loves to challenge us with coding
|
||||||
// please note that winsock will fail if we pass zero fd
|
// 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);
|
POLLTRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms);
|
||||||
|
#endif
|
||||||
if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) {
|
if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) {
|
||||||
return __winsockerr();
|
return __winsockerr();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,9 @@ textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
|
||||||
return __winsockerr();
|
return __winsockerr();
|
||||||
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
|
} else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) {
|
||||||
if (_check_interrupts(restartable, g_fds.p)) return eintr();
|
if (_check_interrupts(restartable, g_fds.p)) return eintr();
|
||||||
|
#if _NTTRACE
|
||||||
POLLTRACE("WSAWaitForMultipleEvents...");
|
POLLTRACE("WSAWaitForMultipleEvents...");
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
115
tool/net/demo/unix-webserver.lua
Normal file
115
tool/net/demo/unix-webserver.lua
Normal file
|
@ -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' ..
|
||||||
|
'<!doctype html>\r\n' ..
|
||||||
|
'<title>redbean</title>\r\n' ..
|
||||||
|
'<h3>webserver within a webserver demo</h3>\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 <a target="_blank" href="%s">%s</a><br>\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<br>\r\n', fd))
|
||||||
|
client, clientip, clientport = unix.accept(fd)
|
||||||
|
unix.write(mainfd, string.format('preparing to accept from %d<br>\r\n', fd))
|
||||||
|
addr = string.format('%s:%d', FormatIp(clientip), clientport)
|
||||||
|
addrs[client] = addr
|
||||||
|
unix.write(mainfd, string.format('got client %s<br>\r\n', addr))
|
||||||
|
pollfds[client] = unix.POLLIN
|
||||||
|
evs[server] = nil
|
||||||
|
else
|
||||||
|
unix.write(mainfd, string.format('preparing to read from %d<br>\r\n', fd))
|
||||||
|
data = unix.read(fd)
|
||||||
|
unix.write(mainfd, string.format('done reading from %d<br>\r\n', fd))
|
||||||
|
if data and #data ~= 0 then
|
||||||
|
unix.write(mainfd, string.format('got %d bytes from %s<br>\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' ..
|
||||||
|
'<!doctype html>\r\n' ..
|
||||||
|
'<title>redbean</title>\r\n' ..
|
||||||
|
'<h3>embedded webserver demo</h3>\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()
|
|
@ -54,6 +54,7 @@
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/ok.h"
|
#include "libc/sysv/consts/ok.h"
|
||||||
|
#include "libc/sysv/consts/poll.h"
|
||||||
#include "libc/sysv/consts/rlim.h"
|
#include "libc/sysv/consts/rlim.h"
|
||||||
#include "libc/sysv/consts/rlimit.h"
|
#include "libc/sysv/consts/rlimit.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
@ -883,12 +884,15 @@ static int LuaUnixSocketpair(lua_State *L) {
|
||||||
// type defaults to SOCK_STREAM
|
// type defaults to SOCK_STREAM
|
||||||
// protocol defaults to IPPROTO_TCP
|
// protocol defaults to IPPROTO_TCP
|
||||||
static int LuaUnixBind(lua_State *L) {
|
static int LuaUnixBind(lua_State *L) {
|
||||||
|
uint32_t x;
|
||||||
int rc, olderr, fd;
|
int rc, olderr, fd;
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
||||||
bzero(&sa, sizeof(sa));
|
bzero(&sa, sizeof(sa));
|
||||||
olderr = errno;
|
olderr = errno;
|
||||||
fd = luaL_checkinteger(L, 1);
|
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));
|
sa.sin_port = htons(luaL_optinteger(L, 3, 0));
|
||||||
rc = bind(fd, &sa, sizeof(sa));
|
rc = bind(fd, &sa, sizeof(sa));
|
||||||
return ReturnRc(L, rc, olderr);
|
return ReturnRc(L, rc, olderr);
|
||||||
|
@ -966,7 +970,7 @@ static int LuaUnixSiocgifconf(lua_State *L) {
|
||||||
if (!(data = malloc((n = 4096)))) {
|
if (!(data = malloc((n = 4096)))) {
|
||||||
return ReturnErrno(L, 1, olderr);
|
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);
|
free(data);
|
||||||
return ReturnErrno(L, 1, olderr);
|
return ReturnErrno(L, 1, olderr);
|
||||||
}
|
}
|
||||||
|
@ -1840,6 +1844,19 @@ int LuaUnix(lua_State *L) {
|
||||||
LuaSetIntField(L, "DT_FIFO", DT_FIFO);
|
LuaSetIntField(L, "DT_FIFO", DT_FIFO);
|
||||||
LuaSetIntField(L, "DT_SOCK", DT_SOCK);
|
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
|
// i/o options
|
||||||
LuaSetIntField(L, "AT_FDCWD", AT_FDCWD);
|
LuaSetIntField(L, "AT_FDCWD", AT_FDCWD);
|
||||||
LuaSetIntField(L, "AT_SYMLINK_NOFOLLOW", AT_SYMLINK_NOFOLLOW);
|
LuaSetIntField(L, "AT_SYMLINK_NOFOLLOW", AT_SYMLINK_NOFOLLOW);
|
||||||
|
|
|
@ -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/sql.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix-rawsocket.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-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/unix-info.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/hello.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/sql.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix-rawsocket.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-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/unix-info.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
||||||
|
|
Loading…
Add table
Reference in a new issue