socket.c 96.9 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * based on Windows Sockets 1.1 specs
 * (ftp.microsoft.com:/Advsys/winsock/spec11/WINSOCK.TXT)
4
 *
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
20
 *
21 22
 * NOTE: If you make any changes to fix a particular app, make sure
 * they don't break something else like Netscape or telnet and ftp
Alexandre Julliard's avatar
Alexandre Julliard committed
23
 * clients and servers (www.winsite.com got a lot of those).
Alexandre Julliard's avatar
Alexandre Julliard committed
24
 */
25

26
#include "config.h"
27
#include "wine/port.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
28

29
#include <stdarg.h>
30
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
31 32
#include <string.h>
#include <sys/types.h>
33 34 35
#ifdef HAVE_SYS_IPC_H
# include <sys/ipc.h>
#endif
36 37 38
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
39 40 41
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
42 43 44
#ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
45

Alexandre Julliard's avatar
Alexandre Julliard committed
46
#if defined(__EMX__)
Alexandre Julliard's avatar
Alexandre Julliard committed
47
# include <sys/so_ioctl.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
48
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
49 50 51 52 53

#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif

54 55 56 57 58 59
#ifdef HAVE_SYS_MSG_H
# include <sys/msg.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
60 61 62
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
63
#ifdef HAVE_SYS_SOCKET_H
Alexandre Julliard's avatar
Alexandre Julliard committed
64
#include <sys/socket.h>
65 66 67 68 69 70 71 72 73 74
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_TCP_H
# include <netinet/tcp.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
75
#include <ctype.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
76 77
#include <fcntl.h>
#include <errno.h>
78
#ifdef HAVE_SYS_ERRNO_H
Alexandre Julliard's avatar
Alexandre Julliard committed
79
#include <sys/errno.h>
80
#endif
81
#ifdef HAVE_NETDB_H
Alexandre Julliard's avatar
Alexandre Julliard committed
82
#include <netdb.h>
83
#endif
84 85 86
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
87
#include <stdlib.h>
88 89 90
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h>
#endif
91 92 93
#ifdef HAVE_RESOLV_H
# include <resolv.h>
#endif
94 95 96
#ifdef HAVE_NET_IF_H
# include <net/if.h>
#endif
97 98 99 100 101 102 103 104 105
#ifdef HAVE_IPX_GNU
# include <netipx/ipx.h>
# define HAVE_IPX
#endif
#ifdef HAVE_IPX_LINUX
# include <asm/types.h>
# include <linux/ipx.h>
# define HAVE_IPX
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
106

107 108 109
#ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
#endif
Marcus Meissner's avatar
Marcus Meissner committed
110 111 112 113
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif

114 115
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
116 117
#include "windef.h"
#include "winbase.h"
118 119
#include "wingdi.h"
#include "winuser.h"
120
#include "winerror.h"
121
#include "winsock2.h"
122
#include "ws2tcpip.h"
123
#include "wsipx.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
124
#include "winnt.h"
125
#include "iphlpapi.h"
126
#include "thread.h"
127
#include "wine/server.h"
128
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
129

130 131
#ifdef __FreeBSD__
# define sipx_network    sipx_addr.x_net
132
# define sipx_node       sipx_addr.x_host.c_host
133
#endif  /* __FreeBSD__ */
134

135
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
136

137 138 139
/* critical section to protect some non-rentrant net function */
extern CRITICAL_SECTION csWSgetXXXbyYYY;

140 141 142 143 144 145 146 147
inline static const char *debugstr_sockaddr( const struct WS_sockaddr *a )
{
    if (!a) return "(nil)";
    return wine_dbg_sprintf("{ family %d, address %s, port %d }",
                            ((struct sockaddr_in *)a)->sin_family,
                            inet_ntoa(((struct sockaddr_in *)a)->sin_addr),
                            ntohs(((struct sockaddr_in *)a)->sin_port));
}
Alexandre Julliard's avatar
Alexandre Julliard committed
148

149 150 151 152
/* HANDLE<->SOCKET conversion (SOCKET is UINT_PTR). */
#define SOCKET2HANDLE(s) ((HANDLE)(s))
#define HANDLE2SOCKET(h) ((SOCKET)(h))

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
/****************************************************************
 * Async IO declarations
 ****************************************************************/
#include "async.h"

static DWORD ws2_async_get_count  (const struct async_private *ovp);
static void CALLBACK ws2_async_call_completion (ULONG_PTR data);
static void ws2_async_cleanup ( struct async_private *ovp );

static struct async_ops ws2_async_ops =
{
    ws2_async_get_count,
    ws2_async_call_completion,
    ws2_async_cleanup
};

static struct async_ops ws2_nocomp_async_ops =
{
    ws2_async_get_count,
    NULL,                     /* call_completion */
    ws2_async_cleanup
};

typedef struct ws2_async
{
    async_private                       async;
    LPWSAOVERLAPPED                     user_overlapped;
    LPWSAOVERLAPPED_COMPLETION_ROUTINE  completion_func;
    struct iovec                        *iovec;
    int                                 n_iovecs;
183
    struct WS_sockaddr                  *addr;
184 185 186 187 188 189 190 191 192
    union {
        int val;     /* for send operations */
        int *ptr;    /* for recv operations */
    }                                   addrlen;
    DWORD                               flags;
} ws2_async;

/****************************************************************/

Alexandre Julliard's avatar
Alexandre Julliard committed
193 194
/* ----------------------------------- internal data */

195 196 197 198 199 200 201
/* ws_... struct conversion flags */

typedef struct          /* WSAAsyncSelect() control struct */
{
  HANDLE      service, event, sock;
  HWND        hWnd;
  UINT        uMsg;
202
  LONG        lEvent;
203
} ws_select_info;
204 205 206

#define WS_MAX_SOCKETS_PER_PROCESS      128     /* reasonable guess */
#define WS_MAX_UDP_DATAGRAM             1024
207
static INT WINAPI WSA_DefaultBlockingHook( FARPROC x );
208

209 210 211
static struct WS_hostent *he_buffer;          /* typecast for Win32 ws_hostent */
static struct WS_servent *se_buffer;          /* typecast for Win32 ws_servent */
static struct WS_protoent *pe_buffer;          /* typecast for Win32 ws_protoent */
212
static INT num_startup;          /* reference counter */
213
static FARPROC blocking_hook = WSA_DefaultBlockingHook;
214 215

/* function prototypes */
216 217 218
static struct WS_hostent *WS_dup_he(const struct hostent* p_he);
static struct WS_protoent *WS_dup_pe(const struct protoent* p_pe);
static struct WS_servent *WS_dup_se(const struct servent* p_se);
219

220 221 222
int WSAIOCTL_GetInterfaceCount(void);
int WSAIOCTL_GetInterfaceName(int intNumber, char *intName);

223 224
UINT wsaErrno(void);
UINT wsaHerrno(int errnr);
Alexandre Julliard's avatar
Alexandre Julliard committed
225

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
#define MAP_OPTION(opt) { WS_##opt, opt }

static const int ws_sock_map[][2] =
{
    MAP_OPTION( SO_DEBUG ),
    MAP_OPTION( SO_REUSEADDR ),
    MAP_OPTION( SO_KEEPALIVE ),
    MAP_OPTION( SO_DONTROUTE ),
    MAP_OPTION( SO_BROADCAST ),
    MAP_OPTION( SO_LINGER ),
    MAP_OPTION( SO_OOBINLINE ),
    MAP_OPTION( SO_SNDBUF ),
    MAP_OPTION( SO_RCVBUF ),
    MAP_OPTION( SO_ERROR ),
    MAP_OPTION( SO_TYPE ),
241
#ifdef SO_RCVTIMEO
242
    MAP_OPTION( SO_RCVTIMEO ),
243 244
#endif
#ifdef SO_SNDTIMEO
245
    MAP_OPTION( SO_SNDTIMEO ),
246
#endif
247
    { 0, 0 }
248 249
};

250
static const int ws_tcp_map[][2] =
251
{
252 253 254 255
#ifdef TCP_NODELAY
    MAP_OPTION( TCP_NODELAY ),
#endif
    { 0, 0 }
256 257
};

258
static const int ws_ip_map[][2] =
259
{
260 261 262 263 264 265
    MAP_OPTION( IP_MULTICAST_IF ),
    MAP_OPTION( IP_MULTICAST_TTL ),
    MAP_OPTION( IP_MULTICAST_LOOP ),
    MAP_OPTION( IP_ADD_MEMBERSHIP ),
    MAP_OPTION( IP_DROP_MEMBERSHIP ),
    MAP_OPTION( IP_OPTIONS ),
266
#ifdef IP_HDRINCL
267
    MAP_OPTION( IP_HDRINCL ),
268
#endif
269 270 271
    MAP_OPTION( IP_TOS ),
    MAP_OPTION( IP_TTL ),
    { 0, 0 }
272 273
};

274
static DWORD opentype_tls_index = TLS_OUT_OF_INDEXES;  /* TLS index for SO_OPENTYPE flag */
275

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
inline static DWORD NtStatusToWSAError ( const DWORD status )
{
    /* We only need to cover the status codes set by server async request handling */
    DWORD wserr;
    switch ( status )
    {
    case STATUS_SUCCESS:              wserr = 0;                     break;
    case STATUS_PENDING:              wserr = WSA_IO_PENDING;        break;
    case STATUS_INVALID_HANDLE:       wserr = WSAENOTSOCK;           break;  /* WSAEBADF ? */
    case STATUS_INVALID_PARAMETER:    wserr = WSAEINVAL;             break;
    case STATUS_PIPE_DISCONNECTED:    wserr = WSAESHUTDOWN;          break;
    case STATUS_CANCELLED:            wserr = WSA_OPERATION_ABORTED; break;
    case STATUS_TIMEOUT:              wserr = WSAETIMEDOUT;          break;
    case STATUS_NO_MEMORY:            wserr = WSAEFAULT;             break;
    default:
        if ( status >= WSABASEERR && status <= WSABASEERR+1004 )
            /* It is not a NT status code but a winsock error */
            wserr = status;
        else
        {
            wserr = RtlNtStatusToDosError( status );
            FIXME ( "Status code %08lx converted to DOS error code %lx\n", status, wserr );
        }
    }
    return wserr;
}

303 304
/* set last error code from NT status without mapping WSA errors */
inline static unsigned int set_error( unsigned int err )
305
{
306
    if (err)
307
    {
308
        err = NtStatusToWSAError ( err );
309
        SetLastError( err );
310
    }
311
    return err;
312 313
}

314
inline static int get_sock_fd( SOCKET s, DWORD access, int *flags )
315
{
316
    int fd;
317
    if (set_error( wine_server_handle_to_fd( SOCKET2HANDLE(s), access, &fd, NULL, flags ) ))
318
        return -1;
319
    return fd;
320 321
}

322
inline static void release_sock_fd( SOCKET s, int fd )
323
{
324
    wine_server_release_fd( SOCKET2HANDLE(s), fd );
325 326
}

327 328
static void _enable_event( HANDLE s, unsigned int event,
                           unsigned int sstate, unsigned int cstate )
329
{
330
    SERVER_START_REQ( enable_socket_event )
331 332 333 334 335
    {
        req->handle = s;
        req->mask   = event;
        req->sstate = sstate;
        req->cstate = cstate;
336
        wine_server_call( req );
337 338
    }
    SERVER_END_REQ;
339 340 341 342
}

static int _is_blocking(SOCKET s)
{
343
    int ret;
344
    SERVER_START_REQ( get_socket_event )
345
    {
346
        req->handle  = SOCKET2HANDLE(s);
347 348
        req->service = FALSE;
        req->c_event = 0;
349 350
        wine_server_call( req );
        ret = (reply->state & FD_WINE_NONBLOCKING) == 0;
351 352 353
    }
    SERVER_END_REQ;
    return ret;
354 355 356 357
}

static unsigned int _get_sock_mask(SOCKET s)
{
358
    unsigned int ret;
359
    SERVER_START_REQ( get_socket_event )
360
    {
361
        req->handle  = SOCKET2HANDLE(s);
362 363
        req->service = FALSE;
        req->c_event = 0;
364 365
        wine_server_call( req );
        ret = reply->mask;
366 367 368
    }
    SERVER_END_REQ;
    return ret;
369
}
370

371
static void _sync_sock_state(SOCKET s)
372
{
373 374 375 376
    /* do a dummy wineserver request in order to let
       the wineserver run through its select loop once */
    (void)_is_blocking(s);
}
377

378 379
static int _get_sock_error(SOCKET s, unsigned int bit)
{
380 381 382
    int events[FD_MAX_EVENTS];

    SERVER_START_REQ( get_socket_event )
383
    {
384
        req->handle  = SOCKET2HANDLE(s);
385 386
        req->service = FALSE;
        req->c_event = 0;
387 388
        wine_server_set_reply( req, events, sizeof(events) );
        wine_server_call( req );
389
    }
390 391
    SERVER_END_REQ;
    return events[bit];
392 393
}

394 395
static void WINSOCK_DeleteIData(void)
{
396
    /* delete scratch buffers */
397

398 399 400
    if (he_buffer) HeapFree( GetProcessHeap(), 0, he_buffer );
    if (se_buffer) HeapFree( GetProcessHeap(), 0, se_buffer );
    if (pe_buffer) HeapFree( GetProcessHeap(), 0, pe_buffer );
401 402 403 404
    he_buffer = NULL;
    se_buffer = NULL;
    pe_buffer = NULL;
    num_startup = 0;
405 406
}

407
/***********************************************************************
408
 *		DllMain (WS2_32.init)
409
 */
410
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad)
411
{
412
    TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad);
413
    switch (fdwReason) {
414
    case DLL_PROCESS_ATTACH:
415
        DisableThreadLibraryCalls(hInstDLL);
416 417
        opentype_tls_index = TlsAlloc();
        break;
418
    case DLL_PROCESS_DETACH:
419
        TlsFree( opentype_tls_index );
420 421 422 423 424 425
	WINSOCK_DeleteIData();
	break;
    }
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
426 427 428 429
/***********************************************************************
 *          convert_sockopt()
 *
 * Converts socket flags from Windows format.
430
 * Return 1 if converted, 0 if not (error).
Alexandre Julliard's avatar
Alexandre Julliard committed
431
 */
