VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

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

© 2023 Oracle
ContactPrivacy policyTerms of Use