VirtualBox

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

Last change on this file since 106579 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 97.3 KB
Line 
1/* $Id: socket.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Network Sockets.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#ifdef RT_OS_WINDOWS
42# include <iprt/win/winsock2.h>
43# include <iprt/win/ws2tcpip.h>
44# include <mstcpip.h> /* for struct tcp_keepalive */
45#else /* !RT_OS_WINDOWS */
46# include <errno.h>
47# include <sys/select.h>
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>
53# ifdef IPRT_WITH_TCPIP_V6
54# include <netinet6/in6.h>
55# endif
56# include <sys/un.h>
57# include <netdb.h>
58# include <unistd.h>
59# include <fcntl.h>
60# include <sys/uio.h>
61# ifndef AF_LOCAL
62# define AF_LOCAL AF_UNIX
63# endif
64#endif /* !RT_OS_WINDOWS */
65#include <limits.h>
66
67#include "internal/iprt.h"
68#include <iprt/socket.h>
69
70#include <iprt/alloca.h>
71#include <iprt/asm.h>
72#include <iprt/assert.h>
73#include <iprt/ctype.h>
74#include <iprt/err.h>
75#include <iprt/mempool.h>
76#include <iprt/poll.h>
77#include <iprt/string.h>
78#include <iprt/thread.h>
79#include <iprt/time.h>
80#include <iprt/mem.h>
81#include <iprt/sg.h>
82#include <iprt/log.h>
83
84#include "internal/magics.h"
85#include "internal/socket.h"
86#include "internal/string.h"
87#ifdef RT_OS_WINDOWS
88# include "win/internal-r3-win.h"
89#endif
90
91
92/*********************************************************************************************************************************
93* Defined Constants And Macros *
94*********************************************************************************************************************************/
95/* non-standard linux stuff (it seems). */
96#ifndef MSG_NOSIGNAL
97# define MSG_NOSIGNAL 0
98#endif
99
100/* Windows has different names for SHUT_XXX. */
101#ifndef SHUT_RDWR
102# ifdef SD_BOTH
103# define SHUT_RDWR SD_BOTH
104# else
105# define SHUT_RDWR 2
106# endif
107#endif
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
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
122
123/* fixup backlevel OSes. */
124#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
125# define socklen_t int
126#endif
127
128/** How many pending connection. */
129#define RTTCP_SERVER_BACKLOG 10
130
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
139
140
141/*********************************************************************************************************************************
142* Structures and Typedefs *
143*********************************************************************************************************************************/
144/**
145 * Socket handle data.
146 *
147 * This is mainly required for implementing RTPollSet on Windows.
148 */
149typedef struct RTSOCKETINT
150{
151 /** Magic number (RTSOCKET_MAGIC). */
152 uint32_t u32Magic;
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). */
157 uint32_t volatile cUsers;
158 /** The native socket handle. */
159 RTSOCKETNATIVE hNative;
160 /** Indicates whether the handle has been closed or not. */
161 bool volatile fClosed;
162 /** Indicates whether the socket is operating in blocking or non-blocking mode
163 * currently. */
164 bool fBlocking;
165 /** Whether to leave the native socket open rather than closing it (for
166 * RTHandleGetStandard). */
167 bool fLeaveOpen;
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
173#ifdef RT_OS_WINDOWS
174 /** The event semaphore we've associated with the socket handle.
175 * This is WSA_INVALID_EVENT if not done. */
176 WSAEVENT hEvent;
177 /** The events we're polling for. */
178 uint32_t fPollEvts;
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;
182 /** Saved events which are only posted once and events harvested for
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... */
190 uint32_t fEventsSaved;
191 /** Set if fEventsSaved contains harvested events (used to avoid multiple
192 * calls to rtSocketPollCheck on the same socket during rtSocketPollDone). */
193 bool fHarvestedEvents;
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;
206#endif /* RT_OS_WINDOWS */
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;
216 struct sockaddr_in IPv4;
217#ifdef IPRT_WITH_TCPIP_V6
218 struct sockaddr_in6 IPv6;
219#endif
220} RTSOCKADDRUNION;
221
222
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
232/*********************************************************************************************************************************
233* Internal Functions *
234*********************************************************************************************************************************/
235#ifdef RT_OS_WINDOWS
236static void rtSocketPokePollFallbackThread(RTSOCKETINT *pThis);
237#endif
238
239
240
241#ifdef RT_OS_WINDOWS
242/**
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 {
276 /* AssertMsg(wsaData.wVersion >= s_awVersions[i]); - triggers with winsock 1.1 */
277 ASMAtomicWriteU32(&g_uWinSockInitedVersion, wsaData.wVersion);
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/**
289 * Get the last error as an iprt status code.
290 *
291 * @returns IPRT status code.
292 */
293DECLINLINE(int) rtSocketError(void)
294{
295#ifdef RT_OS_WINDOWS
296 if (g_pfnWSAGetLastError)
297 return RTErrConvertFromWin32(g_pfnWSAGetLastError());
298 return VERR_NET_IO_ERROR;
299#else
300 return RTErrConvertFromErrno(errno);
301#endif
302}
303
304
305/**
306 * Resets the last error.
307 */
308DECLINLINE(void) rtSocketErrorReset(void)
309{
310#ifdef RT_OS_WINDOWS
311 if (g_pfnWSASetLastError)
312 g_pfnWSASetLastError(0);
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 */
324DECLHIDDEN(int) rtSocketResolverError(void)
325{
326#ifdef RT_OS_WINDOWS
327 if (g_pfnWSAGetLastError)
328 return RTErrConvertFromWin32(g_pfnWSAGetLastError());
329 return VERR_UNRESOLVED_ERROR;
330#else
331 switch (h_errno)
332 {
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:
343 AssertLogRelMsgFailed(("Unhandled error %u\n", h_errno));
344 return VERR_UNRESOLVED_ERROR;
345 }
346#endif
347}
348
349
350/**
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;
369 pAddr->uPort = RT_N2H_U16(pSrc->IPv4.sin_port);
370 pAddr->uAddr.IPv4.u = pSrc->IPv4.sin_addr.s_addr;
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;
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];
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.
397 * @param cbDst The size of the source address.
398 * @param pcbAddr Where to store the size of the returned address.
399 * Optional
400 */
401static int rtSocketAddrFromNetAddr(PCRTNETADDR pAddr, RTSOCKADDRUNION *pDst, size_t cbDst, int *pcbAddr)
402{
403 RT_BZERO(pDst, cbDst);
404 if (pAddr->enmType == RTNETADDRTYPE_IPV4)
405 {
406 if (cbDst < sizeof(struct sockaddr_in))
407 return VERR_BUFFER_OVERFLOW;
408
409 pDst->Addr.sa_family = AF_INET;
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);
414 }
415#ifdef IPRT_WITH_TCPIP_V6
416 else if (pAddr->enmType == RTNETADDRTYPE_IPV6)
417 {
418 if (cbDst < sizeof(struct sockaddr_in6))
419 return VERR_BUFFER_OVERFLOW;
420
421 pDst->Addr.sa_family = AF_INET6;
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);
429 }
430#endif
431 else
432 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
433 return VINF_SUCCESS;
434}
435
436
437/**
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{
447 return ASMAtomicCmpXchgU32(&pThis->cUsers, 1, 0);
448}
449
450
451/**
452 * Unlocks the socket.
453 *
454 * @param pThis The socket structure.
455 */
456DECLINLINE(void) rtSocketUnlock(RTSOCKETINT *pThis)
457{
458 ASMAtomicCmpXchgU32(&pThis->cUsers, 0, 1);
459}
460
461
462/**
463 * The slow path of rtSocketSwitchBlockingMode that does the actual switching.
464 *
465 * @returns IPRT status code.
466 * @param pThis The socket structure.
467 * @param fBlocking The desired mode of operation.
468 * @remarks Do not call directly.
469 */
470static int rtSocketSwitchBlockingModeSlow(RTSOCKETINT *pThis, bool fBlocking)
471{
472#ifdef RT_OS_WINDOWS
473 AssertReturn(g_pfnioctlsocket, VERR_NET_NOT_UNSUPPORTED);
474 u_long uBlocking = fBlocking ? 0 : 1;
475 if (g_pfnioctlsocket(pThis->hNative, FIONBIO, &uBlocking))
476 return rtSocketError();
477
478#else
479 int fFlags = fcntl(pThis->hNative, F_GETFL, 0);
480 if (fFlags == -1)
481 return rtSocketError();
482
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();
489#endif
490
491 pThis->fBlocking = fBlocking;
492 return VINF_SUCCESS;
493}
494
495
496/**
497 * Switches the socket to the desired blocking mode if necessary.
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;
510}
511
512
513/**
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.
519 * @param fLeaveOpen Whether to leave the native socket handle open when
520 * closed.
521 */
522DECLHIDDEN(int) rtSocketCreateForNative(RTSOCKETINT **ppSocket, RTSOCKETNATIVE hNative, bool fLeaveOpen)
523{
524 RTSOCKETINT *pThis = (RTSOCKETINT *)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pThis));
525 if (!pThis)
526 return VERR_NO_MEMORY;
527 pThis->u32Magic = RTSOCKET_MAGIC;
528 pThis->cUsers = 0;
529 pThis->hNative = hNative;
530 pThis->fClosed = false;
531 pThis->fLeaveOpen = fLeaveOpen;
532 pThis->fBlocking = true;
533#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
534 pThis->hPollSet = NIL_RTPOLLSET;
535#endif
536#ifdef RT_OS_WINDOWS
537 pThis->hEvent = WSA_INVALID_EVENT;
538 pThis->fPollEvts = 0;
539 pThis->fSubscribedEvts = 0;
540 pThis->fEventsSaved = 0;
541 pThis->fHarvestedEvents = false;
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;
552#endif
553 *ppSocket = pThis;
554 return VINF_SUCCESS;
555}
556
557
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);
565 return rtSocketCreateForNative(phSocket, uNative, false /*fLeaveOpen*/);
566}
567
568
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.
578 * @param fInheritable Set to true if the socket should be inherted by
579 * child processes, false if not inheritable.
580 */
581DECLHIDDEN(int) rtSocketCreate(PRTSOCKET phSocket, int iDomain, int iType, int iProtocol, bool fInheritable)
582{
583#ifdef RT_OS_WINDOWS
584 AssertReturn(g_pfnsocket, VERR_NET_NOT_UNSUPPORTED);
585 AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
586
587 /* Initialize WinSock. */
588 int rc2 = rtSocketInitWinsock();
589 if (RT_FAILURE(rc2))
590 return rc2;
591#endif
592
593 /*
594 * Create the socket.
595 *
596 * The RTSocketSetInheritance operation isn't necessarily reliable on windows,
597 * so try use WSA_FLAG_NO_HANDLE_INHERIT with WSASocketW when possible.
598 */
599#ifdef RT_OS_WINDOWS
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 }
622#else
623 RTSOCKETNATIVE hNative = socket(iDomain, iType, iProtocol);
624 if (hNative == NIL_RTSOCKETNATIVE)
625 return rtSocketError();
626#endif
627
628 /*
629 * Wrap it.
630 */
631 int rc = rtSocketCreateForNative(phSocket, hNative, false /*fLeaveOpen*/);
632 if (RT_SUCCESS(rc))
633 {
634#ifdef RT_OS_WINDOWS
635 if (fCallSetInheritance)
636#endif
637 RTSocketSetInheritance(*phSocket, fInheritable);
638 }
639 else
640 {
641#ifdef RT_OS_WINDOWS
642 g_pfnclosesocket(hNative);
643#else
644 close(hNative);
645#endif
646 }
647 return rc;
648}
649
650
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.
754 * Note! This isn't TCP per se, but it should fool the users.
755 */
756 int aSockets[2] = { -1, -1 };
757 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, aSockets) == 0)
758 {
759 *phServer = aSockets[0];
760 *phClient = aSockets[1];
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 {
783 rc = rtSocketCreateForNative(phServer, hServer, false /*fLeaveOpen*/);
784 if (RT_SUCCESS(rc))
785 {
786 rc = rtSocketCreateForNative(phClient, hClient, false /*fLeaveOpen*/);
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
812RTDECL(uint32_t) RTSocketRetain(RTSOCKET hSocket)
813{
814 RTSOCKETINT *pThis = hSocket;
815 AssertPtrReturn(pThis, UINT32_MAX);
816 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
817 return RTMemPoolRetain(pThis);
818}
819
820
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{
830 /*
831 * Invalidate the handle structure on destroy.
832 */
833 if (fDestroy)
834 {
835 Assert(ASMAtomicReadU32(&pThis->u32Magic) == RTSOCKET_MAGIC);
836 ASMAtomicWriteU32(&pThis->u32Magic, RTSOCKET_MAGIC_DEAD);
837 }
838
839 int rc = VINF_SUCCESS;
840 if (ASMAtomicCmpXchgBool(&pThis->fClosed, true, false))
841 {
842#ifdef RT_OS_WINDOWS
843 /*
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 /*
858 * Close the native handle.
859 */
860 RTSOCKETNATIVE hNative = pThis->hNative;
861 if (hNative != NIL_RTSOCKETNATIVE)
862 {
863 pThis->hNative = NIL_RTSOCKETNATIVE;
864
865 if (!pThis->fLeaveOpen)
866 {
867#ifdef RT_OS_WINDOWS
868 AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
869 if (g_pfnclosesocket(hNative))
870#else
871 if (close(hNative))
872#endif
873 {
874 rc = rtSocketError();
875#ifdef RT_OS_WINDOWS
876 AssertMsgFailed(("closesocket(%p) -> %Rrc\n", (uintptr_t)hNative, rc));
877#else
878 AssertMsgFailed(("close(%d) -> %Rrc\n", hNative, rc));
879#endif
880 }
881 }
882 }
883
884#ifdef RT_OS_WINDOWS
885 /*
886 * Windows specific polling cleanup.
887 */
888 WSAEVENT hEvent = pThis->hEvent;
889 if (hEvent != WSA_INVALID_EVENT)
890 {
891 pThis->hEvent = WSA_INVALID_EVENT;
892 if (!pThis->fPollFallback)
893 {
894 Assert(g_pfnWSACloseEvent);
895 if (g_pfnWSACloseEvent)
896 g_pfnWSACloseEvent(hEvent);
897 }
898 else
899 CloseHandle(hEvent);
900 }
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 }
923#endif
924 }
925
926 return rc;
927}
928
929
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
966RTDECL(RTHCUINTPTR) RTSocketToNative(RTSOCKET hSocket)
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
975RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable)
976{
977 RTSOCKETINT *pThis = hSocket;
978 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
979 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
980 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
981
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;
986#else
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;
1013#endif
1014}
1015
1016
1017static bool rtSocketIsIPv4Numerical(const char *pszAddress, PRTNETADDRIPV4 pAddr)
1018{
1019
1020 /* Empty address resolves to the INADDR_ANY address (good for bind). */
1021 if (!pszAddress || !*pszAddress)
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);
1033 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
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
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);
1053 AssertPtrNullReturn(pszAddress, VERR_INVALID_POINTER);
1054
1055 /*
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.
1059 */
1060 /** @todo this only supports IPv4, and IPv6 support needs to be added.
1061 * It probably needs to be converted to getaddrinfo(). */
1062 RTNETADDRIPV4 IPv4Quad;
1063 if (rtSocketIsIPv4Numerical(pszAddress, &IPv4Quad))
1064 {
1065 Log3(("rtSocketIsIPv4Numerical: %s -> %#x (%RTnaipv4)\n", pszAddress, IPv4Quad.u, IPv4Quad));
1066 RT_ZERO(*pAddr);
1067 pAddr->enmType = RTNETADDRTYPE_IPV4;
1068 pAddr->uPort = uPort;
1069 pAddr->uAddr.IPv4 = IPv4Quad;
1070 return VINF_SUCCESS;
1071 }
1072
1073#ifdef RT_OS_WINDOWS
1074 /* Initialize WinSock and check version before we call gethostbyname. */
1075 if (!g_pfngethostbyname)
1076 return VERR_NET_NOT_UNSUPPORTED;
1077
1078 int rc2 = rtSocketInitWinsock();
1079 if (RT_FAILURE(rc2))
1080 return rc2;
1081
1082# define gethostbyname g_pfngethostbyname
1083#endif
1084
1085 struct hostent *pHostEnt;
1086 pHostEnt = gethostbyname(pszAddress);
1087 if (!pHostEnt)
1088 {
1089 rc = rtSocketResolverError();
1090 AssertMsg(rc == VERR_NET_HOST_NOT_FOUND,
1091 ("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
1092 return rc;
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;
1101 Log3(("gethostbyname: %s -> %#x (%RTnaipv4)\n", pszAddress, pAddr->uAddr.IPv4.u, pAddr->uAddr.IPv4));
1102 }
1103 else
1104 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
1105
1106#ifdef RT_OS_WINDOWS
1107# undef gethostbyname
1108#endif
1109 return VINF_SUCCESS;
1110}
1111
1112
1113/*
1114 * New function to allow both ipv4 and ipv6 addresses to be resolved.
1115 * Breaks compatibility with windows before 2000.
1116 */
1117RTDECL(int) RTSocketQueryAddressStr(const char *pszHost, char *pszResult, size_t *pcbResult, PRTNETADDRTYPE penmAddrType)
1118{
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
1124#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) /** @todo dynamically resolve the APIs not present in NT4! */
1125 return VERR_NOT_SUPPORTED;
1126
1127#else
1128 int rc;
1129 if (*pcbResult < 16)
1130 return VERR_NET_ADDRESS_NOT_AVAILABLE;
1131
1132 /* Setup the hint. */
1133 struct addrinfo grHints;
1134 RT_ZERO(grHints);
1135 grHints.ai_socktype = 0;
1136 grHints.ai_flags = 0;
1137 grHints.ai_protocol = 0;
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 }
1156
1157# ifdef RT_OS_WINDOWS
1158 /*
1159 * Winsock2 init
1160 */
1161 if ( !g_pfngetaddrinfo
1162 || !g_pfnfreeaddrinfo)
1163 return VERR_NET_NOT_UNSUPPORTED;
1164
1165 int rc2 = rtSocketInitWinsock();
1166 if (RT_FAILURE(rc2))
1167 return rc2;
1168
1169# define getaddrinfo g_pfngetaddrinfo
1170# define freeaddrinfo g_pfnfreeaddrinfo
1171# endif
1172
1173 /** @todo r=bird: getaddrinfo and freeaddrinfo breaks the additions on NT4. */
1174 struct addrinfo *pgrResults = NULL;
1175 rc = getaddrinfo(pszHost, "", &grHints, &pgrResults);
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
1185 struct addrinfo const *pgrResult = pgrResults->ai_next;
1186 if (!pgrResult)
1187 {
1188 freeaddrinfo(pgrResults);
1189 return VERR_NET_ADDRESS_NOT_AVAILABLE;
1190 }
1191
1192 RTNETADDRTYPE enmAddrType = RTNETADDRTYPE_INVALID;
1193 size_t cchIpAddress;
1194 char szIpAddress[48];
1195 if (pgrResult->ai_family == AF_INET)
1196 {
1197 struct sockaddr_in const *pgrSa = (struct sockaddr_in const *)pgrResult->ai_addr;
1198 cchIpAddress = RTStrPrintf(szIpAddress, sizeof(szIpAddress),
1199 "%RTnaipv4", pgrSa->sin_addr.s_addr);
1200 Assert(cchIpAddress >= 7 && cchIpAddress < sizeof(szIpAddress) - 1);
1201 enmAddrType = RTNETADDRTYPE_IPV4;
1202 rc = VINF_SUCCESS;
1203 }
1204 else if (pgrResult->ai_family == AF_INET6)
1205 {
1206 struct sockaddr_in6 const *pgrSa6 = (struct sockaddr_in6 const *)pgrResult->ai_addr;
1207 cchIpAddress = RTStrPrintf(szIpAddress, sizeof(szIpAddress),
1208 "%RTnaipv6", (PRTNETADDRIPV6)&pgrSa6->sin6_addr);
1209 enmAddrType = RTNETADDRTYPE_IPV6;
1210 rc = VINF_SUCCESS;
1211 }
1212 else
1213 {
1214 rc = VERR_NET_ADDRESS_NOT_AVAILABLE;
1215 szIpAddress[0] = '\0';
1216 cchIpAddress = 0;
1217 }
1218 freeaddrinfo(pgrResults);
1219
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
1228 {
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;
1236
1237# ifdef RT_OS_WINDOWS
1238# undef getaddrinfo
1239# undef freeaddrinfo
1240# endif
1241#endif /* !RT_OS_OS2 */
1242}
1243
1244
1245RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
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);
1255#ifdef RT_OS_WINDOWS
1256 AssertReturn(g_pfnrecv, VERR_NET_NOT_UNSUPPORTED);
1257# define recv g_pfnrecv
1258#endif
1259 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1260
1261 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
1262 if (RT_FAILURE(rc))
1263 return rc;
1264
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();
1274#ifdef RTSOCKET_MAX_READ
1275 int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead;
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);
1313#ifdef RT_OS_WINDOWS
1314# undef recv
1315#endif
1316 return rc;
1317}
1318
1319
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);
1331#ifdef RT_OS_WINDOWS
1332 AssertReturn(g_pfnrecvfrom, VERR_NET_NOT_UNSUPPORTED);
1333# define recvfrom g_pfnrecvfrom
1334#endif
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;
1348#ifdef RTSOCKET_MAX_READ
1349 int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead;
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);
1374#ifdef RT_OS_WINDOWS
1375# undef recvfrom
1376#endif
1377 return rc;
1378}
1379
1380
1381RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer)
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);
1389#ifdef RT_OS_WINDOWS
1390 AssertReturn(g_pfnsend, VERR_NET_NOT_UNSUPPORTED);
1391# define send g_pfnsend
1392#endif
1393 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1394
1395 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
1396 if (RT_FAILURE(rc))
1397 return rc;
1398
1399 /*
1400 * Try write all at once.
1401 */
1402#ifdef RTSOCKET_MAX_WRITE
1403 int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
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 */
1429#ifdef RTSOCKET_MAX_WRITE
1430 cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
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);
1450#ifdef RT_OS_WINDOWS
1451# undef send
1452#endif
1453 return rc;
1454}
1455
1456
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);
1465#ifdef RT_OS_WINDOWS
1466 AssertReturn(g_pfnsendto, VERR_NET_NOT_UNSUPPORTED);
1467# define sendto g_pfnsendto
1468#endif
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 {
1487 rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), NULL);
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
1498 int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
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
1510 /// @todo rtSocketUnlock(pThis);
1511#ifdef RT_OS_WINDOWS
1512# undef sendto
1513#endif
1514 return rc;
1515}
1516
1517
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);
1526#ifdef RT_OS_WINDOWS
1527 AssertReturn(g_pfnsendto, VERR_NET_NOT_UNSUPPORTED);
1528# define sendto g_pfnsendto
1529#endif
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
1571 /// @todo rtSocketUnlock(pThis);
1572#ifdef RT_OS_WINDOWS
1573# undef sendto
1574#endif
1575 return rc;
1576}
1577
1578
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);
1588 AssertReturn(pSgBuf->cSegs > 0, VERR_INVALID_PARAMETER);
1589 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1590
1591 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
1592 if (RT_FAILURE(rc))
1593 return rc;
1594
1595 /*
1596 * Construct message descriptor (translate pSgBuf) and send it.
1597 */
1598 rc = VERR_NO_TMP_MEMORY;
1599#ifdef RT_OS_WINDOWS
1600 if (g_pfnWSASend)
1601 {
1602 AssertCompileSize(WSABUF, sizeof(RTSGSEG));
1603 AssertCompileMemberSize(WSABUF, buf, RT_SIZEOFMEMB(RTSGSEG, pvSeg));
1604
1605 LPWSABUF paMsg = (LPWSABUF)RTMemTmpAllocZ(pSgBuf->cSegs * sizeof(WSABUF));
1606 if (paMsg)
1607 {
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 }
1613
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();
1621
1622 RTMemTmpFree(paMsg);
1623 }
1624 }
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
1651 rc = VERR_NET_NOT_UNSUPPORTED;
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++)
1662 {
1663 paMsg[i].iov_base = pSgBuf->paSegs[i].pvSeg;
1664 paMsg[i].iov_len = pSgBuf->paSegs[i].cbSeg;
1665 }
1666
1667 struct msghdr msgHdr;
1668 RT_ZERO(msgHdr);
1669 msgHdr.msg_iov = paMsg;
1670 msgHdr.msg_iovlen = pSgBuf->cSegs;
1671 ssize_t cbWritten = sendmsg(pThis->hNative, &msgHdr, MSG_NOSIGNAL);
1672 if (RT_LIKELY(cbWritten >= 0))
1673 rc = VINF_SUCCESS;
1674/** @todo check for incomplete writes */
1675 else
1676 rc = rtSocketError();
1677
1678 RTMemTmpFree(paMsg);
1679 }
1680#endif /* !RT_OS_WINDOWS */
1681
1682 rtSocketUnlock(pThis);
1683 return rc;
1684}
1685
1686
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
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);
1729#ifdef RT_OS_WINDOWS
1730 AssertReturn(g_pfnrecv, VERR_NET_NOT_UNSUPPORTED);
1731#endif
1732 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1733
1734 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1735 if (RT_FAILURE(rc))
1736 return rc;
1737
1738 rtSocketErrorReset();
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
1745#ifdef RT_OS_WINDOWS
1746 int cbRead = g_pfnrecv(pThis->hNative, (char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1747 if (cbRead >= 0)
1748 {
1749 *pcbRead = cbRead;
1750 rc = VINF_SUCCESS;
1751 }
1752 else
1753 {
1754 rc = rtSocketError();
1755 if (rc == VERR_TRY_AGAIN)
1756 {
1757 *pcbRead = 0;
1758 rc = VINF_TRY_AGAIN;
1759 }
1760 }
1761
1762#else
1763 ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbNow, MSG_NOSIGNAL);
1764 if (cbRead >= 0)
1765 *pcbRead = cbRead;
1766 else if ( errno == EAGAIN
1767# ifdef EWOULDBLOCK
1768# if EWOULDBLOCK != EAGAIN
1769 || errno == EWOULDBLOCK
1770# endif
1771# endif
1772 )
1773 {
1774 *pcbRead = 0;
1775 rc = VINF_TRY_AGAIN;
1776 }
1777 else
1778 rc = rtSocketError();
1779#endif
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);
1795#ifdef RT_OS_WINDOWS
1796 AssertReturn(g_pfnsend, VERR_NET_NOT_UNSUPPORTED);
1797#endif
1798 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1799
1800 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1801 if (RT_FAILURE(rc))
1802 return rc;
1803
1804 rtSocketErrorReset();
1805#ifdef RT_OS_WINDOWS
1806# ifdef RTSOCKET_MAX_WRITE
1807 int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer;
1808# else
1809 size_t cbNow = cbBuffer;
1810# endif
1811 int cbWritten = g_pfnsend(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1812 if (cbWritten >= 0)
1813 {
1814 *pcbWritten = cbWritten;
1815 rc = VINF_SUCCESS;
1816 }
1817 else
1818 {
1819 rc = rtSocketError();
1820 if (rc == VERR_TRY_AGAIN)
1821 {
1822 *pcbWritten = 0;
1823 rc = VINF_TRY_AGAIN;
1824 }
1825 }
1826#else
1827 ssize_t cbWritten = send(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL);
1828 if (cbWritten >= 0)
1829 *pcbWritten = cbWritten;
1830 else if ( errno == EAGAIN
1831# ifdef EWOULDBLOCK
1832# if EWOULDBLOCK != EAGAIN
1833 || errno == EWOULDBLOCK
1834# endif
1835# endif
1836 )
1837 {
1838 *pcbWritten = 0;
1839 rc = VINF_TRY_AGAIN;
1840 }
1841 else
1842 rc = rtSocketError();
1843#endif
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
1867 unsigned cSegsToSend = 0;
1868 rc = VERR_NO_TMP_MEMORY;
1869#ifdef RT_OS_WINDOWS
1870 if (g_pfnWSASend)
1871 {
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();
1882
1883 *pcbWritten = dwSent;
1884
1885 RTMemTmpFree(paMsg);
1886 }
1887 }
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
1919 rc = VERR_NET_NOT_UNSUPPORTED;
1920
1921#else /* !RT_OS_WINDOWS */
1922 struct iovec *paMsg = NULL;
1923
1924 RTSgBufMapToNative(paMsg, pSgBuf, struct iovec, iov_base, void *, iov_len, size_t, cSegsToSend);
1925 if (paMsg)
1926 {
1927 struct msghdr msgHdr;
1928 RT_ZERO(msgHdr);
1929 msgHdr.msg_iov = paMsg;
1930 msgHdr.msg_iovlen = cSegsToSend;
1931 ssize_t cbWritten = sendmsg(pThis->hNative, &msgHdr, MSG_NOSIGNAL);
1932 if (RT_LIKELY(cbWritten >= 0))
1933 {
1934 rc = VINF_SUCCESS;
1935 *pcbWritten = cbWritten;
1936 }
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
1980RTDECL(int) RTSocketSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies)
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);
1988 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1989 int const fdMax = (int)pThis->hNative + 1;
1990 AssertReturn((RTSOCKETNATIVE)(fdMax - 1) == pThis->hNative, VERR_INTERNAL_ERROR_5);
1991#ifdef RT_OS_WINDOWS
1992 AssertReturn(g_pfnselect, VERR_NET_NOT_UNSUPPORTED);
1993# define select g_pfnselect
1994#endif
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)
2007 rc = select(fdMax, &fdsetR, NULL, &fdsetE, NULL);
2008 else
2009 {
2010 struct timeval timeout;
2011 timeout.tv_sec = cMillies / 1000;
2012 timeout.tv_usec = (cMillies % 1000) * 1000;
2013 rc = select(fdMax, &fdsetR, NULL, &fdsetE, &timeout);
2014 }
2015 if (rc > 0)
2016 rc = VINF_SUCCESS;
2017 else if (rc == 0)
2018 rc = VERR_TIMEOUT;
2019 else
2020 rc = rtSocketError();
2021
2022#ifdef RT_OS_WINDOWS
2023# undef select
2024#endif
2025 return rc;
2026}
2027
2028
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)
2039{
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);
2051#ifdef RT_OS_WINDOWS
2052 AssertReturn(g_pfnselect, VERR_NET_NOT_UNSUPPORTED);
2053 AssertReturn(g_pfn__WSAFDIsSet, VERR_NET_NOT_UNSUPPORTED);
2054# define select g_pfnselect
2055# define __WSAFDIsSet g_pfn__WSAFDIsSet
2056#endif
2057
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)
2071 FD_SET(hNative, &fdsetR);
2072 if (fEvents & RTSOCKET_EVT_WRITE)
2073 FD_SET(hNative, &fdsetW);
2074 if (fEvents & RTSOCKET_EVT_ERROR)
2075 FD_SET(hNative, &fdsetE);
2076
2077 int rc;
2078 if (cMillies == RT_INDEFINITE_WAIT)
2079 rc = select(fdMax, &fdsetR, &fdsetW, &fdsetE, NULL);
2080 else
2081 {
2082 struct timeval timeout;
2083 timeout.tv_sec = cMillies / 1000;
2084 timeout.tv_usec = (cMillies % 1000) * 1000;
2085 rc = select(fdMax, &fdsetR, &fdsetW, &fdsetE, &timeout);
2086 }
2087 if (rc > 0)
2088 {
2089 if (pThis->hNative == hNative)
2090 {
2091 if (FD_ISSET(hNative, &fdsetR))
2092 *pfEvents |= RTSOCKET_EVT_READ;
2093 if (FD_ISSET(hNative, &fdsetW))
2094 *pfEvents |= RTSOCKET_EVT_WRITE;
2095 if (FD_ISSET(hNative, &fdsetE))
2096 *pfEvents |= RTSOCKET_EVT_ERROR;
2097 rc = VINF_SUCCESS;
2098 }
2099 else
2100 {
2101 /* Socket was closed while we waited (rtSocketCloseIt). Different status code? */
2102 *pfEvents = RTSOCKET_EVT_ERROR;
2103 rc = VINF_SUCCESS;
2104 }
2105 }
2106 else if (rc == 0)
2107 rc = VERR_TIMEOUT;
2108 else
2109 rc = rtSocketError();
2110
2111#ifdef RT_OS_WINDOWS
2112# undef select
2113# undef __WSAFDIsSet
2114#endif
2115 return rc;
2116}
2117
2118
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
2135RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite)
2136{
2137 /*
2138 * Validate input, don't lock it because we might want to interrupt a call
2139 * active on a different thread.
2140 */
2141 RTSOCKETINT *pThis = hSocket;
2142 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2143 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2144 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
2145 AssertReturn(fRead || fWrite, VERR_INVALID_PARAMETER);
2146#ifdef RT_OS_WINDOWS
2147 AssertReturn(g_pfnshutdown, VERR_NET_NOT_UNSUPPORTED);
2148# define shutdown g_pfnshutdown
2149#endif
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
2165#ifdef RT_OS_WINDOWS
2166# undef shutdown
2167#endif
2168 return rc;
2169}
2170
2171
2172RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
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);
2180 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
2181#ifdef RT_OS_WINDOWS
2182 AssertReturn(g_pfngetsockname, VERR_NET_NOT_UNSUPPORTED);
2183# define getsockname g_pfngetsockname
2184#endif
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)
2198 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
2199 else
2200 rc = rtSocketError();
2201
2202#ifdef RT_OS_WINDOWS
2203# undef getsockname
2204#endif
2205 return rc;
2206}
2207
2208
2209RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
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);
2217 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
2218#ifdef RT_OS_WINDOWS
2219 AssertReturn(g_pfngetpeername, VERR_NET_NOT_UNSUPPORTED);
2220# define getpeername g_pfngetpeername
2221#endif
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)
2235 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
2236 else
2237 rc = rtSocketError();
2238
2239#ifdef RT_OS_WINDOWS
2240# undef getpeername
2241#endif
2242 return rc;
2243}
2244
2245
2246
2247/**
2248 * Wrapper around bind.
2249 *
2250 * @returns IPRT status code.
2251 * @param hSocket The socket handle.
2252 * @param pAddr The address to bind to.
2253 */
2254DECLHIDDEN(int) rtSocketBind(RTSOCKET hSocket, PCRTNETADDR pAddr)
2255{
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 */
2274DECLHIDDEN(int) rtSocketBindRawAddr(RTSOCKET hSocket, void const *pvAddr, size_t cbAddr)
2275{
2276 /*
2277 * Validate input.
2278 */
2279 RTSOCKETINT *pThis = hSocket;
2280 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2281 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2282 AssertPtrReturn(pvAddr, VERR_INVALID_POINTER);
2283#ifdef RT_OS_WINDOWS
2284 AssertReturn(g_pfnbind, VERR_NET_NOT_UNSUPPORTED);
2285# define bind g_pfnbind
2286#endif
2287 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2288
2289 int rc;
2290 if (bind(pThis->hNative, (struct sockaddr const *)pvAddr, (int)cbAddr) == 0)
2291 rc = VINF_SUCCESS;
2292 else
2293 rc = rtSocketError();
2294
2295 rtSocketUnlock(pThis);
2296#ifdef RT_OS_WINDOWS
2297# undef bind
2298#endif
2299 return rc;
2300}
2301
2302
2303
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 */
2311DECLHIDDEN(int) rtSocketListen(RTSOCKET hSocket, int cMaxPending)
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);
2319#ifdef RT_OS_WINDOWS
2320 AssertReturn(g_pfnlisten, VERR_NET_NOT_UNSUPPORTED);
2321# define listen g_pfnlisten
2322#endif
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);
2330#ifdef RT_OS_WINDOWS
2331# undef listen
2332#endif
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 */
2349DECLHIDDEN(int) rtSocketAccept(RTSOCKET hSocket, PRTSOCKET phClient, struct sockaddr *pAddr, size_t *pcbAddr)
2350{
2351 /*
2352 * Validate input.
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.
2355 */
2356 RTSOCKETINT *pThis = hSocket;
2357 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2358 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2359#ifdef RT_OS_WINDOWS
2360 AssertReturn(g_pfnaccept, VERR_NET_NOT_UNSUPPORTED);
2361 AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
2362# define accept g_pfnaccept
2363#endif
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
2376 RTSOCKETNATIVE hNativeClient = accept(pThis->hNative, pAddr, &cbAddr);
2377 if (hNativeClient != NIL_RTSOCKETNATIVE)
2378 {
2379 *pcbAddr = cbAddr;
2380
2381 /*
2382 * Wrap the client socket.
2383 */
2384 rc = rtSocketCreateForNative(phClient, hNativeClient, false /*fLeaveOpen*/);
2385 if (RT_FAILURE(rc))
2386 {
2387#ifdef RT_OS_WINDOWS
2388 g_pfnclosesocket(hNativeClient);
2389#else
2390 close(hNativeClient);
2391#endif
2392 }
2393 }
2394 else
2395 rc = rtSocketError();
2396
2397 rtSocketUnlock(pThis);
2398#ifdef RT_OS_WINDOWS
2399# undef accept
2400#endif
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.
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.
2415 */
2416DECLHIDDEN(int) rtSocketConnect(RTSOCKET hSocket, PCRTNETADDR pAddr, RTMSINTERVAL cMillies)
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);
2424#ifdef RT_OS_WINDOWS
2425 AssertReturn(g_pfnconnect, VERR_NET_NOT_UNSUPPORTED);
2426 AssertReturn(g_pfnselect, VERR_NET_NOT_UNSUPPORTED);
2427 AssertReturn(g_pfngetsockopt, VERR_NET_NOT_UNSUPPORTED);
2428# define connect g_pfnconnect
2429# define select g_pfnselect
2430# define getsockopt g_pfngetsockopt
2431#endif
2432 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2433
2434 RTSOCKADDRUNION u;
2435 int cbAddr;
2436 int rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), &cbAddr);
2437 if (RT_SUCCESS(rc))
2438 {
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);
2478 rcSock = getsockopt(pThis->hNative, SOL_SOCKET, SO_ERROR, (char *)&iSockError, &cbSockOpt);
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 }
2506 }
2507
2508 rtSocketUnlock(pThis);
2509#ifdef RT_OS_WINDOWS
2510# undef connect
2511# undef select
2512# undef getsockopt
2513#endif
2514 return rc;
2515}
2516
2517
2518/**
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);
2534#ifdef RT_OS_WINDOWS
2535 AssertReturn(g_pfnconnect, VERR_NET_NOT_UNSUPPORTED);
2536# define connect g_pfnconnect
2537#endif
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);
2547#ifdef RT_OS_WINDOWS
2548# undef connect
2549#endif
2550 return rc;
2551}
2552
2553
2554/**
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 */
2564DECLHIDDEN(int) rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValue, int cbValue)
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);
2572#ifdef RT_OS_WINDOWS
2573 AssertReturn(g_pfnsetsockopt, VERR_NET_NOT_UNSUPPORTED);
2574# define setsockopt g_pfnsetsockopt
2575#endif
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);
2583#ifdef RT_OS_WINDOWS
2584# undef setsockopt
2585#endif
2586 return rc;
2587}
2588
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.
2597 * @param phNative Where to put the primary handle.
2598 */
2599DECLHIDDEN(int) rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PRTHCINTPTR phNative)
2600{
2601 RTSOCKETINT *pThis = hSocket;
2602 RT_NOREF_PV(fEvents);
2603 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2604 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
2605#ifdef RT_OS_WINDOWS
2606 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
2607
2608 int rc = VINF_SUCCESS;
2609 if (pThis->hEvent != WSA_INVALID_EVENT)
2610 *phNative = (RTHCINTPTR)pThis->hEvent;
2611 else if (g_pfnWSACreateEvent)
2612 {
2613 pThis->hEvent = g_pfnWSACreateEvent();
2614 *phNative = (RTHCINTPTR)pThis->hEvent;
2615 if (pThis->hEvent == WSA_INVALID_EVENT)
2616 rc = rtSocketError();
2617 }
2618 else
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 }
2626
2627 rtSocketUnlock(pThis);
2628 return rc;
2629
2630#else /* !RT_OS_WINDOWS */
2631 *phNative = (RTHCUINTPTR)pThis->hNative;
2632 return VINF_SUCCESS;
2633#endif /* !RT_OS_WINDOWS */
2634}
2635
2636#ifdef RT_OS_WINDOWS
2637
2638/**
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/**
2792 * Undos the harm done by WSAEventSelect.
2793 *
2794 * @returns IPRT status code.
2795 * @param pThis The socket handle.
2796 */
2797static int rtSocketPollClearEventAndRestoreBlocking(RTSOCKETINT *pThis)
2798{
2799 int rc = VINF_SUCCESS;
2800 if (pThis->fSubscribedEvts)
2801 {
2802 if (!pThis->fPollFallback)
2803 {
2804 Assert(g_pfnWSAEventSelect && g_pfnioctlsocket);
2805 if (g_pfnWSAEventSelect && g_pfnioctlsocket)
2806 {
2807 if (g_pfnWSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
2808 {
2809 pThis->fSubscribedEvts = 0;
2810
2811 /*
2812 * Switch back to blocking mode if that was the state before the
2813 * operation.
2814 */
2815 if (pThis->fBlocking)
2816 {
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 }
2824 }
2825 }
2826 else
2827 {
2828 rc = rtSocketError();
2829 AssertMsgFailed(("%Rrc\n", rc));
2830 }
2831 }
2832 else
2833 {
2834 Assert(pThis->fPollFallback);
2835 rc = VINF_SUCCESS;
2836 }
2837 }
2838 /*
2839 * Just clear the event mask as we never started waiting if we get here.
2840 */
2841 else
2842 ASMAtomicWriteU32(&pThis->fSubscribedEvts, 0);
2843 }
2844 return rc;
2845}
2846
2847
2848/**
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{
2857 if (!pThis->fPollFallback)
2858 {
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
2868 if (g_pfnWSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
2869 {
2870 pThis->fSubscribedEvts = fEvents;
2871 return VINF_SUCCESS;
2872 }
2873
2874 int rc = rtSocketError();
2875 AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
2876 return rc;
2877 }
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;
2884}
2885
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
2914#endif /* RT_OS_WINDOWS */
2915
2916
2917#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
2918
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{
2928 uint32_t fRetEvents = 0;
2929
2930 LogFlowFunc(("pThis=%#p fEvents=%#x\n", pThis, fEvents));
2931
2932# ifdef RT_OS_WINDOWS
2933 /* Make sure WSAEnumNetworkEvents returns what we want. */
2934 int rc = VINF_SUCCESS;
2935 if ((pThis->fSubscribedEvts & fEvents) != fEvents)
2936 rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
2937
2938 if (!pThis->fPollFallback)
2939 {
2940 /* Atomically get pending events and reset the event semaphore. */
2941 Assert(g_pfnWSAEnumNetworkEvents);
2942 WSANETWORKEVENTS NetEvts;
2943 RT_ZERO(NetEvts);
2944 if (g_pfnWSAEnumNetworkEvents(pThis->hNative, pThis->hEvent, &NetEvts) == 0)
2945 {
2946 if ( (NetEvts.lNetworkEvents & FD_READ)
2947 && NetEvts.iErrorCode[FD_READ_BIT] == 0)
2948 fRetEvents |= RTPOLL_EVT_READ;
2949
2950 if ( (NetEvts.lNetworkEvents & FD_WRITE)
2951 && NetEvts.iErrorCode[FD_WRITE_BIT] == 0)
2952 fRetEvents |= RTPOLL_EVT_WRITE;
2953
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;
2963 fRetEvents &= fEvents | RTPOLL_EVT_ERROR;
2964 }
2965 else
2966 rc = rtSocketError();
2967 }
2968
2969 /* Fall back on select if we hit an error above or is using fallback polling. */
2970 if (pThis->fPollFallback || RT_FAILURE(rc))
2971 {
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;
2999 rc = g_pfnioctlsocket(pThis->hNative, FIONREAD, &cbAvail);
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)
3006 fRetEvents = 0;
3007 else
3008 fRetEvents |= RTPOLL_EVT_ERROR;
3009 }
3010
3011# else /* RT_OS_OS2 */
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 }
3024# endif /* RT_OS_OS2 */
3025
3026 LogFlowFunc(("fRetEvents=%#x\n", fRetEvents));
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 */
3053DECLHIDDEN(uint32_t) rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
3054{
3055 RTSOCKETINT *pThis = hSocket;
3056 AssertPtrReturn(pThis, UINT32_MAX);
3057 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
3058 /** @todo This isn't quite sane. Replace by critsect and open up concurrent
3059 * reads and writes! */
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). */
3069# ifdef RT_OS_WINDOWS
3070 uint32_t fRetEvents = pThis->fEventsSaved;
3071 pThis->fEventsSaved = 0; /* Reset */
3072 fRetEvents |= rtSocketPollCheck(pThis, fEvents);
3073
3074 if ( !fRetEvents
3075 && !fNoWait)
3076 {
3077 pThis->fPollEvts |= fEvents;
3078 if (fFinalEntry)
3079 {
3080 if (pThis->fSubscribedEvts != pThis->fPollEvts)
3081 {
3082 /** @todo seems like there might be a call to many here and that fPollEvts is
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 }
3090 }
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);
3095 }
3096 }
3097# else
3098 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
3099# endif
3100
3101 if (fRetEvents || fNoWait)
3102 {
3103 if (pThis->cUsers == 1)
3104 {
3105# ifdef RT_OS_WINDOWS
3106 pThis->fEventsSaved &= RTPOLL_EVT_ERROR;
3107 pThis->fHarvestedEvents = false;
3108 rtSocketPollClearEventAndRestoreBlocking(pThis);
3109# endif
3110 pThis->hPollSet = NIL_RTPOLLSET;
3111 }
3112# ifdef RT_OS_WINDOWS
3113 else
3114 pThis->fHarvestedEvents = true;
3115# endif
3116 ASMAtomicDecU32(&pThis->cUsers);
3117 }
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
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).
3145 * @param fHarvestEvents Set if we should check for pending events.
3146 */
3147DECLHIDDEN(uint32_t) rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
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);
3154 RT_NOREF_PV(fFinalEntry);
3155
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 */
3172 uint32_t fRetEvents;
3173# ifdef RT_OS_WINDOWS
3174 if (!pThis->fPollFallback)
3175 {
3176 if (!pThis->fHarvestedEvents)
3177 {
3178 fRetEvents = rtSocketPollCheck(pThis, fEvents);
3179 pThis->fHarvestedEvents = true;
3180 }
3181 else
3182 fRetEvents = pThis->fEventsSaved;
3183 if (fHarvestEvents)
3184 fRetEvents &= fEvents;
3185 else
3186 fRetEvents = 0;
3187 pThis->fPollEvts = 0;
3188 }
3189 else
3190# endif
3191 {
3192 if (fHarvestEvents)
3193 fRetEvents = rtSocketPollCheck(pThis, fEvents);
3194 else
3195 fRetEvents = 0;
3196 }
3197
3198 /*
3199 * Make the socket blocking again and unlock the handle.
3200 */
3201 if (pThis->cUsers == 1)
3202 {
3203# ifdef RT_OS_WINDOWS
3204 pThis->fEventsSaved &= RTPOLL_EVT_ERROR;
3205 pThis->fHarvestedEvents = false;
3206 rtSocketPollClearEventAndRestoreBlocking(pThis);
3207# endif
3208 pThis->hPollSet = NIL_RTPOLLSET;
3209 }
3210 ASMAtomicDecU32(&pThis->cUsers);
3211 return fRetEvents;
3212}
3213
3214#endif /* RT_OS_WINDOWS || RT_OS_OS2 */
3215
Note: See TracBrowser for help on using the repository browser.

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