Make sure to return an error if the file generation fails.
[wine.git] / dlls / wsock32 / socket.c
blob7a2025fd5e23624a7e706f86bbc60e5c8b1c24e9
1 /*
2 * WSOCK32 specific functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wine/debug.h"
26 #include "winsock2.h"
27 #include "winnt.h"
28 #include "wscontrol.h"
29 #include "iphlpapi.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
33 /* internal remapper function for the IP_ constants */
34 static INT _remap_optname(INT level, INT optname)
36 TRACE("level=%d, optname=%d\n", level, optname);
37 if (level == IPPROTO_IP) {
38 switch (optname) { /***** from value *****/
39 case 2: return 9; /* IP_MULTICAST_IF */
40 case 3: return 10; /* IP_MULTICAST_TTL */
41 case 4: return 11; /* IP_MULTICAST_LOOP */
42 case 5: return 12; /* IP_ADD_MEMBERSHIP */
43 case 6: return 13; /* IP_DROP_MEMBERSHIP */
44 case 7: return 4; /* IP_TTL */
45 case 8: return 3; /* IP_TOS */
46 case 9: return 14; /* IP_DONTFRAGMENT */
47 default: FIXME("Unknown optname %d, can't remap!\n", optname); return optname;
49 } else {
50 /* don't need to do anything */
51 return optname;
55 /***********************************************************************
56 * setsockopt (WSOCK32.21)
58 * We have these forwarders because, for reasons unknown to us mere mortals,
59 * the values of the IP_ constants changed between winsock.h and winsock2.h.
60 * So, we need to remap them here.
62 INT WINAPI WS1_setsockopt(SOCKET s, INT level, INT optname, char *optval, INT optlen)
64 return setsockopt(s, level, _remap_optname(level, optname), optval, optlen);
67 /***********************************************************************
68 * getsockopt (WSOCK32.7)
70 INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen)
72 return getsockopt(s, level, _remap_optname(level, optname), optval, optlen);
75 /***********************************************************************
76 * WsControl (WSOCK32.1001)
78 * WsControl seems to be an undocumented Win95 function. A lot of
79 * discussion about WsControl can be found on the net, e.g.
80 * Subject: Re: WSOCK32.DLL WsControl Exported Function
81 * From: "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
82 * Date: 1997/08/17
84 * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
85 * on observing the behaviour of WsControl with an app in
86 * Windows 98. It is not fully implemented, and there could
87 * be (are?) errors due to incorrect assumptions made.
90 * WsControl returns WSCTL_SUCCESS on success.
91 * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
92 * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
94 * It doesn't seem to generate errors that can be retrieved by
95 * WSAGetLastError().
99 DWORD WINAPI WsControl(DWORD protocoll,
100 DWORD action,
101 LPVOID pRequestInfo,
102 LPDWORD pcbRequestInfoLen,
103 LPVOID pResponseInfo,
104 LPDWORD pcbResponseInfoLen)
107 /* Get the command structure into a pointer we can use,
108 rather than void */
109 TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
111 TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
112 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
113 pcommand->toi_class, pcommand->toi_type );
117 switch (action)
119 case WSCNTL_TCPIP_QUERY_INFO:
121 switch (pcommand->toi_id)
124 ENTITY_LIST_ID seems to get number of adapters in the system.
125 (almost like an index to be used when calling other WsControl options)
127 case ENTITY_LIST_ID:
129 TDIEntityID *baseptr = pResponseInfo;
130 DWORD numInt, i, ipAddrTableSize;
131 PMIB_IPADDRTABLE table;
133 if (pcommand->toi_class != INFO_CLASS_GENERIC &&
134 pcommand->toi_type != INFO_TYPE_PROVIDER)
136 FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
137 pcommand->toi_class, pcommand->toi_type);
138 return (WSAEOPNOTSUPP);
141 GetNumberOfInterfaces(&numInt);
143 if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
145 return (STATUS_BUFFER_TOO_SMALL);
148 /* expect a 1:1 correspondence between interfaces and IP
149 addresses, so use the cheaper (less memory allocated)
150 GetIpAddrTable rather than GetIfTable */
151 ipAddrTableSize = 0;
152 GetIpAddrTable(NULL, &ipAddrTableSize, FALSE);
153 table = (PMIB_IPADDRTABLE)calloc(1, ipAddrTableSize);
154 if (!table) return -1; /* FIXME: better error code */
155 GetIpAddrTable(table, &ipAddrTableSize, FALSE);
157 /* 0 it out first */
158 memset(baseptr, 0, sizeof(TDIEntityID)*(table->dwNumEntries*2));
160 for (i=0; i<table->dwNumEntries; i++)
162 /* tei_instance is an network interface identifier.
163 I'm not quite sure what the difference is between tei_entity values of
164 CL_NL_ENTITY and IF_ENTITY */
165 baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++;
166 baseptr->tei_entity = IF_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++;
169 /* Calculate size of out buffer */
170 *pcbResponseInfoLen = sizeof(TDIEntityID)*(table->dwNumEntries*2);
171 free(table);
173 break;
177 /* ENTITY_TYPE_ID is used to obtain simple information about a
178 network card, such as MAC Address, description, interface type,
179 number of network addresses, etc. */
180 case ENTITY_TYPE_ID: /* ALSO: IP_MIB_STATS_ID */
182 if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
184 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
186 * ((ULONG *)pResponseInfo) = IF_MIB;
188 /* Calculate size of out buffer */
189 *pcbResponseInfoLen = sizeof (ULONG);
192 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
194 * ((ULONG *)pResponseInfo) = CL_NL_IP;
196 /* Calculate size of out buffer */
197 *pcbResponseInfoLen = sizeof (ULONG);
200 else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
201 pcommand->toi_type == INFO_TYPE_PROVIDER)
203 if (pcommand->toi_entity.tei_entity == IF_ENTITY)
205 MIB_IFROW row;
206 DWORD index = pcommand->toi_entity.tei_instance, ret;
207 DWORD size = sizeof(row) - sizeof(row.wszName) -
208 sizeof(row.bDescr);
210 if (*pcbResponseInfoLen < size)
212 return (STATUS_BUFFER_TOO_SMALL);
214 row.dwIndex = index;
215 ret = GetIfEntry(&row);
216 if (ret != NO_ERROR)
218 ERR ("Error retrieving data for interface index %lu\n", index);
219 return -1; /* FIXME: better error code */
221 size = sizeof(row) - sizeof(row.wszName) -
222 sizeof(row.bDescr) + row.dwDescrLen;
223 if (*pcbResponseInfoLen < size)
225 return (STATUS_BUFFER_TOO_SMALL);
227 memcpy(pResponseInfo, &row.dwIndex, size);
228 *pcbResponseInfoLen = size;
230 else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
232 /* This case is used to obtain general statistics about the
233 network */
235 if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
237 return (STATUS_BUFFER_TOO_SMALL);
239 GetIpStatistics((PMIB_IPSTATS)pResponseInfo);
241 /* Calculate size of out buffer */
242 *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
245 else
247 FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
248 pcommand->toi_class, pcommand->toi_type);
250 return (WSAEOPNOTSUPP);
253 break;
257 /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
258 particular network adapter */
259 case IP_MIB_ADDRTABLE_ENTRY_ID:
261 DWORD index = pcommand->toi_entity.tei_instance;
262 PMIB_IPADDRROW baseIPInfo = (PMIB_IPADDRROW) pResponseInfo;
263 PMIB_IPADDRTABLE table;
264 DWORD tableSize, i;
266 if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
268 return (STATUS_BUFFER_TOO_SMALL);
271 /* overkill, get entire table, because there isn't an
272 exported function that gets just one entry, and don't
273 necessarily want our own private export. */
274 tableSize = 0;
275 GetIpAddrTable(NULL, &tableSize, FALSE);
276 table = (PMIB_IPADDRTABLE)calloc(1, tableSize);
277 if (!table) return -1; /* FIXME: better error code */
278 GetIpAddrTable(table, &tableSize, FALSE);
279 for (i = 0; i < table->dwNumEntries; i++)
281 if (table->table[i].dwIndex == index)
283 memcpy(baseIPInfo, &table->table[i],
284 sizeof(MIB_IPADDRROW));
285 break;
288 free(table);
290 /************************************************************************/
292 /* Calculate size of out buffer */
293 *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
294 break;
298 /* This call returns the routing table.
299 * No official documentation found, even the name of the command is unknown.
300 * Work is based on
301 * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
302 * and testings done with winipcfg.exe, route.exe and ipconfig.exe.
303 * pcommand->toi_entity.tei_instance seems to be the interface number
304 * but route.exe outputs only the information for the last interface
305 * if only the routes for the pcommand->toi_entity.tei_instance
306 * interface are returned. */
307 case IP_MIB_ROUTETABLE_ENTRY_ID: /* FIXME: not real name. Value is 0x101 */
309 DWORD routeTableSize, numRoutes, ndx;
310 PMIB_IPFORWARDTABLE table;
311 IPRouteEntry *winRouteTable = (IPRouteEntry *) pResponseInfo;
313 GetIpForwardTable(NULL, &routeTableSize, FALSE);
314 numRoutes = min(routeTableSize - sizeof(MIB_IPFORWARDTABLE), 0)
315 / sizeof(MIB_IPFORWARDROW) + 1;
316 if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
318 return (STATUS_BUFFER_TOO_SMALL);
320 table = (PMIB_IPFORWARDTABLE)calloc(1, routeTableSize);
321 if (!table) return -1; /* FIXME: better return value */
322 GetIpForwardTable(table, &routeTableSize, FALSE);
324 memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
325 for (ndx = 0; ndx < table->dwNumEntries; ndx++)
327 winRouteTable->ire_addr =
328 table->table[ndx].dwForwardDest;
329 winRouteTable->ire_index =
330 table->table[ndx].dwForwardIfIndex;
331 winRouteTable->ire_metric =
332 table->table[ndx].dwForwardMetric1;
333 /* winRouteTable->ire_option4 =
334 winRouteTable->ire_option5 =
335 winRouteTable->ire_option6 = */
336 winRouteTable->ire_gw = table->table[ndx].dwForwardNextHop;
337 /* winRouteTable->ire_option8 =
338 winRouteTable->ire_option9 =
339 winRouteTable->ire_option10 = */
340 winRouteTable->ire_mask = table->table[ndx].dwForwardMask;
341 /* winRouteTable->ire_option12 = */
342 winRouteTable++;
345 /* calculate the length of the data in the output buffer */
346 *pcbResponseInfoLen = sizeof(IPRouteEntry) *
347 table->dwNumEntries;
349 free(table);
350 break;
354 default:
356 FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx, toi_type=0x%lx\n",
357 pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
358 pcommand->toi_class, pcommand->toi_type);
360 return (WSAEOPNOTSUPP);
364 break;
367 case WSCNTL_TCPIP_ICMP_ECHO:
369 unsigned int addr = *(unsigned int*)pRequestInfo;
370 #if 0
371 int timeout= *(unsigned int*)(inbuf+4);
372 short x1 = *(unsigned short*)(inbuf+8);
373 short sendbufsize = *(unsigned short*)(inbuf+10);
374 char x2 = *(unsigned char*)(inbuf+12);
375 char ttl = *(unsigned char*)(inbuf+13);
376 char service = *(unsigned char*)(inbuf+14);
377 char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
378 #endif
380 FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
381 break;
384 default:
386 FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
387 protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
389 return (WSAEOPNOTSUPP);
394 return (WSCTL_SUCCESS);
399 /***********************************************************************
400 * WSARecvEx (WSOCK32.1107)
402 * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
403 * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
404 * into the flags parameter when a partial packet is read. This only applies to
405 * sockets using the datagram protocol. This method does not seem to be implemented
406 * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
407 * flag when a fragmented packet arrives.
409 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
411 FIXME("(WSARecvEx) partial packet return value not set \n");
412 return recv(s, buf, len, *flags);
416 /***********************************************************************
417 * s_perror (WSOCK32.1108)
419 void WINAPI s_perror(LPCSTR message)
421 FIXME("(%s): stub\n",message);
422 return;