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