xref: /reactos/dll/win32/ws2_32/src/dthread.c (revision 84344399)
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
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
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
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
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
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
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
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
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
170 WsThreadCleanup(VOID)
171 {
172 }
173 
174 DWORD
175 WSAAPI
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
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
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
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
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
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
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
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