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 18 : 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 : logp_ssl_err(
220 : "%s: network read problem in %s: %d - %d=%s\n",
221 : asfd->desc, __func__,
222 0 : e, errno, strerror(errno));
223 : peer_msg();
224 : goto error;
225 : }
226 : return 0;
227 : error:
228 0 : truncate_readbuf(asfd);
229 0 : return -1;
230 : }
231 :
232 : // Return 0 for OK to write, non-zero for not OK to write.
233 0 : static int check_ratelimit(struct asfd *asfd)
234 : {
235 : float f;
236 : time_t diff;
237 0 : if(!asfd->rlstart) asfd->rlstart=time(NULL);
238 0 : if((diff=asfd->as->now-asfd->rlstart)<0)
239 : {
240 : // It is possible that the clock changed. Reset ourselves.
241 0 : asfd->as->now=asfd->rlstart;
242 0 : asfd->rlbytes=0;
243 0 : logp("Looks like the clock went back in time since starting. "
244 : "Resetting ratelimit\n");
245 0 : return 0;
246 : }
247 0 : if(!diff) return 0; // Need to get started somehow.
248 0 : f=(asfd->rlbytes)/diff; // Bytes per second.
249 :
250 0 : if(f>=asfd->ratelimit)
251 : {
252 : #ifdef HAVE_WIN32
253 : // Windows Sleep is milliseconds, usleep is microseconds.
254 : // Do some conversion.
255 : Sleep(asfd->rlsleeptime/1000);
256 : #else
257 0 : usleep(asfd->rlsleeptime);
258 : #endif
259 : // If sleeping, increase the sleep time.
260 0 : if((asfd->rlsleeptime*=2)>=500000) asfd->rlsleeptime=500000;
261 : return 1;
262 : }
263 : // If not sleeping, decrease the sleep time.
264 0 : if((asfd->rlsleeptime/=2)<=9999) asfd->rlsleeptime=10000;
265 : return 0;
266 : }
267 :
268 0 : static int asfd_do_write(struct asfd *asfd)
269 : {
270 : ssize_t w;
271 0 : if(asfd->ratelimit && check_ratelimit(asfd)) return 0;
272 :
273 0 : w=write(asfd->fd, asfd->writebuf, asfd->writebuflen);
274 0 : if(w<0)
275 : {
276 0 : if(errno==EAGAIN || errno==EINTR)
277 : return 0;
278 0 : logp("%s: Got error in %s, (%d=%s)\n", __func__,
279 : asfd->desc, errno, strerror(errno));
280 0 : return -1;
281 : }
282 0 : else if(!w)
283 : {
284 0 : logp("%s: Wrote nothing in %s\n", asfd->desc, __func__);
285 0 : return -1;
286 : }
287 0 : if(asfd->ratelimit) asfd->rlbytes+=w;
288 0 : asfd->sent+=w;
289 : /*
290 : {
291 : char buf[100000]="";
292 : snprintf(buf, w+1, "%s", asfd->writebuf);
293 : printf("wrote %d: %s\n", w, buf);
294 : }
295 : */
296 :
297 0 : memmove(asfd->writebuf, asfd->writebuf+w, asfd->writebuflen-w);
298 0 : asfd->writebuflen-=w;
299 0 : return 0;
300 : }
301 :
302 0 : static int asfd_do_write_ssl(struct asfd *asfd)
303 : {
304 : int e;
305 : ssize_t w;
306 :
307 0 : asfd->write_blocked_on_read=0;
308 :
309 0 : if(asfd->ratelimit && check_ratelimit(asfd)) return 0;
310 0 : ERR_clear_error();
311 0 : w=SSL_write(asfd->ssl, asfd->writebuf, asfd->writebuflen);
312 :
313 0 : switch((e=SSL_get_error(asfd->ssl, w)))
314 : {
315 : case SSL_ERROR_NONE:
316 : /*
317 : {
318 : char buf[100000]="";
319 : snprintf(buf, w+1, "%s", asfd->writebuf);
320 : printf("wrote %d: %s\n", w, buf);
321 : }
322 : */
323 0 : if(asfd->ratelimit) asfd->rlbytes+=w;
324 0 : memmove(asfd->writebuf,
325 0 : asfd->writebuf+w, asfd->writebuflen-w);
326 0 : asfd->writebuflen-=w;
327 0 : asfd->sent+=w;
328 0 : break;
329 : case SSL_ERROR_WANT_WRITE:
330 : break;
331 : case SSL_ERROR_WANT_READ:
332 0 : asfd->write_blocked_on_read=1;
333 0 : break;
334 : case SSL_ERROR_SYSCALL:
335 0 : if(errno==EAGAIN || errno==EINTR)
336 : break;
337 0 : logp("%s: Got network write error\n",
338 : asfd->desc);
339 : // Fall through to read problem
340 : default:
341 0 : logp_ssl_err(
342 : "%s: network write problem in %s: %d - %d=%s\n",
343 : asfd->desc, __func__,
344 0 : e, errno, strerror(errno));
345 : peer_msg();
346 0 : return -1;
347 : }
348 : return 0;
349 : }
350 :
351 0 : static int append_to_write_buffer(struct asfd *asfd,
352 : const char *buf, size_t len)
353 : {
354 0 : memcpy(asfd->writebuf+asfd->writebuflen, buf, len);
355 0 : asfd->writebuflen+=len;
356 0 : asfd->writebuf[asfd->writebuflen]='\0';
357 0 : return 0;
358 : }
359 :
360 0 : static enum append_ret asfd_append_all_to_write_buffer(struct asfd *asfd,
361 : struct iobuf *wbuf)
362 : {
363 0 : switch(asfd->streamtype)
364 : {
365 : case ASFD_STREAM_STANDARD:
366 : {
367 0 : size_t sblen=0;
368 0 : char sbuf[10]="";
369 0 : if(asfd->writebuflen+6+(wbuf->len)>=asfd->bufmaxsize-1)
370 0 : return APPEND_BLOCKED;
371 :
372 0 : snprintf(sbuf, sizeof(sbuf), "%c%04X",
373 0 : wbuf->cmd, (unsigned int)wbuf->len);
374 0 : sblen=strlen(sbuf);
375 0 : append_to_write_buffer(asfd, sbuf, sblen);
376 0 : break;
377 : }
378 : case ASFD_STREAM_LINEBUF:
379 0 : if(asfd->writebuflen+wbuf->len>=asfd->bufmaxsize-1)
380 : return APPEND_BLOCKED;
381 : break;
382 : case ASFD_STREAM_NCURSES_STDIN:
383 : default:
384 0 : logp("%s: unknown asfd stream type in %s: %d\n",
385 : asfd->desc, __func__, asfd->streamtype);
386 0 : return APPEND_ERROR;
387 : }
388 0 : append_to_write_buffer(asfd, wbuf->buf, wbuf->len);
389 : //printf("append %d: %s\n", wbuf->len, iobuf_to_printable(wbuf));
390 0 : wbuf->len=0;
391 0 : return APPEND_OK;
392 : }
393 :
394 : #ifdef IPTOS_THROUGHPUT
395 0 : static int asfd_connection_af(struct asfd *asfd)
396 : {
397 : struct sockaddr_storage s;
398 0 : socklen_t slen = sizeof(s);
399 :
400 : memset(&s, 0, sizeof(s));
401 0 : if(getsockname(asfd->fd, (struct sockaddr *)&s, &slen)<0)
402 : return 0;
403 0 : return s.ss_family;
404 : }
405 : #endif
406 :
407 0 : static int asfd_set_bulk_packets(struct asfd *asfd)
408 : {
409 : #ifdef IPTOS_THROUGHPUT
410 0 : int opt=IPTOS_THROUGHPUT;
411 0 : if(asfd->fd<0) return -1;
412 :
413 0 : switch(asfd_connection_af(asfd))
414 : {
415 : case AF_INET:
416 0 : if(setsockopt(asfd->fd, IPPROTO_IP, IP_TOS,
417 : (char *)&opt, sizeof(opt))>=0)
418 : break;
419 0 : logp("%s: error: set IPTOS throughput: %s\n",
420 0 : asfd->desc, strerror(errno));
421 0 : return -1;
422 : case AF_INET6:
423 0 : if(setsockopt(asfd->fd, IPPROTO_IPV6, IPV6_TCLASS,
424 : (char *)&opt, sizeof(opt))>=0)
425 : break;
426 0 : logp("%s: error: set IPV6_TCLASS throughput: %s\n",
427 0 : asfd->desc, strerror(errno));
428 0 : return -1;
429 : }
430 : #endif
431 : return 0;
432 : }
433 :
434 0 : static int asfd_read(struct asfd *asfd)
435 : {
436 0 : if(asfd->as->doing_estimate) return 0;
437 0 : while(!asfd->rbuf->buf)
438 0 : if(asfd->as->read_write(asfd->as)) return -1;
439 : return 0;
440 : }
441 :
442 100 : int asfd_read_expect(struct asfd *asfd, enum cmd cmd, const char *expect)
443 : {
444 100 : int ret=0;
445 100 : if(asfd->read(asfd)) return -1;
446 97 : if(asfd->rbuf->cmd!=cmd || strcmp(asfd->rbuf->buf, expect))
447 : {
448 5 : logp("%s: expected '%c:%s', got '%s'\n",
449 : asfd->desc, cmd, expect,
450 : iobuf_to_printable(asfd->rbuf));
451 5 : ret=-1;
452 : }
453 97 : iobuf_free_content(asfd->rbuf);
454 97 : return ret;
455 : }
456 :
457 0 : static int asfd_write(struct asfd *asfd, struct iobuf *wbuf)
458 : {
459 0 : if(asfd->as->doing_estimate) return 0;
460 0 : while(wbuf->len)
461 : {
462 0 : if(asfd->append_all_to_write_buffer(asfd, wbuf)==APPEND_ERROR)
463 : return -1;
464 0 : if(asfd->as->write(asfd->as)) return -1;
465 : }
466 : return 0;
467 : }
468 :
469 0 : static int asfd_write_str(struct asfd *asfd, enum cmd wcmd, const char *wsrc)
470 : {
471 : struct iobuf wbuf;
472 0 : wbuf.cmd=wcmd;
473 0 : wbuf.buf=(char *)wsrc;
474 0 : wbuf.len=strlen(wsrc);
475 0 : return asfd->write(asfd, &wbuf);
476 : }
477 :
478 : #ifndef UTEST
479 : static
480 : #endif
481 17 : int asfd_simple_loop(struct asfd *asfd,
482 : struct conf **confs, void *param, const char *caller,
483 : enum asl_ret callback(struct asfd *asfd, struct conf **confs, void *param))
484 : {
485 17 : struct iobuf *rbuf=asfd->rbuf;
486 : while(1)
487 : {
488 745 : iobuf_free_content(rbuf);
489 745 : if(asfd->read(asfd)) goto error;
490 744 : if(!rbuf->buf) continue;
491 25 : if(rbuf->cmd!=CMD_GEN)
492 : {
493 0 : if(rbuf->cmd==CMD_WARNING
494 0 : || rbuf->cmd==CMD_MESSAGE)
495 : {
496 0 : struct cntr *cntr=NULL;
497 0 : if(confs) cntr=get_cntr(confs);
498 0 : log_recvd(rbuf, cntr, 0);
499 : }
500 0 : else if(rbuf->cmd==CMD_INTERRUPT)
501 : {
502 : // Ignore - client wanted to interrupt a file.
503 : }
504 : else
505 : {
506 0 : logp("%s: unexpected command in %s(), called from %s(): %s\n", asfd->desc, __func__, caller, iobuf_to_printable(rbuf));
507 0 : goto error;
508 : }
509 0 : continue;
510 : }
511 25 : switch(callback(asfd, confs, param))
512 : {
513 : case ASL_CONTINUE: break;
514 : case ASL_END_OK:
515 14 : iobuf_free_content(rbuf);
516 14 : return 0;
517 : case ASL_END_OK_RETURN_1:
518 0 : iobuf_free_content(rbuf);
519 0 : return 1;
520 : case ASL_END_ERROR:
521 : default:
522 : goto error;
523 : }
524 : }
525 : error:
526 3 : iobuf_free_content(rbuf);
527 3 : return -1;
528 : }
529 :
530 0 : static void asfd_set_timeout(struct asfd *asfd, int max_network_timeout)
531 : {
532 0 : asfd->max_network_timeout=max_network_timeout;
533 0 : asfd->network_timeout=asfd->max_network_timeout;
534 0 : }
535 :
536 9 : static int asfd_init(struct asfd *asfd, const char *desc,
537 : struct async *as, int afd, int port,
538 : SSL *assl, enum asfd_streamtype streamtype)
539 : {
540 9 : asfd->as=as;
541 9 : asfd->fd=afd;
542 9 : asfd->port=port;
543 9 : asfd->ssl=assl;
544 9 : asfd->streamtype=streamtype;
545 9 : asfd->rlsleeptime=10000;
546 9 : asfd->pid=-1;
547 9 : asfd->attempt_reads=1;
548 9 : asfd->bufmaxsize=(ASYNC_BUF_LEN*2)+32;
549 : #ifdef HAVE_WIN32
550 : // Windows craps out if you try to read stdin into a buffer that is
551 : // too big!
552 : if(asfd->fd==fileno(stdin))
553 : asfd->bufmaxsize=4096;
554 : #endif
555 :
556 9 : asfd->parse_readbuf=asfd_parse_readbuf;
557 9 : asfd->append_all_to_write_buffer=asfd_append_all_to_write_buffer;
558 9 : asfd->set_bulk_packets=asfd_set_bulk_packets;
559 9 : asfd->set_timeout=asfd_set_timeout;
560 9 : if(asfd->ssl)
561 : {
562 1 : asfd->do_read=asfd_do_read_ssl;
563 1 : asfd->do_write=asfd_do_write_ssl;
564 : }
565 : else
566 : {
567 8 : asfd->do_read=asfd_do_read;
568 8 : asfd->do_write=asfd_do_write;
569 : #ifdef HAVE_NCURSES
570 8 : if(asfd->streamtype==ASFD_STREAM_NCURSES_STDIN)
571 : {
572 1 : asfd->do_read=asfd_do_read_ncurses;
573 1 : asfd->do_write=asfd_do_write_ncurses;
574 : }
575 : #endif
576 : }
577 9 : asfd->read=asfd_read;
578 9 : asfd->simple_loop=asfd_simple_loop;
579 9 : asfd->write=asfd_write;
580 9 : asfd->write_str=asfd_write_str;
581 :
582 9 : switch(asfd->streamtype)
583 : {
584 : case ASFD_STREAM_STANDARD:
585 2 : asfd->parse_readbuf_specific=parse_readbuf_standard;
586 2 : break;
587 : case ASFD_STREAM_LINEBUF:
588 6 : asfd->parse_readbuf_specific=parse_readbuf_line_buf;
589 6 : break;
590 : #ifdef HAVE_NCURSES
591 : case ASFD_STREAM_NCURSES_STDIN:
592 1 : asfd->parse_readbuf_specific=parse_readbuf_ncurses;
593 1 : break;
594 : #endif
595 : default:
596 0 : logp("%s: unknown asfd stream type in %s: %d\n",
597 : desc, __func__, asfd->streamtype);
598 0 : return -1;
599 : }
600 :
601 9 : if(!(asfd->rbuf=iobuf_alloc())
602 9 : || asfd_alloc_buf(asfd, &asfd->readbuf)
603 9 : || asfd_alloc_buf(asfd, &asfd->writebuf)
604 9 : || !(asfd->desc=strdup_w(desc, __func__)))
605 : return -1;
606 : return 0;
607 : }
608 :
609 361 : struct asfd *asfd_alloc(void)
610 : {
611 370 : return (struct asfd *)calloc_w(1, sizeof(struct asfd), __func__);
612 : }
613 :
614 370 : void asfd_close(struct asfd *asfd)
615 : {
616 740 : if(!asfd) return;
617 370 : if(asfd->ssl && asfd->fd>=0)
618 : {
619 1 : set_blocking(asfd->fd);
620 : // I do not think this SSL_shutdown stuff works right.
621 : // Ignore it for now.
622 : #ifndef HAVE_WIN32
623 1 : signal(SIGPIPE, SIG_IGN);
624 : #endif
625 1 : if(!SSL_shutdown(asfd->ssl))
626 : {
627 0 : shutdown(asfd->fd, 1);
628 0 : SSL_shutdown(asfd->ssl);
629 : }
630 : }
631 370 : if(asfd->ssl)
632 : {
633 1 : SSL_free(asfd->ssl);
634 1 : asfd->ssl=NULL;
635 : }
636 370 : close_fd(&asfd->fd);
637 : }
638 :
639 370 : static void asfd_free_content(struct asfd *asfd)
640 : {
641 370 : asfd_close(asfd);
642 370 : iobuf_free(&asfd->rbuf);
643 370 : free_w(&asfd->readbuf);
644 370 : free_w(&asfd->writebuf);
645 370 : free_w(&asfd->desc);
646 370 : free_w(&asfd->client);
647 370 : incoming_free(&asfd->in);
648 370 : blist_free(&asfd->blist);
649 370 : }
650 :
651 372 : void asfd_free(struct asfd **asfd)
652 : {
653 744 : if(!asfd || !*asfd) return;
654 370 : asfd_free_content(*asfd);
655 370 : free_v((void **)asfd);
656 : }
657 :
658 10 : static struct asfd *do_setup_asfd(struct async *as,
659 : const char *desc, int *fd, int port,
660 : SSL *ssl, enum asfd_streamtype streamtype)
661 : {
662 10 : struct asfd *asfd=NULL;
663 :
664 10 : if(!fd || *fd<0)
665 : {
666 1 : logp("Given invalid descriptor in %s\n", __func__);
667 1 : goto error;
668 : }
669 :
670 9 : set_non_blocking(*fd);
671 9 : if(!(asfd=asfd_alloc())
672 9 : || asfd_init(asfd, desc, as, *fd, port, ssl, streamtype))
673 : goto error;
674 9 : *fd=-1;
675 9 : as->asfd_add(as, asfd);
676 9 : return asfd;
677 : error:
678 1 : asfd_free(&asfd);
679 1 : return NULL;
680 : }
681 :
682 1 : struct asfd *setup_asfd_ssl(struct async *as,
683 : const char *desc, int *fd, SSL *ssl)
684 : {
685 1 : return do_setup_asfd(as, desc, fd, /*port*/-1,
686 : ssl, ASFD_STREAM_STANDARD);
687 : }
688 :
689 2 : struct asfd *setup_asfd(struct async *as,
690 : const char *desc, int *fd, int port)
691 : {
692 2 : return do_setup_asfd(as, desc, fd, port,
693 : /*ssl*/NULL, ASFD_STREAM_STANDARD);
694 : }
695 :
696 : static struct asfd *setup_asfd_linebuf(struct async *as,
697 : const char *desc, int *fd)
698 : {
699 6 : return do_setup_asfd(as, desc, fd, -1,
700 : /*ssl*/NULL, ASFD_STREAM_LINEBUF);
701 : }
702 :
703 1 : struct asfd *setup_asfd_linebuf_read(struct async *as,
704 : const char *desc, int *fd)
705 : {
706 1 : return setup_asfd_linebuf(as, desc, fd);
707 : }
708 :
709 3 : struct asfd *setup_asfd_linebuf_write(struct async *as,
710 : const char *desc, int *fd)
711 : {
712 : struct asfd *asfd;
713 3 : if((asfd=setup_asfd_linebuf(as, desc, fd)))
714 3 : asfd->attempt_reads=0;
715 3 : return asfd;
716 : }
717 :
718 0 : static struct asfd *fileno_error(const char *func)
719 : {
720 0 : logp("fileno error in %s: %s\n", func, strerror(errno));
721 0 : return NULL;
722 : }
723 :
724 2 : struct asfd *setup_asfd_stdin(struct async *as)
725 : {
726 2 : int fd=fileno(stdin);
727 2 : if(fd<0)
728 0 : return fileno_error(__func__);
729 2 : return setup_asfd_linebuf_read(as, "stdin", &fd);
730 : }
731 :
732 2 : struct asfd *setup_asfd_stdout(struct async *as)
733 : {
734 2 : int fd=fileno(stdout);
735 2 : if(fd<0)
736 0 : return fileno_error(__func__);
737 2 : return setup_asfd_linebuf_write(as, "stdout", &fd);
738 : }
739 :
740 1 : struct asfd *setup_asfd_ncurses_stdin(struct async *as)
741 : {
742 1 : int fd=fileno(stdin);
743 1 : if(fd<0)
744 0 : return fileno_error(__func__);
745 1 : return do_setup_asfd(as, "stdin", &fd, -1,
746 : /*ssl=*/NULL, ASFD_STREAM_NCURSES_STDIN);
747 : }
748 :
749 : // Want to make sure that we are listening for reads too - this will let us
750 : // exit promptly if the client was killed.
751 0 : static int read_and_write(struct asfd *asfd)
752 : {
753 0 : if(asfd->as->read_write(asfd->as)) return -1;
754 0 : if(!asfd->rbuf->buf) return 0;
755 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
756 : return -1;
757 : }
758 :
759 0 : int asfd_flush_asio(struct asfd *asfd)
760 : {
761 0 : while(asfd && asfd->writebuflen>0)
762 0 : if(read_and_write(asfd)) return -1;
763 : return 0;
764 : }
765 :
766 84 : int asfd_write_wrapper(struct asfd *asfd, struct iobuf *wbuf)
767 : {
768 : while(1)
769 : {
770 84 : switch(asfd->append_all_to_write_buffer(asfd, wbuf))
771 : {
772 : case APPEND_OK: return 0;
773 : case APPEND_BLOCKED: break;
774 3 : default: return -1;
775 : }
776 0 : if(read_and_write(asfd)) return -1;
777 : }
778 : return 0;
779 : }
780 :
781 84 : int asfd_write_wrapper_str(struct asfd *asfd, enum cmd wcmd, const char *wsrc)
782 : {
783 : static struct iobuf wbuf;
784 84 : iobuf_from_str(&wbuf, wcmd, (char *)wsrc);
785 84 : return asfd_write_wrapper(asfd, &wbuf);
786 : }
787 :
|