]> src.bluestatic.org Git - macgdbp.git/blob - Source/NetworkConnection.mm
Fix use-after-free by not removing the dequeued message until after it is sent.
[macgdbp.git] / Source / NetworkConnection.mm
1 /*
2 * MacGDBp
3 * Copyright (c) 2007 - 2011, Blue Static <http://www.bluestatic.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17 #import "NetworkConnection.h"
18
19 #import "AppDelegate.h"
20 #import "LoggingController.h"
21
22 // This is the private interface for the NetworkConnection class. This is shared
23 // by the C++ NetworkCallbackController to communicate.
24 @interface NetworkConnection (Private)
25
26 - (void)handleResponse:(NSXMLDocument*)response;
27
28 // Threadsafe wrappers for the delegate's methods.
29 - (void)errorEncountered:(NSString*)error;
30 - (LogEntry*)recordSend:(NSString*)command;
31 - (LogEntry*)recordReceive:(NSString*)command;
32
33 @end
34
35
36 ////////////////////////////////////////////////////////////////////////////////
37
38 @implementation NetworkConnection
39
40 @synthesize port = port_;
41 @synthesize connected = connected_;
42 @synthesize delegate = delegate_;
43
44 - (id)initWithPort:(NSUInteger)aPort
45 {
46 if (self = [super initWithDelegate:self]) {
47 port_ = aPort;
48 _ideClient = self;
49 }
50 return self;
51 }
52
53 /**
54 * Kicks off the socket on another thread.
55 */
56 - (void)connect
57 {
58 [_ideClient connectOnPort:port_];
59 }
60
61 - (void)close
62 {
63 [_ideClient disconnect];
64 }
65
66 - (void)debuggerEngineConnected:(ProtocolClient*)client
67 {
68 if ([delegate_ respondsToSelector:@selector(connectionDidAccept:)])
69 [delegate_ connectionDidAccept:self];
70 }
71
72 - (void)debuggerEngineDisconnected:(ProtocolClient*)client
73 {
74 if ([delegate_ respondsToSelector:@selector(connectionDidClose:)])
75 [delegate_ connectionDidClose:self];
76 }
77
78 - (void)debuggerEngine:(ProtocolClient*)client receivedMessage:(NSXMLDocument*)message
79 {
80 [self handleResponse:message];
81 }
82
83 - (void)dealloc
84 {
85 [_ideClient release];
86 [super dealloc];
87 }
88
89 /**
90 * Given a file path, this returns a file:// URI and escapes any spaces for the
91 * debugger engine.
92 */
93 - (NSString*)escapedURIPath:(NSString*)path
94 {
95 // Custon GDBp paths are fine.
96 if ([[path substringToIndex:4] isEqualToString:@"gdbp"])
97 return path;
98
99 // Create a temporary URL that will escape all the nasty characters.
100 NSURL* url = [NSURL fileURLWithPath:path];
101 NSString* urlString = [url absoluteString];
102
103 // Remove the host because this is a file:// URL;
104 urlString = [urlString stringByReplacingOccurrencesOfString:[url host] withString:@""];
105
106 // Escape % for use in printf-style NSString formatters.
107 urlString = [urlString stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
108 return urlString;
109 }
110
111 // Private /////////////////////////////////////////////////////////////////////
112 #pragma mark Private
113
114 // Delegate Thread-Safe Wrappers ///////////////////////////////////////////////
115
116 /**
117 * Receives errors from the SocketWrapper and updates the display
118 */
119 - (void)errorEncountered:(NSString*)error
120 {
121 if (![delegate_ respondsToSelector:@selector(errorEncountered:)])
122 return;
123 [delegate_ performSelectorOnMainThread:@selector(errorEncountered:)
124 withObject:error
125 waitUntilDone:NO];
126 }
127
128 - (LogEntry*)recordSend:(NSString*)command
129 {
130 LoggingController* logger = [[AppDelegate instance] loggingController];
131 LogEntry* entry = [LogEntry newSendEntry:command];
132 entry.lastReadTransactionID = _lastReadID;
133 entry.lastWrittenTransactionID = _lastWrittenID;
134 [logger performSelectorOnMainThread:@selector(recordEntry:)
135 withObject:entry
136 waitUntilDone:NO];
137 return [entry autorelease];
138 }
139
140 - (LogEntry*)recordReceive:(NSString*)command
141 {
142 LoggingController* logger = [[AppDelegate instance] loggingController];
143 LogEntry* entry = [LogEntry newReceiveEntry:command];
144 entry.lastReadTransactionID = _lastReadID;
145 entry.lastWrittenTransactionID = _lastWrittenID;
146 [logger performSelectorOnMainThread:@selector(recordEntry:)
147 withObject:entry
148 waitUntilDone:NO];
149 return [entry autorelease];
150 }
151
152 - (void)handleResponse:(NSXMLDocument*)response
153 {
154 // Check and see if there's an error.
155 NSArray* error = [[response rootElement] elementsForName:@"error"];
156 if ([error count] > 0) {
157 NSLog(@"Xdebug error: %@", error);
158 NSString* errorMessage = [[[[error objectAtIndex:0] children] objectAtIndex:0] stringValue];
159 [self errorEncountered:errorMessage];
160 }
161
162 if ([[[response rootElement] name] isEqualToString:@"init"]) {
163 connected_ = YES;
164 [delegate_ handleInitialResponse:response];
165 return;
166 }
167
168 if ([delegate_ respondsToSelector:@selector(handleResponse:)])
169 [delegate_ handleResponse:response];
170 }
171
172 @end