Upstream tarball 10145
[amule.git] / cocoa-mule / EC.mm
blob3033e86d70b94254878a0ad9ebd8180347c57555
2 #import "EC.h"
4 #import <CommonCrypto/CommonDigest.h>
6 @implementation ECTag
8 @synthesize tagName = m_name;
9 @synthesize tagType = m_type;
10 @synthesize subtags = m_subtags;
12 + (id)tagFromBuffer:(uint8_t **) buffer withLenght:(int) length {
13         ECTag *tag = nil; //[[ECTag alloc] init];
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);
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;
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;     
66 + (NSMutableArray *)readSubtags:(uint8_t **) buffer withLenght:(int) length {
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;
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)];
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         }
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;
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;
131 - (void)initSubtags {
132         m_subtags = [NSMutableArray array];
133         [m_subtags retain];
136 - (void) dealloc {
137         [m_subtags release];
138         [super dealloc];
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;
172 - (int)tagCount {
173         return [m_subtags count];
176 @end
178 @implementation ECTagInt8
180 @synthesize uint8Value = m_val;
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;     
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;
203 - (void)writeToSocket:(NSOutputStream *) socket {
204         [super writeToSocket:socket];
205         
206         [socket write:&m_val maxLength:sizeof(m_val)];
209 @end
211 @implementation ECTagInt16
213 @synthesize uint16Value = m_val;
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;     
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;
234         return tag;
238 @end
240 @implementation ECTagInt32
242 @synthesize uint32Value = m_val;
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;     
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;
263         return tag;
267 @end
269 @implementation ECTagInt64
271 @synthesize uint64Value = m_val;
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;     
284 + (id)tagFromBuffer:(uint8_t **) buffer {
285         ECTagInt64 *tag = [[ECTagInt64 alloc] init];
286         uint64_t lo, hi;
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;
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)];
311         val32 = m_val & 0xffffffff;
312         val32 = htonl(val32);
313         [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
316 @end
319 @implementation ECTagData
321 - (void)writeToSocket:(NSOutputStream *) socket {
322         [super writeToSocket:socket];
323         
324         [socket write:(const uint8_t *)[m_data bytes] maxLength:m_size];
327 - (void) dealloc {
328         [m_data release];
329         [super dealloc];
332 + (id)tagFromBuffer:(uint8_t **) buffer withLenght:(int) length {
333         ECTagData *tag = [[ECTagData alloc] init];
335         tag->m_data = [NSData dataWithBytes: *buffer length: length];
336         [tag->m_data retain];
337         
338         return tag;
342 @end
344 @implementation ECTagMD5
346 + (id)tagFromString:(NSString *) string withName:(ECTagNames) name {
347         ECTagMD5 *tag = [[ECTagMD5 alloc] init];
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;
361         return tag;
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;
376 - (MD5Data)getMD5Data {
377         if ( m_data ) {
378                 uint8_t *data_ptr = (uint8_t *)[m_data bytes];
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         }
389 - (NSString *)stringKey {
390         NSString *s = [NSString stringWithFormat:@"%qx%qx", m_val.hi, m_val.lo];
391         return s;
394 @end
396 @implementation ECTagString
398 @synthesize stringValue = m_val;
400 + tagFromString:(NSString *) string withName:(ECTagNames) name {
401         ECTagString *tag = [[ECTagString alloc] init];
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;
410         return tag;
413 + (id)tagFromBuffer:(uint8_t **) buffer {
414         ECTagString *tag = [[ECTagString alloc] init];
416         tag->m_val = [NSString stringWithCString:(char *)(*buffer) encoding:NSUTF8StringEncoding];
417         *buffer += [tag->m_val length] + 1;
418         
419         return tag;
422 @end
424 @implementation ECPacket
426 @synthesize opcode = m_opcode;
428 + (id)packetWithOpcode:(ec_opcode_t) opcode {
429         ECPacket *p = [[ECPacket alloc] init];
431         [p initWithOpcode:opcode];
432         
433         return p;
437 - (void)initWithOpcode:(ec_opcode_t) opcode {
438         m_opcode = opcode;
439         m_flags = 0x20;
441         // allow notification push to my client
442         m_flags |= EC_FLAG_NOTIFY | EC_FLAG_ACCEPTS;
444         [self initSubtags];
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++;
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;
482 - (void)writeToSocket:(NSOutputStream *) socket {
483         // 1 (command) + 2 (tag count)
484         int packet_size = [self getSize] + 1 + 2;
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)];
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         }
507 @end
509 @implementation ECLoginAuthPacket
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;
526 + (id)loginPacket:(NSString *) password withSalt:(uint64_t) salt {
527         ECLoginAuthPacket *p = [[ECLoginAuthPacket alloc] init];
529         [p initWithOpcode:EC_OP_AUTH_PASSWD];
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];
547         NSLog(@"[EC] using salt=%@ saltHash=%@ newPass=%@\n", saltStr, saltMD5, newPass);
549         ECTagMD5 *passtag = [ECTagMD5 tagFromString: newPass withName:EC_TAG_PASSWD_HASH];
550         [p->m_subtags addObject:passtag];
552         return p;
556 @end
558 @implementation ECLoginRequestPacket
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;
578 @end
581 @implementation ECRemoteConnection
583 @synthesize error = m_error;
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;
607 - (void) dealloc {
608         [m_rxbuf release];
609         [m_txbuf release];
611         [m_istream release];
612         [m_ostream release];
613         
614         [super dealloc];
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;
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];
656         [NSStream getStreamsToHost:host port:trgport inputStream:&m_istream outputStream:&m_ostream];
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];
667         [m_ostream scheduleInRunLoop:[NSRunLoop currentRunLoop]
668             forMode:NSDefaultRunLoopMode];
670         [m_istream open];
671         [m_ostream open];
672         
673         m_remaining_size = 8;
674         m_rx_size = 0;
677 - (void)sendLogin:(NSString *) password {
679         [m_login_handler usePass: password];
680         
681         ECLoginRequestPacket *p = [ECLoginRequestPacket loginPacket:@"0.1"];
682         [self sendPacket:p];
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);
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];
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;
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));
761                                                 int delta = 8 - m_rx_size;
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                                 }
814                         }
815                         break;
816                 }
817         }
820 - (void)setDelegate:(id)val {
821     delegate = val;
824 - (id)delegate {
825     return delegate;
829 @end
831 @implementation amuleLoginHandler
833 + (id)initWithConnection:(ECRemoteConnection *) connection {
835         amuleLoginHandler *obj = [[amuleLoginHandler alloc] init]; 
836         obj->m_connection = connection;
837         
838         obj->m_state = LOGIN_REQUEST_SENT;
840         return obj;
843 - (void)usePass:(NSString *) pass {
844         m_pass = pass;
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         }
877 - (void)reset {
878         m_state = LOGIN_IDLE;
881 - (bool)loginOK {
882         return m_state == LOGIN_OK;
886 @end