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
|