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