Happy new year!
[macgdbp.git] / Source / NetworkCallbackController.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 "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 ReportError(CFReadStreamCopyError(stream));
124 UnscheduleReadStream();
125 break;
126
127 case kCFStreamEventEndEncountered:
128 UnscheduleReadStream();
129 [connection_ socketDisconnected];
130 break;
131 };
132 }
133
134 void NetworkCallbackController::OnWriteStreamEvent(CFWriteStreamRef stream,
135 CFStreamEventType eventType)
136 {
137 switch (eventType)
138 {
139 case kCFStreamEventCanAcceptBytes:
140 [connection_ sendQueuedWrites];
141 break;
142
143 case kCFStreamEventErrorOccurred:
144 ReportError(CFWriteStreamCopyError(stream));
145 UnscheduleWriteStream();
146 break;
147
148 case kCFStreamEventEndEncountered:
149 UnscheduleReadStream();
150 [connection_ socketDisconnected];
151 break;
152 }
153 }
154
155 void NetworkCallbackController::UnscheduleReadStream()
156 {
157 CFReadStreamUnscheduleFromRunLoop(connection_.readStream, runLoop_, kCFRunLoopCommonModes);
158 CFReadStreamClose(connection_.readStream);
159 CFRelease(connection_.readStream);
160 connection_.readStream = NULL;
161 }
162
163 void NetworkCallbackController::UnscheduleWriteStream()
164 {
165 CFWriteStreamUnscheduleFromRunLoop(connection_.writeStream, runLoop_, kCFRunLoopCommonModes);
166 CFWriteStreamClose(connection_.writeStream);
167 CFRelease(connection_.writeStream);
168 connection_.writeStream = NULL;
169 }
170
171 void NetworkCallbackController::ReportError(CFErrorRef error)
172 {
173 [connection_ errorEncountered:[(NSError*)error description]];
174 CFRelease(error);
175 }