paulo@0: /* paulo@0: * $Id: gt_utils.c,v 1.10 2004/04/17 06:05:54 hipnod Exp $ paulo@0: * paulo@0: * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: paulo@0: #include "gt_utils.h" paulo@0: paulo@0: #ifdef USE_ZLIB paulo@0: #include paulo@0: #endif /* USE_ZLIB */ paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: int peer_addr (int fd, in_addr_t *r_ip, in_port_t *r_port) paulo@0: { paulo@0: struct sockaddr_in sin; paulo@0: int len = sizeof (struct sockaddr_in); paulo@0: paulo@0: if (getpeername (fd, (struct sockaddr *) &sin, &len) < 0) paulo@0: return FALSE; paulo@0: paulo@0: /* maybe port should be kept in network byte-order */ paulo@0: if (r_port) paulo@0: *r_port = ntohs (sin.sin_port); paulo@0: paulo@0: if (r_ip) paulo@0: *r_ip = sin.sin_addr.s_addr; paulo@0: paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: char *make_str (char *array, int len) paulo@0: { paulo@0: static int data_len = 0; paulo@0: static char *data = 0; paulo@0: paulo@0: if (len <= 0) paulo@0: return ""; paulo@0: paulo@0: if (!data_len || data_len < len) paulo@0: { paulo@0: if (data) paulo@0: free (data); paulo@0: paulo@0: if (!(data = malloc (len + 1))) paulo@0: return "(No memory for string)"; paulo@0: } paulo@0: paulo@0: memcpy (data, array, len); paulo@0: paulo@0: data[len] = 0; paulo@0: paulo@0: if (len > data_len) paulo@0: data_len = len; paulo@0: paulo@0: return data; paulo@0: } paulo@0: paulo@0: void fprint_hex (FILE *f, char *buf, int len) paulo@0: { paulo@0: int i, j; paulo@0: unsigned char *line; paulo@0: unsigned char *end; paulo@0: paulo@0: end = buf + len; paulo@0: paulo@0: while ((line = buf) != end) paulo@0: { paulo@0: for (i = 0; i < 16; i++) paulo@0: { paulo@0: if (line + i == end) paulo@0: break; paulo@0: paulo@0: fprintf (f, "%02x ", line[i]); paulo@0: } paulo@0: paulo@0: for (j = i; j < 16; j++) paulo@0: fprintf (f, " "); paulo@0: paulo@0: fprintf (f, " "); paulo@0: paulo@0: for (i = 0; i < 16; i++) paulo@0: { paulo@0: if (line + i == end) paulo@0: break; paulo@0: paulo@0: fprintf (f, "%c", isprint (line[i]) ? line[i] : '.'); paulo@0: } paulo@0: paulo@0: buf += i; paulo@0: fprintf (f, "\n"); paulo@0: } paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: /* HTTP HEADER STORAGE */ paulo@0: paulo@0: #if 0 paulo@0: static unsigned long hash_lowercase (Dataset *d, void *key, size_t key_len) paulo@0: { paulo@0: char *str; paulo@0: int i; paulo@0: unsigned long hash; paulo@0: paulo@0: for (hash = 0, i = 0; i < key_len; i++) paulo@0: hash ^= tolower (str[i]); paulo@0: paulo@0: return hash; paulo@0: } paulo@0: paulo@0: static int cmp_caseless (Dataset *d, DatasetNode *node, void *key, paulo@0: size_t key_len) paulo@0: { paulo@0: return strncasecmp (node->key, key, MIN (node->key_len, key_len)); paulo@0: } paulo@0: paulo@0: /* Like a Dataset, but stores case-insensitive strings for keys to paulo@0: * string fields. */ paulo@0: Headers *headers_new () paulo@0: { paulo@0: Dataset *dataset; paulo@0: paulo@0: if (!(dataset = dataset_new (DATASET_DEFAULT))) paulo@0: return NULL; paulo@0: paulo@0: dataset->hash_func = hash_lowercase; paulo@0: paulo@0: return hdrs; paulo@0: } paulo@0: paulo@0: char *header_lookup (Headers *hdrs, char *key) paulo@0: { paulo@0: char *value; paulo@0: paulo@0: if (!hdrs || !key) paulo@0: return NULL; paulo@0: paulo@0: return dataset_lookupstr (dataset, key); paulo@0: } paulo@0: paulo@0: void header_insert (Headers **hdrs, char *key, char *value) paulo@0: { paulo@0: if (!d || !key) paulo@0: return; paulo@0: paulo@0: if (!(*hdrs) && !(*hdrs = headers_new ())) paulo@0: return; paulo@0: paulo@0: dataset_insertstr (hdrs->dataset, key, value); paulo@0: } paulo@0: paulo@0: void header_remove (Headers *hdrs, char *key) paulo@0: { paulo@0: if (!hdrs) paulo@0: return NULL; paulo@0: paulo@0: dataset_remove (hdrs->dataset, key, size); paulo@0: } paulo@0: #endif paulo@0: paulo@0: /*****************************************************************************/ paulo@0: /* ZLIB WRAPPER ROUTINES */ paulo@0: paulo@0: static char *zlib_strerror (int error) paulo@0: { paulo@0: #ifndef USE_ZLIB paulo@0: return NULL; paulo@0: #else /* USE_ZLIB */ paulo@0: switch (error) paulo@0: { paulo@0: case Z_OK: return "OK"; paulo@0: case Z_STREAM_END: return "End of stream"; paulo@0: case Z_NEED_DICT: return "Decompressing dictionary needed"; paulo@0: case Z_STREAM_ERROR: return "Stream error"; paulo@0: case Z_ERRNO: return "Generic zlib error"; paulo@0: case Z_DATA_ERROR: return "Data error"; paulo@0: case Z_MEM_ERROR: return "Memory error"; paulo@0: case Z_BUF_ERROR: return "Buffer error"; paulo@0: case Z_VERSION_ERROR: return "Incompatible runtime zlib library"; paulo@0: default: break; paulo@0: } paulo@0: paulo@0: return "Invalid zlib error code"; paulo@0: #endif /* USE_ZLIB */ paulo@0: } paulo@0: paulo@0: static void zstream_close (ZlibStream *stream) paulo@0: { paulo@0: #ifdef USE_ZLIB paulo@0: switch (stream->type) paulo@0: { paulo@0: case ZSTREAM_INFLATE: inflateEnd (stream->streamptr); break; paulo@0: case ZSTREAM_DEFLATE: deflateEnd (stream->streamptr); break; paulo@0: default: break; paulo@0: } paulo@0: paulo@0: if (stream->streamptr) paulo@0: free (stream->streamptr); paulo@0: paulo@0: stream->type = ZSTREAM_NONE; paulo@0: stream->streamptr = NULL; paulo@0: #endif /* USE_ZLIB */ paulo@0: } paulo@0: paulo@0: ZlibStream *zlib_stream_open (size_t max_size) paulo@0: { paulo@0: ZlibStream *stream; paulo@0: char *data; paulo@0: paulo@0: if (!(stream = malloc (sizeof (ZlibStream)))) paulo@0: return NULL; paulo@0: paulo@0: if (!(data = malloc (max_size))) paulo@0: { paulo@0: free (stream); paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: memset (stream, 0, sizeof (ZlibStream)); paulo@0: memset (data, 0, max_size); paulo@0: paulo@0: stream->start = data; paulo@0: stream->end = data + max_size; paulo@0: stream->data = data; paulo@0: stream->pos = data; paulo@0: stream->type = ZSTREAM_NONE; paulo@0: paulo@0: return stream; paulo@0: } paulo@0: paulo@0: void zlib_stream_close (ZlibStream *stream) paulo@0: { paulo@0: if (!stream) paulo@0: return; paulo@0: paulo@0: if (stream->type != ZSTREAM_NONE) paulo@0: zstream_close (stream); paulo@0: paulo@0: if (stream->data) paulo@0: free (stream->data); paulo@0: paulo@0: free (stream); paulo@0: } paulo@0: paulo@0: int zlib_stream_write (ZlibStream *stream, char *data, size_t size) paulo@0: { paulo@0: if (!stream) paulo@0: return 0; paulo@0: paulo@0: /* check for overflow */ paulo@0: if (stream->pos + (size-1) > stream->end) paulo@0: return 0; paulo@0: paulo@0: memcpy (stream->pos, data, size); paulo@0: paulo@0: stream->pos += size; paulo@0: paulo@0: return size; paulo@0: } paulo@0: paulo@0: int zlib_stream_read (ZlibStream *stream, char **r_data) paulo@0: { paulo@0: size_t size; paulo@0: paulo@0: if (stream->start == stream->pos) paulo@0: return 0; paulo@0: paulo@0: *r_data = stream->start; paulo@0: paulo@0: size = stream->pos - stream->start; paulo@0: paulo@0: stream->start = stream->pos; paulo@0: paulo@0: return size; paulo@0: } paulo@0: paulo@0: int zlib_stream_inflate (ZlibStream *stream, char *zdata, size_t size) paulo@0: { paulo@0: #ifndef USE_ZLIB paulo@0: return FALSE; paulo@0: #else /* USE_ZLIB */ paulo@0: z_streamp inz; paulo@0: int ret; paulo@0: size_t free_size; paulo@0: paulo@0: if (!stream) paulo@0: return FALSE; paulo@0: paulo@0: if (!stream->streamptr) paulo@0: { paulo@0: assert (stream->type == ZSTREAM_NONE); paulo@0: paulo@0: if (!(inz = malloc (sizeof (*inz)))) paulo@0: return FALSE; paulo@0: paulo@0: inz->zalloc = NULL; paulo@0: inz->zfree = NULL; paulo@0: inz->opaque = NULL; paulo@0: paulo@0: if ((ret = inflateInit (inz)) != Z_OK) paulo@0: { paulo@0: GT->DBGFN (GT, "inflateInit error %s", zlib_strerror (ret)); paulo@0: free (inz); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: stream->type = ZSTREAM_INFLATE; paulo@0: stream->streamptr = inz; paulo@0: } paulo@0: paulo@0: inz = stream->streamptr; paulo@0: paulo@0: /* Argh, I think this is right, but I'm not sure about the +1 */ paulo@0: free_size = stream->end - stream->pos + 1; paulo@0: paulo@0: inz->next_in = zdata; paulo@0: inz->avail_in = size; paulo@0: inz->next_out = stream->pos; paulo@0: inz->avail_out = free_size; paulo@0: paulo@0: GT->DBGFN (GT, "next_out: %p avail_out: %u", inz->next_out, inz->avail_out); paulo@0: paulo@0: if ((ret = inflate (inz, Z_NO_FLUSH)) != Z_OK) paulo@0: { paulo@0: GT->DBGFN (GT, "decompression error: %s", zlib_strerror (ret)); paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: GT->DBGFN (GT, "inz->avail_in = %u, inz->avail_out = %u", inz->avail_in, paulo@0: inz->avail_out); paulo@0: paulo@0: stream->pos += free_size - inz->avail_out; paulo@0: paulo@0: if (ret == Z_STREAM_END) paulo@0: zstream_close (stream); paulo@0: paulo@0: return TRUE; paulo@0: #endif /* USE_ZLIB */ paulo@0: }