From a38b65ab35a40840d7799e8e67b781ca7474e505 Mon Sep 17 00:00:00 2001 From: David Elliott Date: Wed, 24 Dec 2003 04:04:40 +0000 Subject: [PATCH] * Implemented according to Apple CFSocket documentation: kCFSocketConnectCallBack: Called in response to a successful connect() and of course applies to client sockets only. Fails assertion if received from a server socket. Calls GSocket's Detected_Write otherwise. kCFSocketReadCallBack: Called whenever data is available to read or in the event that a new connection is waiting to be accepted. Call's GSocket's Detected_Read. kCFSocketWriteCallBack: Called whenever data can be written to kernel buffer. Call's GSocket's Detected_Write * Added ALL_CALLBACK_TYPES macro which specifies all of the above three. * Added (by virtue of ALL_CALLBACK_TYPES) the kCFSocketConnectCallBack to the calls to CFSocketCreateWithNative and CFSocketDisableCallBacks during GUI socket data creation. * Use the default flags for CFSocket which automatically reenable the callbacks, but continue to disable close of fd on CFSocket invalidation. Eventually, GSocket should allow the GUI implementation to override close so that we can avoid calling the > 10.2 CFSocketSetSocketFlags function. * CFRelease the socket after invalidating it (fixes memory leak) * When adding/removing callbacks use kCFSocketReadCallBack for server GSOCK_CONNECTION and kCFSocketConnectCallback for client. * When adding/removing callbacks GSOCK_LOST should do the same thing as GSOCK_INPUT (Thanks Kevin Hock) * When enabling events, do not enable kCFSocketConnectCallBack for servers. It should never be called anyway since connect() should never be used on a server socket. * When disabling events, disable ALL_CALLBACK_TYPES. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@24999 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/mac/carbon/gsockosx.c | 46 +++++++++++++++++++++++++++++---------- src/mac/gsockosx.c | 46 +++++++++++++++++++++++++++++---------- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/mac/carbon/gsockosx.c b/src/mac/carbon/gsockosx.c index c93e4c9e2e..fd9703227c 100644 --- a/src/mac/carbon/gsockosx.c +++ b/src/mac/carbon/gsockosx.c @@ -16,6 +16,8 @@ #include +#define ALL_CALLBACK_TYPES (kCFSocketReadCallBack | kCFSocketWriteCallBack | kCFSocketConnectCallBack) + struct MacGSocketData { CFSocketRef socket; @@ -32,7 +34,8 @@ void Mac_Socket_Callback(CFSocketRef s, CFSocketCallBackType callbackType, switch (callbackType) { case kCFSocketConnectCallBack: - socket->m_functions->Detected_Read(socket); + assert(!socket->m_server); + socket->m_functions->Detected_Write(socket); break; case kCFSocketReadCallBack: socket->m_functions->Detected_Read(socket); @@ -49,23 +52,30 @@ struct MacGSocketData* _GSocket_Get_Mac_Socket(GSocket *socket) { /* If socket is already created, returns a pointer to the data */ /* Otherwise, creates socket and returns the pointer */ - CFOptionFlags c; CFSocketContext cont; struct MacGSocketData* data = (struct MacGSocketData*)socket->m_gui_dependent; if (data && data->source) return data; + + /* CFSocket has not been created, create it: */ if (socket->m_fd < 0 || !data) return NULL; cont.version = 0; cont.retain = NULL; cont.release = NULL; cont.copyDescription = NULL; cont.info = socket; - c = kCFSocketReadCallBack | kCFSocketWriteCallBack; - CFSocketRef cf = CFSocketCreateWithNative(NULL, socket->m_fd, c, - Mac_Socket_Callback, &cont); - CFSocketDisableCallBacks(cf, kCFSocketReadCallBack | kCFSocketWriteCallBack); + CFSocketRef cf = CFSocketCreateWithNative(NULL, socket->m_fd, + ALL_CALLBACK_TYPES, Mac_Socket_Callback, &cont); + /* Disable the callbacks until we are asked by GSocket to enable them. */ + CFSocketDisableCallBacks(cf, ALL_CALLBACK_TYPES); CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(NULL, cf, 0); assert(source); - CFSocketSetSocketFlags(cf, 0); /* Callbacks must be reenabled manually */ + /* Turn off kCFSocketCloseOnInvalidate (NOTE: > 10.2 only!) */ + /* Another default flag that we don't turn on here is for DataCallBack and + also AcceptCallback (which overlap in bits) which we don't use anyway */ + /* FIXME: For < 10.2 compatibility fix GSocket to call a platform-dependent + function to close the socket so that we can just call invalidate and + avoid having to set any special flags at all. */ + CFSocketSetSocketFlags(cf, kCFSocketAutomaticallyReenableReadCallBack | kCFSocketAutomaticallyReenableWriteCallBack); socket->m_gui_dependent = (char*)data; CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); @@ -103,8 +113,10 @@ void _GSocket_GUI_Destroy_Socket(GSocket *socket) struct MacGSocketData *data = (struct MacGSocketData*)(socket->m_gui_dependent); if (data) { + /* CFSocketInvalidate does this anyway, so perhaps get rid of this: */ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), data->source, kCFRunLoopCommonModes); CFSocketInvalidate(data->socket); + CFRelease(data->socket); free(data); } } @@ -117,8 +129,12 @@ void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event) switch (event) { case GSOCK_CONNECTION: - c = kCFSocketReadCallBack; /* This works, but I don't know why. */ + if(socket->m_server) + c = kCFSocketReadCallBack; + else + c = kCFSocketConnectCallBack; break; + case GSOCK_LOST: case GSOCK_INPUT: c = kCFSocketReadCallBack; break; @@ -139,8 +155,12 @@ void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) switch (event) { case GSOCK_CONNECTION: - c = kCFSocketConnectCallBack; + if(socket->m_server) + c = kCFSocketReadCallBack; + else + c = kCFSocketConnectCallBack; break; + case GSOCK_LOST: case GSOCK_INPUT: c = kCFSocketReadCallBack; break; @@ -155,16 +175,20 @@ void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) void _GSocket_Enable_Events(GSocket *socket) { + CFOptionFlags callBackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack; struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); if (!data) return; - CFSocketEnableCallBacks(data->socket, kCFSocketReadCallBack | kCFSocketWriteCallBack); + + if(!socket->m_server) + callBackTypes |= kCFSocketConnectCallBack; + CFSocketEnableCallBacks(data->socket, callBackTypes); } void _GSocket_Disable_Events(GSocket *socket) { struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); if (!data) return; - CFSocketDisableCallBacks(data->socket, kCFSocketReadCallBack | kCFSocketWriteCallBack); + CFSocketDisableCallBacks(data->socket, ALL_CALLBACK_TYPES); } #endif // wxUSE_SOCKETS diff --git a/src/mac/gsockosx.c b/src/mac/gsockosx.c index c93e4c9e2e..fd9703227c 100644 --- a/src/mac/gsockosx.c +++ b/src/mac/gsockosx.c @@ -16,6 +16,8 @@ #include +#define ALL_CALLBACK_TYPES (kCFSocketReadCallBack | kCFSocketWriteCallBack | kCFSocketConnectCallBack) + struct MacGSocketData { CFSocketRef socket; @@ -32,7 +34,8 @@ void Mac_Socket_Callback(CFSocketRef s, CFSocketCallBackType callbackType, switch (callbackType) { case kCFSocketConnectCallBack: - socket->m_functions->Detected_Read(socket); + assert(!socket->m_server); + socket->m_functions->Detected_Write(socket); break; case kCFSocketReadCallBack: socket->m_functions->Detected_Read(socket); @@ -49,23 +52,30 @@ struct MacGSocketData* _GSocket_Get_Mac_Socket(GSocket *socket) { /* If socket is already created, returns a pointer to the data */ /* Otherwise, creates socket and returns the pointer */ - CFOptionFlags c; CFSocketContext cont; struct MacGSocketData* data = (struct MacGSocketData*)socket->m_gui_dependent; if (data && data->source) return data; + + /* CFSocket has not been created, create it: */ if (socket->m_fd < 0 || !data) return NULL; cont.version = 0; cont.retain = NULL; cont.release = NULL; cont.copyDescription = NULL; cont.info = socket; - c = kCFSocketReadCallBack | kCFSocketWriteCallBack; - CFSocketRef cf = CFSocketCreateWithNative(NULL, socket->m_fd, c, - Mac_Socket_Callback, &cont); - CFSocketDisableCallBacks(cf, kCFSocketReadCallBack | kCFSocketWriteCallBack); + CFSocketRef cf = CFSocketCreateWithNative(NULL, socket->m_fd, + ALL_CALLBACK_TYPES, Mac_Socket_Callback, &cont); + /* Disable the callbacks until we are asked by GSocket to enable them. */ + CFSocketDisableCallBacks(cf, ALL_CALLBACK_TYPES); CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(NULL, cf, 0); assert(source); - CFSocketSetSocketFlags(cf, 0); /* Callbacks must be reenabled manually */ + /* Turn off kCFSocketCloseOnInvalidate (NOTE: > 10.2 only!) */ + /* Another default flag that we don't turn on here is for DataCallBack and + also AcceptCallback (which overlap in bits) which we don't use anyway */ + /* FIXME: For < 10.2 compatibility fix GSocket to call a platform-dependent + function to close the socket so that we can just call invalidate and + avoid having to set any special flags at all. */ + CFSocketSetSocketFlags(cf, kCFSocketAutomaticallyReenableReadCallBack | kCFSocketAutomaticallyReenableWriteCallBack); socket->m_gui_dependent = (char*)data; CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); @@ -103,8 +113,10 @@ void _GSocket_GUI_Destroy_Socket(GSocket *socket) struct MacGSocketData *data = (struct MacGSocketData*)(socket->m_gui_dependent); if (data) { + /* CFSocketInvalidate does this anyway, so perhaps get rid of this: */ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), data->source, kCFRunLoopCommonModes); CFSocketInvalidate(data->socket); + CFRelease(data->socket); free(data); } } @@ -117,8 +129,12 @@ void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event) switch (event) { case GSOCK_CONNECTION: - c = kCFSocketReadCallBack; /* This works, but I don't know why. */ + if(socket->m_server) + c = kCFSocketReadCallBack; + else + c = kCFSocketConnectCallBack; break; + case GSOCK_LOST: case GSOCK_INPUT: c = kCFSocketReadCallBack; break; @@ -139,8 +155,12 @@ void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) switch (event) { case GSOCK_CONNECTION: - c = kCFSocketConnectCallBack; + if(socket->m_server) + c = kCFSocketReadCallBack; + else + c = kCFSocketConnectCallBack; break; + case GSOCK_LOST: case GSOCK_INPUT: c = kCFSocketReadCallBack; break; @@ -155,16 +175,20 @@ void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) void _GSocket_Enable_Events(GSocket *socket) { + CFOptionFlags callBackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack; struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); if (!data) return; - CFSocketEnableCallBacks(data->socket, kCFSocketReadCallBack | kCFSocketWriteCallBack); + + if(!socket->m_server) + callBackTypes |= kCFSocketConnectCallBack; + CFSocketEnableCallBacks(data->socket, callBackTypes); } void _GSocket_Disable_Events(GSocket *socket) { struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); if (!data) return; - CFSocketDisableCallBacks(data->socket, kCFSocketReadCallBack | kCFSocketWriteCallBack); + CFSocketDisableCallBacks(data->socket, ALL_CALLBACK_TYPES); } #endif // wxUSE_SOCKETS -- 2.45.2