1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS WinSock 2 API 4 * FILE: dll/win32/ws2_32_new/src/nsquery.c 5 * PURPOSE: Namespace Query Object 6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ws2_32.h> 12 13 /* DATA **********************************************************************/ 14 15 #define WsNqLock() EnterCriticalSection(&NsQuery->Lock) 16 #define WsNqUnlock() LeaveCriticalSection(&NsQuery->Lock) 17 18 /* FUNCTIONS *****************************************************************/ 19 20 PNSQUERY 21 WSAAPI 22 WsNqAllocate(VOID) 23 { 24 PNSQUERY NsQuery; 25 26 /* Allocate the object */ 27 NsQuery = HeapAlloc(WsSockHeap, HEAP_ZERO_MEMORY, sizeof(*NsQuery)); 28 if (NsQuery) 29 { 30 /* Set non-zero fields */ 31 NsQuery->Signature = ~0xBEADFACE; 32 InitializeListHead(&NsQuery->ProviderList); 33 NsQuery->TryAgain = TRUE; 34 } 35 36 /* Return it */ 37 return NsQuery; 38 } 39 40 DWORD 41 WSAAPI 42 WsNqInitialize(IN PNSQUERY Query) 43 { 44 /* Initialize the lock */ 45 InitializeCriticalSection(&Query->Lock); 46 47 /* Set initial reference count and signature */ 48 Query->RefCount = 1; 49 Query->Signature = 0xBEADFACE; 50 51 /* Return success */ 52 return ERROR_SUCCESS; 53 } 54 55 BOOL 56 WSAAPI 57 WsNqValidateAndReference(IN PNSQUERY Query) 58 { 59 /* Check the signature first */ 60 if (Query->Signature != 0xBEADFACE) return FALSE; 61 62 /* Validate the reference count */ 63 if (!Query->RefCount) return FALSE; 64 65 /* Increase reference count */ 66 InterlockedIncrement(&Query->RefCount); 67 68 /* Return success */ 69 return TRUE; 70 } 71 72 VOID 73 WSAAPI 74 WsNqDelete(IN PNSQUERY NsQuery) 75 { 76 PNSQUERY_PROVIDER Provider; 77 PLIST_ENTRY Entry; 78 79 /* Make sure that we got initialized */ 80 if (!NsQuery->ProviderList.Flink) return; 81 82 /* Loop the provider list */ 83 while (!IsListEmpty(&NsQuery->ProviderList)) 84 { 85 /* Remove the entry */ 86 Entry = RemoveHeadList(&NsQuery->ProviderList); 87 88 /* Get the provider */ 89 Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink); 90 91 /* Delete it */ 92 WsNqProvDelete(Provider); 93 } 94 95 /* Remove the signature and delete the lock */ 96 NsQuery->Signature = ~0xBEADFACE; 97 DeleteCriticalSection(&NsQuery->Lock); 98 99 /* Free us */ 100 HeapFree(WsSockHeap, 0, NsQuery); 101 } 102 103 VOID 104 WSAAPI 105 WsNqDereference(IN PNSQUERY Query) 106 { 107 /* Decrease the reference count and check if it's zero */ 108 if (!InterlockedDecrement(&Query->RefCount)) 109 { 110 /* Delete us*/ 111 WsNqDelete(Query); 112 } 113 } 114 115 BOOL 116 WSAAPI 117 WsNqBeginEnumerationProc(PVOID Context, 118 PNSCATALOG_ENTRY Entry) 119 { 120 PNS_PROVIDER Provider; 121 BOOLEAN GoOn = TRUE; 122 PENUM_CONTEXT EnumContext = (PENUM_CONTEXT)Context; 123 PNSQUERY NsQuery = EnumContext->NsQuery; 124 DWORD NamespaceId = Entry->NamespaceId; 125 126 /* Match the namespace ID, protocols and make sure it's enabled */ 127 if ((((EnumContext->lpqsRestrictions->dwNameSpace == NamespaceId) || 128 (EnumContext->lpqsRestrictions->dwNameSpace == NS_ALL)) && 129 (!(EnumContext->lpqsRestrictions->dwNumberOfProtocols) || 130 (WsNcMatchProtocols(NamespaceId, 131 Entry->AddressFamily, 132 EnumContext->lpqsRestrictions)))) && 133 (Entry->Enabled)) 134 { 135 /* Get the provider */ 136 if (!(Provider = Entry->Provider)) 137 { 138 /* None was loaded, load it */ 139 if (WsNcLoadProvider(EnumContext->Catalog, Entry) != ERROR_SUCCESS) 140 { 141 /* Return TRUE to continue enumerating */ 142 return TRUE; 143 } 144 145 /* Set the provider */ 146 Provider = Entry->Provider; 147 } 148 149 /* Add it to the query */ 150 if (!WsNqAddProvider(NsQuery, Provider)) 151 { 152 /* We failed */ 153 EnumContext->ErrorCode = WSASYSCALLFAILURE; 154 GoOn = FALSE; 155 } 156 } 157 158 /* Return to caller */ 159 return GoOn; 160 } 161 162 DWORD 163 WSAAPI 164 WsNqLookupServiceEnd(IN PNSQUERY NsQuery) 165 { 166 PNSQUERY_PROVIDER Provider; 167 PLIST_ENTRY Entry; 168 169 /* Protect us from closure */ 170 WsNqLock(); 171 NsQuery->ShuttingDown = TRUE; 172 173 /* Get the list and loop */ 174 Entry = NsQuery->ProviderList.Flink; 175 while (Entry != &NsQuery->ProviderList) 176 { 177 /* Get the provider */ 178 Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink); 179 180 /* Call its routine */ 181 WsNqProvLookupServiceEnd(Provider); 182 183 /* Move to the next one */ 184 Entry = Entry->Flink; 185 } 186 187 /* Release lock and return success */ 188 WsNqUnlock(); 189 return ERROR_SUCCESS; 190 } 191 192 DWORD 193 WSAAPI 194 WsNqLookupServiceNext(IN PNSQUERY NsQuery, 195 IN DWORD ControlFlags, 196 OUT PDWORD BufferLength, 197 OUT LPWSAQUERYSETW Results) 198 { 199 INT ErrorCode = SOCKET_ERROR, OldErrorCode; 200 PNSQUERY_PROVIDER Provider, NextProvider; 201 PLIST_ENTRY Entry; 202 203 /* Make sure we're not shutting down */ 204 if (NsQuery->ShuttingDown) 205 { 206 /* We are shutting down, fail */ 207 SetLastError(WSAECANCELLED); 208 return ErrorCode; 209 } 210 211 /* Acquire query lock */ 212 WsNqLock(); 213 214 /* Check if we already have an active provider */ 215 NextProvider = NsQuery->ActiveProvider; 216 if (!NextProvider) 217 { 218 /* Make sure we have a current provider */ 219 if (!NsQuery->CurrentProvider) 220 { 221 /* We don't; fail */ 222 WsNqUnlock(); 223 SetLastError(WSA_E_NO_MORE); 224 return SOCKET_ERROR; 225 } 226 227 /* Get the last provider in the list and start looping */ 228 Entry = NsQuery->ProviderList.Blink; 229 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink); 230 while (NextProvider) 231 { 232 /* Check if this is a new-style provider */ 233 if (NextProvider->Provider->Service.NSPIoctl) 234 { 235 /* Remove it and re-add it on top */ 236 RemoveEntryList(&NextProvider->QueryLink); 237 InsertHeadList(&NsQuery->ProviderList, &NextProvider->QueryLink); 238 239 /* Set it as the active provider and exit the loop */ 240 NsQuery->ActiveProvider = NextProvider; 241 break; 242 } 243 244 /* Get the previous provider */ 245 NextProvider = WsNqPreviousProvider(NsQuery, NextProvider); 246 } 247 } 248 249 /* Release the lock */ 250 WsNqUnlock(); 251 252 /* Restart and keep looping as long as there is an active provider */ 253 while (NextProvider) 254 { 255 /* Call its routine */ 256 ErrorCode = WsNqProvLookupServiceNext(NextProvider, 257 ControlFlags, 258 BufferLength, 259 Results); 260 /* Check for error or shutdown */ 261 if ((ErrorCode == ERROR_SUCCESS) || 262 (GetLastError() == WSAEFAULT) || (NsQuery->ShuttingDown)) 263 { 264 /* Get out */ 265 break; 266 } 267 268 /* Acquire Query Lock */ 269 WsNqLock(); 270 271 /* Check if we have an active provider */ 272 if (NsQuery->ActiveProvider) 273 { 274 /* Save the old provider and get the next one */ 275 Provider = NextProvider; 276 NextProvider = WsNqNextProvider(NsQuery, NsQuery->ActiveProvider); 277 278 /* Was the old provider our active? */ 279 if (Provider == NsQuery->ActiveProvider) 280 { 281 /* Change our active provider to the new one */ 282 NsQuery->ActiveProvider = NextProvider; 283 } 284 } 285 else 286 { 287 /* No next provider */ 288 NextProvider = NULL; 289 } 290 291 /* Check if we failed and if we can try again */ 292 if (!(NextProvider) && 293 (ErrorCode == SOCKET_ERROR) && 294 (NsQuery->TryAgain)) 295 { 296 /* Save the error code so RAS doesn't overwrite it */ 297 OldErrorCode = GetLastError(); 298 299 /* Make sure we won't try for a 3rd time */ 300 NsQuery->TryAgain = FALSE; 301 302 /* Call the helper to auto-dial */ 303 if (WSAttemptAutodialName(NsQuery->QuerySet)) 304 { 305 /* It succeeded, so we'll delete the current state. */ 306 while (!IsListEmpty(&NsQuery->ProviderList)) 307 { 308 /* Remove the entry and get its provider */ 309 Entry = RemoveHeadList(&NsQuery->ProviderList); 310 Provider = CONTAINING_RECORD(Entry, 311 NSQUERY_PROVIDER, 312 QueryLink); 313 314 /* Reset it */ 315 WsNqProvLookupServiceEnd(Provider); 316 WsNqProvDelete(Provider); 317 } 318 319 /* Start a new query */ 320 if (WsNqLookupServiceBegin(NsQuery, 321 NsQuery->QuerySet, 322 NsQuery->ControlFlags, 323 NsQuery->Catalog) == ERROR_SUCCESS) 324 { 325 /* New query succeeded, set active provider now */ 326 NsQuery->ActiveProvider = 327 WsNqNextProvider(NsQuery, NsQuery->ActiveProvider); 328 } 329 } 330 else 331 { 332 /* Reset the error code */ 333 SetLastError(OldErrorCode); 334 } 335 } 336 337 /* Release lock */ 338 WsNqUnlock(); 339 } 340 341 /* Return */ 342 return ErrorCode; 343 } 344 345 DWORD 346 WSAAPI 347 WsNqLookupServiceBegin(IN PNSQUERY NsQuery, 348 IN LPWSAQUERYSETW Restrictions, 349 IN DWORD ControlFlags, 350 IN PNSCATALOG Catalog) 351 { 352 WSASERVICECLASSINFOW ClassInfo; 353 LPWSASERVICECLASSINFOW pClassInfo = &ClassInfo; 354 PNSQUERY_PROVIDER Provider, NextProvider; 355 PLIST_ENTRY Entry; 356 INT ErrorCode; 357 DWORD ClassInfoSize; 358 PNSCATALOG_ENTRY CatalogEntry = NULL; 359 ENUM_CONTEXT EnumContext; 360 BOOLEAN TryAgain; 361 362 /* Check for RAS Auto-dial attempt */ 363 if (NsQuery->TryAgain) 364 { 365 /* Make a copy of the query set */ 366 ErrorCode = CopyQuerySetW(Restrictions, &NsQuery->QuerySet); 367 TryAgain = (ErrorCode == ERROR_SUCCESS); 368 369 /* Check if we'll try again */ 370 if (!TryAgain) 371 { 372 /* We won't, fail */ 373 SetLastError(ErrorCode); 374 ErrorCode = SOCKET_ERROR; 375 NsQuery->TryAgain = FALSE; 376 goto Exit; 377 } 378 379 /* Cache the information for a restart */ 380 NsQuery->ControlFlags = ControlFlags; 381 NsQuery->Catalog = Catalog; 382 } 383 384 /* Check if we have a specific ID */ 385 if (Restrictions->lpNSProviderId) 386 { 387 /* Get the catalog entry */ 388 ErrorCode = WsNcGetCatalogFromProviderId(Catalog, 389 Restrictions->lpNSProviderId, 390 &CatalogEntry); 391 /* Check for failure */ 392 if (ErrorCode != ERROR_SUCCESS) 393 { 394 /* Fail */ 395 SetLastError(WSAEINVAL); 396 ErrorCode = SOCKET_ERROR; 397 goto Exit; 398 } 399 /* We succeeded, add this provider */ 400 else if (!WsNqAddProvider(NsQuery, CatalogEntry->Provider)) 401 { 402 /* Fail */ 403 SetLastError(WSA_NOT_ENOUGH_MEMORY); 404 ErrorCode = SOCKET_ERROR; 405 goto Exit; 406 } 407 } 408 else 409 { 410 /* Setup the lookup context */ 411 EnumContext.lpqsRestrictions = Restrictions; 412 EnumContext.ErrorCode = ERROR_SUCCESS; 413 EnumContext.NsQuery = NsQuery; 414 EnumContext.Catalog = Catalog; 415 416 /* Do a lookup for every entry */ 417 WsNcEnumerateCatalogItems(Catalog, 418 WsNqBeginEnumerationProc, 419 &EnumContext); 420 ErrorCode = EnumContext.ErrorCode; 421 422 /* Check for success */ 423 if (ErrorCode != ERROR_SUCCESS) 424 { 425 /* Fail */ 426 SetLastError(WSAEINVAL); 427 ErrorCode = SOCKET_ERROR; 428 goto Exit; 429 } 430 } 431 432 /* Get the class information */ 433 ClassInfo.lpServiceClassId = Restrictions->lpServiceClassId; 434 ErrorCode = WsNcGetServiceClassInfo(Catalog, &ClassInfoSize, pClassInfo); 435 436 /* Check if more buffer space is needed */ 437 if ((ErrorCode == SOCKET_ERROR) && (GetLastError() == WSAEFAULT)) 438 { 439 /* FIXME: The WS 2.2 spec hasn't been finalized yet on this... */ 440 } 441 else 442 { 443 /* Assume success */ 444 ErrorCode = ERROR_SUCCESS; 445 } 446 447 /* Check if the provider list is empty */ 448 if (IsListEmpty(&NsQuery->ProviderList)) 449 { 450 /* We don't have any providers to handle this! */ 451 ErrorCode = SOCKET_ERROR; 452 SetLastError(WSASERVICE_NOT_FOUND); 453 goto Exit; 454 } 455 456 /* Get the first provider and loop */ 457 Entry = NsQuery->ProviderList.Flink; 458 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink); 459 while (NextProvider) 460 { 461 /* Call it */ 462 ErrorCode = WsNqProvLookupServiceBegin(NextProvider, 463 Restrictions, 464 pClassInfo, 465 ControlFlags); 466 /* Check for error */ 467 if (ErrorCode == SOCKET_ERROR) 468 { 469 /* Remove this provider, get the next one, delete the old one */ 470 Provider = NextProvider; 471 NextProvider = WsNqNextProvider(NsQuery, NextProvider); 472 RemoveEntryList(&Provider->QueryLink); 473 WsNqProvDelete(Provider); 474 } 475 else 476 { 477 /* Get the next provider */ 478 NextProvider = WsNqNextProvider(NsQuery, NextProvider); 479 } 480 } 481 482 Exit: 483 /* Check if we had an error somewhere */ 484 if (ErrorCode == SOCKET_ERROR) 485 { 486 /* Loop the list */ 487 while (!IsListEmpty(&NsQuery->ProviderList)) 488 { 489 /* Remove this provider */ 490 Entry = RemoveHeadList(&NsQuery->ProviderList); 491 492 /* Get the failed provider and delete it */ 493 Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink); 494 WsNqProvDelete(Provider); 495 } 496 } 497 else 498 { 499 /* Set the active provider */ 500 Entry = NsQuery->ProviderList.Flink; 501 NsQuery->ActiveProvider = CONTAINING_RECORD(Entry, 502 NSQUERY_PROVIDER, 503 QueryLink); 504 } 505 506 /* Return */ 507 return ErrorCode; 508 } 509 510 PNSQUERY_PROVIDER 511 WSAAPI 512 WsNqNextProvider(IN PNSQUERY Query, 513 IN PNSQUERY_PROVIDER Provider) 514 { 515 PNSQUERY_PROVIDER NextProvider = NULL; 516 PLIST_ENTRY Entry; 517 518 /* Get the first entry and get its provider */ 519 Entry = Provider->QueryLink.Flink; 520 if (Entry != &Query->ProviderList) 521 { 522 /* Get the current provider */ 523 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink); 524 } 525 526 /* Return it */ 527 return NextProvider; 528 } 529 530 PNSQUERY_PROVIDER 531 WSAAPI 532 WsNqPreviousProvider(IN PNSQUERY Query, 533 IN PNSQUERY_PROVIDER Provider) 534 { 535 PNSQUERY_PROVIDER PrevProvider = NULL; 536 PLIST_ENTRY Entry; 537 538 /* Get the last entry and get its provider */ 539 Entry = Provider->QueryLink.Blink; 540 if (Entry != &Query->ProviderList) 541 { 542 /* Get the current provider */ 543 PrevProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink); 544 } 545 546 /* Return it */ 547 return PrevProvider; 548 } 549 550 BOOL 551 WSAAPI 552 WsNqAddProvider(IN PNSQUERY Query, 553 IN PNS_PROVIDER Provider) 554 { 555 BOOL Success = TRUE; 556 PNSQUERY_PROVIDER QueryProvider; 557 558 /* Allocate a new Query Provider */ 559 if ((QueryProvider = WsNqProvAllocate())) 560 { 561 /* Initialize it */ 562 WsNqProvInitialize(QueryProvider, Provider); 563 564 /* Insert it into the provider list */ 565 InsertTailList(&Query->ProviderList, &QueryProvider->QueryLink); 566 } 567 else 568 { 569 /* We failed */ 570 SetLastError(WSASYSCALLFAILURE); 571 Success = FALSE; 572 } 573 574 /* Return */ 575 return Success; 576 } 577 578