VirtualBox

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

Last change on this file since 70485 was 70485, checked in by vboxsync, 7 years ago

iprt/socket.cpp: stupid me

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