Greetings All,
As promised, here is a basic rundown on the library that I've been
working on that I see as the basis of Bahamut 2.0. I'm currently
calling it libd - lib daemon, because I'm so original and creative.
At the bottom of this email is the code of a simple echo server based
on the library, which might be useful as a reference.
I'm working on a slightly object oriented model, while still using
straight C. The general idea is simple - the library implements all
lower level functions regarding nonblocking socket interaction. It
(will) support ipv6, compression, SSL, and threading. At current, it
supports ipv6 only of those features. The API is designed based on an
object model, for example:
To create a listener, call the routine create_listener within the
socket engine, get an "object", and set up some basic things you want
associated with the listener. The minimum would be to give the
library a function to identify what constitutes a message, then a
function that would parse and act on that message. You could also
define functions that would be called when we accept a connection and
when a connection is dropped.
There are four core objects - the socket engine handler itself,
SockEng, the listener object, Listener, the client object, Client, and
the grouping object, Group.
SockEng is used to manage the "global" definitions of the library -
such as defining error handling routines.
Listeners are used to manage listeners, and what default settings a
client has when they connect.
Clients are used to interact with clients.
Groups are used to group together different sets of clients, and send
to sets of clients using some optimizations accordingly.
This gives a very high-level overview - but I'd like to talk about the
threading model I have in mind. This hasn't been implemented yet, but
I've been designing a lot of the system with this in mind for the
future. I've decided that threading is important to support simply
because the recent crop of CPU designers hate programmers enough to
effectively force it on us. Threading has always been a point of
heated argument in the past - how do we do it? I've come up with the
following design:
1. Poll thread - basically hosts the polling engine, whatever it happens to be.
2. Read/Write thread set(s). Watch queues and polling states, reads
and writes from and to sockets, and interacts with queues.
3. Event trigger thread(s). Schedules and triggers events on timers,
for anything that isn't edge-triggered from a socket read.
4. Parsing/worker thread pool. Executes actual work from event or
read threads, and places data into write thread queues.
I'm trying to design the library API in such a fashion that it
actually handles most of the threading logic. However, getting this
to work as we want will take a lot of time, but I have a feeling that
IRCd will thread quite well in this method. My hope is to build a
library that will be flexible enough, without being too complex, that
it could be applied to other projects.
So what are people thinking so far? Does this look like a good
direction? Does anyone have comments on the current design? I'll try
to clean up the code and get it available sometime in the next week
for people to start actually poking.
Talk! Discuss! Criticize! Insult! Lets get talking.
-epiphani
====== test.c =======
#include "sockeng.h"
int client_packet_delim(Client *c, char *buf, int len)
{
int i = 0;
/* find a \n */
while(len > i) {
if(buf[i] == '\n')
return ++i;
i++;
}
return 0;
}
int client_echo_parser(Client *c, char *start, int len)
{
char buf[BUFSIZE];
memset(buf, 0, BUFSIZE);
snprintf(buf, len+1, "%s", start);
c->send(c, buf, len);
return 0;
}
void client_disconnecty(Client *s, int err)
{
printf("Client disconnected: %s\n", strerror(err));
}
int main(int argc, char *argv[])
{
SockEng *s;
Listener *l;
s = init_sockeng();
l = s->create_listener(s, 1111, NULL);
if(!l) {
printf("no listener create\n");
return -1;
} else {
l->set_packeter(l, client_packet_delim);
l->set_parser(l, client_echo_parser);
l->set_onclose(l, client_disconnecty);
}
while(1) {
if(s->poll(s, 1)) {
printf("poll error\n");
return -1;
}
}
return 0;
}