1 2#import "EC.h" 3 4#import <CommonCrypto/CommonDigest.h> 5 6@implementation ECTag 7 8@synthesize tagName = m_name; 9@synthesize tagType = m_type; 10@synthesize subtags = m_subtags; 11 12+ (id)tagFromBuffer:(uint8_t **) buffer withLenght:(int) length { 13 ECTag *tag = nil; //[[ECTag alloc] init]; 14 15 if ( length < 4 ) { 16 NSLog(@"[EC] buffer for tag is too short"); 17 return nil; 18 } 19 20 uint16_t name16 = *(uint16_t *)(*buffer); 21 name16 = ntohs(name16); 22 bool have_subtags = (name16 & 1) != 0; 23 name16 >>= 1; 24 ECTagNames tag_name = (ECTagNames)(name16); 25 *buffer += sizeof(name16); 26 27 uint8_t type8 = *(*buffer); 28 ECTagTypes tag_type = (ECTagTypes)type8; 29 *buffer += sizeof(type8); 30 31 uint32_t size32 = *(uint32_t *)(*buffer); 32 size32 = ntohl(size32); 33 *buffer += sizeof(uint32_t); 34 35 NSMutableArray *subtags = have_subtags ? [ECTag readSubtags:buffer withLenght:(length-3)] : nil; 36 37 switch (tag_type) { 38 case EC_TAGTYPE_UINT8: 39 tag = [ECTagInt8 tagFromBuffer:buffer]; 40 break; 41 case EC_TAGTYPE_UINT16: 42 tag = [ECTagInt16 tagFromBuffer:buffer]; 43 break; 44 case EC_TAGTYPE_UINT32: 45 tag = [ECTagInt32 tagFromBuffer:buffer]; 46 break; 47 case EC_TAGTYPE_UINT64: 48 tag = [ECTagInt64 tagFromBuffer:buffer]; 49 break; 50 case EC_TAGTYPE_HASH16: 51 tag = [ECTagMD5 tagFromBuffer:buffer]; 52 break; 53 case EC_TAGTYPE_STRING: 54 tag = [ECTagString tagFromBuffer:buffer]; 55 break; 56 default: ; 57 break; 58 } 59 if ( tag != nil ) { 60 tag->m_name = tag_name; 61 tag->m_subtags = subtags; 62 } 63 return tag; 64} 65 66+ (NSMutableArray *)readSubtags:(uint8_t **) buffer withLenght:(int) length { 67 68 uint16_t count16 = *(uint16_t *)(*buffer); 69 count16 = ntohs(count16); 70 *buffer += sizeof(count16); 71 NSMutableArray *array = [[NSMutableArray alloc] init]; 72 [array retain]; 73 for(int i = 0; i < count16; i++) { 74 id tag = [ECTag tagFromBuffer:buffer withLenght:length]; 75 if ( tag != nil ) { 76 [array addObject:tag]; 77 } 78 } 79 80 return array; 81} 82 83- (void)writeToSocket:(NSOutputStream *) socket { 84 uint16_t name16 = (uint16_t)m_name; 85 name16 <<= 1; 86 uint8_t type8 = (uint8_t)m_type; 87 if ( [m_subtags count] ) { 88 name16 |= 1; 89 } 90 name16 = htons(name16); 91 [socket write:(uint8_t *)&name16 maxLength:sizeof(name16)]; 92 [socket write:&type8 maxLength:sizeof(type8)]; 93 uint32_t size32 = [self getSize]; 94 size32 = htonl(size32); 95 [socket write:(uint8_t *)&size32 maxLength:sizeof(size32)]; 96} 97 98- (void)writeSubtagsToSocket:(NSOutputStream *) socket { 99 uint16_t count16 = [m_subtags count]; 100 count16 = htons(count16); 101 [socket write:(uint8_t *)&count16 maxLength:sizeof(count16)]; 102 for (ECTag *t in m_subtags) { 103 [t writeToSocket:socket]; 104 } 105} 106 107- (int)getSize { 108 int total_size = m_size; 109 for (ECTag *t in m_subtags) { 110 total_size += [t getSize]; 111 // name + type + size 112 total_size += (2 + 1 + 4); 113 if ([t->m_subtags count]) { 114 total_size += 2; 115 } 116 } 117 return total_size; 118} 119 120- (id)tagByName:(ECTagNames) tagname { 121 ECTag *mytag = nil; 122 for (ECTag *t in m_subtags) { 123 if (t.tagName == tagname) { 124 mytag = t; 125 break; 126 } 127 } 128 return mytag; 129} 130 131- (void)initSubtags { 132 m_subtags = [NSMutableArray array]; 133 [m_subtags retain]; 134} 135 136- (void) dealloc { 137 [m_subtags release]; 138 [super dealloc]; 139} 140 141- (uint64_t)tagInt64ByName: (ECTagNames) tagname { 142 ECTag *st = [self tagByName: tagname]; 143 if (st == nil) { 144 return 0; 145 } 146 uint64_t value = 0; 147 switch ([st getSize]) { 148 case 1: { 149 ECTagInt8 *t = (ECTagInt8 *)st; 150 value = t.uint8Value; 151 break; 152 } 153 case 2: { 154 ECTagInt16 *t = (ECTagInt16 *)st; 155 value = t.uint16Value; 156 break; 157 } 158 case 4: { 159 ECTagInt32 *t = (ECTagInt32 *)st; 160 value = t.uint32Value; 161 break; 162 } 163 case 8: { 164 ECTagInt64 *t = (ECTagInt64 *)st; 165 value = t.uint64Value; 166 break; 167 } 168 } 169 return value; 170} 171 172- (int)tagCount { 173 return [m_subtags count]; 174} 175 176@end 177 178@implementation ECTagInt8 179 180@synthesize uint8Value = m_val; 181 182+ (id)tagFromInt8:(uint8_t) value withName:(ECTagNames) name { 183 ECTagInt8 *tag = [[ECTagInt8 alloc] init]; 184 tag->m_val = value; 185 tag->m_size = 1; 186 tag->m_type = EC_TAGTYPE_UINT8; 187 tag->m_name = name; 188 189 return tag; 190} 191 192+ (id)tagFromBuffer:(uint8_t **) buffer { 193 ECTagInt8 *tag = [[ECTagInt8 alloc] init]; 194 tag->m_val = **buffer; 195 tag->m_size = 1; 196 tag->m_type = EC_TAGTYPE_UINT8; 197 198 *buffer += 1; 199 200 return tag; 201} 202 203- (void)writeToSocket:(NSOutputStream *) socket { 204 [super writeToSocket:socket]; 205 206 [socket write:&m_val maxLength:sizeof(m_val)]; 207} 208 209@end 210 211@implementation ECTagInt16 212 213@synthesize uint16Value = m_val; 214 215+ (id)tagFromInt16:(uint16_t) value withName:(ECTagNames) name { 216 ECTagInt16 *tag = [[ECTagInt16 alloc] init]; 217 tag->m_val = value; 218 tag->m_size = 2; 219 tag->m_type = EC_TAGTYPE_UINT16; 220 tag->m_name = name; 221 222 return tag; 223} 224 225+ (id)tagFromBuffer:(uint8_t **) buffer { 226 ECTagInt16 *tag = [[ECTagInt16 alloc] init]; 227 228 tag->m_val = ntohs(*((uint16_t *)(*buffer))); 229 tag->m_size = 2; 230 tag->m_type = EC_TAGTYPE_UINT16; 231 232 *buffer += 2; 233 234 return tag; 235} 236 237 238@end 239 240@implementation ECTagInt32 241 242@synthesize uint32Value = m_val; 243 244+ (id)tagFromInt32:(uint32_t) value withName:(ECTagNames) name { 245 ECTagInt32 *tag = [[ECTagInt32 alloc] init]; 246 tag->m_val = value; 247 tag->m_size = 4; 248 tag->m_type = EC_TAGTYPE_UINT32; 249 tag->m_name = name; 250 251 return tag; 252} 253 254+ (id)tagFromBuffer:(uint8_t **) buffer { 255 ECTagInt32 *tag = [[ECTagInt32 alloc] init]; 256 257 tag->m_val = ntohl(*((uint32_t *)(*buffer))); 258 tag->m_size = 4; 259 tag->m_type = EC_TAGTYPE_UINT32; 260 261 *buffer += 4; 262 263 return tag; 264} 265 266 267@end 268 269@implementation ECTagInt64 270 271@synthesize uint64Value = m_val; 272 273+ (id)tagFromInt64:(uint64_t) value withName:(ECTagNames) name { 274 ECTagInt64 *tag = [[ECTagInt64 alloc] init]; 275 tag->m_val = value; 276 tag->m_size = 8; 277 tag->m_type = EC_TAGTYPE_UINT64; 278 tag->m_name = name; 279 280 return tag; 281} 282 283 284+ (id)tagFromBuffer:(uint8_t **) buffer { 285 ECTagInt64 *tag = [[ECTagInt64 alloc] init]; 286 uint64_t lo, hi; 287 288 uint32 val32 = *((uint32_t *)(*buffer)); 289 hi = ntohl(val32); 290 *buffer += 4; 291 292 val32 = *((uint32_t *)(*buffer)); 293 lo = ntohl(val32); 294 *buffer += 4; 295 296 tag->m_val = (hi << 32) | lo; 297 tag->m_size = 8; 298 tag->m_type = EC_TAGTYPE_UINT64; 299 300 return tag; 301} 302 303 304- (void)writeToSocket:(NSOutputStream *) socket { 305 [super writeToSocket:socket]; 306 307 uint32_t val32 = m_val >> 32; 308 val32 = htonl(val32); 309 [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)]; 310 311 val32 = m_val & 0xffffffff; 312 val32 = htonl(val32); 313 [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)]; 314} 315 316@end 317 318 319@implementation ECTagData 320 321- (void)writeToSocket:(NSOutputStream *) socket { 322 [super writeToSocket:socket]; 323 324 [socket write:(const uint8_t *)[m_data bytes] maxLength:m_size]; 325} 326 327- (void) dealloc { 328 [m_data release]; 329 [super dealloc]; 330} 331 332+ (id)tagFromBuffer:(uint8_t **) buffer withLenght:(int) length { 333 ECTagData *tag = [[ECTagData alloc] init]; 334 335 tag->m_data = [NSData dataWithBytes: *buffer length: length]; 336 [tag->m_data retain]; 337 338 return tag; 339} 340 341 342@end 343 344@implementation ECTagMD5 345 346+ (id)tagFromString:(NSString *) string withName:(ECTagNames) name { 347 ECTagMD5 *tag = [[ECTagMD5 alloc] init]; 348 349 CC_MD5_CTX ctx; 350 unsigned char md5data[16]; 351 CC_MD5_Init(&ctx); 352 CC_MD5_Update(&ctx, [string UTF8String], [string length]); 353 CC_MD5_Final(md5data, &ctx); 354 355 tag->m_data = [NSData dataWithBytes: md5data length: sizeof(md5data)]; 356 [tag->m_data retain]; 357 tag->m_size = 16; 358 tag->m_type = EC_TAGTYPE_HASH16; 359 tag->m_name = name; 360 361 return tag; 362} 363 364+ (id)tagFromBuffer:(uint8_t **) buffer { 365 ECTagMD5 *tag = [[ECTagMD5 alloc] init]; 366 367 tag->m_data = 0; 368 tag->m_val.lo = *((uint64_t *)(*buffer)); 369 (*buffer) += 8; 370 tag->m_val.hi = *((uint64_t *)(*buffer)); 371 (*buffer) += 8; 372 373 return tag; 374} 375 376- (MD5Data)getMD5Data { 377 if ( m_data ) { 378 uint8_t *data_ptr = (uint8_t *)[m_data bytes]; 379 380 uint64_t hi = *(uint64_t *)data_ptr; 381 data_ptr += 8; 382 uint64_t lo = *(uint64_t *)data_ptr; 383 MD5Data md5 = {hi, lo}; 384 return md5; 385 } else { 386 return m_val; 387 } 388} 389- (NSString *)stringKey { 390 NSString *s = [NSString stringWithFormat:@"%qx%qx", m_val.hi, m_val.lo]; 391 return s; 392} 393 394@end 395 396@implementation ECTagString 397 398@synthesize stringValue = m_val; 399 400+ tagFromString:(NSString *) string withName:(ECTagNames) name { 401 ECTagString *tag = [[ECTagString alloc] init]; 402 403 const char *rawstring = [string UTF8String]; 404 tag->m_size = strlen(rawstring) + 1; 405 tag->m_data = [NSData dataWithBytes: rawstring length: tag->m_size]; 406 [tag->m_data retain]; 407 tag->m_type = EC_TAGTYPE_STRING; 408 tag->m_name = name; 409 410 return tag; 411} 412 413+ (id)tagFromBuffer:(uint8_t **) buffer { 414 ECTagString *tag = [[ECTagString alloc] init]; 415 416 tag->m_val = [NSString stringWithCString:(char *)(*buffer) encoding:NSUTF8StringEncoding]; 417 *buffer += [tag->m_val length] + 1; 418 419 return tag; 420} 421 422@end 423 424@implementation ECPacket 425 426@synthesize opcode = m_opcode; 427 428+ (id)packetWithOpcode:(ec_opcode_t) opcode { 429 ECPacket *p = [[ECPacket alloc] init]; 430 431 [p initWithOpcode:opcode]; 432 433 return p; 434} 435 436 437- (void)initWithOpcode:(ec_opcode_t) opcode { 438 m_opcode = opcode; 439 m_flags = 0x20; 440 441 // allow notification push to my client 442 m_flags |= EC_FLAG_NOTIFY | EC_FLAG_ACCEPTS; 443 444 [self initSubtags]; 445} 446 447+ (id)packetFromBuffer:(uint8_t *) buffer withLength:(int)length { 448 if ( length < 11 ) { 449 return nil; 450 } 451 ECPacket *p = [[ECPacket alloc] init]; 452 uint8_t *data = buffer; 453 454 p->m_flags = ntohl(*((uint32_t *)data)); 455 data += 4; 456 uint32_t packet_size = ntohl(*((uint32_t *)data)); 457 data += 4; 458 if ( packet_size > 1024*1024 ) { 459 return nil; 460 } 461 p->m_opcode = (ec_opcode_t)(*data); 462 data++; 463 464 uint16_t tag_count = ntohs(*((uint16_t *)data)); 465 data += 2; 466 if ( tag_count ) { 467 p->m_subtags = [[NSMutableArray alloc] init]; 468 [p->m_subtags retain]; 469 uint8_t *start_ptr = data; 470 for(int i = 0; i < tag_count; i++) { 471 ECTag *tag = [ECTag tagFromBuffer:&data withLenght:(length - (data - start_ptr))]; 472 // some tags are not supported yet 473 if ( tag != nil ) { 474 [p->m_subtags addObject:tag]; 475 } 476 } 477 } 478 479 return p; 480} 481 482- (void)writeToSocket:(NSOutputStream *) socket { 483 // 1 (command) + 2 (tag count) 484 int packet_size = [self getSize] + 1 + 2; 485 486// No need for zlib on client side 487// if ( packet_size > MaxUncompressedPacket ) { 488// m_flags |= (Int32)ECFlags.EC_FLAG_ZLIB; 489// } 490 uint32_t val32 = htonl(m_flags); 491 [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)]; 492 if ( m_flags & EC_FLAG_ACCEPTS ) { 493 [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)]; 494 } 495 val32 = htonl(packet_size); 496 [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)]; 497 [socket write:(uint8_t *)&m_opcode maxLength:sizeof(m_opcode)]; 498 499 if ( [m_subtags count] ) { 500 [self writeSubtagsToSocket:socket]; 501 } else { 502 uint16_t val16 = 0; 503 [socket write:(uint8_t *)&val16 maxLength:sizeof(val16)]; 504 } 505} 506 507@end 508 509@implementation ECLoginAuthPacket 510 511- (NSString *)getMD5_Str:(NSString *) str { 512 CC_MD5_CTX ctx; 513 unsigned char md5data[16]; 514 CC_MD5_Init(&ctx); 515 CC_MD5_Update(&ctx, [str UTF8String], [str length]); 516 CC_MD5_Final(md5data, &ctx); 517 NSString *MD5str = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 518 md5data[0], md5data[1],md5data[2],md5data[3], 519 md5data[4],md5data[5],md5data[6],md5data[7], 520 md5data[8],md5data[9],md5data[10],md5data[11], 521 md5data[12],md5data[13],md5data[14],md5data[15] 522 ]; 523 return MD5str; 524} 525 526+ (id)loginPacket:(NSString *) password withSalt:(uint64_t) salt { 527 ECLoginAuthPacket *p = [[ECLoginAuthPacket alloc] init]; 528 529 [p initWithOpcode:EC_OP_AUTH_PASSWD]; 530 531 NSString *saltStr = [NSString stringWithFormat:@"%llX", salt]; 532// CC_MD5_CTX ctx; 533// unsigned char md5data[16]; 534// CC_MD5_Init(&ctx); 535// CC_MD5_Update(&ctx, [saltStr UTF8String], [saltStr length]); 536// CC_MD5_Final(md5data, &ctx); 537// NSString *saltMD5 = [NSString stringWithFormat:@"%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x", 538// md5data[0], md5data[1],md5data[2],md5data[3], 539// md5data[4],md5data[5],md5data[6],md5data[7], 540// md5data[8],md5data[9],md5data[10],md5data[11], 541// md5data[12],md5data[13],md5data[14],md5data[15] 542// ]; 543 NSString *saltMD5 = [p getMD5_Str: saltStr]; 544 545 NSString *newPass = [NSString stringWithFormat:@"%@%@", [p getMD5_Str: password], saltMD5]; 546 547 NSLog(@"[EC] using salt=%@ saltHash=%@ newPass=%@\n", saltStr, saltMD5, newPass); 548 549 ECTagMD5 *passtag = [ECTagMD5 tagFromString: newPass withName:EC_TAG_PASSWD_HASH]; 550 [p->m_subtags addObject:passtag]; 551 552 return p; 553} 554 555 556@end 557 558@implementation ECLoginRequestPacket 559 560+ (id)loginPacket:(NSString *) version { 561 ECLoginRequestPacket *p = [[ECLoginRequestPacket alloc] init]; 562 563 [p initWithOpcode:EC_OP_AUTH_REQ]; 564 565 ECTagString *version_tag = [ECTagString tagFromString:version withName:EC_TAG_CLIENT_VERSION]; 566 [p->m_subtags addObject:version_tag]; 567 568 ECTagString *client_name_tag = [ECTagString tagFromString:@"cocoa-frontend" withName:EC_TAG_CLIENT_NAME]; 569 [p->m_subtags addObject:client_name_tag]; 570 571 ECTagInt64 *proto_version_tag = [ECTagInt64 tagFromInt64:EC_CURRENT_PROTOCOL_VERSION withName:EC_TAG_PROTOCOL_VERSION]; 572 [p->m_subtags addObject:proto_version_tag]; 573 574 return p; 575} 576 577 578@end 579 580 581@implementation ECRemoteConnection 582 583@synthesize error = m_error; 584 585+ (id)remoteConnection { 586 ECRemoteConnection *p = [[ECRemoteConnection alloc] init]; 587 588 // 589 // rx buffer can be resized as needed 590 // 591 p->m_rxbuf = [NSMutableData dataWithLength:1024]; 592 [p->m_rxbuf retain]; 593 594 p->m_login_handler = [amuleLoginHandler initWithConnection:p]; 595 [p->m_login_handler retain]; 596 // 597 // client only transmit commands, which are 598 // quite small in size. "big enough" buffer will do the trick 599 // 600// p->m_txbuf = [NSMutableData dataWithLength:1024]; 601// [p->m_txbuf retain]; 602 p->m_txbuf = nil; 603 604 return p; 605} 606 607- (void) dealloc { 608 [m_rxbuf release]; 609 [m_txbuf release]; 610 611 [m_istream release]; 612 [m_ostream release]; 613 614 [super dealloc]; 615} 616 617- (bool)isIpv4Address:(NSString *) address { 618 NSArray *ar = [address componentsSeparatedByString:@"."]; 619 if ( [ar count] != 4 ) { 620 return false; 621 } 622 for (NSString *s in ar) { 623 const char *p = [s UTF8String]; 624 while ( *p ) { 625 if ( !isdigit(*p) ) { 626 return false; 627 } 628 p++; 629 } 630 } 631 return true; 632} 633 634- (void)connectToAddress:(NSString *) hostname withPort:(int)trgport { 635 m_error = false; 636 637 NSHost *host = [NSHost hostWithName:hostname]; 638 NSString *addr = nil; 639 640 // 641 // On Mac localhost has ipv6 address (linklocal), but amuled listen 642 // only on ipv4 643 // 644 for (NSString *ad in host.addresses) { 645 NSLog(@"host have address=%@ is_ipv4=%d\n", ad, [self isIpv4Address:ad]); 646 if ( [self isIpv4Address:ad] ) { 647 addr = ad; 648 break; 649 } 650 } 651 if ( addr == nil ) { 652 return; 653 } 654 host = [NSHost hostWithAddress:addr]; 655 656 [NSStream getStreamsToHost:host port:trgport inputStream:&m_istream outputStream:&m_ostream]; 657 658 [m_istream retain]; 659 [m_ostream retain]; 660 661 [m_istream setDelegate:self]; 662 [m_ostream setDelegate:self]; 663 664 [m_istream scheduleInRunLoop:[NSRunLoop currentRunLoop] 665 forMode:NSDefaultRunLoopMode]; 666 667 [m_ostream scheduleInRunLoop:[NSRunLoop currentRunLoop] 668 forMode:NSDefaultRunLoopMode]; 669 670 [m_istream open]; 671 [m_ostream open]; 672 673 m_remaining_size = 8; 674 m_rx_size = 0; 675} 676 677- (void)sendLogin:(NSString *) password { 678 679 [m_login_handler usePass: password]; 680 681 ECLoginRequestPacket *p = [ECLoginRequestPacket loginPacket:@"0.1"]; 682 [self sendPacket:p]; 683} 684 685- (void)sendPacket:(ECPacket *) packet { 686 NSOutputStream *memstream = [NSOutputStream outputStreamToMemory]; 687 [memstream open]; 688 689 [packet writeToSocket:memstream]; 690 id data = [memstream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; 691 692 m_tx_size = [data length]; 693 NSLog(@"[EC] sending packet %d bytes\n", m_tx_size); 694 m_tx_ptr = [m_ostream write:(const uint8_t *)[data bytes] maxLength:[data length]]; 695 NSLog(@"[EC] %d bytes sent\n", m_tx_ptr); 696 if ( m_tx_ptr == m_tx_size ) { 697 m_txbuf = nil; 698 } else { 699 m_txbuf = (NSData *)data; 700 [m_txbuf retain]; 701 } 702 NSStreamStatus stream_status = [m_ostream streamStatus]; 703 switch ( stream_status ) { 704 case NSStreamStatusNotOpen: 705 case NSStreamStatusClosed: 706 case NSStreamStatusError: 707 NSLog(@"[EC] error in output stream\n"); 708 m_error = true; 709 break; 710 default:; 711 } 712// NSLog(@"[EC] status in output stream=%d\n", stream_status); 713 714} 715 716- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode { 717 switch(eventCode) { 718 case NSStreamEventOpenCompleted: 719 { 720 NSLog(@"[EC] open complete\n"); 721 break; 722 } 723 case NSStreamEventErrorOccurred: 724 { 725 NSError *e = [stream streamError]; 726 NSString *description = [e localizedDescription]; 727 NSLog(@"[EC] socket error [%s]\n", [description UTF8String]); 728 break; 729 } 730 case NSStreamEventHasBytesAvailable: 731 { 732 uint8_t *data_ptr = (uint8_t *)[m_rxbuf mutableBytes]; 733 unsigned int len = [m_rxbuf length]; 734 735 len = [(NSInputStream *)stream read:data_ptr + m_rx_size maxLength:len]; 736#ifdef EC_RX_DEBUG 737 NSLog(@"[EC] receiving %d bytes, %d in total, %d remaining\n", len, m_rx_size, m_remaining_size); 738#endif 739 if ( len == 0 ) { 740 // 741 // Remote side must be closed connection 742 // 743 m_error = true; 744 if ( [delegate respondsToSelector:@selector(handleError)] ) { 745 [delegate performSelector:@selector(handleError)]; 746 } 747 } 748 int total_len = len; 749 int packet_offset = 0; 750 while ( total_len != 0 ) { 751 len = ( m_remaining_size > total_len ) ? total_len : m_remaining_size; 752 total_len -= len; 753 754 // are we still waiting for flags and size? 755 if ( m_rx_size < 8 ) { 756 if ( (m_rx_size + len) >= 8 ) { 757 // got flags and packet size - may proceed 758 //uint32_t flags = *(((uint32_t *)[m_rxbuf mutableBytes]) + 0); 759 uint32_t val32 = *((uint32_t *)(data_ptr + 4 + packet_offset)); 760 761 int delta = 8 - m_rx_size; 762 763 m_remaining_size = ntohl(val32) - (len - delta); 764#ifdef EC_RX_DEBUG 765 NSLog(@"[EC] rx got flags+size, remaining count %d\n", m_remaining_size); 766#endif 767 } else { 768 m_remaining_size -= len; 769 } 770 } else { 771 m_remaining_size -= len; 772 } 773 m_rx_size += len; 774 if ( m_remaining_size == 0 ) { 775 // 776 // full packet received, call handler 777 // 778 uint8_t *packet_start = data_ptr + packet_offset; 779 int packet_length = [m_rxbuf length] - packet_offset; 780 ECPacket *packet = [ECPacket packetFromBuffer:packet_start withLength:packet_length]; 781 packet_offset += m_rx_size; 782 783 if ( [m_login_handler loginOK] ) { 784#ifdef EC_RX_DEBUG 785 NSLog(@"[EC] calling delegate\n"); 786#endif 787 if ( [delegate respondsToSelector:@selector(handlePacket:)] ) { 788 [delegate performSelector:@selector(handlePacket:) withObject:packet]; 789 } 790 } else { 791 NSLog(@"[EC] login handler\n"); 792 [m_login_handler handlePacket: packet]; 793 } 794 m_remaining_size = 8; 795 m_rx_size = 0; 796 } 797 } 798 break; 799 } 800 801 case NSStreamEventHasSpaceAvailable: 802 { 803 if ( m_txbuf != nil ) { 804 int remaining = [m_txbuf length] - m_tx_ptr; 805 if ( remaining ) { 806 const uint8_t *txdata = ((const uint8_t *)[m_txbuf bytes]) + m_tx_ptr; 807 int txcount = [m_ostream write:txdata maxLength:remaining]; 808 m_tx_ptr += txcount; 809 } else { 810 [m_txbuf release]; 811 m_txbuf = nil; 812 } 813 814 } 815 break; 816 } 817 } 818} 819 820- (void)setDelegate:(id)val { 821 delegate = val; 822} 823 824- (id)delegate { 825 return delegate; 826} 827 828 829@end 830 831@implementation amuleLoginHandler 832 833+ (id)initWithConnection:(ECRemoteConnection *) connection { 834 835 amuleLoginHandler *obj = [[amuleLoginHandler alloc] init]; 836 obj->m_connection = connection; 837 838 obj->m_state = LOGIN_REQUEST_SENT; 839 840 return obj; 841} 842 843- (void)usePass:(NSString *) pass { 844 m_pass = pass; 845} 846 847- (void)handlePacket:(ECPacket *) packet { 848 switch(m_state) { 849 case LOGIN_IDLE: 850 NSLog(@"[EC]: error - no packet should come until request is sent\n"); 851 break; 852 case LOGIN_REQUEST_SENT: 853 if ( packet.opcode == EC_OP_AUTH_SALT ) { 854 855 uint64_t salt = [packet tagInt64ByName:EC_TAG_PASSWD_SALT]; 856 ECLoginAuthPacket *auth_packet = [ECLoginAuthPacket loginPacket:m_pass withSalt:salt]; 857 [m_connection sendPacket:auth_packet]; 858 859 m_state = LOGIN_PASS_SENT; 860 } else { 861 NSLog(@"[EC]: error - expecting packet with EC_OP_AUTH_SALT, not [%d]\n", packet.opcode); 862 m_state = LOGIN_IDLE; 863 } 864 break; 865 case LOGIN_PASS_SENT: 866 if ( packet.opcode == EC_OP_AUTH_OK ) { 867 m_state = LOGIN_OK; 868 } else { 869 NSLog(@"[EC]: error - login failed, core replied with code=[%d]\n", packet.opcode); 870 } 871 break; 872 case LOGIN_OK: 873 NSLog(@"[EC]: error - this delegate should be replaced after login completed\n"); 874 break; 875 } 876} 877- (void)reset { 878 m_state = LOGIN_IDLE; 879} 880 881- (bool)loginOK { 882 return m_state == LOGIN_OK; 883} 884 885 886@end 887