Addition of libbitdht.

============================================================

This is intended to be a completely independent library from RS, 
(hosted at sf.net/projects/bitdht) hence is being commited at the top level.

As initial further development / testing will be driven by RS integration
it is being added to the RS repository. Equally important is ensuring
that RS can compile without requiring aux libraries.

Once libbitdht is further developed, this section of the repository
is expected to be removed... But that will not be for a while, I expect.

drbob.



git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3276 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2010-07-10 11:48:24 +00:00
parent 9b72977bba
commit c415bb6158
56 changed files with 11344 additions and 0 deletions
libbitdht/src/bitdht

View file

@ -0,0 +1,602 @@
/*
* C implementation of a bencode decoder.
* This is the format defined by BitTorrent:
* http://wiki.theory.org/BitTorrentSpecification#bencoding
*
* The only external requirements are a few [standard] function calls and
* the long long type. Any sane system should provide all of these things.
*
* See the bencode.h header file for usage information.
*
* This is released into the public domain.
* Written by Mike Frysinger <vapier@gmail.com>.
*/
/*
* This implementation isn't optimized at all as I wrote it to support
* a bogus system. I have no real interest in this format. Feel free
* to send me patches (so long as you don't copyright them and you release
* your changes into the public domain as well).
*/
#include <stdio.h>
#include <stdlib.h> /* malloc() realloc() free() strtoll() */
#include <string.h> /* memset() */
#include "bencode.h"
/***
* #define BE_DEBUG_DECODE 1
***/
//#define BE_DEBUG_DECODE 1
#ifdef BE_DEBUG_DECODE
#include <stdio.h> /* debug */
#endif
static be_node *be_alloc(be_type type)
{
be_node *ret = (be_node *) malloc(sizeof(*ret));
if (ret) {
memset(ret, 0x00, sizeof(*ret));
ret->type = type;
}
return ret;
}
static long long _be_decode_int(const char **data, long long *data_len)
{
char *endp;
long long ret = strtoll(*data, &endp, 10);
*data_len -= (endp - *data);
*data = endp;
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode_int(pnt: %p, rem: %lld) = %lld\n", *data, *data_len, ret);
#endif
return ret;
}
long long be_str_len(be_node *node)
{
long long ret = 0;
if (node->val.s)
memcpy(&ret, node->val.s - sizeof(ret), sizeof(ret));
return ret;
}
static char *_be_decode_str(const char **data, long long *data_len)
{
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode_str(pnt: %p, rem: %lld)\n", *data, *data_len);
#endif
long long sllen = _be_decode_int(data, data_len);
long slen = sllen;
unsigned long len;
char *ret = NULL;
/* slen is signed, so negative values get rejected */
if (sllen < 0)
{
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode_str() reject bad length\n");
#endif
return ret;
}
/* reject attempts to allocate large values that overflow the
* size_t type which is used with malloc()
*/
if (sizeof(long long) != sizeof(long))
if (sllen != slen)
{
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode_str() reject large_values\n");
#endif
return ret;
}
/* make sure we have enough data left */
if (sllen > *data_len - 1)
{
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode_str() reject large_values\n");
#endif
return ret;
}
/* switch from signed to unsigned so we don't overflow below */
len = slen;
if (**data == ':') {
char *_ret = (char *) malloc(sizeof(sllen) + len + 1);
memcpy(_ret, &sllen, sizeof(sllen));
ret = _ret + sizeof(sllen);
memcpy(ret, *data + 1, len);
ret[len] = '\0';
*data += len + 1;
*data_len -= len + 1;
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode_str() read %ld bytes\n", len+1);
#endif
}
else
{
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode_str() reject missing :\n");
#endif
}
return ret;
}
static be_node *_be_decode(const char **data, long long *data_len)
{
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode(pnt: %p, rem: %lld)\n", *data, *data_len);
#endif
be_node *ret = NULL;
if (!*data_len)
{
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() reject invalid datalen\n");
#endif
return ret;
}
switch (**data) {
/* lists */
case 'l': {
unsigned int i = 0;
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() found list\n");
#endif
ret = be_alloc(BE_LIST);
--(*data_len);
++(*data);
while (**data != 'e') {
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() list get item (%d)\n", i);
#endif
ret->val.l = (be_node **) realloc(ret->val.l, (i + 2) * sizeof(*ret->val.l));
ret->val.l[i] = _be_decode(data, data_len);
if (ret->val.l[i] == NULL)
{
/* failed decode - kill decode */
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() failed list decode - kill\n");
#endif
be_free(ret);
return NULL;
}
++i;
}
--(*data_len);
++(*data);
/* empty list case. */
if (i == 0)
{
ret->val.l = (be_node **) realloc(ret->val.l, 1 * sizeof(*ret->val.l));
}
ret->val.l[i] = NULL;
return ret;
}
/* dictionaries */
case 'd': {
unsigned int i = 0;
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() found dictionary\n");
#endif
ret = be_alloc(BE_DICT);
--(*data_len);
++(*data);
while (**data != 'e') {
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() dictionary get key (%d)\n", i);
#endif
ret->val.d = (be_dict *) realloc(ret->val.d, (i + 2) * sizeof(*ret->val.d));
ret->val.d[i].key = _be_decode_str(data, data_len);
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() dictionary get val\n");
#endif
ret->val.d[i].val = _be_decode(data, data_len);
if ((ret->val.d[i].key == NULL) || (ret->val.d[i].val == NULL))
{
/* failed decode - kill decode */
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() failed dict decode - kill\n");
#endif
be_free(ret);
return NULL;
}
++i;
}
--(*data_len);
++(*data);
/* empty dictionary case. */
if (i == 0)
{
ret->val.d = (be_dict *) realloc(ret->val.d, 1 * sizeof(*ret->val.d));
}
ret->val.d[i].val = NULL;
return ret;
}
/* integers */
case 'i': {
ret = be_alloc(BE_INT);
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() found int\n");
#endif
--(*data_len);
++(*data);
ret->val.i = _be_decode_int(data, data_len);
if (**data != 'e')
{
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() reject data != e - kill\n");
#endif
be_free(ret);
return NULL;
}
--(*data_len);
++(*data);
return ret;
}
/* byte strings */
case '0'...'9': {
ret = be_alloc(BE_STR);
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() found string\n");
#endif
ret->val.s = _be_decode_str(data, data_len);
return ret;
}
/* invalid */
default:
#ifdef BE_DEBUG_DECODE
fprintf(stderr, "bencode::_be_decode() found invalid - kill\n");
#endif
return NULL;
break;
}
return ret;
}
be_node *be_decoden(const char *data, long long len)
{
return _be_decode(&data, &len);
}
be_node *be_decode(const char *data)
{
return be_decoden(data, strlen(data));
}
static inline void _be_free_str(char *str)
{
if (str)
free(str - sizeof(long long));
}
void be_free(be_node *node)
{
switch (node->type) {
case BE_STR:
_be_free_str(node->val.s);
break;
case BE_INT:
break;
case BE_LIST: {
unsigned int i;
for (i = 0; node->val.l[i]; ++i)
be_free(node->val.l[i]);
free(node->val.l);
break;
}
case BE_DICT: {
unsigned int i;
for (i = 0; node->val.d[i].val; ++i) {
_be_free_str(node->val.d[i].key);
be_free(node->val.d[i].val);
}
free(node->val.d);
break;
}
}
free(node);
}
#ifdef BE_DEBUG
#include <stdio.h>
#include <stdint.h>
static void _be_dump_indent(ssize_t indent)
{
while (indent-- > 0)
printf(" ");
}
static void _be_dump(be_node *node, ssize_t indent)
{
size_t i;
_be_dump_indent(indent);
indent = abs(indent);
switch (node->type) {
case BE_STR:
be_dump_str(node);
//printf("str = %s (len = %lli)\n", node->val.s, be_str_len(node));
break;
case BE_INT:
printf("int = %lli\n", node->val.i);
break;
case BE_LIST:
puts("list [");
for (i = 0; node->val.l[i]; ++i)
_be_dump(node->val.l[i], indent + 1);
_be_dump_indent(indent);
puts("]");
break;
case BE_DICT:
puts("dict {");
for (i = 0; node->val.d[i].val; ++i) {
_be_dump_indent(indent + 1);
printf("%s => ", node->val.d[i].key);
_be_dump(node->val.d[i].val, -(indent + 1));
}
_be_dump_indent(indent);
puts("}");
break;
}
}
void be_dump(be_node *node)
{
_be_dump(node, 0);
}
void be_dump_str(be_node *node)
{
if (node->type != BE_STR)
{
printf("be_dump_str(): error not a string\n");
return;
}
int len = be_str_len(node);
printf("str[%d] = ", len);
for(int i = 0; i < len; i++)
{
/* sensible chars */
if ((node->val.s[i] > 31) && (node->val.s[i] < 127))
{
printf("%c", node->val.s[i]);
}
else
{
printf("[%d]", node->val.s[i]);
}
}
printf("\n");
}
#endif
/******************** New Functions added by drBob *************
* Output bencode
*
*/
int be_encode(be_node *node, char *str, int len)
{
size_t i;
int loc = 0;
switch (node->type) {
case BE_STR:
snprintf(str, len, "%lli:", be_str_len(node));
loc += strlen(&(str[loc]));
memcpy(&(str[loc]), node->val.s, be_str_len(node));
loc += be_str_len(node);
break;
case BE_INT:
snprintf(str, len, "i%llie", node->val.i);
loc += strlen(&(str[loc]));
break;
case BE_LIST:
snprintf(str, len, "l");
loc += 1;
for (i = 0; node->val.l[i]; ++i)
{
loc += be_encode(node->val.l[i], &(str[loc]), len-loc);
}
snprintf(&(str[loc]), len - loc, "e");
loc += 1;
break;
case BE_DICT:
snprintf(str, len, "d");
loc += 1;
for (i = 0; node->val.d[i].val; ++i) {
/* assumption that key must be ascii! */
snprintf(&(str[loc]), len-loc, "%i:%s",
(int) strlen(node->val.d[i].key),
node->val.d[i].key);
loc += strlen(&(str[loc]));
loc += be_encode(node->val.d[i].val, &(str[loc]), len-loc);
}
snprintf(&(str[loc]), len - loc, "e");
loc += 1;
break;
}
return loc;
}
/* hackish way to create nodes! */
be_node *be_create_dict()
{
be_node *n = be_decode("de");
return n;
}
be_node *be_create_list()
{
be_node *n = be_decode("le");
return n;
}
be_node *be_create_str(const char *str)
{
/* must */
be_node *n = be_alloc(BE_STR);
int len = strlen(str);
long long int sllen = len;
char *_ret = (char *) malloc(sizeof(sllen) + len + 1);
char *ret = NULL;
memcpy(_ret, &sllen, sizeof(sllen));
ret = _ret + sizeof(sllen);
memcpy(ret, str, len);
ret[len] = '\0';
n->val.s = ret;
return n;
}
be_node *be_create_str_wlen(const char *str, int len) /* not including \0 */
{
/* must */
be_node *n = be_alloc(BE_STR);
long long int sllen = len;
char *_ret = (char *) malloc(sizeof(sllen) + len + 1);
char *ret = NULL;
memcpy(_ret, &sllen, sizeof(sllen));
ret = _ret + sizeof(sllen);
memcpy(ret, str, len);
ret[len] = '\0';
n->val.s = ret;
return n;
}
be_node *be_create_int(long long int num)
{
/* must */
be_node *n = be_alloc(BE_INT);
n->val.i = num;
return n;
}
int be_add_keypair(be_node *dict, const char *str, be_node *node)
{
int i = 0;
/* only if dict type */
if (dict->type != BE_DICT)
{
return 0;
}
// get to end of dict.
for(i = 0; dict->val.d[i].val; i++);
//fprintf(stderr, "be_add_keypair() i = %d\n",i);
/* realloc space */
dict->val.d = (be_dict *) realloc(dict->val.d, (i + 2) * sizeof(*dict->val.d));
/* stupid key storage system */
int len = strlen(str);
long long int sllen = len;
char *_ret = (char *) malloc(sizeof(sllen) + len + 1);
char *ret = NULL;
//fprintf(stderr, "be_add_keypair() key len = %d\n",len);
memcpy(_ret, &sllen, sizeof(sllen));
ret = _ret + sizeof(sllen);
memcpy(ret, str, len);
ret[len] = '\0';
dict->val.d[i].key = ret;
dict->val.d[i].val = node;
i++;
dict->val.d[i].val = NULL;
return 1;
}
int be_add_list(be_node *list, be_node *node)
{
int i = 0;
/* only if dict type */
if (list->type != BE_LIST)
{
return 0;
}
// get to end of dict.
for(i = 0; list->val.l[i]; i++);
/* realloc space */
list->val.l = (be_node **) realloc(list->val.l, (i + 2) * sizeof(*list->val.l));
list->val.l[i] = node;
++i;
list->val.l[i] = NULL;
return 1;
}