2 /*--------------------------------------------------------------------*/
3 /*--- A simple debuginfo server for Valgrind. ---*/
4 /*--- valgrind-di-server.c ---*/
5 /*--------------------------------------------------------------------*/
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
12 To build for an x86 (32-bit) host
13 The same, except change -DVGA_amd64 to -DVGA_x86
17 This file is part of Valgrind, a dynamic binary instrumentation
20 Copyright (C) 2013-2017 Mozilla Foundation
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.
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.
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, see <http://www.gnu.org/licenses/>.
35 The GNU General Public License is contained in the file COPYING.
38 /* Contributed by Julian Seward <jseward@acm.org> */
40 /* This code works (just), but it's a mess. Cleanups (also for
41 coregrind/m_debuginfo/image.c):
43 * Build this file for the host arch, not the target. But how?
44 Even Tromey had difficulty figuring out how to do that.
46 * Change the use of pread w/ fd to FILE*, for the file we're
47 serving. Or, at least, put a loop around the pread uses
48 so that it works correctly in the case where pread reads more
49 than zero but less than we asked for.
51 * CRC3 request/response: pass session-IDs back and forth and
54 * Check that all error cases result in a FAIL frame being returned.
56 * image.c: don't assert in cases where a FAIL frame is returned;
57 instead cause the debuginfo reading to fail gracefully. (Not
60 * Improve diagnostic printing
62 * image.c: do we need to do VG_(write_socket) ? Will it work
63 just to use ordinary VG_(write) ?
65 * Both files: document the reason for setting TCP_NODELAY
67 * Add a command line argument saying where the served-from
68 directory is -- changes clo_serverpath.
70 * Fix up (common up) massive code duplication between client and
73 * Tidy up the LZO source files; integrate properly in the build
77 /*---------------------------------------------------------------*/
79 /* Include valgrind headers before system headers to avoid problems
80 with the system headers #defining things which are used as names
81 of structure members in vki headers. */
83 #include "pub_core_basics.h"
84 #include "pub_core_libcassert.h" // For VG_BUGS_TO
85 #include "pub_core_vki.h" // Avoids warnings from
86 // pub_core_libcfile.h
87 #include "pub_core_libcfile.h" // For VG_CLO_DEFAULT_LOGPORT
89 /* Needed to get a definition for pread() from unistd.h */
91 #define _XOPEN_SOURCE 600
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>
108 #include "../coregrind/m_debuginfo/minilzo.h"
110 /*---------------------------------------------------------------*/
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
117 /* The maximum allowable number of concurrent connections. */
118 unsigned M_CONNECTIONS
= 0;
120 static const char* clo_serverpath
= ".";
123 /*---------------------------------------------------------------*/
125 __attribute__ ((noreturn
))
126 static void panic ( const char* str
)
129 "\nvalgrind-di-server: the "
130 "'impossible' happened:\n %s\n", str
);
132 "Please report this bug at: %s\n\n", VG_BUGS_TO
);
136 __attribute__ ((noreturn
))
137 static void my_assert_fail ( const char* expr
, const char* file
, int line
, const char* fn
)
140 "\nvalgrind-di-server: %s:%d (%s): Assertion '%s' failed.\n",
141 file
, line
, fn
, expr
);
143 "Please report this bug at: %s\n\n", VG_BUGS_TO
);
149 #define assert(expr) \
150 ((void) ((expr) ? 0 : \
151 (my_assert_fail (VG_STRINGIFY(expr), \
152 __FILE__, __LINE__, \
153 __PRETTY_FUNCTION__), 0)))
156 /*---------------------------------------------------------------*/
158 /* Allocate some memory. Return iff successful. */
159 static void *my_malloc(size_t amount
)
161 void *p
= malloc(amount
?: 1);
164 fprintf(stderr
, "Memory allocation failed; cannot continue.\n");
170 /*---------------------------------------------------------------*/
172 /* Holds the state that we need to track, for each connection. */
175 // is this entry in use?
177 // socket descriptor to communicate with client. Initialised as
178 // soon as this entry is created.
180 // fd for the file that we are connected to. Zero if not
181 // currently connected to any file.
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)
193 /* The state itself. */
194 static int conn_count
= 0;
195 static ConnState
*conn_state
;
197 /* Issues unique session ID values. */
198 static ULong next_session_id
= 1;
201 /*---------------------------------------------------------------*/
203 // Code that is duplicated with the client :-(
205 /* The following Adler-32 checksum code is taken from zlib-1.2.3, which
206 has the following copyright notice. */
210 (C) 1995-2004 Jean-loup Gailly and Mark Adler
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.
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:
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.
228 Jean-loup Gailly Mark Adler
229 jloup@gzip.org madler@alumni.caltech.edu
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.
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
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. */
248 UInt
adler32( UInt adler
, const UChar
* buf
, UInt len
)
250 # define BASE 65521UL /* largest prime smaller than 65536 */
252 /* NMAX is the largest n such that
253 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
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);
261 /* The zlib sources recommend this definition of MOD if the
262 processor cannot do integer division in hardware. */
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; \
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; \
295 /* split Adler-32 into component sums */
296 sum2
= (adler
>> 16) & 0xffff;
299 /* in case user likes doing a byte at a time, keep it fast */
307 return adler
| (sum2
<< 16);
310 /* initial Adler-32 value (deferred check for len == 1 speed) */
314 /* in case short lengths are provided, keep it somewhat fast */
322 MOD4(sum2
); /* only added so many BASE's */
323 return adler
| (sum2
<< 16);
326 /* do length NMAX blocks -- requires just one modulo operation */
327 while (len
>= NMAX
) {
329 n
= NMAX
/ 16; /* NMAX is divisible by 16 */
331 DO16(buf
); /* 16 sums unrolled */
338 /* do remaining bytes (less than NMAX, still just one modulo) */
339 if (len
) { /* avoid modulos if none remaining */
353 /* return recombined sums */
354 return adler
| (sum2
<< 16);
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
;
373 static void write_UInt_le ( /*OUT*/UChar
* dst
, UInt n
)
376 for (i
= 0; i
<= 3; i
++) {
377 dst
[i
] = (UChar
)(n
& 0xFF);
382 static UInt
read_UInt_le ( UChar
* src
)
386 for (i
= 3; i
>= 0; i
--) {
393 static void write_ULong_le ( /*OUT*/UChar
* dst
, ULong n
)
396 for (i
= 0; i
<= 7; i
++) {
397 dst
[i
] = (UChar
)(n
& 0xFF);
402 static ULong
read_ULong_le ( UChar
* src
)
406 for (i
= 7; i
>= 0; i
--) {
413 static Frame
* mk_Frame_asciiz ( const char* tag
, const char* str
)
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);
426 static Bool
parse_Frame_noargs ( Frame
* fr
, const HChar
* tag
)
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
;
436 static Bool
parse_Frame_asciiz ( Frame
* fr
, const HChar
* tag
,
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. */
449 if (i
>= fr
->n_data
) break;
450 if (fr
->data
[i
] == 0) break;
453 assert(i
<= fr
->n_data
);
454 if (i
== fr
->n_data
-1 && fr
->data
[i
] == 0) {
462 static Frame
* mk_Frame_le64 ( const HChar
* tag
, ULong n1
)
464 assert(strlen(tag
) == 4);
465 Frame
* f
= calloc(sizeof(Frame
), 1);
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
);
473 static Frame
* mk_Frame_le64_le64 ( const HChar
* tag
, ULong n1
, ULong n2
)
475 assert(strlen(tag
) == 4);
476 Frame
* f
= calloc(sizeof(Frame
), 1);
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
);
485 static Bool
parse_Frame_le64_le64_le64 ( Frame
* fr
, const HChar
* tag
,
486 /*OUT*/ULong
* n1
, /*OUT*/ULong
* n2
,
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]);
500 static Frame
* mk_Frame_le64_le64_le64_bytes (
502 ULong n1
, ULong n2
, ULong n3
, ULong n_data
,
503 /*OUT*/UChar
** data
)
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];
517 static void free_Frame ( Frame
* fr
)
519 assert(fr
&& fr
->data
);
525 static void set_blocking ( int sd
)
528 res
= fcntl(sd
, F_GETFL
);
529 res
= fcntl(sd
, F_SETFL
, res
& ~O_NONBLOCK
);
531 perror("fcntl failed");
532 panic("set_blocking");
538 static void set_nonblocking ( int sd
)
541 res
= fcntl(sd
, F_GETFL
);
542 res
= fcntl(sd
, F_SETFL
, res
| O_NONBLOCK
);
544 perror("fcntl failed");
545 panic("set_nonblocking");
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
555 static SizeT
my_read ( Int fd
, UChar
* buf
, SizeT len
)
560 if (nRead
== len
) return nRead
;
562 SizeT nNeeded
= len
- nRead
;
564 SSizeT n
= read(fd
, &buf
[nRead
], nNeeded
);
565 if (n
<= 0) return nRead
; /* error or EOF */
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
574 static SizeT
my_write ( Int fd
, UChar
* buf
, SizeT len
)
576 //set_nonblocking(fd);
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 */
590 static UInt
calc_gnu_debuglink_crc32(/*OUT*/Bool
* ok
, int fd
, ULong size
)
592 static const UInt crc32_table
[256] =
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,
648 /* Work through the image in 1 KB chunks. */
649 UInt crc
= 0xFFFFFFFF;
650 ULong img_szB
= size
;
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;
659 Int nRead
= pread(fd
, buf
, avail
, curr_off
);
660 if (nRead
<= 0) { /* EOF or error on the file; neither should happen */
664 /* this is a kludge .. we should loop around pread and deal
665 with short reads, for whatever reason */
666 assert(nRead
== avail
);
668 for (i
= 0; i
< (UInt
)nRead
; i
++)
669 crc
= crc32_table
[(crc
^ buf
[i
]) & 0xff] ^ (crc
>> 8);
673 return ~crc
& 0xFFFFFFFF;
677 /*---------------------------------------------------------------*/
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. */
685 static Bool
handle_transaction ( int conn_no
)
687 Frame
* req
= NULL
; /* the request frame that we receive */
688 Frame
* res
= NULL
; /* the response frame that we send back */
690 assert(conn_no
>= 0 && conn_no
< M_CONNECTIONS
);
691 assert(conn_state
[conn_no
].in_use
);
693 //printf("SERVER: handle_transaction(%d)\n", conn_no); fflush(stdout);
695 Int sd
= conn_state
[conn_no
].conn_sd
;
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
;
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
;
709 req
= calloc(sizeof(Frame
), 1);
710 req
->n_data
= rd_len
;
711 req
->data
= calloc(rd_len
, 1);
713 Int r
= my_read(sd
, req
->data
, req
->n_data
);
714 if (r
!= rd_len
) goto fail
;
716 //printf("SERVER: recv %c%c%c%c\n", req->data[0], req->data[1], req->data[2], req->data[3]); fflush(stdout);
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);
722 adler
= adler32(adler
, req
->data
, req
->n_data
);
724 if (adler
/*computed*/ != rd_adler
/*expected*/) goto fail
;
726 /* Now we have a request frame. Cook up a response. */
729 UChar
* filename
= NULL
;
730 ULong req_session_id
= 0, req_offset
= 0, req_len
= 0;
732 if (parse_Frame_noargs(req
, "VERS")) {
733 res
= mk_Frame_asciiz("VEOK", "Valgrind Debuginfo Server, Version 1");
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");
742 UInt crc32
= calc_gnu_debuglink_crc32(&ok
,
743 conn_state
[conn_no
].file_fd
,
744 conn_state
[conn_no
].file_size
);
746 res
= mk_Frame_le64("CROK", (ULong
)crc32
);
748 res
= mk_Frame_asciiz("FAIL", "CRC3: I/O error reading file");
753 if (parse_Frame_asciiz(req
, "OPEN", &filename
)) {
756 if (conn_state
[conn_no
].file_fd
!= 0) {
757 res
= mk_Frame_asciiz("FAIL", "OPEN: already connected to file");
761 assert(clo_serverpath
);
762 fd
= open((char*)filename
, O_RDONLY
);
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
);
773 struct stat stat_buf
;
774 int r
= fstat(fd
, &stat_buf
);
776 res
= mk_Frame_asciiz("FAIL", "OPEN: cannot stat file");
780 if (ok
&& stat_buf
.st_size
== 0) {
781 res
= mk_Frame_asciiz("FAIL", "OPEN: file has zero size");
786 conn_state
[conn_no
].file_fd
= fd
;
787 conn_state
[conn_no
].file_size
= stat_buf
.st_size
;
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
);
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. */
805 if (req_session_id
!= conn_state
[conn_no
].session_id
) {
806 res
= mk_Frame_asciiz("FAIL", "READ: invalid session ID");
809 /* Check we're connected to a file, and if so range-check the
811 if (ok
&& conn_state
[conn_no
].file_fd
== 0) {
812 res
= mk_Frame_asciiz("FAIL", "READ: no associated file");
815 if (ok
&& (req_len
== 0 || req_len
> 4*1024*1024)) {
816 res
= mk_Frame_asciiz("FAIL", "READ: invalid request size");
819 if (ok
&& req_len
+ req_offset
> conn_state
[conn_no
].file_size
) {
820 res
= mk_Frame_asciiz("FAIL", "READ: request exceeds file size");
823 /* Try to read the file. */
825 /* First, allocate a temp buf and read from the file into it. */
826 /* FIXME: what if pread reads short and we have to redo it? */
827 UChar
* unzBuf
= my_malloc(req_len
);
828 size_t nRead
= pread(conn_state
[conn_no
].file_fd
,
829 unzBuf
, req_len
, req_offset
);
830 if (nRead
!= req_len
) {
832 res
= mk_Frame_asciiz("FAIL", "READ: I/O error reading file");
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 \
842 + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
843 STACK_ALLOC(wrkmem
, LZO1X_1_MEM_COMPRESS
);
845 UInt zLenMax
= req_len
+ req_len
/ 4 + 1024;
846 UChar
* zBuf
= my_malloc(zLenMax
);
847 lzo_uint zLen
= zLenMax
;
848 Int lzo_rc
= lzo1x_1_compress(unzBuf
, req_len
,
849 zBuf
, &zLen
, wrkmem
);
850 if (lzo_rc
== LZO_E_OK
) {
851 //printf("XXXXX req_len %u zLen %u\n", (UInt)req_len, (UInt)zLen);
852 assert(zLen
<= zLenMax
);
853 /* Make a frame to put the results in. Bytes 24 and
854 onwards need to be filled from the compressed data,
855 and 'buf' is set to point to the right bit. */
857 res
= mk_Frame_le64_le64_le64_bytes
858 ("RDOK", req_session_id
, req_offset
, req_len
, zLen
, &buf
);
861 memcpy(buf
, zBuf
, zLen
);
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
;
869 res
= mk_Frame_asciiz("FAIL", "READ: LZO failed");
877 res
= mk_Frame_asciiz("FAIL", "Invalid request frame type");
880 /* All paths through the above should result in an assignment to |res|. */
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[].
888 /* The initial Adler-32 value */
889 adler
= adler32(0, NULL
, 0);
891 /* Fold in the length field, encoded as le32. */
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
);
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
;
905 //printf("SERVER: send %c%c%c%c\n", res->data[0], res->data[1], res->data[2], res->data[3]); fflush(stdout);
910 return False
; /* "connection still in use" */
912 // Is there any difference between these?
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
);
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
);
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" */
942 /*---------------------------------------------------------------*/
947 static void copyout ( char* buf
, int nbuf
)
950 for (i
= 0; i
< nbuf
; i
++) {
951 if (buf
[i
] == '\n') {
952 fprintf(stdout
, "\n(%d) ", conn_count
);
954 __attribute__((unused
)) size_t ignored
955 = fwrite(&buf
[i
], 1, 1, stdout
);
961 static int read_from_sd ( int sd
)
967 n
= read(sd
, buf
, 99);
968 if (n
<= 0) return 0; /* closed */
973 n
= read(sd
, buf
, 100);
974 if (n
<= 0) return 1; /* not closed */
980 static void snooze ( void )
984 req
.tv_nsec
= 200 * 1000 * 1000;
985 nanosleep(&req
,NULL
);
989 /* returns 0 if negative, or > BOUND or invalid characters were found */
990 static int atoi_with_bound ( const char* str
, int bound
)
996 if (*str
< '0' || *str
> '9')
998 n
= 10*n
+ (int)(*str
- '0');
1007 /* returns 0 if invalid, else port # */
1008 static int atoi_portno ( const char* str
)
1010 int n
= atoi_with_bound(str
, 65536);
1018 static void usage ( void )
1024 " valgrind-di-server [--exit-at-zero|-e] [port-number]\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"
1030 " --max-connect=INT can be used to increase the maximum\n"
1031 " number of connected processes (default = %d).\n"
1032 " INT must be positive and less than %d.\n"
1034 " port-number is the default port on which to listen for\n"
1035 " connections. It must be between 1024 and 65535.\n"
1036 " Current default is %d.\n"
1039 M_CONNECTIONS_DEFAULT
, M_CONNECTIONS_MAX
, VG_CLO_DEFAULT_LOGPORT
1045 static void banner ( const char* str
)
1049 printf("valgrind-di-server %s at %s", str
, ctime(&t
));
1054 static void exit_routine ( void )
1061 static void sigint_handler ( int signo
)
1067 int main (int argc
, char** argv
)
1070 int main_sd
, new_sd
;
1071 socklen_t client_len
;
1072 struct sockaddr_in client_addr
, server_addr
;
1074 char /*bool*/ exit_when_zero
= 0;
1075 int port
= VG_CLO_DEFAULT_LOGPORT
;
1077 for (i
= 1; i
< argc
; i
++) {
1078 if (0==strcmp(argv
[i
], "--exit-at-zero")
1079 || 0==strcmp(argv
[i
], "-e")) {
1082 else if (0 == strncmp(argv
[i
], "--max-connect=", 14)) {
1083 M_CONNECTIONS
= atoi_with_bound(strchr(argv
[i
], '=') + 1, 5000);
1084 if (M_CONNECTIONS
<= 0 || M_CONNECTIONS
> M_CONNECTIONS_MAX
)
1088 if (atoi_portno(argv
[i
]) > 0) {
1089 port
= atoi_portno(argv
[i
]);
1095 if (M_CONNECTIONS
== 0) // nothing specified on command line
1096 M_CONNECTIONS
= M_CONNECTIONS_DEFAULT
;
1098 conn_state
= my_malloc(M_CONNECTIONS
* sizeof conn_state
[0]);
1101 signal(SIGINT
, sigint_handler
);
1104 memset(conn_state
, 0, M_CONNECTIONS
* sizeof conn_state
[0]);
1107 main_sd
= socket(AF_INET
, SOCK_STREAM
, 0);
1109 perror("cannot open socket ");
1110 panic("main -- create socket");
1113 /* allow address reuse to avoid "address already in use" errors */
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");
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
);
1127 if (bind(main_sd
, (struct sockaddr
*) &server_addr
,
1128 sizeof(server_addr
) ) < 0) {
1129 perror("cannot bind port ");
1130 panic("main -- bind port");
1133 res
= listen(main_sd
, M_CONNECTIONS
);
1135 perror("listen failed ");
1136 panic("main -- listen");
1139 Bool do_snooze
= False
;
1145 /* Snooze after this iteration, unless something happened. */
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
;
1154 ufd
.events
= POLLIN
;
1156 res
= poll(&ufd
, 1, 0/*ms*/ /* 0=return immediately. */);
1157 if (res
== 0) break;
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
,
1164 perror("cannot accept connection ");
1165 panic("main -- accept connection");
1168 /* find a place to put it. */
1170 for (i
= 0; i
< M_CONNECTIONS
; i
++)
1171 if (!conn_state
[i
].in_use
)
1174 if (i
>= M_CONNECTIONS
) {
1175 fprintf(stderr
, "\n\nMore than %d concurrent connections.\n"
1176 "Restart the server giving --max-connect=INT on the\n"
1177 "commandline to increase the limit.\n\n",
1183 int ret
= setsockopt( new_sd
, IPPROTO_TCP
, TCP_NODELAY
, &one
, sizeof(one
));
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
);
1197 /* We've processed all new connect requests. Listen for changes
1198 to the current set of fds. This requires gathering up all
1199 the known conn_sd values and doing poll() on them. */
1200 static struct pollfd
*tmp_pollfd
;
1201 if (tmp_pollfd
== NULL
)
1202 tmp_pollfd
= my_malloc(M_CONNECTIONS
* sizeof tmp_pollfd
[0]);
1204 /* And a parallel array which maps entries in tmp_pollfd back to
1205 entries in conn_state. */
1206 static int *tmp_pollfd_to_conn_state
;
1207 if (tmp_pollfd_to_conn_state
== NULL
)
1208 tmp_pollfd_to_conn_state
=
1209 my_malloc(M_CONNECTIONS
* sizeof tmp_pollfd_to_conn_state
[0]);
1212 for (i
= 0; i
< M_CONNECTIONS
; i
++) {
1213 if (!conn_state
[i
].in_use
)
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
;
1223 res
= poll(tmp_pollfd
, j
, 20/*ms*/ /* 0=return immediately. */ );
1225 perror("poll(main) failed");
1226 panic("poll(main) failed");
1229 /* nothing happened. go round again. */
1234 /* inspect the fds. */
1235 for (i
= 0; i
< j
; i
++) {
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
);
1244 /* this connection has been closed or otherwise gone
1245 bad; forget about it. */
1248 if (conn_count
== 0 && exit_when_zero
) {
1249 if (0) printf("\n");
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);
1268 } /* for (i = 0; i < j; i++) */
1277 ////////////////////////////////////////////////////
1278 #include "../coregrind/m_debuginfo/minilzo-inl.c"
1280 /*--------------------------------------------------------------------*/
1281 /*--- end valgrind-di-server.c ---*/
1282 /*--------------------------------------------------------------------*/