tTLS: use wrapper functions - sacc - sacc (saccomys): simple gopher client.
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
 (DIR) commit 5a5611b3293eaac0b26832a54b845c6822736b65
 (DIR) parent e3535c1405eac56a658886023b057944b4b91bc0
 (HTM) Author: Quentin Rameau <quinq@fifth.space>
       Date:   Sat, 10 Apr 2021 15:56:05 +0200
       
       TLS: use wrapper functions
       
       Diffstat:
         M Makefile                            |       8 ++++----
         M config.mk                           |      12 ++++++++----
         A io.h                                |      17 +++++++++++++++++
         A io_clr.c                            |      63 +++++++++++++++++++++++++++++++
         A io_tls.c                            |     129 +++++++++++++++++++++++++++++++
         M sacc.c                              |     173 ++++++++-----------------------
       
       6 files changed, 264 insertions(+), 138 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -6,7 +6,7 @@ include config.mk
        
        BIN = sacc
        MAN = $(BIN).1
       -OBJ = $(BIN:=.o) ui_$(UI).o
       +OBJ = $(BIN:=.o) ui_$(UI).o io_$(IO).o
        
        all: $(BIN)
        
       t@@ -14,9 +14,9 @@ config.h:
                cp config.def.h config.h
        
        $(BIN): $(OBJ)
       -        $(CC) $(OBJ) $(LDFLAGS) $(LIBS) $(TLSLIBS) -o $@
       +        $(CC) $(OBJ) $(LDFLAGS) $(IOLIBS) $(LIBS) -o $@
        
       -$(OBJ): config.h config.mk common.h
       +$(OBJ): config.h config.mk common.h io.h
        
        clean:
                rm -f $(BIN) $(OBJ)
       t@@ -33,7 +33,7 @@ uninstall:
        
        # Stock FLAGS
        SACCCFLAGS = -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_GNU_SOURCE \
       -             $(TLSCFLAGS) $(CFLAGS)
       +             $(IOCFLAGS) $(CFLAGS)
        
        .c.o:
                $(CC) $(SACCCFLAGS) -c $<
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -9,10 +9,14 @@ MANDIR = $(PREFIX)/share/man/man1
        UI=ti
        LIBS=-lcurses
        
       +# IO type
       +# clr (clear)
       +#IO = clr
       +# tls (Transport Layer Security)
       +IO = tls
       +IOLIBS = -ltls
       +IOCFLAGS = -DUSE_TLS
       +
        # Define NEED_ASPRINTF and/or NEED_STRCASESTR in your cflags if your system does
        # not provide asprintf() or strcasestr(), respectively.
        #CFLAGS = -DNEED_ASPRINTF -DNEED_STRCASESTR
       -
       -# gophers (gopher over TLS) support
       -TLSCFLAGS = -DUSE_TLS
       -TLSLIBS = -ltls
 (DIR) diff --git a/io.h b/io.h
       t@@ -0,0 +1,17 @@
       +#include <netdb.h>
       +
       +struct cnx {
       +#ifdef USE_TLS
       +        struct tls *tls;
       +#endif
       +        int sock;
       +};
       +
       +extern int tls;
       +
       +extern int (*ioclose)(struct cnx *);
       +extern int (*ioconnect)(struct cnx *, struct addrinfo *, const char *);
       +extern void (*ioconnerr)(struct cnx *, const char *, const char *, int);
       +extern char *(*ioparseurl)(char *);
       +extern ssize_t (*ioread)(struct cnx *, void *, size_t);
       +extern ssize_t (*iowrite)(struct cnx *, void *, size_t);
 (DIR) diff --git a/io_clr.c b/io_clr.c
       t@@ -0,0 +1,63 @@
       +#include <string.h>
       +#include <unistd.h>
       +#include <netdb.h>
       +
       +#include <sys/socket.h>
       +
       +#include "common.h"
       +#include "io.h"
       +
       +static int
       +close_clr(struct cnx *c)
       +{
       +        return close(c->sock);
       +}
       +
       +static int
       +connect_clr(struct cnx *c, struct addrinfo *ai, const char *host)
       +{
       +        return connect(c->sock, ai->ai_addr, ai->ai_addrlen);
       +}
       +
       +static void
       +connerr_clr(struct cnx *c, const char *host, const char *port, int err)
       +{
       +        if (c->sock == -1)
       +                diag("Can't open socket: %s", strerror(err));
       +        else
       +                diag("Can't connect to: %s:%s: %s", host, port, strerror(err));
       +}
       +
       +static char *
       +parseurl_clr(char *url)
       +{
       +        char *p;
       +
       +        if (p = strstr(url, "://")) {
       +                if (strncmp(url, "gopher", p - url))
       +                        die("Protocol not supported: %.*s", p - url, url);
       +
       +                url = p + 3;
       +        }
       +
       +        return url;
       +}
       +
       +static ssize_t
       +read_clr(struct cnx *c, void *buf, size_t bs)
       +{
       +        return read(c->sock, buf, bs);
       +}
       +
       +static ssize_t
       +write_clr(struct cnx *c, void *buf, size_t bs)
       +{
       +        return write(c->sock, buf, bs);
       +}
       +
       +int (*ioclose)(struct cnx *) = close_clr;
       +int (*ioconnect)(struct cnx *, struct addrinfo *, const char *) = connect_clr;
       +void (*ioconnerr)(struct cnx *, const char *, const char *, int) = connerr_clr;
       +char *(*ioparseurl)(char *) = parseurl_clr;
       +ssize_t (*ioread)(struct cnx *, void *, size_t) = read_clr;
       +ssize_t (*iowrite)(struct cnx *, void *, size_t) = write_clr;
 (DIR) diff --git a/io_tls.c b/io_tls.c
       t@@ -0,0 +1,129 @@
       +#include <string.h>
       +#include <unistd.h>
       +#include <netdb.h>
       +
       +#include <sys/socket.h>
       +
       +#include <tls.h>
       +
       +#include "common.h"
       +#include "io.h"
       +
       +int tls;
       +
       +static int
       +close_tls(struct cnx *c)
       +{
       +        int r;
       +
       +        if (tls) {
       +                if (c->tls) {
       +                        do {
       +                                r = tls_close(c->tls);
       +                        } while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT);
       +                }
       +                tls_free(c->tls);
       +        }
       +
       +        return close(c->sock);
       +}
       +
       +static int
       +connect_tls(struct cnx *c, struct addrinfo *ai, const char *host)
       +{
       +        struct tls *t;
       +        int s;
       +
       +        c->tls = NULL;
       +        s = c->sock;
       +
       +        if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1)
       +                return -1;
       +
       +        if (tls) {
       +                if ((t = tls_client()) == NULL)
       +                        return -1;
       +                if (tls_connect_socket(t, s, host) == -1)
       +                        return -1;
       +
       +                c->tls = t;
       +        }
       +
       +        return 0;
       +}
       +
       +static void
       +connerr_tls(struct cnx *c, const char *host, const char *port, int err)
       +{
       +        if (c->sock == -1) {
       +                diag("Can't open socket: %s", strerror(err));
       +        } else {
       +                if (tls && c->tls) {
       +                        diag("Can't establish TLS with \"%s\": %s",
       +                             host, tls_error(c->tls));
       +                } else {
       +                        diag("Can't connect to: %s:%s: %s", host, port,
       +                             strerror(err));
       +                }
       +        }
       +}
       +
       +static char *
       +parseurl_tls(char *url)
       +{
       +        char *p;
       +
       +        if (p = strstr(url, "://")) {
       +                if (!strncmp(url, "gopher", p - url)) {
       +                        if (tls)
       +                                diag("Switching from gophers to gopher");
       +                        tls = 0;
       +                } else if (!strncmp(url, "gophers", p - url)) {
       +                        tls = 1;
       +                } else {
       +                        die("Protocol not supported: %.*s", p - url, url);
       +                }
       +                url = p + 3;
       +        }
       +
       +        return url;
       +}
       +
       +static ssize_t
       +read_tls(struct cnx *c, void *buf, size_t bs)
       +{
       +        ssize_t n;
       +
       +        if (tls && c->tls) {
       +                do {
       +                        n = tls_read(c->tls, buf, bs);
       +                } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT);
       +        } else {
       +                n = read(c->sock, buf, bs);
       +        }
       +
       +        return n;
       +}
       +
       +static ssize_t
       +write_tls(struct cnx *c, void *buf, size_t bs)
       +{
       +        ssize_t n;
       +
       +        if (tls) {
       +                do {
       +                        n = tls_write(c->tls, buf, bs);
       +                } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT);
       +        } else {
       +                n = write(c->sock, buf, bs);
       +        }
       +
       +        return n;
       +}
       +
       +int (*ioclose)(struct cnx *) = close_tls;
       +int (*ioconnect)(struct cnx *, struct addrinfo *, const char *) = connect_tls;
       +void (*ioconnerr)(struct cnx *, const char *, const char *, int) = connerr_tls;
       +char *(*ioparseurl)(char *) = parseurl_tls;
       +ssize_t (*ioread)(struct cnx *, void *, size_t) = read_tls;
       +ssize_t (*iowrite)(struct cnx *, void *, size_t) = write_tls;
 (DIR) diff --git a/sacc.c b/sacc.c
       t@@ -18,26 +18,15 @@
        #include <sys/types.h>
        #include <sys/wait.h>
        
       -#ifdef USE_TLS
       -#include <tls.h>
       -#endif
       -
        #include "common.h"
       +#include "io.h"
        #include "config.h"
        
       -struct cnx {
       -#ifdef USE_TLS
       -        struct tls *tls;
       -#endif
       -        int sock;
       -};
       -
        static char *mainurl;
        static Item *mainentry;
        static int devnullfd;
        static int parent = 1;
        static int interactive;
       -static int tls;
        
        static void (*diag)(char *fmt, ...);
        
       t@@ -429,7 +418,7 @@ molddiritem(char *raw)
        }
        
        static char *
       -getrawitem(struct cnx *cnx)
       +getrawitem(struct cnx *c)
        {
                char *raw, *buf;
                size_t bn, bs;
       t@@ -458,17 +447,7 @@ getrawitem(struct cnx *cnx)
                                bs = BUFSIZ;
                        }
        
       -#ifdef USE_TLS
       -                if (tls) {
       -                        do {
       -                                n = tls_read(cnx->tls, buf, bs);
       -                        } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT);
       -                } else
       -#endif
       -                {
       -                        n = read(cnx->sock, buf, bs);
       -                }
       -        } while (n > 0);
       +        } while ((n = ioread(c, buf, bs)) > 0);
        
                *buf = '\0';
        
       t@@ -481,7 +460,7 @@ getrawitem(struct cnx *cnx)
        }
        
        static int
       -sendselector(struct cnx *cnx, const char *selector)
       +sendselector(struct cnx *c, const char *selector)
        {
                char *msg, *p;
                size_t ln;
       t@@ -491,21 +470,10 @@ sendselector(struct cnx *cnx, const char *selector)
                msg = p = xmalloc(ln);
                snprintf(msg, ln--, "%s\r\n", selector);
        
       -        do {
       -#ifdef USE_TLS
       -                if (tls) {
       -                        do {
       -                                n = tls_write(cnx->tls, p, ln);
       -                        } while (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT);
       -                } else
       -#endif
       -                {
       -                        n = write(cnx->sock, p, ln);
       -                }
       -
       +        while ((n = iowrite(c, p, ln)) > 0) {
                        ln -= n;
                        p += n;
       -        } while (n > 0);
       +        };
        
                free(msg);
                if (n == -1)
       t@@ -514,20 +482,8 @@ sendselector(struct cnx *cnx, const char *selector)
                return n;
        }
        
       -static void
       -closecnx(struct cnx *cnx)
       -{
       -#ifdef USE_TLS
       -        if (tls) {
       -                tls_close(cnx->tls);
       -                tls_free(cnx->tls);
       -        }
       -#endif
       -        close(cnx->sock);
       -}
       -
        static int
       -connectto(const char *host, const char *port, struct cnx *cnx)
       +connectto(const char *host, const char *port, struct cnx *c)
        {
                sigset_t set, oset;
                static const struct addrinfo hints = {
       t@@ -536,7 +492,7 @@ connectto(const char *host, const char *port, struct cnx *cnx)
                    .ai_protocol = IPPROTO_TCP,
                };
                struct addrinfo *addrs, *addr;
       -        int r, sock = -1;
       +        int r, err;
        
                sigemptyset(&set);
                sigaddset(&set, SIGWINCH);
       t@@ -548,86 +504,54 @@ connectto(const char *host, const char *port, struct cnx *cnx)
                        goto err;
                }
        
       +        r = -1;
                for (addr = addrs; addr; addr = addr->ai_next) {
       -                if ((sock = socket(addr->ai_family, addr->ai_socktype,
       -                                   addr->ai_protocol)) == -1)
       -                        continue;
       -
       -                r = connect(sock, addr->ai_addr, addr->ai_addrlen);
       -                if (r == -1) {
       -                        close(sock);
       +                if ((c->sock = socket(addr->ai_family, addr->ai_socktype,
       +                                      addr->ai_protocol)) == -1) {
       +                        err = errno;
                                continue;
                        }
       -#ifdef USE_TLS
       -                if (tls) {
       -                        if ((cnx->tls = tls_client()) == NULL) {
       -                                diag("Can't establish TLS with \"%s\": %s",
       -                                     host, tls_error(cnx->tls));
       -                                close(sock);
       -                                continue;
       -                        }
       -                        r = tls_connect_socket(cnx->tls, sock, host);
       -                }
       -#endif
       -                break;
       -        }
        
       -        freeaddrinfo(addrs);
       +                if ((r = ioconnect(c, addr, host)) == 0)
       +                        break;
        
       -        if (sock == -1) {
       -                diag("Can't open socket: %s", strerror(errno));
       -                goto err;
       -        }
       -        if (r == -1) {
       -                diag("Can't connect to: %s:%s: %s",
       -                     host, port, strerror(errno));
       -                goto err;
       +                err = errno;
       +                close(c->sock);
                }
        
       -        sigprocmask(SIG_SETMASK, &oset, NULL);
       -
       -        cnx->sock = sock;
       +        freeaddrinfo(addrs);
        
       -        return 0;
       +        if (r == -1)
       +                ioconnerr(c, host, port, err);
        err:
                sigprocmask(SIG_SETMASK, &oset, NULL);
       -        return -1;
       +
       +        return r;
        }
        
        static int
        download(Item *item, int dest)
        {
                char buf[BUFSIZ];
       -        struct cnx cnx;
       +        struct cnx c;
                ssize_t r, w;
       -        int src;
        
       -        if (!item->tag) {
       -                if (connectto(item->host, item->port, &cnx) == -1 ||
       -                    sendselector(&cnx, item->selector) == -1)
       +        if (item->tag == NULL) {
       +                if (connectto(item->host, item->port, &c) == -1 ||
       +                    sendselector(&c, item->selector) == -1)
       +                        return 0;
       +        } else {
       +                if ((c.sock = open(item->tag, O_RDONLY)) == -1) {
       +                        printf("Can't open source file %s: %s",
       +                               item->tag, strerror(errno));
       +                        errno = 0;
                                return 0;
       -                src = cnx.sock;
       -        } else if ((src = open(item->tag, O_RDONLY)) == -1) {
       -                printf("Can't open source file %s: %s",
       -                       item->tag, strerror(errno));
       -                errno = 0;
       -                return 0;
       -        }
       -
       -        for (w = 0; w != -1;) {
       -#ifdef USE_TLS
       -                if (tls) {
       -                        do {
       -                                r = tls_read(cnx.tls, buf, sizeof(buf));
       -                        } while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT);
       -                } else
       -#endif
       -                {
       -                        r = read(src, buf, sizeof(buf));
                        }
       -                if (r <= 0)
       -                        break;
       +                c.tls = NULL;
       +        }
        
       +        w = 0;
       +        while ((r = ioread(&c, buf, BUFSIZ)) > 0) {
                        while ((w = write(dest, buf, r)) > 0)
                                r -= w;
                }
       t@@ -638,7 +562,8 @@ download(Item *item, int dest)
                        errno = 0;
                }
        
       -        closecnx(&cnx);
       +        close(dest);
       +        ioclose(&c);
        
                return (r == 0 && w == 0);
        }
       t@@ -693,15 +618,15 @@ cleanup:
        static int
        fetchitem(Item *item)
        {
       -        struct cnx cnx;
       +        struct cnx c;
                char *raw;
        
       -        if (connectto(item->host, item->port, &cnx) == -1 ||
       -            sendselector(&cnx, item->selector) == -1)
       +        if (connectto(item->host, item->port, &c) == -1 ||
       +            sendselector(&c, item->selector) == -1)
                        return 0;
        
       -        raw = getrawitem(&cnx);
       -        closecnx(&cnx);
       +        raw = getrawitem(&c);
       +        ioclose(&c);
        
                if (raw == NULL || !*raw) {
                        diag("Empty response from server");
       t@@ -985,19 +910,7 @@ moldentry(char *url)
                char *p, *host = url, *port = "70", *gopherpath = "1";
                int parsed, ipv6;
        
       -        if (p = strstr(url, "://")) {
       -                if (strncmp(url, "gopher", p - url) == 0) {
       -                        if (tls) {
       -                                diag("Switching from gophers to gopher");
       -                                tls = 0;
       -                        }
       -                } else if (strncmp(url, "gophers", p - url) == 0) {
       -                        tls = 1;
       -                } else {
       -                        die("Protocol not supported: %.*s", p - url, url);
       -                }
       -                host = p + 3;
       -        }
       +        host = ioparseurl(url);
        
                if (*host == '[') {
                        ipv6 = 1;