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