xref: /reactos/dll/win32/ws2_32/src/enumprot.c (revision 3adf4508)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock 2 API
4  * FILE:        dll/win32/ws2_32/src/enumprot.c
5  * PURPOSE:     Protocol Enumeration
6  * PROGRAMMER:  Alex Ionescu (alex@relsoft.net)
7  *              Pierre Schweitzer
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ws2_32.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* FUNCTIONS *****************************************************************/
18 
19 BOOL
20 WSAAPI
21 CheckProtocolMatch(IN LPINT ProtocolSet,
22                    IN LPWSAPROTOCOL_INFOW ProtocolInfo)
23 {
24     BOOL Return = FALSE;
25     DWORD i = 0;
26     INT ProtocolId;
27 
28     /* Make sure we have a set */
29     if (ProtocolSet)
30     {
31         /* Get the first ID */
32         ProtocolId = ProtocolSet[i];
33 
34         /* Loop the list */
35         while (ProtocolId != 0 && ProtocolInfo->iProtocol != 0)
36         {
37             /* Check if it's within ranges */
38             if ((ProtocolId >= ProtocolInfo->iProtocol) &&
39                 (ProtocolId <= (ProtocolInfo->iProtocol +
40                                 ProtocolInfo->iProtocolMaxOffset)))
41             {
42                 /* Found it */
43                 Return = TRUE;
44                 break;
45             }
46 
47             /* Move on */
48             i++;
49             ProtocolId = ProtocolSet[i];
50         }
51     }
52     else
53     {
54         /* Assume match */
55         Return = TRUE;
56     }
57 
58     /* Return result */
59     return Return;
60 }
61 
62 VOID
63 WSAAPI
64 ProtocolInfoFromContext(IN LPWSAPROTOCOL_INFOW ProtocolInfo,
65                         IN PPROTOCOL_ENUM_CONTEXT Context)
66 {
67     /* Check if we'll have space */
68     if ((Context->BufferUsed + sizeof(*ProtocolInfo)) <=
69         (Context->BufferLength))
70     {
71         /* Copy the data */
72         RtlMoveMemory((PVOID)((ULONG_PTR)Context->ProtocolBuffer +
73                               Context->BufferUsed),
74                       ProtocolInfo,
75                       sizeof(*ProtocolInfo));
76 
77         /* Increase the count */
78         Context->Count++;
79     }
80 }
81 
82 BOOL
83 WSAAPI
84 ProtocolEnumerationProc(PVOID EnumContext,
85                         PTCATALOG_ENTRY Entry)
86 {
87     PPROTOCOL_ENUM_CONTEXT Context = (PPROTOCOL_ENUM_CONTEXT)EnumContext;
88     LPWSAPROTOCOL_INFOW ProtocolInfo = &Entry->ProtocolInfo;
89 
90     /* Check if this protocol matches */
91     if (CheckProtocolMatch(Context->Protocols, ProtocolInfo))
92     {
93         /* Copy the information */
94         ProtocolInfoFromContext(ProtocolInfo, Context);
95         Context->BufferUsed += sizeof(*ProtocolInfo);
96     }
97 
98     /* Continue enumeration */
99     return TRUE;
100 }
101 
102 BOOL
103 WSAAPI
104 ProviderEnumerationProc(PVOID EnumContext,
105                         PNSCATALOG_ENTRY Entry)
106 {
107     INT PathLen;
108     PPROVIDER_ENUM_CONTEXT Context = (PPROVIDER_ENUM_CONTEXT)EnumContext;
109 
110     /* Check if this provider matches */
111     if (IsEqualGUID(&Entry->ProviderId, &Context->ProviderId))
112     {
113         /* Get the information about the provider */
114         PathLen = wcslen(Entry->DllPath) + 1;
115         Context->FoundPathLen = PathLen;
116         Context->Found = 1;
117 
118         /* If we have enough room, copy path */
119         if (PathLen <= Context->ProviderDllPathLen)
120         {
121             wcscpy(Context->ProviderDllPath, Entry->DllPath);
122         }
123 
124         /* Stop enumeration */
125         return FALSE;
126     }
127     else
128     {
129         /* Continue enumeration */
130         return TRUE;
131     }
132 
133 }
134 
135 PTCATALOG
136 WSAAPI
137 OpenInitializedCatalog(VOID)
138 {
139     PTCATALOG Catalog;
140     HKEY WsKey;
141 
142     /* Allocate the catalog */
143     Catalog = WsTcAllocate();
144     if (Catalog)
145     {
146         /* Open the WS Key */
147         WsKey = WsOpenRegistryRoot();
148 
149         /* Initialize the catalog */
150         WsTcInitializeFromRegistry(Catalog, WsKey, NULL);
151 
152         /* Close the key */
153         RegCloseKey(WsKey);
154     }
155 
156     /* Return it */
157     return Catalog;
158 }
159 
160 /*
161  * @implemented
162  */
163 INT
164 WSPAPI
165 WSCEnumProtocols(IN LPINT lpiProtocols,
166                  OUT LPWSAPROTOCOL_INFOW lpProtocolBuffer,
167                  IN OUT LPDWORD lpdwBufferLength,
168                  OUT LPINT lpErrno)
169 {
170     INT Status;
171     PTCATALOG Catalog;
172     PROTOCOL_ENUM_CONTEXT Context;
173     DPRINT("WSCEnumProtocols: %p\n", lpiProtocols);
174 
175     /* Create a catalog object from the current one */
176     Catalog = OpenInitializedCatalog();
177     if (!Catalog)
178     {
179         /* Fail if we couldn't */
180         *lpErrno = WSAENOBUFS;
181         return SOCKET_ERROR;
182     }
183 
184     /* Setup the context */
185     Context.Protocols = lpiProtocols;
186     Context.ProtocolBuffer = lpProtocolBuffer;
187     Context.BufferLength = lpProtocolBuffer ? *lpdwBufferLength : 0;
188     Context.BufferUsed = 0;
189     Context.Count = 0;
190     Context.ErrorCode = ERROR_SUCCESS;
191 
192     /* Enumerate the catalog */
193     WsTcEnumerateCatalogItems(Catalog, ProtocolEnumerationProc, &Context);
194 
195     /* Get status */
196     Status = Context.Count;
197 
198     /* Check the error code */
199     if (Context.ErrorCode == ERROR_SUCCESS)
200     {
201         /* Check if enough space was available */
202         if (Context.BufferLength < Context.BufferUsed)
203         {
204             /* Fail and tell them how much we need */
205             *lpdwBufferLength = Context.BufferUsed;
206             *lpErrno = WSAENOBUFS;
207             Status = SOCKET_ERROR;
208         }
209     }
210     else
211     {
212         /* Failure, normalize error */
213         Status = SOCKET_ERROR;
214         *lpErrno = Context.ErrorCode;
215     }
216 
217     /* Delete the catalog object */
218     WsTcDelete(Catalog);
219 
220     /* Return */
221     return Status;
222 }
223 
224 /*
225  * @implemented
226  */
227 INT
228 WSAAPI
229 WSAEnumProtocolsA(IN LPINT lpiProtocols,
230                   OUT LPWSAPROTOCOL_INFOA lpProtocolBuffer,
231                   IN OUT LPDWORD lpdwBufferLength)
232 {
233     INT error, i, count;
234     LPWSAPROTOCOL_INFOW protocolInfoW;
235     DWORD size;
236     DPRINT("WSAEnumProtocolsA: %p %p %p\n", lpiProtocols, lpProtocolBuffer, lpdwBufferLength);
237     if (!lpdwBufferLength)
238     {
239         SetLastError(WSAENOBUFS);
240         return SOCKET_ERROR;
241     }
242     count = WSCEnumProtocols(lpiProtocols, NULL, &size, &error);
243     if (!lpProtocolBuffer || *lpdwBufferLength < (size/sizeof(WSAPROTOCOL_INFOW))*sizeof(WSAPROTOCOL_INFOA))
244     {
245         *lpdwBufferLength = (size/sizeof(WSAPROTOCOL_INFOW))*sizeof(WSAPROTOCOL_INFOA);
246         SetLastError(WSAENOBUFS);
247         return SOCKET_ERROR;
248     }
249     protocolInfoW = HeapAlloc(WsSockHeap, 0, size);
250     count = WSCEnumProtocols(lpiProtocols, protocolInfoW, &size, &error);
251     if (SOCKET_ERROR == count)
252     {
253         HeapFree(WsSockHeap, 0, protocolInfoW);
254         SetLastError(error);
255         return SOCKET_ERROR;
256     }
257     *lpdwBufferLength = 0;
258     for (i = 0; i < count; i++)
259     {
260         /* Copy the data */
261         RtlMoveMemory(&lpProtocolBuffer[i],
262                       &protocolInfoW[i],
263                       sizeof(lpProtocolBuffer[0])-sizeof(lpProtocolBuffer[0].szProtocol));
264         wcstombs(lpProtocolBuffer[i].szProtocol, protocolInfoW[i].szProtocol, sizeof(lpProtocolBuffer[0].szProtocol));
265         *lpdwBufferLength += sizeof(WSAPROTOCOL_INFOA);
266     }
267     HeapFree(WsSockHeap, 0, protocolInfoW);
268     return i;
269 }
270 
271 /*
272  * @implemented
273  */
274 INT
275 WSAAPI
276 WSAEnumProtocolsW(IN LPINT lpiProtocols,
277                   OUT LPWSAPROTOCOL_INFOW lpProtocolBuffer,
278                   IN OUT  LPDWORD lpdwBufferLength)
279 {
280     INT error, count;
281     DPRINT("WSAEnumProtocolsW: %p %p %p\n", lpiProtocols, lpProtocolBuffer, lpdwBufferLength);
282     count = WSCEnumProtocols(lpiProtocols, lpProtocolBuffer, lpdwBufferLength, &error);
283     if (SOCKET_ERROR == count)
284     {
285         SetLastError(error);
286         return SOCKET_ERROR;
287     }
288     return count;
289 }
290 
291 
292 /*
293  * @implemented
294  */
295 INT
296 WSPAPI
297 WPUGetProviderPath(IN LPGUID lpProviderId,
298                    OUT LPWSTR lpszProviderDllPath,
299                    IN OUT LPINT lpProviderDllPathLen,
300                    OUT LPINT lpErrno)
301 {
302     return WSCGetProviderPath(lpProviderId, lpszProviderDllPath, lpProviderDllPathLen, lpErrno);
303 }
304 
305 /*
306  * @implemented
307  */
308 INT
309 WSAAPI
310 WSAProviderConfigChange(IN OUT LPHANDLE lpNotificationHandle,
311                         IN LPWSAOVERLAPPED lpOverlapped,
312                         IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
313 {
314     DPRINT("WSAProviderConfigChange: %p\n", lpNotificationHandle);
315     UNIMPLEMENTED;
316     SetLastError(WSAEINVAL);
317     return SOCKET_ERROR;
318 }
319 
320 /*
321  * @implemented
322  */
323 INT
324 WSPAPI
325 WSCGetProviderPath(IN LPGUID lpProviderId,
326                    OUT LPWSTR lpszProviderDllPath,
327                    IN OUT LPINT lpProviderDllPathLen,
328                    OUT LPINT lpErrno)
329 {
330     PWSTHREAD Thread;
331     PWSPROCESS Process;
332     PNSCATALOG Catalog;
333     INT ErrorCode, PathLen;
334     PROVIDER_ENUM_CONTEXT Context;
335 
336     DPRINT("WSCGetProviderPath: %p %p %p %p\n", lpProviderId, lpszProviderDllPath, lpProviderDllPathLen, lpErrno);
337 
338     /* Enter prolog */
339     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
340     {
341         /* FIXME: if WSANOTINITIALISED, we should init
342          * and perform the search!
343          */
344 
345         /* Leave now */
346         *lpErrno = ErrorCode;
347         return SOCKET_ERROR;
348     }
349 
350     /* Get the catalog */
351     Catalog = WsProcGetNsCatalog(Process);
352 
353     _SEH2_TRY
354     {
355         /* Setup the context */
356         Context.ProviderId = *lpProviderId;
357         Context.ProviderDllPath = lpszProviderDllPath;
358         Context.ProviderDllPathLen = *lpProviderDllPathLen;
359         Context.FoundPathLen = 0;
360         Context.Found = 0;
361         Context.ErrorCode = ERROR_SUCCESS;
362 
363         ErrorCode = ERROR_SUCCESS;
364 
365         /* Enumerate the catalog */
366         WsNcEnumerateCatalogItems(Catalog, ProviderEnumerationProc, &Context);
367 
368         /* Check the error code */
369         if (Context.ErrorCode == ERROR_SUCCESS)
370         {
371             /* Check if provider was found */
372             if (Context.Found)
373             {
374                 PathLen = Context.FoundPathLen;
375 
376                 /* Check whether buffer is too small
377                  * If it isn't, return length without null char
378                  * (see ProviderEnumerationProc)
379                  */
380                 if (Context.FoundPathLen <= *lpProviderDllPathLen)
381                 {
382                     PathLen = Context.FoundPathLen - 1;
383                 }
384                 else
385                 {
386                     ErrorCode = WSAEFAULT;
387                 }
388 
389                 /* Set returned/required length */
390                 *lpProviderDllPathLen = PathLen;
391             }
392             else
393             {
394                 ErrorCode = WSAEINVAL;
395             }
396         }
397         else
398         {
399             ErrorCode = Context.ErrorCode;
400         }
401     }
402     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
403     {
404         ErrorCode = WSAEFAULT;
405     }
406     _SEH2_END;
407 
408     /* Do we have to return failure? */
409     if (ErrorCode != ERROR_SUCCESS)
410     {
411         *lpErrno = ErrorCode;
412         return SOCKET_ERROR;
413     }
414 
415     return 0;
416 }
417