VirtualBox

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

Last change on this file was 100171, checked in by vboxsync, 12 months ago

IPRT: tcp.h+tcp.cpp,socket.h+socket.cpp: Add RTTcpSetKeepAlive() which
allows one to enable or disable sending periodic keep-alive messages on
a socket (SO_KEEPALIVE) as described in RFC 1122. RTTcpSetKeepAlive()
also allows one to adjust several keep-alive options on a per-socket
basis: the idle time before keep-alive probes are sent (TCP_KEEPIDLE
(TCP_KEEPALIVE on macOS)), the amount of time between keep-alive probes
(TCP_KEEPINTVL), and the number of keep-alive probes to send before
closing the connection (TCP_KEEPCNT).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use