net.c - rohrpost - A commandline mail client to change the world as we see it.
 (HTM) git clone git://r-36.net/rohrpost
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       net.c (6386B)
       ---
            1 /*
            2  * Copy me if you can.
            3  * by 20h
            4  */
            5 
            6 #include <unistd.h>
            7 #include <stdio.h>
            8 #include <stdlib.h>
            9 #include <stdarg.h>
           10 #include <string.h>
           11 #include <strings.h>
           12 #include <poll.h>
           13 #include <arpa/inet.h>
           14 #include <netinet/in.h>
           15 #include <sys/types.h>
           16 #include <sys/socket.h>
           17 #include <netdb.h>
           18 
           19 #include <tls.h>
           20 
           21 #include "ind.h"
           22 #include "net.h"
           23 
           24 /*
           25  * net format:
           26  *        net!addr!service
           27  */
           28 enum {
           29         NET_NET = 0x00,
           30         NET_TCP,
           31         NET_TCPS
           32 };
           33 static char *netnames[] = {
           34         [NET_NET] = "net",
           35         [NET_TCP] = "tcp",
           36         [NET_TCPS] = "tcps"
           37 };
           38 
           39 int
           40 net_gettype(char *str)
           41 {
           42         int i;
           43 
           44         for (i = 0; i < nelem(netnames); i++)
           45                 if (!strcmp(netnames[i], str))
           46                         return i;
           47         return -1;
           48 }
           49 
           50 net_t *
           51 net_new(char *desc)
           52 {
           53         net_t *ret;
           54         int state;
           55         char *tok, *buf, *toks;
           56 
           57         state = -1;
           58         toks = NULL;
           59         ret = NULL;
           60         buf = memdup(desc, strlen(desc)+1);
           61 
           62         tok = strtok_r(buf, "!", &toks);
           63         if (tok == NULL)
           64                 goto netnewerror;
           65 
           66         ret = mallocz(sizeof(net_t), 2);
           67         do {
           68                 state++;
           69                 switch(state) {
           70                 case 0:
           71                         ret->net = memdup(tok, strlen(tok)+1);
           72                         ret->type = net_gettype(ret->net);
           73                         break;
           74                 case 1:
           75                         ret->addr = memdup(tok, strlen(tok)+1);
           76                         break;
           77                 case 2:
           78                         ret->service = memdup(tok, strlen(tok)+1);
           79                         break;
           80                 case 3:
           81                         ret->options = memdup(tok, strlen(tok)+1);
           82                         break;
           83                 default:
           84                         break;
           85                 }
           86         } while ((tok = strtok_r(NULL, "!", &toks)) != NULL);
           87         if (state < 2)
           88                 goto netnewerror;
           89         free(buf);
           90 
           91         return ret;
           92 netnewerror:
           93         if (buf != NULL)
           94                 free(buf);
           95 
           96         switch (state) {
           97         case 1:
           98                 free(ret->addr);
           99         case 0:
          100                 free(ret->net);
          101         default:
          102                 break;
          103         }
          104         if (ret != NULL)
          105                 free(ret);
          106 
          107         return NULL;
          108 }
          109 
          110 void
          111 net_free(net_t *net)
          112 {
          113         switch (net->type) {
          114         case NET_TCPS:
          115                 tls_free((struct tls *)net->data[0]);
          116                 tls_config_free((struct tls_config *)net->data[1]);
          117         }
          118 
          119         if (net->net != NULL)
          120                 free(net->net);
          121         if (net->addr != NULL)
          122                 free(net->addr);
          123         if (net->service != NULL)
          124                 free(net->service);
          125         free(net);
          126 }
          127 
          128 int
          129 net_connecttcp(net_t *net)
          130 {
          131         struct addrinfo hints, *ai, *rp;
          132 
          133         memset(&hints, 0, sizeof(hints));
          134         /*
          135          * Anyone knowing a real check for IPv6, instead of failing
          136          * everything, should contact me.
          137          */
          138         hints.ai_family = AF_UNSPEC;
          139         hints.ai_socktype = SOCK_STREAM;
          140         hints.ai_protocol = IPPROTO_TCP;
          141         if (getaddrinfo(net->addr, net->service, &hints, &ai))
          142                 return 1;
          143         if (ai == NULL)
          144                 return 1;
          145 
          146         for (rp = ai; rp != NULL; rp = rp->ai_next) {
          147                 net->fd = socket(rp->ai_family, rp->ai_socktype,
          148                                 rp->ai_protocol);
          149                 if (net->fd < 0)
          150                         continue;
          151                 if (!connect(net->fd, rp->ai_addr, rp->ai_addrlen))
          152                         break;
          153                 close(net->fd);
          154         }
          155         if (rp == NULL)
          156                 return 1;
          157         freeaddrinfo(ai);
          158 
          159         return 0;
          160 }
          161 
          162 int
          163 net_addssl(net_t *net)
          164 {
          165         struct tls *tls = NULL;
          166         struct tls_config *config = NULL;
          167 
          168         if (tls_init() < 0)
          169                 return 1;
          170         if ((tls = tls_client()) == NULL)
          171                 return 1;
          172         if ((config = tls_config_new()) == NULL) {
          173                 tls_free(tls);
          174                 return 1;
          175         }
          176 
          177         if (net->options != NULL) {
          178                 if (strstr(net->options, "tlscertverify=off"))
          179                         tls_config_insecure_noverifycert(config);
          180                 if (strstr(net->options, "tlsnameverify=off"))
          181                         tls_config_insecure_noverifyname(config);
          182         }
          183 
          184         if (tls_configure(tls, config) < 0) {
          185                 fprintf(stderr, "tls_configure: %s\n", tls_error(tls));
          186                 tls_free(tls);
          187                 tls_config_free(config);
          188                 return 1;
          189         }
          190 
          191         if (tls_connect_socket(tls, net->fd, net->addr) < 0) {
          192                 fprintf(stderr, "tls_connect_socket: %s\n", tls_error(tls));
          193                 tls_free(tls);
          194                 tls_config_free(config);
          195                 return 1;
          196         }
          197 
          198         switch (net->type) {
          199         case NET_NET:
          200         case NET_TCP:
          201                 free(net->net);
          202                 net->net = memdup("tcps", 5);
          203                 net->type = net_gettype(net->net);
          204         case NET_TCPS:
          205         default:
          206                 break;
          207         }
          208 
          209         net->data[0] = tls;
          210         net->data[1] = config;
          211 
          212         return 0;
          213 }
          214 
          215 int
          216 net_connecttcps(net_t *net)
          217 {
          218         if (net_connecttcp(net))
          219                 return 1;
          220         if (net_addssl(net))
          221                 return 1;
          222 
          223         return 0;
          224 }
          225 
          226 int
          227 net_connect(net_t *net)
          228 {
          229         switch (net->type) {
          230         case NET_NET:
          231         case NET_TCP:
          232                 return net_connecttcp(net);
          233         case NET_TCPS:
          234                 return net_connecttcps(net);
          235         default:
          236                 return 1;
          237         }
          238         return 0;
          239 }
          240 
          241 void
          242 net_closetcp(net_t *net)
          243 {
          244         shutdown(net->fd, SHUT_RDWR);
          245         close(net->fd);
          246 }
          247 
          248 void
          249 net_closetcps(net_t *net)
          250 {
          251         tls_close((struct tls *)net->data[0]);
          252 }
          253 
          254 void
          255 net_close(net_t *net)
          256 {
          257         switch (net->type) {
          258         case NET_NET:
          259         case NET_TCP:
          260                 net_closetcp(net);
          261         case NET_TCPS:
          262                 net_closetcps(net);
          263         default:
          264                 break;
          265         }
          266 }
          267 
          268 int
          269 net_writetcp(net_t *net, char *buf, int len)
          270 {
          271         return send(net->fd, buf, len, MSG_NOSIGNAL);
          272 }
          273 
          274 int
          275 net_writetcps(net_t *net, char *buf, int len)
          276 {
          277         int r = TLS_WANT_POLLIN;
          278 
          279         while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT)
          280                 r = tls_write((struct tls *)net->data[0], buf, len);
          281 
          282         return r;
          283 }
          284 
          285 int
          286 net_write(net_t *net, char *buf, int len)
          287 {
          288         switch (net->type) {
          289         case NET_NET:
          290         case NET_TCP:
          291                 return net_writetcp(net, buf, len);
          292         case NET_TCPS:
          293                 return net_writetcps(net, buf, len);
          294         default:
          295                 return -1;
          296         }
          297         return -1;
          298 }
          299 
          300 int
          301 net_writeall(net_t *net, char *buf, int len)
          302 {
          303         int olen, nlen;
          304 
          305         for (olen = 0;
          306                         (nlen = net_write(net, &buf[olen], len-olen)) >= 0
          307                         && olen < len;
          308                         olen += nlen);
          309 
          310         return 0;
          311 }
          312 
          313 int
          314 net_printf(net_t *net, char *fmt, ...)
          315 {
          316         va_list fmtargs;
          317         char *buf;
          318         int len;
          319 
          320         va_start(fmtargs, fmt);
          321         len = vsnprintf(NULL, 0, fmt, fmtargs);
          322         va_end(fmtargs);
          323 
          324         va_start(fmtargs, fmt);
          325         buf = vsmprintf(fmt, fmtargs, len);
          326         va_end(fmtargs);
          327 
          328         len = net_writeall(net, buf, strlen(buf));
          329         free(buf);
          330         return len;
          331 }
          332 
          333 int
          334 net_readtcp(net_t *net, char *buf, int len)
          335 {
          336         return recv(net->fd, buf, len, 0);
          337 }
          338 
          339 int
          340 net_readtcps(net_t *net, char *buf, int len)
          341 {
          342         int r = TLS_WANT_POLLIN;
          343 
          344         while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT)
          345                 r = tls_read((struct tls *)net->data[0], buf, len);
          346 
          347         return r;
          348 }
          349 
          350 int
          351 net_read(net_t *net, char *buf, int len)
          352 {
          353         switch (net->type) {
          354         case NET_NET:
          355         case NET_TCP:
          356                 return net_readtcp(net, buf, len);
          357         case NET_TCPS:
          358                 return net_readtcps(net, buf, len);
          359         default:
          360                 return -1;
          361         }
          362         return -1;
          363 }
          364 
          365 int
          366 net_readall(net_t *net, char *buf, int len)
          367 {
          368         int olen, nlen;
          369 
          370         for (olen = 0;
          371                         (nlen = net_read(net, &buf[olen], len-olen))
          372                         && olen < len;
          373                         olen += nlen);
          374 
          375         return 0;
          376 }
          377 
          378 char *
          379 net_gets(net_t *net)
          380 {
          381         char *ret;
          382         int len;
          383 
          384         len = 1;
          385         ret = mallocz(len, 2);
          386         while (net_read(net, &ret[len-1], 1) > 0 && ret[len-1] != '\n'
          387                         && len < MAXLINESIZE)
          388                 ret = reallocz(ret, ++len + 1, 0);
          389         /*
          390         if (ret[len-1] != '\n') {
          391                 free(ret);
          392                 return NULL;
          393         }
          394         ret[len-1] = '\0';
          395         */
          396         ret[len] = '\0';
          397 
          398         return ret;
          399 }
          400