xref: /reactos/dll/win32/ws2_32/src/rnr.c (revision 845faec4)
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     DWORD 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         /* Now convert back to ANSI */
527         ErrorCode = MapUnicodeQuerySetToAnsi(UnicodeQuerySet,
528                                              lpdwBufferLength,
529                                              lpqsResults);
530         if (ErrorCode != ERROR_SUCCESS)
531             SetLastError(ErrorCode);
532     }
533     else
534     {
535         /* Check if we ran out of space */
536         if (GetLastError() == WSAEFAULT)
537         {
538             /* Return how much space we'll need, including padding */
539             *lpdwBufferLength = UnicodeQuerySetSize +
540                                 ((sizeof(ULONG) * 6) - (6 * 1));
541         }
542     }
543 
544     /* If we had a local buffer, free it */
545     if (UnicodeQuerySet)
546         HeapFree(WsSockHeap, 0, UnicodeQuerySet);
547 
548     /* Return to caller */
549     return (ErrorCode == ERROR_SUCCESS) ? ErrorCode : SOCKET_ERROR;
550 }
551 
552 /*
553  * @unimplemented
554  */
555 INT
556 WSPAPI
557 WSANSPIoctl(HANDLE hLookup,
558             DWORD dwControlCode,
559             LPVOID lpvInBuffer,
560             DWORD cbInBuffer,
561             LPVOID lpvOutBuffer,
562             DWORD cbOutBuffer,
563             LPDWORD lpcbBytesReturned,
564             LPWSACOMPLETION lpCompletion)
565 {
566     DPRINT("WSANSPIoctl: %lx\n", hLookup);
567     return 0;
568 }
569 
570 /*
571  * @unimplemented
572  */
573 INT
574 WSAAPI
575 WSARemoveServiceClass(IN LPGUID lpServiceClassId)
576 {
577     DPRINT("WSARemoveServiceClass: %lx\n", lpServiceClassId);
578     SetLastError(WSAEINVAL);
579     return SOCKET_ERROR;
580 }
581 
582 /*
583  * @unimplemented
584  */
585 INT
586 WSAAPI
587 WSASetServiceA(IN LPWSAQUERYSETA lpqsRegInfo,
588                IN WSAESETSERVICEOP essOperation,
589                IN DWORD dwControlFlags)
590 {
591     DPRINT("WSASetServiceA: %lx\n", lpqsRegInfo);
592     SetLastError(WSAEINVAL);
593     return SOCKET_ERROR;
594 }
595 
596 /*
597  * @unimplemented
598  */
599 INT
600 WSAAPI
601 WSASetServiceW(IN LPWSAQUERYSETW lpqsRegInfo,
602                IN WSAESETSERVICEOP essOperation,
603                IN DWORD dwControlFlags)
604 {
605     DPRINT("WSASetServiceW: %lx\n", lpqsRegInfo);
606     SetLastError(WSAEINVAL);
607     return SOCKET_ERROR;
608 }
609 
610 /*
611  * @unimplemented
612  */
613 INT
614 WSAAPI
615 WSAGetServiceClassInfoA(IN LPGUID lpProviderId,
616                         IN LPGUID lpServiceClassId,
617                         IN OUT LPDWORD lpdwBufferLength,
618                         OUT LPWSASERVICECLASSINFOA lpServiceClassInfo)
619 {
620     DPRINT("WSAGetServiceClassInfoA: %lx\n", lpProviderId);
621     SetLastError(WSAEINVAL);
622     return SOCKET_ERROR;
623 }
624 
625 /*
626  * @unimplemented
627  */
628 INT
629 WSAAPI
630 WSAGetServiceClassInfoW(IN LPGUID lpProviderId,
631                         IN LPGUID lpServiceClassId,
632                         IN OUT LPDWORD lpdwBufferLength,
633                         OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)
634 {
635     DPRINT("WSAGetServiceClassInfoW: %lx\n", lpProviderId);
636     SetLastError(WSAEINVAL);
637     return SOCKET_ERROR;
638 }
639 
640 /*
641  * @unimplemented
642  */
643 INT
644 WSAAPI
645 WSAGetServiceClassNameByClassIdA(IN LPGUID lpServiceClassId,
646                                  OUT LPSTR lpszServiceClassName,
647                                  IN OUT LPDWORD lpdwBufferLength)
648 {
649     DPRINT("WSAGetServiceClassNameByClassIdA: %lx\n", lpServiceClassId);
650     SetLastError(WSAEINVAL);
651     return SOCKET_ERROR;
652 }
653 
654 /*
655  * @unimplemented
656  */
657 INT
658 WSAAPI
659 WSAGetServiceClassNameByClassIdW(IN LPGUID lpServiceClassId,
660                                  OUT LPWSTR lpszServiceClassName,
661                                  IN OUT LPDWORD lpdwBufferLength)
662 {
663     DPRINT("WSAGetServiceClassNameByClassIdW: %lx\n", lpServiceClassId);
664     SetLastError(WSAEINVAL);
665     return SOCKET_ERROR;
666 }
667 
668 /*
669  * @unimplemented
670  */
671 INT
672 WSAAPI
673 WSAInstallServiceClassA(IN LPWSASERVICECLASSINFOA lpServiceClassInfo)
674 {
675     DPRINT("WSAInstallServiceClassA: %lx\n", lpServiceClassInfo);
676     SetLastError(WSAEINVAL);
677     return SOCKET_ERROR;
678 }
679 
680 /*
681 * @unimplemented
682 */
683 INT
684 WSAAPI
685 WSAInstallServiceClassW(IN LPWSASERVICECLASSINFOW lpServiceClassInfo)
686 {
687     DPRINT("WSAInstallServiceClassW: %lx\n", lpServiceClassInfo);
688     SetLastError(WSAEINVAL);
689     return SOCKET_ERROR;
690 }
691 
692 VOID
693 WSAAPI
694 NSProviderInfoFromContext(IN PNSCATALOG_ENTRY Entry,
695     IN PNSPROVIDER_ENUM_CONTEXT Context)
696 {
697     INT size = Context->Unicode ? sizeof(WSANAMESPACE_INFOW) : sizeof(WSANAMESPACE_INFOA);
698     /* Calculate ProviderName string size */
699     INT size1 = Entry->ProviderName ? wcslen(Entry->ProviderName) + 1 : 0;
700     INT size2 = Context->Unicode ? size1 * sizeof(WCHAR) : size1 * sizeof(CHAR);
701     WSANAMESPACE_INFOW infoW;
702     /* Fill NS Provider data */
703     infoW.dwNameSpace = Entry->NamespaceId;
704     infoW.dwVersion = Entry->Version;
705     infoW.fActive = Entry->Enabled;
706     RtlMoveMemory(&infoW.NSProviderId,
707         &Entry->ProviderId,
708         sizeof(infoW.NSProviderId));
709     if (size2)
710     {
711         /* Calculate ProviderName string pointer */
712         infoW.lpszIdentifier = (LPWSTR)((ULONG_PTR)Context->ProtocolBuffer +
713             Context->BufferUsed + size);
714     }
715     else
716     {
717         infoW.lpszIdentifier = NULL;
718     }
719 
720     /* Check if we'll have space */
721     if ((Context->BufferUsed + size + size2) <=
722         (Context->BufferLength))
723     {
724         /* Copy the data */
725         RtlMoveMemory((PVOID)((ULONG_PTR)Context->ProtocolBuffer +
726             Context->BufferUsed),
727             &infoW,
728             size);
729         if (size2)
730         {
731             /* Entry->ProviderName is LPWSTR */
732             if (Context->Unicode)
733             {
734                 RtlMoveMemory((PVOID)((ULONG_PTR)Context->ProtocolBuffer +
735                     Context->BufferUsed + size),
736                     Entry->ProviderName,
737                     size2);
738             }
739             else
740             {
741                 /* Call the conversion function */
742                 WideCharToMultiByte(CP_ACP,
743                     0,
744                     Entry->ProviderName,
745                     -1,
746                     (LPSTR)((ULONG_PTR)Context->ProtocolBuffer +
747                         Context->BufferUsed + size),
748                     size2,
749                     NULL,
750                     NULL);
751 
752             }
753         }
754 
755         /* Increase the count */
756         Context->Count++;
757     }
758 }
759 
760 BOOL
761 WSAAPI
762 NSProvidersEnumerationProc(PVOID EnumContext,
763     PNSCATALOG_ENTRY Entry)
764 {
765     PNSPROVIDER_ENUM_CONTEXT Context = (PNSPROVIDER_ENUM_CONTEXT)EnumContext;
766 
767     /* Calculate ProviderName string size */
768     INT size1 = Entry->ProviderName ? wcslen(Entry->ProviderName) + 1 : 0;
769     INT size2 = Context->Unicode ? size1 * sizeof(WCHAR) : size1 * sizeof(CHAR);
770 
771     /* Copy the information */
772     NSProviderInfoFromContext(Entry, Context);
773     Context->BufferUsed += Context->Unicode ? (sizeof(WSANAMESPACE_INFOW)+size2) : (sizeof(WSANAMESPACE_INFOA)+size2);
774 
775     /* Continue enumeration */
776     return TRUE;
777 }
778 
779 INT
780 WSAAPI
781 WSAEnumNameSpaceProvidersInternal(IN OUT LPDWORD lpdwBufferLength,
782     OUT LPWSANAMESPACE_INFOA lpnspBuffer, BOOLEAN Unicode)
783 {
784     INT Status;
785     PWSPROCESS WsProcess;
786     PNSCATALOG Catalog;
787     NSPROVIDER_ENUM_CONTEXT Context;
788 
789     DPRINT("WSAEnumNameSpaceProvidersInternal: %lx\n", lpnspBuffer);
790 
791     if (!lpdwBufferLength)
792     {
793         WSASetLastError(WSAEFAULT);
794         return SOCKET_ERROR;
795     }
796     WsProcess = WsGetProcess();
797     /* Create a catalog object from the current one */
798     Catalog = WsProcGetNsCatalog(WsProcess);
799     if (!Catalog)
800     {
801         /* Fail if we couldn't */
802         WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
803         return SOCKET_ERROR;
804     }
805 
806     Context.ProtocolBuffer = lpnspBuffer;
807     Context.BufferLength = lpnspBuffer ? *lpdwBufferLength : 0;
808     Context.BufferUsed = 0;
809     Context.Count = 0;
810     Context.Unicode = Unicode;
811     Context.ErrorCode = ERROR_SUCCESS;
812 
813     WsNcEnumerateCatalogItems(Catalog, NSProvidersEnumerationProc, &Context);
814 
815     /* Get status */
816     Status = Context.Count;
817 
818     /* Check the error code */
819     if (Context.ErrorCode == ERROR_SUCCESS)
820     {
821         /* Check if enough space was available */
822         if (Context.BufferLength < Context.BufferUsed)
823         {
824             /* Fail and tell them how much we need */
825             *lpdwBufferLength = Context.BufferUsed;
826             WSASetLastError(WSAEFAULT);
827             Status = SOCKET_ERROR;
828         }
829     }
830     else
831     {
832         /* Failure, normalize error */
833         Status = SOCKET_ERROR;
834         WSASetLastError(Context.ErrorCode);
835     }
836 
837     /* Return */
838     return Status;
839 }
840 
841 /*
842  * @implemented
843  */
844 INT
845 WSAAPI
846 WSAEnumNameSpaceProvidersA(IN OUT LPDWORD lpdwBufferLength,
847                            OUT LPWSANAMESPACE_INFOA lpnspBuffer)
848 {
849     DPRINT("WSAEnumNameSpaceProvidersA: %lx\n", lpnspBuffer);
850     return WSAEnumNameSpaceProvidersInternal(lpdwBufferLength, (LPWSANAMESPACE_INFOA)lpnspBuffer, FALSE);
851 }
852 
853 /*
854  * @implemented
855  */
856 INT
857 WSAAPI
858 WSAEnumNameSpaceProvidersW(IN OUT LPDWORD lpdwBufferLength,
859                            OUT LPWSANAMESPACE_INFOW lpnspBuffer)
860 {
861     DPRINT("WSAEnumNameSpaceProvidersW: %lx\n", lpnspBuffer);
862     return WSAEnumNameSpaceProvidersInternal(lpdwBufferLength, (LPWSANAMESPACE_INFOA)lpnspBuffer, TRUE);
863 }
864 
865 /*
866  * @implemented
867  */
868 INT
869 WSAAPI
870 WSAStringToAddressA(IN LPSTR AddressString,
871                     IN INT AddressFamily,
872                     IN LPWSAPROTOCOL_INFOA lpProtocolInfo,
873                     OUT LPSOCKADDR lpAddress,
874                     IN OUT  LPINT lpAddressLength)
875 {
876     PWSPROCESS Process;
877     PWSTHREAD Thread;
878     INT ErrorCode, Status;
879     DWORD CatalogEntryId;
880     PTCATALOG Catalog;
881     PTCATALOG_ENTRY CatalogEntry;
882     LPWSTR UnicodeString;
883     DWORD Length = (DWORD)strlen(AddressString) + 1;
884 
885     DPRINT("WSAStringToAddressA: %s\n", AddressString);
886 
887     /* Enter prolog */
888     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
889     {
890         /* Leave now */
891         SetLastError(ErrorCode);
892         return SOCKET_ERROR;
893     }
894 
895     /* Allocate the unicode string */
896     UnicodeString = HeapAlloc(WsSockHeap, 0, Length * 2);
897     if (!UnicodeString)
898     {
899         /* No memory; fail */
900         SetLastError(WSAENOBUFS);
901         return SOCKET_ERROR;
902     }
903 
904     /* Convert the string */
905     MultiByteToWideChar(CP_ACP, 0, AddressString, -1, UnicodeString, Length);
906 
907     /* Get the catalog */
908     Catalog = WsProcGetTCatalog(Process);
909 
910     /* Check if we got custom protocol info */
911     if (lpProtocolInfo)
912     {
913         /* Get the entry ID */
914         CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
915 
916         /* Get the entry associated with it */
917         ErrorCode = WsTcGetEntryFromCatalogEntryId(Catalog,
918                                                    CatalogEntryId,
919                                                    &CatalogEntry);
920     }
921     else
922     {
923         /* Get it from the address family */
924         ErrorCode = WsTcGetEntryFromAf(Catalog, AddressFamily, &CatalogEntry);
925     }
926 
927     /* Check for success */
928     if (ErrorCode == ERROR_SUCCESS)
929     {
930         /* Call the provider */
931         Status = CatalogEntry->Provider->Service.lpWSPStringToAddress(UnicodeString,
932                                                               AddressFamily,
933                                                               &CatalogEntry->
934                                                               ProtocolInfo,
935                                                               lpAddress,
936                                                               lpAddressLength,
937                                                               &ErrorCode);
938 
939         /* Dereference the entry */
940         WsTcEntryDereference(CatalogEntry);
941 
942         /* Free the unicode string */
943         HeapFree(WsSockHeap, 0, UnicodeString);
944 
945         /* Check for success and return */
946         if (Status == ERROR_SUCCESS) return ERROR_SUCCESS;
947     }
948     else
949     {
950         /* Free the unicode string */
951         HeapFree(WsSockHeap, 0, UnicodeString);
952     }
953 
954     /* Set the error and return */
955     SetLastError(ErrorCode);
956     return SOCKET_ERROR;
957 }
958 
959 /*
960  * @implemented
961  */
962 INT
963 WSAAPI
964 WSAStringToAddressW(IN LPWSTR AddressString,
965                     IN INT AddressFamily,
966                     IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
967                     OUT LPSOCKADDR lpAddress,
968                     IN OUT LPINT lpAddressLength)
969 {
970     PWSPROCESS Process;
971     PWSTHREAD Thread;
972     INT ErrorCode, Status;
973     DWORD CatalogEntryId;
974     PTCATALOG Catalog;
975     PTCATALOG_ENTRY CatalogEntry;
976 
977     DPRINT("WSAStringToAddressW: %S\n", AddressString);
978 
979     /* Enter prolog */
980     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
981     {
982         /* Leave now */
983         SetLastError(ErrorCode);
984         return SOCKET_ERROR;
985     }
986 
987     /* Get the catalog */
988     Catalog = WsProcGetTCatalog(Process);
989 
990     /* Check if we got custom protocol info */
991     if (lpProtocolInfo)
992     {
993         /* Get the entry ID */
994         CatalogEntryId = lpProtocolInfo->dwCatalogEntryId;
995 
996         /* Get the entry associated with it */
997         ErrorCode = WsTcGetEntryFromCatalogEntryId(Catalog,
998                                                    CatalogEntryId,
999                                                    &CatalogEntry);
1000     }
1001     else
1002     {
1003         /* Get it from the address family */
1004         ErrorCode = WsTcGetEntryFromAf(Catalog, AddressFamily, &CatalogEntry);
1005     }
1006 
1007     /* Check for success */
1008     if (ErrorCode == ERROR_SUCCESS)
1009     {
1010         /* Call the provider */
1011         Status = CatalogEntry->Provider->Service.lpWSPStringToAddress(AddressString,
1012                                                                       AddressFamily,
1013                                                                       &CatalogEntry->
1014                                                                       ProtocolInfo,
1015                                                                       lpAddress,
1016                                                                       lpAddressLength,
1017                                                                       &ErrorCode);
1018 
1019         /* Dereference the entry */
1020         WsTcEntryDereference(CatalogEntry);
1021 
1022         /* Check for success and return */
1023         if (Status == ERROR_SUCCESS) return ERROR_SUCCESS;
1024     }
1025 
1026     /* Set the error and return */
1027     SetLastError(ErrorCode);
1028     return SOCKET_ERROR;
1029 }
1030