VirtualBox

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

Last change on this file since 95685 was 94839, checked in by vboxsync, 2 years ago

Runtime/socket.cpp: Relax annoying assertion

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