+public:
+ // default ctor creates the object in uninitialized state, use Initialize()
+ // later to make it usable
+ MacGSocketData()
+ {
+ m_socket = NULL;
+ m_source = NULL;
+ }
+
+ // initialize the data associated with the given socket
+ bool Initialize(GSocket *socket)
+ {
+ wxASSERT_MSG( !IsInitialized(), "shouldn't be called twice" );
+
+ // we need a valid Unix socket to create a CFSocket
+ if ( socket->m_fd < 0 )
+ return false;
+
+ CFSocketContext cont;
+ cont.version = 0; // this currently must be 0
+ cont.info = socket; // pointer passed to our callback
+ cont.retain = NULL; // no need to retain/release/copy the
+ cont.release = NULL; // socket pointer, so all callbacks
+ cont.copyDescription = NULL; // can be left NULL
+
+ m_socket = CFSocketCreateWithNative
+ (
+ NULL, // default allocator
+ socket->m_fd,
+ kCFSocketReadCallBack |
+ kCFSocketWriteCallBack |
+ kCFSocketConnectCallBack,
+ SocketCallback,
+ &cont
+ );
+ if ( !m_socket )
+ return false;
+
+ m_source = CFSocketCreateRunLoopSource(NULL, m_socket, 0);
+
+ return m_source != NULL;
+ }
+
+ // free the objects created by Initialize()
+ ~MacGSocketData()
+ {
+ if ( m_source )
+ CFRelease(m_source);
+ if ( m_socket )
+ CFRelease(m_socket);
+ }
+
+ // return true if Initialize() had already been called successfully
+ bool IsInitialized() const { return m_source && m_socket; }
+
+
+ // accessors: should only be called if IsInitialized()
+ CFSocketRef GetSocket() const
+ {
+ wxASSERT( IsInitialized() );
+
+ return m_socket;
+ }
+
+ CFRunLoopSourceRef GetSource() const
+ {
+ wxASSERT( IsInitialized() );
+
+ return m_source;
+ }
+
+private:
+ static void SocketCallback(CFSocketRef WXUNUSED(s),
+ CFSocketCallBackType callbackType,
+ CFDataRef WXUNUSED(address),
+ const void* data,
+ void* info)
+ {
+ GSocket * const socket = wx_static_cast(GSocket *, info);
+ MacGSocketData * const
+ macdata = wx_static_cast(MacGSocketData *, socket->m_gui_dependent);
+ if ( !macdata )
+ return;
+
+ switch (callbackType)
+ {
+ case kCFSocketConnectCallBack:
+ wxASSERT(!socket->m_server);
+ // KH: If data is non-NULL, the connect failed, do not call Detected_Write,
+ // which will only end up creating a spurious connect event because the
+ // call to getsocketopt SO_ERROR inexplicably returns no error.
+ // The change in behavior cannot be traced to any particular commit or
+ // timeframe so I'm not sure what to think, but after so many hours,
+ // this seems to address the issue and it's time to move on.
+ if (data == NULL)
+ socket->Detected_Write();
+ break;
+
+ case kCFSocketReadCallBack:
+ socket->Detected_Read();
+ break;
+
+ case kCFSocketWriteCallBack:
+ socket->Detected_Write();
+ break;
+
+ default:
+ wxFAIL_MSG( "unexpected socket callback" );
+ }
+ }
+
+ CFSocketRef m_socket;
+ CFRunLoopSourceRef m_source;
+
+ DECLARE_NO_COPY_CLASS(MacGSocketData);