OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2007 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 | |
12 #include "webrtc/base/macsocketserver.h" | |
13 | |
14 #include "webrtc/base/common.h" | |
15 #include "webrtc/base/logging.h" | |
16 #include "webrtc/base/macasyncsocket.h" | |
17 #include "webrtc/base/macutils.h" | |
18 #include "webrtc/base/thread.h" | |
19 | |
20 namespace rtc { | |
21 | |
22 /////////////////////////////////////////////////////////////////////////////// | |
23 // MacBaseSocketServer | |
24 /////////////////////////////////////////////////////////////////////////////// | |
25 | |
26 MacBaseSocketServer::MacBaseSocketServer() { | |
27 } | |
28 | |
29 MacBaseSocketServer::~MacBaseSocketServer() { | |
30 } | |
31 | |
32 Socket* MacBaseSocketServer::CreateSocket(int type) { | |
33 return NULL; | |
34 } | |
35 | |
36 Socket* MacBaseSocketServer::CreateSocket(int family, int type) { | |
37 return NULL; | |
38 } | |
39 | |
40 AsyncSocket* MacBaseSocketServer::CreateAsyncSocket(int type) { | |
41 return CreateAsyncSocket(AF_INET, type); | |
42 } | |
43 | |
44 AsyncSocket* MacBaseSocketServer::CreateAsyncSocket(int family, int type) { | |
45 if (SOCK_STREAM != type) | |
46 return NULL; | |
47 | |
48 MacAsyncSocket* socket = new MacAsyncSocket(this, family); | |
49 if (!socket->valid()) { | |
50 delete socket; | |
51 return NULL; | |
52 } | |
53 return socket; | |
54 } | |
55 | |
56 void MacBaseSocketServer::RegisterSocket(MacAsyncSocket* s) { | |
57 sockets_.insert(s); | |
58 } | |
59 | |
60 void MacBaseSocketServer::UnregisterSocket(MacAsyncSocket* s) { | |
61 VERIFY(1 == sockets_.erase(s)); // found 1 | |
62 } | |
63 | |
64 bool MacBaseSocketServer::SetPosixSignalHandler(int signum, | |
65 void (*handler)(int)) { | |
66 Dispatcher* dispatcher = signal_dispatcher(); | |
67 if (!PhysicalSocketServer::SetPosixSignalHandler(signum, handler)) { | |
68 return false; | |
69 } | |
70 | |
71 // Only register the FD once, when the first custom handler is installed. | |
72 if (!dispatcher && (dispatcher = signal_dispatcher())) { | |
73 CFFileDescriptorContext ctx = { 0 }; | |
74 ctx.info = this; | |
75 | |
76 CFFileDescriptorRef desc = CFFileDescriptorCreate( | |
77 kCFAllocatorDefault, | |
78 dispatcher->GetDescriptor(), | |
79 false, | |
80 &MacBaseSocketServer::FileDescriptorCallback, | |
81 &ctx); | |
82 if (!desc) { | |
83 return false; | |
84 } | |
85 | |
86 CFFileDescriptorEnableCallBacks(desc, kCFFileDescriptorReadCallBack); | |
87 CFRunLoopSourceRef ref = | |
88 CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, desc, 0); | |
89 | |
90 if (!ref) { | |
91 CFRelease(desc); | |
92 return false; | |
93 } | |
94 | |
95 CFRunLoopAddSource(CFRunLoopGetCurrent(), ref, kCFRunLoopCommonModes); | |
96 CFRelease(desc); | |
97 CFRelease(ref); | |
98 } | |
99 | |
100 return true; | |
101 } | |
102 | |
103 // Used to disable socket events from waking our message queue when | |
104 // process_io is false. Does not disable signal event handling though. | |
105 void MacBaseSocketServer::EnableSocketCallbacks(bool enable) { | |
106 for (std::set<MacAsyncSocket*>::iterator it = sockets().begin(); | |
107 it != sockets().end(); ++it) { | |
108 if (enable) { | |
109 (*it)->EnableCallbacks(); | |
110 } else { | |
111 (*it)->DisableCallbacks(); | |
112 } | |
113 } | |
114 } | |
115 | |
116 void MacBaseSocketServer::FileDescriptorCallback(CFFileDescriptorRef fd, | |
117 CFOptionFlags flags, | |
118 void* context) { | |
119 MacBaseSocketServer* this_ss = | |
120 reinterpret_cast<MacBaseSocketServer*>(context); | |
121 ASSERT(this_ss); | |
122 Dispatcher* signal_dispatcher = this_ss->signal_dispatcher(); | |
123 ASSERT(signal_dispatcher); | |
124 | |
125 signal_dispatcher->OnPreEvent(DE_READ); | |
126 signal_dispatcher->OnEvent(DE_READ, 0); | |
127 CFFileDescriptorEnableCallBacks(fd, kCFFileDescriptorReadCallBack); | |
128 } | |
129 | |
130 | |
131 /////////////////////////////////////////////////////////////////////////////// | |
132 // MacCFSocketServer | |
133 /////////////////////////////////////////////////////////////////////////////// | |
134 | |
135 void WakeUpCallback(void* info) { | |
136 MacCFSocketServer* server = static_cast<MacCFSocketServer*>(info); | |
137 ASSERT(NULL != server); | |
138 server->OnWakeUpCallback(); | |
139 } | |
140 | |
141 MacCFSocketServer::MacCFSocketServer() | |
142 : run_loop_(CFRunLoopGetCurrent()), | |
143 wake_up_(NULL) { | |
144 CFRunLoopSourceContext ctx; | |
145 memset(&ctx, 0, sizeof(ctx)); | |
146 ctx.info = this; | |
147 ctx.perform = &WakeUpCallback; | |
148 wake_up_ = CFRunLoopSourceCreate(NULL, 0, &ctx); | |
149 ASSERT(NULL != wake_up_); | |
150 if (wake_up_) { | |
151 CFRunLoopAddSource(run_loop_, wake_up_, kCFRunLoopCommonModes); | |
152 } | |
153 } | |
154 | |
155 MacCFSocketServer::~MacCFSocketServer() { | |
156 if (wake_up_) { | |
157 CFRunLoopSourceInvalidate(wake_up_); | |
158 CFRelease(wake_up_); | |
159 } | |
160 } | |
161 | |
162 bool MacCFSocketServer::Wait(int cms, bool process_io) { | |
163 ASSERT(CFRunLoopGetCurrent() == run_loop_); | |
164 | |
165 if (!process_io && cms == 0) { | |
166 // No op. | |
167 return true; | |
168 } | |
169 | |
170 if (!process_io) { | |
171 // No way to listen to common modes and not get socket events, unless | |
172 // we disable each one's callbacks. | |
173 EnableSocketCallbacks(false); | |
174 } | |
175 | |
176 SInt32 result; | |
177 if (kForever == cms) { | |
178 do { | |
179 // Would prefer to run in a custom mode that only listens to wake_up, | |
180 // but we have qtkit sending work to the main thread which is effectively | |
181 // blocked here, causing deadlock. Thus listen to the common modes. | |
182 // TODO: If QTKit becomes thread safe, do the above. | |
183 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10000000, false); | |
184 } while (result != kCFRunLoopRunFinished && result != kCFRunLoopRunStopped); | |
185 } else { | |
186 // TODO: In the case of 0ms wait, this will only process one event, so we | |
187 // may want to loop until it returns TimedOut. | |
188 CFTimeInterval seconds = cms / 1000.0; | |
189 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, false); | |
190 } | |
191 | |
192 if (!process_io) { | |
193 // Reenable them. Hopefully this won't cause spurious callbacks or | |
194 // missing ones while they were disabled. | |
195 EnableSocketCallbacks(true); | |
196 } | |
197 | |
198 if (kCFRunLoopRunFinished == result) { | |
199 return false; | |
200 } | |
201 return true; | |
202 } | |
203 | |
204 void MacCFSocketServer::WakeUp() { | |
205 if (wake_up_) { | |
206 CFRunLoopSourceSignal(wake_up_); | |
207 CFRunLoopWakeUp(run_loop_); | |
208 } | |
209 } | |
210 | |
211 void MacCFSocketServer::OnWakeUpCallback() { | |
212 ASSERT(run_loop_ == CFRunLoopGetCurrent()); | |
213 CFRunLoopStop(run_loop_); | |
214 } | |
215 } // namespace rtc | |
OLD | NEW |