xref: /reactos/dll/win32/ws2_32/src/rnr.c (revision b8dd046e)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock 2 API
4  * FILE:        dll/win32/ws2_32_new/src/rnr.c
5  * PURPOSE:     Registration and Resolution Support
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 /* FUNCTIONS *****************************************************************/
17 
18 /*
19  * @implemented
20  */
21 INT
22 WSAAPI
23 WSAAddressToStringA(IN LPSOCKADDR lpsaAddress,
24                     IN DWORD dwAddressLength,
25                     IN LPWSAPROTOCOL_INFOA lpProtocolInfo,
26                     OUT LPSTR lpszAddressString,
27                     IN OUT  LPDWORD lpdwAddressStringLength)
28 {
29     PWSPROCESS Process;
30     PWSTHREAD Thread;
31     INT ErrorCode, Status;
32     DWORD CatalogEntryId;
33     PTCATALOG Catalog;
34     PTCATALOG_ENTRY CatalogEntry;
35     LPWSTR UnicodeString;
36     DWORD Length = *lpdwAddressStringLength;
37 
38     DPRINT("WSAAddressToStringA: %p\n", lpsaAddress);
39 
40     /* Enter prolog */
41     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
42     {
43         /* Leave now */
44         SetLastError(ErrorCode);
45         return SOCKET_ERROR;
46     }
47 
48     /* Allocate the unicode string */
49     UnicodeString = HeapAlloc(WsSockHeap, 0, Length * 2);
50     if (!UnicodeString)
51     {
52         /* No memory; fail */
53         SetLastError(WSAENOBUFS);
54         return SOCKET_ERROR;
55     }
56 
57     /* Get the catalog */
58     Catalog = WsProcGetTCatalog(Process);
59 
60     /* Check if we got custom protocol info */
61     if (lpProtocolInfo)
62     {
63         /* Get the entry ID */
64         CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
65 
66         /* Get the entry associated with it */
67         ErrorCode = WsTcGetEntryFromCatalogEntryId(Catalog,
68                                                    CatalogEntryId,
69                                                    &CatalogEntry);
70     }
71     else
72     {
73         /* Get it from the address family */
74         ErrorCode = WsTcGetEntryFromAf(Catalog,
75                                        lpsaAddress->sa_family,
76                                        &CatalogEntry);
77     }
78 
79     /* Check for success */
80     if (ErrorCode == ERROR_SUCCESS)
81     {
82         /* Call the provider */
83         Status = CatalogEntry->Provider->Service.lpWSPAddressToString(lpsaAddress,
84                                                                       dwAddressLength,
85                                                                       &CatalogEntry->
86                                                                       ProtocolInfo,
87                                                                       UnicodeString,
88                                                                       lpdwAddressStringLength,
89                                                                       &ErrorCode);
90         if (Status == ERROR_SUCCESS)
91         {
92             /* Convert the string */
93             WideCharToMultiByte(CP_ACP,
94                                 0,
95                                 UnicodeString,
96                                 -1,
97                                 lpszAddressString,
98                                 Length,
99                                 NULL,
100                                 NULL);
101         }
102 
103         /* Dereference the entry */
104         WsTcEntryDereference(CatalogEntry);
105 
106         /* Free the unicode string */
107         HeapFree(WsSockHeap, 0, UnicodeString);
108 
109         /* Check for success and return */
110         if (Status == ERROR_SUCCESS) return ERROR_SUCCESS;
111     }
112     else
113     {
114         /* Free the unicode string */
115         HeapFree(WsSockHeap, 0, UnicodeString);
116     }
117 
118     /* Set the error and return */
119     SetLastError(ErrorCode);
120     return SOCKET_ERROR;
121 }
122 
123 /*
124  * @implemented
125  */
126 INT
127 WSAAPI
128 WSAAddressToStringW(IN LPSOCKADDR lpsaAddress,
129                     IN DWORD dwAddressLength,
130                     IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
131                     OUT LPWSTR lpszAddressString,
132                     IN OUT LPDWORD lpdwAddressStringLength)
133 {
134     PWSPROCESS Process;
135     PWSTHREAD Thread;
136     INT ErrorCode, Status;
137     DWORD CatalogEntryId;
138     PTCATALOG Catalog;
139     PTCATALOG_ENTRY CatalogEntry;
140 
141     DPRINT("WSAAddressToStringW: %p\n", lpsaAddress);
142 
143     /* Enter prolog */
144     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
145     {
146         /* Leave now */
147         SetLastError(ErrorCode);
148         return SOCKET_ERROR;
149     }
150 
151     /* Get the catalog */
152     Catalog = WsProcGetTCatalog(Process);
153 
154     /* Check if we got custom protocol info */
155     if (lpProtocolInfo)
156     {
157         /* Get the entry ID */
158         CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
159 
160         /* Get the entry associated with it */
161         ErrorCode = WsTcGetEntryFromCatalogEntryId(Catalog,
162                                                    CatalogEntryId,
163                                                    &CatalogEntry);
164     }
165     else
166     {
167         /* Get it from the address family */
168         ErrorCode = WsTcGetEntryFromAf(Catalog,
169                                        lpsaAddress->sa_family,
170                                        &CatalogEntry);
171     }
172 
173     /* Check for success */
174     if (ErrorCode == ERROR_SUCCESS)
175     {
176         /* Call the provider */
177         Status = CatalogEntry->Provider->Service.lpWSPAddressToString(lpsaAddress,
178                                                                       dwAddressLength,
179                                                                       &CatalogEntry->
180                                                                       ProtocolInfo,
181                                                                       lpszAddressString,
182                                                                       lpdwAddressStringLength,
183                                                                       &ErrorCode);
184 
185         /* Dereference the entry */
186         WsTcEntryDereference(CatalogEntry);
187 
188         /* Check for success and return */
189         if (Status == ERROR_SUCCESS) return ERROR_SUCCESS;
190     }
191 
192     /* Set the error and return */
193     SetLastError(ErrorCode);
194     return SOCKET_ERROR;
195 }
196 
197 /*
198  * @implemented
199  */
200 INT
201 WSAAPI
202 WSALookupServiceEnd(IN HANDLE hLookup)
203 {
204     PWSPROCESS Process;
205     PWSTHREAD Thread;
206     INT ErrorCode;
207     PNSQUERY Query = hLookup;
208 
209     DPRINT("WSALookupServiceEnd: %lx\n", hLookup);
210 
211     /* Enter prolog */
212     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
213     {
214         /* Leave now */
215         SetLastError(ErrorCode);
216         return SOCKET_ERROR;
217     }
218 
219     /* Check for a valid handle, then validate and reference it */
220     if (IsBadReadPtr(Query, sizeof(*Query)) || !WsNqValidateAndReference(Query))
221     {
222         /* Fail */
223         SetLastError(WSA_INVALID_HANDLE);
224         return SOCKET_ERROR;
225     }
226 
227     /* Do the lookup */
228     ErrorCode = WsNqLookupServiceEnd(Query);
229 
230     /* Remove the validation reference */
231     WsNqDereference(Query);
232 
233     /* Remove the keep-alive */
234     WsNqDereference(Query);
235 
236     /* Return */
237     return ERROR_SUCCESS;
238 }
239 
240 /*
241  * @implemented
242  */
243 INT
244 WSAAPI
245 WSALookupServiceBeginA(IN LPWSAQUERYSETA lpqsRestrictions,
246                        IN DWORD dwControlFlags,
247                        OUT LPHANDLE lphLookup)
248 {
249     INT ErrorCode;
250     LPWSAQUERYSETW UnicodeQuerySet = NULL;
251     SIZE_T UnicodeQuerySetSize = 0;
252 
253     DPRINT("WSALookupServiceBeginA: %p\n", lpqsRestrictions);
254 
255     /* Verify pointer */
256     if (IsBadReadPtr(lpqsRestrictions, sizeof(*lpqsRestrictions)) ||
257         IsBadReadPtr(lpqsRestrictions->lpServiceClassId, sizeof(*lpqsRestrictions->lpServiceClassId)))
258     {
259         /* Invalid */
260         SetLastError(WSAEFAULT);
261         return SOCKET_ERROR;
262     }
263 
264     /* Clear the reserved fields */
265     lpqsRestrictions->dwOutputFlags = 0;
266     lpqsRestrictions->lpszComment = NULL;
267     lpqsRestrictions->dwNumberOfCsAddrs = 0;
268 
269     /* Find out the side we'll need */
270     ErrorCode = MapAnsiQuerySetToUnicode(lpqsRestrictions,
271                                          &UnicodeQuerySetSize,
272                                          UnicodeQuerySet);
273 
274     /* We should've failed */
275     if (ErrorCode == WSAEFAULT)
276     {
277         /* Allocate the buffer we'll need */
278         UnicodeQuerySet = HeapAlloc(WsSockHeap, 0, UnicodeQuerySetSize);
279         if (UnicodeQuerySet)
280         {
281             /* Do the conversion for real */
282             ErrorCode = MapAnsiQuerySetToUnicode(lpqsRestrictions,
283                                                  &UnicodeQuerySetSize,
284                                                  UnicodeQuerySet);
285             if (ErrorCode == ERROR_SUCCESS)
286             {
287                 /* Now call the Unicode function */
288                 ErrorCode = WSALookupServiceBeginW(UnicodeQuerySet,
289                                                    dwControlFlags,
290                                                    lphLookup);
291             }
292 
293             /* Free our buffer */
294             HeapFree(WsSockHeap, 0, UnicodeQuerySet);
295         }
296         else
297         {
298             /* No memory to allocate */
299             ErrorCode = WSAEFAULT;
300         }
301     }
302 
303     /* Set the error in case of failure */
304     if (ErrorCode != ERROR_SUCCESS)
305         SetLastError(ErrorCode);
306 
307     /* Return to caller */
308     return ErrorCode == ERROR_SUCCESS ? ErrorCode : SOCKET_ERROR;
309 }
310 
311 /*
312  * @implemented
313  */
314 INT
315 WINAPI
316 WSALookupServiceBeginW(IN LPWSAQUERYSETW lpqsRestrictions,
317                        IN DWORD dwControlFlags,
318                        OUT LPHANDLE lphLookup)
319 {
320     PWSPROCESS Process;
321     PWSTHREAD Thread;
322     INT ErrorCode;
323     PNSQUERY Query;
324 
325     DPRINT("WSALookupServiceBeginW: %p\n", lpqsRestrictions);
326 
327     /* Enter prolog */
328     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
329     {
330         /* Leave now */
331         SetLastError(ErrorCode);
332         return SOCKET_ERROR;
333     }
334 
335     /* Verify pointers */
336     if (IsBadWritePtr(lphLookup, sizeof(*lphLookup)) ||
337         IsBadReadPtr(lpqsRestrictions, sizeof(*lpqsRestrictions)) ||
338         IsBadReadPtr(lpqsRestrictions->lpServiceClassId, sizeof(*lpqsRestrictions->lpServiceClassId)))
339     {
340         /* They are invalid; fail */
341         SetLastError(WSAEFAULT);
342         return SOCKET_ERROR;
343     }
344 
345     /* Create a new query object */
346     if ((Query = WsNqAllocate()))
347     {
348         /* Initialize it */
349         WsNqInitialize(Query);
350 
351         /* Do the lookup */
352         ErrorCode = WsNqLookupServiceBegin(Query,
353                                            lpqsRestrictions,
354                                            dwControlFlags,
355                                            WsProcGetNsCatalog(Process));
356 
357         /* Check for success */
358         if (ErrorCode == ERROR_SUCCESS)
359         {
360             /* Return the handle */
361             *lphLookup = Query;
362         }
363         else
364         {
365             /* Fail */
366             *lphLookup = NULL;
367             WsNqDelete(Query);
368         }
369     }
370     else
371     {
372         /* No memory */
373         ErrorCode = SOCKET_ERROR;
374         SetLastError(WSAENOBUFS);
375     }
376 
377     /* Return */
378     return ErrorCode;
379 }
380 
381 /*
382  * @implemented
383  */
384 INT
385 WINAPI
386 WSALookupServiceNextW(IN HANDLE hLookup,
387                       IN DWORD dwControlFlags,
388                       IN OUT LPDWORD lpdwBufferLength,
389                       OUT LPWSAQUERYSETW lpqsResults)
390 {
391     PWSPROCESS Process;
392     PWSTHREAD Thread;
393     INT ErrorCode;
394     PNSQUERY Query = hLookup;
395 
396     DPRINT("WSALookupServiceNextW: %lx\n", hLookup);
397 
398     /* Enter prolog */
399     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
400     {
401         /* Leave now */
402         SetLastError(ErrorCode);
403         return SOCKET_ERROR;
404     }
405 
406     /*
407      * Verify pointers. Note that the size of the buffer
408      * pointed by lpqsResults is given by *lpdwBufferLength.
409      */
410     if (IsBadReadPtr(lpdwBufferLength, sizeof(*lpdwBufferLength)) ||
411         IsBadWritePtr(lpqsResults, *lpdwBufferLength))
412     {
413         /* It is invalid; fail */
414         SetLastError(WSAEFAULT);
415         return SOCKET_ERROR;
416     }
417 
418     /* Check for a valid handle, then validate and reference it */
419     if (IsBadReadPtr(Query, sizeof(*Query)) || !WsNqValidateAndReference(Query))
420     {
421         /* Fail */
422         SetLastError(WSA_INVALID_HANDLE);
423         return SOCKET_ERROR;
424     }
425 
426     /* Do the lookup */
427     ErrorCode = WsNqLookupServiceNext(Query,
428                                       dwControlFlags,
429                                       lpdwBufferLength,
430                                       lpqsResults);
431 
432     /* Remove the validation reference */
433     WsNqDereference(Query);
434 
435     /* Return */
436     return ErrorCode;
437 }
438 
439 /*
440  * @implemented
441  */
442 INT
443 WSAAPI
444 WSALookupServiceNextA(IN HANDLE hLookup,
445                       IN DWORD dwControlFlags,
446                       IN OUT LPDWORD lpdwBufferLength,
447                       OUT LPWSAQUERYSETA lpqsResults)
448 {
449     LPWSAQUERYSETW UnicodeQuerySet;
450     DWORD UnicodeQuerySetSize;
451     INT ErrorCode;
452 
453     DPRINT("WSALookupServiceNextA: %lx\n", hLookup);
454 
455     /*
456      * Verify pointers. Note that the size of the buffer
457      * pointed by lpqsResults is given by *lpdwBufferLength.
458      */
459     if (IsBadReadPtr(lpdwBufferLength, sizeof(*lpdwBufferLength)) ||
460         IsBadWritePtr(lpqsResults, *lpdwBufferLength))
461     {
462         /* It is invalid; fail */
463         SetLastError(WSAEFAULT);
464         return SOCKET_ERROR;
465     }
466 
467     UnicodeQuerySetSize = *lpdwBufferLength;
468 
469     /* Check how much the user is giving */
470     if (UnicodeQuerySetSize >= sizeof(WSAQUERYSETW))
471     {
472         /* Allocate the buffer we'll use */
473         UnicodeQuerySet = HeapAlloc(WsSockHeap, 0, UnicodeQuerySetSize);
474         if (!UnicodeQuerySet)
475         {
476             /*
477              * We failed, possibly because the specified size was too large?
478              * Retrieve the needed buffer size with the WSALookupServiceNextW
479              * call and retry again a second time.
480              */
481             UnicodeQuerySetSize = 0;
482         }
483     }
484     else
485     {
486         /*
487          * The buffer is too small. Retrieve the needed buffer size with
488          * the WSALookupServiceNextW call and return it to the caller.
489          */
490         UnicodeQuerySet = NULL;
491         UnicodeQuerySetSize = 0;
492     }
493 
494     /* Call the Unicode Function */
495     ErrorCode = WSALookupServiceNextW(hLookup,
496                                       dwControlFlags,
497                                       &UnicodeQuerySetSize,
498                                       UnicodeQuerySet);
499 
500     /*
501      * Check whether we actually just retrieved the needed buffer size
502      * because our previous local allocation did fail. If so, allocate
503      * a new buffer and retry again.
504      */
505     if ( (!UnicodeQuerySet) && (*lpdwBufferLength >= sizeof(WSAQUERYSETW)) &&
506          (ErrorCode == SOCKET_ERROR) && (GetLastError() == WSAEFAULT) )
507     {
508         /* Allocate the buffer we'll use */
509         UnicodeQuerySet = HeapAlloc(WsSockHeap, 0, UnicodeQuerySetSize);
510         if (UnicodeQuerySet)
511         {
512             /* Call the Unicode Function */
513             ErrorCode = WSALookupServiceNextW(hLookup,
514                                               dwControlFlags,
515                                               &UnicodeQuerySetSize,
516                                               UnicodeQuerySet);
517         }
518         /*
519          * Otherwise the allocation failed and we
520          * fall back into the error checks below.
521          */
522     }
523 
524     if (ErrorCode == ERROR_SUCCESS)
525     {
526         SIZE_T SetSize = *lpdwBufferLength;
527 
528         /* Now convert back to ANSI */
529         ErrorCode = MapUnicodeQuerySetToAnsi(UnicodeQuerySet,
530                                              &SetSize,
531                                              lpqsResults);
532         if (ErrorCode != ERROR_SUCCESS)
533         {
534             SetLastError(ErrorCode);
535         }
536         else if (SetSize > MAXDWORD)
537         {
538             ErrorCode = ERROR_ARITHMETIC_OVERFLOW;
539             SetLastError(ErrorCode);
540         }
541         else
542         {
543             *lpdwBufferLength = SetSize;
544         }
545     }
546     else
547     {
548         /* Check if we ran out of space */
549         if (GetLastError() == WSAEFAULT)
550         {
551             /* Return how much space we'll need, including padding */
552             *lpdwBufferLength = UnicodeQuerySetSize +
553                                 ((sizeof(ULONG) * 6) - (6 * 1));
554         }
555     }
556 
557     /* If we had a local buffer, free it */
558     if (UnicodeQuerySet)
559         HeapFree(WsSockHeap, 0, UnicodeQuerySet);
560 
561     /* Return to caller */
562     return (ErrorCode == ERROR_SUCCESS) ? ErrorCode : SOCKET_ERROR;
563 }
564 
565 /*
566  * @unimplemented
567  */
568 INT
569 WSPAPI
570 WSANSPIoctl(HANDLE hLookup,
571             DWORD dwControlCode,
572             LPVOID lpvInBuffer,
573             DWORD cbInBuffer,
574             LPVOID lpvOutBuffer,
575             DWORD cbOutBuffer,
576             LPDWORD lpcbBytesReturned,
577             LPWSACOMPLETION lpCompletion)
578 {
579     DPRINT("WSANSPIoctl: %lx\n", hLookup);
580     return 0;
581 }
582 
583 /*
584  * @unimplemented
585  */
586 INT
587 WSAAPI
588 WSARemoveServiceClass(IN LPGUID lpServiceClassId)
589 {
590     DPRINT("WSARemoveServiceClass: %lx\n", lpServiceClassId);
591     SetLastError(WSAEINVAL);
592     return SOCKET_ERROR;
593 }
594 
595 /*
596  * @unimplemented
597  */
598 INT
599 WSAAPI
600 WSASetServiceA(IN LPWSAQUERYSETA lpqsRegInfo,
601                IN WSAESETSERVICEOP essOperation,
602                IN DWORD dwControlFlags)
603 {
604     DPRINT("WSASetServiceA: %lx\n", lpqsRegInfo);
605     SetLastError(WSAEINVAL);
606     return SOCKET_ERROR;
607 }
608 
609 /*
610  * @unimplemented
611  */
612 INT
613 WSAAPI
614 WSASetServiceW(IN LPWSAQUERYSETW lpqsRegInfo,
615                IN WSAESETSERVICEOP essOperation,
616                IN DWORD dwControlFlags)
617 {
618     DPRINT("WSASetServiceW: %lx\n", lpqsRegInfo);
619     SetLastError(WSAEINVAL);
620     return SOCKET_ERROR;
621 }
622 
623 /*
624  * @unimplemented
625  */
626 INT
627 WSAAPI
628 WSAGetServiceClassInfoA(IN LPGUID lpProviderId,
629                         IN LPGUID lpServiceClassId,
630                         IN OUT LPDWORD lpdwBufferLength,
631                         OUT LPWSASERVICECLASSINFOA lpServiceClassInfo)
632 {
633     DPRINT("WSAGetServiceClassInfoA: %lx\n", lpProviderId);
634     SetLastError(WSAEINVAL);
635     return SOCKET_ERROR;
636 }
637 
638 /*
639  * @unimplemented
640  */
641 INT
642 WSAAPI
643 WSAGetServiceClassInfoW(IN LPGUID lpProviderId,
644                         IN LPGUID lpServiceClassId,
645                         IN OUT LPDWORD lpdwBufferLength,
646                         OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)
647 {
648     DPRINT("WSAGetServiceClassInfoW: %lx\n", lpProviderId);
649     SetLastError(WSAEINVAL);
650     return SOCKET_ERROR;
651 }
652 
653 /*
654  * @unimplemented
655  */
656 INT
657 WSAAPI
658 WSAGetServiceClassNameByClassIdA(IN LPGUID lpServiceClassId,
659                                  OUT LPSTR lpszServiceClassName,
660                                  IN OUT LPDWORD lpdwBufferLength)
661 {
662     DPRINT("WSAGetServiceClassNameByClassIdA: %lx\n", lpServiceClassId);
663     SetLastError(WSAEINVAL);
664     return SOCKET_ERROR;
665 }
666 
667 /*
668  * @unimplemented
669  */
670 INT
671 WSAAPI
672 WSAGetServiceClassNameByClassIdW(IN LPGUID lpServiceClassId,
673                                  OUT LPWSTR lpszServiceClassName,
674                                  IN OUT LPDWORD lpdwBufferLength)
675 {
676     DPRINT("WSAGetServiceClassNameByClassIdW: %lx\n", lpServiceClassId);
677     SetLastError(WSAEINVAL);
678     return SOCKET_ERROR;
679 }
680 
681 /*
682  * @unimplemented
683  */
684 INT
685 WSAAPI
686 WSAInstallServiceClassA(IN LPWSASERVICECLASSINFOA lpServiceClassInfo)
687 {
688     DPRINT("WSAInstallServiceClassA: %lx\n", lpServiceClassInfo);
689     SetLastError(WSAEINVAL);
690     return SOCKET_ERROR;
691 }
692 
693 /*
694 * @unimplemented
695 */
696 INT
697 WSAAPI
698 WSAInstallServiceClassW(IN LPWSASERVICECLASSINFOW lpServiceClassInfo)
699 {
700     DPRINT("WSAInstallServiceClassW: %lx\n", lpServiceClassInfo);
701     SetLastError(WSAEINVAL);
702     return SOCKET_ERROR;
703 }
704 
705 VOID
706 WSAAPI
707 NSProviderInfoFromContext(IN PNSCATALOG_ENTRY Entry,
708     IN PNSPROVIDER_ENUM_CONTEXT Context)
709 {
710     INT size = Context->Unicode ? sizeof(WSANAMESPACE_INFOW) : sizeof(WSANAMESPACE_INFOA);
711     /* Calculate ProviderName string size */
712     INT size1 = Entry->ProviderName ? wcslen(Entry->ProviderName) + 1 : 0;
713     INT size2 = Context->Unicode ? size1 * sizeof(WCHAR) : size1 * sizeof(CHAR);
714     WSANAMESPACE_INFOW infoW;
715     /* Fill NS Provider data */
716     infoW.dwNameSpace = Entry->NamespaceId;
717     infoW.dwVersion = Entry->Version;
718     infoW.fActive = Entry->Enabled;
719     RtlMoveMemory(&infoW.NSProviderId,
720         &Entry->ProviderId,
721         sizeof(infoW.NSProviderId));
722     if (size2)
723     {
724         /* Calculate ProviderName string pointer */
725         infoW.lpszIdentifier = (LPWSTR)((ULONG_PTR)Context->ProtocolBuffer +
726             Context->BufferUsed + size);
727     }
728     else
729     {
730         infoW.lpszIdentifier = NULL;
731     }
732 
733     /* Check if we'll have space */
734     if ((Context->BufferUsed + size + size2) <=
735         (Context->BufferLength))
736     {
737         /* Copy the data */
738         RtlMoveMemory((PVOID)((ULONG_PTR)Context->ProtocolBuffer +
739             Context->BufferUsed),
740             &infoW,
741             size);
742         if (size2)
743         {
744             /* Entry->ProviderName is LPWSTR */
745             if (Context->Unicode)
746             {
747                 RtlMoveMemory((PVOID)((ULONG_PTR)Context->ProtocolBuffer +
748                     Context->BufferUsed + size),
749                     Entry->ProviderName,
750                     size2);
751             }
752             else
753             {
754                 /* Call the conversion function */
755                 WideCharToMultiByte(CP_ACP,
756                     0,
757                     Entry->ProviderName,
758                     -1,
759                     (LPSTR)((ULONG_PTR)Context->ProtocolBuffer +
760                         Context->BufferUsed + size),
761                     size2,
762                     NULL,
763                     NULL);
764 
765             }
766         }
767 
768         /* Increase the count */
769         Context->Count++;
770     }
771 }
772 
773 BOOL
774 WSAAPI
775 NSProvidersEnumerationProc(PVOID EnumContext,
776     PNSCATALOG_ENTRY Entry)
777 {
778     PNSPROVIDER_ENUM_CONTEXT Context = (PNSPROVIDER_ENUM_CONTEXT)EnumContext;
779 
780     /* Calculate ProviderName string size */
781     INT size1 = Entry->ProviderName ? wcslen(Entry->ProviderName) + 1 : 0;
782     INT size2 = Context->Unicode ? size1 * sizeof(WCHAR) : size1 * sizeof(CHAR);
783 
784     /* Copy the information */
785     NSProviderInfoFromContext(Entry, Context);
786     Context->BufferUsed += Context->Unicode ? (sizeof(WSANAMESPACE_INFOW)+size2) : (sizeof(WSANAMESPACE_INFOA)+size2);
787 
788     /* Continue enumeration */
789     return TRUE;
790 }
791 
792 INT
793 WSAAPI
794 WSAEnumNameSpaceProvidersInternal(IN OUT LPDWORD lpdwBufferLength,
795     OUT LPWSANAMESPACE_INFOA lpnspBuffer, BOOLEAN Unicode)
796 {
797     INT Status;
798     PWSPROCESS WsProcess;
799     PNSCATALOG Catalog;
800     NSPROVIDER_ENUM_CONTEXT Context;
801 
802     DPRINT("WSAEnumNameSpaceProvidersInternal: %lx\n", lpnspBuffer);
803 
804     if (!lpdwBufferLength)
805     {
806         WSASetLastError(WSAEFAULT);
807         return SOCKET_ERROR;
808     }
809     WsProcess = WsGetProcess();
810     /* Create a catalog object from the current one */
811     Catalog = WsProcGetNsCatalog(WsProcess);
812     if (!Catalog)
813     {
814         /* Fail if we couldn't */
815         WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
816         return SOCKET_ERROR;
817     }
818 
819     Context.ProtocolBuffer = lpnspBuffer;
820     Context.BufferLength = lpnspBuffer ? *lpdwBufferLength : 0;
821     Context.BufferUsed = 0;
822     Context.Count = 0;
823     Context.Unicode = Unicode;
824     Context.ErrorCode = ERROR_SUCCESS;
825 
826     WsNcEnumerateCatalogItems(Catalog, NSProvidersEnumerationProc, &Context);
827 
828     /* Get status */
829     Status = Context.Count;
830 
831     /* Check the error code */
832     if (Context.ErrorCode == ERROR_SUCCESS)
833     {
834         /* Check if enough space was available */
835         if (Context.BufferLength < Context.BufferUsed)
836         {
837             /* Fail and tell them how much we need */
838             *lpdwBufferLength = Context.BufferUsed;
839             WSASetLastError(WSAEFAULT);
840             Status = SOCKET_ERROR;
841         }
842     }
843     else
844     {
845         /* Failure, normalize error */
846         Status = SOCKET_ERROR;
847         WSASetLastError(Context.ErrorCode);
848     }
849 
850     /* Return */
851     return Status;
852 }
853 
854 /*
855  * @implemented
856  */
857 INT
858 WSAAPI
859 WSAEnumNameSpaceProvidersA(IN OUT LPDWORD lpdwBufferLength,
860                            OUT LPWSANAMESPACE_INFOA lpnspBuffer)
861 {
862     DPRINT("WSAEnumNameSpaceProvidersA: %lx\n", lpnspBuffer);
863     return WSAEnumNameSpaceProvidersInternal(lpdwBufferLength, (LPWSANAMESPACE_INFOA)lpnspBuffer, FALSE);
864 }
865 
866 /*
867  * @implemented
868  */
869 INT
870 WSAAPI
871 WSAEnumNameSpaceProvidersW(IN OUT LPDWORD lpdwBufferLength,
872                            OUT LPWSANAMESPACE_INFOW lpnspBuffer)
873 {
874     DPRINT("WSAEnumNameSpaceProvidersW: %lx\n", lpnspBuffer);
875     return WSAEnumNameSpaceProvidersInternal(lpdwBufferLength, (LPWSANAMESPACE_INFOA)lpnspBuffer, TRUE);
876 }
877 
878 /*
879  * @implemented
880  */
881 INT
882 WSAAPI
883 WSAStringToAddressA(IN LPSTR AddressString,
884                     IN INT AddressFamily,
885                     IN LPWSAPROTOCOL_INFOA lpProtocolInfo,
886                     OUT LPSOCKADDR lpAddress,
887                     IN OUT  LPINT lpAddressLength)
888 {
889     PWSPROCESS Process;
890     PWSTHREAD Thread;
891     INT ErrorCode, Status;
892     DWORD CatalogEntryId;
893     PTCATALOG Catalog;
894     PTCATALOG_ENTRY CatalogEntry;
895     LPWSTR UnicodeString;
896     DWORD Length = (DWORD)strlen(AddressString) + 1;
897 
898     DPRINT("WSAStringToAddressA: %s\n", AddressString);
899 
900     /* Enter prolog */
901     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
902     {
903         /* Leave now */
904         SetLastError(ErrorCode);
905         return SOCKET_ERROR;
906     }
907 
908     /* Allocate the unicode string */
909     UnicodeString = HeapAlloc(WsSockHeap, 0, Length * 2);
910     if (!UnicodeString)
911     {
912         /* No memory; fail */
913         SetLastError(WSAENOBUFS);
914         return SOCKET_ERROR;
915     }
916 
917     /* Convert the string */
918     MultiByteToWideChar(CP_ACP, 0, AddressString, -1, UnicodeString, Length);
919 
920     /* Get the catalog */
921     Catalog = WsProcGetTCatalog(Process);
922 
923     /* Check if we got custom protocol info */
924     if (lpProtocolInfo)
925     {
926         /* Get the entry ID */
927         CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
928 
929         /* Get the entry associated with it */
930         ErrorCode = WsTcGetEntryFromCatalogEntryId(Catalog,
931                                                    CatalogEntryId,
932                                                    &CatalogEntry);
933     }
934     else
935     {
936         /* Get it from the address family */
937         ErrorCode = WsTcGetEntryFromAf(Catalog, AddressFamily, &CatalogEntry);
938     }
939 
940     /* Check for success */
941     if (ErrorCode == ERROR_SUCCESS)
942     {
943         /* Call the provider */
944         Status = CatalogEntry->Provider->Service.lpWSPStringToAddress(UnicodeString,
945                                                               AddressFamily,
946                                                               &CatalogEntry->
947                                                               ProtocolInfo,
948                                                               lpAddress,
949                                                               lpAddressLength,
950                                                               &ErrorCode);
951 
952         /* Dereference the entry */
953         WsTcEntryDereference(CatalogEntry);
954 
955         /* Free the unicode string */
956         HeapFree(WsSockHeap, 0, UnicodeString);
957 
958         /* Check for success and return */
959         if (Status == ERROR_SUCCESS) return ERROR_SUCCESS;
960     }
961     else
962     {
963         /* Free the unicode string */
964         HeapFree(WsSockHeap, 0, UnicodeString);
965     }
966 
967     /* Set the error and return */
968     SetLastError(ErrorCode);
969     return SOCKET_ERROR;
970 }
971 
972 /*
973  * @implemented
974  */
975 INT
976 WSAAPI
977 WSAStringToAddressW(IN LPWSTR AddressString,
978                     IN INT AddressFamily,
979                     IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
980                     OUT LPSOCKADDR lpAddress,
981                     IN OUT LPINT lpAddressLength)
982 {
983     PWSPROCESS Process;
984     PWSTHREAD Thread;
985     INT ErrorCode, Status;
986     DWORD CatalogEntryId;
987     PTCATALOG Catalog;
988     PTCATALOG_ENTRY CatalogEntry;
989 
990     DPRINT("WSAStringToAddressW: %S\n", AddressString);
991 
992     /* Enter prolog */
993     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
994     {
995         /* Leave now */
996         SetLastError(ErrorCode);
997         return SOCKET_ERROR;
998     }
999 
1000     /* Get the catalog */
1001     Catalog = WsProcGetTCatalog(Process);
1002 
1003     /* Check if we got custom protocol info */
1004     if (lpProtocolInfo)
1005     {
1006         /* Get the entry ID */
1007         CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
1008 
1009         /* Get the entry associated with it */
1010         ErrorCode = WsTcGetEntryFromCatalogEntryId(Catalog,
1011                                                    CatalogEntryId,
1012                                                    &CatalogEntry);
1013     }
1014     else
1015     {
1016         /* Get it from the address family */
1017         ErrorCode = WsTcGetEntryFromAf(Catalog, AddressFamily, &CatalogEntry);
1018     }
1019 
1020     /* Check for success */
1021     if (ErrorCode == ERROR_SUCCESS)
1022     {
1023         /* Call the provider */
1024         Status = CatalogEntry->Provider->Service.lpWSPStringToAddress(AddressString,
1025                                                                       AddressFamily,
1026                                                                       &CatalogEntry->
1027                                                                       ProtocolInfo,
1028                                                                       lpAddress,
1029                                                                       lpAddressLength,
1030                                                                       &ErrorCode);
1031 
1032         /* Dereference the entry */
1033         WsTcEntryDereference(CatalogEntry);
1034 
1035         /* Check for success and return */
1036         if (Status == ERROR_SUCCESS) return ERROR_SUCCESS;
1037     }
1038 
1039     /* Set the error and return */
1040     SetLastError(ErrorCode);
1041     return SOCKET_ERROR;
1042 }
1043