Commit 54fb31ee authored by Dustin L. Howett's avatar Dustin L. Howett

Abstract the fds and read/write buffers away into a server object.

parent 9af29db8
......@@ -3,7 +3,7 @@ export GO_EASY_ON_ME=1
include theos/makefiles/common.mk
TOOL_NAME = oligos
oligos_FILES = main.cc commands.cc event.cc
oligos_FILES = main.cc commands.cc server.cc event.cc
oligos_SUBPROJECTS = dady
include $(THEOS_MAKE_PATH)/tool.mk
......@@ -10,9 +10,9 @@
extern void *app_handle;
#include "commands.h"
#define _COMMAND(name) extern "C" int cmd_ ## name (int argc, char **argv, struct command_state *state)
#define _COMMAND(name) extern "C" int cmd_ ## name (struct server *server, int argc, char **argv, struct command_state *state)
int dispatch_command(const char *cmdname, int argc, char **argv, struct command_state *state) {
int dispatch_command(struct server *server, const char *cmdname, int argc, char **argv, struct command_state *state) {
char *namecmp = (char *)malloc(strlen(cmdname));
char *namep = namecmp;
while(*cmdname) {
......@@ -26,7 +26,7 @@ int dispatch_command(const char *cmdname, int argc, char **argv, struct command_
command_handler handler = (command_handler)dlsym(app_handle, symname);
if(!handler) return -1;
return handler(argc, argv, state);
return handler(server, argc, argv, state);
}
void do_copyover(char *);
......@@ -37,20 +37,20 @@ _COMMAND(copyover) {
}
_COMMAND(ping) {
ircprintf("PRIVMSG %s :PONG", state->channel);
ircprintf(server, "PRIVMSG %s :PONG", state->channel);
return 0;
}
_COMMAND(report) {
ircprintf("PRIVMSG %s :Compile date: %s %s", state->channel, __DATE__, __TIME__);
ircprintf(server, "PRIVMSG %s :Compile date: %s %s", state->channel, __DATE__, __TIME__);
return 0;
}
_COMMAND(arguments) {
char **argvp = argv;
ircprintf("PRIVMSG %s :argc: %d", state->channel, argc);
ircprintf(server, "PRIVMSG %s :argc: %d", state->channel, argc);
while(*argvp) {
ircprintf("PRIVMSG %s :Argument: %s", state->channel, *argvp);
ircprintf(server, "PRIVMSG %s :Argument: %s", state->channel, *argvp);
argvp++;
}
return 0;
......
......@@ -2,7 +2,7 @@
#define __COMMANDS_H
#include "oligos.h"
typedef int (*command_handler)(int argc, char **argv, struct command_state *state);
int dispatch_command(const char *command, int argc, char **argv, struct command_state *state);
typedef int (*command_handler)(struct server *server, int argc, char **argv, struct command_state *state);
int dispatch_command(struct server *server, const char *command, int argc, char **argv, struct command_state *state);
#endif //__COMMANDS_H
......@@ -7,7 +7,7 @@
#include "event.h"
#include "commands.h"
void dispatch_event(char *name, struct sender *sender, char *msgbuf) {
void dispatch_event(struct server *server, char *name, struct sender *sender, char *msgbuf) {
event_handler_func handler = NULL;
eventhandler *c;
for(c = &event_handlers[0]; c->name; ++c) {
......@@ -18,19 +18,19 @@ void dispatch_event(char *name, struct sender *sender, char *msgbuf) {
}
if(handler) {
handler(sender, msgbuf);
handler(server, sender, msgbuf);
}
}
#define _EVENT(name) void evt_ ## name (struct sender *sender, char *msgbuf)
#define _EVENT(name) void evt_ ## name (struct server *server, struct sender *sender, char *msgbuf)
_EVENT(001) {
char *nick = strsep(&msgbuf, " ");
//_nick = strdup(nick);
ircprintf("JOIN #bacon");
ircprintf(server, "JOIN #bacon");
}
_EVENT(ping) {
ircprintf("PONG %s", msgbuf);
ircprintf(server, "PONG %s", msgbuf);
}
_EVENT(privmsg) {
......@@ -71,8 +71,8 @@ _EVENT(privmsg) {
state.message_type = (priv ? MESSAGE_TYPE_PRIVATE : MESSAGE_TYPE_PUBLIC);
state.channel = (priv ? sender->nick : recipient);
if(dispatch_command(commandname, argc, argv, &state) == -1) {
ircprintf("PRIVMSG %s :Unknown command: %s", priv?sender->nick:recipient, commandname);
if(dispatch_command(server, commandname, argc, argv, &state) == -1) {
ircprintf(server, "PRIVMSG %s :Unknown command: %s", priv?sender->nick:recipient, commandname);
}
free(argv);
......
#ifndef EVENT_H
#define EVENT_H
typedef void (*event_handler_func)(struct sender *sender, char *msgbuf);
typedef void (*event_handler_func)(struct server *server, struct sender *sender, char *msgbuf);
typedef struct {
const char *name;
......@@ -10,6 +10,6 @@ typedef struct {
extern eventhandler event_handlers[];
void dispatch_event(char *name, struct sender *sender, char *msgbuf);
void dispatch_event(struct server *server, char *name, struct sender *sender, char *msgbuf);
#endif /* end of include guard: EVENT_H */
......@@ -21,24 +21,17 @@ void *app_handle;
#include "oligos.h"
#include "event.h"
#include "commands.h"
#include "server.h"
static char *progname;
static int irc_fd = -1;
static int control_fd = -1;
static char irc_read_ring[READ_BUF_LEN]; // We should be able to take up to 8 messages in a buffer. Just in case.
static unsigned long long int nbytes_read = 0;
static char *irc_write_ring;
static unsigned long long int nbytes_write = 0;
static char *_nick;
static struct server *server;
#define MAX(a,b) (a>b?a:b)
void do_copyover(char *requester) {
_D("Beginning copyover.\n");
_D("Bytes in buffer: %llu\n", nbytes_read);
char *fn = strdup("/tmp/copyover.XXXXXX");
int fd = mkstemp(fn);
......@@ -58,22 +51,27 @@ void do_copyover(char *requester) {
free(fn);
if(requester) // Yes, we're actually queueing this for when the copyover comes back and the socket is ready. Clever?!
ircprintf("PRIVMSG %s :--- COPYOVER COMPLETE ---", requester);
ircprintf(server, "PRIVMSG %s :--- COPYOVER COMPLETE ---", requester);
uint8_t *tag_data = NULL;
uint32_t tags_size = 0;
uint8_t *server_data = NULL;
uint32_t server_size = 0;
server_data = server_freeze(server, &server_size);
struct tag_info copyovertags[] = {
{ 'RBUF', nbytes_read, irc_read_ring, },
{ 'WBUF', nbytes_write, irc_write_ring, },
{ 'IRCD', sizeof(irc_fd), &irc_fd, },
{ 'SERV', server_size, server_data, },
{ 'CTLD', sizeof(control_fd), &control_fd, },
{ 'NICK', _nick ? strlen(_nick) : 0, _nick, },
};
tag_data = taglist_to_dady(copyovertags, sizeof(copyovertags)/sizeof(struct tag_info), &tags_size);
write(fd, tag_data, tags_size);
lseek(fd, 0, SEEK_SET);
free(server_data);
free(tag_data);
char *len_str;
asprintf(&len_str, "%u", tags_size);
......@@ -83,27 +81,12 @@ void do_copyover(char *requester) {
static int _load_copyover_tag_cb(uint32_t tagtype, uint32_t len, uint8_t *data, struct dady_callback *cb, void *cbdata) {
switch(tagtype) {
case 'RBUF':
if(len > 0) {
memcpy(irc_read_ring, data, len);
nbytes_read = len;
}
break;
case 'WBUF':
if(len > 0) {
memcpy(irc_write_ring, data, len);
nbytes_write = len;
}
break;
case 'IRCD':
memcpy(&irc_fd, data, len);
_D("Got file descriptor %d for IRC.\n", irc_fd);
case 'SERV':
server = server_thaw(data, len);
break;
case 'CTLD':
memcpy(&control_fd, data, len);
_D("Got control descriptor %d.\n", control_fd);
case 'NICK':
_nick = strndup((char *)data, len);
break;
}
return len;
......@@ -148,16 +131,19 @@ void init_irc(int argc, char **argv) {
_D("Oh shit: %s\n", strerror(errno));
exit(1);
}
irc_fd = socket_fd;
server = server_alloc();
server->hostname = strdup(argv[1]);
server->fd = socket_fd;
control_fd = 0;
_D("Got control fd %d\n", control_fd);
ircprintf("USER 1 2 3 4"); // TODO: YEAH
ircprintf("NICK oligosII");
ircprintf(server, "USER 1 2 3 4"); // TODO: YEAH
ircprintf(server, "NICK oligosII");
}
void ircprintf(const char *format, ...) {
void ircprintf(struct server *server, const char *format, ...) {
char *intermediate;
va_list ap;
......@@ -166,19 +152,19 @@ void ircprintf(const char *format, ...) {
va_end(ap);
_D("-> \"%s\"\n", intermediate);
if(WRITE_BUF_LEN - nbytes_write < strlen(intermediate)+2) {
if(WRITE_BUF_LEN - server->nbytes_write < strlen(intermediate)+2) {
fprintf(stderr, "ERROR: Write buffer filled up!\n");
free(intermediate);
return;
}
nbytes_write += snprintf(irc_write_ring + nbytes_write, WRITE_BUF_LEN - nbytes_write, "%s\r\n", intermediate);
_D("SENDQ: %llu/%d bytes consumed.\n", nbytes_write, WRITE_BUF_LEN);
server->nbytes_write += snprintf(server->writebuf + server->nbytes_write, WRITE_BUF_LEN - server->nbytes_write, "%s\r\n", intermediate);
_D("SENDQ: %llu/%d bytes consumed.\n", server->nbytes_write, WRITE_BUF_LEN);
free(intermediate);
}
void handle_irc(char *msgbuf) {
void handle_irc(struct server *server, char *msgbuf) {
struct sender sender;
memset(&sender, 0, sizeof(sender));
char *cmd = NULL;
......@@ -195,64 +181,64 @@ void handle_irc(char *msgbuf) {
cmd = strsep(&msgbuf, " ");
_D("[%s!%s@%s] %s %s\n", sender.nick, sender.username, sender.host, cmd, msgbuf);
dispatch_event(cmd, &sender, msgbuf);
dispatch_event(server, cmd, &sender, msgbuf);
return;
}
void _read_irc(int fd) {
void _read_irc(struct server *server) {
static char irc_msg[513]; // RFC spec - messages are only 512 characters, and \0.
int readcount = 0;
if(nbytes_read < READ_BUF_LEN)
readcount = read(irc_fd, irc_read_ring + nbytes_read, READ_BUF_LEN-nbytes_read);
if(server->nbytes_read < READ_BUF_LEN)
readcount = read(server->fd, server->readbuf + server->nbytes_read, READ_BUF_LEN-server->nbytes_read);
if(readcount > 0) {
// TODO: There is something wrong with this, I believe.
_D("IRC -> ringbuf[%llu]\n", nbytes_read);
nbytes_read += readcount;
_D("Total bytes in buffer: %llu\n", nbytes_read);
_D("IRC -> ringbuf[%llu]\n", server->nbytes_read);
server->nbytes_read += readcount;
_D("Total bytes in buffer: %llu\n", server->nbytes_read);
}
char *nl_ptr;
int nl;
while((nl_ptr = strstr(irc_read_ring, "\r\n")) != NULL) {
nl = nl_ptr - irc_read_ring;
while((nl_ptr = strstr(server->readbuf, "\r\n")) != NULL) {
nl = nl_ptr - server->readbuf;
if(nl > 0) {
strncpy(irc_msg, irc_read_ring, nl);
strncpy(irc_msg, server->readbuf, nl);
irc_msg[nl] = '\0';
}
int consume = nl;
while(irc_read_ring[consume] == '\n' || irc_read_ring[consume] == '\r') ++consume;
memmove(irc_read_ring, irc_read_ring+consume, READ_BUF_LEN-consume);
nbytes_read -= consume;
_D("Chomped %d bytes. Total bytes in buffer: %llu\n", consume, nbytes_read);
while(server->readbuf[consume] == '\n' || server->readbuf[consume] == '\r') ++consume;
memmove(server->readbuf, server->readbuf+consume, READ_BUF_LEN-consume);
server->nbytes_read -= consume;
_D("Chomped %d bytes. Total bytes in buffer: %llu\n", consume, server->nbytes_read);
if(nl > 0) {
handle_irc(irc_msg);
handle_irc(server, irc_msg);
}
}
}
void _write_irc(int fd) {
int written = write(fd, irc_write_ring, nbytes_write);
_D("Wrote %d/%llu bytes.\n", written, nbytes_write);
nbytes_write -= written;
if(nbytes_write == 0) return;
memmove(irc_write_ring, irc_write_ring+written, nbytes_write);
void _write_irc(struct server *server) {
int written = write(server->fd, server->writebuf, server->nbytes_write);
_D("Wrote %d/%llu bytes.\n", written, server->nbytes_write);
server->nbytes_write -= written;
if(server->nbytes_write == 0) return;
memmove(server->writebuf, server->writebuf+written, server->nbytes_write);
}
void event_loop() {
fd_set read_fds, write_fds;
int nfds = 0;
if(irc_fd > -1)
nfds = MAX(nfds, irc_fd);
if(server->fd > -1)
nfds = MAX(nfds, server->fd);
if(control_fd > -1)
nfds = MAX(nfds, control_fd);
nfds++;
while(true) {
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
if(irc_fd > -1) {
FD_SET(irc_fd, &read_fds);
FD_SET(irc_fd, &write_fds);
if(server->fd > -1) {
FD_SET(server->fd, &read_fds);
FD_SET(server->fd, &write_fds);
}
if(control_fd > -1)
FD_SET(control_fd, &read_fds);
......@@ -261,8 +247,8 @@ void event_loop() {
_D("Error selecting?\n");
exit(1);
}
if(FD_ISSET(irc_fd, &read_fds)) {
_read_irc(irc_fd);
if(FD_ISSET(server->fd, &read_fds)) {
_read_irc(server);
}
if(FD_ISSET(control_fd, &read_fds)) {
char buf[1024];
......@@ -274,27 +260,21 @@ void event_loop() {
} else if(strncmp(buf, "quit", 4) == 0) {
exit(0);
} else if(strncmp(buf, "send ", 5) == 0) {
ircprintf("%s", buf+5);
ircprintf(server, "%s", buf+5);
}
}
if(nbytes_write > 0 && FD_ISSET(irc_fd, &write_fds)) {
_D("Socket ready for writing and we have %llu bytes of data.\n", nbytes_write);
_write_irc(irc_fd);
if(server->nbytes_write > 0 && FD_ISSET(server->fd, &write_fds)) {
_D("Socket ready for writing and we have %llu bytes of data.\n", server->nbytes_write);
_write_irc(server);
}
}
}
void _init_buffers() {
irc_write_ring = (char *)malloc(WRITE_BUF_LEN);
}
int main(int argc, char **argv, char **envp) {
progname = strdup(argv[0]);
app_handle = dlopen(NULL, RTLD_NOW|RTLD_LOCAL|RTLD_FIRST);
_init_buffers();
if(argc > 1 && strcmp(argv[1], "-copyover") == 0) {
init_copyover(argc, argv);
} else {
......
......@@ -22,6 +22,7 @@ struct command_state {
#define READ_BUF_LEN 4096
#define WRITE_BUF_LEN (200*1024)
void ircprintf(const char *format, ...);
struct server;
void ircprintf(struct server *server, const char *format, ...);
#endif /* end of include guard: OLIGOS_H */
#include "oligos.h"
#include "dady/dady.h"
#include "server.h"
/* {{{ DADY */
static int _serv_internal_tag_cb(uint32_t tagtype, uint32_t len, uint8_t *data, struct dady_callback *cb, struct server *server) {
switch(tagtype) {
case 'RBUF':
if(len > 0) {
memcpy(server->readbuf, data, len);
server->nbytes_read = len;
}
break;
case 'WBUF':
if(len > 0) {
memcpy(server->writebuf, data, len);
server->nbytes_write = len;
}
break;
case '_FD_':
memcpy(&server->fd, data, len);
_D("Got file descriptor %d for IRC.\n", server->fd);
break;
case 'NICK':
server->nick = strndup((char *)data, len);
break;
case 'HOST':
server->hostname = strndup((char *)data, len);
break;
}
return len;
}
static struct dady_callback _serv_internal_callbacks = { NULL, (tag_callback)&_serv_internal_tag_cb };
/* }}} */
struct server *server_alloc() {
struct server *newserver = (struct server *)calloc(1, sizeof(struct server));
newserver->readbuf = (char *)malloc(READ_BUF_LEN);
newserver->writebuf = (char *)malloc(WRITE_BUF_LEN);
return newserver;
}
uint8_t *server_freeze(struct server *server, uint32_t *outlen) {
struct tag_info taglist[] = {
{ 'RBUF', server->nbytes_read, server->readbuf, },
{ 'WBUF', server->nbytes_write, server->writebuf, },
{ '_FD_', sizeof(server->fd), &server->fd, },
{ 'NICK', server->nick ? strlen(server->nick) : 0, server->nick, },
{ 'HOST', server->hostname ? strlen(server->hostname) : 0, server->hostname, },
};
uint32_t ntags = sizeof(taglist)/sizeof(struct tag_info);
uint8_t *outbuf = taglist_to_container(taglist, ntags, '----', false, outlen);
return outbuf;
}
struct server *server_thaw(uint8_t *data, uint32_t size) {
struct server *out = NULL;
out = server_alloc();
for(uint8_t *datap = data; datap<data+size;) {
int len = bscantag(datap, size-(datap-data), &_serv_internal_callbacks, out);
if(len == -1) break; // Problem, Officer?
datap += len + _TAG_HEAD_LEN;
}
return out;
}
void server_dealloc(struct server *server) {
free(server->readbuf);
free(server->writebuf);
free(server->nick);
free(server);
}
#ifndef SERVER_H
#define SERVER_H
struct server {
char *hostname;
char *nick;
int fd;
char *readbuf;
unsigned long long int nbytes_read;
char *writebuf;
unsigned long long int nbytes_write;
};
struct server *server_alloc();
uint8_t *server_freeze(struct server *server, uint32_t *outlen);
struct server *server_thaw(uint8_t *data, uint32_t size);
void server_dealloc(struct server *server);
#endif /* end of include guard: SERVER_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment