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