static uint64_t parsePriorities( tr_torrent * tor, const uint8_t * buf, uint32_t len ) { uint64_t ret = 0; if( len == (uint32_t)( 2 * tor->info.fileCount ) ) { const size_t n = tor->info.fileCount; const size_t len = 2 * n; tr_file_index_t *dnd = NULL, dndCount = 0; tr_file_index_t *dl = NULL, dlCount = 0; size_t i; const uint8_t * walk = buf; /* set file priorities */ for( i = 0; i < n; ++i ) { tr_priority_t priority; const char ch = *walk++; switch( ch ) { case 'l': priority = TR_PRI_LOW; break; case 'h': priority = TR_PRI_HIGH; break; default: priority = TR_PRI_NORMAL; break; } tr_torrentInitFilePriority( tor, i, priority ); } /* set the dnd flags */ dl = tr_new( tr_file_index_t, len ); dnd = tr_new( tr_file_index_t, len ); for( i = 0; i < n; ++i ) if( *walk++ == 't' ) /* 't' means the DND flag is true */ dnd[dndCount++] = i; else dl[dlCount++] = i; if( dndCount ) tr_torrentInitFileDLs ( tor, dnd, dndCount, FALSE ); if( dlCount ) tr_torrentInitFileDLs ( tor, dl, dlCount, TRUE ); tr_free( dnd ); tr_free( dl ); ret = TR_FR_PRIORITY; } return ret; }
tr_completion * tr_cpInit( tr_torrent * tor ) { tr_completion * cp = tr_new( tr_completion, 1 ); cp->tor = tor; cp->blockBitfield = tr_bitfieldNew( tor->blockCount ); cp->pieceBitfield = tr_bitfieldNew( tor->info.pieceCount ); cp->completeBlocks = tr_new( uint16_t, tor->info.pieceCount ); tr_cpReset( cp ); return cp; }
static uint64_t loadDND( tr_benc * dict, tr_torrent * tor ) { uint64_t ret = 0; tr_info * inf = &tor->info; const tr_file_index_t n = inf->fileCount; tr_benc * list = NULL; if( tr_bencDictFindList( dict, KEY_DND, &list ) && ( tr_bencListSize( list ) == n ) ) { int64_t tmp; tr_file_index_t * dl = tr_new( tr_file_index_t, n ); tr_file_index_t * dnd = tr_new( tr_file_index_t, n ); tr_file_index_t i, dlCount = 0, dndCount = 0; for( i = 0; i < n; ++i ) { if( tr_bencGetInt( tr_bencListChild( list, i ), &tmp ) && tmp ) dnd[dndCount++] = i; else dl[dlCount++] = i; } if( dndCount ) { tr_torrentInitFileDLs ( tor, dnd, dndCount, FALSE ); tr_tordbg( tor, "Resume file found %d files listed as dnd", dndCount ); } if( dlCount ) { tr_torrentInitFileDLs ( tor, dl, dlCount, TRUE ); tr_tordbg( tor, "Resume file found %d files marked for download", dlCount ); } tr_free( dnd ); tr_free( dl ); ret = TR_FR_DND; } else { tr_tordbg( tor, "Couldn't load DND flags. DND list (%p) has %zu children; torrent has %d files", list, tr_bencListSize( list ), (int)n ); } return ret; }
static uint64_t loadDND(tr_variant* dict, tr_torrent* tor) { uint64_t ret = 0; tr_variant* list = NULL; tr_file_index_t const n = tor->info.fileCount; if (tr_variantDictFindList(dict, TR_KEY_dnd, &list) && tr_variantListSize(list) == n) { int64_t tmp; tr_file_index_t* dl = tr_new(tr_file_index_t, n); tr_file_index_t* dnd = tr_new(tr_file_index_t, n); tr_file_index_t dlCount = 0; tr_file_index_t dndCount = 0; for (tr_file_index_t i = 0; i < n; ++i) { if (tr_variantGetInt(tr_variantListChild(list, i), &tmp) && tmp != 0) { dnd[dndCount++] = i; } else { dl[dlCount++] = i; } } if (dndCount != 0) { tr_torrentInitFileDLs(tor, dnd, dndCount, false); tr_logAddTorDbg(tor, "Resume file found %d files listed as dnd", dndCount); } if (dlCount != 0) { tr_torrentInitFileDLs(tor, dl, dlCount, true); tr_logAddTorDbg(tor, "Resume file found %d files marked for download", dlCount); } tr_free(dnd); tr_free(dl); ret = TR_FR_DND; } else { tr_logAddTorDbg(tor, "Couldn't load DND flags. DND list (%p) has %zu" " children; torrent has %d files", (void*)list, tr_variantListSize(list), (int)n); } return ret; }
static int testStackSmash( int depth ) { int i; int len; int err; uint8_t * in; const uint8_t * end; tr_benc val; char * saved; in = tr_new( uint8_t, depth * 2 + 1 ); for( i = 0; i < depth; ++i ) { in[i] = 'l'; in[depth + i] = 'e'; } in[depth * 2] = '\0'; err = tr_bencParse( in, in + ( depth * 2 ), &val, &end ); check( !err ); check( end == in + ( depth * 2 ) ); saved = tr_bencSave( &val, &len ); check( !strcmp( saved, (char*)in ) ); tr_free( in ); tr_free( saved ); tr_bencFree( &val ); return 0; }
/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric characters, where x is the major version number, y is the minor version number, z is the maintenance number, and b designates beta (Azureus-style) */ uint8_t* tr_peerIdNew( void ) { int i; int val; int total = 0; uint8_t * buf = tr_new( uint8_t, 21 ); const char * pool = "0123456789abcdefghijklmnopqrstuvwxyz"; const int base = 36; memcpy( buf, PEERID_PREFIX, 8 ); for( i = 8; i < 19; ++i ) { val = tr_cryptoRandInt( base ); total += val; buf[i] = pool[val]; } val = total % base ? base - ( total % base ) : 0; buf[19] = pool[val]; buf[20] = '\0'; return buf; }
static int flushContiguous (tr_cache * cache, int pos, int n) { int i; int err = 0; uint8_t * buf = tr_new (uint8_t, n * MAX_BLOCK_SIZE); uint8_t * walk = buf; struct cache_block ** blocks = (struct cache_block**) tr_ptrArrayBase (&cache->blocks); struct cache_block * b = blocks[pos]; tr_torrent * tor = b->tor; const tr_piece_index_t piece = b->piece; const uint32_t offset = b->offset; for (i=pos; i<pos+n; ++i) { b = blocks[i]; evbuffer_copyout (b->evbuf, walk, b->length); walk += b->length; evbuffer_free (b->evbuf); tr_free (b); } tr_ptrArrayErase (&cache->blocks, pos, pos+n); err = tr_ioWrite (tor, piece, offset, walk-buf, buf); tr_free (buf); ++cache->disk_writes; cache->disk_write_bytes += walk-buf; return err; }
static int testStackSmash( void ) { int i; int len; int err; uint8_t * in; const uint8_t * end; tr_benc val; char * saved; const int depth = STACK_SMASH_DEPTH; in = tr_new( uint8_t, depth * 2 + 1 ); for( i = 0; i < depth; ++i ) { in[i] = 'l'; in[depth + i] = 'e'; } in[depth * 2] = '\0'; err = tr_bencParse( in, in + ( depth * 2 ), &val, &end ); check( !err ); check( end == in + ( depth * 2 ) ); saved = tr_bencToStr( &val, TR_FMT_BENC, &len ); check_streq ((char*)in, saved); tr_free( in ); tr_free( saved ); tr_bencFree( &val ); return 0; }
static EVP_CIPHER_CTX * openssl_evp_cipher_context_new (void) { EVP_CIPHER_CTX * handle = tr_new (EVP_CIPHER_CTX, 1); if (handle != NULL) EVP_CIPHER_CTX_init (handle); return handle; }
tr_completion * tr_cpConstruct( tr_completion * cp, tr_torrent * tor ) { cp->tor = tor; cp->completeBlocks = tr_new( uint16_t, tor->info.pieceCount ); tr_bitfieldConstruct( &cp->blockBitfield, tor->blockCount ); tr_bitfieldConstruct( &cp->pieceBitfield, tor->info.pieceCount ); tr_cpReset( cp ); return cp; }
// Envio de mensagem PEX static void sendPex(tr_peerMsgs * msgs) { if (msgs->peerSupportsPex && tr_torrentAllowsPex(msgs->torrent)) { (...) // Seleciona os 50 nós conectados e que são úteis ao torrent sendo baixado. const int newCount = tr_peerMgrGetPeers(msgs->torrent, &newPex, TR_AF_INET, TR_PEERS_CONNECTED, MAX_PEX_PEER_COUNT); (...) /* build the diffs */ diffs.added = tr_new(tr_pex, newCount); diffs.addedCount = 0; diffs.dropped = tr_new(tr_pex, msgs->pexCount); diffs.droppedCount = 0; diffs.elements = tr_new(tr_pex, newCount + msgs->pexCount); diffs.elementCount = 0; tr_set_compare(msgs->pex, msgs->pexCount, newPex, newCount, tr_pexCompare, sizeof(tr_pex), pexDroppedCb, pexAddedCb, pexElementCb, &diffs); (...) // Se tiverem novos peers a serem enviados, o faz. if (diffs.addedCount || diffs.droppedCount || !diffs6.addedCount || diffs6.droppedCount) { int i; tr_variant val; uint8_t * tmp, *walk; // variáveis temporárias struct evbuffer * payload; // listas de peers do PEX struct evbuffer * out = msgs->outMessages; // mensagem a ser enviada /* update peer */ (...) msgs->pex = diffs.elements; msgs->pexCount = diffs.elementCount; (...) /* build the pex payload */ tr_variantInitDict(&val, 3); if (diffs.addedCount > 0) { /* "added" */ tmp = walk = tr_new(uint8_t, diffs.addedCount * 6); for (i = 0; i < diffs.addedCount; ++i) { memcpy(walk, &diffs.added[i].addr.addr, 4); walk += 4; memcpy(walk, &diffs.added[i].port, 2); walk += 2; } (...) tr_variantDictAddRaw(&val, TR_KEY_added, tmp, walk - tmp); (...) }
tr_sha1_ctx_t tr_sha1_init (void) { Sha * handle = tr_new (Sha, 1); if (check_result (InitSha (handle))) return handle; tr_free (handle); return NULL; }
static int readPadD( tr_handshake * handshake, struct evbuffer * inbuf ) { const size_t needlen = handshake->pad_d_len; uint8_t * tmp; dbgmsg( handshake, "pad d: need %zu, got %zu", needlen, evbuffer_get_length( inbuf ) ); if( evbuffer_get_length( inbuf ) < needlen ) return READ_LATER; tmp = tr_new( uint8_t, needlen ); tr_peerIoReadBytes( handshake->io, inbuf, tmp, needlen ); tr_free( tmp ); tr_peerIoSetEncryption( handshake->io, handshake->crypto_select ); setState( handshake, AWAITING_HANDSHAKE ); return READ_NOW; }
static tr_bool recalculateHash( tr_torrent * tor, tr_piece_index_t pieceIndex, uint8_t * setme ) { size_t bytesLeft; uint32_t offset = 0; tr_bool success = TRUE; const size_t buflen = MAX_BLOCK_SIZE; uint8_t * buffer = tr_new( uint8_t, buflen ); SHA_CTX sha; assert( tor != NULL ); assert( pieceIndex < tor->info.pieceCount ); assert( buffer != NULL ); assert( buflen > 0 ); assert( setme != NULL ); SHA1_Init( &sha ); bytesLeft = tr_torPieceCountBytes( tor, pieceIndex ); tr_ioPrefetch( tor, pieceIndex, offset, bytesLeft ); while( bytesLeft ) { const int len = MIN( bytesLeft, buflen ); success = !tr_cacheReadBlock( tor->session->cache, tor, pieceIndex, offset, len, buffer ); if( !success ) break; SHA1_Update( &sha, buffer, len ); offset += len; bytesLeft -= len; } if( success ) SHA1_Final( setme, &sha ); tr_free( buffer ); return success; }
/* Convert to compact form */ static uint8_t * parseOldPeers( tr_benc * bePeers, size_t * byteCount ) { int i; uint8_t * compact, *walk; const int peerCount = bePeers->val.l.count; assert( bePeers->type == TYPE_LIST ); compact = tr_new( uint8_t, peerCount * 6 ); for( i = 0, walk = compact; i < peerCount; ++i ) { const char * s; int64_t itmp; struct in_addr addr; tr_port_t port; tr_benc * peer = &bePeers->val.l.vals[i]; if( !tr_bencDictFindStr( peer, "ip", &s ) || tr_netResolve( s, &addr ) ) continue; memcpy( walk, &addr, 4 ); walk += 4; if( !tr_bencDictFindInt( peer, "port", &itmp ) || itmp < 0 || itmp > 0xffff ) continue; port = htons( itmp ); memcpy( walk, &port, 2 ); walk += 2; } *byteCount = peerCount * 6; return compact; }
static int flushContiguous( tr_cache * cache, int pos, int n ) { int i; int err = 0; uint8_t * buf = tr_new( uint8_t, n * MAX_BLOCK_SIZE ); uint8_t * walk = buf; struct cache_block ** blocks = (struct cache_block**) tr_ptrArrayBase( &cache->blocks ); struct cache_block * b = blocks[pos]; tr_torrent * tor = b->tor; const tr_piece_index_t piece = b->piece; const uint32_t offset = b->offset; //fprintf( stderr, "flushing %d contiguous blocks [%d-%d) from cache to disk\n", n, pos, n+pos ); for( i=pos; i<pos+n; ++i ) { b = blocks[i]; memcpy( walk, b->buf, b->length ); walk += b->length; tr_free( b->buf ); tr_free( b ); } tr_ptrArrayErase( &cache->blocks, pos, pos+n ); #if 0 tr_tordbg( tor, "Writing to disk piece %d, offset %d, len %d", (int)piece, (int)offset, (int)(walk-buf) ); tr_ndbg( MY_NAME, "Removing %d blocks from cache, rank: %d - %d left", n, rank, tr_ptrArraySize(&cache->blocks) ); fprintf( stderr, "%s - Writing to disk piece %d, offset %d, len %d\n", tr_torrentName(tor), (int)piece, (int)offset, (int)(walk-buf) ); fprintf( stderr, "%s - Removing %d blocks from cache; %d left\n", MY_NAME, n, tr_ptrArraySize(&cache->blocks) ); #endif err = tr_ioWrite( tor, piece, offset, walk-buf, buf ); tr_free( buf ); ++cache->disk_writes; cache->disk_write_bytes += walk-buf; return err; }
static tr_list* node_alloc (void) { tr_list * ret = NULL; tr_lock * lock = getRecycledNodesLock (); tr_lockLock (lock); if (recycled_nodes != NULL) { ret = recycled_nodes; recycled_nodes = recycled_nodes->next; } tr_lockUnlock (lock); if (ret == NULL) { ret = tr_new (tr_list, 1); } *ret = TR_LIST_CLEAR; return ret; }
static tr_bool verifyTorrent( tr_torrent * tor, tr_bool * stopFlag ) { SHA_CTX sha; int fd = -1; int64_t filePos = 0; tr_bool changed = 0; tr_bool hadPiece = 0; uint32_t piecePos = 0; uint32_t pieceBytesRead = 0; tr_file_index_t fileIndex = 0; tr_piece_index_t pieceIndex = 0; const int64_t buflen = tor->info.pieceSize; uint8_t * buffer = tr_new( uint8_t, buflen ); #ifdef STOPWATCH time_t now = time( NULL ); #endif SHA1_Init( &sha ); while( !*stopFlag && ( pieceIndex < tor->info.pieceCount ) ) { int64_t leftInPiece; int64_t leftInFile; int64_t bytesThisPass; const tr_file * file = &tor->info.files[fileIndex]; /* if we're starting a new piece... */ if( piecePos == 0 ) { hadPiece = tr_cpPieceIsComplete( &tor->completion, pieceIndex ); /* fprintf( stderr, "starting piece %d of %d\n", (int)pieceIndex, (int)tor->info.pieceCount ); */ } /* if we're starting a new file... */ if( !filePos && (fd<0) ) { char * filename = tr_buildPath( tor->downloadDir, file->name, NULL ); fd = tr_open_file_for_scanning( filename ); /* fprintf( stderr, "opening file #%d (%s) -- %d\n", fileIndex, filename, fd ); */ tr_free( filename ); } /* figure out how much we can read this pass */ leftInPiece = tr_torPieceCountBytes( tor, pieceIndex ) - piecePos; leftInFile = file->length - filePos; bytesThisPass = MIN( leftInFile, leftInPiece ); bytesThisPass = MIN( bytesThisPass, buflen ); /* fprintf( stderr, "reading this pass: %d\n", (int)bytesThisPass ); */ /* read a bit */ if( (fd>=0) && tr_lseek( fd, filePos, SEEK_SET ) != -1 ) { const int64_t numRead = read( fd, buffer, bytesThisPass ); if( numRead > 0 ) pieceBytesRead += numRead; if( numRead == bytesThisPass ) SHA1_Update( &sha, buffer, numRead ); } /* move our offsets */ leftInPiece -= bytesThisPass; leftInFile -= bytesThisPass; piecePos += bytesThisPass; filePos += bytesThisPass; /* if we're finishing a piece... */ if( leftInPiece == 0 ) { tr_bool hasPiece; uint8_t hash[SHA_DIGEST_LENGTH]; SHA1_Final( hash, &sha ); hasPiece = !memcmp( hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH ); /* fprintf( stderr, "do the hashes match? %s\n", (hasPiece?"yes":"no") ); */ if( hasPiece ) { tr_torrentSetHasPiece( tor, pieceIndex, TRUE ); if( !hadPiece ) changed = TRUE; } else if( hadPiece ) { tr_torrentSetHasPiece( tor, pieceIndex, FALSE ); changed = TRUE; } tr_torrentSetPieceChecked( tor, pieceIndex, TRUE ); tor->anyDate = time( NULL ); /* going full-throttle on a verify can choke other processes' * disk IO, so wait a fwe msec between pieces. * The msec is arbitrary, and the "if" clause is to make sure we * don't slow down verification of files that don't exist */ if( pieceBytesRead == tr_torPieceCountBytes( tor, pieceIndex ) ) tr_wait( 50 ); SHA1_Init( &sha ); ++pieceIndex; piecePos = 0; pieceBytesRead = 0; } /* if we're finishing a file... */ if( leftInFile == 0 ) { /* fprintf( stderr, "closing file\n" ); */ if( fd >= 0 ) { tr_close_file( fd ); fd = -1; } ++fileIndex; filePos = 0; } } /* cleanup */ if( fd >= 0 ) tr_close_file( fd ); tr_free( buffer ); #ifdef STOPWATCH { time_t now2 = time( NULL ); fprintf( stderr, "it took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)\n", (int)(now2-now), tor->info.totalSize, (uint64_t)(tor->info.totalSize/(1+(now2-now))) ); } #endif return changed; }
int main(int argc, char **argv) { if (argc > 1) while (++argv, --argc) { if (!strcmp("-c", argv[0])) color_on = 1; else if (!strcmp("-h", argv[0])) printf("liblisp unit tests\n\tusage ./%s (-c)? (-h)?\n", argv[0]); else printf("unknown argument '%s'\n", argv[0]); } unit_test_start("liblisp"); { print_note("util.c"); test(is_number("0xfAb")); test(is_number("-01234567")); test(is_number("+1000000000000000000000000000003")); test(!is_number("")); test(!is_number("+")); test(!is_number("-")); test(unbalanced("(((", '(', ')') > 0); test(unbalanced("))", '(', ')') < 0); test(unbalanced("", '(', ')') == 0); test(unbalanced("\"(", '(', ')') == 0); test(unbalanced("( \"))))(()()()(()\\\"())\")", '(', ')') == 0); test(unbalanced("(a (b) c (d (e (f) \")\" g)))", '(', ')') == 0); test(unbalanced("((a b) c", '(', ')') > 0); test(!is_fnumber("")); test(!is_fnumber("1e")); test(!is_fnumber("-1e")); test(!is_fnumber("1-e")); test(is_fnumber("+0.")); test(is_fnumber("123")); /*this passes, see header */ test(is_fnumber("1e-3")); test(is_fnumber("1.003e+34")); test(is_fnumber("1e34")); test(is_fnumber("93.04")); test(match("", "")); test(match("abc", "abc")); test(!match("abC", "abc")); test(match("aaa*", "aaaXX")); test(!match("aaa*", "XXaaaXX")); test(match(".bc", "abc")); test(match("a.c", "aXc")); test(!match("a\\.c", "aXc")); test(match("a\\.c", "a.c")); char *s = NULL; state(s = vstrcatsep(",", "a", "b", "c", "", "foo", "bar", NULL)); test(!sstrcmp("a,b,c,,foo,bar", s)); free(s); char *t = NULL, *s1 = "Hello,", *s2 = " World!"; state(t = calloc(16, 1)); state(strcpy(t, s1)); test(((size_t) (lstrcatend(t, s2) - t)) == (strlen(s1) + strlen(s2))); free(t); /*test tr, or translate, functionality */ size_t trinsz = 0; uint8_t trout[128] = { 0 }, *trin = (uint8_t *) "aaabbbcdaacccdeeefxxxa"; tr_state_t *tr1; state(tr1 = tr_new()); state(trinsz = strlen((char *)trin)); test(tr_init(tr1, "", (uint8_t *) "abc", (uint8_t *) "def") == TR_OK); test(tr_block(tr1, trin, trout, trinsz) == trinsz); test(!strcmp((char *)trout, "dddeeefdddfffdeeefxxxd")); test(tr_init(tr1, "s", (uint8_t *) "abc", (uint8_t *) "def") == TR_OK); state(memset(trout, 0, 128)); test(tr_block(tr1, trin, trout, trinsz) <= trinsz); test(!strcmp((char *)trout, "defddfdeeefxxxd")); state(tr_delete(tr1)); /*know collisions for the djb2 hash algorithm */ test(djb2("heliotropes", strlen("heliotropes")) == djb2("neurospora", strlen("neurospora"))); test(djb2("depravement", strlen("depravement")) == djb2("serafins", strlen("serafins"))); /*should not collide */ test(djb2("heliotropes", strlen("heliotropes")) != djb2("serafins", strlen("serafins"))); } { /*io.c test */ io_t *in, *out; print_note("io.c"); /*string input */ static const char hello[] = "Hello\n"; /**@note io_sin currently duplicates "hello" internally*/ state(in = io_sin(hello, strlen(hello))); test(io_is_in(in)); test(io_getc(in) == 'H'); test(io_getc(in) == 'e'); test(io_getc(in) == 'l'); test(io_getc(in) == 'l'); test(io_getc(in) == 'o'); test(io_getc(in) == '\n'); test(io_getc(in) == EOF); test(io_getc(in) == EOF); test(!io_error(in)); test(io_seek(in, 0, SEEK_SET) >= 0); test(io_getc(in) == 'H'); test(io_seek(in, 3, SEEK_SET) >= 0); test(io_getc(in) == 'l'); test(io_ungetc('x', in) == 'x'); test(io_getc(in) == 'x'); test(io_getc(in) == 'o'); state(io_close(in)); /*string output */ char *s = NULL; static const char hello_world[] = "Hello,\n\tWorld!\n"; /**@note io_sin currently duplicates hello_world internally*/ state(in = io_sin(hello_world, strlen(hello_world))); test(!strcmp(s = io_getline(in), "Hello,")); s = (free(s), NULL); test(!strcmp(s = io_getline(in), "\tWorld!")); s = (free(s), NULL); test(!io_getline(in)); test(io_seek(in, 0, SEEK_SET) >= 0); test(!strcmp(s = io_getdelim(in, EOF), "Hello,\n\tWorld!\n")); s = (free(s), NULL); state(io_close(in)); state(out = io_sout(1)); test(io_puts("Hello, World", out) != EOF); test(!strcmp("Hello, World", io_get_string(out))); test(io_putc('\n', out) != EOF); test(!strcmp("Hello, World\n", io_get_string(out))); test(io_seek(out, -6, SEEK_CUR) >= 0); test(io_puts("Mars\n", out) != EOF); test(!strcmp("Hello, Mars\n\n", io_get_string(out))); free(io_get_string(out)); state(io_close(out)); static const char block_in[16] = {1, 3, 4, 6}; static char block_out[16] = {0}; state((in = io_sin(block_in, 16))); test(io_getc(in) == 1); test(io_read(block_out, 15, in) == 15); test(!memcmp(block_out, block_in+1, 15)); state(io_close(in)); } { /* hash.c hash table tests */ hash_table_t *h = NULL; print_note("hash.c"); state(h = hash_create(1)); return_if(!h); test(!hash_insert(h, "key1", "val1")); test(!hash_insert(h, "key2", "val2")); /* assuming the hash algorithm is djb2, then * "heliotropes" collides with "neurospora" * "depravement" collides with "serafins" * "playwright" collides with "snush" (for djb2a) * See: * <https://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed> */ test(!hash_insert(h, "heliotropes", "val3")); test(!hash_insert(h, "neurospora", "val4")); test(!hash_insert(h, "depravement", "val5")); test(!hash_insert(h, "serafins", "val6")); test(!hash_insert(h, "playwright", "val7")); test(!hash_insert(h, "snush", "val8")); test(!hash_insert(h, "", "val9")); test(!hash_insert(h, "nil", "")); test(!hash_insert(h, "a", "x")); test(!hash_insert(h, "a", "y")); test(!hash_insert(h, "a", "z")); test(!sstrcmp("val1", hash_lookup(h, "key1"))); test(!sstrcmp("val2", hash_lookup(h, "key2"))); test(!sstrcmp("val3", hash_lookup(h, "heliotropes"))); test(!sstrcmp("val4", hash_lookup(h, "neurospora"))); test(!sstrcmp("val5", hash_lookup(h, "depravement"))); test(!sstrcmp("val6", hash_lookup(h, "serafins"))); test(!sstrcmp("val7", hash_lookup(h, "playwright"))); test(!sstrcmp("val8", hash_lookup(h, "snush"))); test(!sstrcmp("val9", hash_lookup(h, ""))); test(!sstrcmp("", hash_lookup(h, "nil"))); test(!sstrcmp("z", hash_lookup(h, "a"))); test(hash_get_load_factor(h) <= 0.75f); state(hash_destroy(h)); } { /* lisp.c (and the lisp interpreter in general) */ lisp_t *l; print_note("lisp.c"); /*while unit testing eschews state being held across tests it is makes *little sense in this case*/ state(l = lisp_init()); state(io_close(lisp_get_logging(l))); test(!lisp_set_logging(l, io_nout())); return_if(!l); test(!lisp_eval_string(l, "")); test(is_int(lisp_eval_string(l, "2"))); test(get_int(lisp_eval_string(l, "(+ 2 2)")) == 4); test(get_int(lisp_eval_string(l, "(* 3 2)")) == 6); lisp_cell_t *x = NULL, *y = NULL, *z = NULL; char *t = NULL; state(x = lisp_intern(l, lstrdup_or_abort("foo"))); state(y = lisp_intern(l, t = lstrdup_or_abort("foo"))); /*this one needs freeing! */ state(z = lisp_intern(l, lstrdup_or_abort("bar"))); test(x == y && x != NULL); test(x != z); free(t); /*free the non-interned string */ test(is_proc(lisp_eval_string(l, "(define square (lambda (x) (* x x)))"))); test(get_int(lisp_eval_string(l, "(square 4)")) == 16); test(!is_list(cons(l, gsym_tee(), gsym_tee()))); test(is_list(cons(l, gsym_tee(), gsym_nil()))); test(!is_list(cons(l, gsym_nil(), cons(l, gsym_tee(), gsym_tee())))); test(is_list(mk_list(l, gsym_tee(), gsym_nil(), gsym_tee(), NULL))); test(gsym_error() == lisp_eval_string(l, "(> 'a 1)")); test(is_sym(x)); test(is_asciiz(x)); test(!is_str(x)); test(gsym_error() == lisp_eval_string(l, "(eval (cons quote 0))")); char *serial = NULL; test(!strcmp((serial = lisp_serialize(l, cons(l, gsym_tee(), gsym_error()))), "(t . error)")); state(free(serial)); state(lisp_destroy(l)); } return unit_test_end("liblisp"); /*should be zero! */ }
static int readHandshake( tr_handshake * handshake, struct evbuffer * inbuf ) { uint8_t pstrlen; uint8_t * pstr; uint8_t reserved[HANDSHAKE_FLAGS_LEN]; uint8_t hash[SHA_DIGEST_LENGTH]; dbgmsg( handshake, "payload: need %d, got %zu", INCOMING_HANDSHAKE_LEN, evbuffer_get_length( inbuf ) ); if( evbuffer_get_length( inbuf ) < INCOMING_HANDSHAKE_LEN ) return READ_LATER; handshake->haveReadAnythingFromPeer = TRUE; pstrlen = evbuffer_pullup( inbuf, 1 )[0]; /* peek, don't read. We may be handing inbuf to AWAITING_YA */ if( pstrlen == 19 ) /* unencrypted */ { tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_NONE ); if( handshake->encryptionMode == TR_ENCRYPTION_REQUIRED ) { dbgmsg( handshake, "peer is unencrypted, and we're disallowing that" ); return tr_handshakeDone( handshake, FALSE ); } } else /* encrypted or corrupt */ { tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_RC4 ); if( tr_peerIoIsIncoming( handshake->io ) ) { dbgmsg( handshake, "I think peer is sending us an encrypted handshake..." ); setState( handshake, AWAITING_YA ); return READ_NOW; } tr_cryptoDecrypt( handshake->crypto, 1, &pstrlen, &pstrlen ); if( pstrlen != 19 ) { dbgmsg( handshake, "I think peer has sent us a corrupt handshake..." ); return tr_handshakeDone( handshake, FALSE ); } } evbuffer_drain( inbuf, 1 ); /* pstr (BitTorrent) */ pstr = tr_new( uint8_t, pstrlen + 1 ); tr_peerIoReadBytes( handshake->io, inbuf, pstr, pstrlen ); pstr[pstrlen] = '\0'; if( strcmp( (char*)pstr, "BitTorrent protocol" ) ) { tr_free( pstr ); return tr_handshakeDone( handshake, FALSE ); } tr_free( pstr ); /* reserved bytes */ tr_peerIoReadBytes( handshake->io, inbuf, reserved, sizeof( reserved ) ); /** *** Extensions **/ tr_peerIoEnableLTEP( handshake->io, HANDSHAKE_HAS_LTEP( reserved ) ); tr_peerIoEnableFEXT( handshake->io, HANDSHAKE_HAS_FASTEXT( reserved ) ); tr_peerIoEnableDHT( handshake->io, HANDSHAKE_HAS_DHT( reserved ) ); /* torrent hash */ tr_peerIoReadBytes( handshake->io, inbuf, hash, sizeof( hash ) ); if( tr_peerIoIsIncoming( handshake->io ) ) { if( !tr_torrentExists( handshake->session, hash ) ) { dbgmsg( handshake, "peer is trying to connect to us for a torrent we don't have." ); return tr_handshakeDone( handshake, FALSE ); } else { assert( !tr_peerIoHasTorrentHash( handshake->io ) ); tr_peerIoSetTorrentHash( handshake->io, hash ); } } else /* outgoing */ { assert( tr_peerIoHasTorrentHash( handshake->io ) ); if( memcmp( hash, tr_peerIoGetTorrentHash( handshake->io ), SHA_DIGEST_LENGTH ) ) { dbgmsg( handshake, "peer returned the wrong hash. wtf?" ); return tr_handshakeDone( handshake, FALSE ); } } /** *** If it's an incoming message, we need to send a response handshake **/ if( !handshake->haveSentBitTorrentHandshake ) { uint8_t msg[HANDSHAKE_SIZE]; buildHandshakeMessage( handshake, msg ); tr_peerIoWriteBytes( handshake->io, msg, sizeof( msg ), FALSE ); handshake->haveSentBitTorrentHandshake = 1; } setReadState( handshake, AWAITING_PEER_ID ); return READ_NOW; }
char* tr_lookup(str *in, trans_t **tr) { char *p; char *p0; str tclass; tr_export_t *te = NULL; trans_t *t = NULL; trans_t *t0 = NULL; str s; if(in==NULL || in->s==NULL || tr==NULL) return NULL; p = in->s; do { while(is_in_str(p, in) && (*p==' ' || *p=='\t' || *p=='\n')) p++; if(*p != TR_LBRACKET) break; p++; if((t = tr_new())==NULL) return NULL; if(t0==NULL) *tr = t; else t0->next = t; t0 = t; /* find transformation class */ p = tr_get_class(in, p, &tclass); if(p==NULL) goto error; /* locate transformation */ te = tr_lookup_class(&tclass); if(te==NULL) { LM_ERR("unknown transformation: [%.*s] in [%.*s]\n", tclass.len, tclass.s, in->len, in->s); goto error; } s.s = p; s.len = in->s + in->len - p; p0 = te->tparse(&s, t); if(p0==NULL) goto error; p = p0; if(*p != TR_RBRACKET) { LM_ERR("invalid transformation: %.*s | %c !!\n", in->len, in->s, *p); goto error; } p++; if(!is_in_str(p, in)) break; } while(1); return p; error: LM_ERR("error parsing [%.*s]\n", in->len, in->s); t = *tr; while(t) { t0 = t; t = t->next; tr_destroy(t0); pkg_free(t0); } return NULL; }