VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/socket.cpp@ 39804

Last change on this file since 39804 was 39804, checked in by vboxsync, 13 years ago

Fixed regression (I hope) in yesterdays tcp/socket changes (name resolution).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 53.3 KB
Line 
1/* $Id: socket.cpp 39804 2012-01-19 09:41:09Z vboxsync $ */
2/** @file
3 * IPRT - Network Sockets.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#ifdef RT_OS_WINDOWS
32# include <winsock2.h>
33#else /* !RT_OS_WINDOWS */
34# include <errno.h>
35# include <sys/stat.h>
36# include <sys/socket.h>
37# include <netinet/in.h>
38# include <netinet/tcp.h>
39# include <arpa/inet.h>
40# ifdef IPRT_WITH_TCPIP_V6
41# include <netinet6/in6.h>
42# endif
43# include <sys/un.h>
44# include <netdb.h>
45# include <unistd.h>
46# include <fcntl.h>
47# include <sys/uio.h>
48#endif /* !RT_OS_WINDOWS */
49#include <limits.h>
50
51#include "internal/iprt.h"
52#include <iprt/socket.h>
53
54#include <iprt/alloca.h>
55#include <iprt/asm.h>
56#include <iprt/assert.h>
57#include <iprt/ctype.h>
58#include <iprt/err.h>
59#include <iprt/mempool.h>
60#include <iprt/poll.h>
61#include <iprt/string.h>
62#include <iprt/thread.h>
63#include <iprt/time.h>
64#include <iprt/mem.h>
65#include <iprt/sg.h>
66#include <iprt/log.h>
67
68#include "internal/magics.h"
69#include "internal/socket.h"
70
71
72/*******************************************************************************
73* Defined Constants And Macros *
74*******************************************************************************/
75/* non-standard linux stuff (it seems). */
76#ifndef MSG_NOSIGNAL
77# define MSG_NOSIGNAL 0
78#endif
79
80/* Windows has different names for SHUT_XXX. */
81#ifndef SHUT_RDWR
82# ifdef SD_BOTH
83# define SHUT_RDWR SD_BOTH
84# else
85# define SHUT_RDWR 2
86# endif
87#endif
88#ifndef SHUT_WR
89# ifdef SD_SEND
90# define SHUT_WR SD_SEND
91# else
92# define SHUT_WR 1
93# endif
94#endif
95#ifndef SHUT_RD
96# ifdef SD_RECEIVE
97# define SHUT_RD SD_RECEIVE
98# else
99# define SHUT_RD 0
100# endif
101#endif
102
103/* fixup backlevel OSes. */
104#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
105# define socklen_t int
106#endif
107
108/** How many pending connection. */
109#define RTTCP_SERVER_BACKLOG 10
110
111
112/*******************************************************************************
113* Structures and Typedefs *
114*******************************************************************************/
115/**
116 * Socket handle data.
117 *
118 * This is mainly required for implementing RTPollSet on Windows.
119 */
120typedef struct RTSOCKETINT
121{
122 /** Magic number (RTSOCKET_MAGIC). */
123 uint32_t u32Magic;
124 /** Exclusive user count.
125 * This is used to prevent two threads from accessing the handle concurrently.
126 * It can be higher than 1 if this handle is reference multiple times in a
127 * polling set (Windows). */
128 uint32_t volatile cUsers;
129 /** The native socket handle. */
130 RTSOCKETNATIVE hNative;
131 /** Indicates whether the handle has been closed or not. */
132 bool volatile fClosed;
133 /** Indicates whether the socket is operating in blocking or non-blocking mode
134 * currently. */
135 bool fBlocking;
136#ifdef RT_OS_WINDOWS
137 /** The event semaphore we've associated with the socket handle.
138 * This is WSA_INVALID_EVENT if not done. */
139 WSAEVENT hEvent;
140 /** The pollset currently polling this socket. This is NIL if no one is
141 * polling. */
142 RTPOLLSET hPollSet;
143 /** The events we're polling for. */
144 uint32_t fPollEvts;
145 /** The events we're currently subscribing to with WSAEventSelect.
146 * This is ZERO if we're currently not subscribing to anything. */
147 uint32_t fSubscribedEvts;
148 /** Saved events which are only posted once. */
149 uint32_t fEventsSaved;
150#endif /* RT_OS_WINDOWS */
151} RTSOCKETINT;
152
153
154/**
155 * Address union used internally for things like getpeername and getsockname.
156 */
157typedef union RTSOCKADDRUNION
158{
159 struct sockaddr Addr;
160 struct sockaddr_in IPv4;
161#ifdef IPRT_WITH_TCPIP_V6
162 struct sockaddr_in6 IPv6;
163#endif
164} RTSOCKADDRUNION;
165
166
167/**
168 * Get the last error as an iprt status code.
169 *
170 * @returns IPRT status code.
171 */
172DECLINLINE(int) rtSocketError(void)
173{
174#ifdef RT_OS_WINDOWS
175 return RTErrConvertFromWin32(WSAGetLastError());
176#else
177 return RTErrConvertFromErrno(errno);
178#endif
179}
180
181
182/**
183 * Resets the last error.
184 */
185DECLINLINE(void) rtSocketErrorReset(void)
186{
187#ifdef RT_OS_WINDOWS
188 WSASetLastError(0);
189#else
190 errno = 0;
191#endif
192}
193
194
195/**
196 * Get the last resolver error as an iprt status code.
197 *
198 * @returns iprt status code.
199 */
200int rtSocketResolverError(void)
201{
202#ifdef RT_OS_WINDOWS
203 return RTErrConvertFromWin32(WSAGetLastError());
204#else
205 switch (h_errno)
206 {
207 case HOST_NOT_FOUND:
208 return VERR_NET_HOST_NOT_FOUND;
209 case NO_DATA:
210 return VERR_NET_ADDRESS_NOT_AVAILABLE;
211 case NO_RECOVERY:
212 return VERR_IO_GEN_FAILURE;
213 case TRY_AGAIN:
214 return VERR_TRY_AGAIN;
215
216 default:
217 return VERR_UNRESOLVED_ERROR;
218 }
219#endif
220}
221
222
223/**
224 * Converts from a native socket address to a generic IPRT network address.
225 *
226 * @returns IPRT status code.
227 * @param pSrc The source address.
228 * @param cbSrc The size of the source address.
229 * @param pAddr Where to return the generic IPRT network
230 * address.
231 */
232static int rtSocketNetAddrFromAddr(RTSOCKADDRUNION const *pSrc, size_t cbSrc, PRTNETADDR pAddr)
233{
234 /*
235 * Convert the address.
236 */
237 if ( cbSrc == sizeof(struct sockaddr_in)
238 && pSrc->Addr.sa_family == AF_INET)
239 {
240 RT_ZERO(*pAddr);
241 pAddr->enmType = RTNETADDRTYPE_IPV4;
242 pAddr->uPort = RT_N2H_U16(pSrc->IPv4.sin_port);
243 pAddr->uAddr.IPv4.u = pSrc->IPv4.sin_addr.s_addr;
244 }
245#ifdef IPRT_WITH_TCPIP_V6
246 else if ( cbSrc == sizeof(struct sockaddr_in6)
247 && pSrc->Addr.sa_family == AF_INET6)
248 {
249 RT_ZERO(*pAddr);
250 pAddr->enmType = RTNETADDRTYPE_IPV6;
251 pAddr->uPort = RT_N2H_U16(pSrc->IPv6.sin6_port);
252 pAddr->uAddr.IPv6.au32[0] = pSrc->IPv6.sin6_addr.s6_addr32[0];
253 pAddr->uAddr.IPv6.au32[1] = pSrc->IPv6.sin6_addr.s6_addr32[1];
254 pAddr->uAddr.IPv6.au32[2] = pSrc->IPv6.sin6_addr.s6_addr32[2];
255 pAddr->uAddr.IPv6.au32[3] = pSrc->IPv6.sin6_addr.s6_addr32[3];
256 }
257#endif
258 else
259 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
260 return VINF_SUCCESS;
261}
262
263
264/**
265 * Converts from a generic IPRT network address to a native socket address.
266 *
267 * @returns IPRT status code.
268 * @param pAddr Pointer to the generic IPRT network address.
269 * @param pDst The source address.
270 * @param cbSrc The size of the source address.
271 * @param pcbAddr Where to store the size of the returned address.
272 * Optional
273 */
274static int rtSocketAddrFromNetAddr(PCRTNETADDR pAddr, RTSOCKADDRUNION *pDst, size_t cbDst, int *pcbAddr)
275{
276 RT_BZERO(pDst, cbDst);
277 if ( pAddr->enmType == RTNETADDRTYPE_IPV4
278 && cbDst >= sizeof(struct sockaddr_in))
279 {
280 pDst->Addr.sa_family = AF_INET;
281 pDst->IPv4.sin_port = RT_H2N_U16(pAddr->uPort);
282 pDst->IPv4.sin_addr.s_addr = pAddr->uAddr.IPv4.u;
283 if (pcbAddr)
284 *pcbAddr = sizeof(pDst->IPv4);
285 }
286#ifdef IPRT_WITH_TCPIP_V6
287 else if ( pAddr->enmType == RTNETADDRTYPE_IPV6
288 && cbDst >= sizeof(struct sockaddr_in6))
289 {
290 pDst->Addr.sa_family = AF_INET6;
291 pDst->IPv6.sin6_port = RT_H2N_U16(pAddr->uPort);
292 pSrc->IPv6.sin6_addr.s6_addr32[0] = pAddr->uAddr.IPv6.au32[0];
293 pSrc->IPv6.sin6_addr.s6_addr32[1] = pAddr->uAddr.IPv6.au32[1];
294 pSrc->IPv6.sin6_addr.s6_addr32[2] = pAddr->uAddr.IPv6.au32[2];
295 pSrc->IPv6.sin6_addr.s6_addr32[3] = pAddr->uAddr.IPv6.au32[3];
296 if (pcbAddr)
297 *pcbAddr = sizeof(pDst->IPv6);
298 }
299#endif
300 else
301 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
302 return VINF_SUCCESS;
303}
304
305
306/**
307 * Tries to lock the socket for exclusive usage by the calling thread.
308 *
309 * Call rtSocketUnlock() to unlock.
310 *
311 * @returns @c true if locked, @c false if not.
312 * @param pThis The socket structure.
313 */
314DECLINLINE(bool) rtSocketTryLock(RTSOCKETINT *pThis)
315{
316 return ASMAtomicCmpXchgU32(&pThis->cUsers, 1, 0);
317}
318
319
320/**
321 * Unlocks the socket.
322 *
323 * @param pThis The socket structure.
324 */
325DECLINLINE(void) rtSocketUnlock(RTSOCKETINT *pThis)
326{
327 ASMAtomicCmpXchgU32(&pThis->cUsers, 0, 1);
328}
329
330
331/**
332 * The slow path of rtSocketSwitchBlockingMode that does the actual switching.
333 *
334 * @returns IPRT status code.
335 * @param pThis The socket structure.
336 * @param fBlocking The desired mode of operation.
337 * @remarks Do not call directly.
338 */
339static int rtSocketSwitchBlockingModeSlow(RTSOCKETINT *pThis, bool fBlocking)
340{
341#ifdef RT_OS_WINDOWS
342 u_long uBlocking = fBlocking ? 0 : 1;
343 if (ioctlsocket(pThis->hNative, FIONBIO, &uBlocking))
344 return rtSocketError();
345
346#else
347 int fFlags = fcntl(pThis->hNative, F_GETFL, 0);
348 if (fFlags == -1)
349 return rtSocketError();
350
351 if (fBlocking)
352 fFlags &= ~O_NONBLOCK;
353 else
354 fFlags |= O_NONBLOCK;
355 if (fcntl(pThis->hNative, F_SETFL, fFlags) == -1)
356 return rtSocketError();
357#endif
358
359 pThis->fBlocking = fBlocking;
360 return VINF_SUCCESS;
361}
362
363
364/**
365 * Switches the socket to the desired blocking mode if necessary.
366 *
367 * The socket must be locked.
368 *
369 * @returns IPRT status code.
370 * @param pThis The socket structure.
371 * @param fBlocking The desired mode of operation.
372 */
373DECLINLINE(int) rtSocketSwitchBlockingMode(RTSOCKETINT *pThis, bool fBlocking)
374{
375 if (pThis->fBlocking != fBlocking)
376 return rtSocketSwitchBlockingModeSlow(pThis, fBlocking);
377 return VINF_SUCCESS;
378}
379
380
381/**
382 * Creates an IPRT socket handle for a native one.
383 *
384 * @returns IPRT status code.
385 * @param ppSocket Where to return the IPRT socket handle.
386 * @param hNative The native handle.
387 */
388int rtSocketCreateForNative(RTSOCKETINT **ppSocket, RTSOCKETNATIVE hNative)
389{
390 RTSOCKETINT *pThis = (RTSOCKETINT *)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pThis));
391 if (!pThis)
392 return VERR_NO_MEMORY;
393 pThis->u32Magic = RTSOCKET_MAGIC;
394 pThis->cUsers = 0;
395 pThis->hNative = hNative;
396 pThis->fClosed = false;
397 pThis->fBlocking = true;
398#ifdef RT_OS_WINDOWS
399 pThis->hEvent = WSA_INVALID_EVENT;
400 pThis->hPollSet = NIL_RTPOLLSET;
401 pThis->fPollEvts = 0;
402 pThis->fSubscribedEvts = 0;
403#endif
404 *ppSocket = pThis;
405 return VINF_SUCCESS;
406}
407
408
409RTDECL(int) RTSocketFromNative(PRTSOCKET phSocket, RTHCINTPTR uNative)
410{
411 AssertReturn(uNative != NIL_RTSOCKETNATIVE, VERR_INVALID_PARAMETER);
412#ifndef RT_OS_WINDOWS
413 AssertReturn(uNative >= 0, VERR_INVALID_PARAMETER);
414#endif
415 AssertPtrReturn(phSocket, VERR_INVALID_POINTER);
416 return rtSocketCreateForNative(phSocket, uNative);
417}
418
419
420/**
421 * Wrapper around socket().
422 *
423 * @returns IPRT status code.
424 * @param phSocket Where to store the handle to the socket on
425 * success.
426 * @param iDomain The protocol family (PF_XXX).
427 * @param iType The socket type (SOCK_XXX).
428 * @param iProtocol Socket parameter, usually 0.
429 */
430int rtSocketCreate(PRTSOCKET phSocket, int iDomain, int iType, int iProtocol)
431{
432 /*
433 * Create the socket.
434 */
435 RTSOCKETNATIVE hNative = socket(iDomain, iType, iProtocol);
436 if (hNative == NIL_RTSOCKETNATIVE)
437 return rtSocketError();
438
439 /*
440 * Wrap it.
441 */
442 int rc = rtSocketCreateForNative(phSocket, hNative);
443 if (RT_FAILURE(rc))
444 {
445#ifdef RT_OS_WINDOWS
446 closesocket(hNative);
447#else
448 close(hNative);
449#endif
450 }
451 return rc;
452}
453
454
455RTDECL(uint32_t) RTSocketRetain(RTSOCKET hSocket)
456{
457 RTSOCKETINT *pThis = hSocket;
458 AssertPtrReturn(pThis, UINT32_MAX);
459 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
460 return RTMemPoolRetain(pThis);
461}
462
463
464/**
465 * Worker for RTSocketRelease and RTSocketClose.
466 *
467 * @returns IPRT status code.
468 * @param pThis The socket handle instance data.
469 * @param fDestroy Whether we're reaching ref count zero.
470 */
471static int rtSocketCloseIt(RTSOCKETINT *pThis, bool fDestroy)
472{
473 /*
474 * Invalidate the handle structure on destroy.
475 */
476 if (fDestroy)
477 {
478 Assert(ASMAtomicReadU32(&pThis->u32Magic) == RTSOCKET_MAGIC);
479 ASMAtomicWriteU32(&pThis->u32Magic, RTSOCKET_MAGIC_DEAD);
480 }
481
482 int rc = VINF_SUCCESS;
483 if (ASMAtomicCmpXchgBool(&pThis->fClosed, true, false))
484 {
485 /*
486 * Close the native handle.
487 */
488 RTSOCKETNATIVE hNative = pThis->hNative;
489 if (hNative != NIL_RTSOCKETNATIVE)
490 {
491 pThis->hNative = NIL_RTSOCKETNATIVE;
492
493#ifdef RT_OS_WINDOWS
494 if (closesocket(hNative))
495#else
496 if (close(hNative))
497#endif
498 {
499 rc = rtSocketError();
500#ifdef RT_OS_WINDOWS
501 AssertMsgFailed(("\"%s\": closesocket(%p) -> %Rrc\n", (uintptr_t)hNative, rc));
502#else
503 AssertMsgFailed(("\"%s\": close(%d) -> %Rrc\n", hNative, rc));
504#endif
505 }
506 }
507
508#ifdef RT_OS_WINDOWS
509 /*
510 * Close the event.
511 */
512 WSAEVENT hEvent = pThis->hEvent;
513 if (hEvent == WSA_INVALID_EVENT)
514 {
515 pThis->hEvent = WSA_INVALID_EVENT;
516 WSACloseEvent(hEvent);
517 }
518#endif
519 }
520
521 return rc;
522}
523
524
525RTDECL(uint32_t) RTSocketRelease(RTSOCKET hSocket)
526{
527 RTSOCKETINT *pThis = hSocket;
528 if (pThis == NIL_RTSOCKET)
529 return 0;
530 AssertPtrReturn(pThis, UINT32_MAX);
531 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
532
533 /* get the refcount without killing it... */
534 uint32_t cRefs = RTMemPoolRefCount(pThis);
535 AssertReturn(cRefs != UINT32_MAX, UINT32_MAX);
536 if (cRefs == 1)
537 rtSocketCloseIt(pThis, true);
538
539 return RTMemPoolRelease(RTMEMPOOL_DEFAULT, pThis);
540}
541
542
543RTDECL(int) RTSocketClose(RTSOCKET hSocket)
544{
545 RTSOCKETINT *pThis = hSocket;
546 if (pThis == NIL_RTSOCKET)
547 return VINF_SUCCESS;
548 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
549 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
550
551 uint32_t cRefs = RTMemPoolRefCount(pThis);
552 AssertReturn(cRefs != UINT32_MAX, UINT32_MAX);
553
554 int rc = rtSocketCloseIt(pThis, cRefs == 1);
555
556 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pThis);
557 return rc;
558}
559
560
561RTDECL(RTHCUINTPTR) RTSocketToNative(RTSOCKET hSocket)
562{
563 RTSOCKETINT *pThis = hSocket;
564 AssertPtrReturn(pThis, RTHCUINTPTR_MAX);
565 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, RTHCUINTPTR_MAX);
566 return (RTHCUINTPTR)pThis->hNative;
567}
568
569
570RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable)
571{
572 RTSOCKETINT *pThis = hSocket;
573 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
574 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
575 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
576
577 int rc = VINF_SUCCESS;
578#ifdef RT_OS_WINDOWS
579 if (!SetHandleInformation((HANDLE)pThis->hNative, HANDLE_FLAG_INHERIT, fInheritable ? HANDLE_FLAG_INHERIT : 0))
580 rc = RTErrConvertFromWin32(GetLastError());
581#else
582 if (fcntl(pThis->hNative, F_SETFD, fInheritable ? 0 : FD_CLOEXEC) < 0)
583 rc = RTErrConvertFromErrno(errno);
584#endif
585
586 return rc;
587}
588
589static bool rtSocketIsIPv4Numerical(const char *pszAddress, PRTNETADDRIPV4 pAddr)
590{
591
592 /* Empty address resolves to the INADDR_ANY address (good for bind). */
593 if (!*pszAddress)
594 {
595 pAddr->u = INADDR_ANY;
596 return true;
597 }
598
599 /* Four quads? */
600 char *psz = (char *)pszAddress;
601 for (int i = 0; i < 4; i++)
602 {
603 uint8_t u8;
604 int rc = RTStrToUInt8Ex(psz, &psz, 0, &u8);
605 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
606 return false;
607 if (*psz != (i < 3 ? '.' : '\0'))
608 return false;
609 psz++;
610
611 pAddr->au8[i] = u8; /* big endian */
612 }
613
614 return true;
615}
616
617RTDECL(int) RTSocketParseInetAddress(const char *pszAddress, unsigned uPort, PRTNETADDR pAddr)
618{
619 int rc;
620
621 /*
622 * Validate input.
623 */
624 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
625 AssertPtrNullReturn(pszAddress, VERR_INVALID_POINTER);
626
627#ifdef RT_OS_WINDOWS
628 /*
629 * Initialize WinSock and check version.
630 */
631 WORD wVersionRequested = MAKEWORD(1, 1);
632 WSADATA wsaData;
633 rc = WSAStartup(wVersionRequested, &wsaData);
634 if (wsaData.wVersion != wVersionRequested)
635 {
636 AssertMsgFailed(("Wrong winsock version\n"));
637 return VERR_NOT_SUPPORTED;
638 }
639#endif
640
641 /*
642 * Resolve the address. Pretty crude at the moment, but we have to make
643 * sure to not ask the NT 4 gethostbyname about an IPv4 address as it may
644 * give a wrong answer.
645 */
646 /** @todo this only supports IPv4, and IPv6 support needs to be added.
647 * It probably needs to be converted to getaddrinfo(). */
648 RTNETADDRIPV4 IPv4Quad;
649 if ( !pszAddress
650 || rtSocketIsIPv4Numerical(pszAddress, &IPv4Quad))
651 {
652 Log3(("rtSocketIsIPv4Numerical: %#x (%RTnaipv4)\n", pszAddress, IPv4Quad.u, IPv4Quad));
653 RT_ZERO(*pAddr);
654 pAddr->enmType = RTNETADDRTYPE_IPV4;
655 pAddr->uPort = uPort;
656 pAddr->uAddr.IPv4 = IPv4Quad;
657 return VINF_SUCCESS;
658 }
659
660 struct hostent *pHostEnt;
661 pHostEnt = gethostbyname(pszAddress);
662 if (!pHostEnt)
663 {
664 rc = rtSocketResolverError();
665 AssertMsgFailed(("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
666 return rc;
667 }
668
669 if (pHostEnt->h_addrtype == AF_INET)
670 {
671 RT_ZERO(*pAddr);
672 pAddr->enmType = RTNETADDRTYPE_IPV4;
673 pAddr->uPort = uPort;
674 pAddr->uAddr.IPv4.u = ((struct in_addr *)pHostEnt->h_addr)->s_addr;
675 Log3(("gethostbyname: %s -> %#x (%RTnaipv4)\n", pszAddress, pAddr->uAddr.IPv4.u, pAddr->uAddr.IPv4));
676 }
677 else
678 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
679
680 return VINF_SUCCESS;
681}
682
683
684RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
685{
686 /*
687 * Validate input.
688 */
689 RTSOCKETINT *pThis = hSocket;
690 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
691 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
692 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
693 AssertPtr(pvBuffer);
694 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
695
696
697 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
698 if (RT_FAILURE(rc))
699 return rc;
700
701 /*
702 * Read loop.
703 * If pcbRead is NULL we have to fill the entire buffer!
704 */
705 size_t cbRead = 0;
706 size_t cbToRead = cbBuffer;
707 for (;;)
708 {
709 rtSocketErrorReset();
710#ifdef RT_OS_WINDOWS
711 int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
712#else
713 size_t cbNow = cbToRead;
714#endif
715 ssize_t cbBytesRead = recv(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL);
716 if (cbBytesRead <= 0)
717 {
718 rc = rtSocketError();
719 Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
720 if (RT_SUCCESS_NP(rc))
721 {
722 if (!pcbRead)
723 rc = VERR_NET_SHUTDOWN;
724 else
725 {
726 *pcbRead = 0;
727 rc = VINF_SUCCESS;
728 }
729 }
730 break;
731 }
732 if (pcbRead)
733 {
734 /* return partial data */
735 *pcbRead = cbBytesRead;
736 break;
737 }
738
739 /* read more? */
740 cbRead += cbBytesRead;
741 if (cbRead == cbBuffer)
742 break;
743
744 /* next */
745 cbToRead = cbBuffer - cbRead;
746 }
747
748 rtSocketUnlock(pThis);
749 return rc;
750}
751
752
753RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr)
754{
755 /*
756 * Validate input.
757 */
758 RTSOCKETINT *pThis = hSocket;
759 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
760 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
761 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
762 AssertPtr(pvBuffer);
763 AssertPtr(pcbRead);
764 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
765
766 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
767 if (RT_FAILURE(rc))
768 return rc;
769
770 /*
771 * Read data.
772 */
773 size_t cbRead = 0;
774 size_t cbToRead = cbBuffer;
775 rtSocketErrorReset();
776 RTSOCKADDRUNION u;
777#ifdef RT_OS_WINDOWS
778 int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
779 int cbAddr = sizeof(u);
780#else
781 size_t cbNow = cbToRead;
782 socklen_t cbAddr = sizeof(u);
783#endif
784 ssize_t cbBytesRead = recvfrom(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL, &u.Addr, &cbAddr);
785 if (cbBytesRead <= 0)
786 {
787 rc = rtSocketError();
788 Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
789 if (RT_SUCCESS_NP(rc))
790 {
791 *pcbRead = 0;
792 rc = VINF_SUCCESS;
793 }
794 }
795 else
796 {
797 if (pSrcAddr)
798 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pSrcAddr);
799 *pcbRead = cbBytesRead;
800 }
801
802 rtSocketUnlock(pThis);
803 return rc;
804}
805
806
807RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer)
808{
809 /*
810 * Validate input.
811 */
812 RTSOCKETINT *pThis = hSocket;
813 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
814 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
815 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
816
817 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
818 if (RT_FAILURE(rc))
819 return rc;
820
821 /*
822 * Try write all at once.
823 */
824#ifdef RT_OS_WINDOWS
825 int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
826#else
827 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
828#endif
829 ssize_t cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
830 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
831 rc = VINF_SUCCESS;
832 else if (cbWritten < 0)
833 rc = rtSocketError();
834 else
835 {
836 /*
837 * Unfinished business, write the remainder of the request. Must ignore
838 * VERR_INTERRUPTED here if we've managed to send something.
839 */
840 size_t cbSentSoFar = 0;
841 for (;;)
842 {
843 /* advance */
844 cbBuffer -= (size_t)cbWritten;
845 if (!cbBuffer)
846 break;
847 cbSentSoFar += (size_t)cbWritten;
848 pvBuffer = (char const *)pvBuffer + cbWritten;
849
850 /* send */
851#ifdef RT_OS_WINDOWS
852 cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
853#else
854 cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
855#endif
856 cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
857 if (cbWritten >= 0)
858 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%zu cbBuffer=%zu rtSocketError()=%d\n",
859 cbWritten, cbBuffer, rtSocketError()));
860 else
861 {
862 rc = rtSocketError();
863 if (rc != VERR_INTERNAL_ERROR || cbSentSoFar == 0)
864 break;
865 cbWritten = 0;
866 rc = VINF_SUCCESS;
867 }
868 }
869 }
870
871 rtSocketUnlock(pThis);
872 return rc;
873}
874
875
876RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pAddr)
877{
878 /*
879 * Validate input.
880 */
881 RTSOCKETINT *pThis = hSocket;
882 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
883 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
884
885 /* no locking since UDP reads may be done concurrently to writes, and
886 * this is the normal use case of this code. */
887
888 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
889 if (RT_FAILURE(rc))
890 return rc;
891
892 /* Figure out destination address. */
893 struct sockaddr *pSA = NULL;
894#ifdef RT_OS_WINDOWS
895 int cbSA = 0;
896#else
897 socklen_t cbSA = 0;
898#endif
899 RTSOCKADDRUNION u;
900 if (pAddr)
901 {
902 rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), NULL);
903 if (RT_FAILURE(rc))
904 return rc;
905 pSA = &u.Addr;
906 cbSA = sizeof(u);
907 }
908
909 /*
910 * Must write all at once, otherwise it is a failure.
911 */
912#ifdef RT_OS_WINDOWS
913 int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
914#else
915 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
916#endif
917 ssize_t cbWritten = sendto(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL, pSA, cbSA);
918 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
919 rc = VINF_SUCCESS;
920 else if (cbWritten < 0)
921 rc = rtSocketError();
922 else
923 rc = VERR_TOO_MUCH_DATA;
924
925 rtSocketUnlock(pThis);
926 return rc;
927}
928
929
930RTDECL(int) RTSocketSgWrite(RTSOCKET hSocket, PCRTSGBUF pSgBuf)
931{
932 /*
933 * Validate input.
934 */
935 RTSOCKETINT *pThis = hSocket;
936 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
937 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
938 AssertPtrReturn(pSgBuf, VERR_INVALID_PARAMETER);
939 AssertReturn(pSgBuf->cSegs > 0, VERR_INVALID_PARAMETER);
940 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
941
942 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
943 if (RT_FAILURE(rc))
944 return rc;
945
946 /*
947 * Construct message descriptor (translate pSgBuf) and send it.
948 */
949 rc = VERR_NO_TMP_MEMORY;
950#ifdef RT_OS_WINDOWS
951 AssertCompileSize(WSABUF, sizeof(RTSGSEG));
952 AssertCompileMemberSize(WSABUF, buf, RT_SIZEOFMEMB(RTSGSEG, pvSeg));
953
954 LPWSABUF paMsg = (LPWSABUF)RTMemTmpAllocZ(pSgBuf->cSegs * sizeof(WSABUF));
955 if (paMsg)
956 {
957 for (unsigned i = 0; i < pSgBuf->cSegs; i++)
958 {
959 paMsg[i].buf = (char *)pSgBuf->paSegs[i].pvSeg;
960 paMsg[i].len = (u_long)pSgBuf->paSegs[i].cbSeg;
961 }
962
963 DWORD dwSent;
964 int hrc = WSASend(pThis->hNative, paMsg, pSgBuf->cSegs, &dwSent,
965 MSG_NOSIGNAL, NULL, NULL);
966 if (!hrc)
967 rc = VINF_SUCCESS;
968/** @todo check for incomplete writes */
969 else
970 rc = rtSocketError();
971
972 RTMemTmpFree(paMsg);
973 }
974
975#else /* !RT_OS_WINDOWS */
976 AssertCompileSize(struct iovec, sizeof(RTSGSEG));
977 AssertCompileMemberSize(struct iovec, iov_base, RT_SIZEOFMEMB(RTSGSEG, pvSeg));
978 AssertCompileMemberSize(struct iovec, iov_len, RT_SIZEOFMEMB(RTSGSEG, cbSeg));
979
980 struct iovec *paMsg = (struct iovec *)RTMemTmpAllocZ(pSgBuf->cSegs * sizeof(struct iovec));
981 if (paMsg)
982 {
983 for (unsigned i = 0; i < pSgBuf->cSegs; i++)
984 {
985 paMsg[i].iov_base = pSgBuf->paSegs[i].pvSeg;
986 paMsg[i].iov_len = pSgBuf->paSegs[i].cbSeg;
987 }
988
989 struct msghdr msgHdr;
990 RT_ZERO(msgHdr);
991 msgHdr.msg_iov = paMsg;
992 msgHdr.msg_iovlen = pSgBuf->cSegs;
993 ssize_t cbWritten = sendmsg(pThis->hNative, &msgHdr, MSG_NOSIGNAL);
994 if (RT_LIKELY(cbWritten >= 0))
995 rc = VINF_SUCCESS;
996/** @todo check for incomplete writes */
997 else
998 rc = rtSocketError();
999
1000 RTMemTmpFree(paMsg);
1001 }
1002#endif /* !RT_OS_WINDOWS */
1003
1004 rtSocketUnlock(pThis);
1005 return rc;
1006}
1007
1008
1009RTDECL(int) RTSocketSgWriteL(RTSOCKET hSocket, size_t cSegs, ...)
1010{
1011 va_list va;
1012 va_start(va, cSegs);
1013 int rc = RTSocketSgWriteLV(hSocket, cSegs, va);
1014 va_end(va);
1015 return rc;
1016}
1017
1018
1019RTDECL(int) RTSocketSgWriteLV(RTSOCKET hSocket, size_t cSegs, va_list va)
1020{
1021 /*
1022 * Set up a S/G segment array + buffer on the stack and pass it
1023 * on to RTSocketSgWrite.
1024 */
1025 Assert(cSegs <= 16);
1026 PRTSGSEG paSegs = (PRTSGSEG)alloca(cSegs * sizeof(RTSGSEG));
1027 AssertReturn(paSegs, VERR_NO_TMP_MEMORY);
1028 for (size_t i = 0; i < cSegs; i++)
1029 {
1030 paSegs[i].pvSeg = va_arg(va, void *);
1031 paSegs[i].cbSeg = va_arg(va, size_t);
1032 }
1033
1034 RTSGBUF SgBuf;
1035 RTSgBufInit(&SgBuf, paSegs, cSegs);
1036 return RTSocketSgWrite(hSocket, &SgBuf);
1037}
1038
1039
1040RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
1041{
1042 /*
1043 * Validate input.
1044 */
1045 RTSOCKETINT *pThis = hSocket;
1046 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1047 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1048 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
1049 AssertPtr(pvBuffer);
1050 AssertPtrReturn(pcbRead, VERR_INVALID_PARAMETER);
1051 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1052
1053 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1054 if (RT_FAILURE(rc))
1055 return rc;
1056
1057 rtSocketErrorReset();
1058#ifdef RT_OS_WINDOWS
1059 int cbNow = cbBuffer >= INT_MAX/2 ? INT_MAX/2 : (int)cbBuffer;
1060
1061 int cbRead = recv(pThis->hNative, (char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1062 if (cbRead >= 0)
1063 {
1064 *pcbRead = cbRead;
1065 rc = VINF_SUCCESS;
1066 }
1067 else
1068 rc = rtSocketError();
1069
1070 if (rc == VERR_TRY_AGAIN)
1071 rc = VINF_TRY_AGAIN;
1072#else
1073 ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL);
1074 if (cbRead >= 0)
1075 *pcbRead = cbRead;
1076 else if (errno == EAGAIN)
1077 {
1078 *pcbRead = 0;
1079 rc = VINF_TRY_AGAIN;
1080 }
1081 else
1082 rc = rtSocketError();
1083#endif
1084
1085 rtSocketUnlock(pThis);
1086 return rc;
1087}
1088
1089
1090RTDECL(int) RTSocketWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten)
1091{
1092 /*
1093 * Validate input.
1094 */
1095 RTSOCKETINT *pThis = hSocket;
1096 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1097 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1098 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER);
1099 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1100
1101 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1102 if (RT_FAILURE(rc))
1103 return rc;
1104
1105 rtSocketErrorReset();
1106#ifdef RT_OS_WINDOWS
1107 int cbNow = RT_MIN((int)cbBuffer, INT_MAX/2);
1108
1109 int cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1110
1111 if (cbWritten >= 0)
1112 {
1113 *pcbWritten = cbWritten;
1114 rc = VINF_SUCCESS;
1115 }
1116 else
1117 rc = rtSocketError();
1118
1119 if (rc == VERR_TRY_AGAIN)
1120 rc = VINF_TRY_AGAIN;
1121#else
1122 ssize_t cbWritten = send(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL);
1123 if (cbWritten >= 0)
1124 *pcbWritten = cbWritten;
1125 else if (errno == EAGAIN)
1126 {
1127 *pcbWritten = 0;
1128 rc = VINF_TRY_AGAIN;
1129 }
1130 else
1131 rc = rtSocketError();
1132#endif
1133
1134 rtSocketUnlock(pThis);
1135 return rc;
1136}
1137
1138
1139RTDECL(int) RTSocketSgWriteNB(RTSOCKET hSocket, PCRTSGBUF pSgBuf, size_t *pcbWritten)
1140{
1141 /*
1142 * Validate input.
1143 */
1144 RTSOCKETINT *pThis = hSocket;
1145 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1146 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1147 AssertPtrReturn(pSgBuf, VERR_INVALID_PARAMETER);
1148 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER);
1149 AssertReturn(pSgBuf->cSegs > 0, VERR_INVALID_PARAMETER);
1150 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1151
1152 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1153 if (RT_FAILURE(rc))
1154 return rc;
1155
1156 unsigned cSegsToSend = 0;
1157 rc = VERR_NO_TMP_MEMORY;
1158#ifdef RT_OS_WINDOWS
1159 LPWSABUF paMsg = NULL;
1160
1161 RTSgBufMapToNative(paMsg, pSgBuf, WSABUF, buf, char *, len, u_long, cSegsToSend);
1162 if (paMsg)
1163 {
1164 DWORD dwSent = 0;
1165 int hrc = WSASend(pThis->hNative, paMsg, cSegsToSend, &dwSent,
1166 MSG_NOSIGNAL, NULL, NULL);
1167 if (!hrc)
1168 rc = VINF_SUCCESS;
1169 else
1170 rc = rtSocketError();
1171
1172 *pcbWritten = dwSent;
1173
1174 RTMemTmpFree(paMsg);
1175 }
1176
1177#else /* !RT_OS_WINDOWS */
1178 struct iovec *paMsg = NULL;
1179
1180 RTSgBufMapToNative(paMsg, pSgBuf, struct iovec, iov_base, void *, iov_len, size_t, cSegsToSend);
1181 if (paMsg)
1182 {
1183 struct msghdr msgHdr;
1184 RT_ZERO(msgHdr);
1185 msgHdr.msg_iov = paMsg;
1186 msgHdr.msg_iovlen = cSegsToSend;
1187 ssize_t cbWritten = sendmsg(pThis->hNative, &msgHdr, MSG_NOSIGNAL);
1188 if (RT_LIKELY(cbWritten >= 0))
1189 {
1190 rc = VINF_SUCCESS;
1191 *pcbWritten = cbWritten;
1192 }
1193 else
1194 rc = rtSocketError();
1195
1196 RTMemTmpFree(paMsg);
1197 }
1198#endif /* !RT_OS_WINDOWS */
1199
1200 rtSocketUnlock(pThis);
1201 return rc;
1202}
1203
1204
1205RTDECL(int) RTSocketSgWriteLNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, ...)
1206{
1207 va_list va;
1208 va_start(va, pcbWritten);
1209 int rc = RTSocketSgWriteLVNB(hSocket, cSegs, pcbWritten, va);
1210 va_end(va);
1211 return rc;
1212}
1213
1214
1215RTDECL(int) RTSocketSgWriteLVNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, va_list va)
1216{
1217 /*
1218 * Set up a S/G segment array + buffer on the stack and pass it
1219 * on to RTSocketSgWrite.
1220 */
1221 Assert(cSegs <= 16);
1222 PRTSGSEG paSegs = (PRTSGSEG)alloca(cSegs * sizeof(RTSGSEG));
1223 AssertReturn(paSegs, VERR_NO_TMP_MEMORY);
1224 for (size_t i = 0; i < cSegs; i++)
1225 {
1226 paSegs[i].pvSeg = va_arg(va, void *);
1227 paSegs[i].cbSeg = va_arg(va, size_t);
1228 }
1229
1230 RTSGBUF SgBuf;
1231 RTSgBufInit(&SgBuf, paSegs, cSegs);
1232 return RTSocketSgWriteNB(hSocket, &SgBuf, pcbWritten);
1233}
1234
1235
1236RTDECL(int) RTSocketSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies)
1237{
1238 /*
1239 * Validate input.
1240 */
1241 RTSOCKETINT *pThis = hSocket;
1242 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1243 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1244 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1245 int const fdMax = (int)pThis->hNative + 1;
1246 AssertReturn(fdMax - 1 == pThis->hNative, VERR_INTERNAL_ERROR_5);
1247
1248 /*
1249 * Set up the file descriptor sets and do the select.
1250 */
1251 fd_set fdsetR;
1252 FD_ZERO(&fdsetR);
1253 FD_SET(pThis->hNative, &fdsetR);
1254
1255 fd_set fdsetE = fdsetR;
1256
1257 int rc;
1258 if (cMillies == RT_INDEFINITE_WAIT)
1259 rc = select(fdMax, &fdsetR, NULL, &fdsetE, NULL);
1260 else
1261 {
1262 struct timeval timeout;
1263 timeout.tv_sec = cMillies / 1000;
1264 timeout.tv_usec = (cMillies % 1000) * 1000;
1265 rc = select(fdMax, &fdsetR, NULL, &fdsetE, &timeout);
1266 }
1267 if (rc > 0)
1268 rc = VINF_SUCCESS;
1269 else if (rc == 0)
1270 rc = VERR_TIMEOUT;
1271 else
1272 rc = rtSocketError();
1273
1274 return rc;
1275}
1276
1277
1278RTDECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents,
1279 RTMSINTERVAL cMillies)
1280{
1281 /*
1282 * Validate input.
1283 */
1284 RTSOCKETINT *pThis = hSocket;
1285 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1286 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1287 AssertPtrReturn(pfEvents, VERR_INVALID_PARAMETER);
1288 AssertReturn(!(fEvents & ~RTSOCKET_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
1289 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1290 int const fdMax = (int)pThis->hNative + 1;
1291 AssertReturn(fdMax - 1 == pThis->hNative, VERR_INTERNAL_ERROR_5);
1292
1293 *pfEvents = 0;
1294
1295 /*
1296 * Set up the file descriptor sets and do the select.
1297 */
1298 fd_set fdsetR;
1299 fd_set fdsetW;
1300 fd_set fdsetE;
1301 FD_ZERO(&fdsetR);
1302 FD_ZERO(&fdsetW);
1303 FD_ZERO(&fdsetE);
1304
1305 if (fEvents & RTSOCKET_EVT_READ)
1306 FD_SET(pThis->hNative, &fdsetR);
1307 if (fEvents & RTSOCKET_EVT_WRITE)
1308 FD_SET(pThis->hNative, &fdsetW);
1309 if (fEvents & RTSOCKET_EVT_ERROR)
1310 FD_SET(pThis->hNative, &fdsetE);
1311
1312 int rc;
1313 if (cMillies == RT_INDEFINITE_WAIT)
1314 rc = select(fdMax, &fdsetR, &fdsetW, &fdsetE, NULL);
1315 else
1316 {
1317 struct timeval timeout;
1318 timeout.tv_sec = cMillies / 1000;
1319 timeout.tv_usec = (cMillies % 1000) * 1000;
1320 rc = select(fdMax, &fdsetR, &fdsetW, &fdsetE, &timeout);
1321 }
1322 if (rc > 0)
1323 {
1324 if (FD_ISSET(pThis->hNative, &fdsetR))
1325 *pfEvents |= RTSOCKET_EVT_READ;
1326 if (FD_ISSET(pThis->hNative, &fdsetW))
1327 *pfEvents |= RTSOCKET_EVT_WRITE;
1328 if (FD_ISSET(pThis->hNative, &fdsetE))
1329 *pfEvents |= RTSOCKET_EVT_ERROR;
1330
1331 rc = VINF_SUCCESS;
1332 }
1333 else if (rc == 0)
1334 rc = VERR_TIMEOUT;
1335 else
1336 rc = rtSocketError();
1337
1338 return rc;
1339}
1340
1341
1342RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite)
1343{
1344 /*
1345 * Validate input, don't lock it because we might want to interrupt a call
1346 * active on a different thread.
1347 */
1348 RTSOCKETINT *pThis = hSocket;
1349 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1350 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1351 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1352 AssertReturn(fRead || fWrite, VERR_INVALID_PARAMETER);
1353
1354 /*
1355 * Do the job.
1356 */
1357 int rc = VINF_SUCCESS;
1358 int fHow;
1359 if (fRead && fWrite)
1360 fHow = SHUT_RDWR;
1361 else if (fRead)
1362 fHow = SHUT_RD;
1363 else
1364 fHow = SHUT_WR;
1365 if (shutdown(pThis->hNative, fHow) == -1)
1366 rc = rtSocketError();
1367
1368 return rc;
1369}
1370
1371
1372RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
1373{
1374 /*
1375 * Validate input.
1376 */
1377 RTSOCKETINT *pThis = hSocket;
1378 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1379 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1380 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1381
1382 /*
1383 * Get the address and convert it.
1384 */
1385 int rc;
1386 RTSOCKADDRUNION u;
1387#ifdef RT_OS_WINDOWS
1388 int cbAddr = sizeof(u);
1389#else
1390 socklen_t cbAddr = sizeof(u);
1391#endif
1392 RT_ZERO(u);
1393 if (getsockname(pThis->hNative, &u.Addr, &cbAddr) == 0)
1394 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
1395 else
1396 rc = rtSocketError();
1397
1398 return rc;
1399}
1400
1401
1402RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
1403{
1404 /*
1405 * Validate input.
1406 */
1407 RTSOCKETINT *pThis = hSocket;
1408 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1409 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1410 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1411
1412 /*
1413 * Get the address and convert it.
1414 */
1415 int rc;
1416 RTSOCKADDRUNION u;
1417#ifdef RT_OS_WINDOWS
1418 int cbAddr = sizeof(u);
1419#else
1420 socklen_t cbAddr = sizeof(u);
1421#endif
1422 RT_ZERO(u);
1423 if (getpeername(pThis->hNative, &u.Addr, &cbAddr) == 0)
1424 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
1425 else
1426 rc = rtSocketError();
1427
1428 return rc;
1429}
1430
1431
1432
1433/**
1434 * Wrapper around bind.
1435 *
1436 * @returns IPRT status code.
1437 * @param hSocket The socket handle.
1438 * @param pAddr The address to bind to.
1439 */
1440int rtSocketBind(RTSOCKET hSocket, PCRTNETADDR pAddr)
1441{
1442 /*
1443 * Validate input.
1444 */
1445 RTSOCKETINT *pThis = hSocket;
1446 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1447 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1448 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1449
1450 RTSOCKADDRUNION u;
1451 int cbAddr;
1452 int rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), &cbAddr);
1453 if (RT_SUCCESS(rc))
1454 {
1455 if (bind(pThis->hNative, &u.Addr, cbAddr) != 0)
1456 rc = rtSocketError();
1457 }
1458
1459 rtSocketUnlock(pThis);
1460 return rc;
1461}
1462
1463
1464/**
1465 * Wrapper around listen.
1466 *
1467 * @returns IPRT status code.
1468 * @param hSocket The socket handle.
1469 * @param cMaxPending The max number of pending connections.
1470 */
1471int rtSocketListen(RTSOCKET hSocket, int cMaxPending)
1472{
1473 /*
1474 * Validate input.
1475 */
1476 RTSOCKETINT *pThis = hSocket;
1477 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1478 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1479 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1480
1481 int rc = VINF_SUCCESS;
1482 if (listen(pThis->hNative, cMaxPending) != 0)
1483 rc = rtSocketError();
1484
1485 rtSocketUnlock(pThis);
1486 return rc;
1487}
1488
1489
1490/**
1491 * Wrapper around accept.
1492 *
1493 * @returns IPRT status code.
1494 * @param hSocket The socket handle.
1495 * @param phClient Where to return the client socket handle on
1496 * success.
1497 * @param pAddr Where to return the client address.
1498 * @param pcbAddr On input this gives the size buffer size of what
1499 * @a pAddr point to. On return this contains the
1500 * size of what's stored at @a pAddr.
1501 */
1502int rtSocketAccept(RTSOCKET hSocket, PRTSOCKET phClient, struct sockaddr *pAddr, size_t *pcbAddr)
1503{
1504 /*
1505 * Validate input.
1506 * Only lock the socket temporarily while we get the native handle, so that
1507 * we can safely shutdown and destroy the socket from a different thread.
1508 */
1509 RTSOCKETINT *pThis = hSocket;
1510 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1511 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1512 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1513
1514 /*
1515 * Call accept().
1516 */
1517 rtSocketErrorReset();
1518 int rc = VINF_SUCCESS;
1519#ifdef RT_OS_WINDOWS
1520 int cbAddr = (int)*pcbAddr;
1521#else
1522 socklen_t cbAddr = *pcbAddr;
1523#endif
1524 RTSOCKETNATIVE hNativeClient = accept(pThis->hNative, pAddr, &cbAddr);
1525 if (hNativeClient != NIL_RTSOCKETNATIVE)
1526 {
1527 *pcbAddr = cbAddr;
1528
1529 /*
1530 * Wrap the client socket.
1531 */
1532 rc = rtSocketCreateForNative(phClient, hNativeClient);
1533 if (RT_FAILURE(rc))
1534 {
1535#ifdef RT_OS_WINDOWS
1536 closesocket(hNativeClient);
1537#else
1538 close(hNativeClient);
1539#endif
1540 }
1541 }
1542 else
1543 rc = rtSocketError();
1544
1545 rtSocketUnlock(pThis);
1546 return rc;
1547}
1548
1549
1550/**
1551 * Wrapper around connect.
1552 *
1553 * @returns IPRT status code.
1554 * @param hSocket The socket handle.
1555 * @param pAddr The socket address to connect to.
1556 */
1557int rtSocketConnect(RTSOCKET hSocket, PCRTNETADDR pAddr)
1558{
1559 /*
1560 * Validate input.
1561 */
1562 RTSOCKETINT *pThis = hSocket;
1563 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1564 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1565 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1566
1567 RTSOCKADDRUNION u;
1568 int cbAddr;
1569 int rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), &cbAddr);
1570 if (RT_SUCCESS(rc))
1571 {
1572 if (connect(pThis->hNative, &u.Addr, cbAddr) != 0)
1573 rc = rtSocketError();
1574 }
1575
1576 rtSocketUnlock(pThis);
1577 return rc;
1578}
1579
1580
1581/**
1582 * Wrapper around setsockopt.
1583 *
1584 * @returns IPRT status code.
1585 * @param hSocket The socket handle.
1586 * @param iLevel The protocol level, e.g. IPPORTO_TCP.
1587 * @param iOption The option, e.g. TCP_NODELAY.
1588 * @param pvValue The value buffer.
1589 * @param cbValue The size of the value pointed to by pvValue.
1590 */
1591int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValue, int cbValue)
1592{
1593 /*
1594 * Validate input.
1595 */
1596 RTSOCKETINT *pThis = hSocket;
1597 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1598 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1599 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1600
1601 int rc = VINF_SUCCESS;
1602 if (setsockopt(pThis->hNative, iLevel, iOption, (const char *)pvValue, cbValue) != 0)
1603 rc = rtSocketError();
1604
1605 rtSocketUnlock(pThis);
1606 return rc;
1607}
1608
1609#ifdef RT_OS_WINDOWS
1610
1611/**
1612 * Internal RTPollSetAdd helper that returns the handle that should be added to
1613 * the pollset.
1614 *
1615 * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
1616 * @param hSocket The socket handle.
1617 * @param fEvents The events we're polling for.
1618 * @param ph where to put the primary handle.
1619 */
1620int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph)
1621{
1622 RTSOCKETINT *pThis = hSocket;
1623 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1624 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1625 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1626
1627 int rc = VINF_SUCCESS;
1628 if (pThis->hEvent != WSA_INVALID_EVENT)
1629 *ph = pThis->hEvent;
1630 else
1631 {
1632 *ph = pThis->hEvent = WSACreateEvent();
1633 if (pThis->hEvent == WSA_INVALID_EVENT)
1634 rc = rtSocketError();
1635 }
1636
1637 rtSocketUnlock(pThis);
1638 return rc;
1639}
1640
1641
1642/**
1643 * Undos the harm done by WSAEventSelect.
1644 *
1645 * @returns IPRT status code.
1646 * @param pThis The socket handle.
1647 */
1648static int rtSocketPollClearEventAndRestoreBlocking(RTSOCKETINT *pThis)
1649{
1650 int rc = VINF_SUCCESS;
1651 if (pThis->fSubscribedEvts)
1652 {
1653 if (WSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
1654 {
1655 pThis->fSubscribedEvts = 0;
1656
1657 /*
1658 * Switch back to blocking mode if that was the state before the
1659 * operation.
1660 */
1661 if (pThis->fBlocking)
1662 {
1663 u_long fNonBlocking = 0;
1664 int rc2 = ioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
1665 if (rc2 != 0)
1666 {
1667 rc = rtSocketError();
1668 AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
1669 }
1670 }
1671 }
1672 else
1673 {
1674 rc = rtSocketError();
1675 AssertMsgFailed(("%Rrc\n", rc));
1676 }
1677 }
1678 return rc;
1679}
1680
1681
1682/**
1683 * Updates the mask of events we're subscribing to.
1684 *
1685 * @returns IPRT status code.
1686 * @param pThis The socket handle.
1687 * @param fEvents The events we want to subscribe to.
1688 */
1689static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
1690{
1691 LONG fNetworkEvents = 0;
1692 if (fEvents & RTPOLL_EVT_READ)
1693 fNetworkEvents |= FD_READ;
1694 if (fEvents & RTPOLL_EVT_WRITE)
1695 fNetworkEvents |= FD_WRITE;
1696 if (fEvents & RTPOLL_EVT_ERROR)
1697 fNetworkEvents |= FD_CLOSE;
1698 LogFlowFunc(("fNetworkEvents=%#x\n", fNetworkEvents));
1699 if (WSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
1700 {
1701 pThis->fSubscribedEvts = fEvents;
1702 return VINF_SUCCESS;
1703 }
1704
1705 int rc = rtSocketError();
1706 AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
1707 return rc;
1708}
1709
1710
1711/**
1712 * Checks for pending events.
1713 *
1714 * @returns Event mask or 0.
1715 * @param pThis The socket handle.
1716 * @param fEvents The desired events.
1717 */
1718static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents)
1719{
1720 int rc = VINF_SUCCESS;
1721 uint32_t fRetEvents = 0;
1722
1723 LogFlowFunc(("pThis=%#p fEvents=%#x\n", pThis, fEvents));
1724
1725 /* Make sure WSAEnumNetworkEvents returns what we want. */
1726 if ((pThis->fSubscribedEvts & fEvents) != fEvents)
1727 rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
1728
1729 /* Get the event mask, ASSUMES that WSAEnumNetworkEvents doesn't clear stuff. */
1730 WSANETWORKEVENTS NetEvts;
1731 RT_ZERO(NetEvts);
1732 if (WSAEnumNetworkEvents(pThis->hNative, pThis->hEvent, &NetEvts) == 0)
1733 {
1734 if ( (NetEvts.lNetworkEvents & FD_READ)
1735 && (fEvents & RTPOLL_EVT_READ)
1736 && NetEvts.iErrorCode[FD_READ_BIT] == 0)
1737 fRetEvents |= RTPOLL_EVT_READ;
1738
1739 if ( (NetEvts.lNetworkEvents & FD_WRITE)
1740 && (fEvents & RTPOLL_EVT_WRITE)
1741 && NetEvts.iErrorCode[FD_WRITE_BIT] == 0)
1742 fRetEvents |= RTPOLL_EVT_WRITE;
1743
1744 if (fEvents & RTPOLL_EVT_ERROR)
1745 {
1746 if (NetEvts.lNetworkEvents & FD_CLOSE)
1747 fRetEvents |= RTPOLL_EVT_ERROR;
1748 else
1749 for (uint32_t i = 0; i < FD_MAX_EVENTS; i++)
1750 if ( (NetEvts.lNetworkEvents & (1L << i))
1751 && NetEvts.iErrorCode[i] != 0)
1752 fRetEvents |= RTPOLL_EVT_ERROR;
1753 }
1754 }
1755 else
1756 rc = rtSocketError();
1757
1758 /* Fall back on select if we hit an error above. */
1759 if (RT_FAILURE(rc))
1760 {
1761 /** @todo */
1762 }
1763
1764 LogFlowFunc(("fRetEvents=%#x\n", fRetEvents));
1765 return fRetEvents;
1766}
1767
1768
1769/**
1770 * Internal RTPoll helper that polls the socket handle and, if @a fNoWait is
1771 * clear, starts whatever actions we've got running during the poll call.
1772 *
1773 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
1774 * Event mask (in @a fEvents) and no actions if the handle is ready
1775 * already.
1776 * UINT32_MAX (asserted) if the socket handle is busy in I/O or a
1777 * different poll set.
1778 *
1779 * @param hSocket The socket handle.
1780 * @param hPollSet The poll set handle (for access checks).
1781 * @param fEvents The events we're polling for.
1782 * @param fFinalEntry Set if this is the final entry for this handle
1783 * in this poll set. This can be used for dealing
1784 * with duplicate entries.
1785 * @param fNoWait Set if it's a zero-wait poll call. Clear if
1786 * we'll wait for an event to occur.
1787 *
1788 * @remarks There is a potential race wrt duplicate handles when @a fNoWait is
1789 * @c true, we don't currently care about that oddity...
1790 */
1791uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
1792{
1793 RTSOCKETINT *pThis = hSocket;
1794 AssertPtrReturn(pThis, UINT32_MAX);
1795 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
1796 if (rtSocketTryLock(pThis))
1797 pThis->hPollSet = hPollSet;
1798 else
1799 {
1800 AssertReturn(pThis->hPollSet == hPollSet, UINT32_MAX);
1801 ASMAtomicIncU32(&pThis->cUsers);
1802 }
1803
1804 /* (rtSocketPollCheck will reset the event object). */
1805 uint32_t fRetEvents = pThis->fEventsSaved;
1806 pThis->fEventsSaved = 0; /* Reset */
1807 fRetEvents |= rtSocketPollCheck(pThis, fEvents);
1808
1809 if ( !fRetEvents
1810 && !fNoWait)
1811 {
1812 pThis->fPollEvts |= fEvents;
1813 if ( fFinalEntry
1814 && pThis->fSubscribedEvts != pThis->fPollEvts)
1815 {
1816 int rc = rtSocketPollUpdateEvents(pThis, pThis->fPollEvts);
1817 if (RT_FAILURE(rc))
1818 {
1819 pThis->fPollEvts = 0;
1820 fRetEvents = UINT32_MAX;
1821 }
1822 }
1823 }
1824
1825 if (fRetEvents || fNoWait)
1826 {
1827 if (pThis->cUsers == 1)
1828 {
1829 rtSocketPollClearEventAndRestoreBlocking(pThis);
1830 pThis->hPollSet = NIL_RTPOLLSET;
1831 }
1832 ASMAtomicDecU32(&pThis->cUsers);
1833 }
1834
1835 return fRetEvents;
1836}
1837
1838
1839/**
1840 * Called after a WaitForMultipleObjects returned in order to check for pending
1841 * events and stop whatever actions that rtSocketPollStart() initiated.
1842 *
1843 * @returns Event mask or 0.
1844 *
1845 * @param hSocket The socket handle.
1846 * @param fEvents The events we're polling for.
1847 * @param fFinalEntry Set if this is the final entry for this handle
1848 * in this poll set. This can be used for dealing
1849 * with duplicate entries. Only keep in mind that
1850 * this method is called in reverse order, so the
1851 * first call will have this set (when the entire
1852 * set was processed).
1853 * @param fHarvestEvents Set if we should check for pending events.
1854 */
1855uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
1856{
1857 RTSOCKETINT *pThis = hSocket;
1858 AssertPtrReturn(pThis, 0);
1859 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, 0);
1860 Assert(pThis->cUsers > 0);
1861 Assert(pThis->hPollSet != NIL_RTPOLLSET);
1862
1863 /* Harvest events and clear the event mask for the next round of polling. */
1864 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
1865 pThis->fPollEvts = 0;
1866
1867 /*
1868 * Save the write event if required.
1869 * It is only posted once and might get lost if the another source in the
1870 * pollset with a higher priority has pending events.
1871 */
1872 if ( !fHarvestEvents
1873 && fRetEvents)
1874 {
1875 pThis->fEventsSaved = fRetEvents;
1876 fRetEvents = 0;
1877 }
1878
1879 /* Make the socket blocking again and unlock the handle. */
1880 if (pThis->cUsers == 1)
1881 {
1882 rtSocketPollClearEventAndRestoreBlocking(pThis);
1883 pThis->hPollSet = NIL_RTPOLLSET;
1884 }
1885 ASMAtomicDecU32(&pThis->cUsers);
1886 return fRetEvents;
1887}
1888
1889#endif /* RT_OS_WINDOWS */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette