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

Generated by: LCOV version 1.13