rohrpost

A commandline mail client to change the world as we see it.
git clone git://r-36.net/rohrpost
Log | Files | Refs | README | 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