3 * Copyright (c) 2007 - 2011, Blue Static <http://www.bluestatic.org>
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.
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.
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
17 #import "NetworkCallbackController.h"
19 #import "NetworkConnection.h"
20 #import "NetworkConnectionPrivate.h"
22 NetworkCallbackController::NetworkCallbackController(NetworkConnection* connection)
23 : connection_(connection),
24 runLoop_(CFRunLoopGetCurrent())
28 // Static Methods //////////////////////////////////////////////////////////////
30 void NetworkCallbackController::SocketAcceptCallback(CFSocketRef socket,
31 CFSocketCallBackType callbackType,
36 assert(callbackType == kCFSocketAcceptCallBack);
37 static_cast<NetworkCallbackController*>(self)->OnSocketAccept(socket, address, data);
40 void NetworkCallbackController::ReadStreamCallback(CFReadStreamRef stream,
41 CFStreamEventType eventType,
44 static_cast<NetworkCallbackController*>(self)->OnReadStreamEvent(stream, eventType);
47 void NetworkCallbackController::WriteStreamCallback(CFWriteStreamRef stream,
48 CFStreamEventType eventType,
51 static_cast<NetworkCallbackController*>(self)->OnWriteStreamEvent(stream, eventType);
55 // Private Instance Methods ////////////////////////////////////////////////////
57 void NetworkCallbackController::OnSocketAccept(CFSocketRef socket,
61 CFReadStreamRef readStream;
62 CFWriteStreamRef writeStream;
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.
70 // Create struct to register callbacks for the stream.
71 CFStreamClientContext context = { 0 };
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);
85 // Open the stream now that it's scheduled on the run loop.
86 if (!CFReadStreamOpen(readStream)) {
87 ReportError(CFReadStreamCopyError(readStream));
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);
102 // Open the write stream.
103 if (!CFWriteStreamOpen(writeStream)) {
104 ReportError(CFWriteStreamCopyError(writeStream));
108 connection_.readStream = readStream;
109 connection_.writeStream = writeStream;
110 [connection_ socketDidAccept];
113 void NetworkCallbackController::OnReadStreamEvent(CFReadStreamRef stream,
114 CFStreamEventType eventType)
118 case kCFStreamEventHasBytesAvailable:
119 [connection_ readStreamHasData];
122 case kCFStreamEventErrorOccurred:
123 ReportError(CFReadStreamCopyError(stream));
124 UnscheduleReadStream();
127 case kCFStreamEventEndEncountered:
128 UnscheduleReadStream();
129 [connection_ socketDisconnected];
134 void NetworkCallbackController::OnWriteStreamEvent(CFWriteStreamRef stream,
135 CFStreamEventType eventType)
139 case kCFStreamEventCanAcceptBytes:
140 [connection_ sendQueuedWrites];
143 case kCFStreamEventErrorOccurred:
144 ReportError(CFWriteStreamCopyError(stream));
145 UnscheduleWriteStream();
148 case kCFStreamEventEndEncountered:
149 UnscheduleReadStream();
150 [connection_ socketDisconnected];
155 void NetworkCallbackController::UnscheduleReadStream()
157 CFReadStreamUnscheduleFromRunLoop(connection_.readStream, runLoop_, kCFRunLoopCommonModes);
158 CFReadStreamClose(connection_.readStream);
159 CFRelease(connection_.readStream);
160 connection_.readStream = NULL;
163 void NetworkCallbackController::UnscheduleWriteStream()
165 CFWriteStreamUnscheduleFromRunLoop(connection_.writeStream, runLoop_, kCFRunLoopCommonModes);
166 CFWriteStreamClose(connection_.writeStream);
167 CFRelease(connection_.writeStream);
168 connection_.writeStream = NULL;
171 void NetworkCallbackController::ReportError(CFErrorRef error)
173 [connection_ errorEncountered:[(NSError*)error description]];