ticl

tiny irc channel linker
git clone git://git.ircforever.org/ticl
Log | Files | Refs | Submodules | README | LICENSE

commit abeb6b0542e9b7db6ce1ab102f03fc7499f54eb2
parent e09ff804102de75826409b6043619d2668d9cef8
Author: libredev <libredev@ircforever.org>
Date:   Wed, 23 Nov 2022 16:36:01 +0530

replaced poll with picoev (event loop library)

Diffstat:
A.gitmodules | 3+++
MMakefile | 9+++++++--
Mmain.c | 510+++++++++++++++++++++++++++++++++++++++----------------------------------------
Apicoev | 1+
Mutil.c | 6+++---
5 files changed, 263 insertions(+), 266 deletions(-)

diff --git a/.gitmodules b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "picoev"] + path = picoev + url = https://github.com/kazuho/picoev diff --git a/Makefile b/Makefile @@ -6,9 +6,10 @@ PREFIX = /usr/local CC = cc CFLAGS = -g -std=c89 -Wall -Wextra -pedantic -Wfatal-errors -Wconversion\ -Wstrict-prototypes -Wold-style-definition\ - -D_POSIX_C_SOURCE=200809L + -D_POSIX_C_SOURCE=200809L -isystem ./picoev/ #CFLAGS += -fsanitize=address -fno-omit-frame-pointer #LDFLAGS = -fsanitize=address +LDFLAGS = -L ./picoev/ -l picoev VERSION != date '+%Y-%m-%d' PROGRAM = ticl @@ -16,7 +17,10 @@ SOURCES = main.c htable.c HEADERS = htable.h util.c OBJECTS = $(SOURCES:.c=.o) -all: clean $(PROGRAM) +all: clean libpicoev.a $(PROGRAM) + +libpicoev.a: + cd picoev && $(MAKE) libpicoev.a CC=gcc LINUX_BUILD=1 CC_DEBUG_FLAGS=-g $(PROGRAM): $(OBJECTS) $(CC) -o $@ $(OBJECTS) $(LDFLAGS) @@ -26,6 +30,7 @@ $(PROGRAM): $(OBJECTS) clean: rm -f $(PROGRAM) $(OBJECTS) $(PROGRAM)-$(VERSION).tar.gz + cd picoev && $(MAKE) clean dist: clean mkdir -p $(PROGRAM)-$(VERSION) diff --git a/main.c b/main.c @@ -3,7 +3,6 @@ * See COPYING file for more information. */ -#include <fcntl.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -12,66 +11,74 @@ #include <time.h> #include <unistd.h> +#include <picoev.h> + #include "htable.h" #include "util.c" #define BUFFER_LEN 1024 -#define MAX_NICK_LEN 16 +#define NICK_LEN 16 -#define POLLFD_ADDEND 100 +#define EVENT_ADDEND 10000 #define NET_ADDEND 10 #define USER_ADDEND 100 +#define EVENT_TIMEOUT 10000 -#define TIME_OUT 180 +#define UNUSED(x) (void)(x) -typedef struct { - int id; /* fd of linker */ +struct network { + int id; /* event index */ int join; /* is joined */ char *name; /* name */ char *symb; /* symbol */ char *host; /* hostname */ char *port; /* port */ char *chan; /* channel */ -} Network; +}; -/* user defined data for each fd */ -struct FdData { +struct event { + int fd; /* event fd */ int netid; /* net index */ - int suffix; /* suffix count */ char *user; /* user nick */ - time_t time; + int suffix; /* suffix count */ }; -static struct pollfd *fdset; /* pollfd set */ -static struct FdData *fddata; /* user data set */ -static int fdslen; /* fdset length */ -static int fdscap; /* fdset capacity */ +static struct event *events; /* events array */ +static int evlen; /* array length */ +static int evcap; /* array capacity */ -static Network *networks; /* linked list of networks */ -static int netlen; /* current network length */ -static int netcap; /* total memory allocated */ -static Htable *users; /* users-clones hash table */ +static struct network *networks; /* networks array */ +static int netlen; /* array length */ +static int netcap; /* array capacity */ + +/* + * 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; -char msg[BUFFER_LEN]; -static int isrunning = 1; +static char msg [BUFFER_LEN]; +static int done; /* functions prototype */ -void handle_fifo_input(int, char *); -void handle_server_output(int); -void net_add(char *, char *, char *, char *, char *); -void net_del(char *); +void fifo_event_cb(picoev_loop *, int, int, void *); +void server_event_cb(picoev_loop *, int, int, void *); +void net_add(picoev_loop *, char *, char *, char *, char *, char *); +void net_del(picoev_loop *, char *); void net_del_raw(int); -void net_update(int); -void user_add(char *, int); -void user_del(char *, char *); -int *user_ids(char *, int); -int *euserids(char *); -int clone_add(char *, int); -int fdset_add(int, int, int, char *); -void fdset_del(int); +void net_update(picoev_loop *, int); +void user_add(picoev_loop *, char *, int); +void user_del(picoev_loop *, char *, char *); +int *user_get_ids(char *); +int *clone_get_user_ids(char *, int); +int clone_add(picoev_loop *, char *, int); +int event_add(picoev_loop *, int, int, char *); +void event_del(picoev_loop *, int); void nick_add_symb(char *, int); void privmsg_update(char *, char *, int); -void terminate(int); +void clean_exit(picoev_loop *, int); void print_table(void); void print_htable(void); void print_users(void); @@ -80,8 +87,8 @@ void print_border(void); int main(int argc, char *argv[]) { - int i, n, timeout_id; - time_t last_time, timeout; + picoev_loop *loop; + int fd; /* set stdout to unbufferd */ setvbuf(stdout, NULL, _IONBF, 0); @@ -93,88 +100,52 @@ main(int argc, char *argv[]) } /* init global variables */ - fdscap = POLLFD_ADDEND; - fdset = ecalloc((size_t)fdscap, sizeof(struct pollfd)); - fddata = ecalloc((size_t)fdscap, sizeof(struct FdData)); + evcap = EVENT_ADDEND; netcap = NET_ADDEND; - networks = ecalloc((size_t)netcap, sizeof(Network)); - /* - * hash table of users - * key -> <nickname> + '[' + <network_symbol> + ']' - * value -> array of linked clones fds indexed - * corresponding to its connected network - */ + events = ecalloc((size_t)evcap, sizeof(struct event)); + networks = ecalloc((size_t)netcap, sizeof(struct network)); users = htcreate((KeyLenFn *)strlen, (KeyCmpFn *)strcmp, free, free, USER_ADDEND); - /* add fifo_fd */ - fdset_add(fifo_open(argv[1]), -1, -1, NULL); - - /* select loop */ - while (isrunning) { - /* calculate timeout from fdset */ - last_time = time(NULL); - for (i = 0; i < fdslen; i++) { - if ((fddata[i].netid != -1) /* ignore fifo */ - && (fddata[i].time < last_time)) { - last_time = fddata[i].time; - timeout_id = i; - } - } - timeout = TIME_OUT - (time(NULL) - last_time); - if (timeout < 0) - timeout = 0; - - n = poll(fdset, (nfds_t)fdslen, (int)timeout * 1000); - if (n == -1) { - printf("error: poll: %s\n", strerror(errno)); - terminate(1); - } else if (n == 0) { - snprintf(msg, sizeof(msg), "PING :%s\r\n", - networks[fddata[timeout_id].netid].host); - writeall(fdset[timeout_id].fd, msg); - fddata[timeout_id].time = time(NULL); - continue; - } - for (i = 0; i < fdslen; i++) { - if (!(fdset[i].revents & (POLLIN|POLLHUP))) - continue; - if (fddata[i].netid == -1) - handle_fifo_input(i, argv[1]); - else - handle_server_output(i); - - fddata[i].time = time(NULL); - - /* - * handle one ready fd at one time because if we - * close upcoming ready fd, it cause infinite loop. - */ - break; - } - } - terminate(0); + /* init picoev */ + picoev_init(1000); + /* create loop */ + loop = picoev_create_loop(60); + /* get fifo fd */ + fd = fifo_open(argv[1]); + /* add fifo fd */ + picoev_add(loop, fd, PICOEV_READ, 0, fifo_event_cb, argv[1]); + /* loop */ + while (!done) + picoev_loop_once(loop, 10); + /* clean and exit */ + clean_exit(loop, 0); + return 0; } void -handle_fifo_input(int id, char *path) +fifo_event_cb(picoev_loop *loop, int fd, int revents, void *cb_arg) { - char buffer[BUFFER_LEN]; - char *buf; - char *cmd; - ssize_t n; - - /* if failed to read data */ - if ((n = readline(fdset[id].fd, buffer, sizeof(buffer))) < 1) { - if (n == 0) { /* restart again */ - fdset_del(id); - fdset_add(fifo_open(path), -1, -1, NULL); - } else if ((errno != EAGAIN) && (errno != EINTR)) { - printf("error: %d: read: %s\n", fdset[id].fd, strerror(errno)); - } + char buffer[BUFFER_LEN]; + char *buf; + char *cmd; + ssize_t n; + + UNUSED(revents); + + n = readline(fd, buffer, sizeof(buffer)); + if (n == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + printf("error: %d: read: %s\n", fd, strerror(errno)); + clean_exit(loop, 1); + } else if (n == 0) { /* reopen fifo again */ + picoev_del(loop, fd); + close(fd); + fd = fifo_open((char *)cb_arg); + picoev_add(loop, fd, PICOEV_READ, 0, fifo_event_cb, cb_arg); return; } - /* printf("fifo: %s\n", buffer); */ buf = buffer; cmd = split(&buf, ' '); @@ -187,13 +158,13 @@ handle_fifo_input(int id, char *path) if (!*name || !*symb || !*host || !*port || !*chan) printf("usage: netadd <name> <symbol> <hostname> <port> <channel>\n"); else - net_add(name, symb, host, port, chan); + net_add(loop, 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); + net_del(loop, name); } else if (strcmp(cmd, "print") == 0) { print_table(); } else if (strcmp(cmd, "htable") == 0) { @@ -201,37 +172,51 @@ handle_fifo_input(int id, char *path) } else if (strcmp(cmd, "users") == 0) { print_users(); } else if (strcmp(cmd, "exit") == 0) { - isrunning = 0; + done = 1; } else { printf("error: %s is not a command\n", cmd); } } void -handle_server_output(int id) +server_event_cb(picoev_loop *loop, int fd, int revents, void *cb_arg) { - char buffer [BUFFER_LEN]; - char backup [BUFFER_LEN]; - char linker_nick [MAX_NICK_LEN]; - char *buf; - char *cmd; - char *nick; - int i, netid; - ssize_t n; - - /* if failed to read data */ - if ((n = readline(fdset[id].fd, buffer, sizeof(buffer))) < 1) { - if (n == 0) { - printf("error: %d: connection closed\n", fdset[id].fd); - printf("ping: %d : %ld\n", fdset[id].fd, time(0) - fddata[id].time); - terminate(1); - /* fdset_del(fdset[id].fd); */ - } else if ((errno != EAGAIN) && (errno != EINTR)) { - printf("error: %d: read: %s\n", fdset[id].fd, strerror(errno)); - printf("ping: %d : %ld\n", fdset[id].fd, time(0) - fddata[id].time); - terminate(1); + char buffer [BUFFER_LEN]; + char backup [BUFFER_LEN]; + char lnick [NICK_LEN]; /* linker nick */ + char *buf; + char *cmd; + char *nick; + int i, id, netid; + ssize_t n; + + id = (int)((struct event *)cb_arg - events); + netid = events[id].netid; + + if ((revents & PICOEV_WRITE) != 0) { + if (events[id].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); + writeall(fd, msg); + snprintf(msg, sizeof(msg), "USER user 0 * :user\r\n"); + writeall(fd, msg); } - return; + picoev_set_events(loop, fd, PICOEV_READ); + } + + n = readline(fd, buffer, sizeof(buffer)); + if (n == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + printf("error: read: %d: %s\n", fd, strerror(errno)); + clean_exit(loop, 1); + } else if (n == 0) { /* reopen fifo again */ + printf("error: closed: %d\n", fd); + clean_exit(loop, 1); } /* remove CRLFs */ @@ -246,11 +231,10 @@ handle_server_output(int id) strcpy(backup, buffer); buf = buffer; - netid = fddata[id].netid; /* set linker nick */ - strcpy(linker_nick, "linker"); - for (i = 0; i < fddata[id].suffix; i++) - strcat(linker_nick, "_"); + strcpy(lnick, "linker"); + for (i = 0; i < events[id].suffix; i++) + strcat(lnick, "_"); /* first column */ cmd = split(&buf, ' '); @@ -260,7 +244,7 @@ handle_server_output(int id) goto printbuffer; } else if (strcmp(cmd, "PING") == 0) { snprintf(msg, sizeof(msg), "PONG %s\r\n", buf); - writeall(fdset[id].fd, msg); + writeall(fd, msg); return; } /* strip nick from first column */ @@ -296,30 +280,30 @@ handle_server_output(int id) } else if (strcmp(cmd, "433") == 0) { /* Nickname already in use */ split(&buf, ' '); nick = split(&buf, ' '); - if (strlen(nick)+1 > MAX_NICK_LEN) { + if (strlen(nick)+1 > NICK_LEN) { printf("error: cannot append suffix, nick '%s' is too big\n", nick); - if (strcmp(nick, linker_nick) == 0) { - net_del(networks[netid].name); + if (strcmp(nick, lnick) == 0) { + net_del(loop, networks[netid].name); } else { snprintf(msg, sizeof(msg), "QUIT :nick is too big\r\n"); - user_del(nick, msg); + user_del(loop, nick, msg); } } else { strcat(nick, "_"); - fddata[id].suffix++; + events[id].suffix++; snprintf(msg, sizeof(msg), "NICK %s\r\n", nick); - writeall(fdset[id].fd, msg); + writeall(fd, msg); } return; } else if (strcmp(cmd, "001") == 0) { snprintf(msg, sizeof(msg), "JOIN %s\r\n", networks[netid].chan); - writeall(fdset[id].fd, msg); + writeall(fd, msg); return; } else if (strcmp(cmd, "PRIVMSG") == 0) { char privmsg[BUFFER_LEN] = ""; int *ids; - if (fddata[id].user == NULL) { /* if linker */ + if (events[id].user == NULL) { /* if linker */ nick_add_symb(nick, netid); if ((ids = htsearch(users, nick)) == NULL) return; @@ -329,7 +313,7 @@ handle_server_output(int id) for (i = 0; i < netlen; i++) { if (ids[i] > 0) { snprintf(msg, sizeof(msg), "PRIVMSG %s :%s\r\n", networks[i].chan, privmsg); - writeall(fdset[ids[i]].fd, msg); + writeall(events[ids[i]].fd, msg); } } } else { @@ -358,12 +342,12 @@ handle_server_output(int id) split(&buf, ':'); /* set buf to msg */ privmsg_update(privmsg, buf, netid); snprintf(msg, sizeof(msg), "PRIVMSG %s :%s\r\n", user, privmsg); - writeall(fdset[ids[i]].fd, msg); + writeall(events[ids[i]].fd, msg); } return; } /* these messages are handled by linker */ - if (fddata[id].user != NULL) { /* if clone */ + if (events[id].user != NULL) { /* if clone */ if ((strcmp(cmd, "353") == 0) || (strcmp(cmd, "JOIN") == 0) || (strcmp(cmd, "QUIT") == 0) @@ -375,7 +359,7 @@ handle_server_output(int id) char *nick; split(&buf, ':'); networks[netid].join = 1; - net_update(netid); + net_update(loop, netid); while (*(nick = split(&buf, ' ')) != '\0') { if (*nick == '@' || *nick == '&' @@ -384,21 +368,21 @@ handle_server_output(int id) || *nick == '+' || *nick == '\\') nick++; - if (strcmp(nick, linker_nick) != 0) - user_add(nick, netid); + if (strcmp(nick, lnick) != 0) + user_add(loop, nick, netid); } return; } else if (strcmp(cmd, "JOIN") == 0) { - if ((strcmp(nick, linker_nick) != 0) - && (user_ids(nick, netid) == NULL)) /* if not clone */ - user_add(nick, netid); + if ((strcmp(nick, lnick) != 0) + && (clone_get_user_ids(nick, netid) == NULL)) /* if not clone */ + user_add(loop, nick, netid); return; } else if ((strcmp(cmd, "QUIT") == 0) || (strcmp(cmd, "PART") == 0)) { snprintf(msg, sizeof(msg), "QUIT :%s\r\n", buf); nick_add_symb(nick, netid); if (htsearch(users, nick) != NULL) - user_del(nick, msg); + user_del(loop, nick, msg); return; } else if (strcmp(cmd, "NICK") == 0) { int *ids, i; @@ -418,7 +402,7 @@ handle_server_output(int id) snprintf(msg, sizeof(msg), "NICK %s\r\n", newnick); for (i = 0; i < netlen; i++) { if (ids[i] > 0) - writeall(fdset[ids[i]].fd, msg); + writeall(events[ids[i]].fd, msg); } return; } else if (strcmp(cmd, "KICK") == 0) { @@ -431,21 +415,21 @@ handle_server_output(int id) snprintf(msg, sizeof(msg), "QUIT : kicked by %s\r\n", nick); /* delete whole network if it is the linker */ - if (strcmp(user, linker_nick) == 0) { - net_del(networks[netid].name); + if (strcmp(user, lnick) == 0) { + net_del(loop, networks[netid].name); return; } /* delete the user if the message from the same network */ - if ((ids = user_ids(user, netid)) == NULL) { + if ((ids = clone_get_user_ids(user, netid)) == NULL) { nick_add_symb(user, netid); - user_del(user, msg); + user_del(loop, user, msg); return; } /* close the kicked fd */ - writeall(fdset[ids[netid]].fd, msg); - fdset_del(id); + writeall(fd, msg); + event_del(loop, id); /* * send notice in the channel through linker @@ -463,18 +447,18 @@ handle_server_output(int id) 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(fdset[networks[i].id].fd, msg); + writeall(events[networks[i].id].fd, msg); return; } printbuffer: - printf("%d: %s\n", fdset[id].fd, backup); + printf("%d: %s\n", fd, backup); } void -net_add(char *name, char *symb, char *host, char *port, char *chan) +net_add(picoev_loop *loop, char *name, char *symb, char *host, char *port, char *chan) { - int i, fd; - Network *n; + int i, fd; + struct network *n; /* if name, symbol or configuration already exists */ for (i = 0; i < netlen; i++) { @@ -497,7 +481,7 @@ net_add(char *name, char *symb, char *host, char *port, char *chan) /* resize if full */ if (netlen == netcap) { Htiter it = {0}; - networks = erecalloc(networks, (size_t)netcap, NET_ADDEND, sizeof(Network)); + networks = erecalloc(networks, (size_t)netcap, NET_ADDEND, sizeof(struct network)); while (htiterate(users, &it)) it.node->val = erecalloc(it.node->val, (size_t)netcap, NET_ADDEND, sizeof(int)); netcap += NET_ADDEND; @@ -506,14 +490,9 @@ net_add(char *name, char *symb, char *host, char *port, char *chan) /* connect */ if ((fd = dial(host, port)) == -1) return; - /* send NICK and USER commands */ - snprintf(msg, sizeof(msg), "NICK linker\r\n"); - writeall(fd, msg); - snprintf(msg, sizeof(msg), "USER linker 0 * :linker\r\n"); - writeall(fd, msg); /* add a network */ n = &networks[netlen]; - n->id = fdset_add(fd, netlen, 0, NULL); + n->id = event_add(loop, fd, netlen, NULL); n->join = 0; n->name = strdup(name); n->symb = strdup(symb); @@ -525,7 +504,7 @@ net_add(char *name, char *symb, char *host, char *port, char *chan) } void -net_del(char *name) +net_del(picoev_loop *loop, char *name) { int i, netid, *ids; @@ -553,14 +532,14 @@ net_del(char *name) ids = (int *)it.node->val; /* delete all the users of deleting network */ if (ids[netid] == -1) { - user_del(it.node->key, msg); + user_del(loop, it.node->key, msg); /* this node is deleted */ it = lastit; /* delete the clones */ } else { if (ids[netid] > 0) { - writeall(fdset[ids[netid]].fd, msg); - fdset_del(ids[netid]); + writeall(events[ids[netid]].fd, msg); + event_del(loop, ids[netid]); } /* swap last with current one */ ids[netid] = ids[netlen-1]; @@ -568,16 +547,16 @@ net_del(char *name) lastit = it; } - /* set netid of fds with last netid to current netid. */ - for (i = 0; i < fdslen; i++) { - if (fddata[i].netid == netlen-1) - fddata[i].netid = netid; + /* set last netid of events to current netid. */ + for (i = 0; i < evlen; i++) { + if (events[i].netid == netlen-1) + events[i].netid = netid; } - writeall(fdset[networks[netid].id].fd, msg); - fdset_del(networks[netid].id); + writeall(events[networks[netid].id].fd, msg); + event_del(loop, networks[netid].id); net_del_raw(netid); - printf("%d: network '%s' deleted\n", fdset[networks[netid].id].fd, name); + printf("%d: network '%s' deleted\n", events[networks[netid].id].fd, name); /* swap the network with the last */ networks[netid] = networks[netlen-1]; netlen--; @@ -586,7 +565,7 @@ net_del(char *name) void net_del_raw(int netid) { - Network *n = &networks[netid]; + struct network *n = &networks[netid]; free(n->name); free(n->symb); free(n->host); @@ -595,15 +574,15 @@ net_del_raw(int netid) } void -net_update(int netid) +net_update(picoev_loop *loop, int netid) { Htiter it = {0}; while (htiterate(users, &it)) - ((int *)it.node->val)[netid] = clone_add(it.node->key, netid); + ((int *)it.node->val)[netid] = clone_add(loop, it.node->key, netid); } void -user_add(char *unick, int netid) +user_add(picoev_loop *loop, char *unick, int netid) { int i, *ids; size_t len; @@ -612,12 +591,12 @@ user_add(char *unick, int netid) len = strlen(unick) + strlen(networks[netid].symb) + 2 + 1; /* too long nick */ - if (len-1 > MAX_NICK_LEN) { + if (len - 1 > NICK_LEN) { printf("error: user nick '%s' is too big\n", unick); return; } - /* resize hash table if store is low */ + /* resize hash table if storage is low */ if ((users->cap - users->len) < USER_ADDEND) htresize(users, users->cap + USER_ADDEND); @@ -635,33 +614,45 @@ user_add(char *unick, int netid) if (i == netid) { ids[i] = -1; } else { - ids[i] = clone_add(nick, i); + ids[i] = clone_add(loop, nick, i); } } /* insert it to the users hash table */ if (htinsert(users, nick, ids) == -1) { /* this shouldn't happen as it was already checked */ printf("error: user '%s' already exists\n", nick); - terminate(1); + clean_exit(loop, 1); } } void -user_del(char *nick, char *msg) +user_del(picoev_loop *loop, char *nick, char *msg) { int i; - int *ids = euserids(nick); + int *ids = user_get_ids(nick); + for (i = 0; i < netlen; i++) { if (ids[i] > 0) { - writeall(fdset[ids[i]].fd, msg); - fdset_del(ids[i]); + writeall(events[ids[i]].fd, msg); + event_del(loop, ids[i]); } } htremove(users, nick); } int * -user_ids(char *nick, int netid) +user_get_ids(char *user) +{ + int *ids; + if ((ids = htsearch(users, user)) == NULL) { + printf("error: cannot find user '%s'\n", user); + exit(1); + } + return ids; +} + +int * +clone_get_user_ids(char *nick, int netid) { unsigned int suffix; int *ids = NULL; @@ -674,7 +665,7 @@ user_ids(char *nick, int netid) ids = htsearch(users, nick); /* if match but suffix doesn't match */ - if ((ids != NULL) && (fddata[ids[netid]].suffix != (int)suffix)) + if ((ids != NULL) && (events[ids[netid]].suffix != (int)suffix)) ids = NULL; /* add suffix back */ @@ -684,68 +675,64 @@ user_ids(char *nick, int netid) return ids; } -/* get user ids */ -int * -euserids(char *user) -{ - int *ids; - if ((ids = htsearch(users, user)) == NULL) { - printf("error: cannot find user '%s'\n", user); - terminate(1); - } - return ids; -} - int -clone_add(char *nick, int netid) +clone_add(picoev_loop *loop, char *nick, int netid) { - int fd; - Network *n = &networks[netid]; + int fd; + struct network *n = &networks[netid]; + if ((fd = dial(n->host, n->port)) == -1) return -1; - /* send NICK and USER commands */ - snprintf(msg, sizeof(msg), "NICK %s\r\n", nick); - writeall(fd, msg); - snprintf(msg, sizeof(msg), "USER user 0 * :user\r\n"); - writeall(fd, msg); - return fdset_add(fd, netid, 0, nick); + return event_add(loop, fd, netid, nick); } int -fdset_add(int fd, int netid, int suffix, char *user) +event_add(picoev_loop *loop, int fd, int netid, char *user) { - if (fdslen == fdscap) { - fdset = erecalloc(fdset, (size_t)fdscap, POLLFD_ADDEND, sizeof(struct pollfd)); - fddata = erecalloc(fddata, (size_t)fdscap, POLLFD_ADDEND, sizeof(struct FdData)); - fdscap += POLLFD_ADDEND; + int i = evlen; + + if (evlen == evcap) { + events = erecalloc(events, (size_t)evcap, EVENT_ADDEND, sizeof(struct event)); + evcap += EVENT_ADDEND; } - fdset[fdslen].fd = fd; - fdset[fdslen].events = POLLIN; - fddata[fdslen].netid = netid; - fddata[fdslen].suffix = suffix; - fddata[fdslen].user = user; - fddata[fdslen].time = time(NULL); - return fdslen++; + + events[i].fd = fd; + events[i].netid = netid; + events[i].user = user; + events[i].suffix = 0; + picoev_add(loop, fd, PICOEV_WRITE, 0, server_event_cb, &events[i]); + + return evlen++; } void -fdset_del(int id) +event_del(picoev_loop *loop, int id) { - /* set id of last fd to current id */ - if (fddata[fdslen-1].user != NULL) - euserids(fddata[fdslen-1].user)[fddata[fdslen-1].netid] = id; - else if ((fddata[fdslen-1].user == NULL) && (fddata[fdslen-1].netid != -1)) - networks[fddata[fdslen-1].netid].id = id; - /* set id of removing fd to -2 */ - if (fddata[id].user != NULL) - euserids(fddata[id].user)[fddata[id].netid] = -2; - else if ((fddata[id].user == NULL) && (fddata[id].netid != -1)) - networks[fddata[id].netid].id = -2; - - close(fdset[id].fd); - fdset[id] = fdset[fdslen-1]; - fddata[id] = fddata[fdslen-1]; - fdslen--; + int *ids; + int l = evlen - 1; /* last id */ + + /* swap id */ + if (events[l].user == NULL) { /* if linker */ + networks[events[l].netid].id = id; + } else { /* if user */ + ids = user_get_ids(events[l].user); + ids[events[l].netid] = id; + } + + /* disable id */ + if (events[id].user == NULL) { /* if linker */ + networks[events[id].netid].id = -2; + } else { /* if user */ + ids = user_get_ids(events[id].user); + ids[events[id].netid] = -2; + } + + picoev_del(loop, events[id].fd); + close(events[id].fd); + + events[id] = events[l]; + events[id] = events[l]; + evlen--; } void @@ -777,7 +764,7 @@ privmsg_update(char *dst, char *src, int netid) } /* check if the word is nick */ - if (user_ids(src, netid) != NULL) + if (clone_get_user_ids(src, netid) != NULL) *strrchr(src, '[') = '\0'; strcat(dst, src); @@ -788,15 +775,17 @@ privmsg_update(char *dst, char *src, int netid) } void -terminate(int status) +clean_exit(picoev_loop *loop, int status) { int i; snprintf(msg, sizeof(msg), "QUIT :linker shutting down\r\n"); - for (i = 0; i < fdslen; i++) { - if (fddata[i].netid != -1) - writeall(fdset[i].fd, msg); - fdset_del(i); + for (i = 0; i < evlen; i++) { + writeall(events[i].fd, msg); + event_del(loop, i); } + picoev_destroy_loop(loop); + picoev_deinit(); + /* delete all the users */ htdestroy(users); @@ -805,8 +794,7 @@ terminate(int status) net_del_raw(i); free(networks); - free(fdset); - free(fddata); + free(events); if (status == 0) { printf("exit successfully\n"); @@ -829,9 +817,9 @@ print_table(void) print_border(); /* print networks */ - printf("Networks\t\t"); + printf("struct networks\t\t"); for (i = 0; i < netlen; i++) - printf("%s(%d)\t", networks[i].symb, fdset[networks[i].id].fd); + printf("%s(%d)\t", networks[i].symb, events[networks[i].id].fd); printf("\n"); while (htiterate(users, &it)) { @@ -846,8 +834,8 @@ print_table(void) for (i = 0; i < netlen; i++) { printf("%d", ids[i]); /* print suffix */ - if ((ids[i] > 0) && (fddata[ids[i]].suffix > 0)) - printf("(%d)", fddata[ids[i]].suffix); + if ((ids[i] > 0) && (events[ids[i]].suffix > 0)) + printf("(%d)", events[ids[i]].suffix); printf("\t"); } printf("\n"); diff --git a/picoev b/picoev @@ -0,0 +1 @@ +Subproject commit ff85d9ef578842a40f7c91d2544b7932cec74b9d diff --git a/util.c b/util.c @@ -153,10 +153,10 @@ dial(char *host, char *port) printf("error: fcntl: %s\n", strerror(errno)); continue; } - if (connect(fd, res->ai_addr, res->ai_addrlen) == 0) - break; - else if ((errno == EINPROGRESS) && (connect_wait(fd) == 0)) + if ((connect(fd, res->ai_addr, res->ai_addrlen) == -1) + && (errno == EINPROGRESS)) break; + printf("error: connect: %s\n", strerror(errno)); close(fd); fd = -1;