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