1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
local l = require "luxio"
local serv = l.socket(l.AF_INET, l.SOCK_STREAM, 0)
local sa = l.make_sockaddr(l.AF_INET, 1234, "0.0.0.0")
l.setsockopt(serv, l.SOL_SOCKET, l.SO_REUSEADDR, 1)
l.bind(serv, sa)
l.listen(serv, 5)
local pfds = l.pollfds_new()
l.pollfds_resize(pfds, 1);
l.pollfds_setslot(pfds, 1, serv, l.POLLIN, 0)
local quit = false
local clients = { }
local clientslots = {}
function send_to_all(data, exclude)
for fd, client in pairs(clients) do
if fd ~= exclude then
client.sendbuf[#client.sendbuf+1] = data
l.pollfds_setslot(pfds, client.pfd, fd, l.bit.bor(l.POLLIN, l.POLLOUT))
end
end
end
function client_flush(client)
local data = table.concat(client.sendbuf)
local sent, errno = l.write(client.fd, data)
if sent < 0 then
print(("something wicked happened to fd %d"):format(client.fd))
return
end
if sent < #data then
client.sendbuf = { data:sub(sent + 1, -1) }
else
client.sendbuf = { }
l.pollfds_setslot(pfds, client.pfd, client.fd, l.POLLIN)
end
end
function client_recv(client, data)
local line
client.recvbuf[#client.recvbuf+1] = data
if data:match "\n" then
line = table.concat(client.recvbuf)
client.recvbuf = { line:match "\n(.*)" }
send_to_all(("%d: %s\n"):format(client.fd, line:match "(.*)\n"))
end
end
repeat
local nfds, err = l.poll(pfds, 5000)
if nfds == 0 then
print("Timed out")
elseif nfds == -1 then
print(l.strerror(err))
else
for i = 1, #pfds do
local fd, evt, revt = l.pollfds_getslot(pfds, i)
if revt ~= 0 then
if fd == serv then
-- New client!
local newclient, clientaddr = l.accept(serv)
l.fcntl(newclient, l.F_SETFL, l.O_NONBLOCK)
print("New client from", clientaddr)
l.pollfds_resize(pfds, #pfds + 1)
clients[newclient] = { sendbuf = {}, recvbuf = {}, pfd = #pfds, fd = newclient, addr = clientaddr }
clientslots[#pfds] = clients[newclient]
send_to_all("New client from " .. clientaddr.address .. "\n", newclient)
l.pollfds_setslot(pfds, #pfds, newclient, l.POLLIN, 0)
else
client = clients[fd]
if (l.bit.btest(revt, l.POLLOUT)) then
client_flush(client)
end
if (l.bit.btest(revt, l.POLLIN)) then
local s, err = l.read(fd, 1024)
if s == "" then
-- Tell everyone other than this client, it died!
send_to_all("Client on " .. client.addr.address .. " died!\n", fd)
-- Blank out (wasteful us!) this pollfd entry
l.pollfds_setslot(pfds, client.pfd, -1, 0, 0);
-- Remove us from the client list
clients[fd] = nil
-- And close the fd for fun and profit
l.close(fd)
elseif s == -1 then
print(("Something odd happened on client %d"):format(fd))
else
client_recv(client, s)
end
end
end
nfds = nfds - 1
end
if nfds == 0 then
break
end
end
end
until quit
|