Line data Source code
1 0 : /*
2 :
3 : OODebugTCPConsoleClient.m
4 :
5 :
6 : Oolite Debug Support
7 :
8 : Copyright (C) 2009-2013 Jens Ayton and contributors
9 :
10 : Permission is hereby granted, free of charge, to any person obtaining a copy
11 : of this software and associated documentation files (the "Software"), to deal
12 : in the Software without restriction, including without limitation the rights
13 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 : copies of the Software, and to permit persons to whom the Software is
15 : furnished to do so, subject to the following conditions:
16 :
17 : The above copyright notice and this permission notice shall be included in all
18 : copies or substantial portions of the Software.
19 :
20 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 : SOFTWARE.
27 :
28 : */
29 :
30 : #ifndef OO_EXCLUDE_DEBUG_SUPPORT
31 :
32 :
33 : #import "OODebugTCPConsoleClient.h"
34 : #import "OODebugTCPConsoleProtocol.h"
35 : #import "OODebugMonitor.h"
36 : #import "OOFunctionAttributes.h"
37 : #import "OOLogging.h"
38 : #include <stdint.h>
39 : #import "NSDictionaryOOExtensions.h"
40 :
41 : #if OOLITE_WINDOWS
42 : #include <winsock2.h>
43 : #else
44 : #include <arpa/inet.h> // For htonl
45 : #endif
46 :
47 : #import "OOCollectionExtractors.h"
48 : #import "OOTCPStreamDecoder.h"
49 :
50 :
51 : #ifdef OO_LOG_DEBUG_PROTOCOL_PACKETS
52 : static void LogSendPacket(NSDictionary *packet);
53 : #else
54 0 : #define LogSendPacket(packet) do {} while (0)
55 : #endif
56 :
57 :
58 : static void DecoderPacket(void *cbInfo, OOALStringRef packetType, OOALDictionaryRef packet);
59 : static void DecoderError(void *cbInfo, OOALStringRef errorDesc);
60 :
61 :
62 0 : OOINLINE BOOL StatusIsSendable(OOTCPClientConnectionStatus status)
63 : {
64 : return status == kOOTCPClientStartedConnectionStage1 || status == kOOTCPClientStartedConnectionStage2 || status == kOOTCPClientConnected;
65 : }
66 :
67 :
68 : @interface OODebugTCPConsoleClient (OOPrivate)
69 :
70 0 : - (void) closeConnection;
71 :
72 0 : - (BOOL) sendBytes:(const void *)bytes count:(size_t)count;
73 0 : - (void) sendDictionary:(NSDictionary *)dictionary;
74 :
75 0 : - (void) sendPacket:(NSString *)packetType
76 : withParameters:(NSDictionary *)parameters;
77 :
78 0 : - (void) sendPacket:(NSString *)packetType
79 : withValue:(id)value
80 : forParameter:(NSString *)paramKey;
81 :
82 0 : - (void) readData;
83 0 : - (void) dispatchPacket:(NSDictionary *)packet ofType:(NSString *)packetType;
84 :
85 0 : - (void) handleApproveConnectionPacket:(NSDictionary *)packet;
86 0 : - (void) handleRejectConnectionPacket:(NSDictionary *)packet;
87 0 : - (void) handleCloseConnectionPacket:(NSDictionary *)packet;
88 0 : - (void) handleNoteConfigurationChangePacket:(NSDictionary *)packet;
89 0 : - (void) handlePerformCommandPacket:(NSDictionary *)packet;
90 0 : - (void) handleRequestConfigurationValuePacket:(NSDictionary *)packet;
91 0 : - (void) handlePingPacket:(NSDictionary *)packet;
92 0 : - (void) handlePongPacket:(NSDictionary *)packet;
93 :
94 0 : - (void) disconnectFromServerWithMessage:(NSString *)message;
95 0 : - (void) breakConnectionWithMessage:(NSString *)message;
96 0 : - (void) breakConnectionWithBadStream:(NSStream *)stream;
97 :
98 : @end
99 :
100 :
101 : @implementation OODebugTCPConsoleClient
102 :
103 0 : - (id) init
104 : {
105 : return [self initWithAddress:nil port:0];
106 : }
107 :
108 :
109 : - (id) initWithAddress:(NSString *)address port:(uint16_t)port
110 : {
111 : BOOL OK = NO;
112 : NSDictionary *parameters = nil;
113 :
114 : if (address == nil) address = @"127.0.0.1";
115 : if (port == 0) port = kOOTCPConsolePort;
116 :
117 : self = [super init];
118 : if (self != nil)
119 : {
120 : _host = [NSHost hostWithName:address];
121 : if (_host != nil)
122 : {
123 : [_host retain];
124 : [NSStream getStreamsToHost:_host
125 : port:port
126 : inputStream:&_inStream
127 : outputStream:&_outStream];
128 : }
129 :
130 : if (_inStream != nil && _outStream != nil)
131 : {
132 : [_inStream retain];
133 : [_outStream retain];
134 : [_inStream setDelegate:self];
135 : [_outStream setDelegate:self];
136 : [_inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
137 : [_outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
138 : [_inStream open];
139 : [_outStream open];
140 :
141 : // Need to wait for the streams to reach open status before we can send packets
142 : // TODO: Might be neater to use the handleEvent callback to flag this.. - Micha 20090425
143 : NSRunLoop * myRunLoop = [NSRunLoop currentRunLoop];
144 : NSDate * timeOut = [NSDate dateWithTimeIntervalSinceNow:3]; // Wait up to 3 seconds
145 : while( _host != nil && ([_inStream streamStatus] < 2 || [_outStream streamStatus] < 2) &&
146 : [myRunLoop runMode:NSDefaultRunLoopMode beforeDate:timeOut] )
147 : ; // Wait
148 :
149 : _decoder = OOTCPStreamDecoderCreate(DecoderPacket, DecoderError, NULL, self);
150 : }
151 :
152 : if (_decoder != NULL)
153 : {
154 : OK = YES;
155 : _status = kOOTCPClientStartedConnectionStage1;
156 :
157 :
158 : // Attempt to connect
159 : parameters = [NSDictionary dictionaryWithObjectsAndKeys:
160 : [NSNumber numberWithUnsignedInt:kOOTCPProtocolVersion_1_1_0], kOOTCPProtocolVersion,
161 : [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"], kOOTCPOoliteVersion,
162 : nil];
163 : [self sendPacket:kOOTCPPacket_RequestConnection
164 : withParameters:parameters];
165 :
166 : if (_status == kOOTCPClientStartedConnectionStage1) _status = kOOTCPClientStartedConnectionStage2;
167 : else OK = NO; // Connection failed.
168 : }
169 :
170 : if (!OK)
171 : {
172 : OOLog(@"debugTCP.connect.failed", @"Failed to connect to debug console at address %@:%i.", address, port);
173 : [self release];
174 : self = nil;
175 : }
176 : }
177 :
178 : return self;
179 : }
180 :
181 :
182 0 : - (void) dealloc
183 : {
184 : if (StatusIsSendable(_status))
185 : {
186 : [self disconnectFromServerWithMessage:@"TCP console bridge unexpectedly released while active."];
187 : }
188 : if (_monitor)
189 : {
190 : [_monitor disconnectDebugger:self message:@"TCP console bridge unexpectedly released while active."];
191 : }
192 :
193 :
194 : [self closeConnection];
195 :
196 : OOTCPStreamDecoderDestroy(_decoder);
197 : _decoder = NULL;
198 :
199 : [super dealloc];
200 : }
201 :
202 :
203 0 : - (BOOL)connectDebugMonitor:(in OODebugMonitor *)debugMonitor
204 : errorMessage:(out NSString **)message
205 : {
206 : if (_status == kOOTCPClientConnectionRefused)
207 : {
208 : if (message != NULL) *message = @"Connection refused.";
209 : return NO;
210 : }
211 : if (_status == kOOTCPClientDisconnected)
212 : {
213 : if (message != NULL) *message = @"Cannot reconnect after disconnecting.";
214 : return NO;
215 : }
216 :
217 : _monitor = debugMonitor;
218 :
219 : return YES;
220 : }
221 :
222 :
223 0 : - (void)disconnectDebugMonitor:(in OODebugMonitor *)debugMonitor
224 : message:(in NSString *)message
225 : {
226 : [self disconnectFromServerWithMessage:message];
227 : _monitor = nil;
228 : }
229 :
230 :
231 0 : - (oneway void)debugMonitor:(in OODebugMonitor *)debugMonitor
232 : jsConsoleOutput:(in NSString *)output
233 : colorKey:(in NSString *)colorKey
234 : emphasisRange:(in NSRange)emphasisRange
235 : {
236 : NSMutableDictionary *parameters = nil;
237 : NSArray *range = nil;
238 :
239 : parameters = [NSMutableDictionary dictionaryWithCapacity:3];
240 : [parameters setObject:output forKey:kOOTCPMessage];
241 : [parameters setObject:colorKey ? colorKey : (NSString *)@"general" forKey:kOOTCPColorKey];
242 : if (emphasisRange.length != 0)
243 : {
244 : range = [NSArray arrayWithObjects:
245 : [NSNumber numberWithUnsignedInteger:emphasisRange.location],
246 : [NSNumber numberWithUnsignedInteger:emphasisRange.length],
247 : nil];
248 : [parameters setObject:range forKey:kOOTCPEmphasisRanges];
249 : }
250 :
251 : [self sendPacket:kOOTCPPacket_ConsoleOutput
252 : withParameters:parameters];
253 : }
254 :
255 :
256 0 : - (oneway void)debugMonitorClearConsole:(in OODebugMonitor *)debugMonitor
257 : {
258 : [self sendPacket:kOOTCPPacket_ClearConsole
259 : withParameters:nil];
260 : }
261 :
262 :
263 0 : - (oneway void)debugMonitorShowConsole:(in OODebugMonitor *)debugMonitor
264 : {
265 : [self sendPacket:kOOTCPPacket_ShowConsole
266 : withParameters:nil];
267 : }
268 :
269 :
270 0 : - (oneway void)debugMonitor:(in OODebugMonitor *)debugMonitor
271 : noteConfiguration:(in NSDictionary *)configuration
272 : {
273 : [self sendPacket:kOOTCPPacket_NoteConfiguration
274 : withValue:configuration
275 : forParameter:kOOTCPConfiguration];
276 : }
277 :
278 :
279 0 : - (oneway void)debugMonitor:(in OODebugMonitor *)debugMonitor
280 : noteChangedConfigrationValue:(in id)newValue
281 : forKey:(in NSString *)key
282 : {
283 : if (newValue != nil)
284 : {
285 : [self sendPacket:kOOTCPPacket_NoteConfiguration
286 : withValue:[NSDictionary dictionaryWithObject:newValue forKey:key]
287 : forParameter:kOOTCPConfiguration];
288 : }
289 : else
290 : {
291 : [self sendPacket:kOOTCPPacket_NoteConfiguration
292 : withValue:[NSArray arrayWithObject:key]
293 : forParameter:kOOTCPRemovedConfigurationKeys];
294 : }
295 : }
296 :
297 :
298 0 : - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
299 : {
300 : if (_status > kOOTCPClientConnected) return;
301 :
302 : if (stream == _inStream && eventCode == NSStreamEventHasBytesAvailable)
303 : {
304 : [self readData];
305 : }
306 : else if (eventCode == NSStreamEventErrorOccurred)
307 : {
308 : [self breakConnectionWithBadStream:stream];
309 : }
310 : else if (eventCode == NSStreamEventErrorOccurred)
311 : {
312 : [self breakConnectionWithMessage:[NSString stringWithFormat:
313 : @"Console closed the connection."]];
314 : }
315 : }
316 :
317 : @end
318 :
319 :
320 : @implementation OODebugTCPConsoleClient (OOPrivate)
321 :
322 : - (void) closeConnection
323 : {
324 : [_inStream close];
325 : [_inStream setDelegate:nil];
326 : [_inStream release];
327 : _inStream = nil;
328 :
329 : [_outStream close];
330 : [_outStream setDelegate:nil];
331 : [_outStream release];
332 : _outStream = nil;
333 :
334 : [_host release];
335 : _host = nil;
336 : }
337 :
338 :
339 : - (BOOL) sendBytes:(const void *)bytes count:(size_t)count
340 : {
341 : if (bytes == NULL || count == 0) return YES;
342 : if (!StatusIsSendable(_status) || _outStream == nil) return NO;
343 :
344 : do
345 : {
346 : NSInteger written = [_outStream write:bytes maxLength:count];
347 : if (written < 1) return NO;
348 :
349 : count -= written;
350 : bytes += written;
351 : }
352 : while (count > 0);
353 :
354 : return YES;
355 : }
356 :
357 :
358 : - (void) sendDictionary:(NSDictionary *)dictionary
359 : {
360 : NSData *data = nil;
361 : NSString *errorDesc = NULL;
362 : size_t count;
363 : const uint8_t *bytes = NULL;
364 : uint32_t header;
365 : bool sentOK = YES;
366 :
367 : if (dictionary == nil || !StatusIsSendable(_status)) return;
368 :
369 : data = [NSPropertyListSerialization dataFromPropertyList:dictionary
370 : format:NSPropertyListXMLFormat_v1_0
371 : errorDescription:&errorDesc];
372 :
373 : if (data == nil)
374 : {
375 : OOLog(@"debugTCP.conversionFailure", @"Could not convert dictionary to data for transmission to debug console: %@", errorDesc != NULL ? errorDesc : (NSString *)@"unknown error.");
376 : #if OOLITE_RELEASE_PLIST_ERROR_STRINGS
377 : [errorDesc autorelease];
378 : #endif
379 : return;
380 : }
381 :
382 : LogSendPacket(dictionary);
383 :
384 : count = [data length];
385 : if (count == 0) return;
386 : header = htonl(count);
387 :
388 : bytes = [data bytes];
389 :
390 : /* In testing, all bad stream errors were caused by the python console
391 : rejecting headers. Made the protocol a bit more fault tolerant.
392 : -- Kaks 2012.03.24
393 : */
394 : if (![self sendBytes:&header count:sizeof header])
395 : {
396 : OOLog(@"debugTCP.send.warning", @"%@", @"Error sending packet header, retrying.");
397 : // wait 8 milliseconds, resend the header
398 : [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.008]];
399 : if (![self sendBytes:&header count:sizeof header])
400 : {
401 : //OOLog(@"debugTCP.send.warning", @"Error sending packet header, retrying one more time.");
402 : // wait 16 milliseconds, try to resend the header one last time!
403 : [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.016]];
404 : if (![self sendBytes:&header count:sizeof header])
405 : {
406 : sentOK = NO;
407 : }
408 : }
409 : }
410 :
411 : if(sentOK && ![self sendBytes:bytes count:count])
412 : {
413 : OOLog(@"debugTCP.send.warning", @"%@", @"Error sending packet body, retrying.");
414 : // wait 8 milliseconds, try again.
415 : [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.008]];
416 : if(![self sendBytes:bytes count:count])
417 : {
418 : sentOK = NO;
419 : }
420 : }
421 :
422 : if (!sentOK)
423 : {
424 : OOLog(@"debugTCP.send.error", @"The following packet could not be sent: %@", dictionary);
425 : if(![[OODebugMonitor sharedDebugMonitor] TCPIgnoresDroppedPackets])
426 : {
427 : [self breakConnectionWithBadStream:_outStream];
428 : }
429 : }
430 : }
431 :
432 :
433 : - (void) sendPacket:(NSString *)packetType
434 : withParameters:(NSDictionary *)parameters
435 : {
436 : NSDictionary *dict = nil;
437 :
438 : if (packetType == nil) return;
439 :
440 : if (parameters != nil)
441 : {
442 : dict = [parameters dictionaryByAddingObject:packetType forKey:kOOTCPPacketType];
443 : }
444 : else
445 : {
446 : dict = [NSDictionary dictionaryWithObjectsAndKeys:packetType, kOOTCPPacketType, nil];
447 : }
448 :
449 : [self sendDictionary:dict];
450 : }
451 :
452 :
453 : - (void) sendPacket:(NSString *)packetType
454 : withValue:(id)value
455 : forParameter:(NSString *)paramKey
456 : {
457 : if (packetType == nil) return;
458 : if (paramKey == nil) value = nil;
459 :
460 : [self sendDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
461 : packetType, kOOTCPPacketType,
462 : value, paramKey,
463 : nil]];
464 : }
465 :
466 :
467 : - (void) readData
468 : {
469 : enum { kBufferSize = 16 << 10 };
470 :
471 : uint8_t buffer[kBufferSize];
472 : NSInteger length;
473 : NSData *data;
474 :
475 : length = [_inStream read:buffer maxLength:kBufferSize];
476 : while (length > 0)
477 : {
478 : data = [NSData dataWithBytesNoCopy:buffer length:length freeWhenDone:NO];
479 : OOTCPStreamDecoderReceiveData(_decoder, data);
480 : length = [_inStream read:buffer maxLength:kBufferSize];
481 : }
482 : }
483 :
484 :
485 : - (void) dispatchPacket:(NSDictionary *)packet ofType:(NSString *)packetType
486 : {
487 : if (packet == nil || packetType == nil) return;
488 :
489 0 : #define PACKET_CASE(x) else if ([packetType isEqualToString:kOOTCPPacket_##x]) { [self handle##x##Packet:packet]; }
490 :
491 : if (0) {}
492 : PACKET_CASE(ApproveConnection)
493 : PACKET_CASE(RejectConnection)
494 : PACKET_CASE(CloseConnection)
495 : PACKET_CASE(NoteConfigurationChange)
496 : PACKET_CASE(PerformCommand)
497 : PACKET_CASE(RequestConfigurationValue)
498 : PACKET_CASE(Ping)
499 : PACKET_CASE(Pong)
500 : else
501 : {
502 : OOLog(@"debugTCP.protocolError.unknownPacketType", @"Unhandled packet type %@.", packetType);
503 : }
504 : }
505 :
506 :
507 : - (void) handleApproveConnectionPacket:(NSDictionary *)packet
508 : {
509 : NSMutableString *connectedMessage = nil;
510 : NSString *consoleIdentity = nil;
511 : NSString *hostName = nil;
512 :
513 : if (_status == kOOTCPClientStartedConnectionStage2)
514 : {
515 : _status = kOOTCPClientConnected;
516 :
517 : // Build "Connected..." message with two optional parts, console identity and host name.
518 : connectedMessage = [NSMutableString stringWithString:@"Connected to debug console"];
519 :
520 : consoleIdentity = [packet oo_stringForKey:kOOTCPConsoleIdentity];
521 : if (consoleIdentity != nil) [connectedMessage appendFormat:@" \"%@\"", consoleIdentity];
522 :
523 : hostName = [_host name];
524 : if ([hostName length] != 0 &&
525 : ![hostName isEqual:@"localhost"] &&
526 : ![hostName isEqual:@"127.0.0.1"] &&
527 : ![hostName isEqual:@"::1"])
528 : {
529 : [connectedMessage appendFormat:@" at %@", hostName];
530 : }
531 :
532 : OOLog(@"debugTCP.connected", @"%@.", connectedMessage);
533 : }
534 : else
535 : {
536 : OOLog(@"debugTCP.protocolError.outOfOrder", @"Got %@ packet from debug console in wrong context.", kOOTCPPacket_ApproveConnection);
537 : }
538 : }
539 :
540 :
541 : - (void) handleRejectConnectionPacket:(NSDictionary *)packet
542 : {
543 : NSString *message = nil;
544 :
545 : if (_status == kOOTCPClientStartedConnectionStage2)
546 : {
547 : _status = kOOTCPClientConnectionRefused;
548 : }
549 : else
550 : {
551 : OOLog(@"debugTCP.protocolError.outOfOrder", @"Got %@ packet from debug console in wrong context.", kOOTCPPacket_RejectConnection);
552 : }
553 :
554 : message = [packet oo_stringForKey:kOOTCPMessage];
555 : if (message == nil) message = @"Console refused connection.";
556 : [self breakConnectionWithMessage:message];
557 : }
558 :
559 :
560 : - (void) handleCloseConnectionPacket:(NSDictionary *)packet
561 : {
562 : NSString *message = nil;
563 :
564 : if (!StatusIsSendable(_status))
565 : {
566 : OOLog(@"debugTCP.protocolError.outOfOrder", @"Got %@ packet from debug console in wrong context.", kOOTCPPacket_CloseConnection);
567 : }
568 : message = [packet oo_stringForKey:kOOTCPMessage];
569 : if (message == nil) message = @"Console closed connection.";
570 : [self breakConnectionWithMessage:message];
571 : }
572 :
573 :
574 : - (void) handleNoteConfigurationChangePacket:(NSDictionary *)packet
575 : {
576 : NSDictionary *configuration = nil;
577 : NSArray *removed = nil;
578 : NSEnumerator *keyEnum = nil;
579 : NSString *key = nil;
580 : id value = nil;
581 :
582 : if (_monitor == nil) return;
583 :
584 : configuration = [packet oo_dictionaryForKey:kOOTCPConfiguration];
585 : if (configuration != nil)
586 : {
587 : for (keyEnum = [configuration keyEnumerator]; (key = [keyEnum nextObject]); )
588 : {
589 : value = [configuration objectForKey:key];
590 : [_monitor setConfigurationValue:value forKey:key];
591 : }
592 : }
593 :
594 : removed = [configuration oo_arrayForKey:kOOTCPRemovedConfigurationKeys];
595 : for (keyEnum = [removed objectEnumerator]; (key = [keyEnum nextObject]); )
596 : {
597 : [_monitor setConfigurationValue:nil forKey:key];
598 : }
599 : }
600 :
601 :
602 : - (void) handlePerformCommandPacket:(NSDictionary *)packet
603 : {
604 : NSString *message = nil;
605 :
606 : message = [packet oo_stringForKey:kOOTCPMessage];
607 : if (message != nil) [_monitor performJSConsoleCommand:message];
608 : }
609 :
610 :
611 : - (void) handleRequestConfigurationValuePacket:(NSDictionary *)packet
612 : {
613 : NSString *key = nil;
614 : id value = nil;
615 :
616 : key = [packet oo_stringForKey:kOOTCPConfigurationKey];
617 : if (key != nil)
618 : {
619 : value = [_monitor configurationValueForKey:key];
620 : [self debugMonitor:_monitor
621 : noteChangedConfigrationValue:value
622 : forKey:key];
623 : }
624 : }
625 :
626 :
627 : - (void) handlePingPacket:(NSDictionary *)packet
628 : {
629 : id message = nil;
630 :
631 : message = [packet objectForKey:kOOTCPMessage];
632 : [self sendPacket:kOOTCPPacket_Pong
633 : withValue:message
634 : forParameter:kOOTCPMessage];
635 : }
636 :
637 :
638 : - (void) handlePongPacket:(NSDictionary *)packet
639 : {
640 : // Do nothing; we don't currently send pings.
641 : }
642 :
643 :
644 : - (void) disconnectFromServerWithMessage:(NSString *)message
645 : {
646 : if (StatusIsSendable(_status))
647 : {
648 : [self sendPacket:kOOTCPPacket_CloseConnection
649 : withValue:message
650 : forParameter:kOOTCPMessage];
651 : }
652 : [self closeConnection];
653 :
654 : _status = kOOTCPClientDisconnected;
655 : }
656 :
657 :
658 : - (void) breakConnectionWithMessage:(NSString *)message
659 : {
660 : [self closeConnection];
661 :
662 : if (_status != kOOTCPClientConnectionRefused) _status = kOOTCPClientDisconnected;
663 :
664 : if ([message length] > 0)
665 : {
666 : OOLog(@"debugTCP.disconnect", @"No connection to debug console: \"%@\"", message);
667 : }
668 : else
669 : {
670 : OOLog(@"debugTCP.disconnect", @"%@", @"Debug console not connected.");
671 : }
672 :
673 : #if 0
674 : // Disconnecting causes crashiness for reasons I don't understand, and isn't very important anyway.
675 : [_monitor disconnectDebugger:self message:message];
676 : _monitor = nil;
677 : #endif
678 : }
679 :
680 :
681 : - (void) breakConnectionWithBadStream:(NSStream *)stream
682 : {
683 : NSString *errorDesc = nil;
684 : NSError *error = nil;
685 :
686 : error = [stream streamError];
687 : errorDesc = [error localizedDescription];
688 : if (errorDesc == nil) errorDesc = [error description];
689 : if (errorDesc == nil) errorDesc = @"bad stream.";
690 : [self breakConnectionWithMessage:[NSString stringWithFormat:
691 : @"Connection to debug console failed: '%@' (outStream status: %li, inStream status: %li).",
692 : errorDesc, [_outStream streamStatus], [_inStream streamStatus]]];
693 : }
694 :
695 : @end
696 :
697 :
698 0 : static void DecoderPacket(void *cbInfo, OOALStringRef packetType, OOALDictionaryRef packet)
699 : {
700 : [(OODebugTCPConsoleClient *)cbInfo dispatchPacket:packet ofType:packetType];
701 : }
702 :
703 :
704 0 : static void DecoderError(void *cbInfo, OOALStringRef errorDesc)
705 : {
706 : [(OODebugTCPConsoleClient *)cbInfo breakConnectionWithMessage:errorDesc];
707 : }
708 :
709 :
710 : #ifdef OO_LOG_DEBUG_PROTOCOL_PACKETS
711 : void LogOOTCPStreamDecoderPacket(NSDictionary *packet)
712 : {
713 : NSData *data = nil;
714 : NSString *xml = nil;
715 :
716 : data = [NSPropertyListSerialization dataFromPropertyList:packet format:NSPropertyListXMLFormat_v1_0 errorDescription:NULL];
717 : xml = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
718 : OOLog(@"debugTCP.receive", @"Received packet:\n%@", xml);
719 : }
720 :
721 :
722 : static void LogSendPacket(NSDictionary *packet)
723 : {
724 : NSData *data = nil;
725 : NSString *xml = nil;
726 :
727 : data = [NSPropertyListSerialization dataFromPropertyList:packet format:NSPropertyListXMLFormat_v1_0 errorDescription:NULL];
728 : xml = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
729 : OOLog(@"debugTCP.send", @"Sent packet:\n%@", xml);
730 : }
731 : #endif
732 :
733 : #endif /* OO_EXCLUDE_DEBUG_SUPPORT */
|