432
static int convert_sockopt(INT *level, INT *optname)
Alexandre Julliard's avatar
Alexandre Julliard committed
433
{
Alexandre Julliard's avatar
Alexandre Julliard committed
434
  int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
435 436 437 438
  switch (*level)
  {
     case WS_SOL_SOCKET:
        *level = SOL_SOCKET;
439 440 441 442 443 444 445 446
        for(i=0; ws_sock_map[i][0]; i++)
        {
            if( ws_sock_map[i][0] == *optname )
            {
                *optname = ws_sock_map[i][1];
                return 1;
            }
        }
447
        FIXME("Unknown SOL_SOCKET optname 0x%x\n", *optname);
Alexandre Julliard's avatar
Alexandre Julliard committed
448 449
        break;
     case WS_IPPROTO_TCP:
450
        *level = IPPROTO_TCP;
451 452 453 454 455 456 457 458
        for(i=0; ws_tcp_map[i][0]; i++)
        {
            if ( ws_tcp_map[i][0] == *optname )
            {
                *optname = ws_tcp_map[i][1];
                return 1;
            }
        }
459
        FIXME("Unknown IPPROTO_TCP optname 0x%x\n", *optname);
460
	break;
461 462
     case WS_IPPROTO_IP:
        *level = IPPROTO_IP;
463 464 465 466 467 468 469 470
        for(i=0; ws_ip_map[i][0]; i++)
        {
            if (ws_ip_map[i][0] == *optname )
            {
                *optname = ws_ip_map[i][1];
                return 1;
            }
        }
471 472 473
	FIXME("Unknown IPPROTO_IP optname 0x%x\n", *optname);
	break;
     default: FIXME("Unimplemented or unknown socket level\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
474
  }
475
  return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
476 477
}

478 479 480 481 482 483 484 485 486 487 488
static inline BOOL is_timeout_option( int optname )
{
#ifdef SO_RCVTIMEO
    if (optname == SO_RCVTIMEO) return TRUE;
#endif
#ifdef SO_SNDTIMEO
    if (optname == SO_SNDTIMEO) return TRUE;
#endif
    return FALSE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
489
/* ----------------------------------- Per-thread info (or per-process?) */
Alexandre Julliard's avatar
Alexandre Julliard committed
490

491
static char *strdup_lower(const char *str)
Alexandre Julliard's avatar
Alexandre Julliard committed
492
{
493 494
    int i;
    char *ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
495

496
    if (ret)
Alexandre Julliard's avatar
Alexandre Julliard committed
497
    {
498 499
        for (i = 0; str[i]; i++) ret[i] = tolower(str[i]);
        ret[i] = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
500
    }
501 502
    else SetLastError(WSAENOBUFS);
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
503 504
}

505
static fd_set* fd_set_import( fd_set* fds, const WS_fd_set* wsfds, int access, int* highfd, int lfd[] )
Alexandre Julliard's avatar
Alexandre Julliard committed
506
{
Alexandre Julliard's avatar
Alexandre Julliard committed
507
    /* translate Winsock fd set into local fd set */
508 509
    if( wsfds )
    {
510
        int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
511

512 513 514 515
        FD_ZERO(fds);
        for( i = 0; i < wsfds->fd_count; i++ )
        {
            int s = wsfds->fd_array[i];
516
            int fd = get_sock_fd( s, access, NULL );
517 518 519 520 521 522 523 524 525
            if (fd != -1)
            {
                lfd[ i ] = fd;
                if( fd > *highfd ) *highfd = fd;
                FD_SET(fd, fds);
            }
            else lfd[ i ] = -1;
        }
        return fds;
Alexandre Julliard's avatar
Alexandre Julliard committed
526
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
527
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
528 529
}

Patrik Stridvall's avatar
Patrik Stridvall committed
530
inline static int sock_error_p(int s)
Alexandre Julliard's avatar
Alexandre Julliard committed
531
{
Alexandre Julliard's avatar
Alexandre Julliard committed
532 533 534
    unsigned int optval, optlen;

    optlen = sizeof(optval);
Patrik Stridvall's avatar
Patrik Stridvall committed
535
    getsockopt(s, SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen);
536
    if (optval) WARN("\t[%i] error: %d\n", s, optval);
Alexandre Julliard's avatar
Alexandre Julliard committed
537 538 539
    return optval != 0;
}

540
static int fd_set_export( const fd_set* fds, fd_set* exceptfds, WS_fd_set* wsfds, int lfd[] )
Alexandre Julliard's avatar
Alexandre Julliard committed
541
{
Alexandre Julliard's avatar
Alexandre Julliard committed
542 543 544 545 546
    int num_err = 0;

    /* translate local fd set into Winsock fd set, adding
     * errors to exceptfds (only if app requested it) */

Alexandre Julliard's avatar
Alexandre Julliard committed
547
    if( wsfds )
Alexandre Julliard's avatar
Alexandre Julliard committed
548
    {
549
	int i, j, count = wsfds->fd_count;
Alexandre Julliard's avatar
Alexandre Julliard committed
550 551 552

	for( i = 0, j = 0; i < count; i++ )
	{
553 554 555 556 557 558 559 560 561 562 563 564 565
            int fd = lfd[i];
            SOCKET s = wsfds->fd_array[i];
            if (fd == -1) continue;
            if( FD_ISSET(fd, fds) )
            {
                if ( exceptfds && sock_error_p(fd) )
                {
                    FD_SET(fd, exceptfds);
                    num_err++;
                }
                else wsfds->fd_array[j++] = s;
            }
            release_sock_fd( s, fd );
Alexandre Julliard's avatar
Alexandre Julliard committed
566
	}
567
	wsfds->fd_count = j;
Alexandre Julliard's avatar
Alexandre Julliard committed
568
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
569
    return num_err;
Alexandre Julliard's avatar
Alexandre Julliard committed
570 571
}

572
static void fd_set_unimport( WS_fd_set* wsfds, int lfd[] )
573
{
574
    if ( wsfds )
575
    {
576
	int i;
577

578
	for( i = 0; i < wsfds->fd_count; i++ )
579 580
	    if ( lfd[i] >= 0 ) release_sock_fd( wsfds->fd_array[i], lfd[i] );
        wsfds->fd_count = 0;
581 582 583
    }
}

584 585
/* utility: given an fd, will block until one of the events occurs */
static inline int do_block( int fd, int events )
586
{
587
  struct pollfd pfd;
588

589 590 591 592
  pfd.fd = fd;
  pfd.events = events;
  poll(&pfd, 1, -1);
  return pfd.revents;
593 594 595
}


596
/* ----------------------------------- API -----
Alexandre Julliard's avatar
Alexandre Julliard committed
597 598 599 600
 *
 * Init / cleanup / error checking.
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
601
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
602
 *      WSAStartup		(WS2_32.115)
Alexandre Julliard's avatar
Alexandre Julliard committed
603
 */
604
int WINAPI WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)
605 606 607
{
    TRACE("verReq=%x\n", wVersionRequested);

608
    if (LOBYTE(wVersionRequested) < 1)
609 610 611 612
        return WSAVERNOTSUPPORTED;

    if (!lpWSAData) return WSAEINVAL;

613
    num_startup++;
614

615 616
    /* that's the whole of the negotiation for now */
    lpWSAData->wVersion = wVersionRequested;
617 618 619 620 621 622 623 624
    /* return winsock information */
    lpWSAData->wHighVersion = 0x0202;
    strcpy(lpWSAData->szDescription, "WinSock 2.0" );
    strcpy(lpWSAData->szSystemStatus, "Running" );
    lpWSAData->iMaxSockets = WS_MAX_SOCKETS_PER_PROCESS;
    lpWSAData->iMaxUdpDg = WS_MAX_UDP_DATAGRAM;
    /* don't do anything with lpWSAData->lpVendorInfo */
    /* (some apps don't allocate the space for this field) */
625

626 627 628 629 630
    TRACE("succeeded\n");
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
631
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
632
 *      WSACleanup			(WS2_32.116)
Alexandre Julliard's avatar
Alexandre Julliard committed
633
 */
634
INT WINAPI WSACleanup(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
635
{
636 637 638 639 640
    if (num_startup)
    {
        if (--num_startup > 0) return 0;
        WINSOCK_DeleteIData();
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
641
    }
642
    SetLastError(WSANOTINITIALISED);
643
    return SOCKET_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
644
}
Alexandre Julliard's avatar
Alexandre Julliard committed
645 646


Alexandre Julliard's avatar
Alexandre Julliard committed
647
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
648 649
 *      WSAGetLastError		(WINSOCK.111)
 *      WSAGetLastError		(WS2_32.111)
Alexandre Julliard's avatar
Alexandre Julliard committed
650
 */
651
INT WINAPI WSAGetLastError(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
652
{
653
	return GetLastError();
Alexandre Julliard's avatar
Alexandre Julliard committed
654 655
}

Alexandre Julliard's avatar
Alexandre Julliard committed
656
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
657
 *      WSASetLastError		(WS2_32.112)
Alexandre Julliard's avatar
Alexandre Julliard committed
658
 */
659 660
void WINAPI WSASetLastError(INT iError) {
    SetLastError(iError);
Alexandre Julliard's avatar
Alexandre Julliard committed
661
}
Alexandre Julliard's avatar
Alexandre Julliard committed
662

663
static struct WS_hostent *check_buffer_he(int size)
Alexandre Julliard's avatar
Alexandre Julliard committed
664
{
665 666 667 668
    static int he_len;
    if (he_buffer)
    {
        if (he_len >= size ) return he_buffer;
669
        HeapFree( GetProcessHeap(), 0, he_buffer );
670
    }
671
    he_buffer = HeapAlloc( GetProcessHeap(), 0, (he_len = size) );
672
    if (!he_buffer) SetLastError(WSAENOBUFS);
673
    return he_buffer;
Alexandre Julliard's avatar
Alexandre Julliard committed
674 675
}

676
static struct WS_servent *check_buffer_se(int size)
Alexandre Julliard's avatar
Alexandre Julliard committed
677
{
678 679 680 681
    static int se_len;
    if (se_buffer)
    {
        if (se_len >= size ) return se_buffer;
682
        HeapFree( GetProcessHeap(), 0, se_buffer );
683
    }
684
    se_buffer = HeapAlloc( GetProcessHeap(), 0, (se_len = size) );
685
    if (!se_buffer) SetLastError(WSAENOBUFS);
686
    return se_buffer;
Alexandre Julliard's avatar
Alexandre Julliard committed
687 688
}

689
static struct WS_protoent *check_buffer_pe(int size)
Alexandre Julliard's avatar
Alexandre Julliard committed
690
{
691 692 693 694
    static int pe_len;
    if (pe_buffer)
    {
        if (pe_len >= size ) return pe_buffer;
695
        HeapFree( GetProcessHeap(), 0, pe_buffer );
696
    }
697
    pe_buffer = HeapAlloc( GetProcessHeap(), 0, (pe_len = size) );
698
    if (!pe_buffer) SetLastError(WSAENOBUFS);
699
    return pe_buffer;
Alexandre Julliard's avatar
Alexandre Julliard committed
700 701
}

Alexandre Julliard's avatar
Alexandre Julliard committed
702
/* ----------------------------------- i/o APIs */
Alexandre Julliard's avatar
Alexandre Julliard committed
703

704
#ifdef HAVE_IPX
705
#define SUPPORTED_PF(pf) ((pf)==WS_AF_INET || (pf)== WS_AF_IPX)
706
#else
707
#define SUPPORTED_PF(pf) ((pf)==WS_AF_INET)
708 709
#endif

710

711 712
/**********************************************************************/

713 714
/* Returns the converted address if successful, NULL if it was too small to
 * start with. Note that the returned pointer may be the original pointer
715 716
 * if no conversion is necessary.
 */
717
static const struct sockaddr* ws_sockaddr_ws2u(const struct WS_sockaddr* wsaddr, int wsaddrlen, int *uaddrlen)
Alexandre Julliard's avatar
Alexandre Julliard committed
718
{
719 720
    switch (wsaddr->sa_family)
    {
721
#ifdef HAVE_IPX
722 723
    case WS_AF_IPX:
        {
724
            struct WS_sockaddr_ipx* wsipx=(struct WS_sockaddr_ipx*)wsaddr;
725 726
            struct sockaddr_ipx* uipx;

727
            if (wsaddrlen<sizeof(struct WS_sockaddr_ipx))
728 729 730 731
                return NULL;

            *uaddrlen=sizeof(struct sockaddr_ipx);
            uipx=malloc(*uaddrlen);
732
            memset(&uipx,0,sizeof(uipx));
733 734
            uipx->sipx_family=AF_IPX;
            uipx->sipx_port=wsipx->sa_socket;
735
            /* copy sa_netnum and sa_nodenum to sipx_network and sipx_node
736 737 738
             * in one go
             */
            memcpy(&uipx->sipx_network,wsipx->sa_netnum,sizeof(uipx->sipx_network)+sizeof(uipx->sipx_node));
739
#ifdef IPX_FRAME_NONE
740
            uipx->sipx_type=IPX_FRAME_NONE;
741
#endif
742 743 744 745 746
            return (const struct sockaddr*)uipx;
        }
#endif

    default:
747
        if (wsaddrlen<sizeof(struct WS_sockaddr))
748 749 750 751 752 753 754 755 756
            return NULL;

        /* No conversion needed, just return the original address */
        *uaddrlen=wsaddrlen;
        return (const struct sockaddr*)wsaddr;
    }
    return NULL;
}

757
/* Allocates a Unix sockaddr structure to receive the data */
758
inline struct sockaddr* ws_sockaddr_alloc(const struct WS_sockaddr* wsaddr, int* wsaddrlen, int* uaddrlen)
759
{
760
    if (wsaddr==NULL)
761 762 763 764 765 766 767 768 769
    {
      ERR( "WINE shouldn't pass a NULL wsaddr! Attempting to continue\n" );

      /* This is not strictly the right thing to do. Hope it works however */
      *uaddrlen=0;

      return NULL;
    }

770 771 772 773 774 775 776 777 778
    if (*wsaddrlen==0)
        *uaddrlen=0;
    else
        *uaddrlen=max(sizeof(struct sockaddr),*wsaddrlen);

    return malloc(*uaddrlen);
}

/* Returns 0 if successful, -1 if the buffer is too small */
779
static int ws_sockaddr_u2ws(const struct sockaddr* uaddr, int uaddrlen, struct WS_sockaddr* wsaddr, int* wsaddrlen)
780 781 782 783 784 785 786 787 788
{
    int res;

    switch(uaddr->sa_family)
    {
#ifdef HAVE_IPX
    case AF_IPX:
        {
            struct sockaddr_ipx* uipx=(struct sockaddr_ipx*)uaddr;
789
            struct WS_sockaddr_ipx* wsipx=(struct WS_sockaddr_ipx*)wsaddr;
790 791 792 793 794 795

            res=-1;
            switch (*wsaddrlen) /* how much can we copy? */
            {
            default:
                res=0; /* enough */
796
                *wsaddrlen=uaddrlen;
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
                wsipx->sa_socket=uipx->sipx_port;
                /* fall through */
            case 13:
            case 12:
                memcpy(wsipx->sa_nodenum,uipx->sipx_node,sizeof(wsipx->sa_nodenum));
                /* fall through */
            case 11:
            case 10:
            case 9:
            case 8:
            case 7:
            case 6:
                memcpy(wsipx->sa_netnum,&uipx->sipx_network,sizeof(wsipx->sa_netnum));
                /* fall through */
            case 5:
            case 4:
            case 3:
            case 2:
815
                wsipx->sa_family=WS_AF_IPX;
816 817 818 819
                /* fall through */
            case 1:
            case 0:
                /* way too small */
820
                break;
821 822 823
            }
        }
        break;
824
#endif
825 826 827 828

    default:
        /* No conversion needed */
        memcpy(wsaddr,uaddr,*wsaddrlen);
829 830 831 832 833 834
        if (*wsaddrlen<uaddrlen) {
            res=-1;
        } else {
            *wsaddrlen=uaddrlen;
            res=0;
        }
835 836 837 838
    }
    return res;
}

839
/* to be called to free the memory allocated by ws_sockaddr_ws2u or
840 841
 * ws_sockaddr_alloc
 */
842
inline void ws_sockaddr_free(const struct sockaddr* uaddr, const struct WS_sockaddr* wsaddr)
843 844 845 846 847
{
    if (uaddr!=NULL && uaddr!=(const struct sockaddr*)wsaddr)
        free((void*)uaddr);
}

848 849 850 851 852 853
/**************************************************************************
 * Functions for handling overlapped I/O
 **************************************************************************/

static DWORD ws2_async_get_count (const struct async_private *ovp)
{
854
    return ovp->iosb->Information;
855 856 857 858 859 860
}

static void ws2_async_cleanup ( struct async_private *ap )
{
    struct ws2_async *as = (struct ws2_async*) ap;

861
    TRACE ( "as: %p uovl %p ovl %p\n", as, as->user_overlapped, as->async.iosb );
862 863
    if ( !as->user_overlapped )
    {
864 865
#if 0
        /* FIXME: I don't think this is really used */
866 867
        if ( as->overlapped->hEvent != INVALID_HANDLE_VALUE )
            WSACloseEvent ( as->overlapped->hEvent  );
868 869
#endif
        HeapFree ( GetProcessHeap(), 0, as->async.iosb );
870 871 872 873 874 875 876 877 878 879 880 881 882 883
    }

    if ( as->iovec )
        HeapFree ( GetProcessHeap(), 0, as->iovec );

    HeapFree ( GetProcessHeap(), 0, as );
}

static void CALLBACK ws2_async_call_completion (ULONG_PTR data)
{
    ws2_async* as = (ws2_async*) data;

    TRACE ("data: %p\n", as);

884 885
    as->completion_func ( NtStatusToWSAError (as->async.iosb->u.Status),
                          as->async.iosb->Information,
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
                          as->user_overlapped,
                          as->flags );
    ws2_async_cleanup ( &as->async );
}

/***********************************************************************
 *              WS2_make_async          (INTERNAL)
 */

static void WS2_async_recv (async_private *as);
static void WS2_async_send (async_private *as);

inline static struct ws2_async*
WS2_make_async (SOCKET s, int fd, int type, struct iovec *iovec, DWORD dwBufferCount,
                LPDWORD lpFlags, struct WS_sockaddr *addr,
                LPINT addrlen, LPWSAOVERLAPPED lpOverlapped,
                LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    struct ws2_async *wsa = HeapAlloc ( GetProcessHeap(), 0, sizeof ( ws2_async ) );

    TRACE ( "wsa %p\n", wsa );

    if (!wsa)
        return NULL;

    wsa->async.ops = ( lpCompletionRoutine ? &ws2_async_ops : &ws2_nocomp_async_ops );
    wsa->async.handle = (HANDLE) s;
    wsa->async.fd = fd;
    wsa->async.type = type;
    switch (type)
    {
    case ASYNC_TYPE_READ:
        wsa->flags = *lpFlags;
        wsa->async.func = WS2_async_recv;
        wsa->addrlen.ptr = addrlen;
        break;
    case ASYNC_TYPE_WRITE:
        wsa->flags = 0;
        wsa->async.func = WS2_async_send;
        wsa->addrlen.val = *addrlen;
        break;
    default:
        ERR ("Invalid async type: %d\n", type);
    }
    wsa->user_overlapped = lpOverlapped;
    wsa->completion_func = lpCompletionRoutine;
    wsa->iovec = iovec;
    wsa->n_iovecs = dwBufferCount;
    wsa->addr = addr;

    if ( lpOverlapped )
    {
938
        wsa->async.iosb = (IO_STATUS_BLOCK*)lpOverlapped;
939 940 941 942
        wsa->async.event = ( lpCompletionRoutine ? INVALID_HANDLE_VALUE : lpOverlapped->hEvent );
    }
    else
    {
943 944 945
        wsa->async.iosb = HeapAlloc ( GetProcessHeap(), 0,
                                      sizeof (IO_STATUS_BLOCK) );
        if ( !wsa->async.iosb )
946
            goto error;
947
        wsa->async.event = INVALID_HANDLE_VALUE;
948 949
    }

950 951
    wsa->async.iosb->Information = 0;
    TRACE ( "wsa %p, ops %p, h %p, ev %p, fd %d, func %p, iosb %p, uov %p, cfunc %p\n",
952
            wsa, wsa->async.ops, wsa->async.handle, wsa->async.event, wsa->async.fd, wsa->async.func,
953
            wsa->async.iosb, wsa->user_overlapped, wsa->completion_func );
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973

    return wsa;

error:
    TRACE ("Error\n");
    HeapFree ( GetProcessHeap(), 0, wsa );
    return NULL;
}

/***********************************************************************
 *              WS2_recv                (INTERNAL)
 *
 * Work horse for both synchronous and asynchronous recv() operations.
 */
static int WS2_recv ( int fd, struct iovec* iov, int count,
                      struct WS_sockaddr *lpFrom, LPINT lpFromlen,
                      LPDWORD lpFlags )
{
    struct msghdr hdr;
    int n;
974 975
    TRACE ( "fd %d, iovec %p, count %d addr %s, len %p, flags %lx\n",
            fd, iov, count, debugstr_sockaddr(lpFrom), lpFromlen, *lpFlags);
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994

    hdr.msg_name = NULL;

    if ( lpFrom )
    {
        hdr.msg_namelen = *lpFromlen;
        hdr.msg_name = ws_sockaddr_alloc ( lpFrom, lpFromlen, &hdr.msg_namelen );
        if ( !hdr.msg_name )
        {
            WSASetLastError ( WSAEFAULT );
            n = -1;
            goto out;
        }
    }
    else
        hdr.msg_namelen = 0;

    hdr.msg_iov = iov;
    hdr.msg_iovlen = count;
995
#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
996 997 998
    hdr.msg_accrights = NULL;
    hdr.msg_accrightslen = 0;
#else
999 1000 1001
    hdr.msg_control = NULL;
    hdr.msg_controllen = 0;
    hdr.msg_flags = 0;
1002
#endif
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039

    if ( (n = recvmsg (fd, &hdr, *lpFlags)) == -1 )
    {
        TRACE ( "recvmsg error %d\n", errno);
        goto out;
    }

    if ( lpFrom &&
         ws_sockaddr_u2ws ( hdr.msg_name, hdr.msg_namelen,
                            lpFrom, lpFromlen ) != 0 )
    {
        /* The from buffer was too small, but we read the data
         * anyway. Is that really bad?
         */
        WSASetLastError ( WSAEFAULT );
        WARN ( "Address buffer too small\n" );
    }

out:

    ws_sockaddr_free ( hdr.msg_name, lpFrom );
    TRACE ("-> %d\n", n);
    return n;
}

/***********************************************************************
 *              WS2_async_recv          (INTERNAL)
 *
 * Handler for overlapped recv() operations.
 */
static void WS2_async_recv ( async_private *as )
{
    ws2_async* wsa = (ws2_async*) as;
    int result, err;

    TRACE ( "async %p\n", wsa );

1040
    if ( wsa->async.iosb->u.Status != STATUS_PENDING )
1041
    {
1042
        TRACE ( "status: %ld\n", wsa->async.iosb->u.Status );
1043 1044 1045 1046 1047 1048 1049 1050
        return;
    }

    result = WS2_recv ( wsa->async.fd, wsa->iovec, wsa->n_iovecs,
                        wsa->addr, wsa->addrlen.ptr, &wsa->flags );

    if (result >= 0)
    {
1051 1052
        wsa->async.iosb->u.Status = STATUS_SUCCESS;
        wsa->async.iosb->Information = result;
1053
        TRACE ( "received %d bytes\n", result );
1054
        _enable_event ( wsa->async.handle, FD_READ, 0, 0 );
1055 1056 1057 1058 1059 1060
        return;
    }

    err = wsaErrno ();
    if ( err == WSAEINTR || err == WSAEWOULDBLOCK )  /* errno: EINTR / EAGAIN */
    {
1061
        wsa->async.iosb->u.Status = STATUS_PENDING;
1062
        _enable_event ( wsa->async.handle, FD_READ, 0, 0 );
1063 1064 1065 1066
        TRACE ( "still pending\n" );
    }
    else
    {
1067
        wsa->async.iosb->u.Status = err;
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
        TRACE ( "Error: %x\n", err );
    }
}

/***********************************************************************
 *              WS2_send                (INTERNAL)
 *
 * Work horse for both synchronous and asynchronous send() operations.
 */
static int WS2_send ( int fd, struct iovec* iov, int count,
                      const struct WS_sockaddr *to, INT tolen, DWORD dwFlags )
{
    struct msghdr hdr;
    int n = -1;
1082 1083
    TRACE ( "fd %d, iovec %p, count %d addr %s, len %d, flags %lx\n",
            fd, iov, count, debugstr_sockaddr(to), tolen, dwFlags);
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100

    hdr.msg_name = NULL;

    if ( to )
    {
        hdr.msg_name = (struct sockaddr*) ws_sockaddr_ws2u ( to, tolen, &hdr.msg_namelen );
        if ( !hdr.msg_name )
        {
            WSASetLastError ( WSAEFAULT );
            goto out;
        }
    }
    else
        hdr.msg_namelen = 0;

    hdr.msg_iov = iov;
    hdr.msg_iovlen = count;
1101
#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
1102 1103 1104
    hdr.msg_accrights = NULL;
    hdr.msg_accrightslen = 0;
#else
1105 1106 1107
    hdr.msg_control = NULL;
    hdr.msg_controllen = 0;
    hdr.msg_flags = 0;
1108
#endif
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128

    n = sendmsg (fd, &hdr, dwFlags);

out:
    ws_sockaddr_free ( hdr.msg_name, to );
    return n;
}

/***********************************************************************
 *              WS2_async_send          (INTERNAL)
 *
 * Handler for overlapped send() operations.
 */
static void WS2_async_send ( async_private *as )
{
    ws2_async* wsa = (ws2_async*) as;
    int result, err;

    TRACE ( "async %p\n", wsa );

1129
    if ( wsa->async.iosb->u.Status != STATUS_PENDING )
1130
    {
1131
        TRACE ( "status: %ld\n", wsa->async.iosb->u.Status );
1132 1133 1134 1135 1136 1137 1138 1139
        return;
    }

    result = WS2_send ( wsa->async.fd, wsa->iovec, wsa->n_iovecs,
                        wsa->addr, wsa->addrlen.val, wsa->flags );

    if (result >= 0)
    {
1140 1141
        wsa->async.iosb->u.Status = STATUS_SUCCESS;
        wsa->async.iosb->Information = result;
1142
        TRACE ( "sent %d bytes\n", result );
1143
        _enable_event ( wsa->async.handle, FD_WRITE, 0, 0 );
1144 1145 1146 1147 1148 1149
        return;
    }

    err = wsaErrno ();
    if ( err == WSAEINTR )
    {
1150
        wsa->async.iosb->u.Status = STATUS_PENDING;
1151
        _enable_event ( wsa->async.handle, FD_WRITE, 0, 0 );
1152 1153 1154 1155 1156 1157
        TRACE ( "still pending\n" );
    }
    else
    {
        /* We set the status to a winsock error code and check for that
           later in NtStatusToWSAError () */
1158
        wsa->async.iosb->u.Status = err;
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
        TRACE ( "Error: %x\n", err );
    }
}

/***********************************************************************
 *              WS2_async_shutdown      (INTERNAL)
 *
 * Handler for shutdown() operations on overlapped sockets.
 */
static void WS2_async_shutdown ( async_private *as )
{
    ws2_async* wsa = (ws2_async*) as;
    int err = 1;

    TRACE ( "async %p %d\n", wsa, wsa->async.type );
    switch ( wsa->async.type )
    {
    case ASYNC_TYPE_READ:
        err = shutdown ( wsa->async.fd, 0 );
        break;
    case ASYNC_TYPE_WRITE:
        err = shutdown ( wsa->async.fd, 1 );
        break;
    default:
        ERR ("invalid type: %d\n", wsa->async.type );
    }

    if ( err )
1187
        wsa->async.iosb->u.Status = wsaErrno ();
1188
    else
1189
        wsa->async.iosb->u.Status = STATUS_SUCCESS;
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
}

/***********************************************************************
 *  WS2_register_async_shutdown         (INTERNAL)
 *
 * Helper function for WS_shutdown() on overlapped sockets.
 */
static int WS2_register_async_shutdown ( SOCKET s, int fd, int type )
{
    struct ws2_async *wsa;
    int ret, err = WSAEFAULT;
    DWORD dwflags = 0;
    int len = 0;
    LPWSAOVERLAPPED ovl = HeapAlloc (GetProcessHeap(), 0, sizeof ( WSAOVERLAPPED ));

    TRACE ("s %d fd %d type %d\n", s, fd, type);
    if (!ovl)
        goto out;

    ovl->hEvent = WSACreateEvent ();
    if ( ovl->hEvent == WSA_INVALID_EVENT  )
        goto out_free;

    wsa = WS2_make_async ( s, fd, type, NULL, 0,
                           &dwflags, NULL, &len, ovl, NULL );
    if ( !wsa )
        goto out_close;

    /* Hack: this will cause ws2_async_cleanup() to free the overlapped structure */
    wsa->user_overlapped = NULL;
    wsa->async.func = WS2_async_shutdown;
    if ( (ret = register_new_async ( &wsa->async )) )
    {
        err = NtStatusToWSAError ( ret );
        goto out;
    }
1226
    /* Try immediate completion */
1227 1228
    while ( WaitForSingleObjectEx ( ovl->hEvent, 0, TRUE ) == STATUS_USER_APC );
    return 0;
1229 1230 1231 1232 1233 1234 1235 1236 1237

out_close:
    WSACloseEvent ( ovl->hEvent );
out_free:
    HeapFree ( GetProcessHeap(), 0, ovl );
out:
    return err;
}

1238 1239 1240
/***********************************************************************
 *		accept		(WS2_32.1)
 */
1241
SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr,
1242 1243
                                 int *addrlen32)
{
1244
    SOCKET as;
Alexandre Julliard's avatar
Alexandre Julliard committed
1245

1246
    TRACE("socket %04x\n", s );
1247
    if (_is_blocking(s))
Alexandre Julliard's avatar
Alexandre Julliard committed
1248
    {
1249 1250 1251 1252 1253 1254 1255 1256 1257
        int fd = get_sock_fd( s, GENERIC_READ, NULL );
        if (fd == -1) return INVALID_SOCKET;
        /* block here */
        do_block(fd, POLLIN);
        _sync_sock_state(s); /* let wineserver notice connection */
        release_sock_fd( s, fd );
        /* retrieve any error codes from it */
        SetLastError(_get_sock_error(s, FD_ACCEPT_BIT));
        /* FIXME: care about the error? */
1258
    }
1259
    SERVER_START_REQ( accept_socket )
1260
    {
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
        req->lhandle = SOCKET2HANDLE(s);
        req->access  = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE;
        req->inherit = TRUE;
        set_error( wine_server_call( req ) );
        as = HANDLE2SOCKET( reply->handle );
    }
    SERVER_END_REQ;
    if (as)
    {
        if (addr) WS_getpeername(as, addr, addrlen32);
        return as;
1272
    }
1273
    return INVALID_SOCKET;
Alexandre Julliard's avatar
Alexandre Julliard committed
1274 1275
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1276
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1277
 *		bind			(WS2_32.2)
Alexandre Julliard's avatar
Alexandre Julliard committed
1278
 */
1279
int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen)
Alexandre Julliard's avatar
Alexandre Julliard committed
1280
{
1281 1282
    int fd = get_sock_fd( s, 0, NULL );
    int res = SOCKET_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1283

1284
    TRACE("socket %04x, ptr %p %s, length %d\n", s, name, debugstr_sockaddr(name), namelen);
Alexandre Julliard's avatar
Alexandre Julliard committed
1285

1286
    if (fd != -1)
1287
    {
1288
        if (!name || !SUPPORTED_PF(name->sa_family))
1289
        {
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
            SetLastError(WSAEAFNOSUPPORT);
        }
        else
        {
            const struct sockaddr* uaddr;
            int uaddrlen;

            uaddr=ws_sockaddr_ws2u(name,namelen,&uaddrlen);
            if (uaddr == NULL)
            {
                SetLastError(WSAEFAULT);
            }
            else
            {
1304 1305 1306
                int on = 1;
                /* The game GrandPrixLegends binds more than one time, but does
                 * not do a SO_REUSEADDR - Stevens says this is ok */
1307
                TRACE( "Setting WS_SO_REUSEADDR on socket before we bind it\n");
1308 1309
                WS_setsockopt( s, WS_SOL_SOCKET, WS_SO_REUSEADDR, (char*)&on, sizeof(on) );

1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
                if (bind(fd, uaddr, uaddrlen) < 0)
                {
                    int loc_errno = errno;
                    WARN("\tfailure - errno = %i\n", errno);
                    errno = loc_errno;
                    switch (errno)
                    {
                    case EBADF:
                        SetLastError(WSAENOTSOCK);
                        break;
                    case EADDRNOTAVAIL:
                        SetLastError(WSAEINVAL);
                        break;
                    default:
                        SetLastError(wsaErrno());
                        break;
                    }
                }
                else
                {
                    res=0; /* success */
                }
                ws_sockaddr_free(uaddr,name);
            }
        }
1335
        release_sock_fd( s, fd );
1336 1337
    }
    return res;
Alexandre Julliard's avatar
Alexandre Julliard committed
1338 1339
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1340
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1341
 *		closesocket		(WS2_32.3)
Alexandre Julliard's avatar
Alexandre Julliard committed
1342
 */
1343
int WINAPI WS_closesocket(SOCKET s)
Alexandre Julliard's avatar
Alexandre Julliard committed
1344
{
1345
    TRACE("socket %08x\n", s);
1346
    if (CloseHandle(SOCKET2HANDLE(s))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1347
    return SOCKET_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1348 1349
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1350
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1351
 *		connect		(WS2_32.4)
Alexandre Julliard's avatar
Alexandre Julliard committed
1352
 */
1353
int WINAPI WS_connect(SOCKET s, const struct WS_sockaddr* name, int namelen)
Alexandre Julliard's avatar
Alexandre Julliard committed
1354
{
1355
    int fd = get_sock_fd( s, GENERIC_READ, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
1356

1357
    TRACE("socket %04x, ptr %p %s, length %d\n", s, name, debugstr_sockaddr(name), namelen);
Alexandre Julliard's avatar
Alexandre Julliard committed
1358

1359
    if (fd != -1)
1360
    {
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
        const struct sockaddr* uaddr;
        int uaddrlen;

        uaddr=ws_sockaddr_ws2u(name,namelen,&uaddrlen);
        if (uaddr == NULL)
        {
            SetLastError(WSAEFAULT);
        }
        else
        {
            int rc;

            rc=connect(fd, uaddr, uaddrlen);
            ws_sockaddr_free(uaddr,name);
            if (rc == 0)
                goto connect_success;
        }

        if (errno == EINPROGRESS)
        {
            /* tell wineserver that a connection is in progress */
1382
            _enable_event(SOCKET2HANDLE(s), FD_CONNECT|FD_READ|FD_WRITE,
1383 1384 1385 1386 1387 1388
                          FD_CONNECT|FD_READ|FD_WRITE,
                          FD_WINE_CONNECTED|FD_WINE_LISTENING);
            if (_is_blocking(s))
            {
                int result;
                /* block here */
1389
                do_block(fd, POLLIN | POLLOUT );
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
                _sync_sock_state(s); /* let wineserver notice connection */
                /* retrieve any error codes from it */
                result = _get_sock_error(s, FD_CONNECT_BIT);
                if (result)
                    SetLastError(result);
                else
                {
                    goto connect_success;
                }
            }
            else
            {
                SetLastError(WSAEWOULDBLOCK);
            }
        }
        else
        {
            SetLastError(wsaErrno());
        }
1409
        release_sock_fd( s, fd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1410
    }
1411 1412
    return SOCKET_ERROR;

1413
connect_success:
1414
    release_sock_fd( s, fd );
1415
    _enable_event(SOCKET2HANDLE(s), FD_CONNECT|FD_READ|FD_WRITE,
1416 1417 1418
                  FD_WINE_CONNECTED|FD_READ|FD_WRITE,
                  FD_CONNECT|FD_WINE_LISTENING);
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1419 1420
}

1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
/***********************************************************************
 *              WSAConnect             (WS2_32.30)
 */
int WINAPI WSAConnect ( SOCKET s, const struct WS_sockaddr* name, int namelen,
                        LPWSABUF lpCallerData, LPWSABUF lpCalleeData,
                        LPQOS lpSQOS, LPQOS lpGQOS )
{
    if ( lpCallerData || lpCalleeData || lpSQOS || lpGQOS )
        FIXME ("unsupported parameters!\n");
    return WS_connect ( s, name, namelen );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1434
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1435
 *		getpeername		(WS2_32.5)
Alexandre Julliard's avatar
Alexandre Julliard committed
1436
 */
1437
int WINAPI WS_getpeername(SOCKET s, struct WS_sockaddr *name, int *namelen)
Alexandre Julliard's avatar
Alexandre Julliard committed
1438
{
1439
    int fd;
1440
    int res;
Alexandre Julliard's avatar
Alexandre Julliard committed
1441

1442 1443
    TRACE("socket: %04x, ptr %p, len %8x\n", s, name, *namelen);

1444 1445 1446 1447 1448 1449 1450
    /* Check if what we've received is valid. Should we use IsBadReadPtr? */
    if( (name == NULL) || (namelen == NULL) )
    {
        SetLastError( WSAEFAULT );
        return SOCKET_ERROR;
    }

1451
    fd = get_sock_fd( s, 0, NULL );
1452 1453
    res = SOCKET_ERROR;

1454
    if (fd != -1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1455
    {
1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
        struct sockaddr* uaddr;
        int uaddrlen;

        uaddr=ws_sockaddr_alloc(name,namelen,&uaddrlen);
        if (getpeername(fd, uaddr, &uaddrlen) != 0)
        {
            SetLastError(wsaErrno());
        }
        else if (ws_sockaddr_u2ws(uaddr,uaddrlen,name,namelen) != 0)
        {
            /* The buffer was too small */
            SetLastError(WSAEFAULT);
        }
        else
        {
            res=0;
        }
        ws_sockaddr_free(uaddr,name);
1474
        release_sock_fd( s, fd );
1475 1476
    }
    return res;
Alexandre Julliard's avatar
Alexandre Julliard committed
1477 1478 1479
}

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1480
 *		getsockname		(WS2_32.6)
Alexandre Julliard's avatar
Alexandre Julliard committed
1481
 */
1482
int WINAPI WS_getsockname(SOCKET s, struct WS_sockaddr *name, int *namelen)
Alexandre Julliard's avatar
Alexandre Julliard committed
1483
{
1484
    int fd;
1485 1486 1487
    int res;

    TRACE("socket: %04x, ptr %p, len %8x\n", s, name, *namelen);
Alexandre Julliard's avatar
Alexandre Julliard committed
1488

1489 1490 1491 1492 1493 1494 1495
    /* Check if what we've received is valid. Should we use IsBadReadPtr? */
    if( (name == NULL) || (namelen == NULL) )
    {
        SetLastError( WSAEFAULT );
        return SOCKET_ERROR;
    }

1496
    fd = get_sock_fd( s, 0, NULL );
1497 1498
    res = SOCKET_ERROR;

1499
    if (fd != -1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1500
    {
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
        struct sockaddr* uaddr;
        int uaddrlen;

        uaddr=ws_sockaddr_alloc(name,namelen,&uaddrlen);
        if (getsockname(fd, uaddr, &uaddrlen) != 0)
        {
            SetLastError(wsaErrno());
        }
        else if (ws_sockaddr_u2ws(uaddr,uaddrlen,name,namelen) != 0)
        {
            /* The buffer was too small */
            SetLastError(WSAEFAULT);
        }
        else
        {
            res=0;
        }
1518
        release_sock_fd( s, fd );
1519 1520
    }
    return res;
Alexandre Julliard's avatar
Alexandre Julliard committed
1521 1522
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1523
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1524
 *		getsockopt		(WS2_32.7)
Alexandre Julliard's avatar
Alexandre Julliard committed
1525
 */
1526
INT WINAPI WS_getsockopt(SOCKET s, INT level,
1527
                                  INT optname, char *optval, INT *optlen)
Alexandre Julliard's avatar
Alexandre Julliard committed
1528
{
1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
    int fd;

    TRACE("socket: %04x, level 0x%x, name 0x%x, ptr %8x, len %d\n", s, level,
          (int) optname, (int) optval, (int) *optlen);
    /* SO_OPENTYPE does not require a valid socket handle. */
    if (level == WS_SOL_SOCKET && optname == WS_SO_OPENTYPE)
    {
        if (!optlen || *optlen < sizeof(int) || !optval)
        {
            SetLastError(WSAEFAULT);
            return SOCKET_ERROR;
        }
1541
        *(int *)optval = (int)TlsGetValue( opentype_tls_index );
1542
        *optlen = sizeof(int);
1543
        TRACE("getting global SO_OPENTYPE = 0x%x\n", *((int*)optval) );
1544 1545
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1546

1547
    fd = get_sock_fd( s, 0, NULL );
1548
    if (fd != -1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1549
    {
1550 1551 1552 1553 1554
	if (!convert_sockopt(&level, &optname)) {
	    SetLastError(WSAENOPROTOOPT);	/* Unknown option */
        } else {
	    if (getsockopt(fd, (int) level, optname, optval, optlen) == 0 )
	    {
1555
		release_sock_fd( s, fd );
1556 1557 1558
		return 0;
	    }
	    SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
1559
	}
1560
        release_sock_fd( s, fd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1561 1562
    }
    return SOCKET_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1563 1564
}

1565

Alexandre Julliard's avatar
Alexandre Julliard committed
1566
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1567 1568
 *		htonl			(WINSOCK.8)
 *		htonl			(WS2_32.8)
Alexandre Julliard's avatar
Alexandre Julliard committed
1569
 */
1570 1571 1572 1573 1574 1575
u_long WINAPI WS_htonl(u_long hostlong)
{
    return htonl(hostlong);
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1576
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1577 1578
 *		htons			(WINSOCK.9)
 *		htons			(WS2_32.9)
Alexandre Julliard's avatar
Alexandre Julliard committed
1579
 */
1580 1581 1582 1583 1584
u_short WINAPI WS_htons(u_short hostshort)
{
    return htons(hostshort);
}

1585 1586 1587
/***********************************************************************
 *		WSAHtonl		(WS2_32.46)
 */
Gerald Pfeifer's avatar
Gerald Pfeifer committed
1588
int WINAPI WSAHtonl(SOCKET s, u_long hostlong, u_long *lpnetlong)
1589 1590 1591 1592 1593 1594 1595 1596
{
    FIXME("stub.\n");
    return INVALID_SOCKET;
}

/***********************************************************************
 *		WSAHtons		(WS2_32.47)
 */
Gerald Pfeifer's avatar
Gerald Pfeifer committed
1597
int WINAPI WSAHtons(SOCKET s, u_short hostshort, u_short *lpnetshort)
1598 1599 1600 1601 1602
{
    FIXME("stub.\n");
    return INVALID_SOCKET;
}

1603

Alexandre Julliard's avatar
Alexandre Julliard committed
1604
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1605 1606
 *		inet_addr		(WINSOCK.10)
 *		inet_addr		(WS2_32.11)
Alexandre Julliard's avatar
Alexandre Julliard committed
1607
 */
1608 1609 1610 1611 1612 1613
u_long WINAPI WS_inet_addr(const char *cp)
{
    return inet_addr(cp);
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1614
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1615 1616
 *		ntohl			(WINSOCK.14)
 *		ntohl			(WS2_32.14)
Alexandre Julliard's avatar
Alexandre Julliard committed
1617
 */
1618 1619 1620 1621 1622 1623
u_long WINAPI WS_ntohl(u_long netlong)
{
    return ntohl(netlong);
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1624
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1625 1626
 *		ntohs			(WINSOCK.15)
 *		ntohs			(WS2_32.15)
Alexandre Julliard's avatar
Alexandre Julliard committed
1627
 */
1628 1629 1630 1631 1632
u_short WINAPI WS_ntohs(u_short netshort)
{
    return ntohs(netshort);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1633

Alexandre Julliard's avatar
Alexandre Julliard committed
1634
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1635
 *		inet_ntoa		(WS2_32.12)
Alexandre Julliard's avatar
Alexandre Julliard committed
1636
 */
1637
char* WINAPI WS_inet_ntoa(struct WS_in_addr in)
Alexandre Julliard's avatar
Alexandre Julliard committed
1638
{
1639 1640
  /* use "buffer for dummies" here because some applications have
   * propensity to decode addresses in ws_hostent structure without
Alexandre Julliard's avatar
Alexandre Julliard committed
1641 1642
   * saving them first...
   */
1643 1644
    static char dbuffer[16]; /* Yes, 16: 4*3 digits + 3 '.' + 1 '\0' */

1645
    char* s = inet_ntoa(*((struct in_addr*)&in));
1646
    if( s )
Alexandre Julliard's avatar
Alexandre Julliard committed
1647
    {
1648 1649
        strcpy(dbuffer, s);
        return dbuffer;
Alexandre Julliard's avatar
Alexandre Julliard committed
1650
    }
1651
    SetLastError(wsaErrno());
Alexandre Julliard's avatar
Alexandre Julliard committed
1652 1653 1654
    return NULL;
}

1655
/**********************************************************************
1656
 *              WSAIoctl                (WS2_32.50)
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
 *
 *
 *   FIXME:  Only SIO_GET_INTERFACE_LIST option implemented.
 */
INT WINAPI WSAIoctl (SOCKET s,
                     DWORD   dwIoControlCode,
                     LPVOID  lpvInBuffer,
                     DWORD   cbInBuffer,
                     LPVOID  lpbOutBuffer,
                     DWORD   cbOutBuffer,
                     LPDWORD lpcbBytesReturned,
                     LPWSAOVERLAPPED lpOverlapped,
                     LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
1671
   int fd = get_sock_fd( s, 0, NULL );
1672

1673 1674 1675
   if (fd == -1) return SOCKET_ERROR;

   switch( dwIoControlCode )
1676
   {
1677 1678 1679 1680
   case SIO_GET_INTERFACE_LIST:
       {
           INTERFACE_INFO* intArray = (INTERFACE_INFO*)lpbOutBuffer;
           DWORD size, numInt, apiReturn;
1681

1682
           TRACE ("-> SIO_GET_INTERFACE_LIST request\n");
1683

1684 1685 1686
           if (!lpbOutBuffer)
           {
               release_sock_fd( s, fd );
1687 1688
               WSASetLastError(WSAEFAULT);
               return SOCKET_ERROR;
1689 1690 1691 1692
           }
           if (!lpcbBytesReturned)
           {
               release_sock_fd( s, fd );
1693 1694
               WSASetLastError(WSAEFAULT);
               return SOCKET_ERROR;
1695
           }
1696

1697 1698 1699
           apiReturn = GetAdaptersInfo(NULL, &size);
           if (apiReturn == ERROR_NO_DATA)
           {
1700
               numInt = 0;
1701 1702 1703
           }
           else if (apiReturn == ERROR_BUFFER_OVERFLOW)
           {
1704
               PIP_ADAPTER_INFO table = (PIP_ADAPTER_INFO)HeapAlloc(GetProcessHeap(),0,size);
1705

1706
               if (table)
1707
               {
1708 1709 1710 1711
                  if (GetAdaptersInfo(table, &size) == NO_ERROR)
                  {
                     PIP_ADAPTER_INFO ptr;

1712 1713 1714
                     if (size > cbOutBuffer)
                     {
                        HeapFree(GetProcessHeap(),0,table);
1715
                        release_sock_fd( s, fd );
1716 1717 1718
                        WSASetLastError(WSAEFAULT);
                        return (SOCKET_ERROR);
                     }
1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
                     for (ptr = table, numInt = 0; ptr;
                      ptr = ptr->Next, intArray++, numInt++)
                     {
                        unsigned int addr, mask, bcast;
                        struct ifreq ifInfo;

                        /* Socket Status Flags */
                        strncpy(ifInfo.ifr_name, ptr->AdapterName, IFNAMSIZ);
                        ifInfo.ifr_name[IFNAMSIZ-1] = '\0';
                        if (ioctl(fd, SIOCGIFFLAGS, &ifInfo) < 0)
                        {
                           ERR ("Error obtaining status flags for socket!\n");
                           HeapFree(GetProcessHeap(),0,table);
1732
                           release_sock_fd( s, fd );
1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743
                           WSASetLastError(WSAEINVAL);
                           return (SOCKET_ERROR);
                        }
                        else
                        {
                           /* set flags; the values of IFF_* are not the same
                              under Linux and Windows, therefore must generate
                              new flags */
                           intArray->iiFlags = 0;
                           if (ifInfo.ifr_flags & IFF_BROADCAST)
                              intArray->iiFlags |= WS_IFF_BROADCAST;
1744
#ifdef IFF_POINTOPOINT
1745 1746
                           if (ifInfo.ifr_flags & IFF_POINTOPOINT)
                              intArray->iiFlags |= WS_IFF_POINTTOPOINT;
1747
#endif
1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774
                           if (ifInfo.ifr_flags & IFF_LOOPBACK)
                              intArray->iiFlags |= WS_IFF_LOOPBACK;
                           if (ifInfo.ifr_flags & IFF_UP)
                              intArray->iiFlags |= WS_IFF_UP;
                        }

                        addr = inet_addr(ptr->IpAddressList.IpAddress.String);
                        mask = inet_addr(ptr->IpAddressList.IpMask.String);
                        bcast = addr | (addr & !mask);
                        intArray->iiAddress.AddressIn.sin_family = AF_INET;
                        intArray->iiAddress.AddressIn.sin_port = 0;
                        intArray->iiAddress.AddressIn.sin_addr.WS_s_addr =
                         addr;
                        intArray->iiNetmask.AddressIn.sin_family = AF_INET;
                        intArray->iiNetmask.AddressIn.sin_port = 0;
                        intArray->iiNetmask.AddressIn.sin_addr.WS_s_addr =
                         mask;
                        intArray->iiBroadcastAddress.AddressIn.sin_family =
                         AF_INET;
                        intArray->iiBroadcastAddress.AddressIn.sin_port = 0;
                        intArray->iiBroadcastAddress.AddressIn.sin_addr.
                         WS_s_addr = bcast;
                     }
                  }
                  else
                  {
                     ERR ("Unable to get interface table!\n");
1775
                     release_sock_fd( s, fd );
1776 1777 1778 1779
                     HeapFree(GetProcessHeap(),0,table);
                     WSASetLastError(WSAEINVAL);
                     return (SOCKET_ERROR);
                  }
1780
                  HeapFree(GetProcessHeap(),0,table);
1781 1782 1783
               }
               else
               {
1784
                  release_sock_fd( s, fd );
1785 1786 1787
                  WSASetLastError(WSAEINVAL);
                  return (SOCKET_ERROR);
               }
1788 1789 1790
           }
           else
           {
1791
               ERR ("Unable to get interface table!\n");
1792
               release_sock_fd( s, fd );
1793 1794
               WSASetLastError(WSAEINVAL);
               return (SOCKET_ERROR);
1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805
           }
           /* Calculate the size of the array being returned */
           *lpcbBytesReturned = sizeof(INTERFACE_INFO) * numInt;
           break;
       }

   default:
       WARN("\tunsupported WS_IOCTL cmd (%08lx)\n", dwIoControlCode);
       release_sock_fd( s, fd );
       WSASetLastError(WSAEOPNOTSUPP);
       return (SOCKET_ERROR);
1806
   }
1807 1808 1809 1810

   /* Function executed with no errors */
   release_sock_fd( s, fd );
   return (0);
1811 1812 1813
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1814
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1815
 *		ioctlsocket		(WS2_32.10)
Alexandre Julliard's avatar
Alexandre Julliard committed
1816
 */
1817
int WINAPI WS_ioctlsocket(SOCKET s, long cmd, u_long *argp)
Alexandre Julliard's avatar
Alexandre Julliard committed
1818
{
1819 1820
    int fd;
    long newcmd  = cmd;
Alexandre Julliard's avatar
Alexandre Julliard committed
1821

1822
    TRACE("socket %04x, cmd %08lx, ptr %p\n", s, cmd, argp);
Alexandre Julliard's avatar
Alexandre Julliard committed
1823 1824 1825

    switch( cmd )
    {
1826 1827 1828
    case WS_FIONREAD:
        newcmd=FIONREAD;
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1829

1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843
    case WS_FIONBIO:
        newcmd=FIONBIO;
        if( _get_sock_mask(s) )
        {
            /* AsyncSelect()'ed sockets are always nonblocking */
            if (*argp) return 0;
            SetLastError(WSAEINVAL);
            return SOCKET_ERROR;
        }
        if (*argp)
            _enable_event(SOCKET2HANDLE(s), 0, FD_WINE_NONBLOCKING, 0);
        else
            _enable_event(SOCKET2HANDLE(s), 0, 0, FD_WINE_NONBLOCKING);
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1844

1845 1846 1847
    case WS_SIOCATMARK:
        newcmd=SIOCATMARK;
        break;
1848

1849 1850 1851 1852
    case WS__IOW('f',125,u_long):
        WARN("Warning: WS1.1 shouldn't be using async I/O\n");
        SetLastError(WSAEINVAL);
        return SOCKET_ERROR;
1853

1854 1855 1856 1857 1858 1859
    case SIOCGIFBRDADDR:
    case SIOCGIFNETMASK:
    case SIOCGIFADDR:
        /* These don't need any special handling.  They are used by
           WsControl, and are here to suppress an unecessary warning. */
        break;
1860

1861 1862 1863 1864
    default:
        /* Netscape tries hard to use bogus ioctl 0x667e */
        WARN("\tunknown WS_IOCTL cmd (%08lx)\n", cmd);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1865
    }
1866 1867 1868

    fd = get_sock_fd( s, 0, NULL );
    if (fd != -1)
1869
    {
1870 1871 1872 1873 1874 1875 1876
        if( ioctl(fd, newcmd, (char*)argp ) == 0 )
        {
            release_sock_fd( s, fd );
            return 0;
        }
        SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
        release_sock_fd( s, fd );
1877
    }
1878
    return SOCKET_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1879 1880
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1881
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1882
 *		listen		(WS2_32.13)
Alexandre Julliard's avatar
Alexandre Julliard committed
1883
 */
1884
int WINAPI WS_listen(SOCKET s, int backlog)
Alexandre Julliard's avatar
Alexandre Julliard committed
1885
{
1886
    int fd = get_sock_fd( s, GENERIC_READ, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
1887

1888 1889
    TRACE("socket %04x, backlog %d\n", s, backlog);
    if (fd != -1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1890
    {
1891
	if (listen(fd, backlog) == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1892
	{
1893
            release_sock_fd( s, fd );
1894
	    _enable_event(SOCKET2HANDLE(s), FD_ACCEPT,
1895 1896
			  FD_WINE_LISTENING,
			  FD_CONNECT|FD_WINE_CONNECTED);
Alexandre Julliard's avatar
Alexandre Julliard committed
1897
	    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1898
	}
1899
	SetLastError(wsaErrno());
1900
        release_sock_fd( s, fd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1901
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1902 1903
    return SOCKET_ERROR;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1904

Alexandre Julliard's avatar
Alexandre Julliard committed
1905
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1906
 *		recv			(WS2_32.16)
Alexandre Julliard's avatar
Alexandre Julliard committed
1907
 */
1908
int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1909
{
1910
    DWORD n, dwFlags = flags;
1911 1912 1913 1914
    WSABUF wsabuf;

    wsabuf.len = len;
    wsabuf.buf = buf;
Alexandre Julliard's avatar
Alexandre Julliard committed
1915

1916 1917 1918 1919
    if ( WSARecvFrom (s, &wsabuf, 1, &n, &dwFlags, NULL, NULL, NULL, NULL) == SOCKET_ERROR )
        return SOCKET_ERROR;
    else
        return n;
Alexandre Julliard's avatar
Alexandre Julliard committed
1920 1921
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1922
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1923
 *		recvfrom		(WS2_32.17)
Alexandre Julliard's avatar
Alexandre Julliard committed
1924
 */
1925 1926
int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags,
                                struct WS_sockaddr *from, int *fromlen)
Alexandre Julliard's avatar
Alexandre Julliard committed
1927
{
1928
    DWORD n, dwFlags = flags;
1929 1930 1931 1932
    WSABUF wsabuf;

    wsabuf.len = len;
    wsabuf.buf = buf;
Alexandre Julliard's avatar
Alexandre Julliard committed
1933

1934 1935
    if ( WSARecvFrom (s, &wsabuf, 1, &n, &dwFlags, from, fromlen, NULL, NULL) == SOCKET_ERROR )
        return SOCKET_ERROR;
1936
    else
1937
        return n;
Alexandre Julliard's avatar
Alexandre Julliard committed
1938 1939
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1940
/***********************************************************************
1941
 *		select			(WS2_32.18)
Alexandre Julliard's avatar
Alexandre Julliard committed
1942
 */
1943 1944 1945
int WINAPI WS_select(int nfds, WS_fd_set *ws_readfds,
                     WS_fd_set *ws_writefds, WS_fd_set *ws_exceptfds,
                     const struct WS_timeval* ws_timeout)
Alexandre Julliard's avatar
Alexandre Julliard committed
1946
{
1947 1948 1949 1950
    int         highfd = 0;
    fd_set      readfds, writefds, exceptfds;
    fd_set     *p_read, *p_write, *p_except;
    int         readfd[FD_SETSIZE], writefd[FD_SETSIZE], exceptfd[FD_SETSIZE];
1951
    struct timeval timeout, *timeoutaddr = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1952

1953 1954
    TRACE("read %p, write %p, excp %p timeout %p\n",
          ws_readfds, ws_writefds, ws_exceptfds, ws_timeout);
Alexandre Julliard's avatar
Alexandre Julliard committed
1955

1956 1957 1958
    p_read = fd_set_import(&readfds, ws_readfds, GENERIC_READ, &highfd, readfd);
    p_write = fd_set_import(&writefds, ws_writefds, GENERIC_WRITE, &highfd, writefd);
    p_except = fd_set_import(&exceptfds, ws_exceptfds, 0, &highfd, exceptfd);
1959 1960 1961 1962 1963 1964
    if (ws_timeout)
    {
        timeoutaddr = &timeout;
        timeout.tv_sec=ws_timeout->tv_sec;
        timeout.tv_usec=ws_timeout->tv_usec;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1965

1966
    if( (highfd = select(highfd + 1, p_read, p_write, p_except, timeoutaddr)) > 0 )
1967
    {
1968 1969
        fd_set_export(&readfds, p_except, ws_readfds, readfd);
        fd_set_export(&writefds, p_except, ws_writefds, writefd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1970

1971 1972
        if (p_except && ws_exceptfds)
        {
1973
            int i, j;
Alexandre Julliard's avatar
Alexandre Julliard committed
1974

1975
            for (i = j = 0; i < ws_exceptfds->fd_count; i++)
1976 1977
            {
                int fd = exceptfd[i];
1978 1979 1980 1981
                SOCKET s = ws_exceptfds->fd_array[i];
                if (fd == -1) continue;
                if (FD_ISSET(fd, &exceptfds)) ws_exceptfds->fd_array[j++] = s;
                release_sock_fd( s, fd );
1982
            }
1983
            ws_exceptfds->fd_count = j;
1984 1985 1986
        }
        return highfd;
    }
1987 1988 1989
    fd_set_unimport(ws_readfds, readfd);
    fd_set_unimport(ws_writefds, writefd);
    fd_set_unimport(ws_exceptfds, exceptfd);
1990 1991 1992

    if( highfd == 0 ) return 0;
    SetLastError(wsaErrno());
Alexandre Julliard's avatar
Alexandre Julliard committed
1993
    return SOCKET_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1994 1995 1996
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1997
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1998
 *		send			(WS2_32.19)
Alexandre Julliard's avatar
Alexandre Julliard committed
1999
 */
2000
int WINAPI WS_send(SOCKET s, const char *buf, int len, int flags)
Alexandre Julliard's avatar
Alexandre Julliard committed
2001
{
2002
    DWORD n;
2003 2004 2005 2006
    WSABUF wsabuf;

    wsabuf.len = len;
    wsabuf.buf = (char*) buf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2007

2008 2009 2010 2011
    if ( WSASendTo ( s, &wsabuf, 1, &n, flags, NULL, 0, NULL, NULL) == SOCKET_ERROR )
        return SOCKET_ERROR;
    else
        return n;
Alexandre Julliard's avatar
Alexandre Julliard committed
2012 2013
}

2014
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2015
 *		WSASend			(WS2_32.72)
2016 2017 2018 2019 2020 2021
 */
INT WINAPI WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
                    LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
                    LPWSAOVERLAPPED lpOverlapped,
                    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
2022 2023 2024
    return WSASendTo ( s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags,
                       NULL, 0, lpOverlapped, lpCompletionRoutine );
}
2025

Hagen Heiduck's avatar
Hagen Heiduck committed
2026 2027 2028 2029 2030 2031 2032 2033 2034
/***********************************************************************
 *              WSASendDisconnect       (WS2_32.73)
 */
INT WINAPI WSASendDisconnect( SOCKET s, LPWSABUF lpBuffers )
{
    return WS_shutdown ( s, SD_SEND );
}


2035 2036 2037 2038 2039 2040 2041 2042 2043
/***********************************************************************
 *		WSASendTo		(WS2_32.74)
 */
INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
                      LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
                      const struct WS_sockaddr *to, int tolen,
                      LPWSAOVERLAPPED lpOverlapped,
                      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
2044
    int i, n, fd, err = WSAENOTSOCK, flags, ret;
2045
    struct iovec* iovec;
2046
    struct ws2_async *wsa;
2047

2048 2049 2050
    TRACE ("socket %04x, wsabuf %p, nbufs %ld, flags %ld, to %p, tolen %d, ovl %p, func %p\n",
           s, lpBuffers, dwBufferCount, dwFlags,
           to, tolen, lpOverlapped, lpCompletionRoutine);
2051

2052 2053 2054 2055
    fd = get_sock_fd( s, GENERIC_WRITE, &flags );
    TRACE ( "fd=%d, flags=%x\n", fd, flags );

    if ( fd == -1 ) return SOCKET_ERROR;
2056

2057
    if (flags & FD_FLAG_SEND_SHUTDOWN)
2058
    {
2059 2060
        WSASetLastError ( WSAESHUTDOWN );
        goto err_close;
2061
    }
2062

2063 2064 2065
    if ( !lpNumberOfBytesSent )
    {
        err = WSAEFAULT;
2066
        goto err_close;
2067 2068
    }

2069
    iovec = HeapAlloc (GetProcessHeap(), 0, dwBufferCount * sizeof (struct iovec) );
2070 2071

    if ( !iovec )
2072
    {
2073
        err = WSAEFAULT;
2074
        goto err_close;
2075 2076
    }

2077 2078 2079 2080 2081 2082
    for ( i = 0; i < dwBufferCount; i++ )
    {
        iovec[i].iov_base = lpBuffers[i].buf;
        iovec[i].iov_len  = lpBuffers[i].len;
    }

2083
    if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED )
2084
    {
2085 2086 2087 2088
        wsa = WS2_make_async ( s, fd, ASYNC_TYPE_WRITE, iovec, dwBufferCount,
                               &dwFlags, (struct WS_sockaddr*) to, &tolen,
                               lpOverlapped, lpCompletionRoutine );
        if ( !wsa )
2089 2090 2091 2092 2093
        {
            err = WSAEFAULT;
            goto err_free;
        }

2094 2095 2096
        if ( ( ret = register_new_async ( &wsa->async )) )
        {
            err = NtStatusToWSAError ( ret );
2097

2098
            if ( !lpOverlapped )
2099
                HeapFree ( GetProcessHeap(), 0, wsa->async.iosb );
2100 2101 2102 2103 2104 2105 2106
            HeapFree ( GetProcessHeap(), 0, wsa );
            goto err_free;
        }

        /* Try immediate completion */
        if ( lpOverlapped && !NtResetEvent( lpOverlapped->hEvent, NULL ) )
        {
2107
            if  ( WSAGetOverlappedResult ( s, lpOverlapped,
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
                                           lpNumberOfBytesSent, FALSE, &dwFlags) )
                return 0;

            if ( (err = WSAGetLastError ()) != WSA_IO_INCOMPLETE )
                goto error;
        }

        WSASetLastError ( WSA_IO_PENDING );
        return SOCKET_ERROR;
    }
2118 2119 2120 2121

    if (_is_blocking(s))
    {
        /* FIXME: exceptfds? */
2122
        do_block(fd, POLLOUT);
2123 2124
    }

2125 2126
    n = WS2_send ( fd, iovec, dwBufferCount, to, tolen, dwFlags );
    if ( n == -1 )
2127 2128 2129
    {
        err = wsaErrno();
        if ( err == WSAEWOULDBLOCK )
2130
            _enable_event (SOCKET2HANDLE(s), FD_WRITE, 0, 0);
2131 2132 2133
        goto err_free;
    }

2134
    TRACE(" -> %i bytes\n", n);
2135 2136
    *lpNumberOfBytesSent = n;

2137
    HeapFree ( GetProcessHeap(), 0, iovec );
2138
    release_sock_fd( s, fd );
2139 2140 2141
    return 0;

err_free:
2142
    HeapFree ( GetProcessHeap(), 0, iovec );
2143 2144

err_close:
2145
    release_sock_fd( s, fd );
2146 2147 2148

error:
    WARN (" -> ERROR %d\n", err);
2149
    WSASetLastError (err);
2150
    return SOCKET_ERROR;
2151 2152
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2153
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2154
 *		sendto		(WS2_32.20)
Alexandre Julliard's avatar
Alexandre Julliard committed
2155
 */
2156 2157
int WINAPI WS_sendto(SOCKET s, const char *buf, int len, int flags,
                              const struct WS_sockaddr *to, int tolen)
Alexandre Julliard's avatar
Alexandre Julliard committed
2158
{
2159
    DWORD n;
2160 2161 2162 2163
    WSABUF wsabuf;

    wsabuf.len = len;
    wsabuf.buf = (char*) buf;
2164

2165 2166
    if ( WSASendTo (s, &wsabuf, 1, &n, flags, to, tolen, NULL, NULL) == SOCKET_ERROR )
        return SOCKET_ERROR;
2167
    else
2168
        return n;
Alexandre Julliard's avatar
Alexandre Julliard committed
2169 2170
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2171
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2172
 *		setsockopt		(WS2_32.21)
Alexandre Julliard's avatar
Alexandre Julliard committed
2173
 */
2174
int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
2175
                                  const char *optval, int optlen)
Alexandre Julliard's avatar
Alexandre Julliard committed
2176
{
2177
    int fd;
2178 2179 2180 2181 2182 2183
    int woptval;
    struct linger linger;
    struct timeval tval;

    TRACE("socket: %04x, level %d, name %d, ptr %p, len %d\n",
          s, level, optname, optval, optlen);
2184 2185 2186 2187 2188 2189 2190 2191 2192

    /* SO_OPENTYPE does not require a valid socket handle. */
    if (level == WS_SOL_SOCKET && optname == WS_SO_OPENTYPE)
    {
        if (optlen < sizeof(int) || !optval)
        {
            SetLastError(WSAEFAULT);
            return SOCKET_ERROR;
        }
2193 2194
        TlsSetValue( opentype_tls_index, (LPVOID)*(int *)optval );
        TRACE("setting global SO_OPENTYPE to 0x%x\n", *(int *)optval );
2195 2196
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2197

2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
    /* For some reason the game GrandPrixLegends does set SO_DONTROUTE on its
     * socket. This will either not happen under windows or it is ignored in
     * windows (but it works in linux and therefor prevents the game to find
     * games outsite the current network) */
    if ( level==WS_SOL_SOCKET && optname==WS_SO_DONTROUTE ) 
    {
        FIXME("Does windows ignore SO_DONTROUTE?\n");
        return 0;
    }

2208 2209
    /* Is a privileged and useless operation, so we don't. */
    if ((optname == WS_SO_DEBUG) && (level == WS_SOL_SOCKET))
Alexandre Julliard's avatar
Alexandre Julliard committed
2210
    {
2211 2212 2213
        FIXME("(%d,SOL_SOCKET,SO_DEBUG,%p(%ld)) attempted (is privileged). Ignoring.\n",s,optval,*(DWORD*)optval);
        return 0;
    }
2214

2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236
    if(optname == WS_SO_DONTLINGER && level == WS_SOL_SOCKET) {
        /* This is unique to WinSock and takes special conversion */
        linger.l_onoff  = *((int*)optval) ? 0: 1;
        linger.l_linger = 0;
        optname=SO_LINGER;
        optval = (char*)&linger;
        optlen = sizeof(struct linger);
        level = SOL_SOCKET;
    }
    else
    {
        if (!convert_sockopt(&level, &optname)) {
            ERR("Invalid level (%d) or optname (%d)\n", level, optname);
            SetLastError(WSAENOPROTOOPT);
            return SOCKET_ERROR;
        }
        if (optname == SO_LINGER && optval) {
            /* yes, uses unsigned short in both win16/win32 */
            linger.l_onoff  = ((UINT16*)optval)[0];
            linger.l_linger = ((UINT16*)optval)[1];
            /* FIXME: what is documented behavior if SO_LINGER optval
               is null?? */
2237 2238
            optval = (char*)&linger;
            optlen = sizeof(struct linger);
2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260
        }
        else if (optval && optlen < sizeof(int))
        {
            woptval= *((INT16 *) optval);
            optval= (char*) &woptval;
            optlen=sizeof(int);
        }
        if (level == SOL_SOCKET && is_timeout_option(optname))
        {
            if (optlen == sizeof(UINT32)) {
                /* WinSock passes miliseconds instead of struct timeval */
                tval.tv_usec = *(PUINT32)optval % 1000;
                tval.tv_sec = *(PUINT32)optval / 1000;
                /* min of 500 milisec */
                if (tval.tv_sec == 0 && tval.tv_usec < 500) tval.tv_usec = 500;
                optlen = sizeof(struct timeval);
                optval = (char*)&tval;
            } else if (optlen == sizeof(struct timeval)) {
                WARN("SO_SND/RCVTIMEO for %d bytes: assuming unixism\n", optlen);
            } else {
                WARN("SO_SND/RCVTIMEO for %d bytes is weird: ignored\n", optlen);
                return 0;
2261
            }
2262 2263 2264
        }
        if (level == SOL_SOCKET && optname == SO_RCVBUF && *(int*)optval < 2048)
        {
2265 2266 2267
            WARN("SO_RCVBF for %d bytes is too small: ignored\n", *(int*)optval );
            return 0;
        }
2268
    }
2269

2270 2271 2272 2273 2274 2275 2276 2277

    fd = get_sock_fd( s, 0, NULL );
    if (fd == -1) return SOCKET_ERROR;

    if (setsockopt(fd, level, optname, optval, optlen) == 0)
    {
        release_sock_fd( s, fd );
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2278
    }
2279 2280 2281
    TRACE("Setting socket error, %d\n", wsaErrno());
    SetLastError(wsaErrno());
    release_sock_fd( s, fd );
Alexandre Julliard's avatar
Alexandre Julliard committed
2282 2283 2284 2285
    return SOCKET_ERROR;
}

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2286
 *		shutdown		(WS2_32.22)
Alexandre Julliard's avatar
Alexandre Julliard committed
2287
 */
2288
int WINAPI WS_shutdown(SOCKET s, int how)
Alexandre Julliard's avatar
Alexandre Julliard committed
2289
{
2290 2291
    int fd, fd0 = -1, fd1 = -1, flags, err = WSAENOTSOCK;
    unsigned int clear_flags = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2292

2293 2294
    fd = get_sock_fd( s, 0, &flags );
    TRACE("socket %04x, how %i %x\n", s, how, flags );
2295 2296 2297 2298 2299

    if (fd == -1)
        return SOCKET_ERROR;

    switch( how )
Alexandre Julliard's avatar
Alexandre Julliard committed
2300
    {
2301 2302 2303 2304 2305 2306 2307 2308 2309
    case 0: /* drop receives */
        clear_flags |= FD_READ;
        break;
    case 1: /* drop sends */
        clear_flags |= FD_WRITE;
        break;
    case 2: /* drop all */
        clear_flags |= FD_READ|FD_WRITE;
    default:
2310
        clear_flags |= FD_WINE_LISTENING;
2311
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2312

2313
    if ( flags & FD_FLAG_OVERLAPPED ) {
Alexandre Julliard's avatar
Alexandre Julliard committed
2314

2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325
        switch ( how )
        {
        case SD_RECEIVE:
            fd0 = fd;
            break;
        case SD_SEND:
            fd1 = fd;
            break;
        case SD_BOTH:
        default:
            fd0 = fd;
2326 2327
            fd1 = get_sock_fd ( s, 0, NULL );
            break;
2328
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
2329

2330 2331 2332 2333 2334
        if ( fd0 != -1 )
        {
            err = WS2_register_async_shutdown ( s, fd0, ASYNC_TYPE_READ );
            if ( err )
            {
2335
                release_sock_fd( s, fd0 );
2336 2337 2338 2339 2340 2341 2342 2343
                goto error;
            }
        }
        if ( fd1 != -1 )
        {
            err = WS2_register_async_shutdown ( s, fd1, ASYNC_TYPE_WRITE );
            if ( err )
            {
2344
                release_sock_fd( s, fd1 );
2345 2346 2347 2348 2349 2350 2351 2352 2353
                goto error;
            }
        }
    }
    else /* non-overlapped mode */
    {
        if ( shutdown( fd, how ) )
        {
            err = wsaErrno ();
2354
            release_sock_fd( s, fd );
2355 2356
            goto error;
        }
2357
        release_sock_fd( s, fd );
2358 2359
    }

2360
    _enable_event( SOCKET2HANDLE(s), 0, 0, clear_flags );
2361 2362 2363 2364
    if ( how > 1) WSAAsyncSelect( s, 0, 0, 0 );
    return 0;

error:
2365
    _enable_event( SOCKET2HANDLE(s), 0, 0, clear_flags );
2366
    WSASetLastError ( err );
Alexandre Julliard's avatar
Alexandre Julliard committed
2367 2368 2369 2370
    return SOCKET_ERROR;
}

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2371
 *		socket		(WS2_32.23)
Alexandre Julliard's avatar
Alexandre Julliard committed
2372
 */
2373
SOCKET WINAPI WS_socket(int af, int type, int protocol)
Alexandre Julliard's avatar
Alexandre Julliard committed
2374
{
2375
    TRACE("af=%d type=%d protocol=%d\n", af, type, protocol);
Alexandre Julliard's avatar
Alexandre Julliard committed
2376

2377 2378
    return WSASocketA ( af, type, protocol, NULL, 0,
                        (TlsGetValue(opentype_tls_index) ? 0 : WSA_FLAG_OVERLAPPED) );
Alexandre Julliard's avatar
Alexandre Julliard committed
2379 2380 2381 2382
}


/***********************************************************************
2383
 *		gethostbyaddr		(WS2_32.51)
Alexandre Julliard's avatar
Alexandre Julliard committed
2384
 */
2385
struct WS_hostent* WINAPI WS_gethostbyaddr(const char *addr, int len, int type)
Alexandre Julliard's avatar
Alexandre Julliard committed
2386
{
2387
    struct WS_hostent *retval = NULL;
2388
    struct hostent* host;
2389

2390
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
2391 2392 2393 2394 2395 2396
    char *extrabuf;
    int ebufsize=1024;
    struct hostent hostentry;
    int locerr=ENOBUFS;
    host = NULL;
    extrabuf=HeapAlloc(GetProcessHeap(),0,ebufsize) ;
2397 2398
    while(extrabuf) {
        int res = gethostbyaddr_r(addr, len, type,
2399 2400 2401 2402 2403 2404
                                  &hostentry, extrabuf, ebufsize, &host, &locerr);
        if( res != ERANGE) break;
        ebufsize *=2;
        extrabuf=HeapReAlloc(GetProcessHeap(),0,extrabuf,ebufsize) ;
    }
    if (!host) SetLastError((locerr < 0) ? wsaErrno() : wsaHerrno(locerr));
2405
#else
2406 2407 2408
    EnterCriticalSection( &csWSgetXXXbyYYY );
    host = gethostbyaddr(addr, len, type);
    if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
2409
#endif
2410
    if( host != NULL ) retval = WS_dup_he(host);
2411
#ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
2412
    HeapFree(GetProcessHeap(),0,extrabuf);
2413
#else
2414
    LeaveCriticalSection( &csWSgetXXXbyYYY );
2415
#endif
2416
    TRACE("ptr %p, len %d, type %d ret %p\n", addr, len, type, retval);
2417
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2418 2419
}

Patrik Stridvall's avatar
Patrik Stridvall committed
2420
/***********************************************************************
2421
 *		gethostbyname		(WS2_32.52)
Alexandre Julliard's avatar
Alexandre Julliard committed
2422
 */
2423
struct WS_hostent* WINAPI WS_gethostbyname(const char* name)
Alexandre Julliard's avatar
Alexandre Julliard committed
2424
{
2425
    struct WS_hostent *retval = NULL;
2426
    struct hostent*     host;
2427
#ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
2428 2429 2430 2431
    char *extrabuf;
    int ebufsize=1024;
    struct hostent hostentry;
    int locerr = ENOBUFS;
2432 2433 2434 2435 2436 2437 2438 2439 2440 2441
#endif
    char buf[100];
    if( !name) {
        name = buf;
        if( gethostname( buf, 100) == -1) {
            SetLastError( WSAENOBUFS); /* appropriate ? */
            return retval;
        }
    }
#ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
2442 2443 2444 2445 2446 2447 2448 2449 2450
    host = NULL;
    extrabuf=HeapAlloc(GetProcessHeap(),0,ebufsize) ;
    while(extrabuf) {
        int res = gethostbyname_r(name, &hostentry, extrabuf, ebufsize, &host, &locerr);
        if( res != ERANGE) break;
        ebufsize *=2;
        extrabuf=HeapReAlloc(GetProcessHeap(),0,extrabuf,ebufsize) ;
    }
    if (!host) SetLastError((locerr < 0) ? wsaErrno() : wsaHerrno(locerr));
2451
#else
2452 2453 2454
    EnterCriticalSection( &csWSgetXXXbyYYY );
    host = gethostbyname(name);
    if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
2455
#endif
2456
    if (host) retval = WS_dup_he(host);
2457
#ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
2458
    HeapFree(GetProcessHeap(),0,extrabuf);
2459
#else
2460
    LeaveCriticalSection( &csWSgetXXXbyYYY );
2461
#endif
2462
    TRACE( "%s ret %p\n", debugstr_a(name), retval );
2463
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2464
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2465

Alexandre Julliard's avatar
Alexandre Julliard committed
2466

Alexandre Julliard's avatar
Alexandre Julliard committed
2467
/***********************************************************************
2468
 *		getprotobyname		(WS2_32.53)
Alexandre Julliard's avatar
Alexandre Julliard committed
2469
 */
2470
struct WS_protoent* WINAPI WS_getprotobyname(const char* name)
Alexandre Julliard's avatar
Alexandre Julliard committed
2471
{
2472
    struct WS_protoent* retval = NULL;
2473
#ifdef HAVE_GETPROTOBYNAME
2474 2475 2476
    struct protoent*     proto;
    EnterCriticalSection( &csWSgetXXXbyYYY );
    if( (proto = getprotobyname(name)) != NULL )
Alexandre Julliard's avatar
Alexandre Julliard committed
2477
    {
2478
        retval = WS_dup_pe(proto);
2479 2480 2481 2482 2483 2484 2485
    }
    else {
        MESSAGE("protocol %s not found; You might want to add "
                "this to /etc/protocols\n", debugstr_a(name) );
        SetLastError(WSANO_DATA);
    }
    LeaveCriticalSection( &csWSgetXXXbyYYY );
2486
#endif
2487
    TRACE( "%s ret %p\n", debugstr_a(name), retval );
2488
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2489 2490
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2491 2492

/***********************************************************************
2493
 *		getprotobynumber	(WS2_32.54)
Alexandre Julliard's avatar
Alexandre Julliard committed
2494
 */
2495
struct WS_protoent* WINAPI WS_getprotobynumber(int number)
Alexandre Julliard's avatar
Alexandre Julliard committed
2496
{
2497
    struct WS_protoent* retval = NULL;
2498
#ifdef HAVE_GETPROTOBYNUMBER
2499 2500 2501
    struct protoent*     proto;
    EnterCriticalSection( &csWSgetXXXbyYYY );
    if( (proto = getprotobynumber(number)) != NULL )
Alexandre Julliard's avatar
Alexandre Julliard committed
2502
    {
2503
        retval = WS_dup_pe(proto);
2504 2505 2506 2507 2508 2509 2510
    }
    else {
        MESSAGE("protocol number %d not found; You might want to add "
                "this to /etc/protocols\n", number );
        SetLastError(WSANO_DATA);
    }
    LeaveCriticalSection( &csWSgetXXXbyYYY );
2511
#endif
2512
    TRACE("%i ret %p\n", number, retval);
2513
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2514 2515
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2516

Alexandre Julliard's avatar
Alexandre Julliard committed
2517
/***********************************************************************
2518
 *		getservbyname		(WS2_32.55)
Alexandre Julliard's avatar
Alexandre Julliard committed
2519
 */
2520
struct WS_servent* WINAPI WS_getservbyname(const char *name, const char *proto)
Alexandre Julliard's avatar
Alexandre Julliard committed
2521
{
2522
    struct WS_servent* retval = NULL;
2523
    struct servent*     serv;
2524 2525 2526 2527
    char *name_str;
    char *proto_str = NULL;

    if (!(name_str = strdup_lower(name))) return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
2528

2529 2530 2531
    if (proto && *proto)
    {
        if (!(proto_str = strdup_lower(proto)))
2532
        {
2533 2534
            HeapFree( GetProcessHeap(), 0, name_str );
            return NULL;
2535 2536
        }
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2537

2538 2539 2540 2541 2542 2543
    EnterCriticalSection( &csWSgetXXXbyYYY );
    serv = getservbyname(name_str, proto_str);
    if( serv != NULL )
    {
        retval = WS_dup_se(serv);
    }
2544
    else SetLastError(WSANO_DATA);
2545 2546 2547 2548 2549
    LeaveCriticalSection( &csWSgetXXXbyYYY );
    if (proto_str) HeapFree( GetProcessHeap(), 0, proto_str );
    HeapFree( GetProcessHeap(), 0, name_str );
    TRACE( "%s, %s ret %p\n", debugstr_a(name), debugstr_a(proto), retval );
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2550
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2551

Alexandre Julliard's avatar
Alexandre Julliard committed
2552

Alexandre Julliard's avatar
Alexandre Julliard committed
2553
/***********************************************************************
2554
 *		getservbyport		(WS2_32.56)
Alexandre Julliard's avatar
Alexandre Julliard committed
2555
 */
2556
struct WS_servent* WINAPI WS_getservbyport(int port, const char *proto)
Alexandre Julliard's avatar
Alexandre Julliard committed
2557
{
2558
    struct WS_servent* retval = NULL;
2559
#ifdef HAVE_GETSERVBYPORT
2560
    struct servent*     serv;
2561 2562 2563 2564 2565
    char *proto_str = NULL;

    if (proto && *proto)
    {
        if (!(proto_str = strdup_lower(proto))) return NULL;
2566
    }
2567 2568 2569 2570
    EnterCriticalSection( &csWSgetXXXbyYYY );
    if( (serv = getservbyport(port, proto_str)) != NULL ) {
        retval = WS_dup_se(serv);
    }
2571
    else SetLastError(WSANO_DATA);
2572 2573
    LeaveCriticalSection( &csWSgetXXXbyYYY );
    if (proto_str) HeapFree( GetProcessHeap(), 0, proto_str );
2574
#endif
2575
    TRACE("%d (i.e. port %d), %s ret %p\n", port, (int)ntohl(port), debugstr_a(proto), retval);
2576
    return retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
2577 2578 2579
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2580
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2581
 *              gethostname           (WS2_32.57)
Alexandre Julliard's avatar
Alexandre Julliard committed
2582
 */
2583
int WINAPI WS_gethostname(char *name, int namelen)
Alexandre Julliard's avatar
Alexandre Julliard committed
2584
{
2585
    TRACE("name %p, len %d\n", name, namelen);
Alexandre Julliard's avatar
Alexandre Julliard committed
2586

2587
    if (gethostname(name, namelen) == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
2588
    {
2589 2590
        TRACE("<- '%s'\n", name);
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2591
    }
2592
    SetLastError((errno == EINVAL) ? WSAEFAULT : wsaErrno());
Andreas Mohr's avatar
Andreas Mohr committed
2593
    TRACE("<- ERROR !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2594 2595 2596
    return SOCKET_ERROR;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2597

Alexandre Julliard's avatar
Alexandre Julliard committed
2598 2599 2600 2601
/* ------------------------------------- Windows sockets extensions -- *
 *								       *
 * ------------------------------------------------------------------- */

2602
/***********************************************************************
2603
 *		WSAEnumNetworkEvents (WS2_32.36)
2604
 */
2605
int WINAPI WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lpEvent)
Alexandre Julliard's avatar
Alexandre Julliard committed
2606
{
2607
    int ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2608

2609
    TRACE("%08x, hEvent %p, lpEvent %08x\n", s, hEvent, (unsigned)lpEvent );
2610

2611
    SERVER_START_REQ( get_socket_event )
Alexandre Julliard's avatar
Alexandre Julliard committed
2612
    {
2613
        req->handle  = SOCKET2HANDLE(s);
2614 2615
        req->service = TRUE;
        req->c_event = hEvent;
2616 2617
        wine_server_set_reply( req, lpEvent->iErrorCode, sizeof(lpEvent->iErrorCode) );
        if (!(ret = wine_server_call(req))) lpEvent->lNetworkEvents = reply->pmask & reply->mask;
2618
    }
2619
    SERVER_END_REQ;
2620 2621 2622
    if (!ret) return 0;
    SetLastError(WSAEINVAL);
    return SOCKET_ERROR;
2623
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2624

2625
/***********************************************************************
2626
 *		WSAEventSelect (WS2_32.39)
2627
 */
2628 2629
int WINAPI WSAEventSelect(SOCKET s, WSAEVENT hEvent, LONG lEvent)
{
2630
    int ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2631

2632
    TRACE("%08x, hEvent %p, event %08x\n", s, hEvent, (unsigned)lEvent );
2633

2634
    SERVER_START_REQ( set_socket_event )
2635
    {
2636
        req->handle = SOCKET2HANDLE(s);
2637 2638
        req->mask   = lEvent;
        req->event  = hEvent;
2639 2640
        req->window = 0;
        req->msg    = 0;
2641
        ret = wine_server_call( req );
2642
    }
2643 2644 2645 2646
    SERVER_END_REQ;
    if (!ret) return 0;
    SetLastError(WSAEINVAL);
    return SOCKET_ERROR;
2647
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2648

2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667
/**********************************************************************
 *      WSAGetOverlappedResult (WS2_32.40)
 */
BOOL WINAPI WSAGetOverlappedResult ( SOCKET s, LPWSAOVERLAPPED lpOverlapped,
                                     LPDWORD lpcbTransfer, BOOL fWait,
                                     LPDWORD lpdwFlags )
{
    DWORD r;

    TRACE ( "socket %d ovl %p trans %p, wait %d flags %p\n",
            s, lpOverlapped, lpcbTransfer, fWait, lpdwFlags );

    if ( !(lpOverlapped && lpOverlapped->hEvent) )
    {
        ERR ( "Invalid pointer\n" );
        WSASetLastError (WSA_INVALID_PARAMETER);
        return FALSE;
    }

2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680
    if ( fWait )
    {
        while ( WaitForSingleObjectEx (lpOverlapped->hEvent, INFINITE, TRUE) == STATUS_USER_APC );
    }
    else if ( lpOverlapped->Internal == STATUS_PENDING )
    {
        /* Wait in order to give APCs a chance to run. */
        /* This is cheating, so we must set the event again in case of success -
           it may be a non-manual reset event. */
        while ( (r = WaitForSingleObjectEx (lpOverlapped->hEvent, 0, TRUE)) == STATUS_USER_APC );
        if ( r == WAIT_OBJECT_0 )
            NtSetEvent ( lpOverlapped->hEvent, NULL );
    }
2681

2682 2683 2684 2685 2686 2687
    if ( lpcbTransfer )
        *lpcbTransfer = lpOverlapped->InternalHigh;

    if ( lpdwFlags )
        *lpdwFlags = lpOverlapped->Offset;

2688 2689 2690
    switch ( lpOverlapped->Internal )
    {
    case STATUS_SUCCESS:
2691
        return TRUE;
2692 2693 2694 2695 2696 2697 2698 2699
    case STATUS_PENDING:
        WSASetLastError ( WSA_IO_INCOMPLETE );
        if (fWait) ERR ("PENDING status after waiting!\n");
        return FALSE;
    default:
        WSASetLastError ( NtStatusToWSAError ( lpOverlapped->Internal ));
        return FALSE;
    }
2700 2701 2702
}


Patrik Stridvall's avatar
Patrik Stridvall committed
2703 2704 2705
/***********************************************************************
 *      WSAAsyncSelect			(WS2_32.101)
 */
2706
INT WINAPI WSAAsyncSelect(SOCKET s, HWND hWnd, UINT uMsg, LONG lEvent)
Alexandre Julliard's avatar
Alexandre Julliard committed
2707
{
2708
    int ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2709

2710
    TRACE("%x, hWnd %p, uMsg %08x, event %08lx\n", s, hWnd, uMsg, lEvent );
Alexandre Julliard's avatar
Alexandre Julliard committed
2711

2712 2713
    SERVER_START_REQ( set_socket_event )
    {
2714
        req->handle = SOCKET2HANDLE(s);
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724
        req->mask   = lEvent;
        req->event  = 0;
        req->window = hWnd;
        req->msg    = uMsg;
        ret = wine_server_call( req );
    }
    SERVER_END_REQ;
    if (!ret) return 0;
    SetLastError(WSAEINVAL);
    return SOCKET_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
2725 2726
}

2727
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2728
 *      WSACreateEvent          (WS2_32.31)
2729 2730 2731 2732 2733 2734
 *
 */
WSAEVENT WINAPI WSACreateEvent(void)
{
    /* Create a manual-reset event, with initial state: unsignealed */
    TRACE("\n");
2735 2736

    return CreateEventA(NULL, TRUE, FALSE, NULL);
2737 2738 2739
}

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2740
 *      WSACloseEvent          (WS2_32.29)
2741 2742 2743 2744
 *
 */
BOOL WINAPI WSACloseEvent(WSAEVENT event)
{
2745
    TRACE ("event=%p\n", event);
2746 2747 2748 2749 2750

    return CloseHandle(event);
}

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2751
 *      WSASocketA          (WS2_32.78)
2752 2753 2754 2755 2756 2757
 *
 */
SOCKET WINAPI WSASocketA(int af, int type, int protocol,
                         LPWSAPROTOCOL_INFOA lpProtocolInfo,
                         GROUP g, DWORD dwFlags)
{
2758 2759
    SOCKET ret;

2760
   /*
2761
      FIXME: The "advanced" parameters of WSASocketA (lpProtocolInfo,
2762
      g, dwFlags except WSA_FLAG_OVERLAPPED) are ignored.
2763
   */
2764

2765
   TRACE("af=%d type=%d protocol=%d protocol_info=%p group=%d flags=0x%lx\n",
2766 2767
         af, type, protocol, lpProtocolInfo, g, dwFlags );

2768 2769 2770 2771 2772 2773 2774
    /* hack for WSADuplicateSocket */
    if (lpProtocolInfo && lpProtocolInfo->dwServiceFlags4 == 0xff00ff00) {
      ret = lpProtocolInfo->dwCatalogEntryId;
      TRACE("\tgot duplicate %04x\n", ret);
      return ret;
    }

2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831
    /* check the socket family */
    switch(af)
    {
#ifdef HAVE_IPX
        case WS_AF_IPX: af = AF_IPX;
#endif
        case AF_INET:
        case AF_UNSPEC:
            break;
        default:
            SetLastError(WSAEAFNOSUPPORT);
            return INVALID_SOCKET;
    }

    /* check the socket type */
    switch(type)
    {
        case WS_SOCK_STREAM:
            type=SOCK_STREAM;
            break;
        case WS_SOCK_DGRAM:
            type=SOCK_DGRAM;
            break;
        case WS_SOCK_RAW:
            type=SOCK_RAW;
            break;
        default:
            SetLastError(WSAESOCKTNOSUPPORT);
            return INVALID_SOCKET;
    }

    /* check the protocol type */
    if ( protocol < 0 )  /* don't support negative values */
    {
        SetLastError(WSAEPROTONOSUPPORT);
        return INVALID_SOCKET;
    }

    if ( af == AF_UNSPEC)  /* did they not specify the address family? */
        switch(protocol)
	{
          case IPPROTO_TCP:
             if (type == SOCK_STREAM) { af = AF_INET; break; }
          case IPPROTO_UDP:
             if (type == SOCK_DGRAM)  { af = AF_INET; break; }
          default: SetLastError(WSAEPROTOTYPE); return INVALID_SOCKET;
        }

    SERVER_START_REQ( create_socket )
    {
        req->family   = af;
        req->type     = type;
        req->protocol = protocol;
        req->access   = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE;
        req->flags    = dwFlags;
        req->inherit  = TRUE;
        set_error( wine_server_call( req ) );
2832
        ret = HANDLE2SOCKET( reply->handle );
2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851
    }
    SERVER_END_REQ;
    if (ret)
    {
        TRACE("\tcreated %04x\n", ret );
        return ret;
    }

    if (GetLastError() == WSAEACCES) /* raw socket denied */
    {
        if (type == SOCK_RAW)
            MESSAGE("WARNING: Trying to create a socket of type SOCK_RAW, will fail unless running as root\n");
        else
            MESSAGE("WS_SOCKET: not enough privileges to create socket, try running as root\n");
        SetLastError(WSAESOCKTNOSUPPORT);
    }

    WARN("\t\tfailed!\n");
    return INVALID_SOCKET;
2852 2853
}

2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870
/***********************************************************************
 *      WSAJoinLeaf          (WS2_32.58)
 *
 */
SOCKET WINAPI WSAJoinLeaf(
        SOCKET s,
        const struct WS_sockaddr *addr,
        int addrlen,
        LPWSABUF lpCallerData,
        LPWSABUF lpCalleeData,
        LPQOS lpSQOS,
        LPQOS lpGQOS,
        DWORD dwFlags)
{
    FIXME("stub.\n");
    return INVALID_SOCKET;
}
2871

Alexandre Julliard's avatar
Alexandre Julliard committed
2872
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2873
 *      __WSAFDIsSet			(WS2_32.151)
Alexandre Julliard's avatar
Alexandre Julliard committed
2874
 */
2875
int WINAPI __WSAFDIsSet(SOCKET s, WS_fd_set *set)
Alexandre Julliard's avatar
Alexandre Julliard committed
2876
{
Alexandre Julliard's avatar
Alexandre Julliard committed
2877 2878
  int i = set->fd_count;

2879
  TRACE("(%d,%8lx(%i))\n", s,(unsigned long)set, i);
Alexandre Julliard's avatar
Alexandre Julliard committed
2880 2881 2882 2883

  while (i--)
      if (set->fd_array[i] == s) return 1;
  return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2884 2885 2886
}

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2887 2888
 *      WSAIsBlocking			(WINSOCK.114)
 *      WSAIsBlocking			(WS2_32.114)
Alexandre Julliard's avatar
Alexandre Julliard committed
2889
 */
2890
BOOL WINAPI WSAIsBlocking(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2891 2892
{
  /* By default WinSock should set all its sockets to non-blocking mode
2893 2894
   * and poll in PeekMessage loop when processing "blocking" ones. This
   * function is supposed to tell if the program is in this loop. Our
Alexandre Julliard's avatar
Alexandre Julliard committed
2895 2896 2897 2898 2899
   * blocking calls are truly blocking so we always return FALSE.
   *
   * Note: It is allowed to call this function without prior WSAStartup().
   */

2900
  TRACE("\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2901 2902 2903
  return FALSE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2904
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2905 2906
 *      WSACancelBlockingCall		(WINSOCK.113)
 *      WSACancelBlockingCall		(WS2_32.113)
Alexandre Julliard's avatar
Alexandre Julliard committed
2907
 */
2908
INT WINAPI WSACancelBlockingCall(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2909
{
2910 2911
    TRACE("\n");
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2912 2913
}

2914 2915 2916 2917 2918 2919
static INT WINAPI WSA_DefaultBlockingHook( FARPROC x )
{
    FIXME("How was this called?\n");
    return x();
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2920 2921

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2922
 *      WSASetBlockingHook (WS2_32.109)
Alexandre Julliard's avatar
Alexandre Julliard committed
2923
 */
2924
FARPROC WINAPI WSASetBlockingHook(FARPROC lpBlockFunc)
Alexandre Julliard's avatar
Alexandre Julliard committed
2925
{
2926 2927 2928 2929
  FARPROC prev = blocking_hook;
  blocking_hook = lpBlockFunc;
  TRACE("hook %p\n", lpBlockFunc);
  return prev;
Alexandre Julliard's avatar
Alexandre Julliard committed
2930 2931
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2932 2933

/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2934
 *      WSAUnhookBlockingHook (WS2_32.110)
Alexandre Julliard's avatar
Alexandre Julliard committed
2935
 */
2936
INT WINAPI WSAUnhookBlockingHook(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2937
{
2938
    blocking_hook = WSA_DefaultBlockingHook;
2939
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2940 2941
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2942

Alexandre Julliard's avatar
Alexandre Julliard committed
2943
/* ----------------------------------- end of API stuff */
Alexandre Julliard's avatar
Alexandre Julliard committed
2944

Alexandre Julliard's avatar
Alexandre Julliard committed
2945 2946 2947 2948
/* ----------------------------------- helper functions -
 *
 * TODO: Merge WS_dup_..() stuff into one function that
 * would operate with a generic structure containing internal
Alexandre Julliard's avatar
Alexandre Julliard committed
2949
 * pointers (via a template of some kind).
Alexandre Julliard's avatar
Alexandre Julliard committed
2950
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
2951 2952 2953 2954 2955

static int list_size(char** l, int item_size)
{
  int i,j = 0;
  if(l)
2956
  { for(i=0;l[i];i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
2957 2958 2959 2960 2961
	j += (item_size) ? item_size : strlen(l[i]) + 1;
    j += (i + 1) * sizeof(char*); }
  return j;
}

2962
static int list_dup(char** l_src, char** l_to, int item_size)
2963
{
2964 2965
   char *p;
   int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
2966

2967 2968 2969 2970 2971 2972 2973 2974 2975
   for (i = 0; l_src[i]; i++) ;
   p = (char *)(l_to + i + 1);
   for (i = 0; l_src[i]; i++)
   {
       int count = ( item_size ) ? item_size : strlen(l_src[i]) + 1;
       memcpy(p, l_src[i], count);
       l_to[i] = p;
       p += count;
   }
Alexandre Julliard's avatar
Alexandre Julliard committed
2976
   l_to[i] = NULL;
2977
   return (p - (char *)l_to);
Alexandre Julliard's avatar
Alexandre Julliard committed
2978 2979 2980 2981
}

/* ----- hostent */

2982 2983 2984 2985
/* duplicate hostent entry
 * and handle all Win16/Win32 dependent things (struct size, ...) *correctly*.
 * Dito for protoent and servent.
 */
2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010
static struct WS_hostent *WS_dup_he(const struct hostent* p_he)
{
    char *p;
    struct WS_hostent *p_to;

    int size = (sizeof(*p_he) +
                strlen(p_he->h_name) + 1 +
                list_size(p_he->h_aliases, 0) +
                list_size(p_he->h_addr_list, p_he->h_length));

    if (!(p_to = check_buffer_he(size))) return NULL;
    p_to->h_addrtype = p_he->h_addrtype;
    p_to->h_length = p_he->h_length;

    p = (char *)(p_to + 1);
    p_to->h_name = p;
    strcpy(p, p_he->h_name);
    p += strlen(p) + 1;

    p_to->h_aliases = (char **)p;
    p += list_dup(p_he->h_aliases, p_to->h_aliases, 0);

    p_to->h_addr_list = (char **)p;
    list_dup(p_he->h_addr_list, p_to->h_addr_list, p_he->h_length);
    return p_to;
Alexandre Julliard's avatar
Alexandre Julliard committed
3011 3012 3013 3014
}

/* ----- protoent */

3015
static struct WS_protoent *WS_dup_pe(const struct protoent* p_pe)
Alexandre Julliard's avatar
Alexandre Julliard committed
3016
{
3017 3018
    char *p;
    struct WS_protoent *p_to;
Alexandre Julliard's avatar
Alexandre Julliard committed
3019

3020 3021 3022
    int size = (sizeof(*p_pe) +
                strlen(p_pe->p_name) + 1 +
                list_size(p_pe->p_aliases, 0));
3023

3024 3025
    if (!(p_to = check_buffer_pe(size))) return NULL;
    p_to->p_proto = p_pe->p_proto;
3026

3027 3028 3029 3030 3031 3032 3033 3034
    p = (char *)(p_to + 1);
    p_to->p_name = p;
    strcpy(p, p_pe->p_name);
    p += strlen(p) + 1;

    p_to->p_aliases = (char **)p;
    list_dup(p_pe->p_aliases, p_to->p_aliases, 0);
    return p_to;
Alexandre Julliard's avatar
Alexandre Julliard committed
3035 3036 3037 3038
}

/* ----- servent */

3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063
static struct WS_servent *WS_dup_se(const struct servent* p_se)
{
    char *p;
    struct WS_servent *p_to;

    int size = (sizeof(*p_se) +
                strlen(p_se->s_proto) + 1 +
                strlen(p_se->s_name) + 1 +
                list_size(p_se->s_aliases, 0));

    if (!(p_to = check_buffer_se(size))) return NULL;
    p_to->s_port = p_se->s_port;

    p = (char *)(p_to + 1);
    p_to->s_name = p;
    strcpy(p, p_se->s_name);
    p += strlen(p) + 1;

    p_to->s_proto = p;
    strcpy(p, p_se->s_proto);
    p += strlen(p) + 1;

    p_to->s_aliases = (char **)p;
    list_dup(p_se->s_aliases, p_to->s_aliases, 0);
    return p_to;
Alexandre Julliard's avatar
Alexandre Julliard committed
3064 3065 3066 3067
}

/* ----------------------------------- error handling */

3068
UINT wsaErrno(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3069
{
3070
    int	loc_errno = errno;
3071
    WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno));
Alexandre Julliard's avatar
Alexandre Julliard committed
3072 3073 3074 3075 3076

    switch(loc_errno)
    {
	case EINTR:		return WSAEINTR;
	case EBADF:		return WSAEBADF;
3077
	case EPERM:
Alexandre Julliard's avatar
Alexandre Julliard committed
3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100
	case EACCES:		return WSAEACCES;
	case EFAULT:		return WSAEFAULT;
	case EINVAL:		return WSAEINVAL;
	case EMFILE:		return WSAEMFILE;
	case EWOULDBLOCK:	return WSAEWOULDBLOCK;
	case EINPROGRESS:	return WSAEINPROGRESS;
	case EALREADY:		return WSAEALREADY;
	case ENOTSOCK:		return WSAENOTSOCK;
	case EDESTADDRREQ:	return WSAEDESTADDRREQ;
	case EMSGSIZE:		return WSAEMSGSIZE;
	case EPROTOTYPE:	return WSAEPROTOTYPE;
	case ENOPROTOOPT:	return WSAENOPROTOOPT;
	case EPROTONOSUPPORT:	return WSAEPROTONOSUPPORT;
	case ESOCKTNOSUPPORT:	return WSAESOCKTNOSUPPORT;
	case EOPNOTSUPP:	return WSAEOPNOTSUPP;
	case EPFNOSUPPORT:	return WSAEPFNOSUPPORT;
	case EAFNOSUPPORT:	return WSAEAFNOSUPPORT;
	case EADDRINUSE:	return WSAEADDRINUSE;
	case EADDRNOTAVAIL:	return WSAEADDRNOTAVAIL;
	case ENETDOWN:		return WSAENETDOWN;
	case ENETUNREACH:	return WSAENETUNREACH;
	case ENETRESET:		return WSAENETRESET;
	case ECONNABORTED:	return WSAECONNABORTED;
Alexandre Julliard's avatar
Alexandre Julliard committed
3101
	case EPIPE:
Alexandre Julliard's avatar
Alexandre Julliard committed
3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123
	case ECONNRESET:	return WSAECONNRESET;
	case ENOBUFS:		return WSAENOBUFS;
	case EISCONN:		return WSAEISCONN;
	case ENOTCONN:		return WSAENOTCONN;
	case ESHUTDOWN:		return WSAESHUTDOWN;
	case ETOOMANYREFS:	return WSAETOOMANYREFS;
	case ETIMEDOUT:		return WSAETIMEDOUT;
	case ECONNREFUSED:	return WSAECONNREFUSED;
	case ELOOP:		return WSAELOOP;
	case ENAMETOOLONG:	return WSAENAMETOOLONG;
	case EHOSTDOWN:		return WSAEHOSTDOWN;
	case EHOSTUNREACH:	return WSAEHOSTUNREACH;
	case ENOTEMPTY:		return WSAENOTEMPTY;
#ifdef EPROCLIM
	case EPROCLIM:		return WSAEPROCLIM;
#endif
#ifdef EUSERS
	case EUSERS:		return WSAEUSERS;
#endif
#ifdef EDQUOT
	case EDQUOT:		return WSAEDQUOT;
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
3124
#ifdef ESTALE
Alexandre Julliard's avatar
Alexandre Julliard committed
3125
	case ESTALE:		return WSAESTALE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3126 3127
#endif
#ifdef EREMOTE
Alexandre Julliard's avatar
Alexandre Julliard committed
3128
	case EREMOTE:		return WSAEREMOTE;
Alexandre Julliard's avatar
Alexandre Julliard committed
3129
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
3130 3131 3132 3133

       /* just in case we ever get here and there are no problems */
	case 0:			return 0;
        default:
3134
		WARN("Unknown errno %d!\n", loc_errno);
Alexandre Julliard's avatar
Alexandre Julliard committed
3135 3136 3137 3138
		return WSAEOPNOTSUPP;
    }
}

3139
UINT wsaHerrno(int loc_errno)
Alexandre Julliard's avatar
Alexandre Julliard committed
3140 3141
{

3142
    WARN("h_errno %d.\n", loc_errno);
Alexandre Julliard's avatar
Alexandre Julliard committed
3143 3144 3145 3146 3147 3148

    switch(loc_errno)
    {
	case HOST_NOT_FOUND:	return WSAHOST_NOT_FOUND;
	case TRY_AGAIN:		return WSATRY_AGAIN;
	case NO_RECOVERY:	return WSANO_RECOVERY;
3149
	case NO_DATA:		return WSANO_DATA;
3150
	case ENOBUFS:		return WSAENOBUFS;
Alexandre Julliard's avatar
Alexandre Julliard committed
3151 3152 3153

	case 0:			return 0;
        default:
3154
		WARN("Unknown h_errno %d!\n", loc_errno);
Alexandre Julliard's avatar
Alexandre Julliard committed
3155 3156 3157
		return WSAEOPNOTSUPP;
    }
}
3158 3159


3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171
/***********************************************************************
 *		WSARecv			(WS2_32.67)
 */
int WINAPI WSARecv (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
		    LPDWORD NumberOfBytesReceived, LPDWORD lpFlags,
		    LPWSAOVERLAPPED lpOverlapped,
		    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    return WSARecvFrom (s, lpBuffers, dwBufferCount, NumberOfBytesReceived, lpFlags,
                        NULL, NULL, lpOverlapped, lpCompletionRoutine);
}

3172
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
3173
 *              WSARecvFrom             (WS2_32.69)
3174 3175
 */
INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
3176
                        LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct WS_sockaddr *lpFrom,
3177 3178
                        LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
                        LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
3179

3180
{
3181
    int i, n, fd, err = WSAENOTSOCK, flags, ret;
3182
    struct iovec* iovec;
3183
    struct ws2_async *wsa;
3184

3185 3186 3187 3188 3189
    TRACE("socket %04x, wsabuf %p, nbufs %ld, flags %ld, from %p, fromlen %ld, ovl %p, func %p\n",
          s, lpBuffers, dwBufferCount, *lpFlags, lpFrom,
          (lpFromlen ? *lpFromlen : -1L),
          lpOverlapped, lpCompletionRoutine);

3190 3191
    fd = get_sock_fd( s, GENERIC_READ, &flags );
    TRACE ( "fd=%d, flags=%x\n", fd, flags );
3192

3193 3194 3195
    if (fd == -1) return SOCKET_ERROR;

    if (flags & FD_FLAG_RECV_SHUTDOWN)
3196
    {
3197 3198
        WSASetLastError ( WSAESHUTDOWN );
        goto err_close;
3199 3200
    }

3201
    iovec = HeapAlloc ( GetProcessHeap(), 0, dwBufferCount * sizeof (struct iovec) );
3202 3203
    if ( !iovec )
    {
3204
        err = WSAEFAULT;
3205 3206
        goto err_close;
    }
3207

3208 3209 3210 3211 3212 3213
    for (i = 0; i < dwBufferCount; i++)
    {
        iovec[i].iov_base = lpBuffers[i].buf;
        iovec[i].iov_len  = lpBuffers[i].len;
    }

3214
    if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED )
3215
    {
3216 3217 3218
        wsa = WS2_make_async ( s, fd, ASYNC_TYPE_READ, iovec, dwBufferCount,
                               lpFlags, lpFrom, lpFromlen,
                               lpOverlapped, lpCompletionRoutine );
3219

3220 3221 3222 3223 3224
        if ( !wsa )
        {
            err = WSAEFAULT;
            goto err_free;
        }
3225

3226 3227 3228
        if ( ( ret = register_new_async ( &wsa->async )) )
        {
            err = NtStatusToWSAError ( ret );
3229

3230
            if ( !lpOverlapped )
3231
                HeapFree ( GetProcessHeap(), 0, wsa->async.iosb );
3232 3233 3234
            HeapFree ( GetProcessHeap(), 0, wsa );
            goto err_free;
        }
3235

3236 3237 3238
        /* Try immediate completion */
        if ( lpOverlapped && !NtResetEvent( lpOverlapped->hEvent, NULL ) )
        {
3239
            if  ( WSAGetOverlappedResult ( s, lpOverlapped,
3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251
                                           lpNumberOfBytesRecvd, FALSE, lpFlags) )
                return 0;

            if ( (err = WSAGetLastError ()) != WSA_IO_INCOMPLETE )
                goto error;
        }

        WSASetLastError ( WSA_IO_PENDING );
        return SOCKET_ERROR;
    }

    if ( _is_blocking(s) )
3252 3253 3254
    {
        /* block here */
        /* FIXME: OOB and exceptfds? */
3255
        do_block(fd, POLLIN);
3256 3257
    }

3258 3259
    n = WS2_recv ( fd, iovec, dwBufferCount, lpFrom, lpFromlen, lpFlags );
    if ( n == -1 )
3260 3261 3262 3263 3264
    {
        err = wsaErrno();
        goto err_free;
    }

3265 3266
    TRACE(" -> %i bytes\n", n);
    *lpNumberOfBytesRecvd = n;
3267

3268
    HeapFree (GetProcessHeap(), 0, iovec);
3269
    release_sock_fd( s, fd );
3270
    _enable_event(SOCKET2HANDLE(s), FD_READ, 0, 0);
3271 3272 3273 3274

    return 0;

err_free:
3275
    HeapFree (GetProcessHeap(), 0, iovec);
3276 3277

err_close:
3278
    release_sock_fd( s, fd );
3279 3280 3281

error:
    WARN(" -> ERROR %d\n", err);
3282
    WSASetLastError ( err );
3283 3284
    return SOCKET_ERROR;
}
3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311

/***********************************************************************
 *              WSCInstallProvider             (WS2_32.88)
 */
INT WINAPI WSCInstallProvider( const LPGUID lpProviderId,
                               LPCWSTR lpszProviderDllPath,
                               const LPWSAPROTOCOL_INFOW lpProtocolInfoList,
                               DWORD dwNumberOfEntries,
                               LPINT lpErrno )
{
    FIXME("(%s, %s, %p, %ld, %p): stub !\n", debugstr_guid(lpProviderId),
          debugstr_w(lpszProviderDllPath), lpProtocolInfoList,
          dwNumberOfEntries, lpErrno);
    *lpErrno = 0;
    return 0;
}


/***********************************************************************
 *              WSCDeinstallProvider             (WS2_32.83)
 */
INT WINAPI WSCDeinstallProvider(LPGUID lpProviderId, LPINT lpErrno)
{
    FIXME("(%s, %p): stub !\n", debugstr_guid(lpProviderId), lpErrno);
    *lpErrno = 0;
    return 0;
}
Daniel Walker's avatar
Daniel Walker committed
3312 3313


3314 3315 3316
/***********************************************************************
 *              WSAAccept                        (WS2_32.26)
 */
Daniel Walker's avatar
Daniel Walker committed
3317 3318 3319 3320 3321 3322 3323 3324 3325
SOCKET WINAPI WSAAccept( SOCKET s, struct WS_sockaddr *addr, LPINT addrlen,
               LPCONDITIONPROC lpfnCondition, DWORD dwCallbackData)
{

       int ret = 0, size = 0;
       WSABUF CallerId, CallerData, CalleeId, CalleeData;
       /*        QOS SQOS, GQOS; */
       GROUP g;
       SOCKET cs;
3326
       SOCKADDR src_addr, dst_addr;
Daniel Walker's avatar
Daniel Walker committed
3327

3328
       TRACE("Socket  %u, sockaddr %p, addrlen %p, fnCondition %p, dwCallbackData %ld\n",
Daniel Walker's avatar
Daniel Walker committed
3329 3330
               s, addr, addrlen, lpfnCondition, dwCallbackData);

3331

3332 3333
       size = sizeof(src_addr);
       cs = WS_accept(s, &src_addr, &size);
3334

Daniel Walker's avatar
Daniel Walker committed
3335 3336
       if (cs == SOCKET_ERROR) return SOCKET_ERROR;

3337
       CallerId.buf = (char *)&src_addr;
3338
       CallerId.len = sizeof(src_addr);
Daniel Walker's avatar
Daniel Walker committed
3339 3340

       CallerData.buf = NULL;
3341
       CallerData.len = (ULONG)NULL;
Daniel Walker's avatar
Daniel Walker committed
3342

3343
       WS_getsockname(cs, &dst_addr, &size);
Daniel Walker's avatar
Daniel Walker committed
3344

3345
       CalleeId.buf = (char *)&dst_addr;
3346 3347
       CalleeId.len = sizeof(dst_addr);

Daniel Walker's avatar
Daniel Walker committed
3348 3349

       ret = (*lpfnCondition)(&CallerId, &CallerData, NULL, NULL,
3350
                       &CalleeId, &CalleeData, &g, dwCallbackData);
Daniel Walker's avatar
Daniel Walker committed
3351 3352 3353 3354 3355

       switch (ret)
       {
               case CF_ACCEPT:
                       if (addr && addrlen)
3356
                               addr = memcpy(addr, &src_addr, (*addrlen > size) ?  size : *addrlen );
Daniel Walker's avatar
Daniel Walker committed
3357 3358
                       return cs;
               case CF_DEFER:
3359 3360
                       SERVER_START_REQ ( set_socket_deferred )
                       {
3361 3362
                           req->handle = SOCKET2HANDLE (s);
                           req->deferred = SOCKET2HANDLE (cs);
3363 3364 3365
                           if ( !wine_server_call_err ( req ) )
                           {
                               SetLastError ( WSATRY_AGAIN );
3366
                               WS_closesocket ( cs );
3367 3368 3369
                           }
                       }
                       SERVER_END_REQ;
Daniel Walker's avatar
Daniel Walker committed
3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381
                       return SOCKET_ERROR;
               case CF_REJECT:
                       WS_closesocket(cs);
                       SetLastError(WSAECONNREFUSED);
                       return SOCKET_ERROR;
               default:
                       FIXME("Unknown return type from Condition function\n");
                       SetLastError(WSAENOTSOCK);
                       return SOCKET_ERROR;
               }
}

3382 3383 3384
/***********************************************************************
 *              WSAEnumProtocolsA                        (WS2_32.37)
 */
3385
int WINAPI WSAEnumProtocolsA(LPINT lpiProtocols, LPWSAPROTOCOL_INFOA lpProtocolBuffer, LPDWORD lpdwBufferLength)
3386 3387 3388 3389 3390 3391 3392 3393
{
    FIXME("(%p,%p,%p): stub\n", lpiProtocols,lpProtocolBuffer, lpdwBufferLength);
    return 0;
}

/***********************************************************************
 *              WSAEnumProtocolsW                        (WS2_32.38)
 */
3394
int WINAPI WSAEnumProtocolsW(LPINT lpiProtocols, LPWSAPROTOCOL_INFOW lpProtocolBuffer, LPDWORD lpdwBufferLength)
3395 3396 3397 3398 3399
{
    FIXME("(%p,%p,%p): stub\n", lpiProtocols,lpProtocolBuffer, lpdwBufferLength);
    return 0;
}

3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414
/***********************************************************************
 *              WSADuplicateSocketA                      (WS2_32.32)
 */
int WINAPI WSADuplicateSocketA( SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOA lpProtocolInfo )
{
   HANDLE hProcess;

   TRACE("(%d,%lx,%p)\n", s, dwProcessId, lpProtocolInfo);
   memset(lpProtocolInfo, 0, sizeof(*lpProtocolInfo));
   /* FIXME: WS_getsockopt(s, WS_SOL_SOCKET, SO_PROTOCOL_INFO, lpProtocolInfo, sizeof(*lpProtocolInfo)); */
   /* I don't know what the real Windoze does next, this is a hack */
   /* ...we could duplicate and then use ConvertToGlobalHandle on the duplicate, then let
    * the target use the global duplicate, or we could copy a reference to us to the structure
    * and let the target duplicate it from us, but let's do it as simple as possible */
   hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId);
3415
   DuplicateHandle(GetCurrentProcess(), SOCKET2HANDLE(s),
3416 3417 3418 3419 3420 3421
                   hProcess, (LPHANDLE)&lpProtocolInfo->dwCatalogEntryId,
                   0, FALSE, DUPLICATE_SAME_ACCESS);
   CloseHandle(hProcess);
   lpProtocolInfo->dwServiceFlags4 = 0xff00ff00; /* magic */
   return 0;
}
3422 3423 3424 3425 3426 3427 3428

/***********************************************************************
 *              WSAInstallServiceClassA                  (WS2_32.48)
 */
int WINAPI WSAInstallServiceClassA(LPWSASERVICECLASSINFOA info)
{
    FIXME("Request to install service %s\n",debugstr_a(info->lpszServiceClassName));
3429 3430
    WSASetLastError(WSAEACCES);
    return SOCKET_ERROR;
3431 3432 3433 3434 3435 3436 3437 3438
}

/***********************************************************************
 *              WSAInstallServiceClassW                  (WS2_32.49)
 */
int WINAPI WSAInstallServiceClassW(LPWSASERVICECLASSINFOW info)
{
    FIXME("Request to install service %s\n",debugstr_w(info->lpszServiceClassName));
3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450
    WSASetLastError(WSAEACCES);
    return SOCKET_ERROR;
}

/***********************************************************************
 *              WSARemoveServiceClass                    (WS2_32.70)
 */
int WINAPI WSARemoveServiceClass(LPGUID info)
{
    FIXME("Request to remove service %p\n",info);
    WSASetLastError(WSATYPE_NOT_FOUND);
    return SOCKET_ERROR;
3451
}