]> git.saurik.com Git - wxWidgets.git/blame - src/osx/core/sockosx.cpp
Forgot header with OSX prefix
[wxWidgets.git] / src / osx / core / sockosx.cpp
CommitLineData
51fe4b60
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: osx/core/gsockosx.cpp
3// Purpose: wxSocketImpl implementation for OS X
4// Authors: Brian Victor, Vadim Zeitlin
5// Created: February 2002
6// RCS-ID: $Id$
7// Copyright: (c) 2002 Brian Victor
8// (c) 2008 Vadim Zeitlin
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
489468fe
SC
11
12#include "wx/wxprec.h"
13
14#if wxUSE_SOCKETS
15
60913641
VZ
16#include "wx/private/socket.h"
17#include "wx/unix/private/sockunix.h"
489468fe
SC
18#include "wx/apptrait.h"
19
20#include <CoreFoundation/CoreFoundation.h>
21
f0fbbe23
VZ
22namespace
23{
24
25// ----------------------------------------------------------------------------
26// global variables
27// ----------------------------------------------------------------------------
28
29// Sockets must use the event loop to monitor the events so we store a
30// reference to the main thread event loop here
31static CFRunLoopRef gs_mainRunLoop = NULL;
32
489468fe 33// ----------------------------------------------------------------------------
51fe4b60 34// Mac-specific socket implementation
489468fe
SC
35// ----------------------------------------------------------------------------
36
51fe4b60 37class wxSocketImplMac : public wxSocketImplUnix
489468fe
SC
38{
39public:
51fe4b60
VZ
40 wxSocketImplMac(wxSocketBase& wxsocket)
41 : wxSocketImplUnix(wxsocket)
489468fe
SC
42 {
43 m_socket = NULL;
44 m_source = NULL;
45 }
46
51fe4b60
VZ
47 virtual ~wxSocketImplMac()
48 {
49 wxASSERT_MSG( !m_source && !m_socket, "forgot to call Close()?" );
50 }
51
52 // get the underlying socket: creates it on demand
53 CFSocketRef GetSocket() /* const */
54 {
55 if ( !m_socket )
56 Initialize();
57
58 return m_socket;
59 }
60
61private:
62 virtual void DoClose()
489468fe 63 {
51fe4b60
VZ
64 wxSocketManager * const manager = wxSocketManager::Get();
65 if ( manager )
66 {
67 manager->Uninstall_Callback(this, wxSOCKET_INPUT);
68 manager->Uninstall_Callback(this, wxSOCKET_OUTPUT);
69 }
70
71 // VZ: CFRunLoopRemoveSource() is probably unnecessary as
72 // CFSocketInvalidate() seems to do it internally from reading the
73 // docs, please remove it (and this comment) after testing
74 CFRunLoopRemoveSource(gs_mainRunLoop, m_source, kCFRunLoopCommonModes);
75 CFSocketInvalidate(m_socket);
489468fe 76
51fe4b60
VZ
77 CFRelease(m_source);
78 CFRelease(m_socket);
79 }
80
81 // initialize the data associated with the given socket
82 bool Initialize()
83 {
489468fe 84 // we need a valid Unix socket to create a CFSocket
51fe4b60 85 if ( m_fd < 0 )
489468fe
SC
86 return false;
87
88 CFSocketContext cont;
89 cont.version = 0; // this currently must be 0
51fe4b60 90 cont.info = this; // pointer passed to our callback
489468fe
SC
91 cont.retain = NULL; // no need to retain/release/copy the
92 cont.release = NULL; // socket pointer, so all callbacks
93 cont.copyDescription = NULL; // can be left NULL
94
95 m_socket = CFSocketCreateWithNative
96 (
97 NULL, // default allocator
51fe4b60 98 m_fd,
489468fe
SC
99 kCFSocketReadCallBack |
100 kCFSocketWriteCallBack |
101 kCFSocketConnectCallBack,
102 SocketCallback,
103 &cont
104 );
105 if ( !m_socket )
106 return false;
107
108 m_source = CFSocketCreateRunLoopSource(NULL, m_socket, 0);
109
f0fbbe23
VZ
110 if ( !m_source )
111 {
112 CFRelease(m_socket);
113 return false;
114 }
115
116 CFRunLoopAddSource(gs_mainRunLoop, m_source, kCFRunLoopCommonModes);
117
118 return true;
119 }
120
489468fe
SC
121 static void SocketCallback(CFSocketRef WXUNUSED(s),
122 CFSocketCallBackType callbackType,
123 CFDataRef WXUNUSED(address),
124 const void* data,
125 void* info)
126 {
51fe4b60 127 wxSocketImplMac * const socket = static_cast<wxSocketImplMac *>(info);
489468fe
SC
128
129 switch (callbackType)
130 {
131 case kCFSocketConnectCallBack:
51566e1f 132 wxASSERT(!socket->IsServer());
489468fe
SC
133 // KH: If data is non-NULL, the connect failed, do not call Detected_Write,
134 // which will only end up creating a spurious connect event because the
135 // call to getsocketopt SO_ERROR inexplicably returns no error.
136 // The change in behavior cannot be traced to any particular commit or
137 // timeframe so I'm not sure what to think, but after so many hours,
138 // this seems to address the issue and it's time to move on.
139 if (data == NULL)
579213e9 140 socket->OnWriteWaiting();
489468fe
SC
141 break;
142
143 case kCFSocketReadCallBack:
579213e9 144 socket->OnReadWaiting();
489468fe
SC
145 break;
146
147 case kCFSocketWriteCallBack:
579213e9 148 socket->OnWriteWaiting();
489468fe
SC
149 break;
150
151 default:
152 wxFAIL_MSG( "unexpected socket callback" );
153 }
154 }
155
156 CFSocketRef m_socket;
157 CFRunLoopSourceRef m_source;
158
51fe4b60 159 DECLARE_NO_COPY_CLASS(wxSocketImplMac)
489468fe
SC
160};
161
f0fbbe23
VZ
162} // anonymous namespace
163
164
489468fe 165// ----------------------------------------------------------------------------
51fe4b60 166// CoreFoundation implementation of wxSocketManager
489468fe
SC
167// ----------------------------------------------------------------------------
168
51fe4b60 169class wxSocketManagerMac : public wxSocketManager
489468fe
SC
170{
171public:
172 virtual bool OnInit();
173 virtual void OnExit();
174
51fe4b60 175 virtual wxSocketImpl *CreateSocket(wxSocketBase& wxsocket)
489468fe 176 {
51fe4b60 177 return new wxSocketImplMac(wxsocket);
489468fe
SC
178 }
179
51fe4b60
VZ
180 virtual void Install_Callback(wxSocketImpl *socket, wxSocketNotify event);
181 virtual void Uninstall_Callback(wxSocketImpl *socket, wxSocketNotify event);
489468fe 182
51fe4b60 183private:
489468fe
SC
184 // return CFSocket callback mask corresponding to the given event (the
185 // socket parameter is needed because some events are interpreted
186 // differently depending on whether they happen on a server or on a client
187 // socket)
51fe4b60 188 static int GetCFCallback(wxSocketImpl *socket, wxSocketNotify event);
489468fe
SC
189};
190
51fe4b60 191bool wxSocketManagerMac::OnInit()
489468fe
SC
192{
193 // No need to store the main loop again
f0fbbe23 194 if (gs_mainRunLoop != NULL)
489468fe
SC
195 return true;
196
197 // Get the loop for the main thread so our events will actually fire.
198 // The common socket.cpp code will assert if initialize is called from a
199 // secondary thread, otherwise Mac would have the same problems as MSW
f0fbbe23
VZ
200 gs_mainRunLoop = CFRunLoopGetCurrent();
201 if ( !gs_mainRunLoop )
489468fe
SC
202 return false;
203
f0fbbe23 204 CFRetain(gs_mainRunLoop);
489468fe
SC
205
206 return true;
207}
208
51fe4b60 209void wxSocketManagerMac::OnExit()
489468fe
SC
210{
211 // Release the reference count, and set the reference back to NULL
f0fbbe23
VZ
212 CFRelease(gs_mainRunLoop);
213 gs_mainRunLoop = NULL;
489468fe
SC
214}
215
489468fe 216/* static */
51fe4b60 217int wxSocketManagerMac::GetCFCallback(wxSocketImpl *socket, wxSocketNotify event)
489468fe
SC
218{
219 switch ( event )
220 {
51fe4b60 221 case wxSOCKET_CONNECTION:
51566e1f
VZ
222 return socket->IsServer() ? kCFSocketReadCallBack
223 : kCFSocketConnectCallBack;
489468fe 224
51fe4b60 225 case wxSOCKET_INPUT:
489468fe
SC
226 return kCFSocketReadCallBack;
227
51fe4b60 228 case wxSOCKET_OUTPUT:
489468fe
SC
229 return kCFSocketWriteCallBack;
230
c363ead1
VZ
231 case wxSOCKET_LOST:
232 wxFAIL_MSG( "unexpected wxSocketNotify" );
489468fe
SC
233 return 0;
234
235 default:
51fe4b60 236 wxFAIL_MSG( "unknown wxSocketNotify" );
489468fe
SC
237 return 0;
238 }
239}
240
51fe4b60
VZ
241void wxSocketManagerMac::Install_Callback(wxSocketImpl *socket_,
242 wxSocketNotify event)
489468fe 243{
51fe4b60 244 wxSocketImplMac * const socket = static_cast<wxSocketImplMac *>(socket_);
489468fe 245
51fe4b60 246 CFSocketEnableCallBacks(socket->GetSocket(), GetCFCallback(socket, event));
489468fe
SC
247}
248
51fe4b60
VZ
249void wxSocketManagerMac::Uninstall_Callback(wxSocketImpl *socket_,
250 wxSocketNotify event)
489468fe 251{
51fe4b60 252 wxSocketImplMac * const socket = static_cast<wxSocketImplMac *>(socket_);
489468fe 253
51fe4b60 254 CFSocketDisableCallBacks(socket->GetSocket(), GetCFCallback(socket, event));
489468fe
SC
255}
256
51fe4b60
VZ
257// set the wxBase variable to point to our wxSocketManager implementation
258//
259// see comments in wx/apptrait.h for the explanation of why do we do it
260// like this
261static struct ManagerSetter
489468fe 262{
51fe4b60
VZ
263 ManagerSetter()
264 {
265 static wxSocketManagerMac s_manager;
266 wxAppTraits::SetDefaultSocketManager(&s_manager);
267 }
268} gs_managerSetter;
489468fe
SC
269
270#endif // wxUSE_SOCKETS