139 lines
2.8 KiB
Text
139 lines
2.8 KiB
Text
/* Echo_server.wren */
|
|
|
|
var MAX_ENQUEUED = 20
|
|
var BUF_LEN = 256
|
|
var PORT_STR = "12321"
|
|
|
|
var AF_UNSPEC = 0
|
|
var SOCK_STREAM = 1
|
|
var AI_PASSIVE = 1
|
|
|
|
foreign class AddrInfo {
|
|
foreign static getAddrInfo(name, service, req, pai)
|
|
|
|
construct new() {}
|
|
|
|
foreign family
|
|
|
|
foreign family=(f)
|
|
|
|
foreign sockType
|
|
|
|
foreign sockType=(st)
|
|
|
|
foreign flags
|
|
|
|
foreign flags=(f)
|
|
|
|
foreign protocol
|
|
|
|
foreign addr
|
|
|
|
foreign addrLen
|
|
}
|
|
|
|
foreign class AddrInfoPtr {
|
|
construct new() {}
|
|
|
|
foreign deref
|
|
|
|
foreign free()
|
|
}
|
|
|
|
class Socket {
|
|
foreign static create(domain, type, protocol)
|
|
|
|
foreign static bind(fd, addr, len)
|
|
|
|
foreign static listen(fd, n)
|
|
|
|
foreign static accept(fd, addr, addrLen)
|
|
}
|
|
|
|
foreign class SockAddrPtr {
|
|
construct new() {}
|
|
|
|
foreign size
|
|
}
|
|
|
|
class SigAction {
|
|
foreign static cleanUpProcesses()
|
|
}
|
|
|
|
foreign class Buffer {
|
|
construct new(size) {}
|
|
}
|
|
|
|
class Posix {
|
|
foreign static read(fd, buf, nbytes)
|
|
|
|
foreign static write(fd, buf, n)
|
|
|
|
foreign static fork()
|
|
|
|
foreign static close(fd)
|
|
}
|
|
|
|
// Child process.
|
|
var echoLines = Fn.new { |csock|
|
|
var buf = Buffer.new(BUF_LEN)
|
|
var r
|
|
while ((r = Posix.read(csock, buf, BUF_LEN)) > 0) {
|
|
Posix.write(csock, buf, r)
|
|
}
|
|
}
|
|
|
|
// Parent process.
|
|
var takeConnectionsForever = Fn.new { |ssock|
|
|
while (true) {
|
|
var addr = SockAddrPtr.new()
|
|
var addrSize = addr.size
|
|
|
|
/* Block until we take one connection to the server socket */
|
|
var csock = Socket.accept(ssock, addr, addrSize)
|
|
|
|
/* If it was a successful connection, spawn a worker process to service it. */
|
|
if (csock == -1) {
|
|
System.print("Error accepting socket.")
|
|
} else if (Posix.fork() == 0) {
|
|
Posix.close(ssock)
|
|
echoLines.call(csock)
|
|
return
|
|
} else {
|
|
Posix.close(csock)
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Look up the address to bind to. */
|
|
var hints = AddrInfo.new()
|
|
hints.family = AF_UNSPEC
|
|
hints.sockType = SOCK_STREAM
|
|
hints.flags = AI_PASSIVE
|
|
var addrInfoPtr = AddrInfoPtr.new()
|
|
if (AddrInfo.getAddrInfo("", PORT_STR, hints, addrInfoPtr) != 0) {
|
|
Fiber.abort("Failed to get pointer to addressinfo.")
|
|
}
|
|
|
|
/* Make a socket. */
|
|
var res = addrInfoPtr.deref
|
|
var sock = Socket.create(res.family, res.sockType, res.protocol)
|
|
if (sock == -1) Fiber.abort("Failed to make a socket.")
|
|
|
|
/* Arrange to clean up child processes (the workers). */
|
|
SigAction.cleanUpProcesses()
|
|
|
|
/* Associate the socket with its address. */
|
|
if (Socket.bind(sock, res.addr, res.addrLen) != 0) {
|
|
Fiber.abort("Failed to bind socket.")
|
|
}
|
|
|
|
addrInfoPtr.free()
|
|
|
|
/* State that we've opened a server socket and are listening for connections. */
|
|
if (Socket.listen(sock, MAX_ENQUEUED) != 0) {
|
|
Fiber.abort("Failed to listen for connections.")
|
|
}
|
|
|
|
/* Serve the listening socket until killed */
|
|
takeConnectionsForever.call(sock)
|