Commit 91cbe124 authored by Dustin L. Howett's avatar Dustin L. Howett

Initial Commit

parents
export TARGET=native
export GO_EASY_ON_ME=1
include theos/makefiles/common.mk
TOOL_NAME = oligos
oligos_FILES = main.cc
oligos_SUBPROJECTS = dady
include $(THEOS_MAKE_PATH)/tool.mk
include $(THEOS)/makefiles/common.mk
SUBPROJECT_NAME = dady
dady_FILES = dady.c
dady_CFLAGS = -std=c99
AUXILIARY_LDFLAGS += -lz
include $(THEOS_MAKE_PATH)/subproject.mk
#include "dady.h"
#include <sys/types.h>
#include <zlib.h>
/*
char *to_hex_string(uint8_t *data, int size) {
static char o[512];
char *op = o;
int i = 0;
for(i = 0; i < size; i++) {
sprintf(op+(2*i), "%2.02x", *(data+i));
}
op[2*i] = '\0';
return op;
}
void dump(const char *s, int len) {
for(int i = 0; i < len; i++) {
unsigned char x = s[i];
if(isprint(x)) printf(" '%c'", x);
else printf(" %2.02x ", x);
}
printf("\n");
}
*/
static int _default_group_tag_cb(uint32_t tagtype, uint16_t len, uint8_t *data, struct dady_callback *cb, void *cbdata) {
uint16_t size = len;// - 4;
//uint32_t cksm = *(uint32_t*)(data+size);
/*
uint32_t proper_cksm = crc32(0, (uint8_t*)&tagtype, sizeof(tagtype));
proper_cksm = crc32(proper_cksm, (uint8_t*)&len, sizeof(len));
proper_cksm = crc32(proper_cksm, data, size);
if(proper_cksm != cksm) {
_D("YOU WANT TO FUCK ON ME?!?!\n");
#ifndef DEBUG
free(data);
return -1;
#else
_D("Because I'm in debug mode, I'm allowing it anyway.\n");
#endif
}
*/
for(uint8_t *datap = data; datap<data+size;) {
int len = bscantag(datap, size-(datap-data), cb, cbdata);
if(len == -1) break; // Problem, Officer?
datap += len + _TAG_HEAD_LEN;
}
return len;
}
static int _default_tag_cb(uint32_t tagtype, uint16_t len, uint8_t *data, struct dady_callback *cb, void *cbdata) {
_D("Callback got a tag of type %8.08x with a length of %hu.\n", tagtype, len);
return len;
}
struct dady_callback _default_cb = {
.group_tag_cb = _default_group_tag_cb,
.tag_cb = _default_tag_cb
};
int bscantag(uint8_t *buf, uint32_t buflen, struct dady_callback *cb, void *cbdata) {
if(buflen < _TAG_HEAD_LEN) { // We don't have enough data for a tag.
_D("Buffer is only %d bytes :(\n", buflen);
return -1;
}
uint32_t tagtype = *((uint32_t*)buf);
uint16_t size = *(uint16_t*)((uint32_t*)buf+1);
int r = 0;
if(buflen < size) { // We don't have enough remaining buffer for this tag?
_D("Buffer is only %d bytes and tag size is %d...\n", buflen, size);
return -1;
}
uint8_t *data = (uint8_t *)malloc(size);
memcpy(data, buf+_TAG_HEAD_LEN, size);
_D("Got a tag type %4.4s sized %u (buflen %u).\n", (char*)&tagtype, size, buflen);
if(tagtype == TAG_ID_DADY) {
tag_callback tc = cb->group_tag_cb ?: _default_cb.group_tag_cb;
r = tc(tagtype, size, data, cb, cbdata);
} else {
tag_callback tc = cb->tag_cb ?: _default_cb.tag_cb;
r = tc(tagtype, size, data, cb, cbdata);
}
free(data);
return r;
}
/*uint32_t _tag_expected_length(uint32_t datalen, bool checksum = false) {
return datalen + 8 + (checksum ? 4 : 0);
}*/
uint32_t bprinttag(uint8_t *buf, uint32_t tagtype, uint16_t len, void *data, bool checksum) {
uint16_t headlen = len;
if(checksum) headlen += 4;
if(buf) {
uint8_t *tag = buf;
*(uint32_t*)tag = tagtype;
*(uint16_t*)(tag+4) = headlen;
memcpy(tag+_TAG_HEAD_LEN, data, len);
if(checksum) {
uint32_t crc = crc32(0, tag, _TAG_LENGTH(len));
*(uint32_t*)(tag+_TAG_HEAD_LEN+len) = crc;
}
}
return headlen + _TAG_HEAD_LEN;
}
uint32_t abprinttag(uint8_t **buf, uint32_t tagtype, uint16_t len, void *data, bool checksum) {
uint32_t taglen = bprinttag(NULL, tagtype, len, data, checksum);
*buf = (uint8_t*)malloc(taglen);
return bprinttag(*buf, tagtype, len, data, checksum);
}
uint8_t *taglist_to_dady(struct tag_info *taglist, uint32_t ntags, uint32_t *outlen) {
uint32_t n = 0;
for(unsigned int i = 0; i < ntags; i++) {
n += bprinttag(NULL, 0, taglist[i].len, NULL, false);
}
uint32_t contentlen = n;
uint8_t *container = (uint8_t*)malloc(contentlen);
n = 0;
for(unsigned int i = 0; i < ntags; i++) {
n += bprinttag(container+n, taglist[i].type, taglist[i].len, taglist[i].bufp, false);
}
uint8_t *dadytag;
*outlen = abprinttag(&dadytag, TAG_ID_DADY, contentlen, container, false);
free(container);
return dadytag;
}
// vim:ft=objc
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#define TAG_ID_DADY 'DADY'
#define TAG_ID_RBUF 'RBUF'
#define TAG_ID_FD__ 'FD__'
#define TAG_ID_NICK 'NICK'
#define _TAG_HEAD_LEN 6
#define _TAG_LENGTH(datalen) (datalen+_TAG_HEAD_LEN)
#define _TAG_LENGTH_CHECKSUM(datalen) (datalen+_TAG_HEAD_LEN+4)
#ifdef DEBUG
#ifdef __OBJC__
#define _D(...) NSLog(@__VA_ARGS__)
#else
#define _D(...) fprintf(stderr, __VA_ARGS__)
#endif
#else
#define _D(...)
#endif
#ifdef __cplusplus
#define _DEFAULT(d) = d
#else
#define _DEFAULT(d)
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct dady_callback {
int (*group_tag_cb)(uint32_t tagtype, uint16_t len, uint8_t *data, struct dady_callback *cb, void *cbdata);
int (*tag_cb)(uint32_t tagtype, uint16_t len, uint8_t *data, struct dady_callback *cb, void *cbdata);
};
typedef int (*tag_callback)(uint32_t tagtype, uint16_t len, uint8_t *data, struct dady_callback *cb, void *cbdata);
int bscantag(uint8_t *buf, uint32_t buflen, struct dady_callback *cb, void *cbdata);
uint32_t bprinttag(uint8_t *buf, uint32_t tagtype, uint16_t len, void *data, bool checksum _DEFAULT(false));
uint32_t abprinttag(uint8_t **buf, uint32_t tagtype, uint16_t len, void *data, bool checksum _DEFAULT(false));
struct tag_info {
uint32_t type;
uint16_t len;
void *bufp;
};
uint8_t *taglist_to_dady(struct tag_info *taglist, uint32_t ntags, uint32_t *outlen);
#ifdef __cplusplus
}
#endif
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdarg.h>
#include "dady/dady.h"
static char *progname;
static int irc_fd = -1;
static int control_fd = -1;
#define READ_BUF_LEN 4096
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;
#define WRITE_BUF_LEN (200*1024)
static char *irc_write_ring;
static unsigned long long int nbytes_write = 0;
static char *_nick;
struct sender {
char *nick;
char *username;
char *host;
};
void ircprintf(const char *format, ...);
#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);
if(!fd) {
_D("Copyover failed: %s\n", strerror(errno));
return;
}
_D("Copyover filename: %s\n", fn);
char *fd_str;
asprintf(&fd_str, "%d", fd);
#ifndef DEBUG
unlink(fn);
#endif
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);
uint8_t *tag_data = NULL;
uint32_t tags_size = 0;
struct tag_info copyovertags[] = {
{ 'RBUF', nbytes_read, irc_read_ring, },
{ 'WBUF', nbytes_write, irc_write_ring, },
{ 'IRCD', sizeof(irc_fd), &irc_fd, },
{ '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);
char *len_str;
asprintf(&len_str, "%u", tags_size);
execv(progname, (char* const[]){progname, (char*)"-copyover", fd_str, len_str, NULL});
_D("Copyover failed: %s\n", strerror(errno));
}
static int _load_copyover_tag_cb(uint32_t tagtype, uint16_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);
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;
}
static struct dady_callback _load_copyover_callbacks = { NULL, &_load_copyover_tag_cb };
void init_copyover(int argc, char **argv) {
_D("Booting from copyover.\n");
int copyover_fd = strtoul(argv[2], NULL, 10);
int copyover_size = strtoul(argv[3], NULL, 10);
uint8_t *data = (uint8_t *)malloc(copyover_size);
read(copyover_fd, data, copyover_size);
bscantag(data, copyover_size, &_load_copyover_callbacks, NULL);
close(copyover_fd);
free(data);
}
void init_irc(int argc, char **argv) {
struct sockaddr_in server_addr;
int socket_fd = socket(PF_INET, SOCK_STREAM, 0);
if(socket_fd < 0) {
_D("Oh shit: %s\n", strerror(errno));
exit(1);
}
memset(&server_addr, 0, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6667);
if((server_addr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE) {
struct addrinfo *res = NULL;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
getaddrinfo(argv[1], NULL, &hint, &res);
server_addr.sin_addr.s_addr = ((struct sockaddr_in *)(res[0].ai_addr))->sin_addr.s_addr;
freeaddrinfo(res);
}
int ret = connect(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(ret < 0) {
_D("Oh shit: %s\n", strerror(errno));
exit(1);
}
irc_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");
}
void ircprintf(const char *format, ...) {
char *intermediate;
va_list ap;
va_start(ap, format);
vasprintf(&intermediate, format, ap);
va_end(ap);
_D("-> \"%s\"\n", intermediate);
if(WRITE_BUF_LEN - 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);
free(intermediate);
}
void handle_irc(char *msgbuf) {
static bool seen001;
struct sender sender;
memset(&sender, 0, sizeof(sender));
char *cmd = NULL;
if(msgbuf[0] == ':') {
char *temp_sender;
temp_sender = strsep(&msgbuf, " ") + 1;
if(strchr(temp_sender, '!') != NULL) {
sender.nick = strsep(&temp_sender, "!");
sender.username = strsep(&temp_sender, "@");
}
sender.host = temp_sender;
}
cmd = strsep(&msgbuf, " ");
_D("%s from %s (%s) on %s.\n", cmd, sender.nick, sender.username, sender.host);
_D("<- \"%s\"\n", msgbuf);
if(!seen001 && strcmp(cmd, "001") == 0) {
seen001 = true;
char *nick = strsep(&msgbuf, " ");
_nick = strdup(nick);
ircprintf("JOIN #bacon");
} else if(strcmp(cmd, "PING") == 0) {
ircprintf("PONG %s", msgbuf);
} else if(strcmp(cmd, "PRIVMSG") == 0) {
char *recipient = strsep(&msgbuf, " ");
msgbuf++; // Lop off the errant : at the beginning.
bool priv = false;
if(strcmp(recipient, "oligosII") == 0) {
priv = true;
}
bool addressed = priv || strncmp(msgbuf, "!o ", 3) == 0;
if(addressed && !priv) msgbuf += 3;
if(addressed) {
if(strcmp(msgbuf, "copyover") == 0)
do_copyover(sender.nick);
else if(strcmp(msgbuf, "quit") == 0)
exit(0);
else if(strcmp(msgbuf, "ping") == 0)
ircprintf("PRIVMSG %s :PONG (%s!%s@%s)", priv?sender.nick:recipient, sender.nick, sender.username, sender.host);
else if(strcmp(msgbuf, "report") == 0)
ircprintf("PRIVMSG %s :Compile date: %s %s", priv?sender.nick:recipient, __DATE__, __TIME__);
}
}
return;
}
void _read_irc(int fd) {
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(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);
}
char *nl_ptr;
int nl;
while((nl_ptr = strstr(irc_read_ring, "\r\n")) != NULL) {
nl = nl_ptr - irc_read_ring;
if(nl > 0) {
strncpy(irc_msg, irc_read_ring, 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);
if(nl > 0) {
handle_irc(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 event_loop() {
fd_set read_fds, write_fds;
int nfds = 0;
if(irc_fd > -1)
nfds = MAX(nfds, irc_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(control_fd > -1)
FD_SET(control_fd, &read_fds);
int r = select(nfds, &read_fds, &write_fds, NULL, NULL);
if(r == -1) {
_D("Error selecting?\n");
exit(1);
}
if(FD_ISSET(irc_fd, &read_fds)) {
_read_irc(irc_fd);
}
if(FD_ISSET(control_fd, &read_fds)) {
char buf[1024];
int r = read(control_fd, buf, 1024);
buf[r] = '\0';
if(buf[r-1] == '\n') buf[r-1] = '\0';
if(strncmp(buf, "copyover", 8) == 0) {
do_copyover(NULL);
} else if(strncmp(buf, "quit", 4) == 0) {
exit(0);
} else if(strncmp(buf, "send ", 5) == 0) {
ircprintf("%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);
}
}
}
void _init_buffers() {
irc_write_ring = (char *)malloc(WRITE_BUF_LEN);
}
int main(int argc, char **argv, char **envp) {
progname = strdup(argv[0]);
_init_buffers();
if(argc > 1 && strcmp(argv[1], "-copyover") == 0) {
init_copyover(argc, argv);
} else {
init_irc(argc, argv);
}
event_loop();
return 0;
}
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