Sync with trunk r43123
[reactos.git] / reactos / dll / win32 / ws2_32_new / src / dthread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock 2 API
4 * FILE: dprocess.c
5 * PURPOSE: Thread Object
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES ******************************************************************/
10 #include "ws2_32.h"
11
12 /* FUNCTIONS *****************************************************************/
13
14 DWORD
15 WSAAPI
16 WsThreadDefaultBlockingHook(VOID)
17 {
18 MSG Message;
19 BOOL GotMessage = FALSE;
20
21 /* Get the message */
22 GotMessage = PeekMessage(&Message, NULL, 0, 0, PM_REMOVE);
23
24 /* Check if we got one */
25 if (GotMessage)
26 {
27 /* Process it */
28 TranslateMessage(&Message);
29 DispatchMessage(&Message);
30 }
31
32 /* return */
33 return GotMessage;
34 }
35
36 BOOL
37 WSAAPI
38 WsThreadBlockingCallback(IN DWORD_PTR Context)
39 {
40 PWSTHREAD Thread = TlsGetValue(TlsIndex);
41
42 /* Set thread as blocking, set cancel callback and the clear cancel flag */
43 Thread->Blocking = TRUE;
44 Thread->CancelBlockingCall = (LPWSPCANCELBLOCKINGCALL)Context;
45 Thread->Cancelled = FALSE;
46
47 /* Call the blocking hook */
48 while(Thread->BlockingHook());
49
50 /* We're not blocking anymore */
51 Thread->Blocking = FALSE;
52
53 /* Return whether or not we were cancelled */
54 return !Thread->Cancelled;
55 }
56
57 FARPROC
58 WSAAPI
59 WsThreadSetBlockingHook(IN PWSTHREAD Thread,
60 IN FARPROC BlockingHook)
61 {
62 FARPROC OldHook = Thread->BlockingHook;
63
64 /* Check if we're resetting to our default hook */
65 if (BlockingHook == (FARPROC)WsThreadDefaultBlockingHook)
66 {
67 /* Clear out the blocking callback */
68 Thread->BlockingCallback = NULL;
69 }
70 else
71 {
72 /* Set the blocking callback */
73 Thread->BlockingCallback = WsThreadBlockingCallback;
74 }
75
76 /* Set the new blocking hook and return the previous */
77 Thread->BlockingHook = BlockingHook;
78 return OldHook;
79 }
80
81 DWORD
82 WSAAPI
83 WsThreadUnhookBlockingHook(IN PWSTHREAD Thread)
84 {
85 /* Reset the hook to the default, and remove the callback */
86 Thread->BlockingHook = (FARPROC)WsThreadDefaultBlockingHook;
87 Thread->BlockingCallback = NULL;
88
89 /* Return success */
90 return ERROR_SUCCESS;
91 }
92
93 DWORD
94 WSAAPI
95 WsThreadCancelBlockingCall(IN PWSTHREAD Thread)
96 {
97 INT ErrorCode, ReturnValue;
98
99 /* Make sure that the Thread is really in a blocking call */
100 if (!Thread->Blocking) return WSAEINVAL;
101
102 /* Make sure we haven't already been cancelled */
103 if (!Thread->Cancelled)
104 {
105 /* Call the cancel procedure */
106 ReturnValue = Thread->CancelBlockingCall(&ErrorCode);
107 if (ReturnValue != ERROR_SUCCESS) return ErrorCode;
108
109 /* Set us as cancelled */
110 Thread->Cancelled = TRUE;
111 }
112
113 /* Success */
114 return ERROR_SUCCESS;
115 }
116
117 PWSPROTO_BUFFER
118 WSAAPI
119 WsThreadGetProtoBuffer(IN PWSTHREAD Thread)
120 {
121 /* See if it already exists */
122 if (!Thread->ProtocolInfo)
123 {
124 /* We don't have a buffer; allocate it */
125 Thread->ProtocolInfo = HeapAlloc(WsSockHeap, 0, sizeof(PWSPROTO_BUFFER));
126 }
127
128 /* Return it */
129 return Thread->ProtocolInfo;
130 }
131
132 PWSTHREAD
133 WSAAPI
134 WsThreadAllocate(VOID)
135 {
136 PWSTHREAD Thread;
137
138 /* Allocate the object */
139 Thread = HeapAlloc(WsSockHeap, HEAP_ZERO_MEMORY, sizeof(*Thread));
140
141 /* Set non-zero data */
142 Thread->BlockingHook = (FARPROC)WsThreadDefaultBlockingHook;
143
144 /* Return it */
145 return Thread;
146 }
147
148 DWORD
149 WSAAPI
150 WsThreadStartup(VOID)
151 {
152 INT ErrorCode = WSASYSCALLFAILURE;
153
154 /* Check if we have a valid TLS */
155 if (TlsIndex != TLS_OUT_OF_INDEXES)
156 {
157 /* TLS was already OK */
158 ErrorCode = ERROR_SUCCESS;
159 }
160
161 /* Return */
162 return ErrorCode;
163 }
164
165 VOID
166 WSAAPI
167 WsThreadCleanup(VOID)
168 {
169 }
170
171 DWORD
172 WSAAPI
173 WsThreadInitialize(IN PWSTHREAD Thread,
174 IN PWSPROCESS Process)
175 {
176 INT ErrorCode = WSASYSCALLFAILURE;
177
178 /* Set the process */
179 Thread->Process = Process;
180
181 /* Get the helper device */
182 if ((WsProcGetAsyncHelper(Process, &Thread->AsyncHelper)) == ERROR_SUCCESS)
183 {
184 /* Initialize a WAH Thread ID */
185 if ((WahOpenCurrentThread(Thread->AsyncHelper,
186 &Thread->WahThreadId)) == ERROR_SUCCESS)
187 {
188 /* Success */
189 ErrorCode = ERROR_SUCCESS;
190 }
191 }
192
193 /* Return */
194 return ErrorCode;
195 }
196
197 VOID
198 WSAAPI
199 WsThreadDelete(IN PWSTHREAD Thread)
200 {
201 /* Remove the blocking hook */
202 Thread->BlockingHook = NULL;
203
204 /* Free our buffers */
205 if (Thread->Hostent) HeapFree(WsSockHeap, 0, Thread->Hostent);
206 if (Thread->Servent) HeapFree(WsSockHeap, 0, Thread->Servent);
207 if (Thread->ProtocolInfo) HeapFree(WsSockHeap, 0, Thread->ProtocolInfo);
208
209 /* Clear the TLS */
210 TlsSetValue(TlsIndex, NULL);
211
212 /* Close the WAH Handle */
213 WahCloseThread(Thread->AsyncHelper, &Thread->WahThreadId);
214
215 /* Unlink the process and free us */
216 Thread->Process = NULL;
217 HeapFree(WsSockHeap, 0, Thread);
218 }
219
220 VOID
221 WSAAPI
222 WsThreadDestroyCurrentThread(VOID)
223 {
224 PWSTHREAD Thread;
225
226 /* Make sure we have TLS */
227 if (TlsIndex != TLS_OUT_OF_INDEXES)
228 {
229 /* Get the thread */
230 if ((Thread = TlsGetValue(TlsIndex)))
231 {
232 /* Delete it */
233 WsThreadDelete(Thread);
234 TlsSetValue(TlsIndex, 0);
235 }
236 }
237 }
238
239 DWORD
240 WSAAPI
241 WsThreadCreate(IN PWSPROCESS Process,
242 IN PWSTHREAD *CurrentThread)
243 {
244 PWSTHREAD Thread = NULL;
245 INT ErrorCode = WSASYSCALLFAILURE;
246
247 /* Make sure we have TLS */
248 if (TlsIndex != TLS_OUT_OF_INDEXES)
249 {
250 /* Allocate the thread */
251 if ((Thread = WsThreadAllocate()))
252 {
253 /* Initialize it */
254 if (WsThreadInitialize(Thread, Process) == ERROR_SUCCESS)
255 {
256 /* Set the TLS */
257 if (TlsSetValue(TlsIndex, Thread))
258 {
259 /* Return it and success */
260 *CurrentThread = Thread;
261 ErrorCode = ERROR_SUCCESS;
262 }
263 }
264
265 /* Check for any failures */
266 if (ErrorCode != ERROR_SUCCESS) WsThreadDelete(Thread);
267 }
268 }
269
270 /* Return */
271 return ErrorCode;
272 }
273
274 DWORD
275 WSAAPI
276 WsThreadGetCurrentThread(IN PWSPROCESS Process,
277 IN PWSTHREAD *Thread)
278 {
279 /* Get the thread */
280 if ((*Thread = TlsGetValue(TlsIndex)))
281 {
282 /* Success */
283 return ERROR_SUCCESS;
284 }
285 else
286 {
287 /* We failed, initialize it */
288 return WsThreadCreate(Process, Thread);
289 }
290 }
291
292 LPWSATHREADID
293 WSAAPI
294 WsThreadGetThreadId(IN PWSPROCESS Process)
295 {
296 PWSTHREAD Thread;
297
298 /* Get the thread */
299 if ((Thread = TlsGetValue(TlsIndex)))
300 {
301 /* Return the ID */
302 return &Thread->WahThreadId;
303 }
304 else
305 {
306 /* Not a valid thread */
307 return NULL;
308 }
309 }
310
311 PHOSTENT
312 WSAAPI
313 WsThreadBlobToHostent(IN PWSTHREAD Thread,
314 IN LPBLOB Blob)
315 {
316 /* Check if our buffer is too small */
317 if (Thread->HostentSize < Blob->cbSize)
318 {
319 /* Delete the current buffer and allocate a new one */
320 HeapFree(WsSockHeap, 0, Thread->Hostent);
321 Thread->Hostent = HeapAlloc(WsSockHeap, 0, Blob->cbSize);
322
323 /* Set the new size */
324 Thread->HostentSize = Blob->cbSize;
325 }
326
327 /* Do we have a buffer? */
328 if (Thread->Hostent)
329 {
330 /* Copy the data inside */
331 RtlMoveMemory(Thread->Hostent, Blob->pBlobData, Blob->cbSize);
332 }
333 else
334 {
335 /* No buffer space! */
336 Thread->HostentSize = 0;
337 SetLastError(WSA_NOT_ENOUGH_MEMORY);
338 }
339
340 /* Return the buffer */
341 return (PHOSTENT)Thread->Hostent;
342 }
343
344 PSERVENT
345 WSAAPI
346 WsThreadBlobToServent(IN PWSTHREAD Thread,
347 IN LPBLOB Blob)
348 {
349 /* Check if our buffer is too small */
350 if (Thread->ServentSize < Blob->cbSize)
351 {
352 /* Delete the current buffer and allocate a new one */
353 HeapFree(WsSockHeap, 0, Thread->Servent);
354 Thread->Servent = HeapAlloc(WsSockHeap, 0, Blob->cbSize);
355
356 /* Set the new size */
357 Thread->ServentSize = Blob->cbSize;
358 }
359
360 /* Do we have a buffer? */
361 if (Thread->Servent)
362 {
363 /* Copy the data inside */
364 RtlMoveMemory(Thread->Servent, Blob->pBlobData, Blob->cbSize);
365 }
366 else
367 {
368 /* No buffer space! */
369 Thread->ServentSize = 0;
370 SetLastError(WSA_NOT_ENOUGH_MEMORY);
371 }
372
373 /* Return the buffer */
374 return (PSERVENT)Thread->Servent;
375 }
376