blob: 85963f5de0b3a37d29afb993fc62c586eb969a1a [file] [log] [blame]
sewardj5d616df2013-07-02 08:07:15 +00001
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
Elliott Hughesed398002017-06-21 14:41:24 -070020 Copyright (C) 2013-2017 Mozilla Foundation
sewardj5d616df2013-07-02 08:07:15 +000021
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
sewardj5d7fde12013-08-01 22:16:41 +000091/* Needed to get a definition for pread() from unistd.h */
rhyskidd0dc35262015-05-28 12:49:00 +000092#ifndef _XOPEN_SOURCE
sewardj8eb8bab2015-07-21 14:44:28 +000093#define _XOPEN_SOURCE 600
rhyskidd0dc35262015-05-28 12:49:00 +000094#endif
sewardj5d7fde12013-08-01 22:16:41 +000095
sewardj5d616df2013-07-02 08:07:15 +000096#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
florian044514a2015-01-07 14:42:11 +0000114/* 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. */
120unsigned M_CONNECTIONS = 0;
sewardj5d616df2013-07-02 08:07:15 +0000121
122static const char* clo_serverpath = ".";
123
124
125/*---------------------------------------------------------------*/
126
127__attribute__ ((noreturn))
128static 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))
139static 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
florian044514a2015-01-07 14:42:11 +0000160/* Allocate some memory. Return iff successful. */
161static 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
sewardj5d616df2013-07-02 08:07:15 +0000174/* Holds the state that we need to track, for each connection. */
175typedef
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. */
196static int conn_count = 0;
florian044514a2015-01-07 14:42:11 +0000197static ConnState *conn_state;
sewardj5d616df2013-07-02 08:07:15 +0000198
199/* Issues unique session ID values. */
200static 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/*
210Copyright 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
233If you use the zlib library in a product, we would appreciate *not*
234receiving lengthy legal documents to sign. The sources are provided
235for free but without warranty of any kind. The library has been
236entirely written by Jean-loup Gailly and Mark Adler; it does not
237include third-party code.
238
239If you redistribute modified sources, we would appreciate that you include
240in the file ChangeLog history information documenting your changes. Please
241read the FAQ for more information on the distribution of modified source
242versions.
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. */
249static
250UInt 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. */
372typedef struct { UChar* data; SizeT n_data; } Frame;
373
374
375static 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
384static 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
395static 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
404static 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
415static 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
428static 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
438static 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
464static 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
475static 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
487static 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
502static 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
519static void free_Frame ( Frame* fr )
520{
521 assert(fr && fr->data);
522 free(fr->data);
523 free(fr);
524}
525
526
527static 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
540static 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. */
557static 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. */
576static 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
592static 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
687static 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");
sewardj518510b2014-02-05 13:20:58 +0000767 printf("(%d) SessionID %llu: open failed for \"%s\"\n",
768 conn_count, conn_state[conn_no].session_id, filename );
sewardj5d616df2013-07-02 08:07:15 +0000769 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) {
sewardjbd7a24a2013-10-20 09:34:13 +0000806 res = mk_Frame_asciiz("FAIL", "READ: invalid session ID");
sewardj5d616df2013-07-02 08:07:15 +0000807 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? */
florian044514a2015-01-07 14:42:11 +0000827 UChar* unzBuf = my_malloc(req_len);
sewardj5d616df2013-07-02 08:07:15 +0000828 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;
florian2d3aed72014-09-02 12:05:15 +0000834 }
sewardj5d616df2013-07-02 08:07:15 +0000835 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;
florian044514a2015-01-07 14:42:11 +0000846 UChar* zBuf = my_malloc(zLenMax);
florian2d3aed72014-09-02 12:05:15 +0000847 lzo_uint zLen = zLenMax;
sewardj5d616df2013-07-02 08:07:15 +0000848 Int lzo_rc = lzo1x_1_compress(unzBuf, req_len,
florian2d3aed72014-09-02 12:05:15 +0000849 zBuf, &zLen, wrkmem);
sewardj5d616df2013-07-02 08:07:15 +0000850 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. */
florian97b89f72014-09-02 11:58:10 +0000908 free_Frame(req);
909 free_Frame(res);
sewardj5d616df2013-07-02 08:07:15 +0000910 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
947static 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
961static 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
980static 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
florian044514a2015-01-07 14:42:11 +0000989/* returns 0 if negative, or > BOUND or invalid characters were found */
990static int atoi_with_bound ( const char* str, int bound )
sewardj5d616df2013-07-02 08:07:15 +0000991{
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++;
florian044514a2015-01-07 14:42:11 +00001000 if (n >= bound)
sewardj5d616df2013-07-02 08:07:15 +00001001 return 0;
1002 }
florian044514a2015-01-07 14:42:11 +00001003 return n;
1004}
1005
1006
1007/* returns 0 if invalid, else port # */
1008static int atoi_portno ( const char* str )
1009{
1010 int n = atoi_with_bound(str, 65536);
1011
sewardj5d616df2013-07-02 08:07:15 +00001012 if (n < 1024)
1013 return 0;
1014 return n;
1015}
1016
1017
1018static 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"
florian044514a2015-01-07 14:42:11 +00001030 " --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"
sewardj5d616df2013-07-02 08:07:15 +00001034 " 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 ,
florian044514a2015-01-07 14:42:11 +00001039 M_CONNECTIONS_DEFAULT, M_CONNECTIONS_MAX, VG_CLO_DEFAULT_LOGPORT
sewardj5d616df2013-07-02 08:07:15 +00001040 );
1041 exit(1);
1042}
1043
1044
1045static 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
1054static void exit_routine ( void )
1055{
1056 banner("exited");
1057 exit(0);
1058}
1059
1060
1061static void sigint_handler ( int signo )
1062{
1063 exit_routine();
1064}
1065
1066
1067int 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 }
florian044514a2015-01-07 14:42:11 +00001082 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 }
sewardj5d616df2013-07-02 08:07:15 +00001087 else
1088 if (atoi_portno(argv[i]) > 0) {
1089 port = atoi_portno(argv[i]);
1090 }
1091 else
1092 usage();
1093 }
1094
florian044514a2015-01-07 14:42:11 +00001095 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
sewardj5d616df2013-07-02 08:07:15 +00001100 banner("started");
1101 signal(SIGINT, sigint_handler);
1102
1103 conn_count = 0;
florian044514a2015-01-07 14:42:11 +00001104 memset(conn_state, 0, M_CONNECTIONS * sizeof conn_state[0]);
sewardj5d616df2013-07-02 08:07:15 +00001105
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) {
florian044514a2015-01-07 14:42:11 +00001175 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);
sewardj5d616df2013-07-02 08:07:15 +00001180 }
1181
1182assert(one == 1);
1183int ret = setsockopt( new_sd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
1184assert(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. */
florian044514a2015-01-07 14:42:11 +00001200 static struct pollfd *tmp_pollfd;
1201 if (tmp_pollfd == NULL)
1202 tmp_pollfd = my_malloc(M_CONNECTIONS * sizeof tmp_pollfd[0]);
1203
sewardj5d616df2013-07-02 08:07:15 +00001204 /* And a parallel array which maps entries in tmp_pollfd back to
1205 entries in conn_state. */
florian044514a2015-01-07 14:42:11 +00001206 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
sewardj5d616df2013-07-02 08:07:15 +00001211 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/*--------------------------------------------------------------------*/