Line data Source code
1 : #include "burp.h"
2 : #include "alloc.h"
3 : #include "asfd.h"
4 : #include "async.h"
5 : #include "cmd.h"
6 : #include "fsops.h"
7 : #include "handy.h"
8 : #include "iobuf.h"
9 : #include "log.h"
10 : #include "server/protocol2/champ_chooser/incoming.h"
11 :
12 : // For IPTOS / IPTOS_THROUGHPUT.
13 : #ifdef HAVE_WIN32
14 : #include <ws2tcpip.h>
15 : #else
16 : #include <netinet/ip.h>
17 : #endif
18 :
19 : #ifdef HAVE_NCURSES_H
20 : #include <ncurses.h>
21 : #elif HAVE_NCURSES_NCURSES_H
22 : #include <ncurses/ncurses.h>
23 : #endif
24 :
25 : #include "protocol2/blist.h"
26 :
27 : static void truncate_readbuf(struct asfd *asfd)
28 : {
29 0 : asfd->readbuf[0]='\0';
30 0 : asfd->readbuflen=0;
31 : }
32 :
33 : static int asfd_alloc_buf(struct asfd *asfd, char **buf)
34 : {
35 18 : if(!*buf && !(*buf=(char *)calloc_w(1, asfd->bufmaxsize, __func__)))
36 : return -1;
37 : return 0;
38 : }
39 :
40 0 : static int extract_buf(struct asfd *asfd,
41 : size_t len, size_t offset)
42 : {
43 0 : if(offset+len>=asfd->bufmaxsize)
44 : {
45 0 : logp("%s: offset(%lu)+len(%lu)>=asfd->bufmaxsize(%lu) in %s!",
46 : asfd->desc,
47 : (unsigned long)offset,
48 : (unsigned long)len,
49 : (unsigned long)asfd->bufmaxsize,
50 : __func__);
51 0 : return -1;
52 : }
53 :
54 0 : if(!(asfd->rbuf->buf=(char *)malloc_w(len+1, __func__)))
55 : return -1;
56 0 : if(!(memcpy(asfd->rbuf->buf, asfd->readbuf+offset, len)))
57 : {
58 0 : logp("%s: memcpy failed in %s\n", asfd->desc, __func__);
59 0 : return -1;
60 : }
61 0 : asfd->rbuf->buf[len]='\0';
62 0 : if(!(memmove(asfd->readbuf,
63 0 : asfd->readbuf+len+offset, asfd->readbuflen-len-offset)))
64 : {
65 0 : logp("%s: memmove failed in %s\n", asfd->desc, __func__);
66 0 : return -1;
67 : }
68 0 : asfd->readbuflen-=len+offset;
69 0 : asfd->rbuf->len=len;
70 0 : return 0;
71 : }
72 :
73 : #ifdef HAVE_NCURSES
74 0 : static int parse_readbuf_ncurses(struct asfd *asfd)
75 : {
76 0 : if(!asfd->readbuflen) return 0;
77 : // This is reading ints, and will be cast back to an int when it comes
78 : // to be processed later.
79 0 : if(extract_buf(asfd, asfd->readbuflen, 0)) return -1;
80 0 : return 0;
81 : }
82 : #endif
83 :
84 0 : static int parse_readbuf_line_buf(struct asfd *asfd)
85 : {
86 : static char *cp=NULL;
87 : static char *dp=NULL;
88 : static size_t len=0;
89 0 : if(!cp)
90 : {
91 : // Only start from the beginning if we previously got something
92 : // to extract.
93 0 : cp=asfd->readbuf;
94 0 : len=0;
95 : }
96 0 : for(; len<asfd->readbuflen; cp++, len++)
97 : {
98 0 : if(*cp!='\n') continue;
99 0 : len++;
100 0 : if(extract_buf(asfd, len, 0)) return -1;
101 : // Strip trailing white space, like '\r\n'.
102 0 : dp=asfd->rbuf->buf;
103 0 : for(cp=&(dp[len-1]); cp>=dp && isspace(*cp); cp--, len--)
104 0 : *cp='\0';
105 0 : asfd->rbuf->len=len;
106 0 : break;
107 : }
108 0 : cp=NULL;
109 0 : return 0;
110 : }
111 :
112 0 : static int parse_readbuf_standard(struct asfd *asfd)
113 : {
114 0 : unsigned int s=0;
115 : char command;
116 0 : if(asfd->readbuflen<5) return 0;
117 0 : if((sscanf(asfd->readbuf, "%c%04X", &command, &s))!=2)
118 : {
119 0 : logp("%s: sscanf of '%s' failed in %s\n",
120 : asfd->desc, asfd->readbuf, __func__);
121 0 : return -1;
122 : }
123 0 : if(s>=asfd->bufmaxsize)
124 : {
125 0 : logp("%s: given buffer length '%d', which is too big!\n",
126 : asfd->desc, s);
127 0 : return -1;
128 : }
129 0 : if(asfd->readbuflen>=s+5)
130 : {
131 0 : asfd->rbuf->cmd=(enum cmd)command;
132 0 : if(extract_buf(asfd, (size_t)s, 5))
133 : return -1;
134 : }
135 : return 0;
136 : }
137 :
138 0 : static int asfd_parse_readbuf(struct asfd *asfd)
139 : {
140 0 : if(asfd->rbuf->buf) return 0;
141 :
142 0 : if(asfd->parse_readbuf_specific(asfd))
143 : {
144 0 : truncate_readbuf(asfd);
145 0 : return -1;
146 : }
147 :
148 : return 0;
149 : }
150 :
151 : #ifdef HAVE_NCURSES
152 0 : static int asfd_do_read_ncurses(struct asfd *asfd)
153 : {
154 : static int i;
155 0 : i=getch();
156 0 : asfd->readbuflen=sizeof(int);
157 0 : memcpy(asfd->readbuf, &i, asfd->readbuflen);
158 0 : return 0;
159 : }
160 :
161 0 : static int asfd_do_write_ncurses(__attribute__ ((unused)) struct asfd *asfd)
162 : {
163 0 : logp("This function should not have been called: %s\n", __func__);
164 0 : return -1;
165 : }
166 : #endif
167 :
168 0 : static int asfd_do_read(struct asfd *asfd)
169 : {
170 : ssize_t r;
171 0 : r=read(asfd->fd,
172 0 : asfd->readbuf+asfd->readbuflen, asfd->bufmaxsize-asfd->readbuflen);
173 0 : if(r<0)
174 : {
175 0 : if(errno==EAGAIN || errno==EINTR)
176 : return 0;
177 0 : logp("%s: read problem on fd %d: %s\n",
178 : asfd->desc, asfd->fd, strerror(errno));
179 0 : goto error;
180 : }
181 0 : else if(!r)
182 : {
183 : // End of data.
184 0 : logp("%s: end of data\n", asfd->desc);
185 0 : goto error;
186 : }
187 0 : asfd->readbuflen+=r;
188 0 : asfd->rcvd+=r;
189 0 : return 0;
190 : error:
191 0 : truncate_readbuf(asfd);
192 0 : return -1;
193 : }
194 :
195 : static void peer_msg(void)
196 : {
197 0 : logp("This is probably caused by the peer exiting.\n");
198 0 : logp("Please check the peer's logs.\n");
199 : }
200 :
201 0 : static int asfd_do_read_ssl(struct asfd *asfd)
202 : {
203 : int e;
204 : ssize_t r;
205 :
206 0 : asfd->read_blocked_on_write=0;
207 :
208 0 : ERR_clear_error();
209 0 : r=SSL_read(
210 : asfd->ssl,
211 0 : asfd->readbuf+asfd->readbuflen,
212 0 : asfd->bufmaxsize-asfd->readbuflen
213 : );
214 :
215 0 : switch((e=SSL_get_error(asfd->ssl, r)))
216 : {
217 : case SSL_ERROR_NONE:
218 0 : asfd->readbuflen+=r;
219 0 : asfd->rcvd+=r;
220 0 : break;
221 : case SSL_ERROR_ZERO_RETURN:
222 : // End of data.
223 0 : logp("%s: Peer closed SSL session\n", asfd->desc);
224 0 : SSL_shutdown(asfd->ssl);
225 0 : goto error;
226 : case SSL_ERROR_WANT_READ:
227 : break;
228 : case SSL_ERROR_WANT_WRITE:
229 0 : asfd->read_blocked_on_write=1;
230 0 : break;
231 : case SSL_ERROR_SYSCALL:
232 0 : if(errno==EAGAIN || errno==EINTR)
233 : break;
234 0 : logp("%s: Got network read error\n",
235 : asfd->desc);
236 : // Fall through to read problem
237 : default:
238 0 : asfd->errors++;
239 0 : logp_ssl_err(
240 : "%s: network read problem in %s: %d - %d=%s\n",
241 : asfd->desc, __func__,
242 0 : e, errno, strerror(errno));
243 : peer_msg();
244 : goto error;
245 : }
246 : return 0;
247 : error:
248 0 : truncate_readbuf(asfd);
249 0 : return -1;
250 : }
251 :
252 : // Return 0 for OK to write, non-zero for not OK to write.
253 0 : static int check_ratelimit(struct asfd *asfd)
254 : {
255 : float f;
256 : time_t diff;
257 0 : if(!asfd->rlstart) asfd->rlstart=time(NULL);
258 0 : if((diff=asfd->as->now-asfd->rlstart)<0)
259 : {
260 : // It is possible that the clock changed. Reset ourselves.
261 0 : asfd->as->now=asfd->rlstart;
262 0 : asfd->rlbytes=0;
263 0 : logp("Looks like the clock went back in time since starting. "
264 : "Resetting ratelimit\n");
265 0 : return 0;
266 : }
267 0 : if(!diff) return 0; // Need to get started somehow.
268 0 : f=(asfd->rlbytes)/diff; // Bytes per second.
269 :
270 0 : if(f>=asfd->ratelimit)
271 : {
272 : #ifdef HAVE_WIN32
273 : // Windows Sleep is milliseconds, usleep is microseconds.
274 : // Do some conversion.
275 : Sleep(asfd->rlsleeptime/1000);
276 : #else
277 0 : usleep(asfd->rlsleeptime);
278 : #endif
279 : // If sleeping, increase the sleep time.
280 0 : if((asfd->rlsleeptime*=2)>=500000) asfd->rlsleeptime=500000;
281 : return 1;
282 : }
283 : // If not sleeping, decrease the sleep time.
284 0 : if((asfd->rlsleeptime/=2)<=9999) asfd->rlsleeptime=10000;
285 : return 0;
286 : }
287 :
288 0 : static int asfd_do_write(struct asfd *asfd)
289 : {
290 : ssize_t w;
291 0 : if(asfd->ratelimit && check_ratelimit(asfd)) return 0;
292 :
293 0 : w=write(asfd->fd, asfd->writebuf, asfd->writebuflen);
294 0 : if(w<0)
295 : {
296 0 : if(errno==EAGAIN || errno==EINTR)
297 : return 0;
298 0 : logp("%s: Got error in %s, (%d=%s)\n", __func__,
299 : asfd->desc, errno, strerror(errno));
300 0 : asfd->errors++;
301 0 : return -1;
302 : }
303 0 : else if(!w)
304 : {
305 0 : logp("%s: Wrote nothing in %s\n", asfd->desc, __func__);
306 0 : asfd->errors++;
307 0 : return -1;
308 : }
309 0 : if(asfd->ratelimit) asfd->rlbytes+=w;
310 0 : asfd->sent+=w;
311 : /*
312 : {
313 : char buf[100000]="";
314 : snprintf(buf, w+1, "%s", asfd->writebuf);
315 : printf("wrote %d: %s\n", w, buf);
316 : }
317 : */
318 :
319 0 : memmove(asfd->writebuf, asfd->writebuf+w, asfd->writebuflen-w);
320 0 : asfd->writebuflen-=w;
321 0 : return 0;
322 : }
323 :
324 0 : static int asfd_do_write_ssl(struct asfd *asfd)
325 : {
326 : int e;
327 : ssize_t w;
328 :
329 0 : asfd->write_blocked_on_read=0;
330 :
331 0 : if(asfd->ratelimit && check_ratelimit(asfd)) return 0;
332 0 : ERR_clear_error();
333 0 : w=SSL_write(asfd->ssl, asfd->writebuf, asfd->writebuflen);
334 :
335 0 : switch((e=SSL_get_error(asfd->ssl, w)))
336 : {
337 : case SSL_ERROR_NONE:
338 : /*
339 : {
340 : char buf[100000]="";
341 : snprintf(buf, w+1, "%s", asfd->writebuf);
342 : printf("wrote %d: %s\n", w, buf);
343 : }
344 : */
345 0 : if(asfd->ratelimit) asfd->rlbytes+=w;
346 0 : memmove(asfd->writebuf,
347 0 : asfd->writebuf+w, asfd->writebuflen-w);
348 0 : asfd->writebuflen-=w;
349 0 : asfd->sent+=w;
350 0 : break;
351 : case SSL_ERROR_WANT_WRITE:
352 : break;
353 : case SSL_ERROR_WANT_READ:
354 0 : asfd->write_blocked_on_read=1;
355 0 : break;
356 : case SSL_ERROR_SYSCALL:
357 0 : if(errno==EAGAIN || errno==EINTR)
358 : break;
359 0 : logp("%s: Got network write error\n",
360 : asfd->desc);
361 : // Fall through to write problem
362 : default:
363 0 : asfd->errors++;
364 0 : logp_ssl_err(
365 : "%s: network write problem in %s: %d - %d=%s\n",
366 : asfd->desc, __func__,
367 0 : e, errno, strerror(errno));
368 : peer_msg();
369 0 : return -1;
370 : }
371 : return 0;
372 : }
373 :
374 : static int append_to_write_buffer(struct asfd *asfd,
375 : const char *buf, size_t len)
376 : {
377 0 : memcpy(asfd->writebuf+asfd->writebuflen, buf, len);
378 0 : asfd->writebuflen+=len;
379 0 : asfd->writebuf[asfd->writebuflen]='\0';
380 : return 0;
381 : }
382 :
383 0 : static enum append_ret asfd_append_all_to_write_buffer(struct asfd *asfd,
384 : struct iobuf *wbuf)
385 : {
386 0 : switch(asfd->streamtype)
387 : {
388 : case ASFD_STREAM_STANDARD:
389 : {
390 0 : size_t sblen=0;
391 0 : char sbuf[10]="";
392 0 : if(asfd->writebuflen+6+(wbuf->len)>=asfd->bufmaxsize-1)
393 0 : return APPEND_BLOCKED;
394 :
395 0 : snprintf(sbuf, sizeof(sbuf), "%c%04X",
396 0 : wbuf->cmd, (unsigned int)wbuf->len);
397 0 : sblen=strlen(sbuf);
398 0 : append_to_write_buffer(asfd, sbuf, sblen);
399 0 : break;
400 : }
401 : case ASFD_STREAM_LINEBUF:
402 0 : if(asfd->writebuflen+wbuf->len>=asfd->bufmaxsize-1)
403 : return APPEND_BLOCKED;
404 : break;
405 : case ASFD_STREAM_NCURSES_STDIN:
406 : default:
407 0 : logp("%s: unknown asfd stream type in %s: %d\n",
408 : asfd->desc, __func__, asfd->streamtype);
409 0 : return APPEND_ERROR;
410 : }
411 0 : append_to_write_buffer(asfd, wbuf->buf, wbuf->len);
412 : //printf("append %s\n", iobuf_to_printable(wbuf));
413 0 : wbuf->len=0;
414 0 : return APPEND_OK;
415 : }
416 :
417 : #ifdef IPTOS_THROUGHPUT
418 0 : static int asfd_connection_af(struct asfd *asfd)
419 : {
420 : struct sockaddr_storage s;
421 0 : socklen_t slen = sizeof(s);
422 :
423 0 : memset(&s, 0, sizeof(s));
424 0 : if(getsockname(asfd->fd, (struct sockaddr *)&s, &slen)<0)
425 : return 0;
426 0 : return s.ss_family;
427 : }
428 : #endif
429 :
430 0 : static int asfd_set_bulk_packets(struct asfd *asfd)
431 : {
432 : #ifdef IPTOS_THROUGHPUT
433 0 : int opt=IPTOS_THROUGHPUT;
434 0 : if(asfd->fd<0) return -1;
435 :
436 0 : switch(asfd_connection_af(asfd))
437 : {
438 : case AF_INET:
439 0 : if(setsockopt(asfd->fd, IPPROTO_IP, IP_TOS,
440 : (char *)&opt, sizeof(opt))>=0)
441 : break;
442 0 : logp("%s: error: set IPTOS throughput: %s\n",
443 0 : asfd->desc, strerror(errno));
444 0 : return -1;
445 : case AF_INET6:
446 0 : if(setsockopt(asfd->fd, IPPROTO_IPV6, IPV6_TCLASS,
447 : (char *)&opt, sizeof(opt))>=0)
448 : break;
449 0 : logp("%s: error: set IPV6_TCLASS throughput: %s\n",
450 0 : asfd->desc, strerror(errno));
451 0 : return -1;
452 : }
453 : #endif
454 : return 0;
455 : }
456 :
457 0 : static int asfd_read(struct asfd *asfd)
458 : {
459 0 : if(asfd->as->doing_estimate) return 0;
460 0 : while(!asfd->rbuf->buf)
461 : {
462 0 : if(asfd->errors)
463 : return -1;
464 0 : if(asfd->as->read_write(asfd->as))
465 : return -1;
466 : }
467 : return 0;
468 : }
469 :
470 100 : int asfd_read_expect(struct asfd *asfd, enum cmd cmd, const char *expect)
471 : {
472 100 : int ret=0;
473 100 : if(asfd->read(asfd)) return -1;
474 97 : if(asfd->rbuf->cmd!=cmd || strcmp(asfd->rbuf->buf, expect))
475 : {
476 5 : logp("%s: expected '%c:%s', got '%s'\n",
477 : asfd->desc, cmd, expect,
478 : iobuf_to_printable(asfd->rbuf));
479 5 : ret=-1;
480 : }
481 97 : iobuf_free_content(asfd->rbuf);
482 97 : return ret;
483 : }
484 :
485 0 : static int asfd_write(struct asfd *asfd, struct iobuf *wbuf)
486 : {
487 0 : if(asfd->as->doing_estimate) return 0;
488 0 : while(wbuf->len)
489 : {
490 0 : if(asfd->errors)
491 : return -1;
492 0 : if(asfd->append_all_to_write_buffer(asfd, wbuf)==APPEND_ERROR)
493 : return -1;
494 0 : if(asfd->as->write(asfd->as)) return -1;
495 : }
496 : return 0;
497 : }
498 :
499 0 : static int asfd_write_str(struct asfd *asfd, enum cmd wcmd, const char *wsrc)
500 : {
501 : struct iobuf wbuf;
502 0 : wbuf.cmd=wcmd;
503 0 : wbuf.buf=(char *)wsrc;
504 0 : wbuf.len=strlen(wsrc);
505 0 : return asfd->write(asfd, &wbuf);
506 : }
507 :
508 : #ifndef UTEST
509 : static
510 : #endif
511 19 : int asfd_simple_loop(struct asfd *asfd,
512 : struct conf **confs, void *param, const char *caller,
513 : enum asl_ret callback(struct asfd *asfd, struct conf **confs, void *param))
514 : {
515 19 : struct iobuf *rbuf=asfd->rbuf;
516 : while(1)
517 : {
518 750 : iobuf_free_content(rbuf);
519 750 : if(asfd->read(asfd)) goto error;
520 749 : if(!rbuf->buf) continue;
521 30 : if(rbuf->cmd!=CMD_GEN)
522 : {
523 0 : if(rbuf->cmd==CMD_WARNING
524 0 : || rbuf->cmd==CMD_MESSAGE)
525 : {
526 0 : struct cntr *cntr=NULL;
527 0 : if(confs) cntr=get_cntr(confs);
528 0 : log_recvd(rbuf, cntr, 0);
529 : }
530 0 : else if(rbuf->cmd==CMD_INTERRUPT)
531 : {
532 : // Ignore - client wanted to interrupt a file.
533 : }
534 : else
535 : {
536 0 : logp("%s: unexpected command in %s(), called from %s(): %s\n", asfd->desc, __func__, caller, iobuf_to_printable(rbuf));
537 0 : goto error;
538 : }
539 0 : continue;
540 : }
541 30 : switch(callback(asfd, confs, param))
542 : {
543 : case ASL_CONTINUE: break;
544 : case ASL_END_OK:
545 16 : iobuf_free_content(rbuf);
546 16 : return 0;
547 : case ASL_END_OK_RETURN_1:
548 0 : iobuf_free_content(rbuf);
549 0 : return 1;
550 : case ASL_END_ERROR:
551 : default:
552 : goto error;
553 : }
554 : }
555 : error:
556 3 : iobuf_free_content(rbuf);
557 3 : return -1;
558 : }
559 :
560 0 : static void asfd_set_timeout(struct asfd *asfd, int max_network_timeout)
561 : {
562 0 : asfd->max_network_timeout=max_network_timeout;
563 0 : asfd->network_timeout=asfd->max_network_timeout;
564 0 : }
565 :
566 9 : static char *get_asfd_desc(const char *desc, int fd)
567 : {
568 9 : char r[256]="";
569 9 : snprintf(r, sizeof(r), "%s %d", desc, fd);
570 9 : return strdup_w(r, __func__);
571 : }
572 :
573 9 : static int asfd_init(struct asfd *asfd, const char *desc,
574 : struct async *as, int afd, const char *listen,
575 : SSL *assl, enum asfd_streamtype streamtype)
576 : {
577 9 : asfd->as=as;
578 9 : asfd->fd=afd;
579 9 : asfd->ssl=assl;
580 9 : asfd->streamtype=streamtype;
581 9 : asfd->rlsleeptime=10000;
582 9 : asfd->pid=-1;
583 9 : asfd->attempt_reads=1;
584 9 : asfd->bufmaxsize=(ASYNC_BUF_LEN*2)+32;
585 : #ifdef HAVE_WIN32
586 : // Windows craps out if you try to read stdin into a buffer that is
587 : // too big!
588 : if(asfd->fd==fileno(stdin))
589 : asfd->bufmaxsize=4096;
590 : #endif
591 :
592 9 : asfd->parse_readbuf=asfd_parse_readbuf;
593 9 : asfd->append_all_to_write_buffer=asfd_append_all_to_write_buffer;
594 9 : asfd->set_bulk_packets=asfd_set_bulk_packets;
595 9 : asfd->set_timeout=asfd_set_timeout;
596 9 : if(asfd->ssl)
597 : {
598 1 : asfd->do_read=asfd_do_read_ssl;
599 1 : asfd->do_write=asfd_do_write_ssl;
600 : }
601 : else
602 : {
603 8 : asfd->do_read=asfd_do_read;
604 8 : asfd->do_write=asfd_do_write;
605 : #ifdef HAVE_NCURSES
606 8 : if(asfd->streamtype==ASFD_STREAM_NCURSES_STDIN)
607 : {
608 1 : asfd->do_read=asfd_do_read_ncurses;
609 1 : asfd->do_write=asfd_do_write_ncurses;
610 : }
611 : #endif
612 : }
613 9 : asfd->read=asfd_read;
614 9 : asfd->simple_loop=asfd_simple_loop;
615 9 : asfd->write=asfd_write;
616 9 : asfd->write_str=asfd_write_str;
617 :
618 9 : switch(asfd->streamtype)
619 : {
620 : case ASFD_STREAM_STANDARD:
621 2 : asfd->parse_readbuf_specific=parse_readbuf_standard;
622 2 : break;
623 : case ASFD_STREAM_LINEBUF:
624 6 : asfd->parse_readbuf_specific=parse_readbuf_line_buf;
625 6 : break;
626 : #ifdef HAVE_NCURSES
627 : case ASFD_STREAM_NCURSES_STDIN:
628 1 : asfd->parse_readbuf_specific=parse_readbuf_ncurses;
629 1 : break;
630 : #endif
631 : default:
632 0 : logp("%s: unknown asfd stream type in %s: %d\n",
633 : desc, __func__, asfd->streamtype);
634 0 : return -1;
635 : }
636 :
637 9 : if(!(asfd->rbuf=iobuf_alloc())
638 18 : || asfd_alloc_buf(asfd, &asfd->readbuf)
639 18 : || asfd_alloc_buf(asfd, &asfd->writebuf)
640 9 : || !(asfd->desc=get_asfd_desc(desc, asfd->fd))
641 9 : || !(asfd->listen=strdup_w(listen, __func__)))
642 : return -1;
643 : return 0;
644 : }
645 :
646 363 : struct asfd *asfd_alloc(void)
647 : {
648 : struct asfd *asfd;
649 372 : asfd=(struct asfd *)calloc_w(1, sizeof(struct asfd), __func__);
650 372 : if(asfd)
651 372 : asfd->fd=-1;
652 363 : return asfd;
653 : }
654 :
655 372 : void asfd_close(struct asfd *asfd)
656 : {
657 372 : if(!asfd) return;
658 372 : if(asfd->ssl && asfd->fd>=0)
659 : {
660 1 : set_blocking(asfd->fd);
661 : // I do not think this SSL_shutdown stuff works right.
662 : // Ignore it for now.
663 : #ifndef HAVE_WIN32
664 1 : signal(SIGPIPE, SIG_IGN);
665 : #endif
666 1 : if(!SSL_shutdown(asfd->ssl))
667 : {
668 0 : shutdown(asfd->fd, 1);
669 0 : SSL_shutdown(asfd->ssl);
670 : }
671 : }
672 372 : if(asfd->ssl)
673 : {
674 1 : SSL_free(asfd->ssl);
675 1 : asfd->ssl=NULL;
676 : }
677 372 : close_fd(&asfd->fd);
678 : }
679 :
680 372 : static void asfd_free_content(struct asfd *asfd)
681 : {
682 372 : asfd_close(asfd);
683 372 : iobuf_free(&asfd->rbuf);
684 372 : free_w(&asfd->readbuf);
685 372 : free_w(&asfd->writebuf);
686 372 : free_w(&asfd->desc);
687 372 : free_w(&asfd->client);
688 372 : free_w(&asfd->listen);
689 372 : incoming_free(&asfd->in);
690 372 : blist_free(&asfd->blist);
691 372 : }
692 :
693 374 : void asfd_free(struct asfd **asfd)
694 : {
695 374 : if(!asfd || !*asfd) return;
696 372 : asfd_free_content(*asfd);
697 372 : free_v((void **)asfd);
698 : }
699 :
700 10 : static struct asfd *do_setup_asfd(struct async *as,
701 : const char *desc, int *fd, const char *listen,
702 : SSL *ssl, enum asfd_streamtype streamtype)
703 : {
704 10 : struct asfd *asfd=NULL;
705 :
706 10 : if(!fd || *fd<0)
707 : {
708 1 : logp("Given invalid descriptor in %s\n", __func__);
709 1 : goto error;
710 : }
711 :
712 9 : set_non_blocking(*fd);
713 9 : if(!(asfd=asfd_alloc())
714 9 : || asfd_init(asfd, desc, as, *fd, listen, ssl, streamtype))
715 : goto error;
716 9 : *fd=-1;
717 9 : as->asfd_add(as, asfd);
718 9 : return asfd;
719 : error:
720 1 : asfd_free(&asfd);
721 1 : return NULL;
722 : }
723 :
724 1 : struct asfd *setup_asfd_ssl(struct async *as,
725 : const char *desc, int *fd, SSL *ssl)
726 : {
727 1 : return do_setup_asfd(as, desc, fd, /*listen*/"",
728 : ssl, ASFD_STREAM_STANDARD);
729 : }
730 :
731 2 : struct asfd *setup_asfd(struct async *as,
732 : const char *desc, int *fd, const char *listen)
733 : {
734 2 : return do_setup_asfd(as, desc, fd, listen,
735 : /*ssl*/NULL, ASFD_STREAM_STANDARD);
736 : }
737 :
738 : static struct asfd *setup_asfd_linebuf(struct async *as,
739 : const char *desc, int *fd)
740 : {
741 6 : return do_setup_asfd(as, desc, fd, /*listen*/"",
742 : /*ssl*/NULL, ASFD_STREAM_LINEBUF);
743 : }
744 :
745 1 : struct asfd *setup_asfd_linebuf_read(struct async *as,
746 : const char *desc, int *fd)
747 : {
748 3 : return setup_asfd_linebuf(as, desc, fd);
749 : }
750 :
751 1 : struct asfd *setup_asfd_linebuf_write(struct async *as,
752 : const char *desc, int *fd)
753 : {
754 : struct asfd *asfd;
755 3 : if((asfd=setup_asfd_linebuf(as, desc, fd)))
756 3 : asfd->attempt_reads=0;
757 1 : return asfd;
758 : }
759 :
760 0 : static struct asfd *fileno_error(const char *func)
761 : {
762 0 : logp("fileno error in %s: %s\n", func, strerror(errno));
763 0 : return NULL;
764 : }
765 :
766 2 : struct asfd *setup_asfd_stdin(struct async *as)
767 : {
768 2 : int fd=fileno(stdin);
769 2 : if(fd<0)
770 0 : return fileno_error(__func__);
771 2 : return setup_asfd_linebuf_read(as, "stdin", &fd);
772 : }
773 :
774 2 : struct asfd *setup_asfd_stdout(struct async *as)
775 : {
776 2 : int fd=fileno(stdout);
777 2 : if(fd<0)
778 0 : return fileno_error(__func__);
779 : return setup_asfd_linebuf_write(as, "stdout", &fd);
780 : }
781 :
782 1 : struct asfd *setup_asfd_ncurses_stdin(struct async *as)
783 : {
784 1 : int fd=fileno(stdin);
785 1 : if(fd<0)
786 0 : return fileno_error(__func__);
787 1 : return do_setup_asfd(as, "stdin", &fd, /*listen*/"",
788 : /*ssl=*/NULL, ASFD_STREAM_NCURSES_STDIN);
789 : }
790 :
791 : // Want to make sure that we are listening for reads too - this will let us
792 : // exit promptly if the client was killed.
793 0 : static int read_and_write(struct asfd *asfd)
794 : {
795 : // Protect against getting stuck in loops where we are trying to
796 : // flush buffers, but keep getting the same error.
797 0 : if(asfd->as->read_write(asfd->as))
798 : return -1;
799 0 : if(!asfd->rbuf->buf) return 0;
800 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
801 : return -1;
802 : }
803 :
804 0 : int asfd_flush_asio(struct asfd *asfd)
805 : {
806 0 : while(asfd && asfd->writebuflen>0)
807 : {
808 0 : if(asfd->errors)
809 : return -1;
810 0 : if(read_and_write(asfd))
811 : return -1;
812 : }
813 : return 0;
814 : }
815 :
816 84 : int asfd_write_wrapper(struct asfd *asfd, struct iobuf *wbuf)
817 : {
818 : while(1)
819 : {
820 84 : if(asfd->errors)
821 : return -1;
822 84 : switch(asfd->append_all_to_write_buffer(asfd, wbuf))
823 : {
824 : case APPEND_OK: return 0;
825 : case APPEND_BLOCKED: break;
826 3 : default: return -1;
827 : }
828 0 : if(read_and_write(asfd)) return -1;
829 : }
830 : return 0;
831 : }
832 :
833 84 : int asfd_write_wrapper_str(struct asfd *asfd, enum cmd wcmd, const char *wsrc)
834 : {
835 : static struct iobuf wbuf;
836 84 : iobuf_from_str(&wbuf, wcmd, (char *)wsrc);
837 84 : return asfd_write_wrapper(asfd, &wbuf);
838 : }
839 :
|