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