VirtualBox

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

Last change on this file since 87007 was 86415, checked in by vboxsync, 4 years ago

IPRT,++: Made RTHandleGetStandard's fLeaveOpen parameter work for sockets too. bugref:9841

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 93.7 KB
Line 
1/* $Id: socket.cpp 86415 2020-10-02 11:50:21Z vboxsync $ */
2/** @file
3 * IPRT - Network Sockets.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 <iprt/win/winsock2.h>
33# include <iprt/win/ws2tcpip.h>
34#else /* !RT_OS_WINDOWS */
35# include <errno.h>
36# include <sys/select.h>
37# include <sys/stat.h>
38# include <sys/socket.h>
39# include <netinet/in.h>
40# include <netinet/tcp.h>
41# include <arpa/inet.h>
42# ifdef IPRT_WITH_TCPIP_V6
43# include <netinet6/in6.h>
44# endif
45# include <sys/un.h>
46# include <netdb.h>
47# include <unistd.h>
48# include <fcntl.h>
49# include <sys/uio.h>
50#endif /* !RT_OS_WINDOWS */
51#include <limits.h>
52
53#include "internal/iprt.h"
54#include <iprt/socket.h>
55
56#include <iprt/alloca.h>
57#include <iprt/asm.h>
58#include <iprt/assert.h>
59#include <iprt/ctype.h>
60#include <iprt/err.h>
61#include <iprt/mempool.h>
62#include <iprt/poll.h>
63#include <iprt/string.h>
64#include <iprt/thread.h>
65#include <iprt/time.h>
66#include <iprt/mem.h>
67#include <iprt/sg.h>
68#include <iprt/log.h>
69
70#include "internal/magics.h"
71#include "internal/socket.h"
72#include "internal/string.h"
73#ifdef RT_OS_WINDOWS
74# include "win/internal-r3-win.h"
75#endif
76
77
78/*********************************************************************************************************************************
79* Defined Constants And Macros *
80*********************************************************************************************************************************/
81/* non-standard linux stuff (it seems). */
82#ifndef MSG_NOSIGNAL
83# define MSG_NOSIGNAL 0
84#endif
85
86/* Windows has different names for SHUT_XXX. */
87#ifndef SHUT_RDWR
88# ifdef SD_BOTH
89# define SHUT_RDWR SD_BOTH
90# else
91# define SHUT_RDWR 2
92# endif
93#endif
94#ifndef SHUT_WR
95# ifdef SD_SEND
96# define SHUT_WR SD_SEND
97# else
98# define SHUT_WR 1
99# endif
100#endif
101#ifndef SHUT_RD
102# ifdef SD_RECEIVE
103# define SHUT_RD SD_RECEIVE
104# else
105# define SHUT_RD 0
106# endif
107#endif
108
109/* fixup backlevel OSes. */
110#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
111# define socklen_t int
112#endif
113
114/** How many pending connection. */
115#define RTTCP_SERVER_BACKLOG 10
116
117/* Limit read and write sizes on Windows and OS/2. */
118#ifdef RT_OS_WINDOWS
119# define RTSOCKET_MAX_WRITE (INT_MAX / 2)
120# define RTSOCKET_MAX_READ (INT_MAX / 2)
121#elif defined(RT_OS_OS2)
122# define RTSOCKET_MAX_WRITE 0x10000
123# define RTSOCKET_MAX_READ 0x10000
124#endif
125
126
127/*********************************************************************************************************************************
128* Structures and Typedefs *
129*********************************************************************************************************************************/
130/**
131 * Socket handle data.
132 *
133 * This is mainly required for implementing RTPollSet on Windows.
134 */
135typedef struct RTSOCKETINT
136{
137 /** Magic number (RTSOCKET_MAGIC). */
138 uint32_t u32Magic;
139 /** Exclusive user count.
140 * This is used to prevent two threads from accessing the handle concurrently.
141 * It can be higher than 1 if this handle is reference multiple times in a
142 * polling set (Windows). */
143 uint32_t volatile cUsers;
144 /** The native socket handle. */
145 RTSOCKETNATIVE hNative;
146 /** Indicates whether the handle has been closed or not. */
147 bool volatile fClosed;
148 /** Indicates whether the socket is operating in blocking or non-blocking mode
149 * currently. */
150 bool fBlocking;
151 /** Whether to leave the native socket open rather than closing it (for
152 * RTHandleGetStandard). */
153 bool fLeaveOpen;
154#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
155 /** The pollset currently polling this socket. This is NIL if no one is
156 * polling. */
157 RTPOLLSET hPollSet;
158#endif
159#ifdef RT_OS_WINDOWS
160 /** The event semaphore we've associated with the socket handle.
161 * This is WSA_INVALID_EVENT if not done. */
162 WSAEVENT hEvent;
163 /** The events we're polling for. */
164 uint32_t fPollEvts;
165 /** The events we're currently subscribing to with WSAEventSelect.
166 * This is ZERO if we're currently not subscribing to anything. */
167 uint32_t fSubscribedEvts;
168 /** Saved events which are only posted once and events harvested for
169 * sockets entered multiple times into to a poll set. Imagine a scenario where
170 * you have a RTPOLL_EVT_READ entry and RTPOLL_EVT_ERROR entry. The READ
171 * condition can be triggered between checking the READ entry and the ERROR
172 * entry, and we don't want to drop the READ, so we store it here and make sure
173 * the event is signalled.
174 *
175 * The RTPOLL_EVT_ERROR is inconsistenly sticky at the momemnt... */
176 uint32_t fEventsSaved;
177 /** Set if fEventsSaved contains harvested events (used to avoid multiple
178 * calls to rtSocketPollCheck on the same socket during rtSocketPollDone). */
179 bool fHarvestedEvents;
180 /** Set if we're using the polling fallback. */
181 bool fPollFallback;
182 /** Set if the fallback polling is active (event not set). */
183 bool volatile fPollFallbackActive;
184 /** Set to shut down the fallback polling thread. */
185 bool volatile fPollFallbackShutdown;
186 /** Socket use to wake up the select thread. */
187 RTSOCKETNATIVE hPollFallbackNotifyW;
188 /** Socket the select thread always waits on. */
189 RTSOCKETNATIVE hPollFallbackNotifyR;
190 /** The fallback polling thread. */
191 RTTHREAD hPollFallbackThread;
192#endif /* RT_OS_WINDOWS */
193} RTSOCKETINT;
194
195
196/**
197 * Address union used internally for things like getpeername and getsockname.
198 */
199typedef union RTSOCKADDRUNION
200{
201 struct sockaddr Addr;
202 struct sockaddr_in IPv4;
203#ifdef IPRT_WITH_TCPIP_V6
204 struct sockaddr_in6 IPv6;
205#endif
206} RTSOCKADDRUNION;
207
208
209/*********************************************************************************************************************************
210* Global Variables *
211*********************************************************************************************************************************/
212#ifdef RT_OS_WINDOWS
213/** Indicates that we've successfully initialized winsock. */
214static uint32_t volatile g_uWinSockInitedVersion = 0;
215#endif
216
217
218/*********************************************************************************************************************************
219* Internal Functions *
220*********************************************************************************************************************************/
221#ifdef RT_OS_WINDOWS
222static void rtSocketPokePollFallbackThread(RTSOCKETINT *pThis);
223#endif
224
225
226
227#ifdef RT_OS_WINDOWS
228/**
229 * Initializes winsock for the process.
230 *
231 * @returns IPRT status code.
232 */
233static int rtSocketInitWinsock(void)
234{
235 if (g_uWinSockInitedVersion != 0)
236 return VINF_SUCCESS;
237
238 if ( !g_pfnWSAGetLastError
239 || !g_pfnWSAStartup
240 || !g_pfnsocket
241 || !g_pfnclosesocket)
242 return VERR_NET_INIT_FAILED;
243
244 /*
245 * Initialize winsock. Try with 2.2 and back down till we get something that works.
246 */
247 static const WORD s_awVersions[] =
248 {
249 MAKEWORD(2, 2),
250 MAKEWORD(2, 1),
251 MAKEWORD(2, 0),
252 MAKEWORD(1, 1),
253 MAKEWORD(1, 0),
254 };
255 for (uint32_t i = 0; i < RT_ELEMENTS(s_awVersions); i++)
256 {
257 WSADATA wsaData;
258 RT_ZERO(wsaData);
259 int rcWsa = g_pfnWSAStartup(s_awVersions[i], &wsaData);
260 if (rcWsa == 0)
261 {
262 /* AssertMsg(wsaData.wVersion >= s_awVersions[i]); - triggers with winsock 1.1 */
263 ASMAtomicWriteU32(&g_uWinSockInitedVersion, wsaData.wVersion);
264 return VINF_SUCCESS;
265 }
266 AssertLogRelMsg(rcWsa == WSAVERNOTSUPPORTED, ("rcWsa=%d (winsock version %#x)\n", rcWsa, s_awVersions[i]));
267 }
268 LogRel(("Failed to init winsock!\n"));
269 return VERR_NET_INIT_FAILED;
270}
271#endif
272
273
274/**
275 * Get the last error as an iprt status code.
276 *
277 * @returns IPRT status code.
278 */
279DECLINLINE(int) rtSocketError(void)
280{
281#ifdef RT_OS_WINDOWS
282 if (g_pfnWSAGetLastError)
283 return RTErrConvertFromWin32(g_pfnWSAGetLastError());
284 return VERR_NET_IO_ERROR;
285#else
286 return RTErrConvertFromErrno(errno);
287#endif
288}
289
290
291/**
292 * Resets the last error.
293 */
294DECLINLINE(void) rtSocketErrorReset(void)
295{
296#ifdef RT_OS_WINDOWS
297 if (g_pfnWSASetLastError)
298 g_pfnWSASetLastError(0);
299#else
300 errno = 0;
301#endif
302}
303
304
305/**
306 * Get the last resolver error as an iprt status code.
307 *
308 * @returns iprt status code.
309 */
310DECLHIDDEN(int) rtSocketResolverError(void)
311{
312#ifdef RT_OS_WINDOWS
313 if (g_pfnWSAGetLastError)
314 return RTErrConvertFromWin32(g_pfnWSAGetLastError());
315 return VERR_UNRESOLVED_ERROR;
316#else
317 switch (h_errno)
318 {
319 case HOST_NOT_FOUND:
320 return VERR_NET_HOST_NOT_FOUND;
321 case NO_DATA:
322 return VERR_NET_ADDRESS_NOT_AVAILABLE;
323 case NO_RECOVERY:
324 return VERR_IO_GEN_FAILURE;
325 case TRY_AGAIN:
326 return VERR_TRY_AGAIN;
327
328 default:
329 AssertLogRelMsgFailed(("Unhandled error %u\n", h_errno));
330 return VERR_UNRESOLVED_ERROR;
331 }
332#endif
333}
334
335
336/**
337 * Converts from a native socket address to a generic IPRT network address.
338 *
339 * @returns IPRT status code.
340 * @param pSrc The source address.
341 * @param cbSrc The size of the source address.
342 * @param pAddr Where to return the generic IPRT network
343 * address.
344 */
345static int rtSocketNetAddrFromAddr(RTSOCKADDRUNION const *pSrc, size_t cbSrc, PRTNETADDR pAddr)
346{
347 /*
348 * Convert the address.
349 */
350 if ( cbSrc == sizeof(struct sockaddr_in)
351 && pSrc->Addr.sa_family == AF_INET)
352 {
353 RT_ZERO(*pAddr);
354 pAddr->enmType = RTNETADDRTYPE_IPV4;
355 pAddr->uPort = RT_N2H_U16(pSrc->IPv4.sin_port);
356 pAddr->uAddr.IPv4.u = pSrc->IPv4.sin_addr.s_addr;
357 }
358#ifdef IPRT_WITH_TCPIP_V6
359 else if ( cbSrc == sizeof(struct sockaddr_in6)
360 && pSrc->Addr.sa_family == AF_INET6)
361 {
362 RT_ZERO(*pAddr);
363 pAddr->enmType = RTNETADDRTYPE_IPV6;
364 pAddr->uPort = RT_N2H_U16(pSrc->IPv6.sin6_port);
365 pAddr->uAddr.IPv6.au32[0] = pSrc->IPv6.sin6_addr.s6_addr32[0];
366 pAddr->uAddr.IPv6.au32[1] = pSrc->IPv6.sin6_addr.s6_addr32[1];
367 pAddr->uAddr.IPv6.au32[2] = pSrc->IPv6.sin6_addr.s6_addr32[2];
368 pAddr->uAddr.IPv6.au32[3] = pSrc->IPv6.sin6_addr.s6_addr32[3];
369 }
370#endif
371 else
372 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
373 return VINF_SUCCESS;
374}
375
376
377/**
378 * Converts from a generic IPRT network address to a native socket address.
379 *
380 * @returns IPRT status code.
381 * @param pAddr Pointer to the generic IPRT network address.
382 * @param pDst The source address.
383 * @param cbDst The size of the source address.
384 * @param pcbAddr Where to store the size of the returned address.
385 * Optional
386 */
387static int rtSocketAddrFromNetAddr(PCRTNETADDR pAddr, RTSOCKADDRUNION *pDst, size_t cbDst, int *pcbAddr)
388{
389 RT_BZERO(pDst, cbDst);
390 if ( pAddr->enmType == RTNETADDRTYPE_IPV4
391 && cbDst >= sizeof(struct sockaddr_in))
392 {
393 pDst->Addr.sa_family = AF_INET;
394 pDst->IPv4.sin_port = RT_H2N_U16(pAddr->uPort);
395 pDst->IPv4.sin_addr.s_addr = pAddr->uAddr.IPv4.u;
396 if (pcbAddr)
397 *pcbAddr = sizeof(pDst->IPv4);
398 }
399#ifdef IPRT_WITH_TCPIP_V6
400 else if ( pAddr->enmType == RTNETADDRTYPE_IPV6
401 && cbDst >= sizeof(struct sockaddr_in6))
402 {
403 pDst->Addr.sa_family = AF_INET6;
404 pDst->IPv6.sin6_port = RT_H2N_U16(pAddr->uPort);
405 pSrc->IPv6.sin6_addr.s6_addr32[0] = pAddr->uAddr.IPv6.au32[0];
406 pSrc->IPv6.sin6_addr.s6_addr32[1] = pAddr->uAddr.IPv6.au32[1];
407 pSrc->IPv6.sin6_addr.s6_addr32[2] = pAddr->uAddr.IPv6.au32[2];
408 pSrc->IPv6.sin6_addr.s6_addr32[3] = pAddr->uAddr.IPv6.au32[3];
409 if (pcbAddr)
410 *pcbAddr = sizeof(pDst->IPv6);
411 }
412#endif
413 else
414 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
415 return VINF_SUCCESS;
416}
417
418
419/**
420 * Tries to lock the socket for exclusive usage by the calling thread.
421 *
422 * Call rtSocketUnlock() to unlock.
423 *
424 * @returns @c true if locked, @c false if not.
425 * @param pThis The socket structure.
426 */
427DECLINLINE(bool) rtSocketTryLock(RTSOCKETINT *pThis)
428{
429 return ASMAtomicCmpXchgU32(&pThis->cUsers, 1, 0);
430}
431
432
433/**
434 * Unlocks the socket.
435 *
436 * @param pThis The socket structure.
437 */
438DECLINLINE(void) rtSocketUnlock(RTSOCKETINT *pThis)
439{
440 ASMAtomicCmpXchgU32(&pThis->cUsers, 0, 1);
441}
442
443
444/**
445 * The slow path of rtSocketSwitchBlockingMode that does the actual switching.
446 *
447 * @returns IPRT status code.
448 * @param pThis The socket structure.
449 * @param fBlocking The desired mode of operation.
450 * @remarks Do not call directly.
451 */
452static int rtSocketSwitchBlockingModeSlow(RTSOCKETINT *pThis, bool fBlocking)
453{
454#ifdef RT_OS_WINDOWS
455 AssertReturn(g_pfnioctlsocket, VERR_NET_NOT_UNSUPPORTED);
456 u_long uBlocking = fBlocking ? 0 : 1;
457 if (g_pfnioctlsocket(pThis->hNative, FIONBIO, &uBlocking))
458 return rtSocketError();
459
460#else
461 int fFlags = fcntl(pThis->hNative, F_GETFL, 0);
462 if (fFlags == -1)
463 return rtSocketError();
464
465 if (fBlocking)
466 fFlags &= ~O_NONBLOCK;
467 else
468 fFlags |= O_NONBLOCK;
469 if (fcntl(pThis->hNative, F_SETFL, fFlags) == -1)
470 return rtSocketError();
471#endif
472
473 pThis->fBlocking = fBlocking;
474 return VINF_SUCCESS;
475}
476
477
478/**
479 * Switches the socket to the desired blocking mode if necessary.
480 *
481 * The socket must be locked.
482 *
483 * @returns IPRT status code.
484 * @param pThis The socket structure.
485 * @param fBlocking The desired mode of operation.
486 */
487DECLINLINE(int) rtSocketSwitchBlockingMode(RTSOCKETINT *pThis, bool fBlocking)
488{
489 if (pThis->fBlocking != fBlocking)
490 return rtSocketSwitchBlockingModeSlow(pThis, fBlocking);
491 return VINF_SUCCESS;
492}
493
494
495/**
496 * Creates an IPRT socket handle for a native one.
497 *
498 * @returns IPRT status code.
499 * @param ppSocket Where to return the IPRT socket handle.
500 * @param hNative The native handle.
501 * @param fLeaveOpen Whether to leave the native socket handle open when
502 * closed.
503 */
504DECLHIDDEN(int) rtSocketCreateForNative(RTSOCKETINT **ppSocket, RTSOCKETNATIVE hNative, bool fLeaveOpen)
505{
506 RTSOCKETINT *pThis = (RTSOCKETINT *)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pThis));
507 if (!pThis)
508 return VERR_NO_MEMORY;
509 pThis->u32Magic = RTSOCKET_MAGIC;
510 pThis->cUsers = 0;
511 pThis->hNative = hNative;
512 pThis->fClosed = false;
513 pThis->fLeaveOpen = fLeaveOpen;
514 pThis->fBlocking = true;
515#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
516 pThis->hPollSet = NIL_RTPOLLSET;
517#endif
518#ifdef RT_OS_WINDOWS
519 pThis->hEvent = WSA_INVALID_EVENT;
520 pThis->fPollEvts = 0;
521 pThis->fSubscribedEvts = 0;
522 pThis->fEventsSaved = 0;
523 pThis->fHarvestedEvents = false;
524 pThis->fPollFallback = g_uWinSockInitedVersion < MAKEWORD(2, 0)
525 || g_pfnWSACreateEvent == NULL
526 || g_pfnWSACloseEvent == NULL
527 || g_pfnWSAEventSelect == NULL
528 || g_pfnWSAEnumNetworkEvents == NULL;
529 pThis->fPollFallbackActive = false;
530 pThis->fPollFallbackShutdown = false;
531 pThis->hPollFallbackNotifyR = NIL_RTSOCKETNATIVE;
532 pThis->hPollFallbackNotifyW = NIL_RTSOCKETNATIVE;
533 pThis->hPollFallbackThread = NIL_RTTHREAD;
534#endif
535 *ppSocket = pThis;
536 return VINF_SUCCESS;
537}
538
539
540RTDECL(int) RTSocketFromNative(PRTSOCKET phSocket, RTHCINTPTR uNative)
541{
542 AssertReturn(uNative != NIL_RTSOCKETNATIVE, VERR_INVALID_PARAMETER);
543#ifndef RT_OS_WINDOWS
544 AssertReturn(uNative >= 0, VERR_INVALID_PARAMETER);
545#endif
546 AssertPtrReturn(phSocket, VERR_INVALID_POINTER);
547 return rtSocketCreateForNative(phSocket, uNative, false /*fLeaveOpen*/);
548}
549
550
551/**
552 * Wrapper around socket().
553 *
554 * @returns IPRT status code.
555 * @param phSocket Where to store the handle to the socket on
556 * success.
557 * @param iDomain The protocol family (PF_XXX).
558 * @param iType The socket type (SOCK_XXX).
559 * @param iProtocol Socket parameter, usually 0.
560 */
561DECLHIDDEN(int) rtSocketCreate(PRTSOCKET phSocket, int iDomain, int iType, int iProtocol)
562{
563#ifdef RT_OS_WINDOWS
564 AssertReturn(g_pfnsocket, VERR_NET_NOT_UNSUPPORTED);
565 AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
566
567 /* Initialize WinSock. */
568 int rc2 = rtSocketInitWinsock();
569 if (RT_FAILURE(rc2))
570 return rc2;
571#endif
572
573 /*
574 * Create the socket.
575 */
576#ifdef RT_OS_WINDOWS
577 RTSOCKETNATIVE hNative = g_pfnsocket(iDomain, iType, iProtocol);
578#else
579 RTSOCKETNATIVE hNative = socket(iDomain, iType, iProtocol);
580#endif
581 if (hNative == NIL_RTSOCKETNATIVE)
582 return rtSocketError();
583
584 /*
585 * Wrap it.
586 */
587 int rc = rtSocketCreateForNative(phSocket, hNative, false /*fLeaveOpen*/);
588 if (RT_FAILURE(rc))
589 {
590#ifdef RT_OS_WINDOWS
591 g_pfnclosesocket(hNative);
592#else
593 close(hNative);
594#endif
595 }
596 return rc;
597}
598
599
600/**
601 * Wrapper around socketpair() for creating a local TCP connection.
602 *
603 * @returns IPRT status code.
604 * @param phServer Where to return the first native socket.
605 * @param phClient Where to return the second native socket.
606 */
607static int rtSocketCreateNativeTcpPair(RTSOCKETNATIVE *phServer, RTSOCKETNATIVE *phClient)
608{
609#ifdef RT_OS_WINDOWS
610 /*
611 * Initialize WinSock and make sure we got the necessary APIs.
612 */
613 int rc = rtSocketInitWinsock();
614 if (RT_FAILURE(rc))
615 return rc;
616 AssertReturn(g_pfnsocket, VERR_NET_NOT_UNSUPPORTED);
617 AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
618 AssertReturn(g_pfnsetsockopt, VERR_NET_NOT_UNSUPPORTED);
619 AssertReturn(g_pfnbind, VERR_NET_NOT_UNSUPPORTED);
620 AssertReturn(g_pfngetsockname, VERR_NET_NOT_UNSUPPORTED);
621 AssertReturn(g_pfnlisten, VERR_NET_NOT_UNSUPPORTED);
622 AssertReturn(g_pfnaccept, VERR_NET_NOT_UNSUPPORTED);
623 AssertReturn(g_pfnconnect, VERR_NET_NOT_UNSUPPORTED);
624
625 /*
626 * Create the "server" listen socket and the "client" socket.
627 */
628 RTSOCKETNATIVE hListener = g_pfnsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
629 if (hListener == NIL_RTSOCKETNATIVE)
630 return rtSocketError();
631 RTSOCKETNATIVE hClient = g_pfnsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
632 if (hClient != NIL_RTSOCKETNATIVE)
633 {
634
635 /*
636 * We let WinSock choose a port number when we bind.
637 */
638 union
639 {
640 struct sockaddr_in Ip;
641 struct sockaddr Generic;
642 } uAddr;
643 RT_ZERO(uAddr);
644 uAddr.Ip.sin_family = AF_INET;
645 uAddr.Ip.sin_addr.s_addr = RT_H2N_U32_C(INADDR_LOOPBACK);
646 //uAddr.Ip.sin_port = 0;
647 int fReuse = 1;
648 rc = g_pfnsetsockopt(hListener, SOL_SOCKET, SO_REUSEADDR, (const char *)&fReuse, sizeof(fReuse));
649 if (rc == 0)
650 {
651 rc = g_pfnbind(hListener, &uAddr.Generic, sizeof(uAddr.Ip));
652 if (rc == 0)
653 {
654 /*
655 * Get the address the client should connect to. According to the docs,
656 * we cannot assume that getsockname sets the IP and family.
657 */
658 RT_ZERO(uAddr);
659 int cbAddr = sizeof(uAddr.Ip);
660 rc = g_pfngetsockname(hListener, &uAddr.Generic, &cbAddr);
661 if (rc == 0)
662 {
663 uAddr.Ip.sin_family = AF_INET;
664 uAddr.Ip.sin_addr.s_addr = RT_H2N_U32_C(INADDR_LOOPBACK);
665
666 /*
667 * Listen, connect and accept.
668 */
669 rc = g_pfnlisten(hListener, 1 /*cBacklog*/);
670 if (rc == 0)
671 {
672 rc = g_pfnconnect(hClient, &uAddr.Generic, sizeof(uAddr.Ip));
673 if (rc == 0)
674 {
675 RTSOCKETNATIVE hServer = g_pfnaccept(hListener, NULL, NULL);
676 if (hServer != NIL_RTSOCKETNATIVE)
677 {
678 g_pfnclosesocket(hListener);
679
680 /*
681 * Done!
682 */
683 *phServer = hServer;
684 *phClient = hClient;
685 return VINF_SUCCESS;
686 }
687 }
688 }
689 }
690 }
691 }
692 rc = rtSocketError();
693 g_pfnclosesocket(hClient);
694 }
695 else
696 rc = rtSocketError();
697 g_pfnclosesocket(hListener);
698 return rc;
699
700#else
701 /*
702 * Got socket pair, so use it.
703 * Note! This isn't TCP per se, but it should fool the users.
704 */
705 int aSockets[2] = { -1, -1 };
706 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, aSockets) == 0)
707 {
708 *phServer = aSockets[0];
709 *phClient = aSockets[1];
710 return VINF_SUCCESS;
711 }
712 return rtSocketError();
713#endif
714}
715
716
717/**
718 * Worker for RTTcpCreatePair.
719 *
720 * @returns IPRT status code.
721 * @param phServer Where to return the "server" side of the pair.
722 * @param phClient Where to return the "client" side of the pair.
723 * @note There is no server or client side, but we gotta call it something.
724 */
725DECLHIDDEN(int) rtSocketCreateTcpPair(RTSOCKET *phServer, RTSOCKET *phClient)
726{
727 RTSOCKETNATIVE hServer = NIL_RTSOCKETNATIVE;
728 RTSOCKETNATIVE hClient = NIL_RTSOCKETNATIVE;
729 int rc = rtSocketCreateNativeTcpPair(&hServer, &hClient);
730 if (RT_SUCCESS(rc))
731 {
732 rc = rtSocketCreateForNative(phServer, hServer, false /*fLeaveOpen*/);
733 if (RT_SUCCESS(rc))
734 {
735 rc = rtSocketCreateForNative(phClient, hClient, false /*fLeaveOpen*/);
736 if (RT_SUCCESS(rc))
737 return VINF_SUCCESS;
738 RTSocketRelease(*phServer);
739 }
740 else
741 {
742#ifdef RT_OS_WINDOWS
743 g_pfnclosesocket(hServer);
744#else
745 close(hServer);
746#endif
747 }
748#ifdef RT_OS_WINDOWS
749 g_pfnclosesocket(hClient);
750#else
751 close(hClient);
752#endif
753 }
754
755 *phServer = NIL_RTSOCKET;
756 *phClient = NIL_RTSOCKET;
757 return rc;
758}
759
760
761RTDECL(uint32_t) RTSocketRetain(RTSOCKET hSocket)
762{
763 RTSOCKETINT *pThis = hSocket;
764 AssertPtrReturn(pThis, UINT32_MAX);
765 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
766 return RTMemPoolRetain(pThis);
767}
768
769
770/**
771 * Worker for RTSocketRelease and RTSocketClose.
772 *
773 * @returns IPRT status code.
774 * @param pThis The socket handle instance data.
775 * @param fDestroy Whether we're reaching ref count zero.
776 */
777static int rtSocketCloseIt(RTSOCKETINT *pThis, bool fDestroy)
778{
779 /*
780 * Invalidate the handle structure on destroy.
781 */
782 if (fDestroy)
783 {
784 Assert(ASMAtomicReadU32(&pThis->u32Magic) == RTSOCKET_MAGIC);
785 ASMAtomicWriteU32(&pThis->u32Magic, RTSOCKET_MAGIC_DEAD);
786 }
787
788 int rc = VINF_SUCCESS;
789 if (ASMAtomicCmpXchgBool(&pThis->fClosed, true, false))
790 {
791#ifdef RT_OS_WINDOWS
792 /*
793 * Poke the polling thread if active and give it a small chance to stop.
794 */
795 if ( pThis->fPollFallback
796 && pThis->hPollFallbackThread != NIL_RTTHREAD)
797 {
798 ASMAtomicWriteBool(&pThis->fPollFallbackShutdown, true);
799 rtSocketPokePollFallbackThread(pThis);
800 int rc2 = RTThreadWait(pThis->hPollFallbackThread, RT_MS_1SEC, NULL);
801 if (RT_SUCCESS(rc2))
802 pThis->hPollFallbackThread = NIL_RTTHREAD;
803 }
804#endif
805
806 /*
807 * Close the native handle.
808 */
809 RTSOCKETNATIVE hNative = pThis->hNative;
810 if (hNative != NIL_RTSOCKETNATIVE)
811 {
812 pThis->hNative = NIL_RTSOCKETNATIVE;
813
814 if (!pThis->fLeaveOpen)
815 {
816#ifdef RT_OS_WINDOWS
817 AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
818 if (g_pfnclosesocket(hNative))
819#else
820 if (close(hNative))
821#endif
822 {
823 rc = rtSocketError();
824#ifdef RT_OS_WINDOWS
825 AssertMsgFailed(("closesocket(%p) -> %Rrc\n", (uintptr_t)hNative, rc));
826#else
827 AssertMsgFailed(("close(%d) -> %Rrc\n", hNative, rc));
828#endif
829 }
830 }
831 }
832
833#ifdef RT_OS_WINDOWS
834 /*
835 * Windows specific polling cleanup.
836 */
837 WSAEVENT hEvent = pThis->hEvent;
838 if (hEvent != WSA_INVALID_EVENT)
839 {
840 pThis->hEvent = WSA_INVALID_EVENT;
841 if (!pThis->fPollFallback)
842 {
843 Assert(g_pfnWSACloseEvent);
844 if (g_pfnWSACloseEvent)
845 g_pfnWSACloseEvent(hEvent);
846 }
847 else
848 CloseHandle(hEvent);
849 }
850
851 if (pThis->fPollFallback)
852 {
853 if (pThis->hPollFallbackNotifyW != NIL_RTSOCKETNATIVE)
854 {
855 g_pfnclosesocket(pThis->hPollFallbackNotifyW);
856 pThis->hPollFallbackNotifyW = NIL_RTSOCKETNATIVE;
857 }
858
859 if (pThis->hPollFallbackThread != NIL_RTTHREAD)
860 {
861 int rc2 = RTThreadWait(pThis->hPollFallbackThread, RT_MS_1MIN / 2, NULL);
862 AssertRC(rc2);
863 pThis->hPollFallbackThread = NIL_RTTHREAD;
864 }
865
866 if (pThis->hPollFallbackNotifyR != NIL_RTSOCKETNATIVE)
867 {
868 g_pfnclosesocket(pThis->hPollFallbackNotifyR);
869 pThis->hPollFallbackNotifyR = NIL_RTSOCKETNATIVE;
870 }
871 }
872#endif
873 }
874
875 return rc;
876}
877
878
879RTDECL(uint32_t) RTSocketRelease(RTSOCKET hSocket)
880{
881 RTSOCKETINT *pThis = hSocket;
882 if (pThis == NIL_RTSOCKET)
883 return 0;
884 AssertPtrReturn(pThis, UINT32_MAX);
885 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
886
887 /* get the refcount without killing it... */
888 uint32_t cRefs = RTMemPoolRefCount(pThis);
889 AssertReturn(cRefs != UINT32_MAX, UINT32_MAX);
890 if (cRefs == 1)
891 rtSocketCloseIt(pThis, true);
892
893 return RTMemPoolRelease(RTMEMPOOL_DEFAULT, pThis);
894}
895
896
897RTDECL(int) RTSocketClose(RTSOCKET hSocket)
898{
899 RTSOCKETINT *pThis = hSocket;
900 if (pThis == NIL_RTSOCKET)
901 return VINF_SUCCESS;
902 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
903 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
904
905 uint32_t cRefs = RTMemPoolRefCount(pThis);
906 AssertReturn(cRefs != UINT32_MAX, UINT32_MAX);
907
908 int rc = rtSocketCloseIt(pThis, cRefs == 1);
909
910 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pThis);
911 return rc;
912}
913
914
915RTDECL(RTHCUINTPTR) RTSocketToNative(RTSOCKET hSocket)
916{
917 RTSOCKETINT *pThis = hSocket;
918 AssertPtrReturn(pThis, RTHCUINTPTR_MAX);
919 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, RTHCUINTPTR_MAX);
920 return (RTHCUINTPTR)pThis->hNative;
921}
922
923
924RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable)
925{
926 RTSOCKETINT *pThis = hSocket;
927 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
928 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
929 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
930
931 int rc = VINF_SUCCESS;
932#ifdef RT_OS_WINDOWS
933 if (!SetHandleInformation((HANDLE)pThis->hNative, HANDLE_FLAG_INHERIT, fInheritable ? HANDLE_FLAG_INHERIT : 0))
934 rc = RTErrConvertFromWin32(GetLastError());
935#else
936 if (fcntl(pThis->hNative, F_SETFD, fInheritable ? 0 : FD_CLOEXEC) < 0)
937 rc = RTErrConvertFromErrno(errno);
938#endif
939
940 return rc;
941}
942
943
944static bool rtSocketIsIPv4Numerical(const char *pszAddress, PRTNETADDRIPV4 pAddr)
945{
946
947 /* Empty address resolves to the INADDR_ANY address (good for bind). */
948 if (!pszAddress || !*pszAddress)
949 {
950 pAddr->u = INADDR_ANY;
951 return true;
952 }
953
954 /* Four quads? */
955 char *psz = (char *)pszAddress;
956 for (int i = 0; i < 4; i++)
957 {
958 uint8_t u8;
959 int rc = RTStrToUInt8Ex(psz, &psz, 0, &u8);
960 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
961 return false;
962 if (*psz != (i < 3 ? '.' : '\0'))
963 return false;
964 psz++;
965
966 pAddr->au8[i] = u8; /* big endian */
967 }
968
969 return true;
970}
971
972RTDECL(int) RTSocketParseInetAddress(const char *pszAddress, unsigned uPort, PRTNETADDR pAddr)
973{
974 int rc;
975
976 /*
977 * Validate input.
978 */
979 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
980 AssertPtrNullReturn(pszAddress, VERR_INVALID_POINTER);
981
982 /*
983 * Resolve the address. Pretty crude at the moment, but we have to make
984 * sure to not ask the NT 4 gethostbyname about an IPv4 address as it may
985 * give a wrong answer.
986 */
987 /** @todo this only supports IPv4, and IPv6 support needs to be added.
988 * It probably needs to be converted to getaddrinfo(). */
989 RTNETADDRIPV4 IPv4Quad;
990 if (rtSocketIsIPv4Numerical(pszAddress, &IPv4Quad))
991 {
992 Log3(("rtSocketIsIPv4Numerical: %s -> %#x (%RTnaipv4)\n", pszAddress, IPv4Quad.u, IPv4Quad));
993 RT_ZERO(*pAddr);
994 pAddr->enmType = RTNETADDRTYPE_IPV4;
995 pAddr->uPort = uPort;
996 pAddr->uAddr.IPv4 = IPv4Quad;
997 return VINF_SUCCESS;
998 }
999
1000#ifdef RT_OS_WINDOWS
1001 /* Initialize WinSock and check version before we call gethostbyname. */
1002 if (!g_pfngethostbyname)
1003 return VERR_NET_NOT_UNSUPPORTED;
1004
1005 int rc2 = rtSocketInitWinsock();
1006 if (RT_FAILURE(rc2))
1007 return rc2;
1008
1009# define gethostbyname g_pfngethostbyname
1010#endif
1011
1012 struct hostent *pHostEnt;
1013 pHostEnt = gethostbyname(pszAddress);
1014 if (!pHostEnt)
1015 {
1016 rc = rtSocketResolverError();
1017 AssertMsgFailed(("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
1018 return rc;
1019 }
1020
1021 if (pHostEnt->h_addrtype == AF_INET)
1022 {
1023 RT_ZERO(*pAddr);
1024 pAddr->enmType = RTNETADDRTYPE_IPV4;
1025 pAddr->uPort = uPort;
1026 pAddr->uAddr.IPv4.u = ((struct in_addr *)pHostEnt->h_addr)->s_addr;
1027 Log3(("gethostbyname: %s -> %#x (%RTnaipv4)\n", pszAddress, pAddr->uAddr.IPv4.u, pAddr->uAddr.IPv4));
1028 }
1029 else
1030 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
1031
1032#ifdef RT_OS_WINDOWS
1033# undef gethostbyname
1034#endif
1035 return VINF_SUCCESS;
1036}
1037
1038
1039/*
1040 * New function to allow both ipv4 and ipv6 addresses to be resolved.
1041 * Breaks compatibility with windows before 2000.
1042 */
1043RTDECL(int) RTSocketQueryAddressStr(const char *pszHost, char *pszResult, size_t *pcbResult, PRTNETADDRTYPE penmAddrType)
1044{
1045 AssertPtrReturn(pszHost, VERR_INVALID_POINTER);
1046 AssertPtrReturn(pcbResult, VERR_INVALID_POINTER);
1047 AssertPtrNullReturn(penmAddrType, VERR_INVALID_POINTER);
1048 AssertPtrNullReturn(pszResult, VERR_INVALID_POINTER);
1049
1050#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) /** @todo dynamically resolve the APIs not present in NT4! */
1051 return VERR_NOT_SUPPORTED;
1052
1053#else
1054 int rc;
1055 if (*pcbResult < 16)
1056 return VERR_NET_ADDRESS_NOT_AVAILABLE;
1057
1058 /* Setup the hint. */
1059 struct addrinfo grHints;
1060 RT_ZERO(grHints);
1061 grHints.ai_socktype = 0;
1062 grHints.ai_flags = 0;
1063 grHints.ai_protocol = 0;
1064 grHints.ai_family = AF_UNSPEC;
1065 if (penmAddrType)
1066 {
1067 switch (*penmAddrType)
1068 {
1069 case RTNETADDRTYPE_INVALID:
1070 /*grHints.ai_family = AF_UNSPEC;*/
1071 break;
1072 case RTNETADDRTYPE_IPV4:
1073 grHints.ai_family = AF_INET;
1074 break;
1075 case RTNETADDRTYPE_IPV6:
1076 grHints.ai_family = AF_INET6;
1077 break;
1078 default:
1079 AssertFailedReturn(VERR_INVALID_PARAMETER);
1080 }
1081 }
1082
1083# ifdef RT_OS_WINDOWS
1084 /*
1085 * Winsock2 init
1086 */
1087 if ( !g_pfngetaddrinfo
1088 || !g_pfnfreeaddrinfo)
1089 return VERR_NET_NOT_UNSUPPORTED;
1090
1091 int rc2 = rtSocketInitWinsock();
1092 if (RT_FAILURE(rc2))
1093 return rc2;
1094
1095# define getaddrinfo g_pfngetaddrinfo
1096# define freeaddrinfo g_pfnfreeaddrinfo
1097# endif
1098
1099 /** @todo r=bird: getaddrinfo and freeaddrinfo breaks the additions on NT4. */
1100 struct addrinfo *pgrResults = NULL;
1101 rc = getaddrinfo(pszHost, "", &grHints, &pgrResults);
1102 if (rc != 0)
1103 return VERR_NET_ADDRESS_NOT_AVAILABLE;
1104
1105 // return data
1106 // on multiple matches return only the first one
1107
1108 if (!pgrResults)
1109 return VERR_NET_ADDRESS_NOT_AVAILABLE;
1110
1111 struct addrinfo const *pgrResult = pgrResults->ai_next;
1112 if (!pgrResult)
1113 {
1114 freeaddrinfo(pgrResults);
1115 return VERR_NET_ADDRESS_NOT_AVAILABLE;
1116 }
1117
1118 RTNETADDRTYPE enmAddrType = RTNETADDRTYPE_INVALID;
1119 size_t cchIpAddress;
1120 char szIpAddress[48];
1121 if (pgrResult->ai_family == AF_INET)
1122 {
1123 struct sockaddr_in const *pgrSa = (struct sockaddr_in const *)pgrResult->ai_addr;
1124 cchIpAddress = RTStrPrintf(szIpAddress, sizeof(szIpAddress),
1125 "%RTnaipv4", pgrSa->sin_addr.s_addr);
1126 Assert(cchIpAddress >= 7 && cchIpAddress < sizeof(szIpAddress) - 1);
1127 enmAddrType = RTNETADDRTYPE_IPV4;
1128 rc = VINF_SUCCESS;
1129 }
1130 else if (pgrResult->ai_family == AF_INET6)
1131 {
1132 struct sockaddr_in6 const *pgrSa6 = (struct sockaddr_in6 const *)pgrResult->ai_addr;
1133 cchIpAddress = RTStrPrintf(szIpAddress, sizeof(szIpAddress),
1134 "%RTnaipv6", (PRTNETADDRIPV6)&pgrSa6->sin6_addr);
1135 enmAddrType = RTNETADDRTYPE_IPV6;
1136 rc = VINF_SUCCESS;
1137 }
1138 else
1139 {
1140 rc = VERR_NET_ADDRESS_NOT_AVAILABLE;
1141 szIpAddress[0] = '\0';
1142 cchIpAddress = 0;
1143 }
1144 freeaddrinfo(pgrResults);
1145
1146 /*
1147 * Copy out the result.
1148 */
1149 size_t const cbResult = *pcbResult;
1150 *pcbResult = cchIpAddress + 1;
1151 if (cchIpAddress < cbResult)
1152 memcpy(pszResult, szIpAddress, cchIpAddress + 1);
1153 else
1154 {
1155 RT_BZERO(pszResult, cbResult);
1156 if (RT_SUCCESS(rc))
1157 rc = VERR_BUFFER_OVERFLOW;
1158 }
1159 if (penmAddrType && RT_SUCCESS(rc))
1160 *penmAddrType = enmAddrType;
1161 return rc;
1162
1163# ifdef RT_OS_WINDOWS
1164# undef getaddrinfo
1165# undef freeaddrinfo
1166# endif
1167#endif /* !RT_OS_OS2 */
1168}
1169
1170
1171RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
1172{
1173 /*
1174 * Validate input.
1175 */
1176 RTSOCKETINT *pThis = hSocket;
1177 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1178 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1179 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
1180 AssertPtr(pvBuffer);
1181#ifdef RT_OS_WINDOWS
1182 AssertReturn(g_pfnrecv, VERR_NET_NOT_UNSUPPORTED);
1183# define recv g_pfnrecv
1184#endif
1185 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1186
1187 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
1188 if (RT_FAILURE(rc))
1189 return rc;
1190
1191 /*
1192 * Read loop.
1193 * If pcbRead is NULL we have to fill the entire buffer!
1194 */
1195 size_t cbRead = 0;
1196 size_t cbToRead = cbBuffer;
1197 for (;;)
1198 {
1199 rtSocketErrorReset();
1200#ifdef RTSOCKET_MAX_READ
1201 int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead;
1202#else
1203 size_t cbNow = cbToRead;
1204#endif
1205 ssize_t cbBytesRead = recv(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL);
1206 if (cbBytesRead <= 0)
1207 {
1208 rc = rtSocketError();
1209 Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
1210 if (RT_SUCCESS_NP(rc))
1211 {
1212 if (!pcbRead)
1213 rc = VERR_NET_SHUTDOWN;
1214 else
1215 {
1216 *pcbRead = 0;
1217 rc = VINF_SUCCESS;
1218 }
1219 }
1220 break;
1221 }
1222 if (pcbRead)
1223 {
1224 /* return partial data */
1225 *pcbRead = cbBytesRead;
1226 break;
1227 }
1228
1229 /* read more? */
1230 cbRead += cbBytesRead;
1231 if (cbRead == cbBuffer)
1232 break;
1233
1234 /* next */
1235 cbToRead = cbBuffer - cbRead;
1236 }
1237
1238 rtSocketUnlock(pThis);
1239#ifdef RT_OS_WINDOWS
1240# undef recv
1241#endif
1242 return rc;
1243}
1244
1245
1246RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr)
1247{
1248 /*
1249 * Validate input.
1250 */
1251 RTSOCKETINT *pThis = hSocket;
1252 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1253 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1254 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
1255 AssertPtr(pvBuffer);
1256 AssertPtr(pcbRead);
1257#ifdef RT_OS_WINDOWS
1258 AssertReturn(g_pfnrecvfrom, VERR_NET_NOT_UNSUPPORTED);
1259# define recvfrom g_pfnrecvfrom
1260#endif
1261 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1262
1263 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
1264 if (RT_FAILURE(rc))
1265 return rc;
1266
1267 /*
1268 * Read data.
1269 */
1270 size_t cbRead = 0;
1271 size_t cbToRead = cbBuffer;
1272 rtSocketErrorReset();
1273 RTSOCKADDRUNION u;
1274#ifdef RTSOCKET_MAX_READ
1275 int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead;
1276 int cbAddr = sizeof(u);
1277#else
1278 size_t cbNow = cbToRead;
1279 socklen_t cbAddr = sizeof(u);
1280#endif
1281 ssize_t cbBytesRead = recvfrom(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL, &u.Addr, &cbAddr);
1282 if (cbBytesRead <= 0)
1283 {
1284 rc = rtSocketError();
1285 Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
1286 if (RT_SUCCESS_NP(rc))
1287 {
1288 *pcbRead = 0;
1289 rc = VINF_SUCCESS;
1290 }
1291 }
1292 else
1293 {
1294 if (pSrcAddr)
1295 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pSrcAddr);
1296 *pcbRead = cbBytesRead;
1297 }
1298
1299 rtSocketUnlock(pThis);
1300#ifdef RT_OS_WINDOWS
1301# undef recvfrom
1302#endif
1303 return rc;
1304}
1305
1306
1307RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer)
1308{
1309 /*
1310 * Validate input.
1311 */
1312 RTSOCKETINT *pThis = hSocket;
1313 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1314 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1315#ifdef RT_OS_WINDOWS
1316 AssertReturn(g_pfnsend, VERR_NET_NOT_UNSUPPORTED);
1317# define send g_pfnsend
1318#endif
1319 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1320
1321 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
1322 if (RT_FAILURE(rc))
1323 return rc;
1324
1325 /*
1326 * Try write all at once.
1327 */
1328#ifdef RTSOCKET_MAX_WRITE
1329 int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
1330#else
1331 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
1332#endif
1333 ssize_t cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1334 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
1335 rc = VINF_SUCCESS;
1336 else if (cbWritten < 0)
1337 rc = rtSocketError();
1338 else
1339 {
1340 /*
1341 * Unfinished business, write the remainder of the request. Must ignore
1342 * VERR_INTERRUPTED here if we've managed to send something.
1343 */
1344 size_t cbSentSoFar = 0;
1345 for (;;)
1346 {
1347 /* advance */
1348 cbBuffer -= (size_t)cbWritten;
1349 if (!cbBuffer)
1350 break;
1351 cbSentSoFar += (size_t)cbWritten;
1352 pvBuffer = (char const *)pvBuffer + cbWritten;
1353
1354 /* send */
1355#ifdef RTSOCKET_MAX_WRITE
1356 cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
1357#else
1358 cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
1359#endif
1360 cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1361 if (cbWritten >= 0)
1362 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%zu cbBuffer=%zu rtSocketError()=%d\n",
1363 cbWritten, cbBuffer, rtSocketError()));
1364 else
1365 {
1366 rc = rtSocketError();
1367 if (rc != VERR_INTERNAL_ERROR || cbSentSoFar == 0)
1368 break;
1369 cbWritten = 0;
1370 rc = VINF_SUCCESS;
1371 }
1372 }
1373 }
1374
1375 rtSocketUnlock(pThis);
1376#ifdef RT_OS_WINDOWS
1377# undef send
1378#endif
1379 return rc;
1380}
1381
1382
1383RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pAddr)
1384{
1385 /*
1386 * Validate input.
1387 */
1388 RTSOCKETINT *pThis = hSocket;
1389 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1390 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1391#ifdef RT_OS_WINDOWS
1392 AssertReturn(g_pfnsendto, VERR_NET_NOT_UNSUPPORTED);
1393# define sendto g_pfnsendto
1394#endif
1395
1396 /* no locking since UDP reads may be done concurrently to writes, and
1397 * this is the normal use case of this code. */
1398
1399 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
1400 if (RT_FAILURE(rc))
1401 return rc;
1402
1403 /* Figure out destination address. */
1404 struct sockaddr *pSA = NULL;
1405#ifdef RT_OS_WINDOWS
1406 int cbSA = 0;
1407#else
1408 socklen_t cbSA = 0;
1409#endif
1410 RTSOCKADDRUNION u;
1411 if (pAddr)
1412 {
1413 rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), NULL);
1414 if (RT_FAILURE(rc))
1415 return rc;
1416 pSA = &u.Addr;
1417 cbSA = sizeof(u);
1418 }
1419
1420 /*
1421 * Must write all at once, otherwise it is a failure.
1422 */
1423#ifdef RT_OS_WINDOWS
1424 int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
1425#else
1426 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
1427#endif
1428 ssize_t cbWritten = sendto(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL, pSA, cbSA);
1429 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
1430 rc = VINF_SUCCESS;
1431 else if (cbWritten < 0)
1432 rc = rtSocketError();
1433 else
1434 rc = VERR_TOO_MUCH_DATA;
1435
1436 /// @todo rtSocketUnlock(pThis);
1437#ifdef RT_OS_WINDOWS
1438# undef sendto
1439#endif
1440 return rc;
1441}
1442
1443
1444RTDECL(int) RTSocketWriteToNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pAddr)
1445{
1446 /*
1447 * Validate input.
1448 */
1449 RTSOCKETINT *pThis = hSocket;
1450 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1451 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1452#ifdef RT_OS_WINDOWS
1453 AssertReturn(g_pfnsendto, VERR_NET_NOT_UNSUPPORTED);
1454# define sendto g_pfnsendto
1455#endif
1456
1457 /* no locking since UDP reads may be done concurrently to writes, and
1458 * this is the normal use case of this code. */
1459
1460 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1461 if (RT_FAILURE(rc))
1462 return rc;
1463
1464 /* Figure out destination address. */
1465 struct sockaddr *pSA = NULL;
1466#ifdef RT_OS_WINDOWS
1467 int cbSA = 0;
1468#else
1469 socklen_t cbSA = 0;
1470#endif
1471 RTSOCKADDRUNION u;
1472 if (pAddr)
1473 {
1474 rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), NULL);
1475 if (RT_FAILURE(rc))
1476 return rc;
1477 pSA = &u.Addr;
1478 cbSA = sizeof(u);
1479 }
1480
1481 /*
1482 * Must write all at once, otherwise it is a failure.
1483 */
1484#ifdef RT_OS_WINDOWS
1485 int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
1486#else
1487 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
1488#endif
1489 ssize_t cbWritten = sendto(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL, pSA, cbSA);
1490 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
1491 rc = VINF_SUCCESS;
1492 else if (cbWritten < 0)
1493 rc = rtSocketError();
1494 else
1495 rc = VERR_TOO_MUCH_DATA;
1496
1497 /// @todo rtSocketUnlock(pThis);
1498#ifdef RT_OS_WINDOWS
1499# undef sendto
1500#endif
1501 return rc;
1502}
1503
1504
1505RTDECL(int) RTSocketSgWrite(RTSOCKET hSocket, PCRTSGBUF pSgBuf)
1506{
1507 /*
1508 * Validate input.
1509 */
1510 RTSOCKETINT *pThis = hSocket;
1511 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1512 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1513 AssertPtrReturn(pSgBuf, VERR_INVALID_PARAMETER);
1514 AssertReturn(pSgBuf->cSegs > 0, VERR_INVALID_PARAMETER);
1515 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1516
1517 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
1518 if (RT_FAILURE(rc))
1519 return rc;
1520
1521 /*
1522 * Construct message descriptor (translate pSgBuf) and send it.
1523 */
1524 rc = VERR_NO_TMP_MEMORY;
1525#ifdef RT_OS_WINDOWS
1526 if (g_pfnWSASend)
1527 {
1528 AssertCompileSize(WSABUF, sizeof(RTSGSEG));
1529 AssertCompileMemberSize(WSABUF, buf, RT_SIZEOFMEMB(RTSGSEG, pvSeg));
1530
1531 LPWSABUF paMsg = (LPWSABUF)RTMemTmpAllocZ(pSgBuf->cSegs * sizeof(WSABUF));
1532 if (paMsg)
1533 {
1534 for (unsigned i = 0; i < pSgBuf->cSegs; i++)
1535 {
1536 paMsg[i].buf = (char *)pSgBuf->paSegs[i].pvSeg;
1537 paMsg[i].len = (u_long)pSgBuf->paSegs[i].cbSeg;
1538 }
1539
1540 DWORD dwSent;
1541 int hrc = g_pfnWSASend(pThis->hNative, paMsg, pSgBuf->cSegs, &dwSent, MSG_NOSIGNAL, NULL, NULL);
1542 if (!hrc)
1543 rc = VINF_SUCCESS;
1544 /** @todo check for incomplete writes */
1545 else
1546 rc = rtSocketError();
1547
1548 RTMemTmpFree(paMsg);
1549 }
1550 }
1551 else if (g_pfnsend)
1552 {
1553 rc = VINF_SUCCESS;
1554 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
1555 {
1556 uint8_t const *pbSeg = (uint8_t const *)pSgBuf->paSegs[iSeg].pvSeg;
1557 size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
1558 int cbNow;
1559 ssize_t cbWritten;
1560 for (;;)
1561 {
1562 cbNow = cbSeg >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbSeg;
1563 cbWritten = g_pfnsend(pThis->hNative, (const char *)pbSeg, cbNow, MSG_NOSIGNAL);
1564 if ((size_t)cbWritten >= cbSeg || cbWritten < 0)
1565 break;
1566 pbSeg += cbWritten;
1567 cbSeg -= cbWritten;
1568 }
1569 if (cbWritten < 0)
1570 {
1571 rc = rtSocketError();
1572 break;
1573 }
1574 }
1575 }
1576 else
1577 rc = VERR_NET_NOT_UNSUPPORTED;
1578
1579#else /* !RT_OS_WINDOWS */
1580 AssertCompileSize(struct iovec, sizeof(RTSGSEG));
1581 AssertCompileMemberSize(struct iovec, iov_base, RT_SIZEOFMEMB(RTSGSEG, pvSeg));
1582 AssertCompileMemberSize(struct iovec, iov_len, RT_SIZEOFMEMB(RTSGSEG, cbSeg));
1583
1584 struct iovec *paMsg = (struct iovec *)RTMemTmpAllocZ(pSgBuf->cSegs * sizeof(struct iovec));
1585 if (paMsg)
1586 {
1587 for (unsigned i = 0; i < pSgBuf->cSegs; i++)
1588 {
1589 paMsg[i].iov_base = pSgBuf->paSegs[i].pvSeg;
1590 paMsg[i].iov_len = pSgBuf->paSegs[i].cbSeg;
1591 }
1592
1593 struct msghdr msgHdr;
1594 RT_ZERO(msgHdr);
1595 msgHdr.msg_iov = paMsg;
1596 msgHdr.msg_iovlen = pSgBuf->cSegs;
1597 ssize_t cbWritten = sendmsg(pThis->hNative, &msgHdr, MSG_NOSIGNAL);
1598 if (RT_LIKELY(cbWritten >= 0))
1599 rc = VINF_SUCCESS;
1600/** @todo check for incomplete writes */
1601 else
1602 rc = rtSocketError();
1603
1604 RTMemTmpFree(paMsg);
1605 }
1606#endif /* !RT_OS_WINDOWS */
1607
1608 rtSocketUnlock(pThis);
1609 return rc;
1610}
1611
1612
1613RTDECL(int) RTSocketSgWriteL(RTSOCKET hSocket, size_t cSegs, ...)
1614{
1615 va_list va;
1616 va_start(va, cSegs);
1617 int rc = RTSocketSgWriteLV(hSocket, cSegs, va);
1618 va_end(va);
1619 return rc;
1620}
1621
1622
1623RTDECL(int) RTSocketSgWriteLV(RTSOCKET hSocket, size_t cSegs, va_list va)
1624{
1625 /*
1626 * Set up a S/G segment array + buffer on the stack and pass it
1627 * on to RTSocketSgWrite.
1628 */
1629 Assert(cSegs <= 16);
1630 PRTSGSEG paSegs = (PRTSGSEG)alloca(cSegs * sizeof(RTSGSEG));
1631 AssertReturn(paSegs, VERR_NO_TMP_MEMORY);
1632 for (size_t i = 0; i < cSegs; i++)
1633 {
1634 paSegs[i].pvSeg = va_arg(va, void *);
1635 paSegs[i].cbSeg = va_arg(va, size_t);
1636 }
1637
1638 RTSGBUF SgBuf;
1639 RTSgBufInit(&SgBuf, paSegs, cSegs);
1640 return RTSocketSgWrite(hSocket, &SgBuf);
1641}
1642
1643
1644RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
1645{
1646 /*
1647 * Validate input.
1648 */
1649 RTSOCKETINT *pThis = hSocket;
1650 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1651 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1652 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
1653 AssertPtr(pvBuffer);
1654 AssertPtrReturn(pcbRead, VERR_INVALID_PARAMETER);
1655#ifdef RT_OS_WINDOWS
1656 AssertReturn(g_pfnrecv, VERR_NET_NOT_UNSUPPORTED);
1657#endif
1658 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1659
1660 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1661 if (RT_FAILURE(rc))
1662 return rc;
1663
1664 rtSocketErrorReset();
1665#ifdef RTSOCKET_MAX_READ
1666 int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
1667#else
1668 size_t cbNow = cbBuffer;
1669#endif
1670
1671#ifdef RT_OS_WINDOWS
1672 int cbRead = g_pfnrecv(pThis->hNative, (char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1673 if (cbRead >= 0)
1674 {
1675 *pcbRead = cbRead;
1676 rc = VINF_SUCCESS;
1677 }
1678 else
1679 {
1680 rc = rtSocketError();
1681 if (rc == VERR_TRY_AGAIN)
1682 {
1683 *pcbRead = 0;
1684 rc = VINF_TRY_AGAIN;
1685 }
1686 }
1687
1688#else
1689 ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbNow, MSG_NOSIGNAL);
1690 if (cbRead >= 0)
1691 *pcbRead = cbRead;
1692 else if ( errno == EAGAIN
1693# ifdef EWOULDBLOCK
1694# if EWOULDBLOCK != EAGAIN
1695 || errno == EWOULDBLOCK
1696# endif
1697# endif
1698 )
1699 {
1700 *pcbRead = 0;
1701 rc = VINF_TRY_AGAIN;
1702 }
1703 else
1704 rc = rtSocketError();
1705#endif
1706
1707 rtSocketUnlock(pThis);
1708 return rc;
1709}
1710
1711
1712RTDECL(int) RTSocketWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten)
1713{
1714 /*
1715 * Validate input.
1716 */
1717 RTSOCKETINT *pThis = hSocket;
1718 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1719 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1720 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER);
1721#ifdef RT_OS_WINDOWS
1722 AssertReturn(g_pfnsend, VERR_NET_NOT_UNSUPPORTED);
1723#endif
1724 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1725
1726 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1727 if (RT_FAILURE(rc))
1728 return rc;
1729
1730 rtSocketErrorReset();
1731#ifdef RT_OS_WINDOWS
1732# ifdef RTSOCKET_MAX_WRITE
1733 int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
1734# else
1735 size_t cbNow = cbBuffer;
1736# endif
1737 int cbWritten = g_pfnsend(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1738 if (cbWritten >= 0)
1739 {
1740 *pcbWritten = cbWritten;
1741 rc = VINF_SUCCESS;
1742 }
1743 else
1744 {
1745 rc = rtSocketError();
1746 if (rc == VERR_TRY_AGAIN)
1747 {
1748 *pcbWritten = 0;
1749 rc = VINF_TRY_AGAIN;
1750 }
1751 }
1752#else
1753 ssize_t cbWritten = send(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL);
1754 if (cbWritten >= 0)
1755 *pcbWritten = cbWritten;
1756 else if ( errno == EAGAIN
1757# ifdef EWOULDBLOCK
1758# if EWOULDBLOCK != EAGAIN
1759 || errno == EWOULDBLOCK
1760# endif
1761# endif
1762 )
1763 {
1764 *pcbWritten = 0;
1765 rc = VINF_TRY_AGAIN;
1766 }
1767 else
1768 rc = rtSocketError();
1769#endif
1770
1771 rtSocketUnlock(pThis);
1772 return rc;
1773}
1774
1775
1776RTDECL(int) RTSocketSgWriteNB(RTSOCKET hSocket, PCRTSGBUF pSgBuf, size_t *pcbWritten)
1777{
1778 /*
1779 * Validate input.
1780 */
1781 RTSOCKETINT *pThis = hSocket;
1782 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1783 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1784 AssertPtrReturn(pSgBuf, VERR_INVALID_PARAMETER);
1785 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER);
1786 AssertReturn(pSgBuf->cSegs > 0, VERR_INVALID_PARAMETER);
1787 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1788
1789 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1790 if (RT_FAILURE(rc))
1791 return rc;
1792
1793 unsigned cSegsToSend = 0;
1794 rc = VERR_NO_TMP_MEMORY;
1795#ifdef RT_OS_WINDOWS
1796 if (g_pfnWSASend)
1797 {
1798 LPWSABUF paMsg = NULL;
1799 RTSgBufMapToNative(paMsg, pSgBuf, WSABUF, buf, char *, len, u_long, cSegsToSend);
1800 if (paMsg)
1801 {
1802 DWORD dwSent = 0;
1803 int hrc = g_pfnWSASend(pThis->hNative, paMsg, cSegsToSend, &dwSent, MSG_NOSIGNAL, NULL, NULL);
1804 if (!hrc)
1805 rc = VINF_SUCCESS;
1806 else
1807 rc = rtSocketError();
1808
1809 *pcbWritten = dwSent;
1810
1811 RTMemTmpFree(paMsg);
1812 }
1813 }
1814 else if (g_pfnsend)
1815 {
1816 size_t cbWrittenTotal = 0;
1817 rc = VINF_SUCCESS;
1818 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
1819 {
1820 uint8_t const *pbSeg = (uint8_t const *)pSgBuf->paSegs[iSeg].pvSeg;
1821 size_t cbSeg = pSgBuf->paSegs[iSeg].cbSeg;
1822 int cbNow;
1823 ssize_t cbWritten;
1824 for (;;)
1825 {
1826 cbNow = cbSeg >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbSeg;
1827 cbWritten = g_pfnsend(pThis->hNative, (const char *)pbSeg, cbNow, MSG_NOSIGNAL);
1828 if ((size_t)cbWritten >= cbSeg || cbWritten < 0)
1829 break;
1830 cbWrittenTotal += cbWrittenTotal;
1831 pbSeg += cbWritten;
1832 cbSeg -= cbWritten;
1833 }
1834 if (cbWritten < 0)
1835 {
1836 rc = rtSocketError();
1837 break;
1838 }
1839 if (cbWritten != cbNow)
1840 break;
1841 }
1842 *pcbWritten = cbWrittenTotal;
1843 }
1844 else
1845 rc = VERR_NET_NOT_UNSUPPORTED;
1846
1847#else /* !RT_OS_WINDOWS */
1848 struct iovec *paMsg = NULL;
1849
1850 RTSgBufMapToNative(paMsg, pSgBuf, struct iovec, iov_base, void *, iov_len, size_t, cSegsToSend);
1851 if (paMsg)
1852 {
1853 struct msghdr msgHdr;
1854 RT_ZERO(msgHdr);
1855 msgHdr.msg_iov = paMsg;
1856 msgHdr.msg_iovlen = cSegsToSend;
1857 ssize_t cbWritten = sendmsg(pThis->hNative, &msgHdr, MSG_NOSIGNAL);
1858 if (RT_LIKELY(cbWritten >= 0))
1859 {
1860 rc = VINF_SUCCESS;
1861 *pcbWritten = cbWritten;
1862 }
1863 else
1864 rc = rtSocketError();
1865
1866 RTMemTmpFree(paMsg);
1867 }
1868#endif /* !RT_OS_WINDOWS */
1869
1870 rtSocketUnlock(pThis);
1871 return rc;
1872}
1873
1874
1875RTDECL(int) RTSocketSgWriteLNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, ...)
1876{
1877 va_list va;
1878 va_start(va, pcbWritten);
1879 int rc = RTSocketSgWriteLVNB(hSocket, cSegs, pcbWritten, va);
1880 va_end(va);
1881 return rc;
1882}
1883
1884
1885RTDECL(int) RTSocketSgWriteLVNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, va_list va)
1886{
1887 /*
1888 * Set up a S/G segment array + buffer on the stack and pass it
1889 * on to RTSocketSgWrite.
1890 */
1891 Assert(cSegs <= 16);
1892 PRTSGSEG paSegs = (PRTSGSEG)alloca(cSegs * sizeof(RTSGSEG));
1893 AssertReturn(paSegs, VERR_NO_TMP_MEMORY);
1894 for (size_t i = 0; i < cSegs; i++)
1895 {
1896 paSegs[i].pvSeg = va_arg(va, void *);
1897 paSegs[i].cbSeg = va_arg(va, size_t);
1898 }
1899
1900 RTSGBUF SgBuf;
1901 RTSgBufInit(&SgBuf, paSegs, cSegs);
1902 return RTSocketSgWriteNB(hSocket, &SgBuf, pcbWritten);
1903}
1904
1905
1906RTDECL(int) RTSocketSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies)
1907{
1908 /*
1909 * Validate input.
1910 */
1911 RTSOCKETINT *pThis = hSocket;
1912 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1913 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1914 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1915 int const fdMax = (int)pThis->hNative + 1;
1916 AssertReturn((RTSOCKETNATIVE)(fdMax - 1) == pThis->hNative, VERR_INTERNAL_ERROR_5);
1917#ifdef RT_OS_WINDOWS
1918 AssertReturn(g_pfnselect, VERR_NET_NOT_UNSUPPORTED);
1919# define select g_pfnselect
1920#endif
1921
1922 /*
1923 * Set up the file descriptor sets and do the select.
1924 */
1925 fd_set fdsetR;
1926 FD_ZERO(&fdsetR);
1927 FD_SET(pThis->hNative, &fdsetR);
1928
1929 fd_set fdsetE = fdsetR;
1930
1931 int rc;
1932 if (cMillies == RT_INDEFINITE_WAIT)
1933 rc = select(fdMax, &fdsetR, NULL, &fdsetE, NULL);
1934 else
1935 {
1936 struct timeval timeout;
1937 timeout.tv_sec = cMillies / 1000;
1938 timeout.tv_usec = (cMillies % 1000) * 1000;
1939 rc = select(fdMax, &fdsetR, NULL, &fdsetE, &timeout);
1940 }
1941 if (rc > 0)
1942 rc = VINF_SUCCESS;
1943 else if (rc == 0)
1944 rc = VERR_TIMEOUT;
1945 else
1946 rc = rtSocketError();
1947
1948#ifdef RT_OS_WINDOWS
1949# undef select
1950#endif
1951 return rc;
1952}
1953
1954
1955/**
1956 * Internal worker for RTSocketSelectOneEx and rtSocketPollCheck (fallback)
1957 *
1958 * @returns IPRT status code
1959 * @param pThis The socket (valid).
1960 * @param fEvents The events to select for.
1961 * @param pfEvents Where to return the events.
1962 * @param cMillies How long to select for, in milliseconds.
1963 */
1964static int rtSocketSelectOneEx(RTSOCKET pThis, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
1965{
1966 RTSOCKETNATIVE hNative = pThis->hNative;
1967 if (hNative == NIL_RTSOCKETNATIVE)
1968 {
1969 /* Socket is already closed? Possible we raced someone calling rtSocketCloseIt.
1970 Should we return a different status code? */
1971 *pfEvents = RTSOCKET_EVT_ERROR;
1972 return VINF_SUCCESS;
1973 }
1974
1975 int const fdMax = (int)hNative + 1;
1976 AssertReturn((RTSOCKETNATIVE)(fdMax - 1) == hNative, VERR_INTERNAL_ERROR_5);
1977#ifdef RT_OS_WINDOWS
1978 AssertReturn(g_pfnselect, VERR_NET_NOT_UNSUPPORTED);
1979 AssertReturn(g_pfn__WSAFDIsSet, VERR_NET_NOT_UNSUPPORTED);
1980# define select g_pfnselect
1981# define __WSAFDIsSet g_pfn__WSAFDIsSet
1982#endif
1983
1984 *pfEvents = 0;
1985
1986 /*
1987 * Set up the file descriptor sets and do the select.
1988 */
1989 fd_set fdsetR;
1990 fd_set fdsetW;
1991 fd_set fdsetE;
1992 FD_ZERO(&fdsetR);
1993 FD_ZERO(&fdsetW);
1994 FD_ZERO(&fdsetE);
1995
1996 if (fEvents & RTSOCKET_EVT_READ)
1997 FD_SET(hNative, &fdsetR);
1998 if (fEvents & RTSOCKET_EVT_WRITE)
1999 FD_SET(hNative, &fdsetW);
2000 if (fEvents & RTSOCKET_EVT_ERROR)
2001 FD_SET(hNative, &fdsetE);
2002
2003 int rc;
2004 if (cMillies == RT_INDEFINITE_WAIT)
2005 rc = select(fdMax, &fdsetR, &fdsetW, &fdsetE, NULL);
2006 else
2007 {
2008 struct timeval timeout;
2009 timeout.tv_sec = cMillies / 1000;
2010 timeout.tv_usec = (cMillies % 1000) * 1000;
2011 rc = select(fdMax, &fdsetR, &fdsetW, &fdsetE, &timeout);
2012 }
2013 if (rc > 0)
2014 {
2015 if (pThis->hNative == hNative)
2016 {
2017 if (FD_ISSET(hNative, &fdsetR))
2018 *pfEvents |= RTSOCKET_EVT_READ;
2019 if (FD_ISSET(hNative, &fdsetW))
2020 *pfEvents |= RTSOCKET_EVT_WRITE;
2021 if (FD_ISSET(hNative, &fdsetE))
2022 *pfEvents |= RTSOCKET_EVT_ERROR;
2023 rc = VINF_SUCCESS;
2024 }
2025 else
2026 {
2027 /* Socket was closed while we waited (rtSocketCloseIt). Different status code? */
2028 *pfEvents = RTSOCKET_EVT_ERROR;
2029 rc = VINF_SUCCESS;
2030 }
2031 }
2032 else if (rc == 0)
2033 rc = VERR_TIMEOUT;
2034 else
2035 rc = rtSocketError();
2036
2037#ifdef RT_OS_WINDOWS
2038# undef select
2039# undef __WSAFDIsSet
2040#endif
2041 return rc;
2042}
2043
2044
2045RTDECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
2046{
2047 /*
2048 * Validate input.
2049 */
2050 RTSOCKETINT *pThis = hSocket;
2051 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2052 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2053 AssertPtrReturn(pfEvents, VERR_INVALID_PARAMETER);
2054 AssertReturn(!(fEvents & ~RTSOCKET_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
2055 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
2056
2057 return rtSocketSelectOneEx(pThis, fEvents, pfEvents, cMillies);
2058}
2059
2060
2061RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite)
2062{
2063 /*
2064 * Validate input, don't lock it because we might want to interrupt a call
2065 * active on a different thread.
2066 */
2067 RTSOCKETINT *pThis = hSocket;
2068 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2069 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2070 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
2071 AssertReturn(fRead || fWrite, VERR_INVALID_PARAMETER);
2072#ifdef RT_OS_WINDOWS
2073 AssertReturn(g_pfnshutdown, VERR_NET_NOT_UNSUPPORTED);
2074# define shutdown g_pfnshutdown
2075#endif
2076
2077 /*
2078 * Do the job.
2079 */
2080 int rc = VINF_SUCCESS;
2081 int fHow;
2082 if (fRead && fWrite)
2083 fHow = SHUT_RDWR;
2084 else if (fRead)
2085 fHow = SHUT_RD;
2086 else
2087 fHow = SHUT_WR;
2088 if (shutdown(pThis->hNative, fHow) == -1)
2089 rc = rtSocketError();
2090
2091#ifdef RT_OS_WINDOWS
2092# undef shutdown
2093#endif
2094 return rc;
2095}
2096
2097
2098RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
2099{
2100 /*
2101 * Validate input.
2102 */
2103 RTSOCKETINT *pThis = hSocket;
2104 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2105 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2106 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
2107#ifdef RT_OS_WINDOWS
2108 AssertReturn(g_pfngetsockname, VERR_NET_NOT_UNSUPPORTED);
2109# define getsockname g_pfngetsockname
2110#endif
2111
2112 /*
2113 * Get the address and convert it.
2114 */
2115 int rc;
2116 RTSOCKADDRUNION u;
2117#ifdef RT_OS_WINDOWS
2118 int cbAddr = sizeof(u);
2119#else
2120 socklen_t cbAddr = sizeof(u);
2121#endif
2122 RT_ZERO(u);
2123 if (getsockname(pThis->hNative, &u.Addr, &cbAddr) == 0)
2124 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
2125 else
2126 rc = rtSocketError();
2127
2128#ifdef RT_OS_WINDOWS
2129# undef getsockname
2130#endif
2131 return rc;
2132}
2133
2134
2135RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
2136{
2137 /*
2138 * Validate input.
2139 */
2140 RTSOCKETINT *pThis = hSocket;
2141 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2142 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2143 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
2144#ifdef RT_OS_WINDOWS
2145 AssertReturn(g_pfngetpeername, VERR_NET_NOT_UNSUPPORTED);
2146# define getpeername g_pfngetpeername
2147#endif
2148
2149 /*
2150 * Get the address and convert it.
2151 */
2152 int rc;
2153 RTSOCKADDRUNION u;
2154#ifdef RT_OS_WINDOWS
2155 int cbAddr = sizeof(u);
2156#else
2157 socklen_t cbAddr = sizeof(u);
2158#endif
2159 RT_ZERO(u);
2160 if (getpeername(pThis->hNative, &u.Addr, &cbAddr) == 0)
2161 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
2162 else
2163 rc = rtSocketError();
2164
2165#ifdef RT_OS_WINDOWS
2166# undef getpeername
2167#endif
2168 return rc;
2169}
2170
2171
2172
2173/**
2174 * Wrapper around bind.
2175 *
2176 * @returns IPRT status code.
2177 * @param hSocket The socket handle.
2178 * @param pAddr The address to bind to.
2179 */
2180DECLHIDDEN(int) rtSocketBind(RTSOCKET hSocket, PCRTNETADDR pAddr)
2181{
2182 RTSOCKADDRUNION u;
2183 int cbAddr;
2184 int rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), &cbAddr);
2185 if (RT_SUCCESS(rc))
2186 rc = rtSocketBindRawAddr(hSocket, &u.Addr, cbAddr);
2187 return rc;
2188}
2189
2190
2191/**
2192 * Very thin wrapper around bind.
2193 *
2194 * @returns IPRT status code.
2195 * @param hSocket The socket handle.
2196 * @param pvAddr The address to bind to (struct sockaddr and
2197 * friends).
2198 * @param cbAddr The size of the address.
2199 */
2200DECLHIDDEN(int) rtSocketBindRawAddr(RTSOCKET hSocket, void const *pvAddr, size_t cbAddr)
2201{
2202 /*
2203 * Validate input.
2204 */
2205 RTSOCKETINT *pThis = hSocket;
2206 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2207 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2208 AssertPtrReturn(pvAddr, VERR_INVALID_POINTER);
2209#ifdef RT_OS_WINDOWS
2210 AssertReturn(g_pfnbind, VERR_NET_NOT_UNSUPPORTED);
2211# define bind g_pfnbind
2212#endif
2213 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2214
2215 int rc;
2216 if (bind(pThis->hNative, (struct sockaddr const *)pvAddr, (int)cbAddr) == 0)
2217 rc = VINF_SUCCESS;
2218 else
2219 rc = rtSocketError();
2220
2221 rtSocketUnlock(pThis);
2222#ifdef RT_OS_WINDOWS
2223# undef bind
2224#endif
2225 return rc;
2226}
2227
2228
2229
2230/**
2231 * Wrapper around listen.
2232 *
2233 * @returns IPRT status code.
2234 * @param hSocket The socket handle.
2235 * @param cMaxPending The max number of pending connections.
2236 */
2237DECLHIDDEN(int) rtSocketListen(RTSOCKET hSocket, int cMaxPending)
2238{
2239 /*
2240 * Validate input.
2241 */
2242 RTSOCKETINT *pThis = hSocket;
2243 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2244 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2245#ifdef RT_OS_WINDOWS
2246 AssertReturn(g_pfnlisten, VERR_NET_NOT_UNSUPPORTED);
2247# define listen g_pfnlisten
2248#endif
2249 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2250
2251 int rc = VINF_SUCCESS;
2252 if (listen(pThis->hNative, cMaxPending) != 0)
2253 rc = rtSocketError();
2254
2255 rtSocketUnlock(pThis);
2256#ifdef RT_OS_WINDOWS
2257# undef listen
2258#endif
2259 return rc;
2260}
2261
2262
2263/**
2264 * Wrapper around accept.
2265 *
2266 * @returns IPRT status code.
2267 * @param hSocket The socket handle.
2268 * @param phClient Where to return the client socket handle on
2269 * success.
2270 * @param pAddr Where to return the client address.
2271 * @param pcbAddr On input this gives the size buffer size of what
2272 * @a pAddr point to. On return this contains the
2273 * size of what's stored at @a pAddr.
2274 */
2275DECLHIDDEN(int) rtSocketAccept(RTSOCKET hSocket, PRTSOCKET phClient, struct sockaddr *pAddr, size_t *pcbAddr)
2276{
2277 /*
2278 * Validate input.
2279 * Only lock the socket temporarily while we get the native handle, so that
2280 * we can safely shutdown and destroy the socket from a different thread.
2281 */
2282 RTSOCKETINT *pThis = hSocket;
2283 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2284 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2285#ifdef RT_OS_WINDOWS
2286 AssertReturn(g_pfnaccept, VERR_NET_NOT_UNSUPPORTED);
2287 AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
2288# define accept g_pfnaccept
2289#endif
2290 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2291
2292 /*
2293 * Call accept().
2294 */
2295 rtSocketErrorReset();
2296 int rc = VINF_SUCCESS;
2297#ifdef RT_OS_WINDOWS
2298 int cbAddr = (int)*pcbAddr;
2299#else
2300 socklen_t cbAddr = *pcbAddr;
2301#endif
2302 RTSOCKETNATIVE hNativeClient = accept(pThis->hNative, pAddr, &cbAddr);
2303 if (hNativeClient != NIL_RTSOCKETNATIVE)
2304 {
2305 *pcbAddr = cbAddr;
2306
2307 /*
2308 * Wrap the client socket.
2309 */
2310 rc = rtSocketCreateForNative(phClient, hNativeClient, false /*fLeaveOpen*/);
2311 if (RT_FAILURE(rc))
2312 {
2313#ifdef RT_OS_WINDOWS
2314 g_pfnclosesocket(hNativeClient);
2315#else
2316 close(hNativeClient);
2317#endif
2318 }
2319 }
2320 else
2321 rc = rtSocketError();
2322
2323 rtSocketUnlock(pThis);
2324#ifdef RT_OS_WINDOWS
2325# undef accept
2326#endif
2327 return rc;
2328}
2329
2330
2331/**
2332 * Wrapper around connect.
2333 *
2334 * @returns IPRT status code.
2335 * @param hSocket The socket handle.
2336 * @param pAddr The socket address to connect to.
2337 * @param cMillies Number of milliseconds to wait for the connect attempt to complete.
2338 * Use RT_INDEFINITE_WAIT to wait for ever.
2339 * Use RT_TCPCLIENTCONNECT_DEFAULT_WAIT to wait for the default time
2340 * configured on the running system.
2341 */
2342DECLHIDDEN(int) rtSocketConnect(RTSOCKET hSocket, PCRTNETADDR pAddr, RTMSINTERVAL cMillies)
2343{
2344 /*
2345 * Validate input.
2346 */
2347 RTSOCKETINT *pThis = hSocket;
2348 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2349 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2350#ifdef RT_OS_WINDOWS
2351 AssertReturn(g_pfnconnect, VERR_NET_NOT_UNSUPPORTED);
2352 AssertReturn(g_pfnselect, VERR_NET_NOT_UNSUPPORTED);
2353 AssertReturn(g_pfngetsockopt, VERR_NET_NOT_UNSUPPORTED);
2354# define connect g_pfnconnect
2355# define select g_pfnselect
2356# define getsockopt g_pfngetsockopt
2357#endif
2358 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2359
2360 RTSOCKADDRUNION u;
2361 int cbAddr;
2362 int rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), &cbAddr);
2363 if (RT_SUCCESS(rc))
2364 {
2365 if (cMillies == RT_SOCKETCONNECT_DEFAULT_WAIT)
2366 {
2367 if (connect(pThis->hNative, &u.Addr, cbAddr) != 0)
2368 rc = rtSocketError();
2369 }
2370 else
2371 {
2372 /*
2373 * Switch the socket to nonblocking mode, initiate the connect
2374 * and wait for the socket to become writable or until the timeout
2375 * expires.
2376 */
2377 rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
2378 if (RT_SUCCESS(rc))
2379 {
2380 if (connect(pThis->hNative, &u.Addr, cbAddr) != 0)
2381 {
2382 rc = rtSocketError();
2383 if (rc == VERR_TRY_AGAIN || rc == VERR_NET_IN_PROGRESS)
2384 {
2385 int rcSock = 0;
2386 fd_set FdSetWriteable;
2387 struct timeval TvTimeout;
2388
2389 TvTimeout.tv_sec = cMillies / RT_MS_1SEC;
2390 TvTimeout.tv_usec = (cMillies % RT_MS_1SEC) * RT_US_1MS;
2391
2392 FD_ZERO(&FdSetWriteable);
2393 FD_SET(pThis->hNative, &FdSetWriteable);
2394 do
2395 {
2396 rcSock = select(pThis->hNative + 1, NULL, &FdSetWriteable, NULL,
2397 cMillies == RT_INDEFINITE_WAIT || cMillies >= INT_MAX
2398 ? NULL
2399 : &TvTimeout);
2400 if (rcSock > 0)
2401 {
2402 int iSockError = 0;
2403 socklen_t cbSockOpt = sizeof(iSockError);
2404 rcSock = getsockopt(pThis->hNative, SOL_SOCKET, SO_ERROR, (char *)&iSockError, &cbSockOpt);
2405 if (rcSock == 0)
2406 {
2407 if (iSockError == 0)
2408 rc = VINF_SUCCESS;
2409 else
2410 {
2411#ifdef RT_OS_WINDOWS
2412 rc = RTErrConvertFromWin32(iSockError);
2413#else
2414 rc = RTErrConvertFromErrno(iSockError);
2415#endif
2416 }
2417 }
2418 else
2419 rc = rtSocketError();
2420 }
2421 else if (rcSock == 0)
2422 rc = VERR_TIMEOUT;
2423 else
2424 rc = rtSocketError();
2425 } while (rc == VERR_INTERRUPTED);
2426 }
2427 }
2428
2429 rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
2430 }
2431 }
2432 }
2433
2434 rtSocketUnlock(pThis);
2435#ifdef RT_OS_WINDOWS
2436# undef connect
2437# undef select
2438# undef getsockopt
2439#endif
2440 return rc;
2441}
2442
2443
2444/**
2445 * Wrapper around connect, raw address, no timeout.
2446 *
2447 * @returns IPRT status code.
2448 * @param hSocket The socket handle.
2449 * @param pvAddr The raw socket address to connect to.
2450 * @param cbAddr The size of the raw address.
2451 */
2452DECLHIDDEN(int) rtSocketConnectRaw(RTSOCKET hSocket, void const *pvAddr, size_t cbAddr)
2453{
2454 /*
2455 * Validate input.
2456 */
2457 RTSOCKETINT *pThis = hSocket;
2458 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2459 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2460#ifdef RT_OS_WINDOWS
2461 AssertReturn(g_pfnconnect, VERR_NET_NOT_UNSUPPORTED);
2462# define connect g_pfnconnect
2463#endif
2464 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2465
2466 int rc;
2467 if (connect(pThis->hNative, (const struct sockaddr *)pvAddr, (int)cbAddr) == 0)
2468 rc = VINF_SUCCESS;
2469 else
2470 rc = rtSocketError();
2471
2472 rtSocketUnlock(pThis);
2473#ifdef RT_OS_WINDOWS
2474# undef connect
2475#endif
2476 return rc;
2477}
2478
2479
2480/**
2481 * Wrapper around setsockopt.
2482 *
2483 * @returns IPRT status code.
2484 * @param hSocket The socket handle.
2485 * @param iLevel The protocol level, e.g. IPPORTO_TCP.
2486 * @param iOption The option, e.g. TCP_NODELAY.
2487 * @param pvValue The value buffer.
2488 * @param cbValue The size of the value pointed to by pvValue.
2489 */
2490DECLHIDDEN(int) rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValue, int cbValue)
2491{
2492 /*
2493 * Validate input.
2494 */
2495 RTSOCKETINT *pThis = hSocket;
2496 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2497 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2498#ifdef RT_OS_WINDOWS
2499 AssertReturn(g_pfnsetsockopt, VERR_NET_NOT_UNSUPPORTED);
2500# define setsockopt g_pfnsetsockopt
2501#endif
2502 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2503
2504 int rc = VINF_SUCCESS;
2505 if (setsockopt(pThis->hNative, iLevel, iOption, (const char *)pvValue, cbValue) != 0)
2506 rc = rtSocketError();
2507
2508 rtSocketUnlock(pThis);
2509#ifdef RT_OS_WINDOWS
2510# undef setsockopt
2511#endif
2512 return rc;
2513}
2514
2515
2516/**
2517 * Internal RTPollSetAdd helper that returns the handle that should be added to
2518 * the pollset.
2519 *
2520 * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
2521 * @param hSocket The socket handle.
2522 * @param fEvents The events we're polling for.
2523 * @param phNative Where to put the primary handle.
2524 */
2525DECLHIDDEN(int) rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PRTHCINTPTR phNative)
2526{
2527 RTSOCKETINT *pThis = hSocket;
2528 RT_NOREF_PV(fEvents);
2529 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2530 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2531#ifdef RT_OS_WINDOWS
2532 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2533
2534 int rc = VINF_SUCCESS;
2535 if (pThis->hEvent != WSA_INVALID_EVENT)
2536 *phNative = (RTHCINTPTR)pThis->hEvent;
2537 else if (g_pfnWSACreateEvent)
2538 {
2539 pThis->hEvent = g_pfnWSACreateEvent();
2540 *phNative = (RTHCINTPTR)pThis->hEvent;
2541 if (pThis->hEvent == WSA_INVALID_EVENT)
2542 rc = rtSocketError();
2543 }
2544 else
2545 {
2546 AssertCompile(WSA_INVALID_EVENT == (WSAEVENT)NULL);
2547 pThis->hEvent = CreateEventW(NULL, TRUE /*fManualReset*/, FALSE /*fInitialState*/, NULL /*pwszName*/);
2548 *phNative = (RTHCINTPTR)pThis->hEvent;
2549 if (pThis->hEvent == WSA_INVALID_EVENT)
2550 rc = RTErrConvertFromWin32(GetLastError());
2551 }
2552
2553 rtSocketUnlock(pThis);
2554 return rc;
2555
2556#else /* !RT_OS_WINDOWS */
2557 *phNative = (RTHCUINTPTR)pThis->hNative;
2558 return VINF_SUCCESS;
2559#endif /* !RT_OS_WINDOWS */
2560}
2561
2562#ifdef RT_OS_WINDOWS
2563
2564/**
2565 * Fallback poller thread.
2566 *
2567 * @returns VINF_SUCCESS.
2568 * @param hSelf The thread handle.
2569 * @param pvUser Socket instance data.
2570 */
2571static DECLCALLBACK(int) rtSocketPollFallbackThreadProc(RTTHREAD hSelf, void *pvUser)
2572{
2573 RTSOCKETINT *pThis = (RTSOCKETINT *)pvUser;
2574 RT_NOREF(hSelf);
2575# define __WSAFDIsSet g_pfn__WSAFDIsSet
2576
2577 /*
2578 * The execution loop.
2579 */
2580 while (!ASMAtomicReadBool(&pThis->fPollFallbackShutdown))
2581 {
2582 /*
2583 * Do the selecting (with a 15 second timeout because that seems like a good idea).
2584 */
2585 struct fd_set SetRead;
2586 struct fd_set SetWrite;
2587 struct fd_set SetXcpt;
2588
2589 FD_ZERO(&SetRead);
2590 FD_ZERO(&SetWrite);
2591 FD_ZERO(&SetXcpt);
2592
2593 FD_SET(pThis->hPollFallbackNotifyR, &SetRead);
2594 FD_SET(pThis->hPollFallbackNotifyR, &SetXcpt);
2595
2596 bool fActive = ASMAtomicReadBool(&pThis->fPollFallbackActive);
2597 uint32_t fEvents;
2598 if (!fActive)
2599 fEvents = 0;
2600 else
2601 {
2602 fEvents = ASMAtomicReadU32(&pThis->fSubscribedEvts);
2603 if (fEvents & RTPOLL_EVT_READ)
2604 FD_SET(pThis->hNative, &SetRead);
2605 if (fEvents & RTPOLL_EVT_WRITE)
2606 FD_SET(pThis->hNative, &SetWrite);
2607 if (fEvents & RTPOLL_EVT_ERROR)
2608 FD_SET(pThis->hNative, &SetXcpt);
2609 }
2610
2611 struct timeval Timeout;
2612 Timeout.tv_sec = 15;
2613 Timeout.tv_usec = 0;
2614 int rc = g_pfnselect(INT_MAX /*ignored*/, &SetRead, &SetWrite, &SetXcpt, &Timeout);
2615
2616 /* Stop immediately if told to shut down. */
2617 if (ASMAtomicReadBool(&pThis->fPollFallbackShutdown))
2618 break;
2619
2620 /*
2621 * Process the result.
2622 */
2623 if (rc > 0)
2624 {
2625 /* First the socket we're listening on. */
2626 if ( fEvents
2627 && ( FD_ISSET(pThis->hNative, &SetRead)
2628 || FD_ISSET(pThis->hNative, &SetWrite)
2629 || FD_ISSET(pThis->hNative, &SetXcpt)) )
2630 {
2631 ASMAtomicWriteBool(&pThis->fPollFallbackActive, false);
2632 SetEvent(pThis->hEvent);
2633 }
2634
2635 /* Then maintain the notification pipe. (We only read one byte here
2636 because we're overly paranoid wrt socket switching to blocking mode.) */
2637 if (FD_ISSET(pThis->hPollFallbackNotifyR, &SetRead))
2638 {
2639 char chIgnored;
2640 g_pfnrecv(pThis->hPollFallbackNotifyR, &chIgnored, sizeof(chIgnored), MSG_NOSIGNAL);
2641 }
2642 }
2643 else
2644 AssertMsg(rc == 0, ("%Rrc\n", rtSocketError()));
2645 }
2646
2647# undef __WSAFDIsSet
2648 return VINF_SUCCESS;
2649}
2650
2651
2652/**
2653 * Pokes the fallback thread, making sure it gets out of whatever it's stuck in.
2654 *
2655 * @param pThis The socket handle.
2656 */
2657static void rtSocketPokePollFallbackThread(RTSOCKETINT *pThis)
2658{
2659 Assert(pThis->fPollFallback);
2660 if (pThis->hPollFallbackThread != NIL_RTTHREAD)
2661 {
2662 int cbWritten = g_pfnsend(pThis->hPollFallbackNotifyW, "!", 1, MSG_NOSIGNAL);
2663 AssertMsg(cbWritten == 1, ("cbWritten=%d err=%Rrc\n", rtSocketError()));
2664 RT_NOREF_PV(cbWritten);
2665 }
2666}
2667
2668
2669/**
2670 * Called by rtSocketPollStart to make the thread start selecting on the socket.
2671 *
2672 * @returns 0 on success, RTPOLL_EVT_ERROR on failure.
2673 * @param pThis The socket handle.
2674 */
2675static uint32_t rtSocketPollFallbackStart(RTSOCKETINT *pThis)
2676{
2677 /*
2678 * Reset the event and tell the thread to start selecting on the socket.
2679 */
2680 ResetEvent(pThis->hEvent);
2681 ASMAtomicWriteBool(&pThis->fPollFallbackActive, true);
2682
2683 /*
2684 * Wake up the thread the thread.
2685 */
2686 if (pThis->hPollFallbackThread != NIL_RTTHREAD)
2687 rtSocketPokePollFallbackThread(pThis);
2688 else
2689 {
2690 /*
2691 * Not running, need to set it up and start it.
2692 */
2693 AssertLogRelReturn(pThis->hEvent != NULL && pThis->hEvent != INVALID_HANDLE_VALUE, RTPOLL_EVT_ERROR);
2694
2695 /* Create the notification socket pair. */
2696 int rc;
2697 if (pThis->hPollFallbackNotifyR == NIL_RTSOCKETNATIVE)
2698 {
2699 rc = rtSocketCreateNativeTcpPair(&pThis->hPollFallbackNotifyW, &pThis->hPollFallbackNotifyR);
2700 AssertLogRelRCReturn(rc, RTPOLL_EVT_ERROR);
2701
2702 /* Make the read end non-blocking (not fatal). */
2703 u_long fNonBlocking = 1;
2704 rc = g_pfnioctlsocket(pThis->hPollFallbackNotifyR, FIONBIO, &fNonBlocking);
2705 AssertLogRelMsg(rc == 0, ("rc=%#x %Rrc\n", rc, rtSocketError()));
2706 }
2707
2708 /* Finally, start the thread. ASSUME we don't need too much stack. */
2709 rc = RTThreadCreate(&pThis->hPollFallbackThread, rtSocketPollFallbackThreadProc, pThis,
2710 _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "sockpoll");
2711 AssertLogRelRCReturn(rc, RTPOLL_EVT_ERROR);
2712 }
2713 return 0;
2714}
2715
2716
2717/**
2718 * Undos the harm done by WSAEventSelect.
2719 *
2720 * @returns IPRT status code.
2721 * @param pThis The socket handle.
2722 */
2723static int rtSocketPollClearEventAndRestoreBlocking(RTSOCKETINT *pThis)
2724{
2725 int rc = VINF_SUCCESS;
2726 if (pThis->fSubscribedEvts)
2727 {
2728 if (!pThis->fPollFallback)
2729 {
2730 Assert(g_pfnWSAEventSelect && g_pfnioctlsocket);
2731 if (g_pfnWSAEventSelect && g_pfnioctlsocket)
2732 {
2733 if (g_pfnWSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
2734 {
2735 pThis->fSubscribedEvts = 0;
2736
2737 /*
2738 * Switch back to blocking mode if that was the state before the
2739 * operation.
2740 */
2741 if (pThis->fBlocking)
2742 {
2743 u_long fNonBlocking = 0;
2744 int rc2 = g_pfnioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
2745 if (rc2 != 0)
2746 {
2747 rc = rtSocketError();
2748 AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
2749 }
2750 }
2751 }
2752 else
2753 {
2754 rc = rtSocketError();
2755 AssertMsgFailed(("%Rrc\n", rc));
2756 }
2757 }
2758 else
2759 {
2760 Assert(pThis->fPollFallback);
2761 rc = VINF_SUCCESS;
2762 }
2763 }
2764 /*
2765 * Just clear the event mask as we never started waiting if we get here.
2766 */
2767 else
2768 ASMAtomicWriteU32(&pThis->fSubscribedEvts, 0);
2769 }
2770 return rc;
2771}
2772
2773
2774/**
2775 * Updates the mask of events we're subscribing to.
2776 *
2777 * @returns IPRT status code.
2778 * @param pThis The socket handle.
2779 * @param fEvents The events we want to subscribe to.
2780 */
2781static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
2782{
2783 if (!pThis->fPollFallback)
2784 {
2785 LONG fNetworkEvents = 0;
2786 if (fEvents & RTPOLL_EVT_READ)
2787 fNetworkEvents |= FD_READ;
2788 if (fEvents & RTPOLL_EVT_WRITE)
2789 fNetworkEvents |= FD_WRITE;
2790 if (fEvents & RTPOLL_EVT_ERROR)
2791 fNetworkEvents |= FD_CLOSE;
2792 LogFlowFunc(("fNetworkEvents=%#x\n", fNetworkEvents));
2793
2794 if (g_pfnWSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
2795 {
2796 pThis->fSubscribedEvts = fEvents;
2797 return VINF_SUCCESS;
2798 }
2799
2800 int rc = rtSocketError();
2801 AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
2802 return rc;
2803 }
2804
2805 /*
2806 * Update the events we're waiting for. Caller will poke/start the thread. later
2807 */
2808 ASMAtomicWriteU32(&pThis->fSubscribedEvts, fEvents);
2809 return VINF_SUCCESS;
2810}
2811
2812#endif /* RT_OS_WINDOWS */
2813
2814
2815#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
2816
2817/**
2818 * Checks for pending events.
2819 *
2820 * @returns Event mask or 0.
2821 * @param pThis The socket handle.
2822 * @param fEvents The desired events.
2823 */
2824static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents)
2825{
2826 uint32_t fRetEvents = 0;
2827
2828 LogFlowFunc(("pThis=%#p fEvents=%#x\n", pThis, fEvents));
2829
2830# ifdef RT_OS_WINDOWS
2831 /* Make sure WSAEnumNetworkEvents returns what we want. */
2832 int rc = VINF_SUCCESS;
2833 if ((pThis->fSubscribedEvts & fEvents) != fEvents)
2834 rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
2835
2836 if (!pThis->fPollFallback)
2837 {
2838 /* Atomically get pending events and reset the event semaphore. */
2839 Assert(g_pfnWSAEnumNetworkEvents);
2840 WSANETWORKEVENTS NetEvts;
2841 RT_ZERO(NetEvts);
2842 if (g_pfnWSAEnumNetworkEvents(pThis->hNative, pThis->hEvent, &NetEvts) == 0)
2843 {
2844 if ( (NetEvts.lNetworkEvents & FD_READ)
2845 && NetEvts.iErrorCode[FD_READ_BIT] == 0)
2846 fRetEvents |= RTPOLL_EVT_READ;
2847
2848 if ( (NetEvts.lNetworkEvents & FD_WRITE)
2849 && NetEvts.iErrorCode[FD_WRITE_BIT] == 0)
2850 fRetEvents |= RTPOLL_EVT_WRITE;
2851
2852 if (NetEvts.lNetworkEvents & FD_CLOSE)
2853 fRetEvents |= RTPOLL_EVT_ERROR;
2854 else
2855 for (uint32_t i = 0; i < FD_MAX_EVENTS; i++)
2856 if ( (NetEvts.lNetworkEvents & (1L << i))
2857 && NetEvts.iErrorCode[i] != 0)
2858 fRetEvents |= RTPOLL_EVT_ERROR;
2859
2860 pThis->fEventsSaved = fRetEvents |= pThis->fEventsSaved;
2861 fRetEvents &= fEvents | RTPOLL_EVT_ERROR;
2862 }
2863 else
2864 rc = rtSocketError();
2865 }
2866
2867 /* Fall back on select if we hit an error above or is using fallback polling. */
2868 if (pThis->fPollFallback || RT_FAILURE(rc))
2869 {
2870 rc = rtSocketSelectOneEx(pThis, fEvents & RTPOLL_EVT_ERROR ? fEvents | RTPOLL_EVT_READ : fEvents, &fRetEvents, 0);
2871 if (RT_SUCCESS(rc))
2872 {
2873 /* rtSocketSelectOneEx may return RTPOLL_EVT_READ on disconnect. Use
2874 getpeername to fix this. */
2875 if ((fRetEvents & (RTPOLL_EVT_READ | RTPOLL_EVT_ERROR)) == RTPOLL_EVT_READ)
2876 {
2877# if 0 /* doens't work */
2878 rtSocketErrorReset();
2879 char chIgn;
2880 rc = g_pfnrecv(pThis->hNative, &chIgn, 0, MSG_NOSIGNAL);
2881 rc = rtSocketError();
2882 if (RT_FAILURE(rc))
2883 fRetEvents |= RTPOLL_EVT_ERROR;
2884
2885 rc = g_pfnsend(pThis->hNative, &chIgn, 0, MSG_NOSIGNAL);
2886 rc = rtSocketError();
2887 if (RT_FAILURE(rc))
2888 fRetEvents |= RTPOLL_EVT_ERROR;
2889
2890 RTSOCKADDRUNION u;
2891 int cbAddr = sizeof(u);
2892 if (g_pfngetpeername(pThis->hNative, &u.Addr, &cbAddr) == SOCKET_ERROR)
2893 fRetEvents |= RTPOLL_EVT_ERROR;
2894# endif
2895 /* If no bytes are available, assume error condition. */
2896 u_long cbAvail = 0;
2897 rc = g_pfnioctlsocket(pThis->hNative, FIONREAD, &cbAvail);
2898 if (rc == 0 && cbAvail == 0)
2899 fRetEvents |= RTPOLL_EVT_ERROR;
2900 }
2901 fRetEvents &= fEvents | RTPOLL_EVT_ERROR;
2902 }
2903 else if (rc == VERR_TIMEOUT)
2904 fRetEvents = 0;
2905 else
2906 fRetEvents |= RTPOLL_EVT_ERROR;
2907 }
2908
2909# else /* RT_OS_OS2 */
2910 int aFds[4] = { pThis->hNative, pThis->hNative, pThis->hNative, -1 };
2911 int rc = os2_select(aFds, 1, 1, 1, 0);
2912 if (rc > 0)
2913 {
2914 if (aFds[0] == pThis->hNative)
2915 fRetEvents |= RTPOLL_EVT_READ;
2916 if (aFds[1] == pThis->hNative)
2917 fRetEvents |= RTPOLL_EVT_WRITE;
2918 if (aFds[2] == pThis->hNative)
2919 fRetEvents |= RTPOLL_EVT_ERROR;
2920 fRetEvents &= fEvents;
2921 }
2922# endif /* RT_OS_OS2 */
2923
2924 LogFlowFunc(("fRetEvents=%#x\n", fRetEvents));
2925 return fRetEvents;
2926}
2927
2928
2929/**
2930 * Internal RTPoll helper that polls the socket handle and, if @a fNoWait is
2931 * clear, starts whatever actions we've got running during the poll call.
2932 *
2933 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
2934 * Event mask (in @a fEvents) and no actions if the handle is ready
2935 * already.
2936 * UINT32_MAX (asserted) if the socket handle is busy in I/O or a
2937 * different poll set.
2938 *
2939 * @param hSocket The socket handle.
2940 * @param hPollSet The poll set handle (for access checks).
2941 * @param fEvents The events we're polling for.
2942 * @param fFinalEntry Set if this is the final entry for this handle
2943 * in this poll set. This can be used for dealing
2944 * with duplicate entries.
2945 * @param fNoWait Set if it's a zero-wait poll call. Clear if
2946 * we'll wait for an event to occur.
2947 *
2948 * @remarks There is a potential race wrt duplicate handles when @a fNoWait is
2949 * @c true, we don't currently care about that oddity...
2950 */
2951DECLHIDDEN(uint32_t) rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
2952{
2953 RTSOCKETINT *pThis = hSocket;
2954 AssertPtrReturn(pThis, UINT32_MAX);
2955 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
2956 /** @todo This isn't quite sane. Replace by critsect and open up concurrent
2957 * reads and writes! */
2958 if (rtSocketTryLock(pThis))
2959 pThis->hPollSet = hPollSet;
2960 else
2961 {
2962 AssertReturn(pThis->hPollSet == hPollSet, UINT32_MAX);
2963 ASMAtomicIncU32(&pThis->cUsers);
2964 }
2965
2966 /* (rtSocketPollCheck will reset the event object). */
2967# ifdef RT_OS_WINDOWS
2968 uint32_t fRetEvents = pThis->fEventsSaved;
2969 pThis->fEventsSaved = 0; /* Reset */
2970 fRetEvents |= rtSocketPollCheck(pThis, fEvents);
2971
2972 if ( !fRetEvents
2973 && !fNoWait)
2974 {
2975 pThis->fPollEvts |= fEvents;
2976 if (fFinalEntry)
2977 {
2978 if (pThis->fSubscribedEvts != pThis->fPollEvts)
2979 {
2980 /** @todo seems like there might be a call to many here and that fPollEvts is
2981 * totally unnecessary... (bird) */
2982 int rc = rtSocketPollUpdateEvents(pThis, pThis->fPollEvts);
2983 if (RT_FAILURE(rc))
2984 {
2985 pThis->fPollEvts = 0;
2986 fRetEvents = UINT32_MAX;
2987 }
2988 }
2989
2990 /* Make sure we don't block when there are events pending relevant to an earlier poll set entry. */
2991 if (pThis->fEventsSaved && !pThis->fPollFallback && g_pfnWSASetEvent && fRetEvents == 0)
2992 g_pfnWSASetEvent(pThis->hEvent);
2993 }
2994 }
2995# else
2996 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
2997# endif
2998
2999 if (fRetEvents || fNoWait)
3000 {
3001 if (pThis->cUsers == 1)
3002 {
3003# ifdef RT_OS_WINDOWS
3004 pThis->fEventsSaved &= RTPOLL_EVT_ERROR;
3005 pThis->fHarvestedEvents = false;
3006 rtSocketPollClearEventAndRestoreBlocking(pThis);
3007# endif
3008 pThis->hPollSet = NIL_RTPOLLSET;
3009 }
3010# ifdef RT_OS_WINDOWS
3011 else
3012 pThis->fHarvestedEvents = true;
3013# endif
3014 ASMAtomicDecU32(&pThis->cUsers);
3015 }
3016# ifdef RT_OS_WINDOWS
3017 /*
3018 * Kick the poller thread on if this is the final entry and we're in
3019 * winsock 1.x fallback mode.
3020 */
3021 else if (pThis->fPollFallback && fFinalEntry)
3022 fRetEvents = rtSocketPollFallbackStart(pThis);
3023# endif
3024
3025 return fRetEvents;
3026}
3027
3028
3029/**
3030 * Called after a WaitForMultipleObjects returned in order to check for pending
3031 * events and stop whatever actions that rtSocketPollStart() initiated.
3032 *
3033 * @returns Event mask or 0.
3034 *
3035 * @param hSocket The socket handle.
3036 * @param fEvents The events we're polling for.
3037 * @param fFinalEntry Set if this is the final entry for this handle
3038 * in this poll set. This can be used for dealing
3039 * with duplicate entries. Only keep in mind that
3040 * this method is called in reverse order, so the
3041 * first call will have this set (when the entire
3042 * set was processed).
3043 * @param fHarvestEvents Set if we should check for pending events.
3044 */
3045DECLHIDDEN(uint32_t) rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
3046{
3047 RTSOCKETINT *pThis = hSocket;
3048 AssertPtrReturn(pThis, 0);
3049 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, 0);
3050 Assert(pThis->cUsers > 0);
3051 Assert(pThis->hPollSet != NIL_RTPOLLSET);
3052 RT_NOREF_PV(fFinalEntry);
3053
3054# ifdef RT_OS_WINDOWS
3055 /*
3056 * Deactivate the poll thread if we're in winsock 1.x fallback poll mode.
3057 */
3058 if ( pThis->fPollFallback
3059 && pThis->hPollFallbackThread != NIL_RTTHREAD)
3060 {
3061 ASMAtomicWriteU32(&pThis->fSubscribedEvts, 0);
3062 if (ASMAtomicXchgBool(&pThis->fPollFallbackActive, false))
3063 rtSocketPokePollFallbackThread(pThis);
3064 }
3065# endif
3066
3067 /*
3068 * Harvest events and clear the event mask for the next round of polling.
3069 */
3070 uint32_t fRetEvents;
3071# ifdef RT_OS_WINDOWS
3072 if (!pThis->fPollFallback)
3073 {
3074 if (!pThis->fHarvestedEvents)
3075 {
3076 fRetEvents = rtSocketPollCheck(pThis, fEvents);
3077 pThis->fHarvestedEvents = true;
3078 }
3079 else
3080 fRetEvents = pThis->fEventsSaved;
3081 if (fHarvestEvents)
3082 fRetEvents &= fEvents;
3083 else
3084 fRetEvents = 0;
3085 pThis->fPollEvts = 0;
3086 }
3087 else
3088# endif
3089 {
3090 if (fHarvestEvents)
3091 fRetEvents = rtSocketPollCheck(pThis, fEvents);
3092 else
3093 fRetEvents = 0;
3094 }
3095
3096 /*
3097 * Make the socket blocking again and unlock the handle.
3098 */
3099 if (pThis->cUsers == 1)
3100 {
3101# ifdef RT_OS_WINDOWS
3102 pThis->fEventsSaved &= RTPOLL_EVT_ERROR;
3103 pThis->fHarvestedEvents = false;
3104 rtSocketPollClearEventAndRestoreBlocking(pThis);
3105# endif
3106 pThis->hPollSet = NIL_RTPOLLSET;
3107 }
3108 ASMAtomicDecU32(&pThis->cUsers);
3109 return fRetEvents;
3110}
3111
3112#endif /* RT_OS_WINDOWS || RT_OS_OS2 */
3113
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