Initial commit

This commit is contained in:
Stefan Bühler 2010-08-05 14:42:59 +02:00
commit d6b2e72612
7 changed files with 523 additions and 0 deletions

8
src/Makefile Normal file
View File

@ -0,0 +1,8 @@
LDC=ldc
override DFLAGS+=-O2
override CFLAGS+=-O2
delight: io/base.d io/base_c.o io/events.d io/events_c.o
gdc $(DFLAGS) -o "$@" $^ -lev

243
src/io/base.d Normal file
View File

@ -0,0 +1,243 @@
module io.base;
import std.socket;
import io.events;
R delegate(T) makeDelegate(R, T)(R function(T) f) {
struct delegateClass {
R function(T) m_f;
R callback(T t) { return m_f(t); }
}
delegateClass* o = new delegateClass;
o.m_f = f;
return &o.callback;
}
private extern (C) int iobase_write(int fd, void *buf, int len);
private extern (C) int iobase_read(int fd, void *buf, int len);
class BufferedSocket {
private Socket m_socket;
private IOWatcher m_watcher;
private void delegate(void[] buf) m_readcb;
private void delegate() m_eofcb, m_closecb;
private bool m_closed, m_eof, m_sendeof;
private class chunk {
chunk next;
void[] buf;
this(void[] b) { buf = b.dup; }
}
private chunk m_cfirst, m_clast;
final void delegate(void[] buf) readcb() { return m_readcb; }
final void delegate(void[] buf) readcb(void delegate(void[] buf) r) {
m_readcb = r;
if (m_readcb is null || m_eof || m_closed) {
m_watcher.events = m_watcher.events & ~Event.READ;
} else {
m_watcher.events = m_watcher.events | Event.READ;
}
return m_readcb;
}
final void delegate() eofcb() { return m_eofcb; }
final void delegate() eofcb(void delegate() f) { return m_eofcb = f; }
final void delegate() closecb() { return m_closecb; }
final void delegate() closecb(void delegate() f) { return m_closecb = f; }
this(Loop loop, Socket sock, void delegate(void[] buf) readcb = null) {
m_socket = sock;
m_readcb = readcb;
m_watcher = new IOWatcher();
m_watcher.socket = m_socket;
m_watcher.events = Event.READ;
m_watcher.read = &this.handleread;
m_watcher.write = &this.handlewrite;
m_watcher.start(loop);
}
~this() {
m_cfirst = m_clast = null;
shutdown();
delete m_watcher;
delete m_socket;
}
void write(void[] buf) {
if (m_closed || m_sendeof || 0 == buf.length) return;
chunk c = new chunk(buf);
if (m_clast !is null) {
m_clast.next = c;
m_clast = c;
} else {
m_cfirst = m_clast = c;
}
m_watcher.events = m_watcher.events | Event.WRITE;
}
void shutdown() {
if (m_closed || m_sendeof) return;
m_sendeof = true;
if (m_cfirst is null) {
m_socket.shutdown(SocketShutdown.SEND);
}
}
/* may destroy object */
private final void handleeof() {
m_eof = true;
m_watcher.events = m_watcher.events & ~Event.READ;
if (m_eofcb !is null) {
m_eofcb();
} else {
delete this;
}
}
/* may destroy object */
private final void handleclose() {
m_closed = true;
m_watcher.events = Event.NONE;
if (m_closecb !is null) {
m_closecb();
} else {
delete this;
}
}
private final void handleread() {
if (m_readcb is null) {
m_watcher.events = m_watcher.events & ~Event.READ;
return;
}
ubyte buf[4096];
int res = iobase_read(m_socket.handle, buf.ptr, buf.length);
if (res == 0) {
handleeof();
} else if (res > 0) {
m_readcb(buf[0 .. res]);
} else if (res != -1) {
handleclose();
}
}
private final void handlewrite() {
while (m_cfirst !is null) {
chunk c = m_cfirst;
int res = iobase_write(m_socket.handle, c.buf.ptr, c.buf.length);
if (res > 0) {
if (res == c.buf.length) {
m_cfirst = c.next;
} else {
c.buf = c.buf[res .. $];
return;
}
} else if (res == -1) {
return;
} else {
handleclose();
return;
}
}
if (m_sendeof) {
m_socket.shutdown(SocketShutdown.SEND);
}
m_clast = null;
m_watcher.events = m_watcher.events & ~Event.WRITE;
}
}
class TcpServer {
private Socket m_socket;
private IOWatcher m_watcher;
private void delegate(Socket con) m_accept_cb;
public final Socket socket() { return m_socket; }
this(Loop loop, Address bind, void delegate(Socket con) accept) {
m_accept_cb = accept;
m_socket = new TcpSocket(bind.addressFamily);
m_socket.blocking = false;
m_socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, 1);
// m_socket.setOption(SocketOptionLevel.IPV6, SocketOption.IPV6_V6ONLY, 1);
m_socket.bind(bind);
m_socket.listen(1024);
m_watcher = new IOWatcher();
m_watcher.socket = m_socket;
m_watcher.events = Event.READ;
m_watcher.read = &this.acceptcb;
m_watcher.start(loop);
}
private final void acceptcb() {
Socket con = m_socket.accept();
if (con !is null) m_accept_cb(con);
}
}
class EchoConnection {
protected int m_idx = -1;
protected EchoServer m_srv;
protected Socket m_socket;
protected BufferedSocket m_bufsock;
this(Socket s) {
m_socket = s;
m_bufsock = new BufferedSocket(Loop.defaultloop, s, &this.handleread);
}
~this() {
if (m_srv !is null) m_srv.delCon(this);
}
private final void handleread(void[] buf) {
m_bufsock.write(buf);
}
};
class EchoServer {
private EchoConnection m_con[];
private Loop m_loop;
private TcpServer m_server;
this(Loop loop, Address address) {
m_loop = loop;
m_server = new TcpServer(m_loop, address, &this.accept);
m_con = new EchoConnection[0];
}
protected final void addCon(EchoConnection con) {
con.m_srv = this;
con.m_idx = m_con.length;
m_con.length = m_con.length + 1;
m_con[con.m_idx] = con;
}
protected final void delCon(EchoConnection con) {
if (con.m_srv !is this) return;
m_con[con.m_idx] = m_con[m_con.length - 1];
m_con.length = m_con.length - 1;
con.m_srv = null;
con.m_idx = -1;
}
private final void accept(Socket s) {
auto con = new EchoConnection(s);
addCon(con);
}
};
void main(string args[]) {
Loop loop = Loop.defaultloop;
EchoServer srv = new EchoServer(loop, new InternetAddress(8080));
Loop.defaultloop.run();
}

45
src/io/base_c.c Normal file
View File

@ -0,0 +1,45 @@
#include <unistd.h>
#include <errno.h>
/* -1: not now (try later), -2: con closed, -3: unexpected error */
int iobase_write(int fd, const void* buf, int len) {
int res = write(fd, buf, len);
if (res >= 0) return res;
switch (errno) {
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
case EINTR:
return -1;
break;
case ECONNRESET:
case EPIPE:
case ETIMEDOUT:
return -2;
default:
return -3;
}
}
/* 0: eof, -1: not now (try later), -2: con closed, -3: unexpected error */
int iobase_read(int fd, void* buf, int len) {
int res = read(fd, buf, len);
if (res >= 0) return res;
switch (errno) {
case EAGAIN:
#if EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
case EINTR:
return -1;
break;
case ECONNRESET:
case ETIMEDOUT:
return -2;
default:
return -3;
}
}

BIN
src/io/base_c.o Normal file

Binary file not shown.

177
src/io/events.d Normal file
View File

@ -0,0 +1,177 @@
module io.events;
import std.socket;
import std.outofmemory;
private struct evloop {
}
private struct ev_io {
}
enum Event {
NONE = 0,
READ = 1,
WRITE = 2,
TIMEOUT = 4,
ERROR = 128,
}
private extern (C) void ioev_event_callback(Watcher watcher, int revents) {
watcher.callback(revents);
}
private extern (C) evloop* ioev_ev_default_loop(uint flags); /* is a inline function... */
private extern (C) evloop* ev_loop_new(uint flags);
private extern (C) void ev_default_destroy(evloop *loop);
private extern (C) void ev_loop_destroy(evloop *loop);
private extern (C) void ev_loop(evloop *loop, int flags);
private extern (C) void ev_io_start(evloop *loop, ev_io *w);
private extern (C) void ev_io_stop(evloop *loop, ev_io *w);
private extern (C) ev_io* ioev_io_watcher_new(Watcher watcher);
private extern (C) void ioev_io_watcher_free(ev_io *w);
private extern (C) void ioev_io_set(ev_io *w, int fd, int events);
class Watcher {
protected Loop m_cur_loop = null;
protected bool m_active = false;
protected final Loop loop(Loop l) {
if (m_cur_loop is l) return l;
if (m_cur_loop !is null) stop();
return m_cur_loop = l;
}
~this() {
loop = null;
}
abstract void callback(int revents);
abstract protected void do_start();
abstract protected void do_stop();
final public Loop loop() {
return m_cur_loop;
}
final public void start(Loop l) {
if (l is null) throw new Exception("Cannot start on null loop");
loop = l;
do_start();
m_active = true;
}
final public void start() {
start(m_cur_loop);
}
final public void stop() {
if (!m_active) return;
if (m_cur_loop !is null && m_cur_loop.loop !is null)
do_stop();
m_active = false;
}
}
class IOWatcher : Watcher {
private ev_io *m_w;
private Socket m_socket;
private Event m_events;
private int m_fd = -1;
void delegate() read, write, error;
this() {
m_w = ioev_io_watcher_new(this);
if (m_w is null) throw new OutOfMemoryException;
}
~this() {
ioev_io_watcher_free(m_w);
}
override final void callback(int revents) {
if (revents & Event.READ) read();
if (revents & Event.WRITE) write();
if (revents & Event.ERROR) error();
}
private final void set(int fd, int ev) {
bool active = m_active;
stop();
m_fd = fd; m_events = cast(Event)(ev);
ioev_io_set(m_w, m_fd, m_events);
if (active) start();
}
final Socket socket(Socket s) {
m_socket = s;
if (m_fd != s.handle)
set(s.handle, m_events);
return m_socket;
}
final Event events() { return m_events; }
final Event events(int ev) {
if (m_events != ev) set(m_fd, ev);
return m_events;
}
final void events(bool waitForRead, bool waitForWrite) {
Event ev = Event.NONE;
if (waitForRead) ev = ev | Event.READ;
if (waitForWrite) ev = ev | Event.WRITE;
events(ev);
}
override final protected void do_start() {
ev_io_start(loop.loop, m_w);
}
override final protected void do_stop() {
ev_io_stop(loop.loop, m_w);
}
}
class Loop {
protected evloop* loop;
private bool default_loop;
private static Loop def = null;
private this(evloop* loop) {
this.loop = loop;
default_loop = true;
}
static synchronized Loop defaultloop() {
if (def !is null) return def;
evloop* l = ioev_ev_default_loop(0);
if (l is null) throw new Exception("ev_default_loop failed");
def = new Loop(l);
return def;
}
this() {
default_loop = false;
loop = ev_loop_new(0);
if (loop is null) throw new Exception("ev_loop_new failed");
}
~this() {
if (loop !is null) {
if (default_loop) {
ev_default_destroy(loop);
} else {
ev_loop_destroy(loop);
}
}
}
final void run() {
ev_loop(loop, 0);
}
}

50
src/io/events_c.c Normal file
View File

@ -0,0 +1,50 @@
#include <stdlib.h>
#include <ev.h>
#define UNUSED(x) ((void)(x))
#define IOEV_NONE 0
#define IOEV_READ 1
#define IOEV_WRITE 2
#define IOEV_TIMEOUT 4
#define IOEV_ERROR 128
void ioev_event_callback(void* watcher, int revents);
struct ev_loop *ioev_ev_default_loop (unsigned int flags) {
return ev_default_loop(flags);
}
static void io_cb(struct ev_loop *loop, ev_io *w, int revents) {
int ev = 0;
UNUSED(loop);
if (revents & EV_READ) ev = ev | IOEV_READ;
if (revents & EV_WRITE) ev = ev | IOEV_WRITE;
if (revents & EV_ERROR) ev = ev | IOEV_ERROR;
ioev_event_callback(w->data, ev);
}
ev_io* ioev_io_watcher_new(void *watcher) {
ev_io *w = malloc(sizeof(ev_io));
ev_io_init(w, io_cb, -1, 0);
w->data = watcher;
return w;
}
void ioev_io_watcher_free(ev_io *w) {
free(w);
}
void ioev_io_set(ev_io *w, int fd, int ev) {
int events = 0;
if (ev & IOEV_READ) events = events | EV_READ;
if (ev & IOEV_WRITE) events = events | EV_WRITE;
ev_io_set(w, fd, events);
}

BIN
src/io/events_c.o Normal file

Binary file not shown.