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