1#include <ctype.h> /* isspace() */ 2#include <errno.h> /* EILSEQ */ 3#include <string.h> /* strlen(), strncmp() */ 4 5#include <event2/buffer.h> 6 7#include "transmission.h" 8#include "bencode.h" 9#include "utils.h" /* tr_free */ 10 11// #define VERBOSE 12#include "libtransmission-test.h" 13 14#ifndef WIN32 15#define STACK_SMASH_DEPTH (1 * 1000 * 1000) 16#else 17#define STACK_SMASH_DEPTH ( 100 * 1000) 18#endif 19 20static int 21testInt( void ) 22{ 23 uint8_t buf[128]; 24 int64_t val; 25 int err; 26 const uint8_t * end; 27 28 /* good int string */ 29 tr_snprintf( (char*)buf, sizeof( buf ), "i64e" ); 30 err = tr_bencParseInt( buf, buf + 4, &end, &val ); 31 check_int_eq( 0, err ); 32 check_int_eq( 64, val ); 33 check( (buf + 4) == end ); 34 35 /* missing 'e' */ 36 end = NULL; 37 val = 888; 38 err = tr_bencParseInt( buf, buf + 3, &end, &val ); 39 check_int_eq( EILSEQ, err ); 40 check_int_eq( 888, val ); 41 check( end == NULL ); 42 43 /* empty buffer */ 44 err = tr_bencParseInt( buf, buf + 0, &end, &val ); 45 check_int_eq( EILSEQ, err ); 46 check_int_eq( 888, val ); 47 check( end == NULL ); 48 49 /* bad number */ 50 tr_snprintf( (char*)buf, sizeof( buf ), "i6z4e" ); 51 err = tr_bencParseInt( buf, buf + 5, &end, &val ); 52 check_int_eq( EILSEQ, err ); 53 check_int_eq( 888, val ); 54 check( end == NULL ); 55 56 /* negative number */ 57 tr_snprintf( (char*)buf, sizeof( buf ), "i-3e" ); 58 err = tr_bencParseInt( buf, buf + 4, &end, &val ); 59 check_int_eq( 0, err ); 60 check_int_eq( -3, val ); 61 check( (buf + 4) == end ); 62 63 /* zero */ 64 tr_snprintf( (char*)buf, sizeof( buf ), "i0e" ); 65 err = tr_bencParseInt( buf, buf + 4, &end, &val ); 66 check_int_eq( 0, err ); 67 check_int_eq( 0, val ); 68 check( (buf + 3) == end ); 69 70 /* no leading zeroes allowed */ 71 val = 0; 72 end = NULL; 73 tr_snprintf( (char*)buf, sizeof( buf ), "i04e" ); 74 err = tr_bencParseInt( buf, buf + 4, &end, &val ); 75 check_int_eq( EILSEQ, err ); 76 check_int_eq( 0, val ); 77 check( NULL == end ); 78 79 return 0; 80} 81 82static int 83testStr( void ) 84{ 85 uint8_t buf[128]; 86 int err; 87 const uint8_t * end; 88 const uint8_t * str; 89 size_t len; 90 91 /* good string */ 92 tr_snprintf( (char*)buf, sizeof( buf ), "4:boat" ); 93 err = tr_bencParseStr( buf, buf + 6, &end, &str, &len ); 94 check_int_eq (0, err); 95 check_int_eq (4, len); 96 check( !strncmp( (char*)str, "boat", len ) ); 97 check( end == buf + 6 ); 98 str = NULL; 99 end = NULL; 100 len = 0; 101 102 /* string goes past end of buffer */ 103 err = tr_bencParseStr( buf, buf + 5, &end, &str, &len ); 104 check_int_eq (EILSEQ, err); 105 check_int_eq (0, len); 106 check( str == NULL ); 107 check( end == NULL ); 108 check( !len ); 109 110 /* empty string */ 111 tr_snprintf( (char*)buf, sizeof( buf ), "0:" ); 112 err = tr_bencParseStr( buf, buf + 2, &end, &str, &len ); 113 check_int_eq (0, err); 114 check_int_eq (0, len); 115 check( !*str ); 116 check( end == buf + 2 ); 117 str = NULL; 118 end = NULL; 119 len = 0; 120 121 /* short string */ 122 tr_snprintf( (char*)buf, sizeof( buf ), "3:boat" ); 123 err = tr_bencParseStr( buf, buf + 6, &end, &str, &len ); 124 check_int_eq (0, err); 125 check_int_eq (3, len); 126 check( !strncmp( (char*)str, "boa", len ) ); 127 check( end == buf + 5 ); 128 str = NULL; 129 end = NULL; 130 len = 0; 131 132 return 0; 133} 134 135static int 136testString( const char * str, 137 int isGood ) 138{ 139 tr_benc val; 140 const uint8_t * end = NULL; 141 char * saved; 142 const size_t len = strlen( str ); 143 int savedLen; 144 int err = tr_bencParse( str, str + len, &val, &end ); 145 146 if( !isGood ) 147 { 148 check( err ); 149 } 150 else 151 { 152 check( !err ); 153#if 0 154 fprintf( stderr, "in: [%s]\n", str ); 155 fprintf( stderr, "out:\n%s", tr_bencToStr( &val, TR_FMT_JSON, NULL ) ); 156#endif 157 check( end == (const uint8_t*)str + len ); 158 saved = tr_bencToStr( &val, TR_FMT_BENC, &savedLen ); 159 check_streq (str, saved); 160 check_int_eq (savedLen, len); 161 tr_free( saved ); 162 tr_bencFree( &val ); 163 } 164 return 0; 165} 166 167static int 168testParse( void ) 169{ 170 tr_benc val; 171 tr_benc * child; 172 tr_benc * child2; 173 uint8_t buf[512]; 174 const uint8_t * end; 175 int err; 176 int len; 177 int64_t i; 178 char * saved; 179 180 tr_snprintf( (char*)buf, sizeof( buf ), "i64e" ); 181 err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end ); 182 check( !err ); 183 check( tr_bencGetInt( &val, &i ) ); 184 check_int_eq (64, i); 185 check( end == buf + 4 ); 186 tr_bencFree( &val ); 187 188 tr_snprintf( (char*)buf, sizeof( buf ), "li64ei32ei16ee" ); 189 err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end ); 190 check( !err ); 191 check( end == buf + strlen( (char*)buf ) ); 192 check( val.val.l.count == 3 ); 193 check( tr_bencGetInt( &val.val.l.vals[0], &i ) ); 194 check_int_eq (64, i); 195 check( tr_bencGetInt( &val.val.l.vals[1], &i ) ); 196 check_int_eq (32, i); 197 check( tr_bencGetInt( &val.val.l.vals[2], &i ) ); 198 check_int_eq (16, i); 199 saved = tr_bencToStr( &val, TR_FMT_BENC, &len ); 200 check_streq ((char*)buf, saved); 201 tr_free( saved ); 202 tr_bencFree( &val ); 203 204 end = NULL; 205 tr_snprintf( (char*)buf, sizeof( buf ), "lllee" ); 206 err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end ); 207 check( err ); 208 check( end == NULL ); 209 210 end = NULL; 211 tr_snprintf( (char*)buf, sizeof( buf ), "le" ); 212 err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end ); 213 check( !err ); 214 check( end == buf + 2 ); 215 saved = tr_bencToStr( &val, TR_FMT_BENC, &len ); 216 check_streq( "le", saved ); 217 tr_free( saved ); 218 tr_bencFree( &val ); 219 220 if( ( err = testString( "llleee", true ) ) ) 221 return err; 222 if( ( err = testString( "d3:cow3:moo4:spam4:eggse", true ) ) ) 223 return err; 224 if( ( err = testString( "d4:spaml1:a1:bee", true ) ) ) 225 return err; 226 if( ( err = 227 testString( "d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee", 228 true ) ) ) 229 return err; 230 if( ( err = 231 testString( 232 "d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee", 233 true ) ) ) 234 return err; 235 if( ( err = 236 testString( 237 "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", 238 true ) ) ) 239 return err; 240 if( ( err = testString( "d1:ai0e1:be", false ) ) ) /* odd number of children 241 */ 242 return err; 243 if( ( err = testString( "", false ) ) ) 244 return err; 245 if( ( err = testString( " ", false ) ) ) 246 return err; 247 248 /* nested containers 249 * parse an unsorted dict 250 * save as a sorted dict */ 251 end = NULL; 252 tr_snprintf( (char*)buf, sizeof( buf ), "lld1:bi32e1:ai64eeee" ); 253 err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end ); 254 check( !err ); 255 check( end == buf + strlen( (const char*)buf ) ); 256 check( ( child = tr_bencListChild( &val, 0 ) ) ); 257 check( ( child2 = tr_bencListChild( child, 0 ) ) ); 258 saved = tr_bencToStr( &val, TR_FMT_BENC, &len ); 259 check_streq( "lld1:ai64e1:bi32eeee", saved ); 260 tr_free( saved ); 261 tr_bencFree( &val ); 262 263 /* too many endings */ 264 end = NULL; 265 tr_snprintf( (char*)buf, sizeof( buf ), "leee" ); 266 err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end ); 267 check( !err ); 268 check( end == buf + 2 ); 269 saved = tr_bencToStr( &val, TR_FMT_BENC, &len ); 270 check_streq( "le", saved ); 271 tr_free( saved ); 272 tr_bencFree( &val ); 273 274 /* no ending */ 275 end = NULL; 276 tr_snprintf( (char*)buf, sizeof( buf ), "l1:a1:b1:c" ); 277 err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end ); 278 check( err ); 279 280 /* incomplete string */ 281 end = NULL; 282 tr_snprintf( (char*)buf, sizeof( buf ), "1:" ); 283 err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end ); 284 check( err ); 285 286 return 0; 287} 288 289static void 290stripWhitespace( char * in ) 291{ 292 char * out; 293 294 for( out = in; *in; ++in ) 295 if( !isspace( *in ) ) 296 *out++ = *in; 297 *out = '\0'; 298} 299 300static int 301testJSONSnippet( const char * benc_str, 302 const char * expected ) 303{ 304 tr_benc top; 305 char * serialized; 306 struct evbuffer * buf; 307 308 tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL ); 309 buf = tr_bencToBuf( &top, TR_FMT_JSON ); 310 serialized = (char*) evbuffer_pullup( buf, -1 ); 311 stripWhitespace( serialized ); 312#if 0 313 fprintf( stderr, "benc: %s\n", benc_str ); 314 fprintf( stderr, "json: %s\n", serialized ); 315 fprintf( stderr, "want: %s\n", expected ); 316#endif 317 check_streq (expected, serialized); 318 tr_bencFree( &top ); 319 evbuffer_free( buf ); 320 return 0; 321} 322 323static int 324testJSON( void ) 325{ 326 int val; 327 const char * benc_str; 328 const char * expected; 329 330 benc_str = "i6e"; 331 expected = "6"; 332 if( ( val = testJSONSnippet( benc_str, expected ) ) ) 333 return val; 334 335 benc_str = "d5:helloi1e5:worldi2ee"; 336 expected = "{\"hello\":1,\"world\":2}"; 337 if( ( val = testJSONSnippet( benc_str, expected ) ) ) 338 return val; 339 340 benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee"; 341 expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}"; 342 if( ( val = testJSONSnippet( benc_str, expected ) ) ) 343 return val; 344 345 benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eeee"; 346 expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}"; 347 if( ( val = testJSONSnippet( benc_str, expected ) ) ) 348 return val; 349 350 benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe"; 351 expected = 352 "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}"; 353 if( ( val = testJSONSnippet( benc_str, expected ) ) ) 354 return val; 355 356 return 0; 357} 358 359static int 360testMerge( void ) 361{ 362 tr_benc dest, src; 363 int64_t i; 364 const char * s; 365 366 /* initial dictionary (default values) */ 367 tr_bencInitDict( &dest, 10 ); 368 tr_bencDictAddInt( &dest, "i1", 1 ); 369 tr_bencDictAddInt( &dest, "i2", 2 ); 370 tr_bencDictAddInt( &dest, "i4", -35 ); /* remains untouched */ 371 tr_bencDictAddStr( &dest, "s5", "abc" ); 372 tr_bencDictAddStr( &dest, "s6", "def" ); 373 tr_bencDictAddStr( &dest, "s7", "127.0.0.1" ); /* remains untouched */ 374 375 /* new dictionary, will overwrite items in dest */ 376 tr_bencInitDict( &src, 10 ); 377 tr_bencDictAddInt( &src, "i1", 1 ); /* same value */ 378 tr_bencDictAddInt( &src, "i2", 4 ); /* new value */ 379 tr_bencDictAddInt( &src, "i3", 3 ); /* new key:value */ 380 tr_bencDictAddStr( &src, "s5", "abc" ); /* same value */ 381 tr_bencDictAddStr( &src, "s6", "xyz" ); /* new value */ 382 tr_bencDictAddStr( &src, "s8", "ghi" ); /* new key:value */ 383 384 tr_bencMergeDicts( &dest, /*const*/ &src ); 385 386 check( tr_bencDictFindInt( &dest, "i1", &i )); 387 check_int_eq (1, i); 388 check( tr_bencDictFindInt( &dest, "i2", &i )); 389 check_int_eq (4, i); 390 check( tr_bencDictFindInt( &dest, "i3", &i )); 391 check_int_eq (3, i); 392 check( tr_bencDictFindInt( &dest, "i4", &i )); 393 check_int_eq (-35, i); 394 check( tr_bencDictFindStr( &dest, "s5", &s )); 395 check_streq ("abc", s); 396 check( tr_bencDictFindStr( &dest, "s6", &s )); 397 check_streq ("xyz", s); 398 check( tr_bencDictFindStr( &dest, "s7", &s )); 399 check_streq ("127.0.0.1", s); 400 check( tr_bencDictFindStr( &dest, "s8", &s )); 401 check_streq ("ghi", s); 402 403 tr_bencFree( &dest ); 404 tr_bencFree( &src ); 405 return 0; 406} 407 408static int 409testStackSmash( void ) 410{ 411 int i; 412 int len; 413 int err; 414 uint8_t * in; 415 const uint8_t * end; 416 tr_benc val; 417 char * saved; 418 const int depth = STACK_SMASH_DEPTH; 419 420 in = tr_new( uint8_t, depth * 2 + 1 ); 421 for( i = 0; i < depth; ++i ) 422 { 423 in[i] = 'l'; 424 in[depth + i] = 'e'; 425 } 426 in[depth * 2] = '\0'; 427 err = tr_bencParse( in, in + ( depth * 2 ), &val, &end ); 428 check( !err ); 429 check( end == in + ( depth * 2 ) ); 430 saved = tr_bencToStr( &val, TR_FMT_BENC, &len ); 431 check_streq ((char*)in, saved); 432 tr_free( in ); 433 tr_free( saved ); 434 tr_bencFree( &val ); 435 436 return 0; 437} 438 439static int 440testBool( void ) 441{ 442 tr_benc top; 443 int64_t intVal; 444 bool boolVal; 445 446 tr_bencInitDict( &top, 0 ); 447 448 tr_bencDictAddBool( &top, "key1", false ); 449 tr_bencDictAddBool( &top, "key2", 0 ); 450 tr_bencDictAddInt ( &top, "key3", true ); 451 tr_bencDictAddInt ( &top, "key4", 1 ); 452 check( tr_bencDictFindBool( &top, "key1", &boolVal ) ); 453 check( !boolVal ); 454 check( tr_bencDictFindBool( &top, "key2", &boolVal ) ); 455 check( !boolVal ); 456 check( tr_bencDictFindBool( &top, "key3", &boolVal ) ); 457 check( boolVal ); 458 check( tr_bencDictFindBool( &top, "key4", &boolVal ) ); 459 check( boolVal ); 460 check( tr_bencDictFindInt( &top, "key1", &intVal ) ); 461 check( !intVal); 462 check( tr_bencDictFindInt( &top, "key2", &intVal ) ); 463 check( !intVal ); 464 check( tr_bencDictFindInt( &top, "key3", &intVal ) ); 465 check( intVal ); 466 check( tr_bencDictFindInt( &top, "key4", &intVal ) ); 467 check( intVal ); 468 469 tr_bencFree( &top ); 470 return 0; 471} 472 473static int 474testParse2( void ) 475{ 476 tr_benc top; 477 tr_benc top2; 478 int64_t intVal; 479 const char * strVal; 480 double realVal; 481 bool boolVal; 482 int len; 483 char * benc; 484 const uint8_t * end; 485 486 tr_bencInitDict( &top, 0 ); 487 tr_bencDictAddBool( &top, "this-is-a-bool", true ); 488 tr_bencDictAddInt( &top, "this-is-an-int", 1234 ); 489 tr_bencDictAddReal( &top, "this-is-a-real", 0.5 ); 490 tr_bencDictAddStr( &top, "this-is-a-string", "this-is-a-string" ); 491 492 benc = tr_bencToStr( &top, TR_FMT_BENC, &len ); 493 check_streq( "d14:this-is-a-booli1e14:this-is-a-real8:0.50000016:this-is-a-string16:this-is-a-string14:this-is-an-inti1234ee", benc ); 494 check( !tr_bencParse( benc, benc+len, &top2, &end ) ); 495 check( (char*)end == benc + len ); 496 check( tr_bencIsDict( &top2 ) ); 497 check( tr_bencDictFindInt( &top, "this-is-an-int", &intVal ) ); 498 check_int_eq (1234, intVal); 499 check( tr_bencDictFindBool( &top, "this-is-a-bool", &boolVal ) ); 500 check( boolVal == true ); 501 check( tr_bencDictFindStr( &top, "this-is-a-string", &strVal ) ); 502 check_streq ("this-is-a-string", strVal); 503 check( tr_bencDictFindReal( &top, "this-is-a-real", &realVal ) ); 504 check_int_eq (50, (int)(realVal*100)); 505 506 tr_bencFree( &top2 ); 507 tr_free( benc ); 508 tr_bencFree( &top ); 509 510 return 0; 511} 512 513int 514main( void ) 515{ 516 static const testFunc tests[] = { 517 testInt, testStr, testParse, testJSON, testMerge, testBool, 518 testParse2, testStackSmash, 519 }; 520 521 return runTests(tests, NUM_TESTS(tests)); 522} 523