1 /* -------------------------------------------------------------------------
2 * Project: GSocket (Generic Socket) for WX
3 * Name: src/mac/corefoundation/gsockosx.c
4 * Purpose: GSocket: Mac OS X mach-o part
6 * Mac code by Brian Victor, February 2002. Email comments to bhv1@psu.edu
7 * ------------------------------------------------------------------------- */
14 #include "wx/gsocket.h"
15 #include "wx/unix/gsockunx.h"
17 #include <CoreFoundation/CoreFoundation.h>
19 #define ALL_CALLBACK_TYPES (kCFSocketReadCallBack | kCFSocketWriteCallBack | kCFSocketConnectCallBack)
24 CFRunLoopSourceRef source
;
27 // Sockets must use the event loop on the main thread
28 // We will store the main loop's reference when Initialize is called
29 static CFRunLoopRef s_mainRunLoop
= NULL
;
31 void Mac_Socket_Callback(CFSocketRef
WXUNUSED(s
), CFSocketCallBackType callbackType
,
32 CFDataRef
WXUNUSED(address
), const void* data
, void* info
)
34 GSocket
* socket
= (GSocket
*)info
;
35 struct MacGSocketData
* macdata
;
36 macdata
= (struct MacGSocketData
*)socket
->m_gui_dependent
;
40 case kCFSocketConnectCallBack
:
41 assert(!socket
->m_server
);
42 // KH: If data is non-NULL, the connect failed, do not call Detected_Write,
43 // which will only end up creating a spurious connect event because the
44 // call to getsocketopt SO_ERROR inexplicably returns no error.
45 // The change in behavior cannot be traced to any particular commit or
46 // timeframe so I'm not sure what to think, but after so many hours,
47 // this seems to address the issue and it's time to move on.
49 socket
->Detected_Write();
51 case kCFSocketReadCallBack
:
52 socket
->Detected_Read();
54 case kCFSocketWriteCallBack
:
55 socket
->Detected_Write();
58 break; /* We shouldn't get here. */
62 struct MacGSocketData
* _GSocket_Get_Mac_Socket(GSocket
*socket
)
64 /* If socket is already created, returns a pointer to the data */
65 /* Otherwise, creates socket and returns the pointer */
67 struct MacGSocketData
* data
= (struct MacGSocketData
*)socket
->m_gui_dependent
;
69 if (data
&& data
->source
) return data
;
71 /* CFSocket has not been created, create it: */
72 if (socket
->m_fd
< 0 || !data
) return NULL
;
73 cont
.version
= 0; cont
.retain
= NULL
;
74 cont
.release
= NULL
; cont
.copyDescription
= NULL
;
77 CFSocketRef cf
= CFSocketCreateWithNative(NULL
, socket
->m_fd
,
78 ALL_CALLBACK_TYPES
, Mac_Socket_Callback
, &cont
);
79 CFRunLoopSourceRef source
= CFSocketCreateRunLoopSource(NULL
, cf
, 0);
81 socket
->m_gui_dependent
= (char*)data
;
83 /* Keep the source and the socket around. */
84 data
->source
= source
;
90 bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop()
93 bool GSocketGUIFunctionsTableConcrete::OnInit(void)
95 // No need to store the main loop again
96 if (s_mainRunLoop
!= NULL
)
99 // Get the loop for the main thread so our events will actually fire.
100 // The common socket.cpp code will assert if initialize is called from a
101 // secondary thread, otherwise Mac would have the same problems as MSW
102 s_mainRunLoop
= CFRunLoopGetCurrent();
103 CFRetain(s_mainRunLoop
);
108 void GSocketGUIFunctionsTableConcrete::OnExit(void)
110 // Release the reference count, and set the reference back to NULL
111 CFRelease(s_mainRunLoop
);
112 s_mainRunLoop
= NULL
;
115 bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket
*socket
)
117 struct MacGSocketData
*data
= (struct MacGSocketData
*)malloc(sizeof(struct MacGSocketData
));
120 socket
->m_gui_dependent
= (char*)data
;
128 void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket
*socket
)
130 struct MacGSocketData
*data
= (struct MacGSocketData
*)(socket
->m_gui_dependent
);
134 CFRelease(data
->source
);
136 CFRelease(data
->socket
);
141 void GSocketGUIFunctionsTableConcrete::Install_Callback(GSocket
*socket
, GSocketEvent event
)
144 struct MacGSocketData
* data
= _GSocket_Get_Mac_Socket(socket
);
148 case GSOCK_CONNECTION
:
150 c
= kCFSocketReadCallBack
;
152 c
= kCFSocketConnectCallBack
;
156 c
= kCFSocketReadCallBack
;
159 c
= kCFSocketWriteCallBack
;
164 CFSocketEnableCallBacks(data
->socket
, c
);
167 void GSocketGUIFunctionsTableConcrete::Uninstall_Callback(GSocket
*socket
, GSocketEvent event
)
170 struct MacGSocketData
* data
= _GSocket_Get_Mac_Socket(socket
);
174 case GSOCK_CONNECTION
:
176 c
= kCFSocketReadCallBack
;
178 c
= kCFSocketConnectCallBack
;
182 c
= kCFSocketReadCallBack
;
185 c
= kCFSocketWriteCallBack
;
190 CFSocketDisableCallBacks(data
->socket
, c
);
193 void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket
*socket
)
195 struct MacGSocketData
* data
= _GSocket_Get_Mac_Socket(socket
);
198 CFRunLoopAddSource(s_mainRunLoop
, data
->source
, kCFRunLoopCommonModes
);
201 void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket
*socket
)
203 struct MacGSocketData
* data
= _GSocket_Get_Mac_Socket(socket
);
206 /* CFSocketInvalidate does CFRunLoopRemoveSource anyway */
207 CFRunLoopRemoveSource(s_mainRunLoop
, data
->source
, kCFRunLoopCommonModes
);
208 CFSocketInvalidate(data
->socket
);
210 // CFSocketInvalidate has closed the socket so we want to make sure GSocket knows this
211 socket
->m_fd
= -1 /*INVALID_SOCKET*/;
214 #endif // wxUSE_SOCKETS