Split out the C++ class into its own file. Also move NetworkConnection's private...
[macgdbp.git] / Source / NetworkCallbackController.mm
1 /*
2 * MacGDBp
3 * Copyright (c) 2007 - 2010, 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 "NetworkCallbackController.h"
18
19 #import "NetworkConnection.h"
20 #import "NetworkConnectionPrivate.h"
21
22 NetworkCallbackController::NetworkCallbackController(NetworkConnection* connection)
23 : connection_(connection),
24 runLoop_(CFRunLoopGetCurrent())
25 {
26 }
27
28 // Static Methods //////////////////////////////////////////////////////////////
29
30 void NetworkCallbackController::SocketAcceptCallback(CFSocketRef socket,
31 CFSocketCallBackType callbackType,
32 CFDataRef address,
33 const void* data,
34 void* self)
35 {
36 assert(callbackType == kCFSocketAcceptCallBack);
37 static_cast<NetworkCallbackController*>(self)->OnSocketAccept(socket, address, data);
38 }
39
40 void NetworkCallbackController::ReadStreamCallback(CFReadStreamRef stream,
41 CFStreamEventType eventType,
42 void* self)
43 {
44 static_cast<NetworkCallbackController*>(self)->OnReadStreamEvent(stream, eventType);
45 }
46
47 void NetworkCallbackController::WriteStreamCallback(CFWriteStreamRef stream,
48 CFStreamEventType eventType,
49 void* self)
50 {
51 static_cast<NetworkCallbackController*>(self)->OnWriteStreamEvent(stream, eventType);
52 }
53
54
55 // Private Instance Methods ////////////////////////////////////////////////////
56
57 void NetworkCallbackController::OnSocketAccept(CFSocketRef socket,
58 CFDataRef address,
59 const void* data)
60 {
61 CFReadStreamRef readStream;
62 CFWriteStreamRef writeStream;
63
64 // Create the streams on the socket.
65 CFStreamCreatePairWithSocket(kCFAllocatorDefault,
66 *(CFSocketNativeHandle*)data, // Socket handle.
67 &readStream, // Read stream in-pointer.
68 &writeStream); // Write stream in-pointer.
69
70 // Create struct to register callbacks for the stream.
71 CFStreamClientContext context = { 0 };
72 context.info = this;
73
74 // Set the client of the read stream.
75 CFOptionFlags readFlags = kCFStreamEventOpenCompleted |
76 kCFStreamEventHasBytesAvailable |
77 kCFStreamEventErrorOccurred |
78 kCFStreamEventEndEncountered;
79 if (CFReadStreamSetClient(readStream, readFlags, &NetworkCallbackController::ReadStreamCallback, &context))
80 // Schedule in run loop to do asynchronous communication with the engine.
81 CFReadStreamScheduleWithRunLoop(readStream, runLoop_, kCFRunLoopCommonModes);
82 else
83 return;
84
85 // Open the stream now that it's scheduled on the run loop.
86 if (!CFReadStreamOpen(readStream)) {
87 ReportError(CFReadStreamCopyError(readStream));
88 return;
89 }
90
91 // Set the client of the write stream.
92 CFOptionFlags writeFlags = kCFStreamEventOpenCompleted |
93 kCFStreamEventCanAcceptBytes |
94 kCFStreamEventErrorOccurred |
95 kCFStreamEventEndEncountered;
96 if (CFWriteStreamSetClient(writeStream, writeFlags, &NetworkCallbackController::WriteStreamCallback, &context))
97 // Schedule it in the run loop to receive error information.
98 CFWriteStreamScheduleWithRunLoop(writeStream, runLoop_, kCFRunLoopCommonModes);
99 else
100 return;
101
102 // Open the write stream.
103 if (!CFWriteStreamOpen(writeStream)) {
104 ReportError(CFWriteStreamCopyError(writeStream));
105 return;
106 }
107
108 connection_.readStream = readStream;
109 connection_.writeStream = writeStream;
110 [connection_ socketDidAccept];
111 }
112
113 void NetworkCallbackController::OnReadStreamEvent(CFReadStreamRef stream,
114 CFStreamEventType eventType)
115 {
116 switch (eventType)
117 {
118 case kCFStreamEventHasBytesAvailable:
119 [connection_ readStreamHasData];
120 break;
121
122 case kCFStreamEventErrorOccurred:
123 {
124 ReportError(CFReadStreamCopyError(stream));
125 UnscheduleReadStream();
126 break;
127 }
128
129 case kCFStreamEventEndEncountered:
130 UnscheduleReadStream();
131 [connection_ socketDisconnected];
132 break;
133 };
134 }
135
136 void NetworkCallbackController::OnWriteStreamEvent(CFWriteStreamRef stream,
137 CFStreamEventType eventType)
138 {
139 switch (eventType)
140 {
141 case kCFStreamEventCanAcceptBytes:
142 [connection_ sendQueuedWrites];
143 break;
144
145 case kCFStreamEventErrorOccurred:
146 {
147 ReportError(CFWriteStreamCopyError(stream));
148 UnscheduleWriteStream();
149 break;
150 }
151
152 case kCFStreamEventEndEncountered:
153 UnscheduleReadStream();
154 [connection_ socketDisconnected];
155 break;
156 }
157 }
158
159 void NetworkCallbackController::UnscheduleReadStream()
160 {
161 CFReadStreamUnscheduleFromRunLoop(connection_.readStream, runLoop_, kCFRunLoopCommonModes);
162 CFReadStreamClose(connection_.readStream);
163 CFRelease(connection_.readStream);
164 connection_.readStream = NULL;
165 }
166
167 void NetworkCallbackController::UnscheduleWriteStream()
168 {
169 CFWriteStreamUnscheduleFromRunLoop(connection_.writeStream, runLoop_, kCFRunLoopCommonModes);
170 CFWriteStreamClose(connection_.writeStream);
171 CFRelease(connection_.writeStream);
172 connection_.writeStream = NULL;
173 }
174
175 void NetworkCallbackController::ReportError(CFErrorRef error)
176 {
177 [connection_ errorEncountered:[(NSError*)error description]];
178 CFRelease(error);
179 }