LCOV - code coverage report
Current view: top level - src - asfd.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 132 370 35.7 %
Date: 2022-12-03 01:09:05 Functions: 18 40 45.0 %

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

Generated by: LCOV version 1.13