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