1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS WinSock 2 API 4 * FILE: dll/win32/ws2_32/src/nscatalo.c 5 * PURPOSE: Namespace Catalog Object 6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ws2_32.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* DATA **********************************************************************/ 17 18 #define WsNcLock() EnterCriticalSection(&Catalog->Lock) 19 #define WsNcUnlock() LeaveCriticalSection(&Catalog->Lock) 20 21 /* FUNCTIONS *****************************************************************/ 22 23 PNSCATALOG 24 WSAAPI 25 WsNcAllocate(VOID) 26 { 27 PNSCATALOG Catalog; 28 29 /* Allocate the catalog */ 30 Catalog = HeapAlloc(WsSockHeap, HEAP_ZERO_MEMORY, sizeof(*Catalog)); 31 32 /* Return it */ 33 return Catalog; 34 } 35 36 BOOLEAN 37 WSAAPI 38 WsNcOpen(IN PNSCATALOG Catalog, 39 IN HKEY ParentKey) 40 { 41 LONG ErrorCode; 42 DWORD CreateDisposition; 43 HKEY CatalogKey, NewKey; 44 DWORD RegType = REG_DWORD; 45 DWORD RegSize = sizeof(DWORD); 46 DWORD UniqueId = 0; 47 DWORD NewData = 0; 48 CHAR* CatalogKeyName; 49 50 /* Initialize the catalog lock and namespace list */ 51 InitializeCriticalSection(&Catalog->Lock); 52 InitializeListHead(&Catalog->CatalogList); 53 54 /* Read the catalog name */ 55 ErrorCode = RegQueryValueEx(ParentKey, 56 "Current_NameSpace_Catalog", 57 0, 58 &RegType, 59 NULL, 60 &RegSize); 61 if (ErrorCode == ERROR_FILE_NOT_FOUND) 62 { 63 static const CHAR DefaultCatalogName[] = "NameSpace_Catalog5"; 64 RegSize = sizeof(DefaultCatalogName); 65 CatalogKeyName = HeapAlloc(WsSockHeap, 0, RegSize); 66 memcpy(CatalogKeyName, DefaultCatalogName, RegSize); 67 } 68 else 69 { 70 if (ErrorCode != ERROR_SUCCESS) 71 { 72 DPRINT1("Failed to get namespace catalog name: %d.\n", ErrorCode); 73 return FALSE; 74 } 75 76 if (RegType != REG_SZ) 77 { 78 DPRINT1("Namespace catalog name is not a string (Type %d).\n", RegType); 79 return FALSE; 80 } 81 82 CatalogKeyName = HeapAlloc(WsSockHeap, 0, RegSize); 83 84 /* Read the catalog name */ 85 ErrorCode = RegQueryValueEx(ParentKey, 86 "Current_NameSpace_Catalog", 87 0, 88 &RegType, 89 (LPBYTE)CatalogKeyName, 90 &RegSize); 91 92 /* Open the Catalog Key */ 93 ErrorCode = RegOpenKeyEx(ParentKey, 94 CatalogKeyName, 95 0, 96 MAXIMUM_ALLOWED, 97 &CatalogKey); 98 } 99 100 /* If we didn't find the key, create it */ 101 if (ErrorCode == ERROR_SUCCESS) 102 { 103 /* Fake that we opened an existing key */ 104 CreateDisposition = REG_OPENED_EXISTING_KEY; 105 } 106 else if (ErrorCode == ERROR_FILE_NOT_FOUND) 107 { 108 /* Create the Catalog Name */ 109 ErrorCode = RegCreateKeyEx(ParentKey, 110 CatalogKeyName, 111 0, 112 NULL, 113 REG_OPTION_NON_VOLATILE, 114 KEY_ALL_ACCESS, 115 NULL, 116 &CatalogKey, 117 &CreateDisposition); 118 } 119 120 HeapFree(WsSockHeap, 0, CatalogKeyName); 121 RegType = REG_DWORD; 122 RegSize = sizeof(DWORD); 123 124 /* Fail if that didn't work */ 125 if (ErrorCode != ERROR_SUCCESS) return FALSE; 126 127 /* Check if we had to create the key */ 128 if (CreateDisposition == REG_CREATED_NEW_KEY) 129 { 130 /* Write the count of entries (0 now) */ 131 ErrorCode = RegSetValueEx(CatalogKey, 132 "Num_Catalog_Entries", 133 0, 134 REG_DWORD, 135 (LPBYTE)&NewData, 136 sizeof(NewData)); 137 if (ErrorCode != ERROR_SUCCESS) 138 { 139 /* Close the key and fail */ 140 RegCloseKey(CatalogKey); 141 return FALSE; 142 } 143 144 /* Write the first catalog entry Uniqe ID */ 145 NewData = 1; 146 ErrorCode = RegSetValueEx(CatalogKey, 147 "Serial_Access_Num", 148 0, 149 REG_DWORD, 150 (LPBYTE)&NewData, 151 sizeof(NewData)); 152 if (ErrorCode != ERROR_SUCCESS) 153 { 154 /* Close the key and fail */ 155 RegCloseKey(CatalogKey); 156 return FALSE; 157 } 158 159 /* Create a key for this entry */ 160 ErrorCode = RegCreateKeyEx(CatalogKey, 161 "Catalog_Entries", 162 0, 163 NULL, 164 REG_OPTION_NON_VOLATILE, 165 KEY_ALL_ACCESS, 166 NULL, 167 &NewKey, 168 &CreateDisposition); 169 if (ErrorCode != ERROR_SUCCESS) 170 { 171 /* Close the key and fail */ 172 RegCloseKey(CatalogKey); 173 return FALSE; 174 } 175 176 /* Close the key since we don't need it */ 177 RegCloseKey(NewKey); 178 } 179 else 180 { 181 RegSize = sizeof(UniqueId); 182 /* Read the serial number */ 183 ErrorCode = RegQueryValueEx(CatalogKey, 184 "Serial_Access_Num", 185 0, 186 &RegType, 187 (LPBYTE)&UniqueId, 188 &RegSize); 189 190 /* Check if it's missing for some reason */ 191 if (ErrorCode != ERROR_SUCCESS) 192 { 193 /* Write the first catalog entry Unique ID */ 194 NewData = 1; 195 ErrorCode = RegSetValueEx(CatalogKey, 196 "Serial_Access_Num", 197 0, 198 REG_DWORD, 199 (LPBYTE)&NewData, 200 sizeof(NewData)); 201 } 202 } 203 204 /* Set the Catalog Key */ 205 Catalog->CatalogKey = CatalogKey; 206 return TRUE; 207 } 208 209 INT 210 WSAAPI 211 WsNcInitializeFromRegistry(IN PNSCATALOG Catalog, 212 IN HKEY ParentKey, 213 IN HANDLE CatalogEvent) 214 { 215 INT ErrorCode = WSASYSCALLFAILURE; 216 217 /* Open the catalog */ 218 if (WsNcOpen(Catalog, ParentKey)) 219 { 220 /* Refresh it */ 221 ErrorCode = WsNcRefreshFromRegistry(Catalog, CatalogEvent); 222 } 223 224 /* Return the status */ 225 return ErrorCode; 226 } 227 228 INT 229 WSAAPI 230 WsNcRefreshFromRegistry(IN PNSCATALOG Catalog, 231 IN HANDLE CatalogEvent) 232 { 233 INT ErrorCode; 234 BOOLEAN LocalEvent = FALSE; 235 LIST_ENTRY LocalList; 236 DWORD UniqueId; 237 HKEY EntriesKey; 238 DWORD CatalogEntries; 239 PNSCATALOG_ENTRY CatalogEntry; 240 BOOL NewChangesMade; 241 PLIST_ENTRY Entry; 242 DWORD RegType = REG_DWORD; 243 DWORD RegSize = sizeof(DWORD); 244 DWORD i; 245 246 /* Check if we got an event */ 247 if (!CatalogEvent) 248 { 249 /* Create an event ourselves */ 250 CatalogEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 251 if (!CatalogEvent) return WSASYSCALLFAILURE; 252 LocalEvent = TRUE; 253 } 254 255 /* Lock the catalog */ 256 WsNcLock(); 257 258 /* Initialize our local list for the loop */ 259 InitializeListHead(&LocalList); 260 261 /* Start looping */ 262 do 263 { 264 /* Setup notifications for the catalog entry */ 265 ErrorCode = WsSetupCatalogProtection(Catalog->CatalogKey, 266 CatalogEvent, 267 &UniqueId); 268 if (ErrorCode != ERROR_SUCCESS) break; 269 270 /* Check if we've changed till now */ 271 if (UniqueId == Catalog->UniqueId) 272 { 273 /* We haven't, so return */ 274 ErrorCode = ERROR_SUCCESS; 275 break; 276 } 277 278 /* Now Open the Entries */ 279 ErrorCode = RegOpenKeyEx(Catalog->CatalogKey, 280 "Catalog_Entries", 281 0, 282 MAXIMUM_ALLOWED, 283 &EntriesKey); 284 if (ErrorCode != ERROR_SUCCESS) 285 { 286 /* Critical failure */ 287 ErrorCode = WSASYSCALLFAILURE; 288 break; 289 } 290 291 /* Find out how many there are */ 292 ErrorCode = RegQueryValueEx(Catalog->CatalogKey, 293 "Num_Catalog_Entries", 294 0, 295 &RegType, 296 (LPBYTE)&CatalogEntries, 297 &RegSize); 298 if (ErrorCode != ERROR_SUCCESS) 299 { 300 /* Critical failure */ 301 ErrorCode = WSASYSCALLFAILURE; 302 break; 303 } 304 305 /* Initialize them all */ 306 for (i = 1; i <= CatalogEntries; i++) 307 { 308 /* Allocate a Catalog Entry Structure */ 309 CatalogEntry = WsNcEntryAllocate(); 310 if (!CatalogEntry) 311 { 312 /* Not enough memory, fail */ 313 ErrorCode = WSA_NOT_ENOUGH_MEMORY; 314 break; 315 } 316 317 /* Initialize it from the Registry Key */ 318 ErrorCode = WsNcEntryInitializeFromRegistry(CatalogEntry, 319 EntriesKey, 320 i); 321 if (ErrorCode != ERROR_SUCCESS) 322 { 323 /* We failed to get it, dereference the entry and leave */ 324 WsNcEntryDereference(CatalogEntry); 325 break; 326 } 327 328 /* Insert it to our List */ 329 InsertTailList(&LocalList, &CatalogEntry->CatalogLink); 330 } 331 332 /* Close the catalog key */ 333 RegCloseKey(EntriesKey); 334 335 /* Check if we changed during our read and if we have success */ 336 NewChangesMade = WsCheckCatalogState(CatalogEvent); 337 if (!NewChangesMade && ErrorCode == ERROR_SUCCESS) 338 { 339 /* All is good, update the protocol list */ 340 WsNcUpdateNamespaceList(Catalog, &LocalList); 341 342 /* Update and return */ 343 Catalog->UniqueId = UniqueId; 344 break; 345 } 346 347 /* We failed and/or catalog data changed, free what we did till now */ 348 while (!IsListEmpty(&LocalList)) 349 { 350 /* Get the LP Catalog Item */ 351 Entry = RemoveHeadList(&LocalList); 352 CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink); 353 354 /* Dereference it */ 355 WsNcEntryDereference(CatalogEntry); 356 } 357 } while (NewChangesMade); 358 359 /* Release the lock */ 360 WsNcUnlock(); 361 362 /* Close the event, if any was created by us */ 363 if (LocalEvent) CloseHandle(CatalogEvent); 364 365 /* All Done */ 366 return ErrorCode; 367 } 368 369 VOID 370 WSAAPI 371 WsNcEnumerateCatalogItems(IN PNSCATALOG Catalog, 372 IN PNSCATALOG_ENUMERATE_PROC Callback, 373 IN PVOID Context) 374 { 375 PLIST_ENTRY Entry; 376 PNSCATALOG_ENTRY CatalogEntry; 377 BOOL GoOn = TRUE; 378 379 /* Lock the catalog */ 380 WsNcLock(); 381 382 /* Loop the entries */ 383 Entry = Catalog->CatalogList.Flink; 384 while (GoOn && (Entry != &Catalog->CatalogList)) 385 { 386 /* Get the entry */ 387 CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink); 388 389 /* Move to the next one and call the callback */ 390 Entry = Entry->Flink; 391 GoOn = Callback(Context, CatalogEntry); 392 } 393 394 /* Release the lock */ 395 WsNcUnlock(); 396 } 397 398 INT 399 WSAAPI 400 WsNcLoadProvider(IN PNSCATALOG Catalog, 401 IN PNSCATALOG_ENTRY CatalogEntry) 402 { 403 INT ErrorCode = ERROR_SUCCESS; 404 PNS_PROVIDER Provider; 405 406 /* Lock the catalog */ 407 WsNcLock(); 408 409 /* Check if we have a provider already */ 410 if (!CatalogEntry->Provider) 411 { 412 /* Allocate a provider */ 413 if ((Provider = WsNpAllocate())) 414 { 415 /* Initialize it */ 416 ErrorCode = WsNpInitialize(Provider, 417 CatalogEntry->DllPath, 418 &CatalogEntry->ProviderId); 419 420 /* Ensure success */ 421 if (ErrorCode == ERROR_SUCCESS) 422 { 423 /* Set the provider */ 424 WsNcEntrySetProvider(CatalogEntry, Provider); 425 } 426 427 /* Dereference it */ 428 WsNpDereference(Provider); 429 } 430 else 431 { 432 /* No memory */ 433 ErrorCode = WSA_NOT_ENOUGH_MEMORY; 434 } 435 } 436 437 /* Release the lock and return */ 438 WsNcUnlock(); 439 return ErrorCode; 440 } 441 442 INT 443 WSAAPI 444 WsNcGetServiceClassInfo(IN PNSCATALOG Catalog, 445 IN OUT LPDWORD BugSize, 446 IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo) 447 { 448 /* Not yet implemented in the spec? */ 449 SetLastError(ERROR_SUCCESS); 450 return SOCKET_ERROR; 451 } 452 453 VOID 454 WSAAPI 455 WsNcUpdateNamespaceList(IN PNSCATALOG Catalog, 456 IN PLIST_ENTRY List) 457 { 458 LIST_ENTRY TempList; 459 PNSCATALOG_ENTRY CatalogEntry, OldCatalogEntry; 460 PLIST_ENTRY Entry; 461 462 /* First move from our list to the old one */ 463 InsertHeadList(&Catalog->CatalogList, &TempList); 464 RemoveEntryList(&Catalog->CatalogList); 465 InitializeListHead(&Catalog->CatalogList); 466 467 /* Loop every item on the list */ 468 while (!IsListEmpty(List)) 469 { 470 /* Get the catalog entry */ 471 Entry = RemoveHeadList(List); 472 CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink); 473 474 /* Check if this item is already on our list */ 475 Entry = TempList.Flink; 476 while (Entry != &TempList) 477 { 478 /* Get the catalog entry */ 479 OldCatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink); 480 Entry = Entry->Flink; 481 482 /* Check if they match */ 483 if (IsEqualGUID(&CatalogEntry->ProviderId, 484 &OldCatalogEntry->ProviderId)) 485 { 486 /* We have a match, use the old item instead */ 487 WsNcEntryDereference(CatalogEntry); 488 CatalogEntry = OldCatalogEntry; 489 RemoveEntryList(&CatalogEntry->CatalogLink); 490 491 /* Decrease the number of protocols we have */ 492 Catalog->ItemCount--; 493 break; 494 } 495 } 496 497 /* Add this item */ 498 InsertTailList(&Catalog->CatalogList, &CatalogEntry->CatalogLink); 499 Catalog->ItemCount++; 500 } 501 502 /* If there's anything left on the temporary list */ 503 while (!IsListEmpty(&TempList)) 504 { 505 /* Get the entry */ 506 Entry = RemoveHeadList(&TempList); 507 CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink); 508 509 /* Remove it */ 510 Catalog->ItemCount--; 511 WsNcEntryDereference(CatalogEntry); 512 } 513 } 514 515 INT 516 WSAAPI 517 WsNcGetCatalogFromProviderId(IN PNSCATALOG Catalog, 518 IN LPGUID ProviderId, 519 OUT PNSCATALOG_ENTRY *CatalogEntry) 520 { 521 INT ErrorCode = WSAEINVAL; 522 PLIST_ENTRY NextEntry; 523 PNSCATALOG_ENTRY Entry; 524 525 /* Lock the catalog */ 526 WsNcLock(); 527 528 /* Match the Id with all the entries in the List */ 529 NextEntry = Catalog->CatalogList.Flink; 530 while (NextEntry != &Catalog->CatalogList) 531 { 532 /* Get the Current Entry */ 533 Entry = CONTAINING_RECORD(NextEntry, NSCATALOG_ENTRY, CatalogLink); 534 NextEntry = NextEntry->Flink; 535 536 /* Check if this is the Catalog Entry ID we want */ 537 if (IsEqualGUID(&Entry->ProviderId, ProviderId)) 538 { 539 /* If it doesn't already have a provider, load the provider */ 540 if (!Entry->Provider) 541 ErrorCode = WsNcLoadProvider(Catalog, Entry); 542 543 /* If we succeeded, reference the entry and return it */ 544 if (Entry->Provider /* || ErrorCode == ERROR_SUCCESS */) 545 { 546 InterlockedIncrement(&Entry->RefCount); 547 *CatalogEntry = Entry; 548 ErrorCode = ERROR_SUCCESS; 549 break; 550 } 551 } 552 } 553 554 /* Release the lock and return */ 555 WsNcUnlock(); 556 return ErrorCode; 557 } 558 559 BOOL 560 WSAAPI 561 WsNcMatchProtocols(IN DWORD NameSpace, 562 IN LONG AddressFamily, 563 IN LPWSAQUERYSETW QuerySet) 564 { 565 DWORD ProtocolCount = QuerySet->dwNumberOfProtocols; 566 LPAFPROTOCOLS AfpProtocols = QuerySet->lpafpProtocols; 567 LONG Family; 568 569 /* Check for valid family */ 570 if (AddressFamily != -1) 571 { 572 /* Check if it's the magic */ 573 if (AddressFamily == AF_UNSPEC) return TRUE; 574 Family = AddressFamily; 575 } 576 else 577 { 578 /* No family given, check for namespace */ 579 if (NameSpace == NS_SAP) 580 { 581 /* Use IPX family */ 582 Family = AF_IPX; 583 } 584 else 585 { 586 /* Other namespace, it's valid */ 587 return TRUE; 588 } 589 } 590 591 /* Now try to get a match */ 592 while (ProtocolCount--) 593 { 594 /* Check this protocol entry */ 595 if ((AfpProtocols->iAddressFamily == AF_UNSPEC) || 596 (AfpProtocols->iAddressFamily == Family)) 597 { 598 /* Match found */ 599 return TRUE; 600 } 601 602 /* Move to the next one */ 603 AfpProtocols++; 604 } 605 606 /* No match */ 607 return FALSE; 608 } 609 610 VOID 611 WSAAPI 612 WsNcRemoveCatalogItem(IN PNSCATALOG Catalog, 613 IN PNSCATALOG_ENTRY Entry) 614 { 615 /* Remove the entry from the list */ 616 RemoveEntryList(&Entry->CatalogLink); 617 618 /* Decrease our count */ 619 Catalog->ItemCount--; 620 } 621 622 VOID 623 WSAAPI 624 WsNcDelete(IN PNSCATALOG Catalog) 625 { 626 PLIST_ENTRY Entry; 627 PNSCATALOG_ENTRY CatalogEntry; 628 629 /* Check if we're initialized */ 630 if (!Catalog->CatalogList.Flink) return; 631 632 /* Acquire lock */ 633 WsNcLock(); 634 635 /* Loop every entry */ 636 Entry = Catalog->CatalogList.Flink; 637 while (Entry != &Catalog->CatalogList) 638 { 639 /* Get this entry */ 640 CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink); 641 642 /* Remove it and dereference it */ 643 WsNcRemoveCatalogItem(Catalog, CatalogEntry); 644 WsNcEntryDereference(CatalogEntry); 645 646 /* Move to the next entry */ 647 Entry = Catalog->CatalogList.Flink; 648 } 649 650 /* Check if the catalog key is opened */ 651 if (Catalog->CatalogKey) 652 { 653 /* Close it */ 654 RegCloseKey(Catalog->CatalogKey); 655 Catalog->CatalogKey = NULL; 656 } 657 658 /* Release and delete the lock */ 659 WsNcUnlock(); 660 DeleteCriticalSection(&Catalog->Lock); 661 662 /* Delete the object */ 663 HeapFree(WsSockHeap, 0, Catalog); 664 } 665