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