tentative reconnection support - irc - Unnamed repository; edit this file 'description' to name the repository.
 (HTM) git clone git://vernunftzentrum.de/irc.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 3bb53c314db1eede1b9359c9e7886105cedd8fc3
 (DIR) parent 874cde6562f0c0817a6d14878269c4364cddb801
 (HTM) Author: Quentin Carbonneaux <quentin.carbonneaux@yale.edu>
       Date:   Thu, 19 Jan 2017 11:10:01 -0500
       
       tentative reconnection support
       
       Diffstat:
         irc.c                               |     145 ++++++++++++++++++++-----------
       
       1 file changed, 94 insertions(+), 51 deletions(-)
       ---
 (DIR) diff --git a/irc.c b/irc.c
       @@ -39,6 +39,7 @@ enum {
                MaxChans = 16,
                BufSz = 2048,
                LogSz = 4096,
       +        MaxRecons = 10, /* -1 for infinitely many */
                UtfSz = 4,
                RuneInvalid = 0xFFFD,
        };
       @@ -58,6 +59,7 @@ static struct Chan {
                size_t sz; /* Size of buf. */
                char high; /* Nick highlight. */
                char new;  /* New message. */
       +        char join; /* Channel was 'j'-oined. */
        } chl[MaxChans];
        
        static int ssl;
       @@ -184,12 +186,7 @@ srd(void)
                        rd = SSL_read(srv.ssl, p, BufSz - (p - l));
                else
                        rd = read(srv.fd, p, BufSz - (p - l));
       -        if (rd < 0) {
       -                if (errno == EINTR)
       -                        return 1;
       -                panic("IO error while reading.");
       -        }
       -        if (rd == 0)
       +        if (rd <= 0)
                        return 0;
                p += rd;
                for (;;) { /* Cycle on all received lines. */
       @@ -220,6 +217,16 @@ srd(void)
        }
        
        static void
       +sinit(const char *key, const char *nick, const char *user)
       +{
       +        if (key)
       +                sndf("PASS %s", key);
       +        sndf("NICK %s", nick);
       +        sndf("USER %s 8 * :%s", user, user);
       +        sndf("MODE %s +i", nick);
       +}
       +
       +static char *
        dial(const char *host, const char *service)
        {
                struct addrinfo hints, *res = NULL, *rp;
       @@ -230,7 +237,7 @@ dial(const char *host, const char *service)
                hints.ai_flags = AI_NUMERICSERV; /* avoid name lookup for port */
                hints.ai_socktype = SOCK_STREAM;
                if ((e = getaddrinfo(host, service, &hints, &res)))
       -                panic("Getaddrinfo failed.");
       +                return "Getaddrinfo failed.";
                for (rp = res; rp; rp = rp->ai_next) {
                        if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1)
                                continue;
       @@ -241,27 +248,62 @@ dial(const char *host, const char *service)
                        break;
                }
                if (fd == -1)
       -                panic("Cannot connect to host.");
       +                return "Cannot connect to host.";
                srv.fd = fd;
                if (ssl) {
                        SSL_load_error_strings();
                        SSL_library_init();
                        srv.ctx = SSL_CTX_new(SSLv23_client_method());
                        if (!srv.ctx)
       -                        panic("Could not initialize ssl context.");
       +                        return "Could not initialize ssl context.";
                        srv.ssl = SSL_new(srv.ctx);
                        if (SSL_set_fd(srv.ssl, srv.fd) == 0
                        || SSL_connect(srv.ssl) != 1)
       -                        panic("Could not connect with ssl.");
       +                        return "Could not connect with ssl.";
                }
                freeaddrinfo(res);
       +        return 0;
       +}
       +
       +static void
       +hangup(void)
       +{
       +        if (srv.ssl) {
       +                SSL_shutdown(srv.ssl);
       +                SSL_free(srv.ssl);
       +                srv.ssl = 0;
       +        }
       +        if (srv.fd) {
       +                close(srv.fd);
       +                srv.fd = 0;
       +        }
       +        if (srv.ctx) {
       +                SSL_CTX_free(srv.ctx);
       +                srv.ctx = 0;
       +        }
       +}
       +
       +static inline int
       +chfind(const char *name)
       +{
       +        int i;
       +
       +        assert(name);
       +        for (i = nch - 1; i > 0; i--)
       +                if (!strcmp(chl[i].name, name))
       +                        break;
       +        return i;
        }
        
        static int
       -chadd(char *name, int change)
       +chadd(const char *name, int joined)
        {
       +        int n;
       +
                if (nch >= MaxChans || strlen(name) >= ChanLen)
                        return -1;
       +        if ((n = chfind(name)) > 0)
       +                return n;
                strcpy(chl[nch].name, name);
                chl[nch].sz = LogSz;
                chl[nch].buf = malloc(LogSz);
       @@ -269,25 +311,14 @@ chadd(char *name, int change)
                        panic("Out of memory.");
                chl[nch].eol = chl[nch].buf;
                chl[nch].n = 0;
       -        if (change)
       +        chl[nch].join = joined;
       +        if (joined)
                        ch = nch;
                nch++;
                tdrawbar();
                return nch;
        }
        
       -static inline int
       -chfind(char *name)
       -{
       -        int i;
       -
       -        assert(name);
       -        for (i = nch - 1; i > 0; i--)
       -                if (!strcmp(chl[i].name, name))
       -                        break;
       -        return i;
       -}
       -
        static int
        chdel(char *name)
        {
       @@ -779,8 +810,10 @@ main(int argc, char *argv[])
                const char *key = getenv("IRCPASS");
                const char *server = SRV;
                const char *port = PORT;
       -        int o;
       +        char *err;
       +        int o, reconn;
        
       +        signal(SIGPIPE, SIG_IGN);
                while ((o = getopt(argc, argv, "thk:n:u:s:p:l:")) >= 0)
                        switch (o) {
                        case 'h':
       @@ -817,14 +850,15 @@ main(int argc, char *argv[])
                if (!user)
                        user = "anonymous";
                tinit();
       -        dial(server, port);
       -        chadd("*server*", 1);
       -        if (key)
       -                sndf("PASS %s", key);
       -        sndf("NICK %s", nick);
       -        sndf("USER %s 8 * :%s", user, user);
       -        sndf("MODE %s +i", nick);
       +        err = dial(server, port);
       +        if (err)
       +                panic(err);
       +        chadd(server, 0);
       +        sinit(key, nick, user);
       +        reconn = 0;
                while (!quit) {
       +                struct timeval t = {.tv_sec = 5};
       +                struct Chan *c;
                        fd_set rfs, wfs;
                        int ret;
        
       @@ -833,18 +867,35 @@ main(int argc, char *argv[])
                        FD_ZERO(&wfs);
                        FD_ZERO(&rfs);
                        FD_SET(0, &rfs);
       -                FD_SET(srv.fd, &rfs);
       -                if (outp != outb)
       -                        FD_SET(srv.fd, &wfs);
       -                ret = select(srv.fd + 1, &rfs, &wfs, 0, 0);
       +                if (!reconn) {
       +                        FD_SET(srv.fd, &rfs);
       +                        if (outp != outb)
       +                                FD_SET(srv.fd, &wfs);
       +                }
       +                ret = select(srv.fd + 1, &rfs, &wfs, 0, &t);
                        if (ret < 0) {
                                if (errno == EINTR)
                                        continue;
                                panic("Select failed.");
                        }
       +                if (reconn) {
       +                        hangup();
       +                        if (reconn++ == MaxRecons + 1)
       +                                panic("Link lost.");
       +                        pushf(0, "-!- Link lost, attempting reconnection...");
       +                        if (dial(server, port) != 0)
       +                                continue;
       +                        sinit(key, nick, user);
       +                        for (c = chl; c < &chl[nch]; ++c)
       +                                if (c->join)
       +                                        sndf("JOIN %s", c->name);
       +                        reconn = 0;
       +                }
                        if (FD_ISSET(srv.fd, &rfs)) {
       -                        if (!srd())
       -                                quit = 1;
       +                        if (!srd()) {
       +                                reconn = 1;
       +                                continue;
       +                        }
                        }
                        if (FD_ISSET(srv.fd, &wfs)) {
                                int wr;
       @@ -853,13 +904,10 @@ main(int argc, char *argv[])
                                        wr = SSL_write(srv.ssl, outb, outp - outb);
                                else
                                        wr = write(srv.fd, outb, outp - outb);
       -                        if (wr < 0) {
       -                                if (errno == EINTR)
       -                                        continue;
       -                                panic("Write error.");
       -                        }
       -                        if (wr == 0)
       +                        if (wr <= 0) {
       +                                reconn = wr < 0;
                                        continue;
       +                        }
                                outp -= wr;
                                memmove(outb, outb + wr, outp - outb);
                        }
       @@ -867,14 +915,9 @@ main(int argc, char *argv[])
                                tgetch();
                                wrefresh(scr.iw);
                        }
       +                continue;
                }
       -        if (ssl) {
       -                SSL_shutdown(srv.ssl);
       -                SSL_free(srv.ssl);
       -                close(srv.fd);
       -                SSL_CTX_free(srv.ctx);
       -        } else
       -                close(srv.fd);
       +        hangup();
                while (nch--)
                        free(chl[nch].buf);
                treset();