Implemented EnumProtocolA/W.
[wine] / dlls / wsock32 / protocol.c
1 /*
2  * WSOCK32 specific functions
3  *
4  * Copyright (C) 2001 Stefan Leichter
5  */
6
7 #include "config.h"
8
9 #include <stdio.h>
10 #include "winbase.h"
11 #include "debugtools.h"
12 #include "heap.h"
13 #include "nspapi.h"
14 #include "winsock.h"
15 #include "wsipx.h"
16 #include "wshisotp.h"
17
18 DEFAULT_DEBUG_CHANNEL(winsock);
19
20 /* name of the protocols
21  */
22 static WCHAR NameIpx[]   = {'I', 'P', 'X', '\0'};
23 static WCHAR NameSpx[]   = {'S', 'P', 'X', '\0'};
24 static WCHAR NameSpxII[] = {'S', 'P', 'X', ' ', 'I', 'I', '\0'};
25 static WCHAR NameTcp[]   = {'T', 'C', 'P', '/', 'I', 'P', '\0'};
26 static WCHAR NameUdp[]   = {'U', 'D', 'P', '/', 'I', 'P', '\0'};
27
28 /*****************************************************************************
29  *          WSOCK32_EnterSingleProtocol [internal]
30  *
31  *    enters the protocol informations of one given protocol into the
32  *    given buffer. If the given buffer is too small only the required size for
33  *    the protocols are returned.
34  *
35  * RETURNS
36  *    The number of protocols entered into the buffer
37  *
38  * BUGS
39  *    - only implemented for IPX, SPX, SPXII, TCP, UDP
40  *    - there is no check that the operating system supports the returned
41  *      protocols
42  */
43 static INT WSOCK32_EnterSingleProtocol( INT iProtocol,
44                                         PROTOCOL_INFOA* lpBuffer,
45                                         LPDWORD lpSize, BOOL unicode)
46 { DWORD  dwLength = 0, dwOldSize = *lpSize;
47   INT    iAnz = 1;
48   WCHAR  *lpProtName = NULL;
49
50   *lpSize = sizeof( PROTOCOL_INFOA);
51   switch (iProtocol) {
52     case IPPROTO_TCP :
53         dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameTcp)+1) :
54                                WideCharToMultiByte( CP_ACP, 0, NameTcp, -1,
55                                                     NULL, 0, NULL, NULL);
56       break;
57     case IPPROTO_UDP :
58         dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameUdp)+1) :
59                                WideCharToMultiByte( CP_ACP, 0, NameUdp, -1,
60                                                     NULL, 0, NULL, NULL);
61       break;
62     case NSPROTO_IPX :
63         dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameIpx)+1) :
64                                WideCharToMultiByte( CP_ACP, 0, NameIpx, -1,
65                                                     NULL, 0, NULL, NULL);
66       break;
67     case NSPROTO_SPX :
68         dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameSpx)+1) :
69                                WideCharToMultiByte( CP_ACP, 0, NameSpx, -1,
70                                                     NULL, 0, NULL, NULL);
71       break;
72     case NSPROTO_SPXII :
73         dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameSpxII)+1) :
74                                WideCharToMultiByte( CP_ACP, 0, NameSpxII, -1,
75                                                     NULL, 0, NULL, NULL);
76       break;
77     default:
78         *lpSize = 0;
79         if ((iProtocol == ISOPROTO_TP4) || (iProtocol == NSPROTO_SPX))
80           FIXME("Protocol <%s> not implemented\n",
81                 (iProtocol == ISOPROTO_TP4) ? "ISOPROTO_TP4" : "NSPROTO_SPX");
82         else
83           FIXME("unknown Protocol <0x%08x>\n", iProtocol);
84       break;
85   }
86   *lpSize += dwLength;
87
88   if ( !lpBuffer || !*lpSize || (*lpSize > dwOldSize))
89      return 0;
90
91   memset( lpBuffer, 0, dwOldSize);
92
93   lpBuffer->lpProtocol = (LPSTR) &lpBuffer[ iAnz];
94   lpBuffer->iProtocol  = iProtocol;
95
96   switch (iProtocol) {
97     case IPPROTO_TCP :
98         lpBuffer->dwServiceFlags = XP_FRAGMENTATION      | XP_EXPEDITED_DATA     |
99                                    XP_GRACEFUL_CLOSE     | XP_GUARANTEED_ORDER   |
100                                    XP_GUARANTEED_DELIVERY;
101         lpBuffer->iAddressFamily = WS_AF_INET;
102         lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
103         lpBuffer->iMinSockAddr   = 0x10;  /* NT4 SP5 */
104         lpBuffer->iSocketType    = SOCK_STREAM;
105         lpBuffer->dwMessageSize  = 0;
106         lpProtName = NameTcp;
107       break;
108     case IPPROTO_UDP :
109         lpBuffer->dwServiceFlags = XP_FRAGMENTATION      | XP_SUPPORTS_BROADCAST |
110                                    XP_SUPPORTS_MULTICAST | XP_MESSAGE_ORIENTED   |
111                                    XP_CONNECTIONLESS;
112         lpBuffer->iAddressFamily = WS_AF_INET;
113         lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
114         lpBuffer->iMinSockAddr   = 0x10;  /* NT4 SP5 */
115         lpBuffer->iSocketType    = SOCK_DGRAM;
116         lpBuffer->dwMessageSize  = 65457; /* NT4 SP5 */
117         lpProtName = NameUdp;
118       break;
119     case NSPROTO_IPX :
120         lpBuffer->dwServiceFlags = XP_FRAGMENTATION      | XP_SUPPORTS_BROADCAST |
121                                    XP_SUPPORTS_MULTICAST | XP_MESSAGE_ORIENTED   |
122                                    XP_CONNECTIONLESS;
123         lpBuffer->iAddressFamily = WS_AF_IPX;
124         lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
125         lpBuffer->iMinSockAddr   = 0x0e;  /* NT4 SP5 */
126         lpBuffer->iSocketType    = SOCK_DGRAM;
127         lpBuffer->dwMessageSize  = 576;   /* NT4 SP5 */
128         lpProtName = NameIpx;
129       break;
130     case NSPROTO_SPX :
131         lpBuffer->dwServiceFlags = XP_FRAGMENTATION      |
132                                    XP_PSEUDO_STREAM      | XP_MESSAGE_ORIENTED   |
133                                    XP_GUARANTEED_ORDER   | XP_GUARANTEED_DELIVERY;
134         lpBuffer->iAddressFamily = WS_AF_IPX;
135         lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
136         lpBuffer->iMinSockAddr   = 0x0e;  /* NT4 SP5 */
137         lpBuffer->iSocketType    = 5;
138         lpBuffer->dwMessageSize  = -1;    /* NT4 SP5 */
139         lpProtName = NameSpx;
140       break;
141     case NSPROTO_SPXII :
142         lpBuffer->dwServiceFlags = XP_FRAGMENTATION      | XP_GRACEFUL_CLOSE     |
143                                    XP_PSEUDO_STREAM      | XP_MESSAGE_ORIENTED   |
144                                    XP_GUARANTEED_ORDER   | XP_GUARANTEED_DELIVERY;
145         lpBuffer->iAddressFamily = WS_AF_IPX;
146         lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
147         lpBuffer->iMinSockAddr   = 0x0e;  /* NT4 SP5 */
148         lpBuffer->iSocketType    = 5;
149         lpBuffer->dwMessageSize  = -1;    /* NT4 SP5 */
150         lpProtName = NameSpxII;
151       break;
152   }
153   if (unicode)
154     strcpyW( (LPWSTR)lpBuffer->lpProtocol, lpProtName);
155   else
156     WideCharToMultiByte( CP_ACP, 0, lpProtName, -1, lpBuffer->lpProtocol,
157                          dwOldSize - iAnz * sizeof( PROTOCOL_INFOA), NULL, NULL);
158
159   return iAnz;
160 }
161
162 /*****************************************************************************
163  *          WSOCK32_EnumProtocol [internal]
164  *
165  *    Enters the information about installed protocols into a given buffer
166  *
167  * RETURNS
168  *    SOCKET_ERROR if the buffer is to small for the requested protocol infos
169  *    on success the number of protocols inside the buffer
170  *
171  * NOTE
172  *    NT4SP5 does not return SPX if lpiProtocols == NULL
173  *
174  * BUGS
175  *    - NT4SP5 returns in addition these list of NETBIOS protocols
176  *      (address family 17), each entry two times one for socket type 2 and 5
177  *
178  *      iProtocol   lpProtocol
179  *      0x80000000  \Device\NwlnkNb
180  *      0xfffffffa  \Device\NetBT_CBENT7
181  *      0xfffffffb  \Device\Nbf_CBENT7
182  *      0xfffffffc  \Device\NetBT_NdisWan5
183  *      0xfffffffd  \Device\NetBT_El9202
184  *      0xfffffffe  \Device\Nbf_El9202
185  *      0xffffffff  \Device\Nbf_NdisWan4
186  *
187  *    - there is no check that the operating system supports the returned
188  *      protocols
189  */
190 static INT WSOCK32_EnumProtocol( LPINT lpiProtocols, PROTOCOL_INFOA* lpBuffer,
191                                  LPDWORD lpdwLength, BOOL unicode)
192 { DWORD dwCurSize, dwOldSize = *lpdwLength, dwTemp;
193   INT   anz = 0, i;
194   INT   iLocal[] = { IPPROTO_TCP, IPPROTO_UDP, NSPROTO_IPX, NSPROTO_SPXII, 0};
195
196   if (!lpiProtocols) lpiProtocols = iLocal;
197
198   *lpdwLength = 0;
199   while ( *lpiProtocols )
200   { dwCurSize = 0;
201     WSOCK32_EnterSingleProtocol( *lpiProtocols, NULL, &dwCurSize, unicode);
202
203     if ( lpBuffer && dwCurSize && ((*lpdwLength + dwCurSize) <= dwOldSize))
204     { /* reserve the required space for the current protocol_info after the
205        * last protocol_info before the start of the string buffer and adjust
206        * the references into the string buffer
207        */
208       memmove( &((char*)&lpBuffer[ anz])[dwCurSize],
209                   &lpBuffer[ anz],
210                *lpdwLength - anz * sizeof( PROTOCOL_INFOA));
211       for (i=0; i < anz; i++)
212         lpBuffer[i].lpProtocol += dwCurSize;
213
214       dwTemp = dwCurSize;
215       anz += WSOCK32_EnterSingleProtocol( *lpiProtocols, &lpBuffer[anz],
216                                           &dwTemp, unicode);
217     }
218
219     *lpdwLength += dwCurSize;
220     lpiProtocols++;
221   }
222
223   if (dwOldSize < *lpdwLength) anz = SOCKET_ERROR;
224
225   return anz;
226 }
227
228 /*****************************************************************************
229  *          EnumProtocolsA       [WSOCK32.1111]
230  *
231  *    see function WSOCK32_EnumProtocol for RETURNS, BUGS
232  */
233 INT WINAPI EnumProtocolsA( LPINT lpiProtocols, LPVOID lpBuffer,
234                            LPDWORD lpdwLength)
235 {
236    return WSOCK32_EnumProtocol( lpiProtocols, (PROTOCOL_INFOA*) lpBuffer,
237                                 lpdwLength, FALSE);
238 }
239
240 /*****************************************************************************
241  *          EnumProtocolsW       [WSOCK32.1112]
242  *
243  *    see function WSOCK32_EnumProtocol for RETURNS, BUGS
244  */
245 INT WINAPI EnumProtocolsW( LPINT lpiProtocols, LPVOID lpBuffer,
246                            LPDWORD lpdwLength)
247 {
248    return WSOCK32_EnumProtocol( lpiProtocols, (PROTOCOL_INFOA*) lpBuffer,
249                                 lpdwLength, TRUE);
250 }