Add the ID of the blocking thread to the error message.
[wine] / dlls / wsock32 / socket.c
1 /*
2  * WSOCK32 specific functions
3  *
4  * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5  *
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.
10  *
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.
15  *
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
19  */
20
21
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"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
32
33 /* internal remapper function for the IP_ constants */
34 static INT _remap_optname(INT level, INT optname)
35 {
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; 
48     }
49   } else {
50     /* don't need to do anything */
51     return optname;
52   }
53 }
54
55 /***********************************************************************
56  *              setsockopt              (WSOCK32.21)
57  *
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.
61  */
62 INT WINAPI WS1_setsockopt(SOCKET s, INT level, INT optname, char *optval, INT optlen)
63 {
64   return setsockopt(s, level, _remap_optname(level, optname), optval, optlen);
65 }
66
67 /***********************************************************************
68  *              getsockopt              (WSOCK32.7)
69  */
70 INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen)
71 {
72   return getsockopt(s, level, _remap_optname(level, optname), optval, optlen);
73 }
74
75 /***********************************************************************
76  *              WsControl (WSOCK32.1001)
77  *
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
83  *
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.
88  *
89  *
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.
93  *
94  * It doesn't seem to generate errors that can be retrieved by
95  * WSAGetLastError().
96  *
97  */
98
99 DWORD WINAPI WsControl(DWORD protocoll,
100                        DWORD action,
101                        LPVOID pRequestInfo,
102                        LPDWORD pcbRequestInfoLen,
103                        LPVOID pResponseInfo,
104                        LPDWORD pcbResponseInfoLen)
105 {
106
107    /* Get the command structure into a pointer we can use,
108       rather than void */
109    TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
110
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 );
114
115
116
117    switch (action)
118    {
119       case WSCNTL_TCPIP_QUERY_INFO:
120       {
121          switch (pcommand->toi_id)
122          {
123             /*
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)
126             */
127             case ENTITY_LIST_ID:
128             {
129                TDIEntityID *baseptr = pResponseInfo;
130                DWORD numInt, i, ipAddrTableSize;
131                PMIB_IPADDRTABLE table;
132
133                if (pcommand->toi_class != INFO_CLASS_GENERIC &&
134                    pcommand->toi_type != INFO_TYPE_PROVIDER)
135                {
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);
139                }
140
141                GetNumberOfInterfaces(&numInt);
142
143                if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
144                {
145                   return (STATUS_BUFFER_TOO_SMALL);
146                }
147
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);
156
157                /* 0 it out first */
158                memset(baseptr, 0, sizeof(TDIEntityID)*(table->dwNumEntries*2));
159
160                for (i=0; i<table->dwNumEntries; i++)
161                {
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++;
167                }
168
169                /* Calculate size of out buffer */
170                *pcbResponseInfoLen = sizeof(TDIEntityID)*(table->dwNumEntries*2);
171                free(table);
172
173                break;
174             }
175
176
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 */
181             {
182                if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
183                {
184                   if (pcommand->toi_entity.tei_entity == IF_ENTITY)
185                   {
186                      * ((ULONG *)pResponseInfo) = IF_MIB;
187
188                      /* Calculate size of out buffer */
189                      *pcbResponseInfoLen = sizeof (ULONG);
190
191                   }
192                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
193                   {
194                      * ((ULONG *)pResponseInfo) = CL_NL_IP;
195
196                      /* Calculate size of out buffer */
197                      *pcbResponseInfoLen = sizeof (ULONG);
198                   }
199                }
200                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
201                         pcommand->toi_type == INFO_TYPE_PROVIDER)
202                {
203                   if (pcommand->toi_entity.tei_entity == IF_ENTITY)
204                   {
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);
209
210                      if (*pcbResponseInfoLen < size)
211                      {
212                         return (STATUS_BUFFER_TOO_SMALL);
213                      }
214                      row.dwIndex = index;
215                      ret = GetIfEntry(&row);
216                      if (ret != NO_ERROR)
217                      {
218                        ERR ("Error retrieving data for interface index %lu\n", index);
219                        return -1; /* FIXME: better error code */
220                      }
221                      size = sizeof(row) - sizeof(row.wszName) -
222                       sizeof(row.bDescr) + row.dwDescrLen;
223                      if (*pcbResponseInfoLen < size)
224                      {
225                         return (STATUS_BUFFER_TOO_SMALL);
226                      }
227                      memcpy(pResponseInfo, &row.dwIndex, size);
228                      *pcbResponseInfoLen = size;
229                   }
230                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
231                   {
232                      /* This case is used to obtain general statistics about the
233                         network */
234
235                      if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS))
236                      {
237                         return (STATUS_BUFFER_TOO_SMALL);
238                      }
239                      GetIpStatistics((PMIB_IPSTATS)pResponseInfo);
240
241                      /* Calculate size of out buffer */
242                      *pcbResponseInfoLen = sizeof(MIB_IPSTATS);
243                   }
244                }
245                else
246                {
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);
249
250                   return (WSAEOPNOTSUPP);
251                }
252
253                break;
254             }
255
256
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:
260             {
261                DWORD index = pcommand->toi_entity.tei_instance;
262                PMIB_IPADDRROW baseIPInfo = (PMIB_IPADDRROW) pResponseInfo;
263                PMIB_IPADDRTABLE table;
264                DWORD tableSize, i;
265
266                if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW))
267                {
268                   return (STATUS_BUFFER_TOO_SMALL);
269                }
270
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++)
280                {
281                     if (table->table[i].dwIndex == index)
282                     {
283                        memcpy(baseIPInfo, &table->table[i],
284                         sizeof(MIB_IPADDRROW));
285                        break;
286                     }
287                }
288                free(table);
289
290                /************************************************************************/
291
292                /* Calculate size of out buffer */
293                *pcbResponseInfoLen = sizeof(MIB_IPADDRROW);
294                break;
295             }
296
297
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 */
308             {
309                 DWORD routeTableSize, numRoutes, ndx;
310                 PMIB_IPFORWARDTABLE table;
311                 IPRouteEntry *winRouteTable  = (IPRouteEntry *) pResponseInfo;
312
313                 GetIpForwardTable(NULL, &routeTableSize, FALSE);
314                 numRoutes = min(routeTableSize - sizeof(MIB_IPFORWARDTABLE), 0)
315                  / sizeof(MIB_IPFORWARDROW) + 1;
316                 if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes)
317                 {
318                     return (STATUS_BUFFER_TOO_SMALL);
319                 }
320                 table = (PMIB_IPFORWARDTABLE)calloc(1, routeTableSize);
321                 if (!table) return -1; /* FIXME: better return value */
322                 GetIpForwardTable(table, &routeTableSize, FALSE);
323
324                 memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes);
325                 for (ndx = 0; ndx < table->dwNumEntries; ndx++)
326                 {
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++;
343                 }
344
345                 /* calculate the length of the data in the output buffer */
346                 *pcbResponseInfoLen = sizeof(IPRouteEntry) *
347                  table->dwNumEntries;
348
349                 free(table);
350                 break;
351             }
352
353
354             default:
355             {
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);
359
360                return (WSAEOPNOTSUPP);
361             }
362          }
363
364          break;
365       }
366
367       case WSCNTL_TCPIP_ICMP_ECHO:
368       {
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
379
380          FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
381          break;
382       }
383
384       default:
385       {
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);
388
389          return (WSAEOPNOTSUPP);
390       }
391    }
392
393
394    return (WSCTL_SUCCESS);
395 }
396
397
398
399 /***********************************************************************
400  *              WSARecvEx                       (WSOCK32.1107)
401  *
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.
408  */
409 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
410 {
411     FIXME("(WSARecvEx) partial packet return value not set \n");
412     return recv(s, buf, len, *flags);
413 }
414
415
416 /***********************************************************************
417  *       s_perror         (WSOCK32.1108)
418  */
419 void WINAPI s_perror(LPCSTR message)
420 {
421     FIXME("(%s): stub\n",message);
422     return;
423 }