tTLS: use wrapper functions - sacc - sacc (saccomys): simple gopher client.
Log
Files
Refs
LICENSE
---
commit 5a5611b3293eaac0b26832a54b845c6822736b65
parent e3535c1405eac56a658886023b057944b4b91bc0
Author: Quentin Rameau 
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(-)
---
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 $<
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
diff --git a/io.h b/io.h
t@@ -0,0 +1,17 @@
+#include 
+
+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);
diff --git a/io_clr.c b/io_clr.c
t@@ -0,0 +1,63 @@
+#include 
+#include 
+#include 
+
+#include 
+
+#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;
diff --git a/io_tls.c b/io_tls.c
t@@ -0,0 +1,129 @@
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+
+#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;
diff --git a/sacc.c b/sacc.c
t@@ -18,26 +18,15 @@
 #include 
 #include 
 
-#ifdef USE_TLS
-#include 
-#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;