ref: 202447793107a549c7e418dc3b2208caa89a0bb3
parent: 375f68cba6f87f824a01f604b65057138c754a43
author: libredev <libredev@ircforever.org>
date: Mon Feb 13 08:46:51 EST 2023
cleaned up the code
--- a/config.mk
+++ b/config.mk
@@ -6,9 +6,6 @@
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
-# OpenBSD (comment)
-LIBS = -lbsd
-
CPPFLAGS = -D_DEFAULT_SOURCE -DVERSION=\"$(VERSION)\"
CFLAGS = -g -std=c89 -Wall -Wextra -pedantic -Wfatal-errors -Wconversion\
-Wstrict-prototypes -Wold-style-definition $(CPPFLAGS)
--- a/htable.c
+++ b/htable.c
@@ -3,70 +3,25 @@
* See COPYING file for more information.
*/
-#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
-#include <string.h>
#include "htable.h"
-static unsigned int
-hash(Htable *ht, void *key)
-{
- unsigned int i;
- unsigned int sum = 0;
-
- /* very simple hash function */
- for (i = 0; i < (unsigned int)ht->keylenfn(key); i++) {
- sum += ((unsigned char *)key)[i] * (i + 1);
- }
- return (sum % ht->cap);
-}
-
-Htable *
-htcreate(KeyLenFn *keylenfn, KeyCmpFn *keycmpfn, FreeKeyFn *freekeyfn, FreeValFn *freevalfn, unsigned int cap)
-{
- unsigned int i;
- Htable *ht;
-
- if (keylenfn == NULL || keycmpfn == NULL || freekeyfn == NULL || freevalfn == NULL) {
- printf("error: callback function(s) cannot be NULL\n");
- return NULL;
- }
-
- /* create a hash table */
- if ((ht = calloc(1, sizeof(Htable))) == NULL) {
- printf("error: calloc: %s\n", strerror(errno));
- return NULL;
- }
- if ((ht->nodes = calloc(cap, sizeof(Htnode))) == NULL) {
- printf("error: calloc: %s\n", strerror(errno));
- return NULL;
- }
- ht->cap = cap;
- ht->len = 0;
- ht->keylenfn = keylenfn;
- ht->keycmpfn = keycmpfn;
- ht->freekeyfn = freekeyfn;
- ht->freevalfn = freevalfn;
-
- for (i = 0; i < cap; i++)
- ht->nodes[i] = NULL;
- return ht;
-}
-
+/*
+ * Destroy the hash table and, if the free_key_val flag is true, free the keys and values.
+ */
static void
-__htdestroy(Htable *ht, int dofree)
+destroy_and_free(struct htable *ht, int free_key_val)
{
unsigned int i;
- Htnode *n;
- Htnode *tmp;
+ struct htnode *n, *tmp;
for (i = 0; i < ht->cap; i++) {
for (n = ht->nodes[i]; n != NULL;) {
- if (dofree) {
- ht->freekeyfn(n->key);
- ht->freevalfn(n->val);
+ if (free_key_val) {
+ ht->key_free(n->key);
+ ht->val_free(n->val);
}
tmp = n;
n = n->next;
@@ -77,160 +32,196 @@
free(ht);
}
-void
-htdestroy(Htable *ht)
+/*
+ * Insert a new node or, if the replace flag is true, replace the value of an existing node.
+ */
+static int
+insert_or_replace_val(struct htable *ht, void *key, void *val, int replace)
{
- __htdestroy(ht, 1);
-}
-
-void *
-htsearch(Htable *ht, void *key)
-{
unsigned int i;
- Htnode *n;
+ struct htnode *n, *ln; /* current and last node */
- i = hash(ht, key);
+ i = ht->hash(key, ht->cap);
+ ln = NULL;
for (n = ht->nodes[i]; n != NULL; n = n->next) {
- if (ht->keycmpfn(key, n->key) == 0)
- return n->val;
- }
- return NULL;
-}
-
-int
-htinsert(Htable *ht, void *key, void *val)
-{
- unsigned int i;
- Htnode *n; /* current node */
- Htnode *pn; /* previous node */
-
- pn = NULL;
- i = hash(ht, key);
- for (n = ht->nodes[i]; n != NULL; n = n->next) {
- /*if key already exist, override value */
- if (ht->keycmpfn(key, n->key) == 0) {
- ht->freekeyfn(n->key);
- ht->freevalfn(n->val);
- n->key = key;
- n->val = val;
- return 0;
+ /* if key already exist */
+ if (ht->key_cmp(key, n->key) == 0) {
+ if (replace) {
+ ht->val_free(n->val);
+ n->val = val;
+ return 0;
+ } else {
+ return -1;
+ }
}
- pn = n;
+ ln = n;
}
- /* create a new node */
- if ((n = calloc(1, sizeof(Htnode))) == NULL) {
- printf("error: calloc: %s\n", strerror(errno));
+ if (replace) /* failed to replace */
return -1;
+
+ if ((n = malloc(sizeof(struct htnode))) == NULL) {
+ perror("error: malloc");
+ return -1;
}
n->key = key;
n->val = val;
n->next = NULL;
- /* link to the previous node */
- if (pn == NULL)
+ /* link to the last node */
+ if (ln == NULL)
ht->nodes[i] = n;
else
- pn->next = n;
- /* increment the hash table length */
+ ln->next = n;
ht->len++;
- return 1;
+ return 0;
}
+/*
+ * Remove a node or, if the replace flag is true, change the key of the node.
+ */
static int
-__htremove(Htable *ht, void *key, int freeval)
+remove_or_replace_key(struct htable *ht, void *key, int replace, void *newkey)
{
unsigned int i;
- Htnode *n; /* current node */
- Htnode *pn; /* previous node */
+ struct htnode *n, *ln; /* current and last node */
- pn = NULL;
- i = hash(ht, key);
+ i = ht->hash(key, ht->cap);
+ ln = NULL;
for (n = ht->nodes[i]; n != NULL; n = n->next) {
- if (ht->keycmpfn(key, n->key) == 0) {
- /* free node memory */
- ht->freekeyfn(n->key);
- if (freeval)
- ht->freevalfn(n->val);
- /* link to the previous node */
- if (pn == NULL)
+ if (ht->key_cmp(key, n->key) == 0) {
+ ht->key_free(n->key);
+ if (!replace) {
+ ht->val_free(n->val);
+ } else {
+ if (htinsert(ht, newkey, n->val) == -1)
+ return -1;
+ }
+ /* link to the last node */
+ if (ln == NULL)
ht->nodes[i] = n->next;
else
- pn->next = n->next;
- /* free the node */
+ ln->next = n->next;
free(n);
- return 1;
+ return 0;
}
- pn = n;
+ ln = n;
}
return -1;
}
+struct htable *
+htcreate(hash_fn *hash, key_cmp_fn *key_cmp, key_free_fn *key_free,
+ val_free_fn *val_free, unsigned int cap)
+{
+ unsigned int i;
+ struct htable *ht;
+
+ if ((ht = malloc(sizeof(struct htable))) == NULL) {
+ perror("error: malloc");
+ return NULL;
+ }
+ if ((ht->nodes = malloc(cap * sizeof(struct htnode *))) == NULL) {
+ perror("error: malloc");
+ return NULL;
+ }
+ for (i = 0; i < cap; i++)
+ ht->nodes[i] = NULL;
+
+ ht->cap = cap;
+ ht->len = 0;
+ ht->hash = hash;
+ ht->key_cmp = key_cmp;
+ ht->key_free = key_free;
+ ht->val_free = val_free;
+ return ht;
+}
+
+void
+htdestroy(struct htable *ht)
+{
+ destroy_and_free(ht, 1);
+}
+
+void *
+htsearch(struct htable *ht, void *key)
+{
+ unsigned int i;
+ struct htnode *n;
+
+ i = ht->hash(key, ht->cap);
+ for (n = ht->nodes[i]; n != NULL; n = n->next) {
+ if (ht->key_cmp(key, n->key) == 0)
+ return n->val;
+ }
+ return NULL;
+}
+
int
-htremove(Htable *ht, void *key)
+htinsert(struct htable *ht, void *key, void *val)
{
- return __htremove(ht, key, 1);
+ return insert_or_replace_val(ht, key, val, 0);
}
int
-htsetkey(Htable *ht, void *oldkey, void *newkey)
+htremove(struct htable *ht, void *key)
{
- void *val = NULL;
- if ((val = htsearch(ht, oldkey)) == NULL)
- return -1;
- __htremove(ht, oldkey, 0);
- htinsert(ht, newkey, val);
- return 1;
+ return remove_or_replace_key(ht, key, 0, NULL);
}
-void
-htresize(Htable *ht, unsigned int ncap)
+int
+htmodkey(struct htable *ht, void *oldkey, void *newkey)
{
- unsigned int i, tmp;
- Htable *nht; /* new hash table */
- Htnode *n; /* current node */
- Htnode **list; /* list of nodes */
+ return remove_or_replace_key(ht, oldkey, 1, newkey);
+}
- /* create a new hash table */
- nht = htcreate(ht->keylenfn, ht->keycmpfn, ht->freekeyfn, ht->freevalfn, ncap);
- for (i = 0; i < ht->cap; i++) {
- for (n = ht->nodes[i]; n != NULL; n = n->next)
- htinsert(nht, n->key, n->val);
- }
+int
+htmodval(struct htable *ht, void *key, void *newval)
+{
+ return insert_or_replace_val(ht, key, newval, 1);
+}
- /* swap old hash table with new one */
- list = ht->nodes;
- ht->nodes = nht->nodes;
- nht->nodes = list;
+struct htable *
+htresize(struct htable *ht, unsigned int newcap)
+{
+ struct htable *newht;
+ struct htiter it;
- tmp = ht->cap;
- ht->cap = nht->cap;
- nht->cap = tmp;
+ newht = htcreate(ht->hash, ht->key_cmp, ht->key_free, ht->val_free, newcap);
+ if (newht == NULL)
+ return NULL;
- tmp = ht->len;
- ht->len = nht->len;
- nht->len = tmp;
+ htiter_init(&it);
+ while(htiterate(ht, &it)) {
+ if (htinsert(newht, it.node->key, it.node->val) == -1) {
+ htdestroy(newht);
+ return NULL;
+ }
+ }
- /* destroy new(old) hash table */
- __htdestroy(nht, 0);
+ destroy_and_free(ht, 0);
+ return newht;
}
+void
+htiter_init(struct htiter *it)
+{
+ it->index = 0;
+ it->node = NULL;
+}
+
int
-htiterate(Htable *ht, Htiter *it)
+htiterate(struct htable *ht, struct htiter *it)
{
- if (it->index == 0 && it->node == NULL) {
- it->index = 0;
- it->node = ht->nodes[0];
- } else {
+ if (it->node != NULL)
it->node = it->node->next;
- }
- while (it->index < ht->cap) {
- while (it->node != NULL) {
- return 1;
- it->node = it->node->next;
- }
- it->index++;
+ while (it->node == NULL && it->index < ht->cap) {
it->node = ht->nodes[it->index];
+ it->index++;
}
- return 0;
+
+ if (it->node != NULL)
+ return 1;
+ else
+ return 0;
}
--- a/htable.h
+++ b/htable.h
@@ -3,41 +3,48 @@
* See COPYING file for more information.
*/
-typedef struct Htnode Htnode;
-typedef struct Htable Htable;
-typedef struct Htiter Htiter;
+#ifndef HTABLE_H
+#define HTABLE_H
-typedef size_t (KeyLenFn)(const void *key);
-typedef int (KeyCmpFn)(const void *key1, const void *key2);
-typedef void (FreeKeyFn)(void *ptr);
-typedef void (FreeValFn)(void *ptr);
+typedef unsigned int (hash_fn)(void *key, unsigned int cap);
+typedef int (key_cmp_fn)(const void *key1, const void *key2);
+typedef void (key_free_fn)(void *key);
+typedef void (val_free_fn)(void *val);
-struct Htnode {
- void *key; /* key for the node */
- void *val; /* value for the node */
- Htnode *next; /* next node (open hash table) */
+struct htnode {
+ void *key;
+ void *val;
+ struct htnode *next;
};
-struct Htable {
- unsigned int cap; /* capacity */
- unsigned int len; /* length */
- Htnode **nodes; /* list of nodes */
- KeyLenFn *keylenfn; /* key length function */
- KeyCmpFn *keycmpfn; /* key compare function */
- FreeKeyFn *freekeyfn;
- FreeValFn *freevalfn;
+struct htable {
+ struct htnode **nodes;
+ unsigned int cap;
+ unsigned int len;
+ hash_fn *hash;
+ key_cmp_fn *key_cmp;
+ key_free_fn *key_free;
+ val_free_fn *val_free;
};
-struct Htiter {
+struct htiter {
unsigned int index;
- Htnode *node;
+ struct htnode *node;
};
-Htable *htcreate(KeyLenFn *keylenfn, KeyCmpFn *keycmpfn, FreeKeyFn *freekeyfn, FreeValFn *freevalfn, unsigned int cap);
-void htdestroy(Htable *ht);
-void *htsearch(Htable *ht, void *key);
-int htinsert(Htable *ht, void *key, void *val);
-int htremove(Htable *ht, void *key);
-int htsetkey(Htable *ht, void *oldkey, void *newkey);
-void htresize(Htable *ht, unsigned int ncap);
-int htiterate(Htable *ht, Htiter *it);
+struct htable *htcreate(hash_fn *hash,
+ key_cmp_fn *key_cmp,
+ key_free_fn *key_free,
+ val_free_fn *val_free,
+ unsigned int cap);
+void htdestroy(struct htable *ht);
+void *htsearch(struct htable *ht, void *key);
+int htinsert(struct htable *ht, void *key, void *val);
+int htremove(struct htable *ht, void *key);
+int htmodkey(struct htable *ht, void *oldkey, void *newkey);
+int htmodval(struct htable *ht, void *key, void *newval);
+struct htable *htresize(struct htable *ht, unsigned int newcap);
+void htiter_init(struct htiter *it);
+int htiterate(struct htable *ht, struct htiter *it);
+
+#endif /* HTABLE_H */
--- a/main.c
+++ b/main.c
@@ -14,107 +14,91 @@
#ifdef __gnu_linux__
#include <sys/epoll.h>
-#include <bsd/err.h>
-#include <bsd/stdlib.h>
-#include <bsd/string.h>
+char *strlcpy(char *dst, const char *src, size_t n)
+{
+ return strncpy(dst, src, n);
+}
#else
#include <sys/event.h>
#endif
+#define LOG_LEVEL 1
+
#include "htable.h"
#include "util.c"
#define CLONE_COOLDOWN 1
#define CLONE_ADDEND 10
-/* #define PING_TIMEOUT 240 */
-#define EVENT_ADDEND 100
+#define FD_ADDEND 100
#define NET_ADDEND 10
#define USER_ADDEND 100
#define BUFSIZE 1024
#define NICK_LEN 16
-#define MAX_EVENTS 10
+#define HANDLE_EVENTS 10 /* no. of events to handle at a time */
-#define EV_READ 1
-#define EV_WRITE 2
+#define EV_READ 1
+#define EV_WRITE 2
enum {
IDLE = 0,
RESET,
- CLONING
+ CLONING,
+ DONE
};
-struct network {
- int id; /* event index */
- char *name; /* name */
- char *symb; /* symbol */
- char *host; /* host */
- char *port; /* port */
- char *chan; /* channel */
- int ready; /* joined */
+struct vuser {
+ char *user; /* nick */
+ int netid; /* net index */
+ int suffix; /* suffix count */
+ int ready; /* joined */
};
-struct event {
- int fd; /* event fd */
- int netid; /* net index */
- char *user; /* user nick */
- int suffix; /* suffix count */
- time_t time; /* last response */
- int ready; /* joined */
+struct network {
+ int fd; /* fd */
+ char *name; /* name */
+ char *symb; /* symbol */
+ char *host; /* host */
+ char *port; /* port */
+ char *chan; /* channel */
};
+static time_t ntime = -1; /* next timeout */
+static int state = IDLE; /* program state */
+static int fifofd; /* fifo fd */
+static int break_evloop; /* break event loop */
+static char *fifopath; /* fifo path */
+static char msg[BUFSIZE]; /* message buffer */
-static int debug;
-static int done; /* program state */
-static int fifofd; /* fifo fd */
-static char *fifopath; /* fifo path */
-static char msg [BUFSIZE]; /* message buffer */
-static int timeout_id = -1;
-
#ifdef __gnu_linux__
-static int epfd; /* epoll instance */
+static int epfd; /* epoll instance */
#else
-static int kqfd; /* kqueue instance */
+static int kqfd; /* kqueue instance */
#endif
-static int *fdtoid; /* fd to event id */
-static int fdslen; /* maximum fd */
+static struct network *networks; /* networks array */
+static int netlen; /* array length */
+static int netcap; /* array capacity */
+static struct vuser **fdtovuser; /* fd -> vuser pointer */
+static int fdcap; /* fdtovuser capacity */
+static struct htable *usertofds; /* user -> array of fds of clones
+ indexed according to networks array */
-static struct event *events; /* events array */
-static int evslen; /* array length */
-static int evscap; /* array capacity */
-
-static struct network *networks; /* networks array */
-static int netlen; /* array length */
-static int netcap; /* array capacity */
-static int state = IDLE;
-
-/*
- * hash table of users
- * key -> <user_nick> + '[' + <network_symbol> + ']'
- * value -> array of all user's clones event ids indexed
- * corresponding to its connected network
- */
-static struct Htable *users;
-
/* functions prototype */
-
void fd_register(int, int);
void fifo_read(void);
time_t event_timeout(void);
-void event_write(int);
-int event_read(int);
+void fd_write(int);
+void fd_read(int);
void net_add(char *, char *, char *, char *, char *);
-void net_del(char *);
+void net_del(int, char *);
void net_del_raw(int);
-void net_users_add(int, char *);
void user_add(char *, int, int);
void user_del(char *, char *);
-int *user_event_ids(char *, int);
-int clone_add(char *, int);
-int event_add(int, int, char *);
-void event_del(int);
+int vuser_add(int, char *);
+void vuser_del(int, char *);
+int *vuser_get_fds(char *, int);
void nick_add_symb(char *, int);
void privmsg_update(char *, char *, int);
void print_table(void);
@@ -126,76 +110,67 @@
main(int argc, char *argv[])
{
#ifdef __gnu_linux__
- struct epoll_event epevs [MAX_EVENTS]; /* maximum event to handle */
+ struct epoll_event epevs[HANDLE_EVENTS];
#else
- struct kevent kevs [MAX_EVENTS]; /* maximum event to handle */
- struct timespec tmsp;
+ struct kevent kevs[HANDLE_EVENTS];
+ struct timespec tmsp;
#endif
- int i, r, fd, id, nev;
+ int i, fd, *fds, nev; /* no. of returned events to handle */
time_t timeout;
- time_t ntime; /* next timeout time */
+ struct htiter it;
/* set stdout to unbufferd */
setvbuf(stdout, NULL, _IONBF, 0);
- /* check arguments */
- if (argc != 2) {
- printf("usage: %s fifo\n", getprogname());
- return 0;
- } else {
+ /* handle arguments */
+ if (argc != 2)
+ fatal("usage: ticl fifo");
+ else
fifopath = argv[1];
- }
/* init global variables */
- fdslen = evscap = EVENT_ADDEND;
netcap = NET_ADDEND;
- fdtoid = ecalloc((size_t)fdslen, sizeof(int));
- events = ecalloc((size_t)evscap, sizeof(struct event));
- networks = ecalloc((size_t)netcap, sizeof(struct network));
- users = htcreate((KeyLenFn *)strlen, (KeyCmpFn *)strcmp, free, free,
- USER_ADDEND);
+ fdcap = FD_ADDEND;
+ networks = emalloc((size_t)netcap * sizeof(struct network));
+ fdtovuser = emalloc((size_t)fdcap * sizeof(struct vuser *));
+ usertofds = htcreate(hash_str, (key_cmp_fn *)strcmp, free, free,
+ USER_ADDEND);
#ifdef __gnu_linux__
if ((epfd = epoll_create1(0)) == -1)
- err(1, "epoll_create1");
+ fatal("epoll_create1:");
#else
if ((kqfd = kqueue()) == -1)
- err(1, "kqueue");
+ fatal("kqueue:");
#endif
fifofd = fifo_open(fifopath);
fd_register(fifofd, EV_READ);
- ntime = -1;
/* event loop */
- while (!done) {
- if (ntime == -1)
+ while (state != DONE) {
+ if (ntime == -1) {
timeout = -1;
- else if ((timeout = ntime - time(NULL)) < 0)
- timeout = 0;
+ } else {
+ timeout = ntime - time(NULL);
+ if (timeout < 0)
+ timeout = 0;
+ }
#ifdef __gnu_linux__
- if ((nev = epoll_wait(epfd, epevs, MAX_EVENTS,
- (int)timeout * 1000)) == -1)
- err(1, "epoll_wait");
+ nev = epoll_wait(epfd, epevs, HANDLE_EVENTS, (int)timeout * 1000);
+ if (nev == -1)
+ fatal("epoll_wait:");
#else
tmsp.tv_sec = timeout;
tmsp.tv_nsec = 0;
- if ((nev = kevent(kqfd, NULL, 0, kevs, MAX_EVENTS,
- timeout < 0 ? NULL : &tmsp)) == -1)
- err(1, "kevent");
+ nev = kevent(kqfd, NULL, 0, kevs, HANDLE_EVENTS, timeout < 0 ? NULL : &tmsp);
+ if (nev == -1)
+ fatal("kevent:");
#endif
- if (nev == 0) {
+ else if (nev == 0) {
ntime = event_timeout();
continue;
}
- if (debug) {
- printf("fds:");
- for (i = 0; i < nev; i++) {
- printf(" %d", epevs[i].data.fd);
- }
- printf("\n");
- }
-
for (i = 0; i < nev; i++) {
#ifdef __gnu_linux__
fd = epevs[i].data.fd;
@@ -202,94 +177,93 @@
#else
fd = (int)kevs[i].ident;
#endif
- id = fdtoid[fd];
if (fd == fifofd) {
fifo_read();
+ break;
#ifdef __gnu_linux__
} else if (epevs[i].events & EPOLLOUT) {
#else
} else if (kevs[i].filter == EVFILT_WRITE) {
#endif
- event_write(id);
+ fd_write(fd);
#ifdef __gnu_linux__
} else if (epevs[i].events & EPOLLIN) {
#else
} else if (kevs[i].filter == EVFILT_READ) {
#endif
- r = event_read(id);
- if (r == 1) {
- timeout_id = -1;
- ntime = 0;
- } else if (r == -2) {
+ fd_read(fd);
+ if (break_evloop) {
+ break_evloop = FALSE;
break;
}
} else {
- errx(1, "unknown event");
+ fatal("unknown event");
}
}
}
- /*
- * cleanup
- */
- snprintf(msg, sizeof(msg), "QUIT :linker shutting down\r\n");
- for (i = 0; i < evslen; i++) {
- writeall(events[i].fd, msg);
- close(events[i].fd);
+ /* cleanup */
+ snprintf(msg, sizeof(msg), "QUIT :relay shutting down\r\n");
+
+ /* delete and free all the users with their fds */
+ htiter_init(&it);
+ while(htiterate(usertofds, &it)) {
+ fds = (int *)it.node->val;
+ for (i = 0; i < netlen; i++) {
+ if (fds[i] > 0)
+ vuser_del(fds[i], msg);
+ }
}
+ htdestroy(usertofds);
- free(fdtoid);
- free(events);
-
- /* delete all the networks */
- for (i = 0; i < netlen; i++)
+ /* delete and free all the networks with their fd */
+ for (i = 0; i < netlen; i++) {
+ vuser_del(networks[i].fd, msg);
net_del_raw(i);
+ }
free(networks);
- /* delete all the users */
- htdestroy(users);
-
+ free(fdtovuser);
return 0;
}
void
-fd_register(int fd, int type)
+fd_register(int fd, int mode)
{
#ifdef __gnu_linux__
struct epoll_event ev;
- if (type == EV_READ)
+ if (mode == EV_READ)
ev.events = EPOLLIN;
- else if (type == EV_WRITE)
+ else if (mode == EV_WRITE)
ev.events = EPOLLOUT;
else
- errx(1, "unkown event type");
+ fatal("unknown event mode");
ev.data.fd = fd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
- err(1, "epoll_ctl");
+ fatal("epoll_ctl:");
#else
struct kevent ev;
int filter;
- if (type == EV_READ)
+ if (mode == EV_READ)
filter = EVFILT_READ;
- else if (type == EV_WRITE)
+ else if (mode == EV_WRITE)
filter = EVFILT_WRITE;
else
- errx(1, "unkown event type");
+ fatal("unknown event mode");
EV_SET(&ev, fd, filter, EV_ADD, 0, 0, 0);
if (kevent(kqfd, &ev, 1, NULL, 0, NULL) == -1)
- err(1, "kevent");
+ fatal("kevent:");
#endif
- /* printf("added fd: %d\n", fd); */
}
void
fifo_read(void)
{
- char buffer [BUFSIZE];
+ char buffer[BUFSIZE];
char *buf;
char *cmd;
ssize_t n;
@@ -296,7 +270,7 @@
n = readline(fifofd, buffer, sizeof(buffer));
if (n == -1) {
- err(1, "fifo: read");
+ fatal("read:");
} else if (n == 0) {
/* reopen fifo again */
close(fifofd);
@@ -304,8 +278,7 @@
fd_register(fifofd, EV_READ);
return;
}
-
- if (!*buffer)
+ if (*buffer == '\0')
return;
buf = buffer;
@@ -317,15 +290,24 @@
char *port = split(&buf, ' ');
char *chan = buf;
if (!*name || !*symb || !*host || !*port || !*chan)
- printf("usage: netadd <name> <symbol> <host> <port> <channel>\n");
+ warnf("usage: netadd <name> <symbol> <host> <port> <channel>");
else
net_add(name, symb, host, port, chan);
} else if (strcmp(cmd, "netdel") == 0) {
char *name = buf;
- if (!*name)
- printf("usage: netdel <name>\n");
- else
- net_del(name);
+ if (!*name) {
+ warnf("usage: netdel <name>");
+ } else {
+ int i;
+ for (i = 0; i < netlen; i++) {
+ if (strcmp(name, networks[i].name) == 0) {
+ snprintf(msg, sizeof(msg), "QUIT :unlinking %s\r\n", networks[i].name);
+ net_del(i, msg);
+ return;
+ }
+ }
+ warnf("%s: network doesn't exist", name);
+ }
} else if (strcmp(cmd, "print") == 0) {
print_table();
} else if (strcmp(cmd, "htable") == 0) {
@@ -333,9 +315,9 @@
} else if (strcmp(cmd, "users") == 0) {
print_users();
} else if (strcmp(cmd, "exit") == 0) {
- done = TRUE;
+ state = DONE;
} else {
- warnx("%s is not a command", cmd);
+ warnf("%s is not a command", cmd);
}
}
@@ -342,95 +324,64 @@
time_t
event_timeout(void)
{
- static Htiter it = {0};
+ static struct htiter it;
- int i, j, *ids;
- char *nick;
- struct network *n;
- time_t ntime;
+ int i, j, *fds;
+ char *user;
- /* if (timeout_id != -1) {
- printf("%d: PING\n", events[timeout_id].fd);
- snprintf(msg, sizeof(msg), "PING %s\r\n",
- networks[events[timeout_id].netid].host);
- writeall(events[timeout_id].fd, msg);
- events[timeout_id].time = time(NULL);
- } else { */
- if (state == RESET) {
- state = CLONING;
- it.index = 0;
- it.node = NULL;
- }
- printf("Adding %d bot\n", CLONE_ADDEND);
+ if (state == RESET) {
+ state = CLONING;
+ htiter_init(&it);
+ }
+ log1(".");
- j = 0;
- while (htiterate(users, &it)) {
- nick = (char *)it.node->key;
- ids = (int *)it.node->val;
- for (i = 0; i < netlen; i++) {
- n = &networks[i];
- if (!n->ready || ids[i] != 0)
- continue;
- ids[i] = clone_add(nick, i);
- }
- if (++j >= CLONE_ADDEND)
- goto calculate;
+ j = 0;
+ while (htiterate(usertofds, &it)) {
+ user = (char *)it.node->key;
+ fds = (int *)it.node->val;
+ for (i = 0; i < netlen; i++) {
+ if (fds[i] == 0 && fdtovuser[networks[i].fd]->ready)
+ fds[i] = vuser_add(i, user);
}
- state = IDLE;
- it.index = 0;
- it.node = NULL;
- /* } */
-
-calculate:
- ntime = -1;
- timeout_id = -1;
-
- if (state == CLONING)
- ntime = time(NULL) + CLONE_COOLDOWN;
-
- /* for(i = 0; i < evslen; i++) {
- if ((events[i].time != 0)
- && ((ntime == -1) || (events[i].time + PING_TIMEOUT < ntime))) {
- ntime = events[i].time + PING_TIMEOUT;
- timeout_id = i;
- }
- } */
- return ntime;
+ j++;
+ if (j >= CLONE_ADDEND)
+ return time(NULL) + CLONE_COOLDOWN;
+ }
+ state = IDLE;
+ return -1;
}
void
-event_write(int id)
+fd_write(int fd)
{
- int fd = events[id].fd;
#ifdef __gnu_linux__
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = fd;
if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) == -1)
- err(1, "epoll_ctl");
+ fatal("epoll_ctl:");
#else
struct kevent ev;
EV_SET(&ev, fd, EV_WRITE, EV_DISABLE, 0, 0, 0);
if (kevent(kqfd, &ev, 1, NULL, 0, NULL) == -1)
- err(1, "kevent");
+ fatal("kevent:");
fd_register(fd, EV_READ);
#endif
- if (events[id].user == NULL) { /* linker */
+ if (fdtovuser[fd]->user == NULL) { /* linker */
snprintf(msg, sizeof(msg), "NICK linker\r\n");
writeall(fd, msg);
snprintf(msg, sizeof(msg), "USER linker 0 * :linker\r\n");
writeall(fd, msg);
} else { /* user */
- snprintf(msg, sizeof(msg), "NICK %s\r\n", events[id].user);
+ snprintf(msg, sizeof(msg), "NICK %s\r\n", fdtovuser[fd]->user);
writeall(fd, msg);
snprintf(msg, sizeof(msg), "USER user 0 * :user\r\n");
writeall(fd, msg);
}
- events[id].time = time(NULL);
}
-int
-event_read(int id)
+void
+fd_read(int fd)
{
char buffer [BUFSIZE];
char backup [BUFSIZE];
@@ -438,47 +389,43 @@
char *buf;
char *cmd;
char *nick;
- int i, fd, netid;
+ int i, netid;
ssize_t n;
- fd = events[id].fd;
- netid = events[id].netid;
- events[id].time = time(NULL);
+ netid = fdtovuser[fd]->netid;
n = readline(fd, buffer, sizeof(buffer));
if (n == -1) {
- warn("%d: read", fd);
- event_del(id);
- return 0;
+ warnf("%d: read:", fd);
+ snprintf(msg, sizeof(msg), "QUIT :read failed\r\n");
+ goto del;
} else if (n == 0) {
- warnx("%d: connection closed", fd);
- event_del(id);
- return 0;
+ warnf("%d: connection closed", fd);
+ snprintf(msg, sizeof(msg), "QUIT :connection closed\r\n");
+ goto del;
}
+ if (*buffer == '\0')
+ return;
- if (!*buffer)
- return 0;
-
/* clone the buffer */
- strlcpy(backup, buffer, sizeof(buffer));
+ strlcpy(backup, buffer, sizeof(backup));
buf = buffer;
/* set linker nick */
strlcpy(lnick, "linker", sizeof(lnick));
- for (i = 0; i < events[id].suffix; i++)
+ for (i = 0; i < fdtovuser[fd]->suffix; i++)
strcat(lnick, "_");
/* first column */
cmd = split(&buf, ' ');
- if (strcmp(cmd, "NOTICE") == 0) {
- return 0;
+ if (strcmp(cmd, "NOTICE") == 0) { /* ignore */
+ return;
} else if (strcmp(cmd, "ERROR") == 0) {
- event_del(id);
- goto printbuffer;
+ fatal("%d: %s", fd, backup);
} else if (strcmp(cmd, "PING") == 0) {
snprintf(msg, sizeof(msg), "PONG %s\r\n", buf);
writeall(fd, msg);
- return 0;
+ return;
}
/* strip nick from first column */
nick = split(&cmd, '!');
@@ -489,70 +436,65 @@
cmd = split(&buf, ' ');
/* ignore all the info messages */
- if ((strcmp(cmd, "002") == 0)
- || (strcmp(cmd, "003") == 0)
- || (strcmp(cmd, "004") == 0)
- || (strcmp(cmd, "005") == 0)
- || (strcmp(cmd, "003") == 0)
- || (strcmp(cmd, "251") == 0)
- || (strcmp(cmd, "252") == 0)
- || (strcmp(cmd, "253") == 0) /* unknown connection(s) */
- || (strcmp(cmd, "254") == 0)
- || (strcmp(cmd, "255") == 0)
- || (strcmp(cmd, "265") == 0)
- || (strcmp(cmd, "266") == 0)
- || (strcmp(cmd, "250") == 0)
- || (strcmp(cmd, "332") == 0)
- || (strcmp(cmd, "333") == 0)
- || (strcmp(cmd, "375") == 0)
- || (strcmp(cmd, "372") == 0)
- || (strcmp(cmd, "376") == 0)
- || (strcmp(cmd, "396") == 0)
- || (strcmp(cmd, "366") == 0)
- || (strcmp(cmd, "MODE") == 0)
- || (strcmp(cmd, "TOPIC") == 0)
- || (strcmp(cmd, "NOTICE") == 0)) {
- return 0;
+ if ((strcmp(cmd, "002") == 0) ||
+ (strcmp(cmd, "003") == 0) ||
+ (strcmp(cmd, "004") == 0) ||
+ (strcmp(cmd, "005") == 0) ||
+ (strcmp(cmd, "003") == 0) ||
+ (strcmp(cmd, "251") == 0) ||
+ (strcmp(cmd, "252") == 0) ||
+ (strcmp(cmd, "253") == 0) || /* unknown connection(s) */
+ (strcmp(cmd, "254") == 0) ||
+ (strcmp(cmd, "255") == 0) ||
+ (strcmp(cmd, "265") == 0) ||
+ (strcmp(cmd, "266") == 0) ||
+ (strcmp(cmd, "250") == 0) ||
+ (strcmp(cmd, "332") == 0) ||
+ (strcmp(cmd, "333") == 0) ||
+ (strcmp(cmd, "375") == 0) ||
+ (strcmp(cmd, "372") == 0) ||
+ (strcmp(cmd, "376") == 0) ||
+ (strcmp(cmd, "396") == 0) ||
+ (strcmp(cmd, "366") == 0) ||
+ (strcmp(cmd, "MODE") == 0) ||
+ (strcmp(cmd, "TOPIC") == 0) ||
+ (strcmp(cmd, "NOTICE") == 0)) {
+ return;
} else if (strcmp(cmd, "432") == 0) { /* Erroneous Nickname */
- event_del(id);
- goto printbuffer;
+ fatal("%d: %s", fd, backup);
} else if (strcmp(cmd, "433") == 0) { /* Nickname already in use */
split(&buf, ' ');
nick = split(&buf, ' ');
strcat(nick, "_");
- events[id].suffix++;
+ fdtovuser[fd]->suffix++;
if (strlen(nick) > NICK_LEN) {
- warnx("nick '%s' is too big", nick);
- if (strcmp(nick, lnick) == 0) {
- net_del(networks[netid].name);
- } else {
- snprintf(msg, sizeof(msg), "QUIT :nick is too big\r\n");
- user_del(nick, msg);
- }
+ warnf("%s: nickname too long", nick);
+ snprintf(msg, sizeof(msg), "QUIT :%s: nickname too long\r\n", nick);
+ goto del;
} else {
snprintf(msg, sizeof(msg), "NICK %s\r\n", nick);
writeall(fd, msg);
}
- return 0;
+ return;
} else if (strcmp(cmd, "001") == 0) {
snprintf(msg, sizeof(msg), "JOIN %s\r\n", networks[netid].chan);
writeall(fd, msg);
- return 0;
+ return;
} else if (strcmp(cmd, "PRIVMSG") == 0) {
- char privmsg [BUFSIZE] = "";
- int *ids;
+ char privmsg[BUFSIZE] = "";
+ int *fds;
- if (events[id].user == NULL) { /* if linker */
+ if (fdtovuser[fd]->user == NULL) { /* if linker */
nick_add_symb(nick, netid);
- if ((ids = htsearch(users, nick)) == NULL)
- return 0;
+ if ((fds = htsearch(usertofds, nick)) == NULL)
+ return;
split(&buf, ':'); /* set buf to msg */
privmsg_update(privmsg, buf, netid);
for (i = 0; i < netlen; i++) {
- if (ids[i] > 0) {
+ if (fds[i] > 0) {
snprintf(msg, sizeof(msg), "PRIVMSG %s :%s\r\n", networks[i].chan, privmsg);
- writeall(events[ids[i]].fd, msg);
+ writeall(fds[i], msg);
}
}
} else {
@@ -560,12 +502,12 @@
char *user = split(&buf, ' ');
/* ignore messages from channel (it is handled by linker) */
- if ((user[0] == '#') || (user[0] == '&'))
- return 0;
+ if (user[0] == '#' || user[0] == '&')
+ return;
nick_add_symb(nick, netid);
- if ((ids = htsearch(users, nick)) == NULL)
- return 0;
+ if ((fds = htsearch(usertofds, nick)) == NULL)
+ return;
/* split user nick and network symbol */
*strrchr(user, ']') = '\0';
@@ -581,127 +523,137 @@
split(&buf, ':'); /* set buf to msg */
privmsg_update(privmsg, buf, netid);
snprintf(msg, sizeof(msg), "PRIVMSG %s :%s\r\n", user, privmsg);
- writeall(events[ids[i]].fd, msg);
+ writeall(fds[i], msg);
}
- return 0;
+ return;
}
+ else if (strcmp(cmd, "353") == 0) {
+ fdtovuser[fd]->ready = TRUE;
+ /* FALLBACK */
+ }
/* these messages are handled by linker */
- if (events[id].user != NULL) { /* if clone */
- if (strcmp(cmd, "353") == 0) {
- events[id].ready = TRUE;
- return 0;
- } else if ((strcmp(cmd, "JOIN") == 0)
- || (strcmp(cmd, "QUIT") == 0)
- || (strcmp(cmd, "PART") == 0)
- || (strcmp(cmd, "KICK") == 0)
- || (strcmp(cmd, "NICK") == 0)) {
- return 0;
+ if (fdtovuser[fd]->user != NULL) { /* if clone */
+ if ((strcmp(cmd, "353") == 0) ||
+ (strcmp(cmd, "JOIN") == 0) ||
+ (strcmp(cmd, "QUIT") == 0) ||
+ (strcmp(cmd, "PART") == 0) ||
+ (strcmp(cmd, "KICK") == 0) ||
+ (strcmp(cmd, "NICK") == 0)) {
+ return;
}
} else if (strcmp(cmd, "353") == 0) {
char *nick;
split(&buf, ':');
- networks[netid].ready = TRUE;
state = RESET;
+ ntime = 0;
/* then add all new users */
while (*(nick = split(&buf, ' ')) != '\0') {
- if (*nick == '@'
- || *nick == '&'
- || *nick == '~'
- || *nick == '%'
- || *nick == '+'
- || *nick == '\\')
+ if (*nick == '@' ||
+ *nick == '&' ||
+ *nick == '~' ||
+ *nick == '%' ||
+ *nick == '+' ||
+ *nick == '\\')
nick++;
if (strcmp(nick, lnick) != 0)
user_add(nick, netid, FALSE);
}
- return 1;
+ return;
} else if (strcmp(cmd, "JOIN") == 0) {
- if ((strcmp(nick, lnick) != 0)
- && (user_event_ids(nick, netid) == NULL)) { /* if not clone */
+ /* if real user */
+ if ((strcmp(nick, lnick) != 0) &&
+ (vuser_get_fds(nick, netid) == NULL)) {
if (state != IDLE)
- warnx("ignoring user '%s' due to network cloning", nick);
+ warnf("%s: ignored (network cloning)", nick);
else
user_add(nick, netid, TRUE);
}
- return 0;
- } else if ((strcmp(cmd, "QUIT") == 0)
- || (strcmp(cmd, "PART") == 0)) {
+ return;
+ } else if ((strcmp(cmd, "QUIT") == 0) || (strcmp(cmd, "PART") == 0)) {
+ split(&buf, ':'); /* ignore ':' and assign QUIT/PART msg to buf */
snprintf(msg, sizeof(msg), "QUIT :%s\r\n", buf);
nick_add_symb(nick, netid);
- if (htsearch(users, nick) != NULL)
+ if (htsearch(usertofds, nick) != NULL) {
user_del(nick, msg);
- return -2;
+ break_evloop = TRUE;
+ return;
+ }
+ return;
} else if (strcmp(cmd, "NICK") == 0) {
- int *ids, i;
+ int *fds, i;
char *newnick;
nick_add_symb(nick, netid);
- if ((ids = htsearch(users, nick)) == NULL)
- return 0;
+ if ((fds = htsearch(usertofds, nick)) == NULL)
+ return;
/* set buf to new nick */
split(&buf, ':');
- /* allocate a newnick and append the netsym and then replace the old */
- newnick = ecalloc(strlen(buf) + strlen(networks[netid].symb) + 2 + 1, sizeof(char));
+ /* allocate a new nick with net symbol and replace the old one */
+ newnick = emalloc((strlen(buf) + strlen(networks[netid].symb) + 2 + 1) * sizeof(char));
sprintf(newnick, "%s[%s]", buf, networks[netid].symb);
- htsetkey(users, nick, newnick);
-
+ htmodkey(usertofds, nick, newnick);
snprintf(msg, sizeof(msg), "NICK %s\r\n", newnick);
for (i = 0; i < netlen; i++) {
- events[ids[i]].user = newnick;
- if (ids[i] > 0)
- writeall(events[ids[i]].fd, msg);
+ if (fds[i] > 0) {
+ fdtovuser[fds[i]]->user = newnick;
+ writeall(fds[i], msg);
+ }
}
- return 0;
+ return;
} else if (strcmp(cmd, "KICK") == 0) {
- /* :<nick_which_is_kicking>!~user@host KICK <channel> <nick_which_has_been_kicked> :<kick_msg> */
- int *ids;
- char *chan = split(&buf, ' ');
- char *user = split(&buf, ' ');
+ /* :<user_who_kicked>!~username@host KICK <channel> <user_who_is_being_kicked> :<kick_msg> */
+ int *fds;
+ char *user;
- /* set the quit msg */
- snprintf(msg, sizeof(msg), "QUIT : kicked by %s\r\n", nick);
+ split(&buf, ' '); /* channel name */
+ user = split(&buf, ' '); /* user who is being kicked */
+ split(&buf, ':'); /* ignore ':' and store reason to buf */
- /* delete whole network if it is the linker */
+ /* if linker is being kicked, delete the network */
if (strcmp(user, lnick) == 0) {
- net_del(networks[netid].name);
- return 0;
+ snprintf(msg, sizeof(msg), "QUIT :netdel: %s (%s is kicked by %s)\r\n",
+ networks[netid].name, lnick, nick);
+ net_del(netid, msg);
+ break_evloop = TRUE;
+ return;
}
- /* delete the user if the message from the same network */
- if ((ids = user_event_ids(user, netid)) == NULL) {
+ /* if message is from a real user, delete the user */
+ if ((fds = vuser_get_fds(user, netid)) == NULL) {
+ snprintf(msg, sizeof(msg), "QUIT :userdel: %s (kicked by %s)\r\n", user, nick);
nick_add_symb(user, netid);
user_del(user, msg);
- return 0;
+ break_evloop = TRUE;
+ return;
}
- /* close the kicked fd */
- writeall(fd, msg);
- event_del(id);
+ /* delete the kicked clone */
+ snprintf(msg, sizeof(msg), "QUIT :kicked by %s\r\n", nick);
+ vuser_del(fds[netid], msg);
- /*
- * send notice in the channel through linker
- */
/* get the original user netid */
for (i = 0; i < netlen; i++) {
- if (ids[i] == -1)
+ if (fds[i] == -1)
break;
}
- /* set buf to msg */
- split(&buf, ':');
- /* remove netsymb and suffix */
- *strrchr(user, '[') = '\0';
- /* send notice */
- snprintf(msg, sizeof(msg),
- "PRIVMSG %s :%s was kicked out by %s from network %s %s [%s]\r\n",
- networks[i].chan, user, nick, networks[netid].name, chan, buf);
- writeall(events[networks[i].id].fd, msg);
- return 0;
+ /* send notice in the channel through linker */
+ snprintf(msg, sizeof(msg), "PRIVMSG %s :%s is kicked by %s [%s]\r\n",
+ networks[i].chan, user, nick, buf);
+ writeall(networks[i].fd, msg);
+ break_evloop = TRUE;
+ return;
}
-printbuffer:
- printf("%d: %s\n", fd, backup);
- return 0;
+ warnf("%d: %s", fd, backup);
+ return;
+del:
+ if (fdtovuser[fd]->user == NULL)
+ net_del(netid, msg);
+ else
+ vuser_del(fd, msg);
+ break_evloop = TRUE;
+ return;
}
void
@@ -708,110 +660,84 @@
net_add(char *name, char *symb, char *host, char *port, char *chan)
{
struct network *n;
- int i, fd;
+ int i;
- /* if name, symbol or configuration already exists */
for (i = 0; i < netlen; i++) {
if (strcmp(networks[i].name, name) == 0) {
- warnx("network name '%s' already exists", name);
+ warnf("%s: network name already exists", name);
return;
}
if (strcmp(networks[i].symb, symb) == 0) {
- warnx("network symbol '%s' already exists", symb);
+ warnf("%s: network symbol already exists", symb);
return;
}
- if ((strcmp(networks[i].host, host) == 0)
- && (strcmp(networks[i].port, port) == 0)
- && (strcmp(networks[i].chan, chan) == 0)) {
- warnx("network configuration already exists");
+ if ((strcmp(networks[i].host, host) == 0) &&
+ (strcmp(networks[i].port, port) == 0) &&
+ (strcmp(networks[i].chan, chan) == 0)) {
+ warnf("%s:%s%s: network configuration already exists",
+ host, port, chan);
return;
}
}
- /* resize if full */
+ /* if full, resize the network and user fds */
if (netlen == netcap) {
- Htiter it = {0};
- networks = realloc0(networks, sizeof(struct network) * (size_t)netcap,
- sizeof(struct network) * (size_t)(netcap + NET_ADDEND));
- while (htiterate(users, &it))
- it.node->val = realloc0(it.node->val, sizeof(int) * (size_t)netcap,
- sizeof(int) * (size_t)(netcap + NET_ADDEND));
+ struct htiter it;
+ htiter_init(&it);
+
+ networks = erealloc(networks, (size_t)(netcap + NET_ADDEND) *
+ sizeof(struct network));
+ while (htiterate(usertofds, &it)) {
+ it.node->val = erealloc(it.node->val,
+ (size_t)(netcap + NET_ADDEND) *
+ sizeof(int));
+ /* zero out the extended array */
+ for (i = netcap; i < netcap + NET_ADDEND; i++)
+ ((int *)it.node->val)[i] = 0;
+ }
netcap += NET_ADDEND;
}
- /* connect */
- if ((fd = dial(host, port)) == -1)
- return;
/* add a network */
n = &networks[netlen];
- n->id = event_add(fd, netlen, NULL);
n->name = strdup(name);
n->symb = strdup(symb);
n->host = strdup(host);
n->port = strdup(port);
n->chan = strdup(chan);
- n->ready = FALSE;
+ n->fd = vuser_add(netlen, NULL);
netlen++;
-
- printf("%d: network '%s' added\n", fd, name);
}
void
-net_del(char *name)
+net_del(int netid, char *msg)
{
- int i, netid, *ids;
+ int *fds;
+ struct htiter lit, it; /* last, current iterator */
- Htiter it = {0}; /* current iterator */
- Htiter lastit = {0}; /* last iterator */
-
- /* get netid */
- netid = -1;
- for (i = 0; i < netlen; i++) {
- if (strcmp(name, networks[i].name) == 0) {
- netid = i;
- break;
- }
- }
- if (netid == -1) {
- warnx("network '%s' doesn't exist", name);
- return;
- }
-
- /* set the quit msg */
- snprintf(msg, sizeof(msg), "QUIT :unlinking network %s\r\n", name);
-
- /* reconstruct the user-clones table */
- while (htiterate(users, &it)) {
- ids = (int *)it.node->val;
- /* delete all the users of deleting network */
- if (ids[netid] == -1) {
+ htiter_init(&it);
+ htiter_init(&lit);
+ while (htiterate(usertofds, &it)) {
+ fds = (int *)it.node->val;
+ if (fds[netid] == -1) {
user_del(it.node->key, msg);
- /* this node is deleted */
- it = lastit;
- /* delete the clones */
+ it = lit; /* this node is deleted */
} else {
- if (ids[netid] > 0) {
- writeall(events[ids[netid]].fd, msg);
- event_del(ids[netid]);
- }
- /* swap last with current one */
- ids[netid] = ids[netlen-1];
+ if (fds[netid] > 0)
+ vuser_del(fds[netid], msg);
+ fds[netid] = fds[netlen-1];
+ if (fds[netid] > 0)
+ fdtovuser[fds[netid]]->netid = netid;
+ fds[netlen-1] = 0;
}
- lastit = it;
+ lit = it;
}
- /* set last netid of events to current netid. */
- for (i = 0; i < evslen; i++) {
- if (events[i].netid == netlen-1)
- events[i].netid = netid;
- }
-
- writeall(events[networks[netid].id].fd, msg);
- event_del(networks[netid].id);
+ vuser_del(networks[netid].fd, msg);
net_del_raw(netid);
- printf("%d: network '%s' deleted\n", events[networks[netid].id].fd, name);
- /* swap the network with the last */
networks[netid] = networks[netlen-1];
+ if (networks[netid].fd > 0)
+ fdtovuser[networks[netid].fd]->netid = netid;
netlen--;
}
@@ -831,161 +757,132 @@
{
size_t len;
char *nick;
- int *ids, i;
+ int *fds;
len = strlen(unick) + strlen(networks[netid].symb) + 2 + 1;
-
- /* too long nick */
if (len-1 > NICK_LEN) {
- warnx("nick '%s' is too big", unick);
+ warnf("%s[%s]: nickname too long", unick, networks[netid].symb);
return;
}
/* resize hash table if storage is low */
- if ((users->cap - users->len) < USER_ADDEND)
- htresize(users, users->cap + USER_ADDEND);
+ if ((usertofds->cap - usertofds->len) < USER_ADDEND)
+ usertofds = htresize(usertofds, usertofds->cap + USER_ADDEND);
/* allocate a new user */
- nick = ecalloc(len, sizeof(char));
- ids = ecalloc((size_t)netcap, sizeof(int));
+ nick = emalloc(len * sizeof(char));
+ fds = ecalloc((size_t)netcap, sizeof(int));
sprintf(nick, "%s[%s]", unick, networks[netid].symb);
- ids[netid] = -1;
+ fds[netid] = -1;
- if (debug)
- printf("useradd: %s\n", nick);
-
if (clone) {
- /* clone the user on all other network */
+ int i;
for (i = 0; i < netlen; i++) {
- if (networks[i].ready && i != netid)
- ids[i] = clone_add(nick, i);
+ if (fds[i] == 0 && fdtovuser[networks[i].fd]->ready)
+ fds[i] = vuser_add(i, nick);
}
}
- /* insert it to the users hash table */
- if (htinsert(users, nick, ids) == -1)
- /* this shouldn't happen as it was already checked */
- errx(1, "user '%s' already exists", nick);
+ if (htinsert(usertofds, nick, fds) == -1)
+ fatal("%s: user already exists", nick);
}
void
user_del(char *nick, char *msg)
{
- int i, *ids;
+ int i, *fds;
- if ((ids = htsearch(users, nick)) == NULL)
- errx(1, "user '%s' 1 doesn't exists", nick);
+ if ((fds = htsearch(usertofds, nick)) == NULL)
+ fatal("%s: user doesn't exist", nick);
for (i = 0; i < netlen; i++) {
- if (ids[i] <= 0)
- continue;
- printf("%d: del[%s]: %s\n", events[ids[i]].fd,
- networks[i].symb, nick);
-
- if (events[ids[i]].ready)
- writeall(events[ids[i]].fd, msg);
- event_del(ids[i]);
+ if (fds[i] > 0)
+ vuser_del(fds[i], msg);
}
- htremove(users, nick);
+ htremove(usertofds, nick);
}
-int *
-user_event_ids(char *nick, int netid)
-{
- unsigned int s;
- int *ids = NULL;
-
- /* count suffix */
- for (s = 0; nick[strlen(nick)-s-1] == '_'; s++);
- /* remove suffix */
- if (s > 0)
- nick[strlen(nick)-s] = '\0';
-
- ids = htsearch(users, nick);
- /* if match but suffix doesn't match */
- if ((ids != NULL) && (events[ids[netid]].suffix != (int)s))
- ids = NULL;
-
- /* add suffix back */
- if (s > 0)
- nick[strlen(nick)] = '_';
-
- return ids;
-}
-
int
-clone_add(char *nick, int netid)
+vuser_add(int netid, char *user)
{
- struct network *n;
- int fd;
+ int fd;
+ struct network *n;
+ struct vuser *vuser;
n = &networks[netid];
- if ((fd = dial(n->host, n->port)) == -1) {
- warn("enable to connect to %s\n", n->host);
- return -1;
+ fd = dial(n->host, n->port);
+ if (fd == -1) {
+ warnf("%s:%s: failed to connect", n->host, n->port);
+ return -2;
}
- printf("%d: add[%s]: %s\n", fd, n->symb, nick);
- return event_add(fd, netid, nick);
-}
+ fd_register(fd, EV_WRITE);
-int
-event_add(int fd, int netid, char *user)
-{
- int i = evslen;
+ if (user == NULL)
+ log1("%d: netadd: %s[%s]", fd, n->name, n->symb);
+ else
+ log1("%d: add[%s]: %s", fd, n->symb, user);
- if (evslen == evscap) {
- events = realloc0(events, sizeof(struct event) * (size_t)evscap,
- sizeof(struct event) * (size_t)(evscap + EVENT_ADDEND));
- evscap += EVENT_ADDEND;
+ if (fd+1 > fdcap) {
+ fdcap *= 2;
+ fdtovuser = erealloc(fdtovuser, (size_t)fdcap * sizeof(struct vuser *));
}
- events[i].fd = fd;
- events[i].netid = netid;
- events[i].user = user;
- events[i].suffix = 0;
- events[i].time = 0;
- events[i].ready = FALSE;
+ vuser = emalloc(1 * sizeof(struct vuser));
+ vuser->netid = netid;
+ vuser->user = user;
+ vuser->suffix = 0;
+ vuser->ready = FALSE;
- fd_register(fd, EV_WRITE);
+ fdtovuser[fd] = vuser;
- if (fd == fdslen - 1) {
- fdtoid = realloc0(fdtoid, sizeof(int) * (size_t)fdslen,
- sizeof(int) * (size_t)fdslen * 2);
- fdslen *= 2;
- }
- fdtoid[fd] = i;
-
- return evslen++;
+ return fd;
}
void
-event_del(int id)
+vuser_del(int fd, char *msg)
{
- int *ids;
- int l = evslen - 1; /* last id */
+ char *user = fdtovuser[fd]->user;
+ int netid = fdtovuser[fd]->netid;
+ int *fds;
- /* swap id */
- if (events[l].user == NULL) { /* if linker */
- networks[events[l].netid].id = id;
- } else { /* else user */
- if ((ids = htsearch(users, events[l].user)) == NULL)
- errx(1, "user '%s' 2 doesn't exists", events[l].user);
- ids[events[l].netid] = id;
+ if (user == NULL) {
+ log1("%d: netdel: %s[%s]", fd, networks[netid].name, networks[netid].symb);
+ networks[netid].fd = -2;
+ } else {
+ log1("%d: del[%s]: %s", fd, networks[netid].symb, user);
+ if ((fds = htsearch(usertofds, user)) == NULL)
+ fatal("%s: user doesn't exist", user);
+ fds[netid] = -2;
}
- /* disable id */
- if (events[id].user == NULL) { /* if linker */
- networks[events[id].netid].id = -2;
- } else { /* else user */
- if ((ids = htsearch(users, events[id].user)) == NULL)
- errx(1, "user '%s' 3 doesn't exists", events[id].user);
- ids[events[id].netid] = -2;
- }
+ if (fdtovuser[fd]->ready)
+ writeall(fd, msg);
+ close(fd);
+ free(fdtovuser[fd]);
+ fdtovuser[fd] = NULL;
+}
- close(events[id].fd);
+int *
+vuser_get_fds(char *nick, int netid)
+{
+ unsigned int s;
+ int *fds = NULL;
- events[id] = events[l];
- evslen--;
- fdtoid[events[id].fd] = id;
+ /* count suffix */
+ for (s = 0; nick[strlen(nick)-s-1] == '_'; s++);
+ /* remove suffix */
+ if (s > 0)
+ nick[strlen(nick)-s] = '\0';
+
+ fds = htsearch(usertofds, nick);
+ /* if match but suffix doesn't match */
+ if ((fds != NULL) && (fdtovuser[fds[netid]]->suffix != (int)s))
+ fds = NULL;
+
+ /* add suffix back */
+ if (s > 0)
+ nick[strlen(nick)] = '_';
+
+ return fds;
}
void
@@ -1017,7 +914,7 @@
}
/* check if the word is nick */
- if (user_event_ids(src, netid) != NULL)
+ if (vuser_get_fds(src, netid) != NULL)
*strrchr(src, '[') = '\0';
strcat(dst, src);
@@ -1030,9 +927,9 @@
void
print_table(void)
{
- int i, *ids, diff, tabs;
- Htiter it = {0};
+ int i, *fds, diff, tabs;
char *nick;
+ struct htiter it;
if (netlen == 0)
return;
@@ -1039,13 +936,20 @@
print_border();
/* print networks */
- printf("struct networks\t\t");
- for (i = 0; i < netlen; i++)
- printf("%s(%d)\t", networks[i].symb, events[networks[i].id].fd);
+ printf("Networks\t\t");
+ for (i = 0; i < netlen; i++) {
+ printf("%s->%d", networks[i].symb, networks[i].fd);
+ /* print suffix */
+ if (fdtovuser[networks[i].fd]->suffix > 0)
+ printf("(%d)\t", fdtovuser[networks[i].fd]->suffix);
+ else
+ printf("\t\t");
+ }
printf("\n");
- while (htiterate(users, &it)) {
- ids = (int *)it.node->val;
+ htiter_init(&it);
+ while (htiterate(usertofds, &it)) {
+ fds = (int *)it.node->val;
nick = (char *)it.node->key;
/* print tabbed user nick */
printf("%s", nick);
@@ -1052,13 +956,13 @@
diff = 24 - (int)strlen(nick);
tabs = ((diff / 8) + (diff % 8 > 0));
printf("%.*s", tabs, "\t\t\t");
- /* print tabbed clones ids */
+ /* print tabbed fds */
for (i = 0; i < netlen; i++) {
- printf("%d", ids[i]);
+ printf("%d", fds[i]);
/* print suffix */
- if ((ids[i] > 0) && (events[ids[i]].suffix > 0))
- printf("(%d)", events[ids[i]].suffix);
- printf("\t");
+ if ((fds[i] > 0) && (fdtovuser[fds[i]]->suffix > 0))
+ printf("(%d)", fdtovuser[fds[i]]->suffix);
+ printf("\t\t");
}
printf("\n");
}
@@ -1068,16 +972,17 @@
void
print_htable(void)
{
- Htiter it = {0};
- int index = -1;
+ struct htiter it;
+ int index = -1;
print_border();
- while (htiterate(users, &it)) {
+ htiter_init(&it);
+ while (htiterate(usertofds, &it)) {
if (index != (int)it.index) {
/* ignore first new line */
if (index != -1)
printf("\n");
- printf("%d", it.index);
+ printf("%d", it.index-1);
index = (int)it.index;
}
printf(" -> %s", (char *)it.node->key);
@@ -1089,11 +994,12 @@
void
print_users(void)
{
- Htiter it = {0};
+ struct htiter it;
int i = 0;
print_border();
- while (htiterate(users, &it))
+ htiter_init(&it);
+ while (htiterate(usertofds, &it))
printf("%d: %s\n", i++, (char *)it.node->key);
print_border();
}
--- a/util.c
+++ b/util.c
@@ -9,45 +9,103 @@
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#ifdef __gnu_linux__
-#include <bsd/err.h>
-#else
-#include <err.h>
-#endif
+#define FALSE 0
+#define TRUE 1
-#define FALSE 0
-#define TRUE 1
+void
+print_log(int level, FILE *stream, const char *fmt, va_list arg)
+{
+ size_t len;
-/*
- * ecalloc - calloc with error handling
- */
+ if (level > LOG_LEVEL)
+ return;
+
+ vfprintf(stream, fmt, arg);
+ len = strlen(fmt);
+ if (len && fmt[len-1] == ':')
+ fprintf(stream, " %s\n", strerror(errno));
+ else
+ fprintf(stream, "\n");
+}
+
+void
+log1(const char *fmt, ...)
+{
+ va_list arg;
+ va_start(arg, fmt);
+ print_log(1, stdout, fmt, arg);
+ va_end(arg);
+}
+
+void
+log2(const char *fmt, ...)
+{
+ va_list arg;
+ va_start(arg, fmt);
+ print_log(2, stdout, fmt, arg);
+ va_end(arg);
+}
+
+void
+log3(const char *fmt, ...)
+{
+ va_list arg;
+ va_start(arg, fmt);
+ print_log(3, stdout, fmt, arg);
+ va_end(arg);
+}
+
+void
+warnf(const char *fmt, ...)
+{
+ va_list arg;
+ fprintf(stderr, "warn: ");
+ va_start(arg, fmt);
+ print_log(0, stderr, fmt, arg);
+ va_end(arg);
+}
+
+void
+fatal(const char *fmt, ...)
+{
+ va_list arg;
+ fprintf(stderr, "error: ");
+ va_start(arg, fmt);
+ print_log(0, stderr, fmt, arg);
+ va_end(arg);
+ exit(1);
+}
+
void *
+emalloc(size_t size)
+{
+ void *p;
+ if ((p = malloc(size)) == NULL)
+ fatal("malloc:");
+ return p;
+}
+
+void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if ((p = calloc(nmemb, size)) == NULL)
- err(1, "calloc");
+ fatal("calloc:");
return p;
}
-/*
- * realloc0 -- allocate more memory and zero new memory
- * ptr - pointer of the old memory
- * osize - size of old memory
- * nsize - size to new memory
- */
void *
-realloc0(void *ptr, size_t osize, size_t nsize)
+erealloc(void *ptr, size_t size)
{
void *p;
- if ((p = realloc(ptr, nsize)) == NULL)
- err(1, "realloc");
- memset(((char *)p + osize), 0, nsize - osize);
+ if ((p = realloc(ptr, size)) == NULL)
+ fatal("realloc:");
return p;
}
@@ -70,42 +128,6 @@
}
int
-fifo_open(char *path)
-{
- struct stat st;
- int fd;
-
- /* make fifo if it doesn't exists */
- if (lstat(path, &st) != -1) {
- if (!(st.st_mode & S_IFIFO))
- errx(1, "'%s' is not a fifo file", path);
- } else if (mkfifo(path, S_IRWXU) == -1) {
- err(1, "mkfifo: %s", path);
- }
-
- fd = open(path, O_RDONLY | O_NONBLOCK, 0);
- if (fd == -1)
- err(1, "open: %s", path);
-
- return fd;
-}
-
-ssize_t
-writeall(int fd, char *buf)
-{
- ssize_t left, sent, n;
- left = (ssize_t)strlen(buf);
- sent = 0;
- while (sent < left) {
- if ((n = write(fd, buf+sent, (size_t)left)) == -1)
- err(1, "%d: write", fd);
- sent += n;
- left -= n;
- }
- return sent;
-}
-
-int
dial(char *host, char *port)
{
static struct addrinfo hints, *res = NULL, *res0;
@@ -116,32 +138,54 @@
hints.ai_socktype = SOCK_STREAM;
if ((r = getaddrinfo(host, port, &hints, &res0)) != 0) {
- warnx("getaddrinfo: %s", gai_strerror(r));
+ warnf("getaddrinfo: %s", gai_strerror(r));
return -1;
}
for (res = res0; res != NULL; res = res->ai_next) {
- if ((fd = socket(res->ai_family, res->ai_socktype,
- res->ai_protocol)) == -1)
+ fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (fd == -1) {
+ warnf("socket:");
continue;
+ }
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
- warn("fnctl");
+ warnf("fnctl:");
continue;
}
- if ((connect(fd, res->ai_addr, res->ai_addrlen) == -1)
- && (errno == EINPROGRESS))
+ if ((connect(fd, res->ai_addr, res->ai_addrlen) == -1) &&
+ (errno == EINPROGRESS))
break;
-
- warn("connect");
+ warnf("connect:");
close(fd);
fd = -1;
}
if (fd == -1)
- warnx("cannot connect to %s", host);
+ warnf("failed to connect to %s", host);
freeaddrinfo(res0);
return fd;
}
+int
+fifo_open(char *path)
+{
+ struct stat st;
+ int fd;
+
+ /* make a fifo file if it doesn't exists */
+ if (lstat(path, &st) != -1) {
+ if (!(st.st_mode & S_IFIFO))
+ fatal("%s: not a fifo file", path);
+ } else if (mkfifo(path, S_IRWXU) == -1) {
+ fatal("mkfifo: %s:", path);
+ }
+
+ fd = open(path, O_RDONLY | O_NONBLOCK, 0);
+ if (fd == -1)
+ fatal("open: %s:", path);
+
+ return fd;
+}
+
ssize_t
readline(int fd, char *buffer, size_t size)
{
@@ -149,18 +193,44 @@
char c;
ssize_t l;
- do {
+ while (i < size) {
l = read(fd, &c, sizeof(char));
- if (l > 0)
- buffer[i++] = c;
- else if (l == 0)
- return 0;
- else if (l == -1 && errno == EAGAIN)
+ if (l == -1 && errno == EAGAIN)
continue;
- else
- return -1;
- } while ((i < size) && (c != '\r') && (c != '\n'));
+ else if (l == -1 || l == 0)
+ return l;
- buffer[i-1] = '\0';
+ if (c == '\r' || c == '\n')
+ break;
+ buffer[i++] = c;
+ }
+ buffer[i++] = '\0';
return (ssize_t)i;
+}
+
+ssize_t
+writeall(int fd, char *buf)
+{
+ ssize_t left, sent, n;
+ left = (ssize_t)strlen(buf);
+ sent = 0;
+ while (sent < left) {
+ if ((n = write(fd, buf+sent, (size_t)left)) == -1)
+ fatal("%d: write:", fd);
+ sent += n;
+ left -= n;
+ }
+ return sent;
+}
+
+/* very simple string hash function */
+unsigned int
+hash_str(void *key, unsigned int cap)
+{
+ unsigned int i, sum = 0;
+
+ for (i = 0; i < (unsigned int)strlen(key); i++) {
+ sum += ((unsigned char *)key)[i] * (i + 1);
+ }
+ return (sum % cap);
}