Home | History | Annotate | Download | only in auxprogs
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- A simple debuginfo server for Valgrind.                      ---*/
      4 /*---                                         valgrind-di-server.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /* To build for an x86_64-linux host:
      8       gcc -g -Wall -O -o valgrind-di-server \
      9          auxprogs/valgrind-di-server.c -Icoregrind -Iinclude \
     10          -IVEX/pub -DVGO_linux -DVGA_amd64
     11 
     12    To build for an x86 (32-bit) host
     13       The same, except change -DVGA_amd64 to -DVGA_x86
     14 */
     15 
     16 /*
     17    This file is part of Valgrind, a dynamic binary instrumentation
     18    framework.
     19 
     20    Copyright (C) 2013-2013 Mozilla Foundation
     21 
     22    This program is free software; you can redistribute it and/or
     23    modify it under the terms of the GNU General Public License as
     24    published by the Free Software Foundation; either version 2 of the
     25    License, or (at your option) any later version.
     26 
     27    This program is distributed in the hope that it will be useful, but
     28    WITHOUT ANY WARRANTY; without even the implied warranty of
     29    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     30    General Public License for more details.
     31 
     32    You should have received a copy of the GNU General Public License
     33    along with this program; if not, write to the Free Software
     34    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     35    02111-1307, USA.
     36 
     37    The GNU General Public License is contained in the file COPYING.
     38 */
     39 
     40 /* Contributed by Julian Seward <jseward (at) acm.org> */
     41 
     42 /* This code works (just), but it's a mess.  Cleanups (also for
     43    coregrind/m_debuginfo/image.c):
     44 
     45    * Build this file for the host arch, not the target.  But how?
     46      Even Tromey had difficulty figuring out how to do that.
     47 
     48    * Change the use of pread w/ fd to FILE*, for the file we're
     49      serving.  Or, at least, put a loop around the pread uses
     50      so that it works correctly in the case where pread reads more
     51      than zero but less than we asked for.
     52 
     53    * CRC3 request/response: pass session-IDs back and forth and
     54      check them
     55 
     56    * Check that all error cases result in a FAIL frame being returned.
     57 
     58    * image.c: don't assert in cases where a FAIL frame is returned;
     59      instead cause the debuginfo reading to fail gracefully.  (Not
     60      sure how to do this)
     61 
     62    * Improve diagnostic printing
     63 
     64    * image.c: do we need to do VG_(write_socket) ?  Will it work
     65      just to use ordinary VG_(write) ?
     66 
     67    * Both files: document the reason for setting TCP_NODELAY
     68 
     69    * Add a command line argument saying where the served-from
     70      directory is -- changes clo_serverpath.
     71 
     72    * Fix up (common up) massive code duplication between client and
     73      server.
     74 
     75    * Tidy up the LZO source files; integrate properly in the build
     76      system.
     77 */
     78 
     79 /*---------------------------------------------------------------*/
     80 
     81 /* Include valgrind headers before system headers to avoid problems
     82    with the system headers #defining things which are used as names
     83    of structure members in vki headers. */
     84 
     85 #include "pub_core_basics.h"
     86 #include "pub_core_libcassert.h"    // For VG_BUGS_TO
     87 #include "pub_core_vki.h"           // Avoids warnings from
     88                                     // pub_core_libcfile.h
     89 #include "pub_core_libcfile.h"      // For VG_CLO_DEFAULT_LOGPORT
     90 
     91 /* Needed to get a definition for pread() from unistd.h */
     92 #define _XOPEN_SOURCE 500
     93 
     94 #include <stdio.h>
     95 #include <unistd.h>
     96 #include <string.h>
     97 #include <time.h>
     98 #include <fcntl.h>
     99 #include <stdlib.h>
    100 #include <signal.h>
    101 #include <sys/poll.h>
    102 #include <sys/types.h>
    103 #include <sys/socket.h>
    104 #include <netinet/in.h>
    105 #include <sys/stat.h>
    106 #include <netinet/tcp.h>
    107 
    108 #include "../coregrind/m_debuginfo/minilzo.h"
    109 
    110 /*---------------------------------------------------------------*/
    111 
    112 /* The maximum allowable number concurrent connections. */
    113 #define M_CONNECTIONS 50
    114 
    115 static const char* clo_serverpath = ".";
    116 
    117 
    118 /*---------------------------------------------------------------*/
    119 
    120 __attribute__ ((noreturn))
    121 static void panic ( const char* str )
    122 {
    123    fprintf(stderr,
    124            "\nvalgrind-di-server: the "
    125            "'impossible' happened:\n   %s\n", str);
    126    fprintf(stderr,
    127            "Please report this bug at: %s\n\n", VG_BUGS_TO);
    128    exit(1);
    129 }
    130 
    131 __attribute__ ((noreturn))
    132 static void my_assert_fail ( const char* expr, const char* file, int line, const char* fn )
    133 {
    134    fprintf(stderr,
    135            "\nvalgrind-di-server: %s:%d (%s): Assertion '%s' failed.\n",
    136            file, line, fn, expr );
    137    fprintf(stderr,
    138            "Please report this bug at: %s\n\n", VG_BUGS_TO);
    139    exit(1);
    140 }
    141 
    142 #undef assert
    143 
    144 #define assert(expr)                                             \
    145   ((void) ((expr) ? 0 :					         \
    146 	   (my_assert_fail (VG_STRINGIFY(expr),	                 \
    147                             __FILE__, __LINE__,                  \
    148                             __PRETTY_FUNCTION__), 0)))
    149 
    150 
    151 /*---------------------------------------------------------------*/
    152 
    153 /* Holds the state that we need to track, for each connection. */
    154 typedef
    155    struct {
    156       // is this entry in use?
    157       Bool in_use;
    158       // socket descriptor to communicate with client.  Initialised as
    159       // soon as this entry is created.
    160       int  conn_sd;
    161       // fd for the file that we are connected to.  Zero if not
    162       // currently connected to any file.
    163       int   file_fd;
    164       ULong file_size;
    165       // Session ID
    166       ULong session_id;
    167       // How many bytes and chunks sent?
    168       ULong stats_n_rdok_frames;
    169       ULong stats_n_read_unz_bytes; // bytes via READ (uncompressed)
    170       ULong stats_n_read_z_bytes;   // bytes via READ (compressed)
    171    }
    172    ConnState;
    173 
    174 /* The state itself. */
    175 static int       conn_count = 0;
    176 static ConnState conn_state[M_CONNECTIONS];
    177 
    178 /* Issues unique session ID values. */
    179 static ULong next_session_id = 1;
    180 
    181 
    182 /*---------------------------------------------------------------*/
    183 
    184 // Code that is duplicated with the client :-(
    185 
    186 /* The following Adler-32 checksum code is taken from zlib-1.2.3, which
    187    has the following copyright notice. */
    188 /*
    189 Copyright notice:
    190 
    191  (C) 1995-2004 Jean-loup Gailly and Mark Adler
    192 
    193   This software is provided 'as-is', without any express or implied
    194   warranty.  In no event will the authors be held liable for any damages
    195   arising from the use of this software.
    196 
    197   Permission is granted to anyone to use this software for any purpose,
    198   including commercial applications, and to alter it and redistribute it
    199   freely, subject to the following restrictions:
    200 
    201   1. The origin of this software must not be misrepresented; you must not
    202      claim that you wrote the original software. If you use this software
    203      in a product, an acknowledgment in the product documentation would be
    204      appreciated but is not required.
    205   2. Altered source versions must be plainly marked as such, and must not be
    206      misrepresented as being the original software.
    207   3. This notice may not be removed or altered from any source distribution.
    208 
    209   Jean-loup Gailly        Mark Adler
    210   jloup (at) gzip.org          madler (at) alumni.caltech.edu
    211 
    212 If you use the zlib library in a product, we would appreciate *not*
    213 receiving lengthy legal documents to sign. The sources are provided
    214 for free but without warranty of any kind.  The library has been
    215 entirely written by Jean-loup Gailly and Mark Adler; it does not
    216 include third-party code.
    217 
    218 If you redistribute modified sources, we would appreciate that you include
    219 in the file ChangeLog history information documenting your changes. Please
    220 read the FAQ for more information on the distribution of modified source
    221 versions.
    222 */
    223 
    224 /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and
    225    return the updated checksum. If buf is NULL, this function returns
    226    the required initial value for the checksum. An Adler-32 checksum is
    227    almost as reliable as a CRC32 but can be computed much faster. */
    228 static
    229 UInt adler32( UInt adler, const UChar* buf, UInt len )
    230 {
    231 #  define BASE 65521UL    /* largest prime smaller than 65536 */
    232 #  define NMAX 5552
    233    /* NMAX is the largest n such that
    234       255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
    235 
    236 #  define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
    237 #  define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
    238 #  define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
    239 #  define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
    240 #  define DO16(buf)   DO8(buf,0); DO8(buf,8);
    241 
    242    /* The zlib sources recommend this definition of MOD if the
    243       processor cannot do integer division in hardware. */
    244 #  define MOD(a) \
    245       do { \
    246           if (a >= (BASE << 16)) a -= (BASE << 16); \
    247           if (a >= (BASE << 15)) a -= (BASE << 15); \
    248           if (a >= (BASE << 14)) a -= (BASE << 14); \
    249           if (a >= (BASE << 13)) a -= (BASE << 13); \
    250           if (a >= (BASE << 12)) a -= (BASE << 12); \
    251           if (a >= (BASE << 11)) a -= (BASE << 11); \
    252           if (a >= (BASE << 10)) a -= (BASE << 10); \
    253           if (a >= (BASE << 9)) a -= (BASE << 9); \
    254           if (a >= (BASE << 8)) a -= (BASE << 8); \
    255           if (a >= (BASE << 7)) a -= (BASE << 7); \
    256           if (a >= (BASE << 6)) a -= (BASE << 6); \
    257           if (a >= (BASE << 5)) a -= (BASE << 5); \
    258           if (a >= (BASE << 4)) a -= (BASE << 4); \
    259           if (a >= (BASE << 3)) a -= (BASE << 3); \
    260           if (a >= (BASE << 2)) a -= (BASE << 2); \
    261           if (a >= (BASE << 1)) a -= (BASE << 1); \
    262           if (a >= BASE) a -= BASE; \
    263       } while (0)
    264 #  define MOD4(a) \
    265       do { \
    266           if (a >= (BASE << 4)) a -= (BASE << 4); \
    267           if (a >= (BASE << 3)) a -= (BASE << 3); \
    268           if (a >= (BASE << 2)) a -= (BASE << 2); \
    269           if (a >= (BASE << 1)) a -= (BASE << 1); \
    270           if (a >= BASE) a -= BASE; \
    271       } while (0)
    272 
    273     UInt sum2;
    274     UInt n;
    275 
    276     /* split Adler-32 into component sums */
    277     sum2 = (adler >> 16) & 0xffff;
    278     adler &= 0xffff;
    279 
    280     /* in case user likes doing a byte at a time, keep it fast */
    281     if (len == 1) {
    282         adler += buf[0];
    283         if (adler >= BASE)
    284             adler -= BASE;
    285         sum2 += adler;
    286         if (sum2 >= BASE)
    287             sum2 -= BASE;
    288         return adler | (sum2 << 16);
    289     }
    290 
    291     /* initial Adler-32 value (deferred check for len == 1 speed) */
    292     if (buf == NULL)
    293         return 1L;
    294 
    295     /* in case short lengths are provided, keep it somewhat fast */
    296     if (len < 16) {
    297         while (len--) {
    298             adler += *buf++;
    299             sum2 += adler;
    300         }
    301         if (adler >= BASE)
    302             adler -= BASE;
    303         MOD4(sum2);             /* only added so many BASE's */
    304         return adler | (sum2 << 16);
    305     }
    306 
    307     /* do length NMAX blocks -- requires just one modulo operation */
    308     while (len >= NMAX) {
    309         len -= NMAX;
    310         n = NMAX / 16;          /* NMAX is divisible by 16 */
    311         do {
    312             DO16(buf);          /* 16 sums unrolled */
    313             buf += 16;
    314         } while (--n);
    315         MOD(adler);
    316         MOD(sum2);
    317     }
    318 
    319     /* do remaining bytes (less than NMAX, still just one modulo) */
    320     if (len) {                  /* avoid modulos if none remaining */
    321         while (len >= 16) {
    322             len -= 16;
    323             DO16(buf);
    324             buf += 16;
    325         }
    326         while (len--) {
    327             adler += *buf++;
    328             sum2 += adler;
    329         }
    330         MOD(adler);
    331         MOD(sum2);
    332     }
    333 
    334     /* return recombined sums */
    335     return adler | (sum2 << 16);
    336 
    337 #  undef MOD4
    338 #  undef MOD
    339 #  undef DO16
    340 #  undef DO8
    341 #  undef DO4
    342 #  undef DO2
    343 #  undef DO1
    344 #  undef NMAX
    345 #  undef BASE
    346 }
    347 
    348 
    349 /* A frame.  The first 4 bytes of |data| give the kind of the frame,
    350    and the rest of it is kind-specific data. */
    351 typedef  struct { UChar* data; SizeT n_data; }  Frame;
    352 
    353 
    354 static void write_UInt_le ( /*OUT*/UChar* dst, UInt n )
    355 {
    356    Int i;
    357    for (i = 0; i <= 3; i++) {
    358       dst[i] = (UChar)(n & 0xFF);
    359       n >>= 8;
    360    }
    361 }
    362 
    363 static UInt read_UInt_le ( UChar* src )
    364 {
    365    UInt r = 0;
    366    Int i;
    367    for (i = 3; i >= 0; i--) {
    368       r <<= 8;
    369       r += (UInt)src[i];
    370    }
    371    return r;
    372 }
    373 
    374 static void write_ULong_le ( /*OUT*/UChar* dst, ULong n )
    375 {
    376    Int i;
    377    for (i = 0; i <= 7; i++) {
    378       dst[i] = (UChar)(n & 0xFF);
    379       n >>= 8;
    380    }
    381 }
    382 
    383 static ULong read_ULong_le ( UChar* src )
    384 {
    385    ULong r = 0;
    386    Int i;
    387    for (i = 7; i >= 0; i--) {
    388       r <<= 8;
    389       r += (ULong)src[i];
    390    }
    391    return r;
    392 }
    393 
    394 static Frame* mk_Frame_asciiz ( const char* tag, const char* str )
    395 {
    396    assert(strlen(tag) == 4);
    397    Frame* f = calloc(sizeof(Frame), 1);
    398    size_t n_str = strlen(str);
    399    f->n_data = 4 + n_str + 1;
    400    f->data = calloc(f->n_data, 1);
    401    memcpy(&f->data[0], tag, 4);
    402    memcpy(&f->data[4], str, n_str);
    403    assert(f->data[4 + n_str] == 0);
    404    return f;
    405 }
    406 
    407 static Bool parse_Frame_noargs ( Frame* fr, const HChar* tag )
    408 {
    409    assert(strlen(tag) == 4);
    410    if (!fr || !fr->data) return False;
    411    if (fr->n_data < 4) return False;
    412    if (memcmp(&fr->data[0], tag, 4) != 0) return False;
    413    if (fr->n_data != 4) return False;
    414    return True;
    415 }
    416 
    417 static Bool parse_Frame_asciiz ( Frame* fr, const HChar* tag,
    418                                  /*OUT*/UChar** str )
    419 {
    420    assert(strlen(tag) == 4);
    421    if (!fr || !fr->data) return False;
    422    if (fr->n_data < 4) return False;
    423    if (memcmp(&fr->data[0], tag, 4) != 0) return False;
    424    if (fr->n_data < 5) return False; // else there isn't even enough
    425                                      // space for the terminating zero
    426    /* Find the terminating zero and ensure it's right at the end
    427       of the data.  If not, the frame is malformed. */
    428    SizeT i = 4;
    429    while (True) {
    430       if (i >= fr->n_data) break;
    431       if (fr->data[i] == 0) break;
    432       i++;
    433    }
    434    assert(i <= fr->n_data);
    435    if (i == fr->n_data-1 && fr->data[i] == 0) {
    436       *str = &fr->data[4];
    437       return True;
    438    } else {
    439       return False;
    440    }
    441 }
    442 
    443 static Frame* mk_Frame_le64 ( const HChar* tag, ULong n1 )
    444 {
    445    assert(strlen(tag) == 4);
    446    Frame* f = calloc(sizeof(Frame), 1);
    447    f->n_data = 4 + 1*8;
    448    f->data = calloc(f->n_data, 1);
    449    memcpy(&f->data[0], tag, 4);
    450    write_ULong_le(&f->data[4 + 0*8], n1);
    451    return f;
    452 }
    453 
    454 static Frame* mk_Frame_le64_le64 ( const HChar* tag, ULong n1, ULong n2 )
    455 {
    456    assert(strlen(tag) == 4);
    457    Frame* f = calloc(sizeof(Frame), 1);
    458    f->n_data = 4 + 2*8;
    459    f->data = calloc(f->n_data, 1);
    460    memcpy(&f->data[0], tag, 4);
    461    write_ULong_le(&f->data[4 + 0*8], n1);
    462    write_ULong_le(&f->data[4 + 1*8], n2);
    463    return f;
    464 }
    465 
    466 static Bool parse_Frame_le64_le64_le64 ( Frame* fr, const HChar* tag,
    467                                          /*OUT*/ULong* n1, /*OUT*/ULong* n2,
    468                                          /*OUT*/ULong* n3 )
    469 {
    470    assert(strlen(tag) == 4);
    471    if (!fr || !fr->data) return False;
    472    if (fr->n_data < 4) return False;
    473    if (memcmp(&fr->data[0], tag, 4) != 0) return False;
    474    if (fr->n_data != 4 + 3*8) return False;
    475    *n1 = read_ULong_le(&fr->data[4 + 0*8]);
    476    *n2 = read_ULong_le(&fr->data[4 + 1*8]);
    477    *n3 = read_ULong_le(&fr->data[4 + 2*8]);
    478    return True;
    479 }
    480 
    481 static Frame* mk_Frame_le64_le64_le64_bytes (
    482                  const HChar* tag,
    483                  ULong n1, ULong n2, ULong n3, ULong n_data,
    484                  /*OUT*/UChar** data )
    485 {
    486    assert(strlen(tag) == 4);
    487    Frame* f = calloc(sizeof(Frame), 1);
    488    f->n_data = 4 + 3*8 + n_data;
    489    f->data = calloc(f->n_data, 1);
    490    memcpy(&f->data[0], tag, 4);
    491    write_ULong_le(&f->data[4 + 0*8], n1);
    492    write_ULong_le(&f->data[4 + 1*8], n2);
    493    write_ULong_le(&f->data[4 + 2*8], n3);
    494    *data = &f->data[4 + 3*8];
    495    return f;
    496 }
    497 
    498 static void free_Frame ( Frame* fr )
    499 {
    500    assert(fr && fr->data);
    501    free(fr->data);
    502    free(fr);
    503 }
    504 
    505 
    506 static void set_blocking ( int sd )
    507 {
    508    int res;
    509    res = fcntl(sd, F_GETFL);
    510    res = fcntl(sd, F_SETFL, res & ~O_NONBLOCK);
    511    if (res != 0) {
    512       perror("fcntl failed");
    513       panic("set_blocking");
    514    }
    515 }
    516 
    517 
    518 #if 0
    519 static void set_nonblocking ( int sd )
    520 {
    521    int res;
    522    res = fcntl(sd, F_GETFL);
    523    res = fcntl(sd, F_SETFL, res | O_NONBLOCK);
    524    if (res != 0) {
    525       perror("fcntl failed");
    526       panic("set_nonblocking");
    527    }
    528 }
    529 #endif
    530 
    531 
    532 /* Tries to read 'len' bytes from fd, blocking if necessary.  Assumes
    533    fd has been set in blocking mode.  If it returns with the number of
    534    bytes read < len, it means that either fd was closed, or there was
    535    an error on it. */
    536 static SizeT my_read ( Int fd, UChar* buf, SizeT len )
    537 {
    538   //set_blocking(fd);
    539    SizeT nRead = 0;
    540    while (1) {
    541       if (nRead == len) return nRead;
    542       assert(nRead < len);
    543       SizeT nNeeded = len - nRead;
    544       assert(nNeeded > 0);
    545       SSizeT n = read(fd, &buf[nRead], nNeeded);
    546       if (n <= 0) return nRead; /* error or EOF */
    547       nRead += n;
    548    }
    549 }
    550 
    551 /* Tries to write 'len' bytes to fd, blocking if necessary.  Assumes
    552    fd has been set in blocking mode.  If it returns with the number of
    553    bytes written < len, it means that either fd was closed, or there was
    554    an error on it. */
    555 static SizeT my_write ( Int fd, UChar* buf, SizeT len )
    556 {
    557   //set_nonblocking(fd);
    558    SizeT nWritten = 0;
    559    while (1) {
    560       if (nWritten == len) return nWritten;
    561       assert(nWritten < len);
    562       SizeT nStillToDo = len - nWritten;
    563       assert(nStillToDo > 0);
    564       SSizeT n = write(fd, &buf[nWritten], nStillToDo);
    565       if (n < 0) return nWritten; /* error or EOF */
    566       nWritten += n;
    567    }
    568 }
    569 
    570 
    571 static UInt calc_gnu_debuglink_crc32(/*OUT*/Bool* ok, int fd, ULong size)
    572 {
    573   static const UInt crc32_table[256] =
    574     {
    575       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
    576       0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
    577       0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
    578       0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    579       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
    580       0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    581       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
    582       0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    583       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
    584       0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
    585       0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
    586       0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    587       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
    588       0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
    589       0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
    590       0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    591       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
    592       0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    593       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
    594       0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    595       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
    596       0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
    597       0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
    598       0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    599       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
    600       0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
    601       0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
    602       0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    603       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
    604       0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    605       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
    606       0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    607       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
    608       0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
    609       0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
    610       0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    611       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
    612       0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
    613       0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
    614       0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    615       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
    616       0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    617       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
    618       0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    619       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
    620       0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
    621       0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
    622       0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    623       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
    624       0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
    625       0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
    626       0x2d02ef8d
    627     };
    628 
    629       /* Work through the image in 1 KB chunks. */
    630       UInt  crc      = 0xFFFFFFFF;
    631       ULong img_szB  = size;
    632       ULong curr_off = 0;
    633       while (1) {
    634          assert(curr_off >= 0 && curr_off <= img_szB);
    635          if (curr_off == img_szB) break;
    636          ULong avail = img_szB - curr_off;
    637          assert(avail > 0 && avail <= img_szB);
    638          if (avail > 65536) avail = 65536;
    639          UChar buf[65536];
    640          Int nRead = pread(fd, buf, avail, curr_off);
    641          if (nRead <= 0) { /* EOF or error on the file; neither should happen */
    642             *ok = False;
    643             return 0;
    644          }
    645          /* this is a kludge .. we should loop around pread and deal
    646             with short reads, for whatever reason */
    647          assert(nRead == avail);
    648          UInt i;
    649          for (i = 0; i < (UInt)nRead; i++)
    650             crc = crc32_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
    651          curr_off += nRead;
    652       }
    653       *ok = True;
    654       return ~crc & 0xFFFFFFFF;
    655    }
    656 
    657 
    658 /*---------------------------------------------------------------*/
    659 
    660 /* Handle a transaction for conn_state[conn_no].  There is incoming
    661    data available; read it and send back an appropriate response.
    662    Returns a boolean indicating whether the connection has been
    663    closed; in which case this function does all necessary cleanup and
    664    leaves conn_state[conn_no] in a not-in-use state. */
    665 
    666 static Bool handle_transaction ( int conn_no )
    667 {
    668    Frame* req = NULL; /* the request frame that we receive */
    669    Frame* res = NULL; /* the response frame that we send back */
    670 
    671    assert(conn_no >= 0 && conn_no < M_CONNECTIONS);
    672    assert(conn_state[conn_no].in_use);
    673 
    674    //printf("SERVER: handle_transaction(%d)\n", conn_no); fflush(stdout);
    675 
    676    Int sd = conn_state[conn_no].conn_sd;
    677 
    678    /* Get a frame out of the channel. */
    679    UChar rd_first8[8];  // adler32; length32
    680    { Int r = my_read(sd, &rd_first8[0], 8);
    681      if (r == 0) goto client_closed_conn;
    682      if (r != 8) goto fail;
    683    }
    684    UInt rd_adler = read_UInt_le(&rd_first8[0]);
    685    UInt rd_len   = read_UInt_le(&rd_first8[4]);
    686    /* Allocate a Frame to hold the result data, and read into it. */
    687    // Reject obviously-insane length fields.
    688    if (rd_len > 4*1024*1024) goto fail;
    689    assert(req == NULL);
    690    req = calloc(sizeof(Frame), 1);
    691    req->n_data = rd_len;
    692    req->data = calloc(rd_len, 1);
    693    if (rd_len > 0) {
    694       Int r = my_read(sd, req->data, req->n_data);
    695       if (r != rd_len) goto fail;
    696    }
    697 //printf("SERVER: recv %c%c%c%c\n", req->data[0], req->data[1], req->data[2], req->data[3]); fflush(stdout);
    698 
    699    /* Compute the checksum for the received data, and check it. */
    700    UInt adler = adler32(0, NULL, 0); // initial value
    701    adler = adler32(adler, &rd_first8[4], 4);
    702    if (req->n_data > 0)
    703       adler = adler32(adler, req->data, req->n_data);
    704 
    705    if (adler/*computed*/ != rd_adler/*expected*/) goto fail;
    706 
    707    /* Now we have a request frame.  Cook up a response. */
    708    assert(res == NULL);
    709 
    710    UChar* filename = NULL;
    711    ULong req_session_id = 0, req_offset = 0, req_len = 0;
    712 
    713    if (parse_Frame_noargs(req, "VERS")) {
    714       res = mk_Frame_asciiz("VEOK", "Valgrind Debuginfo Server, Version 1");
    715    }
    716    else
    717    if (parse_Frame_noargs(req, "CRC3")) {
    718       /* FIXME: add a session ID to this request, and check it */
    719       if (conn_state[conn_no].file_fd == 0) {
    720          res = mk_Frame_asciiz("CRC3", "FAIL: not connected to file");
    721       } else {
    722          Bool ok    = False;
    723          UInt crc32 = calc_gnu_debuglink_crc32(&ok,
    724                                                conn_state[conn_no].file_fd,
    725                                                conn_state[conn_no].file_size);
    726          if (ok) {
    727             res = mk_Frame_le64("CROK", (ULong)crc32);
    728          } else {
    729             res = mk_Frame_asciiz("FAIL", "CRC3: I/O error reading file");
    730          }
    731       }
    732    }
    733    else
    734    if (parse_Frame_asciiz(req, "OPEN", &filename)) {
    735       Bool ok = True;
    736       int  fd = 0;
    737       if (conn_state[conn_no].file_fd != 0) {
    738          res = mk_Frame_asciiz("FAIL", "OPEN: already connected to file");
    739          ok = False;
    740       }
    741       if (ok) {
    742          assert(clo_serverpath);
    743          fd = open((char*)filename, O_RDONLY);
    744          if (fd == -1) {
    745             res = mk_Frame_asciiz("FAIL", "OPEN: cannot open file");
    746             printf("(%d) SessionID %llu: open failed for \"%s\"\n",
    747                    conn_count, conn_state[conn_no].session_id, filename );
    748             ok = False;
    749          } else {
    750             assert(fd > 2);
    751          }
    752       }
    753       if (ok) {
    754          struct stat stat_buf;
    755          int r = fstat(fd, &stat_buf);
    756          if (r != 0) {
    757             res = mk_Frame_asciiz("FAIL", "OPEN: cannot stat file");
    758             ok = False;
    759          }
    760          if (ok && stat_buf.st_size == 0) {
    761             res = mk_Frame_asciiz("FAIL", "OPEN: file has zero size");
    762             ok = False;
    763          }
    764          if (ok) {
    765             conn_state[conn_no].file_fd   = fd;
    766             conn_state[conn_no].file_size = stat_buf.st_size;
    767             assert(res == NULL);
    768             res = mk_Frame_le64_le64("OPOK", conn_state[conn_no].session_id,
    769                                              conn_state[conn_no].file_size);
    770             printf("(%d) SessionID %llu: open successful for \"%s\"\n",
    771                    conn_count, conn_state[conn_no].session_id, filename );
    772             fflush(stdout);
    773          }
    774       }
    775    }
    776    else
    777    if (parse_Frame_le64_le64_le64(req, "READ", &req_session_id,
    778                                   &req_offset, &req_len)) {
    779       /* Because each new connection is associated with its own socket
    780          descriptor and hence with a particular conn_no, the requested
    781          session-ID is redundant -- it must be the one associated with
    782          this slot.  But check anyway. */
    783       Bool ok = True;
    784       if (req_session_id != conn_state[conn_no].session_id) {
    785          res = mk_Frame_asciiz("FAIL", "READ: invalid session ID");
    786          ok = False;
    787       }
    788       /* Check we're connected to a file, and if so range-check the
    789          request. */
    790       if (ok && conn_state[conn_no].file_fd == 0) {
    791          res = mk_Frame_asciiz("FAIL", "READ: no associated file");
    792          ok = False;
    793       }
    794       if (ok && (req_len == 0 || req_len > 4*1024*1024)) {
    795          res = mk_Frame_asciiz("FAIL", "READ: invalid request size");
    796          ok = False;
    797       }
    798       if (ok && req_len + req_offset > conn_state[conn_no].file_size) {
    799          res = mk_Frame_asciiz("FAIL", "READ: request exceeds file size");
    800          ok = False;
    801       }
    802       /* Try to read the file. */
    803       if (ok) {
    804          /* First, allocate a temp buf and read from the file into it. */
    805          /* FIXME: what if pread reads short and we have to redo it? */
    806          UChar* unzBuf = malloc(req_len);
    807          size_t nRead = pread(conn_state[conn_no].file_fd,
    808                               unzBuf, req_len, req_offset);
    809          if (nRead != req_len) {
    810             free_Frame(res);
    811             res = mk_Frame_asciiz("FAIL", "READ: I/O error reading file");
    812             ok = False;
    813          }         UInt zLen = 0;
    814          if (ok) {
    815             // Now compress it with LZO.  LZO appears to recommend
    816             // the worst-case output size as (in_len + in_len / 16 + 67).
    817             // Be more conservative here.
    818 #           define STACK_ALLOC(var,size) \
    819                lzo_align_t __LZO_MMODEL \
    820                   var [ ((size) \
    821                         + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
    822             STACK_ALLOC(wrkmem, LZO1X_1_MEM_COMPRESS);
    823 #           undef STACK_ALLOC
    824             UInt zLenMax = req_len + req_len / 4 + 1024;
    825             UChar* zBuf = malloc(zLenMax);
    826             zLen = zLenMax;
    827             Int lzo_rc = lzo1x_1_compress(unzBuf, req_len,
    828                                           zBuf, (lzo_uint*)&zLen, wrkmem);
    829             if (lzo_rc == LZO_E_OK) {
    830               //printf("XXXXX req_len %u  zLen %u\n", (UInt)req_len, (UInt)zLen);
    831                assert(zLen <= zLenMax);
    832                /* Make a frame to put the results in.  Bytes 24 and
    833                   onwards need to be filled from the compressed data,
    834                   and 'buf' is set to point to the right bit. */
    835                UChar* buf = NULL;
    836                res = mk_Frame_le64_le64_le64_bytes
    837                  ("RDOK", req_session_id, req_offset, req_len, zLen, &buf);
    838                assert(res);
    839                assert(buf);
    840                memcpy(buf, zBuf, zLen);
    841                // Update stats
    842                conn_state[conn_no].stats_n_rdok_frames++;
    843                conn_state[conn_no].stats_n_read_unz_bytes += req_len;
    844                conn_state[conn_no].stats_n_read_z_bytes   += zLen;
    845             } else {
    846                ok = False;
    847                free_Frame(res);
    848                res = mk_Frame_asciiz("FAIL", "READ: LZO failed");
    849             }
    850             free(zBuf);
    851          }
    852          free(unzBuf);
    853       }
    854    }
    855    else {
    856       res = mk_Frame_asciiz("FAIL", "Invalid request frame type");
    857    }
    858 
    859    /* All paths through the above should result in an assignment to |res|. */
    860    assert(res != NULL);
    861 
    862    /* And send the response frame back to the client. */
    863    /* What goes on the wire is:
    864          adler(le32) n_data(le32) data[0 .. n_data-1]
    865       where the checksum covers n_data as well as data[].
    866    */
    867    /* The initial Adler-32 value */
    868    adler = adler32(0, NULL, 0);
    869 
    870    /* Fold in the length field, encoded as le32. */
    871    UChar wr_first8[8];
    872    write_UInt_le(&wr_first8[4], res->n_data);
    873    adler = adler32(adler, &wr_first8[4], 4);
    874    /* Fold in the data values */
    875    adler = adler32(adler, res->data, res->n_data);
    876    write_UInt_le(&wr_first8[0], adler);
    877 
    878    Int r = my_write(sd, &wr_first8[0], 8);
    879    if (r != 8) goto fail;
    880    assert(res->n_data >= 4); // else ill formed -- no KIND field
    881    r = my_write(sd, res->data, res->n_data);
    882    if (r != res->n_data) goto fail;
    883 
    884 //printf("SERVER: send %c%c%c%c\n", res->data[0], res->data[1], res->data[2], res->data[3]); fflush(stdout);
    885 
    886    /* So, success. */
    887    if (req) free_Frame(req);
    888    if (res) free_Frame(res);
    889    return False;  /* "connection still in use" */
    890 
    891    // Is there any difference between these?
    892   client_closed_conn:
    893   fail:
    894    if (conn_state[conn_no].conn_sd > 0)
    895       close(conn_state[conn_no].conn_sd);
    896    if (conn_state[conn_no].file_fd > 0)
    897       close(conn_state[conn_no].file_fd);
    898 
    899    if (conn_state[conn_no].stats_n_rdok_frames > 0) {
    900       printf("(%d) SessionID %llu:   sent %llu frames, "
    901              "%llu MB (unz), %llu MB (z), ratio %4.2f:1\n",
    902              conn_count, conn_state[conn_no].session_id,
    903              conn_state[conn_no].stats_n_rdok_frames,
    904              conn_state[conn_no].stats_n_read_unz_bytes / 1000000,
    905              conn_state[conn_no].stats_n_read_z_bytes / 1000000,
    906              (double)conn_state[conn_no].stats_n_read_unz_bytes
    907                / (double)conn_state[conn_no].stats_n_read_z_bytes);
    908       printf("(%d) SessionID %llu: closed\n",
    909              conn_count, conn_state[conn_no].session_id);
    910 
    911       fflush(stdout);
    912    }
    913 
    914    memset(&conn_state[conn_no], 0, sizeof(conn_state[conn_no]));
    915    if (req) free_Frame(req);
    916    if (res) free_Frame(res);
    917    return True; /* "connection has been closed" */
    918 }
    919 
    920 
    921 /*---------------------------------------------------------------*/
    922 
    923 
    924 
    925 #if 0
    926 static void copyout ( char* buf, int nbuf )
    927 {
    928    int i;
    929    for (i = 0; i < nbuf; i++) {
    930       if (buf[i] == '\n') {
    931          fprintf(stdout, "\n(%d) ", conn_count);
    932       } else {
    933          __attribute__((unused)) size_t ignored
    934             = fwrite(&buf[i], 1, 1, stdout);
    935       }
    936    }
    937    fflush(stdout);
    938 }
    939 
    940 static int read_from_sd ( int sd )
    941 {
    942    char buf[100];
    943    int n;
    944 
    945    set_blocking(sd);
    946    n = read(sd, buf, 99);
    947    if (n <= 0) return 0; /* closed */
    948    copyout(buf, n);
    949 
    950    set_nonblocking(sd);
    951    while (1) {
    952       n = read(sd, buf, 100);
    953       if (n <= 0) return 1; /* not closed */
    954       copyout(buf, n);
    955    }
    956 }
    957 #endif
    958 
    959 static void snooze ( void )
    960 {
    961    struct timespec req;
    962    req.tv_sec = 0;
    963    req.tv_nsec = 200 * 1000 * 1000;
    964    nanosleep(&req,NULL);
    965 }
    966 
    967 
    968 /* returns 0 if invalid, else port # */
    969 static int atoi_portno ( const char* str )
    970 {
    971    int n = 0;
    972    while (1) {
    973       if (*str == 0)
    974          break;
    975       if (*str < '0' || *str > '9')
    976          return 0;
    977       n = 10*n + (int)(*str - '0');
    978       str++;
    979       if (n >= 65536)
    980          return 0;
    981    }
    982    if (n < 1024)
    983       return 0;
    984    return n;
    985 }
    986 
    987 
    988 static void usage ( void )
    989 {
    990    fprintf(stderr,
    991       "\n"
    992       "usage is:\n"
    993       "\n"
    994       "   valgrind-di-server [--exit-at-zero|-e] [port-number]\n"
    995       "\n"
    996       "   where   --exit-at-zero or -e causes the listener to exit\n"
    997       "           when the number of connections falls back to zero\n"
    998       "           (the default is to keep listening forever)\n"
    999       "\n"
   1000       "           port-number is the default port on which to listen for\n"
   1001       "           connections.  It must be between 1024 and 65535.\n"
   1002       "           Current default is %d.\n"
   1003       "\n"
   1004       ,
   1005       VG_CLO_DEFAULT_LOGPORT
   1006    );
   1007    exit(1);
   1008 }
   1009 
   1010 
   1011 static void banner ( const char* str )
   1012 {
   1013    time_t t;
   1014    t = time(NULL);
   1015    printf("valgrind-di-server %s at %s", str, ctime(&t));
   1016    fflush(stdout);
   1017 }
   1018 
   1019 
   1020 static void exit_routine ( void )
   1021 {
   1022    banner("exited");
   1023    exit(0);
   1024 }
   1025 
   1026 
   1027 static void sigint_handler ( int signo )
   1028 {
   1029    exit_routine();
   1030 }
   1031 
   1032 
   1033 int main (int argc, char** argv)
   1034 {
   1035    int    i, j, res, one;
   1036    int    main_sd, new_sd;
   1037    socklen_t client_len;
   1038    struct sockaddr_in client_addr, server_addr;
   1039 
   1040    char /*bool*/ exit_when_zero = 0;
   1041    int           port = VG_CLO_DEFAULT_LOGPORT;
   1042 
   1043    for (i = 1; i < argc; i++) {
   1044       if (0==strcmp(argv[i], "--exit-at-zero")
   1045           || 0==strcmp(argv[i], "-e")) {
   1046          exit_when_zero = 1;
   1047       }
   1048       else
   1049       if (atoi_portno(argv[i]) > 0) {
   1050          port = atoi_portno(argv[i]);
   1051       }
   1052       else
   1053       usage();
   1054    }
   1055 
   1056    banner("started");
   1057    signal(SIGINT, sigint_handler);
   1058 
   1059    conn_count = 0;
   1060    memset(&conn_state, 0, sizeof(conn_state));
   1061 
   1062    /* create socket */
   1063    main_sd = socket(AF_INET, SOCK_STREAM, 0);
   1064    if (main_sd < 0) {
   1065       perror("cannot open socket ");
   1066       panic("main -- create socket");
   1067    }
   1068 
   1069    /* allow address reuse to avoid "address already in use" errors */
   1070 
   1071    one = 1;
   1072    if (setsockopt(main_sd, SOL_SOCKET, SO_REUSEADDR,
   1073 		  &one, sizeof(one)) < 0) {
   1074       perror("cannot enable address reuse ");
   1075       panic("main -- enable address reuse");
   1076    }
   1077 
   1078    /* bind server port */
   1079    server_addr.sin_family      = AF_INET;
   1080    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
   1081    server_addr.sin_port        = htons(port);
   1082 
   1083    if (bind(main_sd, (struct sockaddr *) &server_addr,
   1084                      sizeof(server_addr) ) < 0) {
   1085       perror("cannot bind port ");
   1086       panic("main -- bind port");
   1087    }
   1088 
   1089    res = listen(main_sd, M_CONNECTIONS);
   1090    if (res != 0) {
   1091       perror("listen failed ");
   1092       panic("main -- listen");
   1093    }
   1094 
   1095    Bool do_snooze = False;
   1096    while (1) {
   1097 
   1098       if (0 && do_snooze)
   1099          snooze();
   1100 
   1101       /* Snooze after this iteration, unless something happened. */
   1102       do_snooze = True;
   1103 
   1104       /* enquire, using poll, whether there is any activity available on
   1105          the main socket descriptor.  If so, someone is trying to
   1106          connect; get the fd and add it to our table thereof. */
   1107       { struct pollfd ufd;
   1108         while (1) {
   1109            ufd.fd      = main_sd;
   1110            ufd.events  = POLLIN;
   1111            ufd.revents = 0;
   1112            res = poll(&ufd, 1, 0/*ms*/ /* 0=return immediately. */);
   1113            if (res == 0) break;
   1114 
   1115            /* ok, we have someone waiting to connect.  Get the sd. */
   1116            client_len = sizeof(client_addr);
   1117            new_sd = accept(main_sd, (struct sockaddr *)&client_addr,
   1118                                                        &client_len);
   1119            if (new_sd < 0) {
   1120               perror("cannot accept connection ");
   1121               panic("main -- accept connection");
   1122            }
   1123 
   1124            /* find a place to put it. */
   1125 	   assert(new_sd > 0);
   1126            for (i = 0; i < M_CONNECTIONS; i++)
   1127               if (!conn_state[i].in_use)
   1128                  break;
   1129 
   1130            if (i >= M_CONNECTIONS) {
   1131               fprintf(stderr, "Too many concurrent connections.  "
   1132                               "Increase M_CONNECTIONS and recompile.\n");
   1133               panic("main -- too many concurrent connections");
   1134            }
   1135 
   1136 assert(one == 1);
   1137 int ret = setsockopt( new_sd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
   1138 assert(ret != -1);
   1139 
   1140            memset(&conn_state[i], 0, sizeof(conn_state[i]));
   1141            conn_state[i].in_use     = True;
   1142            conn_state[i].conn_sd    = new_sd;
   1143            conn_state[i].file_fd    = 0; /* not known yet */
   1144            conn_state[i].session_id = next_session_id++;
   1145            set_blocking(new_sd);
   1146            conn_count++;
   1147            do_snooze = False;
   1148         } /* while (1) */
   1149       }
   1150 
   1151       /* We've processed all new connect requests.  Listen for changes
   1152          to the current set of fds.  This requires gathering up all
   1153          the known conn_sd values and doing poll() on them. */
   1154       struct pollfd tmp_pollfd[M_CONNECTIONS];
   1155       /* And a parallel array which maps entries in tmp_pollfd back to
   1156          entries in conn_state. */
   1157       int tmp_pollfd_to_conn_state[M_CONNECTIONS];
   1158       j = 0;
   1159       for (i = 0; i < M_CONNECTIONS; i++) {
   1160          if (!conn_state[i].in_use)
   1161             continue;
   1162          assert(conn_state[i].conn_sd > 2);
   1163          tmp_pollfd[j].fd      = conn_state[i].conn_sd;
   1164          tmp_pollfd[j].events  = POLLIN /* | POLLHUP | POLLNVAL */;
   1165          tmp_pollfd[j].revents = 0;
   1166          tmp_pollfd_to_conn_state[j] = i;
   1167          j++;
   1168       }
   1169 
   1170       res = poll(tmp_pollfd, j, 20/*ms*/ /* 0=return immediately. */ );
   1171       if (res < 0) {
   1172          perror("poll(main) failed");
   1173          panic("poll(main) failed");
   1174       }
   1175 
   1176       /* nothing happened. go round again. */
   1177       if (res == 0) {
   1178          continue;
   1179       }
   1180 
   1181       /* inspect the fds. */
   1182       for (i = 0; i < j; i++) {
   1183 
   1184          if (tmp_pollfd[i].revents & POLLIN) {
   1185             /* We have some activity on tmp_pollfd[i].  We need to
   1186                figure out which conn_state[] entry that corresponds
   1187                to, which is what tmp_pollfd_to_conn_state is for. */
   1188             Int  conn_no  = tmp_pollfd_to_conn_state[i];
   1189             Bool finished = handle_transaction(conn_no);
   1190             if (finished) {
   1191                /* this connection has been closed or otherwise gone
   1192                   bad; forget about it. */
   1193                conn_count--;
   1194                fflush(stdout);
   1195                if (conn_count == 0 && exit_when_zero) {
   1196                   if (0) printf("\n");
   1197                   fflush(stdout);
   1198                   exit_routine();
   1199 	       }
   1200             } else {
   1201                // maybe show stats
   1202                if (conn_state[i].stats_n_rdok_frames > 0
   1203                    && (conn_state[i].stats_n_rdok_frames % 1000) == 0) {
   1204                   printf("(%d) SessionID %llu:   sent %llu frames, "
   1205                          "%llu MB (unz), %llu MB (z)\n",
   1206                          conn_count, conn_state[conn_no].session_id,
   1207                          conn_state[conn_no].stats_n_rdok_frames,
   1208                          conn_state[conn_no].stats_n_read_unz_bytes / 1000000,
   1209                          conn_state[conn_no].stats_n_read_z_bytes / 1000000);
   1210                   fflush(stdout);
   1211                }
   1212             }
   1213          }
   1214 
   1215       } /* for (i = 0; i < j; i++) */
   1216 
   1217       do_snooze = False;
   1218 
   1219    } /* while (1) */
   1220 
   1221    /* NOTREACHED */
   1222 }
   1223 
   1224 ////////////////////////////////////////////////////
   1225 #include "../coregrind/m_debuginfo/minilzo-inl.c"
   1226 
   1227 /*--------------------------------------------------------------------*/
   1228 /*--- end                                     valgrind-di-server.c ---*/
   1229 /*--------------------------------------------------------------------*/
   1230