static void handle_qhit(const char *data, size_t size) { const struct gnutella_qhit_header *header; const struct gnutella_guid *guid; const struct gnutella_qhit_item *item; size_t guid_offset = size - sizeof *guid; unsigned hits; size_t pos; RUNTIME_ASSERT(size <= GNUTELLA_MAX_PAYLOAD); if (size < sizeof *header) { fprintf(stderr, "handle_qhit(): Too little payload for header.\n"); return; } header = cast_to_const_void_ptr(data); hits = (unsigned char) header->hits; printf("Hits: %u\n", hits); printf("Address: %s\n", net_addr_port_to_string(net_addr_peek_ipv4(cast_to_const_char_ptr(header->addr)), peek_le16(header->port))); printf("Speed: %lu\n", (unsigned long) peek_le32(header->speed)); if (size < sizeof *header + sizeof *guid) { fprintf(stderr, "handle_qhit(): Insufficient payload for query hit.\n"); return; } if (size >= sizeof *header + sizeof *guid) { guid = cast_to_const_void_ptr(&data[guid_offset]); printf("Servent ID: %08lx-%08lx-%08lx-%08lx\n", (unsigned long) peek_be32(&guid->data[0]), (unsigned long) peek_be32(&guid->data[4]), (unsigned long) peek_be32(&guid->data[8]), (unsigned long) peek_be32(&guid->data[12])); } printf("----\n"); pos = sizeof *header; for (/* NOTHING */; hits > 0; hits--) { const char *nul_ptr; if (pos >= guid_offset || guid_offset - pos < sizeof *item + 2) break; item = cast_to_const_void_ptr(&data[pos]); printf("Index: %lu\n", (unsigned long) peek_le32(item->index)); printf("Size: %lu\n", (unsigned long) peek_le32(item->size)); pos += sizeof *item; nul_ptr = memchr(&data[pos], 0, guid_offset - pos); if (!nul_ptr) { fprintf(stderr, "handle_qhit(): Non-terminated filename.\n"); return; } else { size_t len; len = (nul_ptr - &data[pos]); if (len > (((size_t) -1) / 4 - 1)) { fprintf(stderr, "handle_qhit(): Filename is too long.\n"); /* Ignore */ } else { const char *p; size_t avail; printf("Filename: "); avail = len; p = &data[pos]; while (avail > 0) { uint32_t cp; cp = utf8_decode(p, avail); if ((uint32_t) -1 != cp) { uint8_t u_len, i; u_len = utf8_first_byte_length_hint((unsigned char) *p); RUNTIME_ASSERT(u_len > 0); RUNTIME_ASSERT(avail >= u_len); avail -= u_len; if (cp >= 0x20 && cp != 0x7f) { for (i = 0; i < u_len; i++) { putchar((unsigned char) p[i]); } } else { char ch = cp & 0xff; printf("%s", escape_buffer(&ch, 1)); } p += u_len; } else { if (verbosity > 0) { fprintf(stderr, "handle_qhit(): Invalid UTF-8.\n"); } break; } } } printf("\n"); pos += len; } RUNTIME_ASSERT(nul_ptr); RUNTIME_ASSERT(&data[pos] == nul_ptr); RUNTIME_ASSERT('\0' == *nul_ptr); pos++; RUNTIME_ASSERT(pos <= guid_offset); nul_ptr = memchr(&data[pos], 0, guid_offset - pos); if (!nul_ptr) { fprintf(stderr, "handle_qhit(): Non-terminated extension block.\n"); return; } else if (nul_ptr != &data[pos]) { size_t len = nul_ptr - &data[pos]; printf("Extension size: %lu\n", (unsigned long) len); handle_extension(&data[pos], len); pos += len; } RUNTIME_ASSERT(nul_ptr); RUNTIME_ASSERT(&data[pos] == nul_ptr); RUNTIME_ASSERT('\0' == *nul_ptr); pos++; RUNTIME_ASSERT(pos <= guid_offset); printf("------\n"); } if (hits > 0) { fprintf(stderr, "handle_qhit(): Expected %u more hits.\n", hits); } if (pos < guid_offset) { static const unsigned vendor_id_len = 4; printf("Extended QHD size: %lu\n", (unsigned long) guid_offset - pos); if (guid_offset - pos >= vendor_id_len) { printf("Vendor ID: %s\n", escape_buffer(&data[pos], vendor_id_len)); pos += vendor_id_len; if (pos < guid_offset) { uint8_t open_data_size = data[pos]; bool has_ggep = false; printf("Open data size: %u\n", open_data_size); pos++; if (open_data_size > guid_offset - pos) { printf("Open data size is too large.\n"); return; } if (open_data_size >= 2) { uint8_t mask = data[pos]; uint8_t value = data[pos + 1]; printf("mask: 0x%02x\n", mask); printf("value: 0x%02x\n", value); if (0x20 & mask) { has_ggep = 0x20 & value; printf("Has GGEP: %s\n", has_ggep ? "yes" : "no"); } if (0x10 & mask) { printf("Has speed: %s\n", (0x10 & value) ? "yes" : "no"); } if (0x08 & mask) { printf("Has uploaded: %s\n", (0x08 & value) ? "yes" : "no"); } if (0x04 & mask) { printf("Busy: %s\n", (0x04 & value) ? "yes" : "no"); } /* mask and value are swapped */ if (0x01 & value) { printf("Must push: %s\n", (0x01 & mask) ? "yes" : "no"); } } pos += open_data_size; if (pos < guid_offset) { size_t priv_data_size = guid_offset - pos; static const char id_deflate[] = "{deflate}"; const char *priv_data, *x; priv_data = &data[pos]; priv_data_size = guid_offset - pos; printf("Private data area size: %lu\n", (unsigned long) priv_data_size); handle_extension(priv_data, priv_data_size); x = compat_memmem(priv_data, priv_data_size, id_deflate, STATIC_STRLEN(id_deflate)); if (x) { char buf[64 * 1024]; const char *src; size_t n, src_len; src = &x[STATIC_STRLEN(id_deflate)]; src_len = priv_data_size - STATIC_STRLEN(id_deflate); n = buffer_inflate(buf, sizeof buf, src, src_len); if ((size_t) -1 != n) { printf("Inflated: %s\n", escape_buffer(buf, n)); } } pos += priv_data_size; } RUNTIME_ASSERT(pos == guid_offset); } } } printf("----\n"); }
int cmd_check(int argc, char *argv[]) { struct buffer *comp_buf, *uncomp_buf; z_stream stream; struct stat st; int fd; setlocale(LC_ALL, ""); if (argc < 2) usage(); parse_args(argc, argv); init_stream(&stream); fd = open(filename, O_RDONLY); if (fd < 0) die("%s: %s: %s\n", program, filename, strerror(errno)); if (fstat(fd, &st) < 0) die("%s: %s: %s\n", program, filename, strerror(errno)); comp_buf = buffer_mmap(fd, st.st_size); if (!comp_buf) die("%s: %s\n", program, strerror(errno)); stream.next_in = (void *) buffer_start(comp_buf); uncomp_buf = buffer_new(BUFFER_SIZE); if (!uncomp_buf) die("%s: %s\n", program, strerror(errno)); for (;;) { struct itch41_message *msg; retry_size: if (buffer_size(uncomp_buf) < sizeof(u16)) { ssize_t nr; buffer_compact(uncomp_buf); nr = buffer_inflate(comp_buf, uncomp_buf, &stream); if (nr < 0) die("%s: zlib error\n", program); if (!nr) break; if (show_progress) print_progress(comp_buf, st.st_size); goto retry_size; } buffer_advance(uncomp_buf, sizeof(u16)); retry_message: msg = itch41_message_decode(uncomp_buf); if (!msg) { ssize_t nr; buffer_compact(uncomp_buf); nr = buffer_inflate(comp_buf, uncomp_buf, &stream); if (nr < 0) die("%s: zlib error\n", program); if (!nr) break; if (show_progress) print_progress(comp_buf, st.st_size); goto retry_message; } if (verbose) printf("%c", msg->MessageType); stats[msg->MessageType - 'A']++; } printf("\n"); buffer_munmap(comp_buf); buffer_delete(uncomp_buf); if (close(fd) < 0) die("%s: %s: %s\n", program, filename, strerror(errno)); release_stream(&stream); print_stats(); return 0; }
int bats_pitch_read(struct stream *stream, struct pitch_message **msg_p) { struct pitch_message *msg; unsigned char ch; *msg_p = NULL; retry_size: if (buffer_size(stream->uncomp_buf) < sizeof(u8) + sizeof(struct pitch_message)) { ssize_t nr; buffer_compact(stream->uncomp_buf); nr = buffer_inflate(stream->comp_buf, stream->uncomp_buf, stream->zstream); if (nr < 0) return nr; if (!nr) return 0; if (stream->progress) stream->progress(stream->comp_buf); goto retry_size; } ch = buffer_peek_8(stream->uncomp_buf); if (ch != 0x53) return -EINVAL; buffer_advance(stream->uncomp_buf, sizeof(u8)); retry_message: msg = pitch_message_decode(stream->uncomp_buf, 1); if (!msg) { ssize_t nr; buffer_compact(stream->uncomp_buf); nr = buffer_inflate(stream->comp_buf, stream->uncomp_buf, stream->zstream); if (nr < 0) return nr; if (!nr) return 0; if (stream->progress) stream->progress(stream->comp_buf); goto retry_message; } ch = buffer_peek_8(stream->uncomp_buf); if (ch != 0x0A) return -EINVAL; buffer_advance(stream->uncomp_buf, sizeof(u8)); *msg_p = msg; return 0; }