]> git.saurik.com Git - wxWidgets.git/blob - src/mac/gsockosx.c
* Implemented according to Apple CFSocket documentation:
[wxWidgets.git] / src / mac / gsockosx.c
1 /* -------------------------------------------------------------------------
2 * Project: GSocket (Generic Socket) for WX
3 * Name: gsockosx.c
4 * Purpose: GSocket: Mac OS X mach-o part
5 * CVSID: $Id$
6 * Mac code by Brian Victor, February 2002. Email comments to bhv1@psu.edu
7 * ------------------------------------------------------------------------- */
8
9 #include "wx/setup.h"
10
11 #if wxUSE_SOCKETS
12
13 #include <stdlib.h>
14 #include "wx/gsocket.h"
15 #include "wx/unix/gsockunx.h"
16
17 #include <CoreFoundation/CoreFoundation.h>
18
19 #define ALL_CALLBACK_TYPES (kCFSocketReadCallBack | kCFSocketWriteCallBack | kCFSocketConnectCallBack)
20
21 struct MacGSocketData
22 {
23 CFSocketRef socket;
24 CFRunLoopSourceRef source;
25 };
26
27 void Mac_Socket_Callback(CFSocketRef s, CFSocketCallBackType callbackType,
28 CFDataRef address, const void* data, void* info)
29 {
30 GSocket* socket = (GSocket*)info;
31 struct MacGSocketData* macdata;
32 macdata = (struct MacGSocketData*)socket->m_gui_dependent;
33 if (!macdata) return;
34 switch (callbackType)
35 {
36 case kCFSocketConnectCallBack:
37 assert(!socket->m_server);
38 socket->m_functions->Detected_Write(socket);
39 break;
40 case kCFSocketReadCallBack:
41 socket->m_functions->Detected_Read(socket);
42 break;
43 case kCFSocketWriteCallBack:
44 socket->m_functions->Detected_Write(socket);
45 break;
46 default:
47 break; /* We shouldn't get here. */
48 }
49 }
50
51 struct MacGSocketData* _GSocket_Get_Mac_Socket(GSocket *socket)
52 {
53 /* If socket is already created, returns a pointer to the data */
54 /* Otherwise, creates socket and returns the pointer */
55 CFSocketContext cont;
56 struct MacGSocketData* data = (struct MacGSocketData*)socket->m_gui_dependent;
57
58 if (data && data->source) return data;
59
60 /* CFSocket has not been created, create it: */
61 if (socket->m_fd < 0 || !data) return NULL;
62 cont.version = 0; cont.retain = NULL;
63 cont.release = NULL; cont.copyDescription = NULL;
64 cont.info = socket;
65
66 CFSocketRef cf = CFSocketCreateWithNative(NULL, socket->m_fd,
67 ALL_CALLBACK_TYPES, Mac_Socket_Callback, &cont);
68 /* Disable the callbacks until we are asked by GSocket to enable them. */
69 CFSocketDisableCallBacks(cf, ALL_CALLBACK_TYPES);
70 CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(NULL, cf, 0);
71 assert(source);
72 /* Turn off kCFSocketCloseOnInvalidate (NOTE: > 10.2 only!) */
73 /* Another default flag that we don't turn on here is for DataCallBack and
74 also AcceptCallback (which overlap in bits) which we don't use anyway */
75 /* FIXME: For < 10.2 compatibility fix GSocket to call a platform-dependent
76 function to close the socket so that we can just call invalidate and
77 avoid having to set any special flags at all. */
78 CFSocketSetSocketFlags(cf, kCFSocketAutomaticallyReenableReadCallBack | kCFSocketAutomaticallyReenableWriteCallBack);
79 socket->m_gui_dependent = (char*)data;
80 CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
81
82 /* Keep the source and the socket around. */
83 data->source = source;
84 data->socket = cf;
85
86 return data;
87 }
88
89 int _GSocket_GUI_Init(void)
90 {
91 return 1;
92 }
93
94 void _GSocket_GUI_Cleanup(void)
95 {
96 }
97
98 int _GSocket_GUI_Init_Socket(GSocket *socket)
99 {
100 struct MacGSocketData *data = malloc(sizeof(struct MacGSocketData));
101 if (data)
102 {
103 socket->m_gui_dependent = (char*)data;
104 data->socket = NULL;
105 data->source = NULL;
106 return 1;
107 }
108 return 0;
109 }
110
111 void _GSocket_GUI_Destroy_Socket(GSocket *socket)
112 {
113 struct MacGSocketData *data = (struct MacGSocketData*)(socket->m_gui_dependent);
114 if (data)
115 {
116 /* CFSocketInvalidate does this anyway, so perhaps get rid of this: */
117 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), data->source, kCFRunLoopCommonModes);
118 CFSocketInvalidate(data->socket);
119 CFRelease(data->socket);
120 free(data);
121 }
122 }
123
124 void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event)
125 {
126 int c;
127 struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket);
128 if (!data) return;
129 switch (event)
130 {
131 case GSOCK_CONNECTION:
132 if(socket->m_server)
133 c = kCFSocketReadCallBack;
134 else
135 c = kCFSocketConnectCallBack;
136 break;
137 case GSOCK_LOST:
138 case GSOCK_INPUT:
139 c = kCFSocketReadCallBack;
140 break;
141 case GSOCK_OUTPUT:
142 c = kCFSocketWriteCallBack;
143 break;
144 default:
145 c = 0;
146 }
147 CFSocketEnableCallBacks(data->socket, c);
148 }
149
150 void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event)
151 {
152 int c;
153 struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket);
154 if (!data) return;
155 switch (event)
156 {
157 case GSOCK_CONNECTION:
158 if(socket->m_server)
159 c = kCFSocketReadCallBack;
160 else
161 c = kCFSocketConnectCallBack;
162 break;
163 case GSOCK_LOST:
164 case GSOCK_INPUT:
165 c = kCFSocketReadCallBack;
166 break;
167 case GSOCK_OUTPUT:
168 c = kCFSocketWriteCallBack;
169 break;
170 default:
171 c = 0;
172 }
173 CFSocketDisableCallBacks(data->socket, c);
174 }
175
176 void _GSocket_Enable_Events(GSocket *socket)
177 {
178 CFOptionFlags callBackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack;
179 struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket);
180 if (!data) return;
181
182 if(!socket->m_server)
183 callBackTypes |= kCFSocketConnectCallBack;
184 CFSocketEnableCallBacks(data->socket, callBackTypes);
185 }
186
187 void _GSocket_Disable_Events(GSocket *socket)
188 {
189 struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket);
190 if (!data) return;
191 CFSocketDisableCallBacks(data->socket, ALL_CALLBACK_TYPES);
192 }
193
194 #endif // wxUSE_SOCKETS