LCOV - code coverage report
Current view: top level - src - async.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 32 126 25.4 %
Date: 2018-03-30 Functions: 5 11 45.5 %

          Line data    Source code
       1             : #include "burp.h"
       2             : #include "alloc.h"
       3             : #include "asfd.h"
       4             : #include "async.h"
       5             : #include "handy.h"
       6             : #include "iobuf.h"
       7             : #include "log.h"
       8             : 
       9         137 : void async_free(struct async **as)
      10             : {
      11         287 :         if(!as || !*as) return;
      12         147 :         free_v((void **)as);
      13             : }
      14             : 
      15           0 : static void async_settimers(struct async *as, int sec, int usec)
      16             : {
      17           0 :         as->setsec=sec;
      18           0 :         as->setusec=usec;
      19           0 : }
      20             : 
      21             : // The normal server and client processes will just exit on error within
      22             : // async_io, but the champ chooser server needs to manage client fds and
      23             : // remove them from its list if one of them had a problem.
      24             : static int asfd_problem(struct asfd *asfd)
      25             : {
      26           0 :         asfd->want_to_remove++;
      27           0 :         asfd->as->last_time=asfd->as->now;
      28             :         return -1;
      29             : }
      30             : 
      31             : #ifdef HAVE_WIN32
      32             : // Jesus H. Christ. How does anybody ever get anything done with windows?
      33             : // The normal async stuff does not work for the client monitor, because the
      34             : // windows select() only supports sockets, and windows stdin/stdout are not
      35             : // sockets.
      36             : // It seems to be impossible to do non-blocking i/o on windows stdin.
      37             : // If you have a windows console, you can use PeekConsoleInput to look at
      38             : // events in order to look ahead. This is not looking at stdin, which means
      39             : // that this does not work for ssh via cygwin.
      40             : static int windows_stupidity_hacks(struct asfd *asfd,
      41             :         fd_set *fsr, fd_set *fsw)
      42             : {
      43             :         if(asfd->do_read && asfd->fd==fileno(stdin))
      44             :         {
      45             :                 DWORD len=0;
      46             :                 INPUT_RECORD irec;
      47             :                 HANDLE han=GetStdHandle(STD_INPUT_HANDLE);
      48             : 
      49             :                 switch(WaitForSingleObject(han, 0))
      50             :                 {
      51             :                         case WAIT_OBJECT_0:
      52             :                                 if(!PeekConsoleInput(han, &irec, 1, &len))
      53             :                                         break;
      54             :                                 if(irec.EventType==KEY_EVENT
      55             :                                   && irec.Event.KeyEvent.bKeyDown)
      56             :                                 {
      57             :                                         // This will block until the user hits
      58             :                                         // the return key.
      59             :                                         if(asfd->do_read(asfd)
      60             :                                           || asfd->parse_readbuf(asfd))
      61             :                                                 return asfd_problem(asfd);
      62             :                                 }
      63             :                                 else
      64             :                                 {
      65             :                                         // Purge event we are not interested in.
      66             :                                         ReadConsoleInput(han, &irec, 1, &len);
      67             :                                 }
      68             :                                 break;
      69             :                         default:
      70             :                                 break;
      71             :                 }
      72             :         }
      73             :         if(asfd->do_write && asfd->fd==fileno(stdout))
      74             :         {
      75             :                 // This is saying that we think that stdout is always OK to
      76             :                 // write to. Maybe this will not work all the time.
      77             :                 FD_SET((unsigned int)asfd->fd, fsw);
      78             :         }
      79             :         return 0;
      80             : }
      81             : #endif
      82             : 
      83           0 : static int async_io(struct async *as, int doread)
      84             : {
      85           0 :         int mfd=-1;
      86             :         fd_set fsr;
      87             :         fd_set fsw;
      88             :         fd_set fse;
      89           0 :         int dosomething=0;
      90             :         struct timeval tval;
      91           0 :         struct asfd *asfd;
      92             :         static int s=0;
      93             : 
      94           0 :         as->now=time(NULL);
      95           0 :         if(!as->last_time) as->last_time=as->now;
      96             : 
      97           0 :         if(as->doing_estimate) goto end;
      98             : 
      99           0 :         FD_ZERO(&fsr);
     100           0 :         FD_ZERO(&fsw);
     101           0 :         FD_ZERO(&fse);
     102             : 
     103           0 :         tval.tv_sec=as->setsec;
     104           0 :         tval.tv_usec=as->setusec;
     105             : 
     106           0 :         for(asfd=as->asfd; asfd; asfd=asfd->next)
     107             :         {
     108           0 :                 if(asfd->attempt_reads)
     109           0 :                         asfd->doread=doread;
     110             :                 else
     111           0 :                         asfd->doread=0;
     112             : 
     113           0 :                 asfd->dowrite=0;
     114             : 
     115           0 :                 if(doread)
     116             :                 {
     117           0 :                         if(asfd->parse_readbuf(asfd))
     118           0 :                                 return asfd_problem(asfd);
     119           0 :                         if(asfd->rbuf->buf || asfd->read_blocked_on_write)
     120           0 :                                 asfd->doread=0;
     121             :                 }
     122             : 
     123           0 :                 if(asfd->writebuflen && !asfd->write_blocked_on_read)
     124           0 :                         asfd->dowrite++; // The write buffer is not yet empty.
     125             : 
     126           0 :                 if(!asfd->doread && !asfd->dowrite) continue;
     127             : 
     128             : #ifdef HAVE_WIN32
     129             :                 if(asfd->fd==fileno(stdin)
     130             :                   || asfd->fd==fileno(stdout))
     131             :                 {
     132             :                         dosomething++;
     133             :                         continue;
     134             :                 }
     135             : #endif
     136             : 
     137           0 :                 add_fd_to_sets(asfd->fd, asfd->doread?&fsr:NULL,
     138           0 :                         asfd->dowrite?&fsw:NULL, &fse, &mfd);
     139             : 
     140           0 :                 dosomething++;
     141             :         }
     142           0 :         if(!dosomething) goto end;
     143             : /*
     144             :         for(asfd=as->asfd; asfd; asfd=asfd->next)
     145             :         {
     146             :                 printf("%s: %d %d %d %d\n", asfd->desc,
     147             :                         asfd->doread, asfd->dowrite,
     148             :                         asfd->readbuflen, asfd->writebuflen);
     149             :         }
     150             : */
     151             : 
     152           0 :         if(mfd>0)
     153             :         {
     154           0 :                 errno=0;
     155           0 :                 s=select(mfd+1, &fsr, &fsw, &fse, &tval);
     156           0 :                 if(errno==EAGAIN || errno==EINTR) goto end;
     157             : 
     158           0 :                 if(s<0)
     159             :                 {
     160           0 :                         logp("select error in %s: %s\n", __func__,
     161             :                                 strerror(errno));
     162           0 :                         as->last_time=as->now;
     163           0 :                         return -1;
     164             :                 }
     165             :         }
     166             : 
     167           0 :         for(asfd=as->asfd; asfd; asfd=asfd->next)
     168             :         {
     169             : #ifdef HAVE_WIN32
     170             :                 if(windows_stupidity_hacks(asfd, &fsr, &fsw))
     171             :                         return -1;
     172             : #endif
     173           0 :                 if(FD_ISSET(asfd->fd, &fse))
     174             :                 {
     175           0 :                         switch(asfd->fdtype)
     176             :                         {
     177             :                                 case ASFD_FD_SERVER_LISTEN_MAIN:
     178             :                                 case ASFD_FD_SERVER_LISTEN_STATUS:
     179           0 :                                         as->last_time=as->now;
     180           0 :                                         return -1;
     181             :                                 default:
     182             : #ifdef _AIX
     183             :                                         /* On AIX, for some weird reason,
     184             :                                          * writing the stats file makes the
     185             :                                          * socket show up in fse, despite
     186             :                                          * everything being fine. We ignore
     187             :                                          * it.
     188             :                                          */
     189             :                                         if(strncmp(asfd->desc, "stats file",
     190             :                                                 sizeof("stats file")))
     191             :                                         {
     192             :                                                 logp("%s: had an exception\n",
     193             :                                                         asfd->desc);
     194             :                                                 return asfd_problem(asfd);
     195             :                                         }
     196             : #else
     197           0 :                                         logp("%s: had an exception\n",
     198             :                                                 asfd->desc);
     199           0 :                                         return asfd_problem(asfd);
     200             : #endif /* _AIX */
     201             :                         }
     202             :                 }
     203             : 
     204           0 :                 if(asfd->doread && FD_ISSET(asfd->fd, &fsr)) // Able to read.
     205             :                 {
     206           0 :                         asfd->network_timeout=asfd->max_network_timeout;
     207           0 :                         switch(asfd->fdtype)
     208             :                         {
     209             :                                 case ASFD_FD_SERVER_LISTEN_MAIN:
     210             :                                 case ASFD_FD_SERVER_LISTEN_STATUS:
     211             :                                         // Indicate to the caller that we have
     212             :                                         // a new incoming client.
     213           0 :                                         asfd->new_client++;
     214           0 :                                         break;
     215             :                                 default:
     216           0 :                                         if(asfd->do_read(asfd)
     217           0 :                                           || asfd->parse_readbuf(asfd))
     218           0 :                                                 return asfd_problem(asfd);
     219             :                                         break;
     220             :                         }
     221             :                 }
     222             : 
     223           0 :                 if(asfd->dowrite && FD_ISSET(asfd->fd, &fsw)) // Able to write.
     224             :                 {
     225           0 :                         asfd->network_timeout=asfd->max_network_timeout;
     226           0 :                         if(asfd->do_write(asfd))
     227           0 :                                 return asfd_problem(asfd);
     228             :                 }
     229             : 
     230           0 :                 if((!asfd->doread || !FD_ISSET(asfd->fd, &fsr))
     231           0 :                   && (!asfd->dowrite || !FD_ISSET(asfd->fd, &fsw)))
     232             :                 {
     233             :                         // Be careful to avoid 'read quick' mode.
     234           0 :                         if((as->setsec || as->setusec)
     235           0 :                           && asfd->max_network_timeout>0
     236           0 :                           && as->now-as->last_time>0
     237           0 :                           && asfd->network_timeout--<=0)
     238             :                         {
     239           0 :                                 logp("%s: no activity for %d seconds.\n",
     240             :                                         asfd->desc, asfd->max_network_timeout);
     241           0 :                                 return asfd_problem(asfd);
     242             :                         }
     243             :                 }
     244             :         }
     245             : 
     246             : end:
     247           0 :         as->last_time=as->now;
     248           0 :         return 0;
     249             : }
     250             : 
     251           0 : static int async_read_write(struct async *as)
     252             : {
     253           0 :         return async_io(as, 1 /* Read too. */);
     254             : }
     255             : 
     256           0 : static int async_write(struct async *as)
     257             : {
     258           0 :         return async_io(as, 0 /* No read. */);
     259             : }
     260             : 
     261           0 : static int async_read_quick(struct async *as)
     262             : {
     263             :         int r;
     264           0 :         int savesec=as->setsec;
     265           0 :         int saveusec=as->setusec;
     266           0 :         as->setsec=0;
     267           0 :         as->setusec=0;
     268           0 :         r=as->read_write(as); // Maybe make an as->read(as) function some time.
     269           0 :         as->setsec=savesec;
     270           0 :         as->setusec=saveusec;
     271           0 :         return r;
     272             : }
     273             : 
     274         195 : static void async_asfd_add(struct async *as, struct asfd *asfd)
     275             : {
     276             :         struct asfd *x;
     277         195 :         if(!as->asfd)
     278             :         {
     279         138 :                 as->asfd=asfd;
     280         333 :                 return;
     281             :         }
     282             :         // Add to the end;
     283          88 :         for(x=as->asfd; x->next; x=x->next) { }
     284          57 :         x->next=asfd;
     285             : }
     286             : 
     287           0 : static void async_asfd_remove(struct async *as, struct asfd *asfd)
     288             : {
     289             :         struct asfd *l;
     290           0 :         if(!asfd) return;
     291           0 :         if(as->asfd==asfd)
     292             :         {
     293           0 :                 as->asfd=as->asfd->next;
     294           0 :                 return;
     295             :         }
     296           0 :         for(l=as->asfd; l; l=l->next)
     297             :         {
     298           0 :                 if(l->next!=asfd) continue;
     299           0 :                 l->next=asfd->next;
     300           0 :                 return;
     301             :         }
     302             : }
     303             : 
     304          13 : void async_asfd_free_all(struct async **as)
     305             : {
     306          13 :         struct asfd *a=NULL;
     307          13 :         struct asfd *asfd=NULL;
     308          13 :         if(!as || !*as) return;
     309          26 :         for(asfd=(*as)->asfd; asfd; asfd=a)
     310             :         {
     311          13 :                 a=asfd->next;
     312          13 :                 asfd_free(&asfd);
     313             :         }
     314             :         async_free(as);
     315             : }
     316             : 
     317         147 : static int async_init(struct async *as, int estimate)
     318             : {
     319         147 :         as->setsec=1;
     320         147 :         as->setusec=0;
     321         147 :         as->last_time=0;
     322         147 :         as->doing_estimate=estimate;
     323             : 
     324         147 :         as->read_write=async_read_write;
     325         147 :         as->write=async_write;
     326         147 :         as->read_quick=async_read_quick;
     327             : 
     328         147 :         as->settimers=async_settimers;
     329         147 :         as->asfd_add=async_asfd_add;
     330         147 :         as->asfd_remove=async_asfd_remove;
     331             : 
     332         147 :         return 0;
     333             : }
     334             : 
     335         147 : struct async *async_alloc(void)
     336             : {
     337             :         struct async *as;
     338         147 :         if(!(as=(struct async *)calloc_w(1, sizeof(struct async), __func__)))
     339             :                 return NULL;
     340         147 :         as->init=async_init;
     341         147 :         return as;
     342             : }

Generated by: LCOV version 1.10