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