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