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