VirtualBox

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

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

IPRT/socket: WSAStartup fix for winsock 1.1 (NT 3.1).

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