ref: 49ca82832b3505a7ce86e96f11a90599219afaab
parent: 8cdec92600494e5d844cb79e25d95215cda12f8a
author: libredev <libredev@ircforever.org>
date: Sun Jan 15 11:37:08 EST 2023
replaced picoev with kqueue and epoll
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,0 @@
-[submodule "picoev"]
- path = picoev
- url = https://github.com/kazuho/picoev
--- a/Makefile
+++ b/Makefile
@@ -1,51 +1,37 @@
# This work is dedicated to the public domain.
# See COPYING file for more information.
-PREFIX = /usr/local
+include config.mk
-CC = cc
-CFLAGS = -g -std=c89 -Wall -Wextra -pedantic -Wfatal-errors -Wconversion\
- -Wstrict-prototypes -Wold-style-definition\
- -D_POSIX_C_SOURCE=200809L -isystem ./picoev/
-#CFLAGS += -fsanitize=address -fno-omit-frame-pointer
-#LDFLAGS = -fsanitize=address
-LDFLAGS = -L ./picoev/ -l picoev
+OUT = ticl
+SRC = main.c htable.c
+OBJ = $(SRC:.c=.o)
-VERSION != date '+%Y-%m-%d'
-PROGRAM = ticl
-SOURCES = main.c htable.c
-HEADERS = htable.h util.c
-OBJECTS = $(SOURCES:.c=.o)
+all: clean $(OUT)
-all: clean libpicoev.a $(PROGRAM)
-
-libpicoev.a:
- cd picoev && $(MAKE) libpicoev.a LINUX_BUILD=1 CC_DEBUG_FLAGS=-g
-
-$(PROGRAM): $(OBJECTS)
- $(CC) -o $@ $(OBJECTS) $(LDFLAGS)
-
.c.o:
$(CC) -c $(CFLAGS) $<
+$(OUT): $(OBJ)
+ $(CC) -o $@ $(OBJ) $(LDFLAGS)
+
clean:
- rm -f $(PROGRAM) $(OBJECTS) $(PROGRAM)-$(VERSION).tar.gz
- cd picoev && $(MAKE) clean
+ rm -f $(OUT) $(OBJ) $(OUT)-*.tar.gz
dist: clean
- mkdir -p $(PROGRAM)-$(VERSION)
- cp -R README COPYING Makefile $(SOURCES) $(HEADERS)\
- $(PROGRAM)-$(VERSION)
- tar -cf $(PROGRAM)-$(VERSION).tar $(PROGRAM)-$(VERSION)
- gzip $(PROGRAM)-$(VERSION).tar
- rm -rf $(PROGRAM)-$(VERSION)
+ mkdir -p $(OUT)-$(VERSION)
+ cp -R README COPYING Makefile config.mk htable.h util.c $(SRC)\
+ $(OUT)-$(VERSION)
+ tar -cf $(OUT)-$(VERSION).tar $(OUT)-$(VERSION)
+ gzip $(OUT)-$(VERSION).tar
+ rm -rf $(OUT)-$(VERSION)
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
- cp -f $(PROGRAM) $(DESTDIR)$(PREFIX)/bin
- chmod 755 $(DESTDIR)$(PREFIX)/bin/$(PROGRAM)
+ cp -f $(OUT) $(DESTDIR)$(PREFIX)/bin
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/$(OUT)
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/$(PROGRAM)
+ rm -f $(DESTDIR)$(PREFIX)/bin/$(OUT)
.PHONY: all clean dist install uninstall
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
-====================================================================
+======================================================================
WARNING: This program is still in progress, use it at your own risk.
-====================================================================
+======================================================================
ticl - tiny irc channel linker
------------------------------
@@ -7,170 +7,217 @@
ticl is a very small and simple multi-network irc channel linker.
+WARNING: If you use this program on networks that you are not allowed
+ then your nick or IP may get banned. This is because this
+ program opens multiple simultaneous connections to the server
+ and most networks have some limit on each IP.
+
Working
-------
-A bot named 'linker' joins each given channels and clones each user of its
-channel on other channels and relays the user's messages received from its
-channel to the clones on other channels.
+- A bot named 'linker' joins each given channels and clones each user
+ of its channel on other channels and relays the user's messages
+ received from its channel to the clones on other channels.
-If a user JOIN, QUIT, PART, or NICK, the linker attempts to emulate the
-same action with the clones on the other channels.
+- If a user on a channel joins(JOIN), quits(QUIT), leaves(PART), or
+ changes their nick(NICK), the linker attempts to emulate the same
+ action with the respective clones on the other channels.
-The nick of clones has the network symbol (included in square brackets) as
-a suffix.
+- Each clone's nick is followed by the original user's channel symbol
+ (enclosed in square brackets).
-If nick is already taken then additional suffix '_' will be added until
-nick is accepted on the network.
+- If the nick is already taken by another user/clone on that network,
+ an additional suffix '_' is added until the nick is accepted on that
+ network.
+- Nick of users or clones that are longer than 16 characters are
+ ignored as some networks only allow nicknames of length 16 or less.
-Limitation
-----------
-- Networks and channels that require any type of registration or verification
- will not work because clones cannot register themselves.
+Limitations
+-----------
-- Linking any two channels that are already linked will create an infinite
- loop of clones and may get your IP banned.
+- This program will not work on any channel that requires any kind of
+ registration or verification as clones cannot register.
-- Channels on the same network will not link (can be possible in the future).
+- Linking the same channel with a different name is undefined and can
+ create an infinite loop of clones.
+- Linking more than one channel from a network is undefined.
+
- No spam protection.
+- No support for TLS/SSL.
+
Features
--------
-- written in POSIX ANSI C.
-- one clone for every user on all other channels.
-- no support for TLS/SSL (this is a feature).
+- Written in OpenBSD's C style(9).
+- One clone per user on each channel.
+
Dependencies
------------
- C compiler (C89)
-- libc (with POSIX support)
+
+- C POSIX library
+
+- libbsd (on non-BSD operating systems)
+
- POSIX make (optional)
-Compiling
----------
+Installation
+-------------
- $ make
-or
- $ gcc ticl.c htable.c utils.c -o ticl
+Edit config.mk for your system.
+Then to compile and install, run:
-Example
--------
+ $ make clean install
-To start the program with 'in' as the fifo file:
+To compile without POSIX make on BSD systems, run:
- $ ./ticl ./in
+ $ cc -o ticl main.c htable.c
+Or on non-BSD systems, run:
+
+ $ cc -o ticl main.c htable.c -lbsd
+
+
+Usages
+------
+
+This program uses FIFO special file (a named pipe) for configuration.
+
+To start the program:
+
+ $ ticl <fifo>
+
+ # Example:
+
+ $ ticl in
+
+ # This will create a 'in' FIFO file if it doesn't already exist.
+
Or, to start the program with the log printing to a file:
- $ ./ticl ./in > ticl.log
+ $ ticl <fifo> > <logfile> 2>&1
-To link channel #test20 from libera and channel #test21 from ircnow:
+ # Example:
- $ echo 'netadd libera L irc.libera.chat 6667 #test20' > ./in
- $ echo 'netadd ircnow N irc.ircnow.org 6667 #test21' > ./in
+ $ ticl in > log 2>&1
-To unlink channel ircnow:
+ # This will create a 'log' file and print everything to the file.
- $ echo 'netdel ircnow' > ./in
+Or, to start and run the program in background:
-To list all the sockets (connections):
+ $ ticl <fifo> > <logfile> 2>&1 &
- $ echo 'print' > ./in
+ # Example:
- # -1 indicate original user
- # -2 indicate kicked clone
+ $ ticl in > log 2>&1 &
-To list all the users:
+To add a channel:
- $ echo 'users' > ./in
+ $ echo 'netadd <name> <symbol> <host> <ip> <channel>' > <fifo>
-To shutdown the program:
+ # Example, to link #test20 from libera and #test21 from ircnow:
- $ echo exit > ./in
+ $ echo 'netadd libera L irc.libera.chat 6667 #test20' > in
+ $ echo 'netadd ircnow N irc.ircnow.org 6667 #test21' > in
+To remove a channel from the link:
-Community
----------
+ $ echo 'netdel <name>' > <fifo>
-Join #playground on irc.ircnow.org:6697 (TLS)
+ # Example, to unlink channel ircnow:
-For any help, tag or private message me (libredev).
+ $ echo 'netdel ircnow' > in
-NOTE: Anything is allowed as long as you are not violating IRCNow TOS.
- (https://wiki.ircnow.org/index.php?n=Terms.Terms)
+To list all the users:
-Email: libredev@ircforever.org (expect late response)
+ $ echo users > <fifo>
+To close the program:
-SSL/TLS support
+ $ echo exit > <fifo>
+
+
+SSL/TLS Support
---------------
-1. relayd (OpenBSD)
--------------------
+On Openbsd (relayd):
-/etc/relayd.conf:
+ Edit /etc/relayd.conf:
- table <libera> { irc.libera.chat }
- table <ircnow> { irc.ircnow.org }
+ table <libera> { irc.libera.chat }
+ table <ircnow> { irc.ircnow.org }
- protocol "irctls" {
- tcp { nodelay, sack }
- }
+ protocol "irctls" {
+ tcp { nodelay, sack }
+ }
- relay "libera" {
- listen on 127.0.0.1 port 31220
- protocol "irctls"
- forward with tls to <libera> port 6697
- }
+ relay "libera" {
+ listen on 127.0.0.1 port 31220
+ protocol "irctls"
+ forward with tls to <libera> port 6697
+ }
- relay "ircnow" {
- listen on 127.0.0.1 port 31221
- protocol "irctls"
- forward with tls to <ircnow> port 6697
- }
+ relay "ircnow" {
+ listen on 127.0.0.1 port 31221
+ protocol "irctls"
+ forward with tls to <ircnow> port 6697
+ }
-2. stunnel (*BSD, GNU/Linux, GNU/Hurd, Plan9, etc)
---------------------------------------------------
+ To enable and start:
-On debian, /etc/stunnel/stunnel.conf:
+ $ doas rcctl enable relayd
+ $ doas rcctl start relayd
- pid = /etc/stunnel/pid
+On other platforms (stunnel):
- [libera]
- client = yes
- accept = 127.0.0.1:31220
- connect = irc.libera.chat:6697
- checkHost = irc.libera.chat
- verifyChain = yes
- CApath = /etc/ssl/certs
- OCSPaia = yes
+ Edit /etc/stunnel/stunnel.conf:
- [ircnow]
- client = yes
- accept = 127.0.0.1:31221
- connect = irc.ircnow.org:6697
- checkHost = irc.ircnow.org
- verifyChain = yes
- CApath = /etc/ssl/certs
- OCSPaia = yes
+ pid = /etc/stunnel/pid
-3. To connect:
---------------
+ [libera]
+ client = yes
+ accept = 127.0.0.1:31220
+ connect = irc.libera.chat:6697
+ checkHost = irc.libera.chat
+ verifyChain = yes
+ CApath = /etc/ssl/certs
+ OCSPaia = yes
- $ echo 'netadd libera L 127.0.0.1 31220 #test20' > ./in
- $ echo 'netadd ircnow N 127.0.0.1 31221 #test21' > ./in
+ [ircnow]
+ client = yes
+ accept = 127.0.0.1:31221
+ connect = irc.ircnow.org:6697
+ checkHost = irc.ircnow.org
+ verifyChain = yes
+ CApath = /etc/ssl/certs
+ OCSPaia = yes
+ Then enable and start stunnel service.
+Now to connect:
+
+ $ echo 'netadd libera L 127.0.0.1 31220 #test20' > in
+ $ echo 'netadd ircnow N 127.0.0.1 31221 #test21' > in
+
+
+Community / Bug Report
+----------------------
+
+Email: libredev@ircforever.org (expect late response)
+IRC: #playground on irc.ircnow.org:6697 (TLS)
+
+
License
-------
@@ -181,6 +228,6 @@
Note
----
-It is a free software and please do not call it open source as the
+This work is free software but please don't call it open source as the
Open Source Initiative (OSI) does not consider public domain software
as open source. https://opensource.org/node/878
--- /dev/null
+++ b/config.mk
@@ -1,0 +1,17 @@
+# This work is dedicated to the public domain.
+# See COPYING file for more information.
+
+VERSION != date '+%Y-%m-%d'
+
+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)
+LDFLAGS = $(LIBS)
+
+CC = cc
--- a/main.c
+++ b/main.c
@@ -4,40 +4,57 @@
*/
#include <errno.h>
+#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <poll.h>
+#include <signal.h>
#include <time.h>
#include <unistd.h>
-#include <picoev.h>
+#ifdef __gnu_linux__
+#include <sys/epoll.h>
+#include <bsd/err.h>
+#include <bsd/stdlib.h>
+#include <bsd/string.h>
+#else
+#include <sys/event.h>
+#endif
#include "htable.h"
#include "util.c"
-#define BUFFER_LEN 1024
-#define NICK_LEN 16
+#define FALSE 0
+#define TRUE 1
-#define EVENT_ADDEND 10000
+#define EV_READ 1
+#define EV_WRITE 2
+
+#define EVENT_ADDEND 100
#define NET_ADDEND 10
#define USER_ADDEND 100
-#define EVENT_TIMEOUT 10000
+#define PING_TIMEOUT 240
+#define CLONE_COOLDOWN 1
+#define CLONE_ADDEND 10
-#define MAX_FDS 10000
-#define CLONE_COOLDOWN 5
-#define CLONE_ADDEND 5
+#define BUFSIZE 1024
+#define NICK_LEN 16
+#define MAX_EVENTS 10
-#define UNUSED(x) (void)(x)
+enum {
+ IDLE = 0,
+ RESET,
+ CLONING
+};
struct network {
int id; /* event index */
- int join; /* is joined */
char *name; /* name */
char *symb; /* symbol */
- char *host; /* hostname */
+ char *host; /* host */
char *port; /* port */
char *chan; /* channel */
+ int ready; /* joined */
};
struct event {
@@ -45,19 +62,36 @@
int netid; /* net index */
char *user; /* user nick */
int suffix; /* suffix count */
+ time_t time; /* last response */
+ int ready; /* joined */
};
-static char msg [BUFFER_LEN];
-static int done;
-static struct event *events; /* events array */
-static int evlen; /* array length */
-static int evcap; /* array capacity */
+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;
-static struct network *networks; /* networks array */
-static int netlen; /* array length */
-static int netcap; /* array capacity */
+#ifdef __gnu_linux__
+static int epfd; /* epoll instance */
+#else
+static int kqfd; /* kqueue instance */
+#endif
+static int *fdtoid; /* fd to event id */
+static int fdslen; /* maximum fd */
+
+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> + ']'
@@ -67,22 +101,24 @@
static struct Htable *users;
/* functions prototype */
-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 fd_register(int, int);
+void fifo_read(void);
+time_t event_timeout(void);
+void event_write(int);
+int event_read(int);
+void net_add(char *, char *, char *, char *, char *);
+void net_del(char *);
void net_del_raw(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 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);
void nick_add_symb(char *, int);
void privmsg_update(char *, char *, int);
-void clean_exit(picoev_loop *, int);
void print_table(void);
void print_htable(void);
void print_users(void);
@@ -91,68 +127,180 @@
int
main(int argc, char *argv[])
{
- picoev_loop *loop;
- /* int fd; */
+#ifdef __gnu_linux__
+ struct epoll_event epevs [MAX_EVENTS]; /* maximum event to handle */
+#else
+ struct kevent kevs [MAX_EVENTS]; /* maximum event to handle */
+ struct timespec tmsp;
+#endif
+ int i, fd, id, nev;
+ time_t timeout;
+ time_t ntime; /* next timeout time */
/* set stdout to unbufferd */
setvbuf(stdout, NULL, _IONBF, 0);
/* check arguments */
- /* if (argc != 2) {
- printf("usage: %s <fifo>\n", argv[0]);
- return 1;
- }*/
+ if (argc != 2) {
+ printf("usage: %s fifo\n", getprogname());
+ return 0;
+ } else {
+ fifopath = argv[1];
+ }
/* init global variables */
- evcap = EVENT_ADDEND;
+ fdslen = evscap = EVENT_ADDEND;
netcap = NET_ADDEND;
- events = ecalloc((size_t)evcap, sizeof(struct event));
+ 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);
- /* init picoev */
- picoev_init(MAX_FDS);
- /* 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]); */
+#ifdef __gnu_linux__
+ if ((epfd = epoll_create1(0)) == -1)
+ err(1, "epoll_create1");
+#else
+ if ((kqfd = kqueue()) == -1)
+ err(1, "kqueue");
+#endif
+ fifofd = fifo_open(fifopath);
+ fd_register(fifofd, EV_READ);
- net_add(loop, "libre", "L", "38.87.162.53", "6667", "#debian2");
- net_add(loop, "ircnow", "N", "irc.ircnow.org", "6667", "#debian");
+ ntime = -1;
+ /* event loop */
+ while (!done) {
+ if (ntime == -1)
+ timeout = -1;
+ else if ((timeout = ntime - time(NULL)) < 0)
+ timeout = 0;
+#ifdef __gnu_linux__
+ if ((nev = epoll_wait(epfd, epevs, MAX_EVENTS,
+ (int)timeout * 1000)) == -1)
+ err(1, "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");
+#endif
+ if (nev == 0) {
+ ntime = event_timeout();
+ continue;
+ }
- /* loop */
- while (!done)
- picoev_loop_once(loop, 10);
- /* clean and exit */
- clean_exit(loop, 0);
+ 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;
+#else
+ fd = (int)kevs[i].ident;
+#endif
+ id = fdtoid[fd];
+ if (fd == fifofd) {
+ fifo_read();
+#ifdef __gnu_linux__
+ } else if (epevs[i].events & EPOLLOUT) {
+#else
+ } else if (kevs[i].filter == EVFILT_WRITE) {
+#endif
+ event_write(id);
+#ifdef __gnu_linux__
+ } else if (epevs[i].events & EPOLLIN) {
+#else
+ } else if (kevs[i].filter == EVFILT_READ) {
+#endif
+ if (event_read(id)) {
+ timeout_id = -1;
+ ntime = 0;
+ }
+ } else {
+ errx(1, "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);
+ }
+
+ free(fdtoid);
+ free(events);
+
+ /* delete all the networks */
+ for (i = 0; i < netlen; i++)
+ net_del_raw(i);
+ free(networks);
+
+ /* delete all the users */
+ htdestroy(users);
+
return 0;
}
void
-fifo_event_cb(picoev_loop *loop, int fd, int revents, void *cb_arg)
+fd_register(int fd, int type)
{
- char buffer[BUFFER_LEN];
+#ifdef __gnu_linux__
+ struct epoll_event ev;
+
+ if (type == EV_READ)
+ ev.events = EPOLLIN;
+ else if (type == EV_WRITE)
+ ev.events = EPOLLOUT;
+ else
+ errx(1, "unkown event type");
+
+ ev.data.fd = fd;
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
+ err(1, "epoll_ctl");
+#else
+ struct kevent ev;
+ int filter;
+
+ if (type == EV_READ)
+ filter = EVFILT_READ;
+ else if (type == EV_WRITE)
+ filter = EVFILT_WRITE;
+ else
+ errx(1, "unkown event type");
+
+ EV_SET(&ev, fd, filter, EV_ADD, 0, 0, 0);
+ if (kevent(kqfd, &ev, 1, NULL, 0, NULL) == -1)
+ err(1, "kevent");
+#endif
+ /* printf("added fd: %d\n", fd); */
+}
+
+void
+fifo_read(void)
+{
+ char buffer [BUFSIZE];
char *buf;
char *cmd;
ssize_t n;
- UNUSED(revents);
-
- n = readline(fd, buffer, sizeof(buffer));
+ n = readline(fifofd, 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);
+ err(1, "fifo: read");
+ } else if (n == 0) {
+ /* reopen fifo again */
+ close(fifofd);
+ fifofd = fifo_open(fifopath);
+ fd_register(fifofd, EV_READ);
return;
}
@@ -165,15 +313,15 @@
char *port = split(&buf, ' ');
char *chan = buf;
if (!*name || !*symb || !*host || !*port || !*chan)
- printf("usage: netadd <name> <symbol> <hostname> <port> <channel>\n");
+ printf("usage: netadd <name> <symbol> <host> <port> <channel>\n");
else
- net_add(loop, name, symb, host, port, chan);
+ 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(loop, name);
+ net_del(name);
} else if (strcmp(cmd, "print") == 0) {
print_table();
} else if (strcmp(cmd, "htable") == 0) {
@@ -181,90 +329,139 @@
} else if (strcmp(cmd, "users") == 0) {
print_users();
} else if (strcmp(cmd, "exit") == 0) {
- done = 1;
+ done = TRUE;
} else {
- printf("error: %s is not a command\n", cmd);
+ warnx("%s is not a command", cmd);
}
}
-void
-server_event_cb(picoev_loop *loop, int fd, int revents, void *cb_arg)
+time_t
+event_timeout(void)
{
- 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;
+ static Htiter it = {0};
- id = (int)((struct event *)cb_arg - events);
- netid = events[id].netid;
+ int i, j, *ids;
+ char *nick;
+ struct network *n;
+ time_t ntime;
- if ((revents & PICOEV_TIMEOUT) != 0) {
- int *ids, cfd, count = 0;
- Htiter it = {0};
+ /* 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);
- printf("info: time to clone %d users\n", CLONE_ADDEND);
+ j = 0;
while (htiterate(users, &it)) {
+ nick = (char *)it.node->key;
ids = (int *)it.node->val;
- buf = (char *)it.node->key;
- if (ids[netid] == 0) {
- cfd = clone_add(loop, buf, netid);
- ids[netid] = cfd;
- printf("%d. %d: %s\n", count, cfd, buf);
- count++;
- if (count >= CLONE_ADDEND) {
- picoev_set_timeout(loop, fd, CLONE_COOLDOWN);
- return;
- }
+ for (i = 0; i < netlen; i++) {
+ n = &networks[i];
+ if (!n->ready || ids[i] != 0)
+ continue;
+ ids[i] = clone_add(nick, i);
+ printf("%d: %s\n", events[ids[i]].fd, nick);
}
+ if (++j >= CLONE_ADDEND)
+ goto calculate;
}
- picoev_set_timeout(loop, fd, 0);
- return;
- }
+ state = IDLE;
+ it.index = 0;
+ it.node = NULL;
+ /* } */
- 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);
+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;
}
- picoev_set_events(loop, fd, PICOEV_READ);
+ } */
+ return ntime;
+}
+
+void
+event_write(int id)
+{
+ 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");
+#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");
+ fd_register(fd, EV_READ);
+#endif
+ 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);
}
+ events[id].time = time(NULL);
+}
+int
+event_read(int id)
+{
+ char buffer [BUFSIZE];
+ char backup [BUFSIZE];
+ char lnick [NICK_LEN]; /* linker nick */
+ char *buf;
+ char *cmd;
+ char *nick;
+ int i, fd, netid;
+ ssize_t n;
+
+ fd = events[id].fd;
+ netid = events[id].netid;
+ events[id].time = time(NULL);
+
n = readline(fd, buffer, sizeof(buffer));
if (n == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- return;
- printf("error: read: %d: %s\n", fd, strerror(errno));
- event_del(loop, id);
- } else if (n == 0) { /* reopen fifo again */
- printf("error: closed: %d\n", fd);
- event_del(loop, id);
+ warn("%d: read", fd);
+ event_del(id);
+ return 0;
+ } else if (n == 0) {
+ warnx("%d: connection closed", fd);
+ event_del(id);
+ return 0;
}
- /* remove CRLFs */
- for (i = 0; i < (int)strlen(buffer); i++) {
- if (buffer[i] == '\r' || buffer[i] == '\n') {
- buffer[i] = '\0';
- break;
- }
- }
+ if (!*buffer)
+ return 0;
/* clone the buffer */
- strcpy(backup, buffer);
+ strlcpy(backup, buffer, sizeof(buffer));
buf = buffer;
/* set linker nick */
- strcpy(lnick, "linker");
+ strlcpy(lnick, "linker", sizeof(lnick));
for (i = 0; i < events[id].suffix; i++)
strcat(lnick, "_");
@@ -271,13 +468,13 @@
/* first column */
cmd = split(&buf, ' ');
if (strcmp(cmd, "NOTICE") == 0) {
- return;
+ return 0;
} else if (strcmp(cmd, "ERROR") == 0) {
goto printbuffer;
} else if (strcmp(cmd, "PING") == 0) {
snprintf(msg, sizeof(msg), "PONG %s\r\n", buf);
writeall(fd, msg);
- return;
+ goto printbuffer;
}
/* strip nick from first column */
nick = split(&cmd, '!');
@@ -301,6 +498,8 @@
|| (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)
@@ -308,17 +507,17 @@
|| (strcmp(cmd, "366") == 0)
|| (strcmp(cmd, "MODE") == 0)
|| (strcmp(cmd, "NOTICE") == 0)) {
- return;
+ return 0;
} else if (strcmp(cmd, "433") == 0) { /* Nickname already in use */
split(&buf, ' ');
nick = split(&buf, ' ');
if (strlen(nick)+1 > NICK_LEN) {
- printf("error: cannot append suffix, nick '%s' is too big\n", nick);
+ warnx("nick '%s' is too big", nick);
if (strcmp(nick, lnick) == 0) {
- net_del(loop, networks[netid].name);
+ net_del(networks[netid].name);
} else {
snprintf(msg, sizeof(msg), "QUIT :nick is too big\r\n");
- user_del(loop, nick, msg);
+ user_del(nick, msg);
}
} else {
strcat(nick, "_");
@@ -326,19 +525,19 @@
snprintf(msg, sizeof(msg), "NICK %s\r\n", nick);
writeall(fd, msg);
}
- return;
+ return 0;
} else if (strcmp(cmd, "001") == 0) {
snprintf(msg, sizeof(msg), "JOIN %s\r\n", networks[netid].chan);
writeall(fd, msg);
- return;
+ return 0;
} else if (strcmp(cmd, "PRIVMSG") == 0) {
- char privmsg[BUFFER_LEN] = "";
+ char privmsg [BUFSIZE] = "";
int *ids;
if (events[id].user == NULL) { /* if linker */
nick_add_symb(nick, netid);
if ((ids = htsearch(users, nick)) == NULL)
- return;
+ return 0;
split(&buf, ':'); /* set buf to msg */
privmsg_update(privmsg, buf, netid);
@@ -354,11 +553,11 @@
/* ignore messages from channel (it is handled by linker) */
if ((user[0] == '#') || (user[0] == '&'))
- return;
+ return 0;
nick_add_symb(nick, netid);
if ((ids = htsearch(users, nick)) == NULL)
- return;
+ return 0;
/* split user nick and network symbol */
*strrchr(user, ']') = '\0';
@@ -376,22 +575,27 @@
snprintf(msg, sizeof(msg), "PRIVMSG %s :%s\r\n", user, privmsg);
writeall(events[ids[i]].fd, msg);
}
- return;
+ return 0;
}
/* these messages are handled by linker */
if (events[id].user != NULL) { /* if clone */
- if ((strcmp(cmd, "353") == 0)
- || (strcmp(cmd, "JOIN") == 0)
+ 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;
+ || (strcmp(cmd, "NICK") == 0)) {
+ return 0;
+ }
} else if (strcmp(cmd, "353") == 0) {
char *nick;
split(&buf, ':');
- networks[netid].join = 1;
- /* net_update(loop, netid); */
+ networks[netid].ready = TRUE;
+ state = RESET;
+
+ /* then add all new users */
while (*(nick = split(&buf, ' ')) != '\0') {
if (*nick == '@'
|| *nick == '&'
@@ -401,26 +605,27 @@
|| *nick == '\\')
nick++;
if (strcmp(nick, lnick) != 0)
- user_add(loop, nick, netid);
+ user_add(nick, netid, FALSE);
}
- for (i = 0; i < netlen; i++)
- picoev_set_timeout(loop, events[networks[i].id].fd, CLONE_COOLDOWN);
- return;
+ return 1;
} else if (strcmp(cmd, "JOIN") == 0) {
if ((strcmp(nick, lnick) != 0)
- && (clone_get_user_ids(nick, netid) == NULL)) { /* if not clone */
- user_add(loop, nick, netid);
- for (i = 0; i < netlen; i++)
- picoev_set_timeout(loop, events[networks[i].id].fd, CLONE_COOLDOWN);
+ && (user_event_ids(nick, netid) == NULL)) { /* if not clone */
+ if (state != IDLE)
+ warn("ignoring user '%s' due to network cloning", nick);
+ else
+ user_add(nick, netid, TRUE);
}
- return;
+ return 0;
} 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(loop, nick, msg);
- return;
+ if (htsearch(users, nick) != NULL) {
+ printf("userdel: %s\n", nick);
+ user_del(nick, msg);
+ }
+ return 0;
} else if (strcmp(cmd, "NICK") == 0) {
int *ids, i;
char *newnick;
@@ -427,7 +632,7 @@
nick_add_symb(nick, netid);
if ((ids = htsearch(users, nick)) == NULL)
- return;
+ return 0;
/* set buf to new nick */
split(&buf, ':');
@@ -441,7 +646,7 @@
if (ids[i] > 0)
writeall(events[ids[i]].fd, msg);
}
- return;
+ return 0;
} else if (strcmp(cmd, "KICK") == 0) {
/* :<nick_which_is_kicking>!~user@host KICK <channel> <nick_which_has_been_kicked> :<kick_msg> */
int *ids;
@@ -453,20 +658,20 @@
/* delete whole network if it is the linker */
if (strcmp(user, lnick) == 0) {
- net_del(loop, networks[netid].name);
- return;
+ net_del(networks[netid].name);
+ return 0;
}
/* delete the user if the message from the same network */
- if ((ids = clone_get_user_ids(user, netid)) == NULL) {
+ if ((ids = user_event_ids(user, netid)) == NULL) {
nick_add_symb(user, netid);
- user_del(loop, user, msg);
- return;
+ user_del(user, msg);
+ return 0;
}
/* close the kicked fd */
writeall(fd, msg);
- event_del(loop, id);
+ event_del(id);
/*
* send notice in the channel through linker
@@ -485,32 +690,32 @@
"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;
+ return 0;
}
printbuffer:
- printf("%d: %s\n", fd, backup);
+ return 0;
}
void
-net_add(picoev_loop *loop, char *name, char *symb, char *host, char *port, char *chan)
+net_add(char *name, char *symb, char *host, char *port, char *chan)
{
- int i, fd;
struct network *n;
+ int i, fd;
/* if name, symbol or configuration already exists */
for (i = 0; i < netlen; i++) {
if (strcmp(networks[i].name, name) == 0) {
- printf("error: network name '%s' already exists\n", name);
+ warnx("network name '%s' already exists", name);
return;
}
if (strcmp(networks[i].symb, symb) == 0) {
- printf("error: network symbol '%s' already exists\n", symb);
+ warnx("network symbol '%s' already exists", symb);
return;
}
if ((strcmp(networks[i].host, host) == 0)
&& (strcmp(networks[i].port, port) == 0)
&& (strcmp(networks[i].chan, chan) == 0)) {
- printf("error: network configuration already exists\n");
+ warnx("network configuration already exists");
return;
}
}
@@ -518,11 +723,11 @@
/* resize if full */
if (netlen == netcap) {
Htiter it = {0};
- networks = erecalloc(networks, (size_t)netcap, NET_ADDEND,
- sizeof(struct network));
+ networks = realloc0(networks, sizeof(struct network) * (size_t)netcap,
+ sizeof(struct network) * (size_t)(netcap + NET_ADDEND));
while (htiterate(users, &it))
- it.node->val = erecalloc(it.node->val, (size_t)netcap,
- NET_ADDEND, sizeof(int));
+ it.node->val = realloc0(it.node->val, sizeof(int) * (size_t)netcap,
+ sizeof(int) * (size_t)(netcap + NET_ADDEND));
netcap += NET_ADDEND;
}
@@ -531,19 +736,20 @@
return;
/* add a network */
n = &networks[netlen];
- n->id = event_add(loop, fd, netlen, NULL);
- n->join = 0;
+ 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;
netlen++;
+
printf("%d: network '%s' added\n", fd, name);
}
void
-net_del(picoev_loop *loop, char *name)
+net_del(char *name)
{
int i, netid, *ids;
@@ -559,7 +765,7 @@
}
}
if (netid == -1) {
- printf("error: network '%s' doesn't exist\n", name);
+ warnx("network '%s' doesn't exist", name);
return;
}
@@ -571,7 +777,7 @@
ids = (int *)it.node->val;
/* delete all the users of deleting network */
if (ids[netid] == -1) {
- user_del(loop, it.node->key, msg);
+ user_del(it.node->key, msg);
/* this node is deleted */
it = lastit;
/* delete the clones */
@@ -578,7 +784,7 @@
} else {
if (ids[netid] > 0) {
writeall(events[ids[netid]].fd, msg);
- event_del(loop, ids[netid]);
+ event_del(ids[netid]);
}
/* swap last with current one */
ids[netid] = ids[netlen-1];
@@ -587,13 +793,13 @@
}
/* set last netid of events to current netid. */
- for (i = 0; i < evlen; i++) {
+ 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(loop, networks[netid].id);
+ event_del(networks[netid].id);
net_del_raw(netid);
printf("%d: network '%s' deleted\n", events[networks[netid].id].fd, name);
/* swap the network with the last */
@@ -613,103 +819,84 @@
}
void
-net_update(picoev_loop *loop, int netid)
+user_add(char *unick, int netid, int clone)
{
- Htiter it = {0};
- while (htiterate(users, &it))
- ((int *)it.node->val)[netid] = clone_add(loop, it.node->key,
- netid);
-}
-
-void
-user_add(picoev_loop *loop, char *unick, int netid)
-{
- int i, *ids;
- size_t len;
+ size_t len;
char *nick;
+ int *ids, i;
len = strlen(unick) + strlen(networks[netid].symb) + 2 + 1;
/* too long nick */
- if (len - 1 > NICK_LEN) {
- printf("error: user nick '%s' is too big\n", unick);
- return;
- }
+ if (len - 1 > NICK_LEN)
+ warnx("nick '%s' is too big", unick);
/* resize hash table if storage is low */
if ((users->cap - users->len) < USER_ADDEND)
htresize(users, users->cap + USER_ADDEND);
- printf("useradd: %s\n", unick);
-
/* allocate a new user */
nick = ecalloc(len, sizeof(char));
ids = ecalloc((size_t)netcap, sizeof(int));
sprintf(nick, "%s[%s]", unick, networks[netid].symb);
+ ids[netid] = -1;
- /* clone the user on all other network */
- for (i = 0; i < netlen; i++) {
- if (networks[i].join == 0)
- continue;
- if (i == netid) {
- ids[i] = -1;
- } else {
- /* ids[i] = clone_add(loop, nick, i); */
+ printf("useradd: %s\n", nick);
+
+ if (clone) {
+ /* clone the user on all other network */
+ for (i = 0; i < netlen; i++) {
+ if (networks[i].ready == FALSE)
+ continue;
+ if (i != netid) {
+ ids[i] = clone_add(nick, i);
+ printf("%d: %s\n", events[ids[i]].fd, nick);
+ }
}
}
+
/* insert it to the users hash table */
- if (htinsert(users, nick, ids) == -1) {
+ if (htinsert(users, nick, ids) == -1)
/* this shouldn't happen as it was already checked */
- printf("error: user '%s' already exists\n", nick);
- clean_exit(loop, 1);
- }
+ errx(1, "user '%s' already exists", nick);
}
void
-user_del(picoev_loop *loop, char *nick, char *msg)
+user_del(char *nick, char *msg)
{
- int i;
- int *ids = user_get_ids(nick);
+ int i, *ids;
+ if ((ids = htsearch(users, nick)) == NULL)
+ errx(1, "user '%s' 1 doesn't exists", nick);
for (i = 0; i < netlen; i++) {
- if (ids[i] > 0) {
+ if (ids[i] <= 0)
+ continue;
+ if (events[ids[i]].ready == TRUE)
writeall(events[ids[i]].fd, msg);
- event_del(loop, ids[i]);
- }
+ event_del(ids[i]);
}
htremove(users, nick);
}
int *
-user_get_ids(char *user)
+user_event_ids(char *nick, int netid)
{
- 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;
+ unsigned int s;
int *ids = NULL;
/* count suffix */
- for (suffix = 0; nick[strlen(nick)-suffix-1] == '_'; suffix++);
+ for (s = 0; nick[strlen(nick)-s-1] == '_'; s++);
/* remove suffix */
- if (suffix > 0)
- nick[strlen(nick)-suffix] = '\0';
+ 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)suffix))
+ if ((ids != NULL) && (events[ids[netid]].suffix != (int)s))
ids = NULL;
/* add suffix back */
- if (suffix > 0)
+ if (s > 0)
nick[strlen(nick)] = '_';
return ids;
@@ -716,64 +903,78 @@
}
int
-clone_add(picoev_loop *loop, char *nick, int netid)
+clone_add(char *nick, int netid)
{
- int fd;
- struct network *n = &networks[netid];
+ struct network *n;
+ int fd;
- if ((fd = dial(n->host, n->port)) == -1)
+ n = &networks[netid];
+ if ((fd = dial(n->host, n->port)) == -1) {
+ warn("enable to connect to %s\n", n->host);
return -1;
- return event_add(loop, fd, netid, nick);
+ }
+ return event_add(fd, netid, nick);
}
int
-event_add(picoev_loop *loop, int fd, int netid, char *user)
+event_add(int fd, int netid, char *user)
{
- int i = evlen;
+ int i = evslen;
- if (evlen == evcap) {
- events = erecalloc(events, (size_t)evcap, EVENT_ADDEND,
- sizeof(struct event));
- evcap += EVENT_ADDEND;
+ if (evslen == evscap) {
+ events = realloc0(events, sizeof(struct event) * (size_t)evscap,
+ sizeof(struct event) * (size_t)(evscap + EVENT_ADDEND));
+ evscap += EVENT_ADDEND;
}
- events[i].fd = fd;
- events[i].netid = netid;
- events[i].user = user;
+ 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]);
+ events[i].time = 0;
+ events[i].ready = FALSE;
- return evlen++;
+ fd_register(fd, EV_WRITE);
+
+ 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++;
}
void
-event_del(picoev_loop *loop, int id)
+event_del(int id)
{
int *ids;
- int l = evlen - 1; /* last id */
+ int l = evslen - 1; /* last id */
/* swap id */
- if (events[l].user == NULL) { /* if linker */
+ if (events[l].user == NULL) { /* if linker */
networks[events[l].netid].id = id;
- } else { /* if user */
- ids = user_get_ids(events[l].user);
+ } 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;
}
/* disable id */
- if (events[id].user == NULL) { /* if linker */
+ if (events[id].user == NULL) { /* if linker */
networks[events[id].netid].id = -2;
- } else { /* if user */
- ids = user_get_ids(events[id].user);
+ } 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;
}
- picoev_del(loop, events[id].fd);
close(events[id].fd);
events[id] = events[l];
- events[id] = events[l];
- evlen--;
+ evslen--;
+ fdtoid[events[id].fd] = id;
}
void
@@ -805,7 +1006,7 @@
}
/* check if the word is nick */
- if (clone_get_user_ids(src, netid) != NULL)
+ if (user_event_ids(src, netid) != NULL)
*strrchr(src, '[') = '\0';
strcat(dst, src);
@@ -812,37 +1013,6 @@
strncat(dst, &d, 1);
src = n;
- }
-}
-
-void
-clean_exit(picoev_loop *loop, int status)
-{
- int i;
- snprintf(msg, sizeof(msg), "QUIT :linker shutting down\r\n");
- 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);
-
- /* delete all the networks */
- for (i = 0; i < netlen; i++)
- net_del_raw(i);
-
- free(networks);
- free(events);
-
- if (status == 0) {
- printf("exit successfully\n");
- exit(0);
- } else {
- printf("aborted\n");
- exit(1);
}
}