Alexander Avery
9 months ago
1 changed files with 143 additions and 0 deletions
@ -0,0 +1,143 @@ |
|||
use bufio; |
|||
use io; |
|||
use log; |
|||
use net; |
|||
use net::ip; |
|||
use net::tcp; |
|||
use strings; |
|||
use time; |
|||
use unix::poll; |
|||
|
|||
// our message to send to clients as a constant |
|||
def tick: [5]u8 = ['t', 'i', 'c', 'k', '\n']; |
|||
|
|||
// tryconn attempts to add a client to a pollfd slice. |
|||
fn tryconn(fds: []poll::pollfd) void = { |
|||
let socket = fds[0]; |
|||
if (socket.revents & poll::event::POLLIN > 0) { |
|||
|
|||
// try to accept the connection. |
|||
let conn = match(net::accept(socket.fd)) { |
|||
case let err: net::error => |
|||
log::println("failed to accept connection"); |
|||
return; |
|||
case let sock: net::socket => |
|||
yield sock; |
|||
}; |
|||
|
|||
// the events we want to listen for |
|||
let events = (poll::event::POLLIN | poll::event::POLLPRI); |
|||
|
|||
for (let i = 1z; i < len(fds); i += 1) { |
|||
// empty slot is indicated by a |
|||
// file descriptor equal to 0 |
|||
if (fds[i].fd == 0) { |
|||
|
|||
fds[i].fd = conn; |
|||
fds[i].events = events; |
|||
|
|||
return; |
|||
}; |
|||
}; |
|||
|
|||
// close the connection if there is no room |
|||
io::close(conn)!; |
|||
}; |
|||
}; |
|||
|
|||
// tryread will attempt to read from all connected clients. |
|||
fn tryread(fds: []poll::pollfd) void = { |
|||
for (let i = 1z; i < len(fds); i += 1) { |
|||
|
|||
let revents = fds[i].revents; |
|||
|
|||
// just close the file descriptor |
|||
// on error or hangup events |
|||
if (revents & poll::event::POLLERR |
|||
& poll::event::POLLHUP > 0) { |
|||
closefd(&fds[i]); |
|||
continue; |
|||
}; |
|||
|
|||
// if there is data to read... |
|||
if (revents & poll::event::POLLIN > 0) { |
|||
|
|||
let scanner = bufio::newscanner(fds[i].fd, 1024z); |
|||
defer bufio::finish(&scanner); |
|||
|
|||
match(bufio::scan_line(&scanner)) { |
|||
case let msg: const str => |
|||
log::printfln("client said: {}", msg); |
|||
case => |
|||
// io::EOF, io::error, or utf8::invalid |
|||
closefd(&fds[i]); |
|||
}; |
|||
|
|||
}; |
|||
}; |
|||
}; |
|||
|
|||
// write sends a 'tick' message to all connected clients. |
|||
fn write(fds: []poll::pollfd) void = { |
|||
for (let i = 1z; i < len(fds); i += 1) { |
|||
if (fds[i].fd > 0) { |
|||
io::writeall(fds[i].fd, tick)!; |
|||
}; |
|||
}; |
|||
}; |
|||
|
|||
// closefd closes a provided file descriptor |
|||
// and resets all fields to 0. |
|||
fn closefd(fd: *poll::pollfd) void = { |
|||
|
|||
match(io::close(fd.fd)) { |
|||
case void => |
|||
void; |
|||
case io::error => |
|||
log::println("failed to close socket"); |
|||
}; |
|||
|
|||
fd.fd = 0; |
|||
fd.events = 0; |
|||
fd.revents = 0; |
|||
}; |
|||
|
|||
export fn main() void = { |
|||
|
|||
let socket = tcp::listen(ip::LOCAL_V4, 8080)!; |
|||
|
|||
// initialize all pollfds with zero values |
|||
let fds: [15]poll::pollfd = [ |
|||
poll::pollfd { |
|||
fd = 0, |
|||
events = 0, |
|||
revents = 0, |
|||
} |
|||
... |
|||
]; |
|||
|
|||
// overwrite the first pollfd with our socket |
|||
fds[0] = poll::pollfd { |
|||
fd = socket, |
|||
events = (poll::event::POLLIN | poll::event::POLLPRI), |
|||
revents = 0 |
|||
}; |
|||
|
|||
for (true) { |
|||
match(poll::poll(fds, time::SECOND)) { |
|||
|
|||
case let n: uint => |
|||
if (n > 0) { |
|||
tryconn(fds); |
|||
tryread(fds); |
|||
} else { |
|||
write(fds); |
|||
}; |
|||
|
|||
case let err: poll::error => |
|||
log::fatal("poll failed"); |
|||
}; |
|||
|
|||
}; |
|||
|
|||
}; |
Loading…
Reference in new issue