VirtualBox

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

Last change on this file since 92258 was 90105, checked in by vboxsync, 3 years ago

iprt/socket.cpp: rtSocketAddrFromNetAddr - oops, fix inverted test in
previous.

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