Upstream tarball 9324
[amule.git] / cocoa-mule / EC.mm
blob12d2db1ae6b765b0291f985edd4018e484874d9c
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;
173 @end
175 @implementation ECTagInt8
177 @synthesize uint8Value = m_val;
179 + (id)tagFromInt8:(uint8_t) value withName:(ECTagNames) name {
180         ECTagInt8 *tag = [[ECTagInt8 alloc] init];
181         tag->m_val = value;
182         tag->m_size = 1;
183         tag->m_type = EC_TAGTYPE_UINT8;
184         tag->m_name = name;
185         
186         return tag;     
189 + (id)tagFromBuffer:(uint8_t **) buffer {
190         ECTagInt8 *tag = [[ECTagInt8 alloc] init];
191         tag->m_val = **buffer;
192         tag->m_size = 1;
193         tag->m_type = EC_TAGTYPE_UINT8;
194         
195         *buffer += 1;
196         
197         return tag;
200 - (void)writeToSocket:(NSOutputStream *) socket {
201         [super writeToSocket:socket];
202         
203         [socket write:&m_val maxLength:sizeof(m_val)];
206 @end
208 @implementation ECTagInt16
210 @synthesize uint16Value = m_val;
212 + (id)tagFromInt16:(uint16_t) value withName:(ECTagNames) name {
213         ECTagInt16 *tag = [[ECTagInt16 alloc] init];
214         tag->m_val = value;
215         tag->m_size = 2;
216         tag->m_type = EC_TAGTYPE_UINT16;
217         tag->m_name = name;
218         
219         return tag;     
222 + (id)tagFromBuffer:(uint8_t **) buffer {
223         ECTagInt16 *tag = [[ECTagInt16 alloc] init];
224         
225         tag->m_val = ntohs(*((uint16_t *)(*buffer)));
226         tag->m_size = 2;
227         tag->m_type = EC_TAGTYPE_UINT16;
228         
229         *buffer += 2;
231         return tag;
235 @end
237 @implementation ECTagInt32
239 @synthesize uint32Value = m_val;
241 + (id)tagFromInt32:(uint32_t) value withName:(ECTagNames) name {
242         ECTagInt32 *tag = [[ECTagInt32 alloc] init];
243         tag->m_val = value;
244         tag->m_size = 4;
245         tag->m_type = EC_TAGTYPE_UINT32;
246         tag->m_name = name;
247         
248         return tag;     
251 + (id)tagFromBuffer:(uint8_t **) buffer {
252         ECTagInt32 *tag = [[ECTagInt32 alloc] init];
253         
254         tag->m_val = ntohl(*((uint32_t *)(*buffer)));
255         tag->m_size = 4;
256         tag->m_type = EC_TAGTYPE_UINT32;
257         
258         *buffer += 4;
260         return tag;
264 @end
266 @implementation ECTagInt64
268 @synthesize uint64Value = m_val;
270 + (id)tagFromInt64:(uint64_t) value withName:(ECTagNames) name {
271         ECTagInt64 *tag = [[ECTagInt64 alloc] init];
272         tag->m_val = value;
273         tag->m_size = 8;
274         tag->m_type = EC_TAGTYPE_UINT64;
275         tag->m_name = name;
276         
277         return tag;     
281 + (id)tagFromBuffer:(uint8_t **) buffer {
282         ECTagInt64 *tag = [[ECTagInt64 alloc] init];
283         uint64_t lo, hi;
284         uint32 val32 = *((uint32_t *)(*buffer));
285         lo = ntohl(val32);
286         *buffer += 4;
288         val32 = *((uint32_t *)(*buffer));
289         hi = ntohl(val32);
290         *buffer += 4;
291         
292         tag->m_val = (hi << 32) | lo;
293         tag->m_size = 8;
294         tag->m_type = EC_TAGTYPE_UINT64;
295         
296         return tag;
300 - (void)writeToSocket:(NSOutputStream *) socket {
301         [super writeToSocket:socket];
302         
303         uint32_t val32 = m_val >> 32;
304         val32 = htonl(val32);
305         [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
307         val32 = m_val & 0xffffffff;
308         val32 = htonl(val32);
309         [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
312 @end
315 @implementation ECTagData
317 - (void)writeToSocket:(NSOutputStream *) socket {
318         [super writeToSocket:socket];
319         
320         [socket write:(const uint8_t *)[m_data bytes] maxLength:m_size];
323 - (void) dealloc {
324         [m_data release];
325         [super dealloc];
328 + (id)tagFromBuffer:(uint8_t **) buffer withLenght:(int) length {
329         ECTagData *tag = [[ECTagData alloc] init];
331         tag->m_data = [NSData dataWithBytes: *buffer length: length];
332         [tag->m_data retain];
333         
334         return tag;
338 @end
340 @implementation ECTagMD5
342 + (id)tagFromString:(NSString *) string withName:(ECTagNames) name {
343         ECTagMD5 *tag = [[ECTagMD5 alloc] init];
345         CC_MD5_CTX ctx;
346         unsigned char md5data[16];
347         CC_MD5_Init(&ctx);
348         CC_MD5_Update(&ctx, [string UTF8String], [string length]);
349         CC_MD5_Final(md5data, &ctx);
350         
351         tag->m_data = [NSData dataWithBytes: md5data length: sizeof(md5data)];
352         [tag->m_data retain];
353         tag->m_size = 16;
354         tag->m_type = EC_TAGTYPE_HASH16;
355         tag->m_name = name;
357         return tag;
360 + (id)tagFromBuffer:(uint8_t **) buffer {
361         ECTagMD5 *tag = [[ECTagMD5 alloc] init];
362         
363         tag->m_data = 0;
364         tag->m_val.lo = *((uint64_t *)(*buffer));
365         (*buffer) += 8;
366         tag->m_val.hi = *((uint64_t *)(*buffer));
367         (*buffer) += 8;
368         
369         return tag;
372 - (MD5Data)getMD5Data {
373         if ( m_data ) {
374                 uint8_t *data_ptr = (uint8_t *)[m_data bytes];
376                 uint64_t hi = *(uint64_t *)data_ptr;
377                 data_ptr += 8;
378                 uint64_t lo = *(uint64_t *)data_ptr;
379                 MD5Data md5 = {hi, lo};
380                 return md5;
381         } else {
382                 return m_val;
383         }
385 - (NSString *)stringKey {
386         NSString *s = [NSString stringWithFormat:@"%qx%qx", m_val.hi, m_val.lo];
387         return s;
390 @end
392 @implementation ECTagString
394 @synthesize stringValue = m_val;
396 + tagFromString:(NSString *) string withName:(ECTagNames) name {
397         ECTagString *tag = [[ECTagString alloc] init];
399         const char *rawstring = [string UTF8String];
400         tag->m_size = strlen(rawstring) + 1;
401         tag->m_data = [NSData dataWithBytes: rawstring length: tag->m_size];
402         [tag->m_data retain];
403         tag->m_type = EC_TAGTYPE_STRING;
404         tag->m_name = name;
406         return tag;
409 + (id)tagFromBuffer:(uint8_t **) buffer {
410         ECTagString *tag = [[ECTagString alloc] init];
412         tag->m_val = [NSString stringWithCString:(char *)(*buffer) encoding:NSUTF8StringEncoding];
413         *buffer += [tag->m_val length] + 1;
414         
415         return tag;
418 @end
420 @implementation ECPacket
422 @synthesize opcode = m_opcode;
424 + (id)packetWithOpcode:(ec_opcode_t) opcode {
425         ECPacket *p = [[ECPacket alloc] init];
427         [p initWithOpcode:opcode];
428         
429         return p;
433 - (void)initWithOpcode:(ec_opcode_t) opcode {
434         m_opcode = opcode;
435         m_flags = 0x20;
437         // allow notification push to my client
438         m_flags |= EC_FLAG_NOTIFY | EC_FLAG_ACCEPTS;
440         [self initSubtags];
443 + (id)packetFromBuffer:(uint8_t *) buffer withLength:(int)length {
444         if ( length < 11 ) {
445                 return nil;
446         }
447         ECPacket *p = [[ECPacket alloc] init];
448         uint8_t *data = buffer;
449         
450         p->m_flags = ntohl(*((uint32_t *)data));
451         data += 4;
452         uint32_t packet_size = ntohl(*((uint32_t *)data));
453         data += 4;
454         if ( packet_size > 1024*1024 ) {
455                 return nil;
456         }
457         p->m_opcode = (ec_opcode_t)(*data);
458         data++;
460         uint16_t tag_count = ntohs(*((uint16_t *)data));
461         data += 2;
462         if ( tag_count ) {
463                 p->m_subtags = [[NSMutableArray alloc] init];
464                 [p->m_subtags retain];
465                 uint8_t *start_ptr = data;
466                 for(int i = 0; i < tag_count; i++) {
467                         ECTag *tag = [ECTag tagFromBuffer:&data withLenght:(length - (data - start_ptr))];
468                         // some tags are not supported yet
469                         if ( tag != nil ) {
470                                 [p->m_subtags addObject:tag];
471                         }
472                 }
473         }
474         
475         return p;
478 - (void)writeToSocket:(NSOutputStream *) socket {
479         // 1 (command) + 2 (tag count)
480         int packet_size = [self getSize] + 1 + 2;
482 // No need for zlib on client side      
483 //      if ( packet_size > MaxUncompressedPacket ) {
484 //              m_flags |= (Int32)ECFlags.EC_FLAG_ZLIB;
485 //      }
486         uint32_t val32 = htonl(m_flags);
487         [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
488         if ( m_flags & EC_FLAG_ACCEPTS ) {
489                 [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
490         }
491         val32 = htonl(packet_size);
492         [socket write:(uint8_t *)&val32 maxLength:sizeof(val32)];
493         [socket write:(uint8_t *)&m_opcode maxLength:sizeof(m_opcode)];
495         if ( [m_subtags count] ) {
496                 [self writeSubtagsToSocket:socket];
497         } else {
498                 uint16_t val16 = 0;
499                 [socket write:(uint8_t *)&val16 maxLength:sizeof(val16)];
500         }
503 @end
505 @implementation ECLoginPacket
507 + (id)loginPacket:(NSString *) password withVersion:(NSString *) version {
508         ECLoginPacket *p = [[ECLoginPacket alloc] init];
510         [p initWithOpcode:EC_OP_AUTH_REQ];
512         ECTagMD5 *passtag = [ECTagMD5 tagFromString: password withName:EC_TAG_PASSWD_HASH];
513         [p->m_subtags addObject:passtag];
515         ECTagString *version_tag = [ECTagString tagFromString:version withName:EC_TAG_CLIENT_VERSION];
516         [p->m_subtags addObject:version_tag];
517         
518         ECTagString *client_name_tag = [ECTagString tagFromString:@"cocoa-frontend" withName:EC_TAG_CLIENT_NAME];
519         [p->m_subtags addObject:client_name_tag];
520         
521         ECTagInt64 *proto_version_tag = [ECTagInt64 tagFromInt64:EC_CURRENT_PROTOCOL_VERSION withName:EC_TAG_PROTOCOL_VERSION];
522         [p->m_subtags addObject:proto_version_tag];
523                 
524         return p;
528 @end
531 @implementation ECRemoteConnection
533 @synthesize error = m_error;
535 + (id)remoteConnection {
536         ECRemoteConnection *p = [[ECRemoteConnection alloc] init];
537         
538         //
539         // rx buffer can be resized as needed
540         //
541         p->m_rxbuf = [NSMutableData dataWithLength:1024];
542         [p->m_rxbuf retain];
543         
544         //
545         // client only transmit commands, which are
546         // quite small in size. "big enough" buffer will do the trick
547         //
548 //      p->m_txbuf = [NSMutableData dataWithLength:1024];
549 //      [p->m_txbuf retain];
550         p->m_txbuf = nil;
551         
552         return p;
555 - (void) dealloc {
556         [m_rxbuf release];
557         [m_txbuf release];
559         [m_istream release];
560         [m_ostream release];
561         
562         [super dealloc];
566 - (void)connectToAddress:(NSString *) hostname withPort:(int)trgport {
567         m_error = false;
568         
569 //      NSHost *host = [NSHost hostWithName:hostname];
570         NSHost *host = [NSHost hostWithAddress:hostname];
572         [NSStream getStreamsToHost:host port:trgport inputStream:&m_istream outputStream:&m_ostream];
574         [m_istream retain];
575         [m_ostream retain];
576         
577         [m_istream setDelegate:self];
578         [m_ostream setDelegate:self];
579         
580         [m_istream scheduleInRunLoop:[NSRunLoop currentRunLoop]
581             forMode:NSDefaultRunLoopMode];
583         [m_ostream scheduleInRunLoop:[NSRunLoop currentRunLoop]
584             forMode:NSDefaultRunLoopMode];
586         [m_istream open];
587         [m_ostream open];
588         
589         m_remaining_size = 8;
590         m_rx_size = 0;
593 - (void)sendLogin:(NSString *) password {
594         m_login_requested = true;
595         m_login_ok = false;
596         ECLoginPacket *p = [ECLoginPacket loginPacket:password withVersion:@"0.1"];
597         [self sendPacket:p];
600 - (void)sendPacket:(ECPacket *) packet {
601         NSOutputStream *memstream = [NSOutputStream outputStreamToMemory];
602         [memstream open];
603         
604         [packet writeToSocket:memstream];
605         id data = [memstream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
606         
607         m_tx_size = [data length];
608         NSLog(@"[EC] sending packet %d bytes\n", m_tx_size);
609         m_tx_ptr = [m_ostream write:(const uint8_t *)[data bytes] maxLength:[data length]];
610         NSLog(@"[EC] %d bytes sent\n", m_tx_ptr);
611         if ( m_tx_ptr == m_tx_size ) {
612                 m_txbuf = nil;
613         } else {
614                 m_txbuf = (NSData *)data;
615                 [m_txbuf retain];
616         }
617         NSStreamStatus stream_status = [m_ostream streamStatus];
618         switch ( stream_status ) {
619                 case NSStreamStatusNotOpen:
620                 case NSStreamStatusClosed:
621                 case NSStreamStatusError:
622                         NSLog(@"[EC] error in output stream\n");
623                         m_error = true;
624                         break;
625                 default:;
626         }
627 //      NSLog(@"[EC] status in output stream=%d\n", stream_status);
631 - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
632     switch(eventCode) {
633                 case NSStreamEventOpenCompleted:
634                 {
635                         NSLog(@"[EC] open complete\n");
636                         break;
637                 }
638                 case NSStreamEventErrorOccurred:
639                 {
640                         NSError *e = [stream streamError];
641                         NSString *description = [e localizedDescription];
642                         NSLog(@"[EC] socket error [%s]\n", [description UTF8String]);
643                         break;
644                 }
645         case NSStreamEventHasBytesAvailable:
646         {
647                         uint8_t *data_ptr = (uint8_t *)[m_rxbuf mutableBytes];
648                         unsigned int len = [m_rxbuf length];
650             len = [(NSInputStream *)stream read:data_ptr + m_rx_size maxLength:len];
651                         NSLog(@"[EC] receiving %d bytes, %d in total, %d remaining\n", len, m_rx_size, m_remaining_size);
652                         if ( len == 0 ) {
653                                 //
654                                 // Remote side must be closed connection
655                                 //
656                         }
657                         int total_len = len;
658                         int packet_offset = 0;
659                         while ( total_len != 0 ) {
660                                 len = ( m_remaining_size > total_len ) ? total_len : m_remaining_size;
661                                 total_len -= len;
663                                 // are we still waiting for flags and size?
664                                 if ( m_rx_size < 8 ) {
665                                         if ( (m_rx_size + len) >= 8 ) {
666                                                 // got flags and packet size - may proceed
667                                                 //uint32_t flags = *(((uint32_t *)[m_rxbuf mutableBytes]) + 0);
668                                                 uint32_t val32 = *((uint32_t *)(data_ptr + 4 + packet_offset));
670                                                 int delta = 8 - m_rx_size;
672                                                 m_remaining_size = ntohl(val32) - (len - delta);
673                                                 NSLog(@"[EC] rx got flags+size, remaining count %d\n", m_remaining_size);
674                                         } else {
675                                                 m_remaining_size -= len;
676                                         }
677                                 } else {
678                                         m_remaining_size -= len;
679                                 }
680                                 m_rx_size += len;
681                                 if ( m_remaining_size == 0 ) {
682                                         //
683                                         // full packet received, call handler
684                                         //
685                                         uint8_t *packet_start = data_ptr + packet_offset;
686                                         int packet_length = [m_rxbuf length] - packet_offset;
687                                         ECPacket *packet = [ECPacket packetFromBuffer:packet_start withLength:packet_length];
688                                         packet_offset += m_rx_size;
689                                         
690                                         if ( m_login_requested ) {
691                                                 m_login_requested = false;
692                                                 m_login_ok = packet.opcode == EC_OP_AUTH_OK;
693                                                 NSLog(@"[EC] server reply: %@\n", m_login_ok ? @"login OK" : @"login FAILED");
694                                         } else {
695                                                 NSLog(@"[EC] calling delegate\n");
696                                                 if ( [delegate respondsToSelector:@selector(handlePacket:)] ) {
697                                                         [delegate handlePacket: packet];
698                                                 }
699                                         }
700                                         m_remaining_size = 8;
701                                         m_rx_size = 0;
702                                 }
703                         }
704             break;
705         }
706                 
707         case NSStreamEventHasSpaceAvailable:
708                 {
709                         if ( m_txbuf != nil ) {
710                                 int remaining = [m_txbuf length] - m_tx_ptr;
711                                 if ( remaining ) {
712                                         const uint8_t *txdata = ((const uint8_t *)[m_txbuf bytes]) + m_tx_ptr;
713                                         int txcount = [m_ostream write:txdata maxLength:remaining];
714                                         m_tx_ptr += txcount;
715                                 } else {
716                                         [m_txbuf release];
717                                         m_txbuf = nil;
718                                 }
720                         }
721                         break;
722                 }
723         }
726 - (void)setDelegate:(id)val
728     delegate = val;
731 - (id)delegate
733     return delegate;
737 @end