57dd8f1ca130a057d537f803891f18ef90caba1d
[reactos.git] / reactos / dll / win32 / ws2_32 / src / nscatalo.c
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((LPCRITICAL_SECTION)&Catalog->Lock);
19 #define WsNcUnlock() LeaveCriticalSection((LPCRITICAL_SECTION)&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((LPCRITICAL_SECTION)&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 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 */
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 (memcmp(&CatalogEntry->ProviderId,
463 &OldCatalogEntry->ProviderId,
464 sizeof(GUID)))
465 {
466 /* We have a match, use the old item instead */
467 WsNcEntryDereference(CatalogEntry);
468 CatalogEntry = OldCatalogEntry;
469 RemoveEntryList(&CatalogEntry->CatalogLink);
470
471 /* Decrease the number of protocols we have */
472 Catalog->ItemCount--;
473 break;
474 }
475 }
476
477 /* Add this item */
478 InsertTailList(&Catalog->CatalogList, &CatalogEntry->CatalogLink);
479 Catalog->ItemCount++;
480 }
481
482 /* If there's anything left on the temporary list */
483 while (!IsListEmpty(&TempList))
484 {
485 /* Get the entry */
486 Entry = RemoveHeadList(&TempList);
487 CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink);
488
489 /* Remove it */
490 Catalog->ItemCount--;
491 WsNcEntryDereference(CatalogEntry);
492 }
493 }
494
495 INT
496 WSAAPI
497 WsNcGetCatalogFromProviderId(IN PNSCATALOG Catalog,
498 IN LPGUID ProviderId,
499 OUT PNSCATALOG_ENTRY *CatalogEntry)
500 {
501 PLIST_ENTRY NextEntry = Catalog->CatalogList.Flink;
502 PNSCATALOG_ENTRY Entry;
503
504 /* Lock the catalog */
505 WsNcLock();
506
507 /* Match the Id with all the entries in the List */
508 while (NextEntry != &Catalog->CatalogList)
509 {
510 /* Get the Current Entry */
511 Entry = CONTAINING_RECORD(NextEntry, NSCATALOG_ENTRY, CatalogLink);
512 NextEntry = NextEntry->Flink;
513
514 /* Check if this is the Catalog Entry ID we want */
515 if (!(memcmp(&Entry->ProviderId, ProviderId, sizeof(GUID))))
516 {
517 /* Check if it doesn't already have a provider */
518 if (!Entry->Provider)
519 {
520 /* Match, load the Provider */
521 WsNcLoadProvider(Catalog, Entry);
522 }
523
524 /* Reference the entry and return it */
525 InterlockedIncrement(&Entry->RefCount);
526 *CatalogEntry = Entry;
527 break;
528 }
529 }
530
531 /* Release the catalog */
532 WsNcUnlock();
533
534 /* Return */
535 return ERROR_SUCCESS;
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 */
622 WsNcRemoveCatalogItem(Catalog, CatalogEntry);
623
624 /* Dereference it */
625 WsNcEntryDereference(CatalogEntry);
626
627 /* Move to the next entry */
628 Entry = Catalog->CatalogList.Flink;
629 }
630
631 /* Check if the catalog key is opened */
632 if (Catalog->CatalogKey)
633 {
634 /* Close it */
635 RegCloseKey(Catalog->CatalogKey);
636 Catalog->CatalogKey = NULL;
637 }
638
639 /* Release and delete the lock */
640 WsNcUnlock();
641 DeleteCriticalSection((LPCRITICAL_SECTION)&Catalog->Lock);
642
643 /* Delete the object */
644 HeapFree(WsSockHeap, 0, Catalog);
645 }