VirtualBox

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

Last change on this file since 39801 was 39801, checked in by vboxsync, 13 years ago

IPRT: socket / address resolving fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 53.1 KB
Line 
1/* $Id: socket.cpp 39801 2012-01-18 18:01:11Z vboxsync $ */
2/** @file
3 * IPRT - Network Sockets.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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 <winsock2.h>
33#else /* !RT_OS_WINDOWS */
34# include <errno.h>
35# include <sys/stat.h>
36# include <sys/socket.h>
37# include <netinet/in.h>
38# include <netinet/tcp.h>
39# include <arpa/inet.h>
40# ifdef IPRT_WITH_TCPIP_V6
41# include <netinet6/in6.h>
42# endif
43# include <sys/un.h>
44# include <netdb.h>
45# include <unistd.h>
46# include <fcntl.h>
47# include <sys/uio.h>
48#endif /* !RT_OS_WINDOWS */
49#include <limits.h>
50
51#include "internal/iprt.h"
52#include <iprt/socket.h>
53
54#include <iprt/alloca.h>
55#include <iprt/asm.h>
56#include <iprt/assert.h>
57#include <iprt/ctype.h>
58#include <iprt/err.h>
59#include <iprt/mempool.h>
60#include <iprt/poll.h>
61#include <iprt/string.h>
62#include <iprt/thread.h>
63#include <iprt/time.h>
64#include <iprt/mem.h>
65#include <iprt/sg.h>
66#include <iprt/log.h>
67
68#include "internal/magics.h"
69#include "internal/socket.h"
70
71
72/*******************************************************************************
73* Defined Constants And Macros *
74*******************************************************************************/
75/* non-standard linux stuff (it seems). */
76#ifndef MSG_NOSIGNAL
77# define MSG_NOSIGNAL 0
78#endif
79
80/* Windows has different names for SHUT_XXX. */
81#ifndef SHUT_RDWR
82# ifdef SD_BOTH
83# define SHUT_RDWR SD_BOTH
84# else
85# define SHUT_RDWR 2
86# endif
87#endif
88#ifndef SHUT_WR
89# ifdef SD_SEND
90# define SHUT_WR SD_SEND
91# else
92# define SHUT_WR 1
93# endif
94#endif
95#ifndef SHUT_RD
96# ifdef SD_RECEIVE
97# define SHUT_RD SD_RECEIVE
98# else
99# define SHUT_RD 0
100# endif
101#endif
102
103/* fixup backlevel OSes. */
104#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
105# define socklen_t int
106#endif
107
108/** How many pending connection. */
109#define RTTCP_SERVER_BACKLOG 10
110
111
112/*******************************************************************************
113* Structures and Typedefs *
114*******************************************************************************/
115/**
116 * Socket handle data.
117 *
118 * This is mainly required for implementing RTPollSet on Windows.
119 */
120typedef struct RTSOCKETINT
121{
122 /** Magic number (RTSOCKET_MAGIC). */
123 uint32_t u32Magic;
124 /** Exclusive user count.
125 * This is used to prevent two threads from accessing the handle concurrently.
126 * It can be higher than 1 if this handle is reference multiple times in a
127 * polling set (Windows). */
128 uint32_t volatile cUsers;
129 /** The native socket handle. */
130 RTSOCKETNATIVE hNative;
131 /** Indicates whether the handle has been closed or not. */
132 bool volatile fClosed;
133 /** Indicates whether the socket is operating in blocking or non-blocking mode
134 * currently. */
135 bool fBlocking;
136#ifdef RT_OS_WINDOWS
137 /** The event semaphore we've associated with the socket handle.
138 * This is WSA_INVALID_EVENT if not done. */
139 WSAEVENT hEvent;
140 /** The pollset currently polling this socket. This is NIL if no one is
141 * polling. */
142 RTPOLLSET hPollSet;
143 /** The events we're polling for. */
144 uint32_t fPollEvts;
145 /** The events we're currently subscribing to with WSAEventSelect.
146 * This is ZERO if we're currently not subscribing to anything. */
147 uint32_t fSubscribedEvts;
148 /** Saved events which are only posted once. */
149 uint32_t fEventsSaved;
150#endif /* RT_OS_WINDOWS */
151} RTSOCKETINT;
152
153
154/**
155 * Address union used internally for things like getpeername and getsockname.
156 */
157typedef union RTSOCKADDRUNION
158{
159 struct sockaddr Addr;
160 struct sockaddr_in IPv4;
161#ifdef IPRT_WITH_TCPIP_V6
162 struct sockaddr_in6 IPv6;
163#endif
164} RTSOCKADDRUNION;
165
166
167/**
168 * Get the last error as an iprt status code.
169 *
170 * @returns IPRT status code.
171 */
172DECLINLINE(int) rtSocketError(void)
173{
174#ifdef RT_OS_WINDOWS
175 return RTErrConvertFromWin32(WSAGetLastError());
176#else
177 return RTErrConvertFromErrno(errno);
178#endif
179}
180
181
182/**
183 * Resets the last error.
184 */
185DECLINLINE(void) rtSocketErrorReset(void)
186{
187#ifdef RT_OS_WINDOWS
188 WSASetLastError(0);
189#else
190 errno = 0;
191#endif
192}
193
194
195/**
196 * Get the last resolver error as an iprt status code.
197 *
198 * @returns iprt status code.
199 */
200int rtSocketResolverError(void)
201{
202#ifdef RT_OS_WINDOWS
203 return RTErrConvertFromWin32(WSAGetLastError());
204#else
205 switch (h_errno)
206 {
207 case HOST_NOT_FOUND:
208 return VERR_NET_HOST_NOT_FOUND;
209 case NO_DATA:
210 return VERR_NET_ADDRESS_NOT_AVAILABLE;
211 case NO_RECOVERY:
212 return VERR_IO_GEN_FAILURE;
213 case TRY_AGAIN:
214 return VERR_TRY_AGAIN;
215
216 default:
217 return VERR_UNRESOLVED_ERROR;
218 }
219#endif
220}
221
222
223/**
224 * Converts from a native socket address to a generic IPRT network address.
225 *
226 * @returns IPRT status code.
227 * @param pSrc The source address.
228 * @param cbSrc The size of the source address.
229 * @param pAddr Where to return the generic IPRT network
230 * address.
231 */
232static int rtSocketNetAddrFromAddr(RTSOCKADDRUNION const *pSrc, size_t cbSrc, PRTNETADDR pAddr)
233{
234 /*
235 * Convert the address.
236 */
237 if ( cbSrc == sizeof(struct sockaddr_in)
238 && pSrc->Addr.sa_family == AF_INET)
239 {
240 RT_ZERO(*pAddr);
241 pAddr->enmType = RTNETADDRTYPE_IPV4;
242 pAddr->uPort = RT_N2H_U16(pSrc->IPv4.sin_port);
243 pAddr->uAddr.IPv4.u = pSrc->IPv4.sin_addr.s_addr;
244 }
245#ifdef IPRT_WITH_TCPIP_V6
246 else if ( cbSrc == sizeof(struct sockaddr_in6)
247 && pSrc->Addr.sa_family == AF_INET6)
248 {
249 RT_ZERO(*pAddr);
250 pAddr->enmType = RTNETADDRTYPE_IPV6;
251 pAddr->uPort = RT_N2H_U16(pSrc->IPv6.sin6_port);
252 pAddr->uAddr.IPv6.au32[0] = pSrc->IPv6.sin6_addr.s6_addr32[0];
253 pAddr->uAddr.IPv6.au32[1] = pSrc->IPv6.sin6_addr.s6_addr32[1];
254 pAddr->uAddr.IPv6.au32[2] = pSrc->IPv6.sin6_addr.s6_addr32[2];
255 pAddr->uAddr.IPv6.au32[3] = pSrc->IPv6.sin6_addr.s6_addr32[3];
256 }
257#endif
258 else
259 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
260 return VINF_SUCCESS;
261}
262
263
264/**
265 * Converts from a generic IPRT network address to a native socket address.
266 *
267 * @returns IPRT status code.
268 * @param pAddr Pointer to the generic IPRT network address.
269 * @param pDst The source address.
270 * @param cbSrc The size of the source address.
271 * @param pcbAddr Where to store the size of the returned address.
272 * Optional
273 */
274static int rtSocketAddrFromNetAddr(PCRTNETADDR pAddr, RTSOCKADDRUNION *pDst, size_t cbDst, int *pcbAddr)
275{
276 RT_BZERO(pDst, cbDst);
277 if ( pAddr->enmType == RTNETADDRTYPE_IPV4
278 && cbDst >= sizeof(struct sockaddr_in))
279 {
280 pDst->Addr.sa_family = AF_INET;
281 pDst->IPv4.sin_port = RT_H2N_U16(pAddr->uPort);
282 pDst->IPv4.sin_addr.s_addr = pAddr->uAddr.IPv4.u;
283 if (pcbAddr)
284 *pcbAddr = sizeof(pDst->IPv4);
285 }
286#ifdef IPRT_WITH_TCPIP_V6
287 else if ( pAddr->enmType == RTNETADDRTYPE_IPV6
288 && cbDst >= sizeof(struct sockaddr_in6))
289 {
290 pDst->Addr.sa_family = AF_INET6;
291 pDst->IPv6.sin6_port = RT_H2N_U16(pAddr->uPort);
292 pSrc->IPv6.sin6_addr.s6_addr32[0] = pAddr->uAddr.IPv6.au32[0];
293 pSrc->IPv6.sin6_addr.s6_addr32[1] = pAddr->uAddr.IPv6.au32[1];
294 pSrc->IPv6.sin6_addr.s6_addr32[2] = pAddr->uAddr.IPv6.au32[2];
295 pSrc->IPv6.sin6_addr.s6_addr32[3] = pAddr->uAddr.IPv6.au32[3];
296 if (pcbAddr)
297 *pcbAddr = sizeof(pDst->IPv6);
298 }
299#endif
300 else
301 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
302 return VINF_SUCCESS;
303}
304
305
306/**
307 * Tries to lock the socket for exclusive usage by the calling thread.
308 *
309 * Call rtSocketUnlock() to unlock.
310 *
311 * @returns @c true if locked, @c false if not.
312 * @param pThis The socket structure.
313 */
314DECLINLINE(bool) rtSocketTryLock(RTSOCKETINT *pThis)
315{
316 return ASMAtomicCmpXchgU32(&pThis->cUsers, 1, 0);
317}
318
319
320/**
321 * Unlocks the socket.
322 *
323 * @param pThis The socket structure.
324 */
325DECLINLINE(void) rtSocketUnlock(RTSOCKETINT *pThis)
326{
327 ASMAtomicCmpXchgU32(&pThis->cUsers, 0, 1);
328}
329
330
331/**
332 * The slow path of rtSocketSwitchBlockingMode that does the actual switching.
333 *
334 * @returns IPRT status code.
335 * @param pThis The socket structure.
336 * @param fBlocking The desired mode of operation.
337 * @remarks Do not call directly.
338 */
339static int rtSocketSwitchBlockingModeSlow(RTSOCKETINT *pThis, bool fBlocking)
340{
341#ifdef RT_OS_WINDOWS
342 u_long uBlocking = fBlocking ? 0 : 1;
343 if (ioctlsocket(pThis->hNative, FIONBIO, &uBlocking))
344 return rtSocketError();
345
346#else
347 int fFlags = fcntl(pThis->hNative, F_GETFL, 0);
348 if (fFlags == -1)
349 return rtSocketError();
350
351 if (fBlocking)
352 fFlags &= ~O_NONBLOCK;
353 else
354 fFlags |= O_NONBLOCK;
355 if (fcntl(pThis->hNative, F_SETFL, fFlags) == -1)
356 return rtSocketError();
357#endif
358
359 pThis->fBlocking = fBlocking;
360 return VINF_SUCCESS;
361}
362
363
364/**
365 * Switches the socket to the desired blocking mode if necessary.
366 *
367 * The socket must be locked.
368 *
369 * @returns IPRT status code.
370 * @param pThis The socket structure.
371 * @param fBlocking The desired mode of operation.
372 */
373DECLINLINE(int) rtSocketSwitchBlockingMode(RTSOCKETINT *pThis, bool fBlocking)
374{
375 if (pThis->fBlocking != fBlocking)
376 return rtSocketSwitchBlockingModeSlow(pThis, fBlocking);
377 return VINF_SUCCESS;
378}
379
380
381/**
382 * Creates an IPRT socket handle for a native one.
383 *
384 * @returns IPRT status code.
385 * @param ppSocket Where to return the IPRT socket handle.
386 * @param hNative The native handle.
387 */
388int rtSocketCreateForNative(RTSOCKETINT **ppSocket, RTSOCKETNATIVE hNative)
389{
390 RTSOCKETINT *pThis = (RTSOCKETINT *)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pThis));
391 if (!pThis)
392 return VERR_NO_MEMORY;
393 pThis->u32Magic = RTSOCKET_MAGIC;
394 pThis->cUsers = 0;
395 pThis->hNative = hNative;
396 pThis->fClosed = false;
397 pThis->fBlocking = true;
398#ifdef RT_OS_WINDOWS
399 pThis->hEvent = WSA_INVALID_EVENT;
400 pThis->hPollSet = NIL_RTPOLLSET;
401 pThis->fPollEvts = 0;
402 pThis->fSubscribedEvts = 0;
403#endif
404 *ppSocket = pThis;
405 return VINF_SUCCESS;
406}
407
408
409RTDECL(int) RTSocketFromNative(PRTSOCKET phSocket, RTHCINTPTR uNative)
410{
411 AssertReturn(uNative != NIL_RTSOCKETNATIVE, VERR_INVALID_PARAMETER);
412#ifndef RT_OS_WINDOWS
413 AssertReturn(uNative >= 0, VERR_INVALID_PARAMETER);
414#endif
415 AssertPtrReturn(phSocket, VERR_INVALID_POINTER);
416 return rtSocketCreateForNative(phSocket, uNative);
417}
418
419
420/**
421 * Wrapper around socket().
422 *
423 * @returns IPRT status code.
424 * @param phSocket Where to store the handle to the socket on
425 * success.
426 * @param iDomain The protocol family (PF_XXX).
427 * @param iType The socket type (SOCK_XXX).
428 * @param iProtocol Socket parameter, usually 0.
429 */
430int rtSocketCreate(PRTSOCKET phSocket, int iDomain, int iType, int iProtocol)
431{
432 /*
433 * Create the socket.
434 */
435 RTSOCKETNATIVE hNative = socket(iDomain, iType, iProtocol);
436 if (hNative == NIL_RTSOCKETNATIVE)
437 return rtSocketError();
438
439 /*
440 * Wrap it.
441 */
442 int rc = rtSocketCreateForNative(phSocket, hNative);
443 if (RT_FAILURE(rc))
444 {
445#ifdef RT_OS_WINDOWS
446 closesocket(hNative);
447#else
448 close(hNative);
449#endif
450 }
451 return rc;
452}
453
454
455RTDECL(uint32_t) RTSocketRetain(RTSOCKET hSocket)
456{
457 RTSOCKETINT *pThis = hSocket;
458 AssertPtrReturn(pThis, UINT32_MAX);
459 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
460 return RTMemPoolRetain(pThis);
461}
462
463
464/**
465 * Worker for RTSocketRelease and RTSocketClose.
466 *
467 * @returns IPRT status code.
468 * @param pThis The socket handle instance data.
469 * @param fDestroy Whether we're reaching ref count zero.
470 */
471static int rtSocketCloseIt(RTSOCKETINT *pThis, bool fDestroy)
472{
473 /*
474 * Invalidate the handle structure on destroy.
475 */
476 if (fDestroy)
477 {
478 Assert(ASMAtomicReadU32(&pThis->u32Magic) == RTSOCKET_MAGIC);
479 ASMAtomicWriteU32(&pThis->u32Magic, RTSOCKET_MAGIC_DEAD);
480 }
481
482 int rc = VINF_SUCCESS;
483 if (ASMAtomicCmpXchgBool(&pThis->fClosed, true, false))
484 {
485 /*
486 * Close the native handle.
487 */
488 RTSOCKETNATIVE hNative = pThis->hNative;
489 if (hNative != NIL_RTSOCKETNATIVE)
490 {
491 pThis->hNative = NIL_RTSOCKETNATIVE;
492
493#ifdef RT_OS_WINDOWS
494 if (closesocket(hNative))
495#else
496 if (close(hNative))
497#endif
498 {
499 rc = rtSocketError();
500#ifdef RT_OS_WINDOWS
501 AssertMsgFailed(("\"%s\": closesocket(%p) -> %Rrc\n", (uintptr_t)hNative, rc));
502#else
503 AssertMsgFailed(("\"%s\": close(%d) -> %Rrc\n", hNative, rc));
504#endif
505 }
506 }
507
508#ifdef RT_OS_WINDOWS
509 /*
510 * Close the event.
511 */
512 WSAEVENT hEvent = pThis->hEvent;
513 if (hEvent == WSA_INVALID_EVENT)
514 {
515 pThis->hEvent = WSA_INVALID_EVENT;
516 WSACloseEvent(hEvent);
517 }
518#endif
519 }
520
521 return rc;
522}
523
524
525RTDECL(uint32_t) RTSocketRelease(RTSOCKET hSocket)
526{
527 RTSOCKETINT *pThis = hSocket;
528 if (pThis == NIL_RTSOCKET)
529 return 0;
530 AssertPtrReturn(pThis, UINT32_MAX);
531 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
532
533 /* get the refcount without killing it... */
534 uint32_t cRefs = RTMemPoolRefCount(pThis);
535 AssertReturn(cRefs != UINT32_MAX, UINT32_MAX);
536 if (cRefs == 1)
537 rtSocketCloseIt(pThis, true);
538
539 return RTMemPoolRelease(RTMEMPOOL_DEFAULT, pThis);
540}
541
542
543RTDECL(int) RTSocketClose(RTSOCKET hSocket)
544{
545 RTSOCKETINT *pThis = hSocket;
546 if (pThis == NIL_RTSOCKET)
547 return VINF_SUCCESS;
548 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
549 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
550
551 uint32_t cRefs = RTMemPoolRefCount(pThis);
552 AssertReturn(cRefs != UINT32_MAX, UINT32_MAX);
553
554 int rc = rtSocketCloseIt(pThis, cRefs == 1);
555
556 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pThis);
557 return rc;
558}
559
560
561RTDECL(RTHCUINTPTR) RTSocketToNative(RTSOCKET hSocket)
562{
563 RTSOCKETINT *pThis = hSocket;
564 AssertPtrReturn(pThis, RTHCUINTPTR_MAX);
565 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, RTHCUINTPTR_MAX);
566 return (RTHCUINTPTR)pThis->hNative;
567}
568
569
570RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable)
571{
572 RTSOCKETINT *pThis = hSocket;
573 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
574 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
575 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
576
577 int rc = VINF_SUCCESS;
578#ifdef RT_OS_WINDOWS
579 if (!SetHandleInformation((HANDLE)pThis->hNative, HANDLE_FLAG_INHERIT, fInheritable ? HANDLE_FLAG_INHERIT : 0))
580 rc = RTErrConvertFromWin32(GetLastError());
581#else
582 if (fcntl(pThis->hNative, F_SETFD, fInheritable ? 0 : FD_CLOEXEC) < 0)
583 rc = RTErrConvertFromErrno(errno);
584#endif
585
586 return rc;
587}
588
589static bool rtSocketIsIPv4Numerical(const char *pszAddress, PRTNETADDRIPV4 pAddr)
590{
591
592 /* Empty address resolves to the INADDR_ANY address (good for bind). */
593 if (!*pszAddress)
594 {
595 pAddr->u = INADDR_ANY;
596 return true;
597 }
598
599 /* Four quads? */
600 char *psz = (char *)pszAddress;
601 for (int i = 0; i < 4; i++)
602 {
603 uint8_t u8;
604 int rc = RTStrToUInt8Ex(psz, &psz, 0, &u8);
605 if (rc != VINF_SUCCESS)
606 return false;
607 if (*psz != (i < 3 ? '.' : '\0'))
608 return false;
609 psz++;
610
611 pAddr->au8[i] = u8; /* big endian */
612 }
613
614 return true;
615}
616
617RTDECL(int) RTSocketParseInetAddress(const char *pszAddress, unsigned uPort, PRTNETADDR pAddr)
618{
619 int rc;
620
621 /*
622 * Validate input.
623 */
624 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
625 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
626
627#ifdef RT_OS_WINDOWS
628 /*
629 * Initialize WinSock and check version.
630 */
631 WORD wVersionRequested = MAKEWORD(1, 1);
632 WSADATA wsaData;
633 rc = WSAStartup(wVersionRequested, &wsaData);
634 if (wsaData.wVersion != wVersionRequested)
635 {
636 AssertMsgFailed(("Wrong winsock version\n"));
637 return VERR_NOT_SUPPORTED;
638 }
639#endif
640
641 /*
642 * Resolve the address. Pretty crude at the moment, but we have to make
643 * sure to not ask the NT 4 gethostbyname about an IPv4 address as it may
644 * give a wrong answer.
645 */
646 /** @todo this only supports IPv4, and IPv6 support needs to be added.
647 * It probably needs to be converted to getaddrinfo(). */
648 RTNETADDRIPV4 IPv4Quad;
649 if (rtSocketIsIPv4Numerical(pszAddress, &IPv4Quad))
650 {
651 RT_ZERO(*pAddr);
652 pAddr->enmType = RTNETADDRTYPE_IPV4;
653 pAddr->uPort = uPort;
654 pAddr->uAddr.IPv4 = IPv4Quad;
655 return VINF_SUCCESS;
656 }
657
658 struct hostent *pHostEnt;
659 pHostEnt = gethostbyname(pszAddress);
660 if (!pHostEnt)
661 {
662 rc = rtSocketResolverError();
663 AssertMsgFailed(("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
664 return rc;
665 }
666
667 if (pHostEnt->h_addrtype == AF_INET)
668 {
669 RT_ZERO(*pAddr);
670 pAddr->enmType = RTNETADDRTYPE_IPV4;
671 pAddr->uPort = uPort;
672 pAddr->uAddr.IPv4.u = ((struct in_addr *)pHostEnt->h_addr)->s_addr;
673 }
674 else
675 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
676
677 return VINF_SUCCESS;
678}
679
680
681RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
682{
683 /*
684 * Validate input.
685 */
686 RTSOCKETINT *pThis = hSocket;
687 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
688 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
689 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
690 AssertPtr(pvBuffer);
691 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
692
693
694 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
695 if (RT_FAILURE(rc))
696 return rc;
697
698 /*
699 * Read loop.
700 * If pcbRead is NULL we have to fill the entire buffer!
701 */
702 size_t cbRead = 0;
703 size_t cbToRead = cbBuffer;
704 for (;;)
705 {
706 rtSocketErrorReset();
707#ifdef RT_OS_WINDOWS
708 int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
709#else
710 size_t cbNow = cbToRead;
711#endif
712 ssize_t cbBytesRead = recv(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL);
713 if (cbBytesRead <= 0)
714 {
715 rc = rtSocketError();
716 Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
717 if (RT_SUCCESS_NP(rc))
718 {
719 if (!pcbRead)
720 rc = VERR_NET_SHUTDOWN;
721 else
722 {
723 *pcbRead = 0;
724 rc = VINF_SUCCESS;
725 }
726 }
727 break;
728 }
729 if (pcbRead)
730 {
731 /* return partial data */
732 *pcbRead = cbBytesRead;
733 break;
734 }
735
736 /* read more? */
737 cbRead += cbBytesRead;
738 if (cbRead == cbBuffer)
739 break;
740
741 /* next */
742 cbToRead = cbBuffer - cbRead;
743 }
744
745 rtSocketUnlock(pThis);
746 return rc;
747}
748
749
750RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr)
751{
752 /*
753 * Validate input.
754 */
755 RTSOCKETINT *pThis = hSocket;
756 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
757 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
758 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
759 AssertPtr(pvBuffer);
760 AssertPtr(pcbRead);
761 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
762
763 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
764 if (RT_FAILURE(rc))
765 return rc;
766
767 /*
768 * Read data.
769 */
770 size_t cbRead = 0;
771 size_t cbToRead = cbBuffer;
772 rtSocketErrorReset();
773 RTSOCKADDRUNION u;
774#ifdef RT_OS_WINDOWS
775 int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
776 int cbAddr = sizeof(u);
777#else
778 size_t cbNow = cbToRead;
779 socklen_t cbAddr = sizeof(u);
780#endif
781 ssize_t cbBytesRead = recvfrom(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL, &u.Addr, &cbAddr);
782 if (cbBytesRead <= 0)
783 {
784 rc = rtSocketError();
785 Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
786 if (RT_SUCCESS_NP(rc))
787 {
788 *pcbRead = 0;
789 rc = VINF_SUCCESS;
790 }
791 }
792 else
793 {
794 if (pSrcAddr)
795 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pSrcAddr);
796 *pcbRead = cbBytesRead;
797 }
798
799 rtSocketUnlock(pThis);
800 return rc;
801}
802
803
804RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer)
805{
806 /*
807 * Validate input.
808 */
809 RTSOCKETINT *pThis = hSocket;
810 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
811 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
812 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
813
814 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
815 if (RT_FAILURE(rc))
816 return rc;
817
818 /*
819 * Try write all at once.
820 */
821#ifdef RT_OS_WINDOWS
822 int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
823#else
824 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
825#endif
826 ssize_t cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
827 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
828 rc = VINF_SUCCESS;
829 else if (cbWritten < 0)
830 rc = rtSocketError();
831 else
832 {
833 /*
834 * Unfinished business, write the remainder of the request. Must ignore
835 * VERR_INTERRUPTED here if we've managed to send something.
836 */
837 size_t cbSentSoFar = 0;
838 for (;;)
839 {
840 /* advance */
841 cbBuffer -= (size_t)cbWritten;
842 if (!cbBuffer)
843 break;
844 cbSentSoFar += (size_t)cbWritten;
845 pvBuffer = (char const *)pvBuffer + cbWritten;
846
847 /* send */
848#ifdef RT_OS_WINDOWS
849 cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
850#else
851 cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
852#endif
853 cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
854 if (cbWritten >= 0)
855 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%zu cbBuffer=%zu rtSocketError()=%d\n",
856 cbWritten, cbBuffer, rtSocketError()));
857 else
858 {
859 rc = rtSocketError();
860 if (rc != VERR_INTERNAL_ERROR || cbSentSoFar == 0)
861 break;
862 cbWritten = 0;
863 rc = VINF_SUCCESS;
864 }
865 }
866 }
867
868 rtSocketUnlock(pThis);
869 return rc;
870}
871
872
873RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pAddr)
874{
875 /*
876 * Validate input.
877 */
878 RTSOCKETINT *pThis = hSocket;
879 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
880 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
881
882 /* no locking since UDP reads may be done concurrently to writes, and
883 * this is the normal use case of this code. */
884
885 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
886 if (RT_FAILURE(rc))
887 return rc;
888
889 /* Figure out destination address. */
890 struct sockaddr *pSA = NULL;
891#ifdef RT_OS_WINDOWS
892 int cbSA = 0;
893#else
894 socklen_t cbSA = 0;
895#endif
896 RTSOCKADDRUNION u;
897 if (pAddr)
898 {
899 rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), NULL);
900 if (RT_FAILURE(rc))
901 return rc;
902 pSA = &u.Addr;
903 cbSA = sizeof(u);
904 }
905
906 /*
907 * Must write all at once, otherwise it is a failure.
908 */
909#ifdef RT_OS_WINDOWS
910 int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
911#else
912 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
913#endif
914 ssize_t cbWritten = sendto(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL, pSA, cbSA);
915 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
916 rc = VINF_SUCCESS;
917 else if (cbWritten < 0)
918 rc = rtSocketError();
919 else
920 rc = VERR_TOO_MUCH_DATA;
921
922 rtSocketUnlock(pThis);
923 return rc;
924}
925
926
927RTDECL(int) RTSocketSgWrite(RTSOCKET hSocket, PCRTSGBUF pSgBuf)
928{
929 /*
930 * Validate input.
931 */
932 RTSOCKETINT *pThis = hSocket;
933 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
934 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
935 AssertPtrReturn(pSgBuf, VERR_INVALID_PARAMETER);
936 AssertReturn(pSgBuf->cSegs > 0, VERR_INVALID_PARAMETER);
937 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
938
939 int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
940 if (RT_FAILURE(rc))
941 return rc;
942
943 /*
944 * Construct message descriptor (translate pSgBuf) and send it.
945 */
946 rc = VERR_NO_TMP_MEMORY;
947#ifdef RT_OS_WINDOWS
948 AssertCompileSize(WSABUF, sizeof(RTSGSEG));
949 AssertCompileMemberSize(WSABUF, buf, RT_SIZEOFMEMB(RTSGSEG, pvSeg));
950
951 LPWSABUF paMsg = (LPWSABUF)RTMemTmpAllocZ(pSgBuf->cSegs * sizeof(WSABUF));
952 if (paMsg)
953 {
954 for (unsigned i = 0; i < pSgBuf->cSegs; i++)
955 {
956 paMsg[i].buf = (char *)pSgBuf->paSegs[i].pvSeg;
957 paMsg[i].len = (u_long)pSgBuf->paSegs[i].cbSeg;
958 }
959
960 DWORD dwSent;
961 int hrc = WSASend(pThis->hNative, paMsg, pSgBuf->cSegs, &dwSent,
962 MSG_NOSIGNAL, NULL, NULL);
963 if (!hrc)
964 rc = VINF_SUCCESS;
965/** @todo check for incomplete writes */
966 else
967 rc = rtSocketError();
968
969 RTMemTmpFree(paMsg);
970 }
971
972#else /* !RT_OS_WINDOWS */
973 AssertCompileSize(struct iovec, sizeof(RTSGSEG));
974 AssertCompileMemberSize(struct iovec, iov_base, RT_SIZEOFMEMB(RTSGSEG, pvSeg));
975 AssertCompileMemberSize(struct iovec, iov_len, RT_SIZEOFMEMB(RTSGSEG, cbSeg));
976
977 struct iovec *paMsg = (struct iovec *)RTMemTmpAllocZ(pSgBuf->cSegs * sizeof(struct iovec));
978 if (paMsg)
979 {
980 for (unsigned i = 0; i < pSgBuf->cSegs; i++)
981 {
982 paMsg[i].iov_base = pSgBuf->paSegs[i].pvSeg;
983 paMsg[i].iov_len = pSgBuf->paSegs[i].cbSeg;
984 }
985
986 struct msghdr msgHdr;
987 RT_ZERO(msgHdr);
988 msgHdr.msg_iov = paMsg;
989 msgHdr.msg_iovlen = pSgBuf->cSegs;
990 ssize_t cbWritten = sendmsg(pThis->hNative, &msgHdr, MSG_NOSIGNAL);
991 if (RT_LIKELY(cbWritten >= 0))
992 rc = VINF_SUCCESS;
993/** @todo check for incomplete writes */
994 else
995 rc = rtSocketError();
996
997 RTMemTmpFree(paMsg);
998 }
999#endif /* !RT_OS_WINDOWS */
1000
1001 rtSocketUnlock(pThis);
1002 return rc;
1003}
1004
1005
1006RTDECL(int) RTSocketSgWriteL(RTSOCKET hSocket, size_t cSegs, ...)
1007{
1008 va_list va;
1009 va_start(va, cSegs);
1010 int rc = RTSocketSgWriteLV(hSocket, cSegs, va);
1011 va_end(va);
1012 return rc;
1013}
1014
1015
1016RTDECL(int) RTSocketSgWriteLV(RTSOCKET hSocket, size_t cSegs, va_list va)
1017{
1018 /*
1019 * Set up a S/G segment array + buffer on the stack and pass it
1020 * on to RTSocketSgWrite.
1021 */
1022 Assert(cSegs <= 16);
1023 PRTSGSEG paSegs = (PRTSGSEG)alloca(cSegs * sizeof(RTSGSEG));
1024 AssertReturn(paSegs, VERR_NO_TMP_MEMORY);
1025 for (size_t i = 0; i < cSegs; i++)
1026 {
1027 paSegs[i].pvSeg = va_arg(va, void *);
1028 paSegs[i].cbSeg = va_arg(va, size_t);
1029 }
1030
1031 RTSGBUF SgBuf;
1032 RTSgBufInit(&SgBuf, paSegs, cSegs);
1033 return RTSocketSgWrite(hSocket, &SgBuf);
1034}
1035
1036
1037RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
1038{
1039 /*
1040 * Validate input.
1041 */
1042 RTSOCKETINT *pThis = hSocket;
1043 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1044 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1045 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
1046 AssertPtr(pvBuffer);
1047 AssertPtrReturn(pcbRead, VERR_INVALID_PARAMETER);
1048 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1049
1050 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1051 if (RT_FAILURE(rc))
1052 return rc;
1053
1054 rtSocketErrorReset();
1055#ifdef RT_OS_WINDOWS
1056 int cbNow = cbBuffer >= INT_MAX/2 ? INT_MAX/2 : (int)cbBuffer;
1057
1058 int cbRead = recv(pThis->hNative, (char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1059 if (cbRead >= 0)
1060 {
1061 *pcbRead = cbRead;
1062 rc = VINF_SUCCESS;
1063 }
1064 else
1065 rc = rtSocketError();
1066
1067 if (rc == VERR_TRY_AGAIN)
1068 rc = VINF_TRY_AGAIN;
1069#else
1070 ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL);
1071 if (cbRead >= 0)
1072 *pcbRead = cbRead;
1073 else if (errno == EAGAIN)
1074 {
1075 *pcbRead = 0;
1076 rc = VINF_TRY_AGAIN;
1077 }
1078 else
1079 rc = rtSocketError();
1080#endif
1081
1082 rtSocketUnlock(pThis);
1083 return rc;
1084}
1085
1086
1087RTDECL(int) RTSocketWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten)
1088{
1089 /*
1090 * Validate input.
1091 */
1092 RTSOCKETINT *pThis = hSocket;
1093 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1094 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1095 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER);
1096 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1097
1098 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1099 if (RT_FAILURE(rc))
1100 return rc;
1101
1102 rtSocketErrorReset();
1103#ifdef RT_OS_WINDOWS
1104 int cbNow = RT_MIN((int)cbBuffer, INT_MAX/2);
1105
1106 int cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
1107
1108 if (cbWritten >= 0)
1109 {
1110 *pcbWritten = cbWritten;
1111 rc = VINF_SUCCESS;
1112 }
1113 else
1114 rc = rtSocketError();
1115
1116 if (rc == VERR_TRY_AGAIN)
1117 rc = VINF_TRY_AGAIN;
1118#else
1119 ssize_t cbWritten = send(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL);
1120 if (cbWritten >= 0)
1121 *pcbWritten = cbWritten;
1122 else if (errno == EAGAIN)
1123 {
1124 *pcbWritten = 0;
1125 rc = VINF_TRY_AGAIN;
1126 }
1127 else
1128 rc = rtSocketError();
1129#endif
1130
1131 rtSocketUnlock(pThis);
1132 return rc;
1133}
1134
1135
1136RTDECL(int) RTSocketSgWriteNB(RTSOCKET hSocket, PCRTSGBUF pSgBuf, size_t *pcbWritten)
1137{
1138 /*
1139 * Validate input.
1140 */
1141 RTSOCKETINT *pThis = hSocket;
1142 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1143 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1144 AssertPtrReturn(pSgBuf, VERR_INVALID_PARAMETER);
1145 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER);
1146 AssertReturn(pSgBuf->cSegs > 0, VERR_INVALID_PARAMETER);
1147 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1148
1149 int rc = rtSocketSwitchBlockingMode(pThis, false /* fBlocking */);
1150 if (RT_FAILURE(rc))
1151 return rc;
1152
1153 unsigned cSegsToSend = 0;
1154 rc = VERR_NO_TMP_MEMORY;
1155#ifdef RT_OS_WINDOWS
1156 LPWSABUF paMsg = NULL;
1157
1158 RTSgBufMapToNative(paMsg, pSgBuf, WSABUF, buf, char *, len, u_long, cSegsToSend);
1159 if (paMsg)
1160 {
1161 DWORD dwSent = 0;
1162 int hrc = WSASend(pThis->hNative, paMsg, cSegsToSend, &dwSent,
1163 MSG_NOSIGNAL, NULL, NULL);
1164 if (!hrc)
1165 rc = VINF_SUCCESS;
1166 else
1167 rc = rtSocketError();
1168
1169 *pcbWritten = dwSent;
1170
1171 RTMemTmpFree(paMsg);
1172 }
1173
1174#else /* !RT_OS_WINDOWS */
1175 struct iovec *paMsg = NULL;
1176
1177 RTSgBufMapToNative(paMsg, pSgBuf, struct iovec, iov_base, void *, iov_len, size_t, cSegsToSend);
1178 if (paMsg)
1179 {
1180 struct msghdr msgHdr;
1181 RT_ZERO(msgHdr);
1182 msgHdr.msg_iov = paMsg;
1183 msgHdr.msg_iovlen = cSegsToSend;
1184 ssize_t cbWritten = sendmsg(pThis->hNative, &msgHdr, MSG_NOSIGNAL);
1185 if (RT_LIKELY(cbWritten >= 0))
1186 {
1187 rc = VINF_SUCCESS;
1188 *pcbWritten = cbWritten;
1189 }
1190 else
1191 rc = rtSocketError();
1192
1193 RTMemTmpFree(paMsg);
1194 }
1195#endif /* !RT_OS_WINDOWS */
1196
1197 rtSocketUnlock(pThis);
1198 return rc;
1199}
1200
1201
1202RTDECL(int) RTSocketSgWriteLNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, ...)
1203{
1204 va_list va;
1205 va_start(va, pcbWritten);
1206 int rc = RTSocketSgWriteLVNB(hSocket, cSegs, pcbWritten, va);
1207 va_end(va);
1208 return rc;
1209}
1210
1211
1212RTDECL(int) RTSocketSgWriteLVNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, va_list va)
1213{
1214 /*
1215 * Set up a S/G segment array + buffer on the stack and pass it
1216 * on to RTSocketSgWrite.
1217 */
1218 Assert(cSegs <= 16);
1219 PRTSGSEG paSegs = (PRTSGSEG)alloca(cSegs * sizeof(RTSGSEG));
1220 AssertReturn(paSegs, VERR_NO_TMP_MEMORY);
1221 for (size_t i = 0; i < cSegs; i++)
1222 {
1223 paSegs[i].pvSeg = va_arg(va, void *);
1224 paSegs[i].cbSeg = va_arg(va, size_t);
1225 }
1226
1227 RTSGBUF SgBuf;
1228 RTSgBufInit(&SgBuf, paSegs, cSegs);
1229 return RTSocketSgWriteNB(hSocket, &SgBuf, pcbWritten);
1230}
1231
1232
1233RTDECL(int) RTSocketSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies)
1234{
1235 /*
1236 * Validate input.
1237 */
1238 RTSOCKETINT *pThis = hSocket;
1239 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1240 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1241 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1242 int const fdMax = (int)pThis->hNative + 1;
1243 AssertReturn(fdMax - 1 == pThis->hNative, VERR_INTERNAL_ERROR_5);
1244
1245 /*
1246 * Set up the file descriptor sets and do the select.
1247 */
1248 fd_set fdsetR;
1249 FD_ZERO(&fdsetR);
1250 FD_SET(pThis->hNative, &fdsetR);
1251
1252 fd_set fdsetE = fdsetR;
1253
1254 int rc;
1255 if (cMillies == RT_INDEFINITE_WAIT)
1256 rc = select(fdMax, &fdsetR, NULL, &fdsetE, NULL);
1257 else
1258 {
1259 struct timeval timeout;
1260 timeout.tv_sec = cMillies / 1000;
1261 timeout.tv_usec = (cMillies % 1000) * 1000;
1262 rc = select(fdMax, &fdsetR, NULL, &fdsetE, &timeout);
1263 }
1264 if (rc > 0)
1265 rc = VINF_SUCCESS;
1266 else if (rc == 0)
1267 rc = VERR_TIMEOUT;
1268 else
1269 rc = rtSocketError();
1270
1271 return rc;
1272}
1273
1274
1275RTDECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents,
1276 RTMSINTERVAL cMillies)
1277{
1278 /*
1279 * Validate input.
1280 */
1281 RTSOCKETINT *pThis = hSocket;
1282 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1283 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1284 AssertPtrReturn(pfEvents, VERR_INVALID_PARAMETER);
1285 AssertReturn(!(fEvents & ~RTSOCKET_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
1286 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1287 int const fdMax = (int)pThis->hNative + 1;
1288 AssertReturn(fdMax - 1 == pThis->hNative, VERR_INTERNAL_ERROR_5);
1289
1290 *pfEvents = 0;
1291
1292 /*
1293 * Set up the file descriptor sets and do the select.
1294 */
1295 fd_set fdsetR;
1296 fd_set fdsetW;
1297 fd_set fdsetE;
1298 FD_ZERO(&fdsetR);
1299 FD_ZERO(&fdsetW);
1300 FD_ZERO(&fdsetE);
1301
1302 if (fEvents & RTSOCKET_EVT_READ)
1303 FD_SET(pThis->hNative, &fdsetR);
1304 if (fEvents & RTSOCKET_EVT_WRITE)
1305 FD_SET(pThis->hNative, &fdsetW);
1306 if (fEvents & RTSOCKET_EVT_ERROR)
1307 FD_SET(pThis->hNative, &fdsetE);
1308
1309 int rc;
1310 if (cMillies == RT_INDEFINITE_WAIT)
1311 rc = select(fdMax, &fdsetR, &fdsetW, &fdsetE, NULL);
1312 else
1313 {
1314 struct timeval timeout;
1315 timeout.tv_sec = cMillies / 1000;
1316 timeout.tv_usec = (cMillies % 1000) * 1000;
1317 rc = select(fdMax, &fdsetR, &fdsetW, &fdsetE, &timeout);
1318 }
1319 if (rc > 0)
1320 {
1321 if (FD_ISSET(pThis->hNative, &fdsetR))
1322 *pfEvents |= RTSOCKET_EVT_READ;
1323 if (FD_ISSET(pThis->hNative, &fdsetW))
1324 *pfEvents |= RTSOCKET_EVT_WRITE;
1325 if (FD_ISSET(pThis->hNative, &fdsetE))
1326 *pfEvents |= RTSOCKET_EVT_ERROR;
1327
1328 rc = VINF_SUCCESS;
1329 }
1330 else if (rc == 0)
1331 rc = VERR_TIMEOUT;
1332 else
1333 rc = rtSocketError();
1334
1335 return rc;
1336}
1337
1338
1339RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite)
1340{
1341 /*
1342 * Validate input, don't lock it because we might want to interrupt a call
1343 * active on a different thread.
1344 */
1345 RTSOCKETINT *pThis = hSocket;
1346 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1347 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1348 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1349 AssertReturn(fRead || fWrite, VERR_INVALID_PARAMETER);
1350
1351 /*
1352 * Do the job.
1353 */
1354 int rc = VINF_SUCCESS;
1355 int fHow;
1356 if (fRead && fWrite)
1357 fHow = SHUT_RDWR;
1358 else if (fRead)
1359 fHow = SHUT_RD;
1360 else
1361 fHow = SHUT_WR;
1362 if (shutdown(pThis->hNative, fHow) == -1)
1363 rc = rtSocketError();
1364
1365 return rc;
1366}
1367
1368
1369RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
1370{
1371 /*
1372 * Validate input.
1373 */
1374 RTSOCKETINT *pThis = hSocket;
1375 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1376 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1377 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1378
1379 /*
1380 * Get the address and convert it.
1381 */
1382 int rc;
1383 RTSOCKADDRUNION u;
1384#ifdef RT_OS_WINDOWS
1385 int cbAddr = sizeof(u);
1386#else
1387 socklen_t cbAddr = sizeof(u);
1388#endif
1389 RT_ZERO(u);
1390 if (getsockname(pThis->hNative, &u.Addr, &cbAddr) == 0)
1391 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
1392 else
1393 rc = rtSocketError();
1394
1395 return rc;
1396}
1397
1398
1399RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
1400{
1401 /*
1402 * Validate input.
1403 */
1404 RTSOCKETINT *pThis = hSocket;
1405 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1406 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1407 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1408
1409 /*
1410 * Get the address and convert it.
1411 */
1412 int rc;
1413 RTSOCKADDRUNION u;
1414#ifdef RT_OS_WINDOWS
1415 int cbAddr = sizeof(u);
1416#else
1417 socklen_t cbAddr = sizeof(u);
1418#endif
1419 RT_ZERO(u);
1420 if (getpeername(pThis->hNative, &u.Addr, &cbAddr) == 0)
1421 rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
1422 else
1423 rc = rtSocketError();
1424
1425 return rc;
1426}
1427
1428
1429
1430/**
1431 * Wrapper around bind.
1432 *
1433 * @returns IPRT status code.
1434 * @param hSocket The socket handle.
1435 * @param pAddr The address to bind to.
1436 */
1437int rtSocketBind(RTSOCKET hSocket, PCRTNETADDR pAddr)
1438{
1439 /*
1440 * Validate input.
1441 */
1442 RTSOCKETINT *pThis = hSocket;
1443 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1444 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1445 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1446
1447 RTSOCKADDRUNION u;
1448 int cbAddr;
1449 int rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), &cbAddr);
1450 if (RT_SUCCESS(rc))
1451 {
1452 if (bind(pThis->hNative, &u.Addr, cbAddr) != 0)
1453 rc = rtSocketError();
1454 }
1455
1456 rtSocketUnlock(pThis);
1457 return rc;
1458}
1459
1460
1461/**
1462 * Wrapper around listen.
1463 *
1464 * @returns IPRT status code.
1465 * @param hSocket The socket handle.
1466 * @param cMaxPending The max number of pending connections.
1467 */
1468int rtSocketListen(RTSOCKET hSocket, int cMaxPending)
1469{
1470 /*
1471 * Validate input.
1472 */
1473 RTSOCKETINT *pThis = hSocket;
1474 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1475 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1476 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1477
1478 int rc = VINF_SUCCESS;
1479 if (listen(pThis->hNative, cMaxPending) != 0)
1480 rc = rtSocketError();
1481
1482 rtSocketUnlock(pThis);
1483 return rc;
1484}
1485
1486
1487/**
1488 * Wrapper around accept.
1489 *
1490 * @returns IPRT status code.
1491 * @param hSocket The socket handle.
1492 * @param phClient Where to return the client socket handle on
1493 * success.
1494 * @param pAddr Where to return the client address.
1495 * @param pcbAddr On input this gives the size buffer size of what
1496 * @a pAddr point to. On return this contains the
1497 * size of what's stored at @a pAddr.
1498 */
1499int rtSocketAccept(RTSOCKET hSocket, PRTSOCKET phClient, struct sockaddr *pAddr, size_t *pcbAddr)
1500{
1501 /*
1502 * Validate input.
1503 * Only lock the socket temporarily while we get the native handle, so that
1504 * we can safely shutdown and destroy the socket from a different thread.
1505 */
1506 RTSOCKETINT *pThis = hSocket;
1507 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1508 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1509 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1510
1511 /*
1512 * Call accept().
1513 */
1514 rtSocketErrorReset();
1515 int rc = VINF_SUCCESS;
1516#ifdef RT_OS_WINDOWS
1517 int cbAddr = (int)*pcbAddr;
1518#else
1519 socklen_t cbAddr = *pcbAddr;
1520#endif
1521 RTSOCKETNATIVE hNativeClient = accept(pThis->hNative, pAddr, &cbAddr);
1522 if (hNativeClient != NIL_RTSOCKETNATIVE)
1523 {
1524 *pcbAddr = cbAddr;
1525
1526 /*
1527 * Wrap the client socket.
1528 */
1529 rc = rtSocketCreateForNative(phClient, hNativeClient);
1530 if (RT_FAILURE(rc))
1531 {
1532#ifdef RT_OS_WINDOWS
1533 closesocket(hNativeClient);
1534#else
1535 close(hNativeClient);
1536#endif
1537 }
1538 }
1539 else
1540 rc = rtSocketError();
1541
1542 rtSocketUnlock(pThis);
1543 return rc;
1544}
1545
1546
1547/**
1548 * Wrapper around connect.
1549 *
1550 * @returns IPRT status code.
1551 * @param hSocket The socket handle.
1552 * @param pAddr The socket address to connect to.
1553 */
1554int rtSocketConnect(RTSOCKET hSocket, PCRTNETADDR pAddr)
1555{
1556 /*
1557 * Validate input.
1558 */
1559 RTSOCKETINT *pThis = hSocket;
1560 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1561 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1562 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1563
1564 RTSOCKADDRUNION u;
1565 int cbAddr;
1566 int rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u), &cbAddr);
1567 if (RT_SUCCESS(rc))
1568 {
1569Log(("Calling connect()...\n%.*Rhxs\n", cbAddr, &u));
1570 if (connect(pThis->hNative, &u.Addr, cbAddr) != 0)
1571 rc = rtSocketError();
1572 }
1573
1574 rtSocketUnlock(pThis);
1575 return rc;
1576}
1577
1578
1579/**
1580 * Wrapper around setsockopt.
1581 *
1582 * @returns IPRT status code.
1583 * @param hSocket The socket handle.
1584 * @param iLevel The protocol level, e.g. IPPORTO_TCP.
1585 * @param iOption The option, e.g. TCP_NODELAY.
1586 * @param pvValue The value buffer.
1587 * @param cbValue The size of the value pointed to by pvValue.
1588 */
1589int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValue, int cbValue)
1590{
1591 /*
1592 * Validate input.
1593 */
1594 RTSOCKETINT *pThis = hSocket;
1595 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1596 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1597 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1598
1599 int rc = VINF_SUCCESS;
1600 if (setsockopt(pThis->hNative, iLevel, iOption, (const char *)pvValue, cbValue) != 0)
1601 rc = rtSocketError();
1602
1603 rtSocketUnlock(pThis);
1604 return rc;
1605}
1606
1607#ifdef RT_OS_WINDOWS
1608
1609/**
1610 * Internal RTPollSetAdd helper that returns the handle that should be added to
1611 * the pollset.
1612 *
1613 * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
1614 * @param hSocket The socket handle.
1615 * @param fEvents The events we're polling for.
1616 * @param ph where to put the primary handle.
1617 */
1618int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph)
1619{
1620 RTSOCKETINT *pThis = hSocket;
1621 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1622 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1623 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1624
1625 int rc = VINF_SUCCESS;
1626 if (pThis->hEvent != WSA_INVALID_EVENT)
1627 *ph = pThis->hEvent;
1628 else
1629 {
1630 *ph = pThis->hEvent = WSACreateEvent();
1631 if (pThis->hEvent == WSA_INVALID_EVENT)
1632 rc = rtSocketError();
1633 }
1634
1635 rtSocketUnlock(pThis);
1636 return rc;
1637}
1638
1639
1640/**
1641 * Undos the harm done by WSAEventSelect.
1642 *
1643 * @returns IPRT status code.
1644 * @param pThis The socket handle.
1645 */
1646static int rtSocketPollClearEventAndRestoreBlocking(RTSOCKETINT *pThis)
1647{
1648 int rc = VINF_SUCCESS;
1649 if (pThis->fSubscribedEvts)
1650 {
1651 if (WSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
1652 {
1653 pThis->fSubscribedEvts = 0;
1654
1655 /*
1656 * Switch back to blocking mode if that was the state before the
1657 * operation.
1658 */
1659 if (pThis->fBlocking)
1660 {
1661 u_long fNonBlocking = 0;
1662 int rc2 = ioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
1663 if (rc2 != 0)
1664 {
1665 rc = rtSocketError();
1666 AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
1667 }
1668 }
1669 }
1670 else
1671 {
1672 rc = rtSocketError();
1673 AssertMsgFailed(("%Rrc\n", rc));
1674 }
1675 }
1676 return rc;
1677}
1678
1679
1680/**
1681 * Updates the mask of events we're subscribing to.
1682 *
1683 * @returns IPRT status code.
1684 * @param pThis The socket handle.
1685 * @param fEvents The events we want to subscribe to.
1686 */
1687static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
1688{
1689 LONG fNetworkEvents = 0;
1690 if (fEvents & RTPOLL_EVT_READ)
1691 fNetworkEvents |= FD_READ;
1692 if (fEvents & RTPOLL_EVT_WRITE)
1693 fNetworkEvents |= FD_WRITE;
1694 if (fEvents & RTPOLL_EVT_ERROR)
1695 fNetworkEvents |= FD_CLOSE;
1696 LogFlowFunc(("fNetworkEvents=%#x\n", fNetworkEvents));
1697 if (WSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
1698 {
1699 pThis->fSubscribedEvts = fEvents;
1700 return VINF_SUCCESS;
1701 }
1702
1703 int rc = rtSocketError();
1704 AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
1705 return rc;
1706}
1707
1708
1709/**
1710 * Checks for pending events.
1711 *
1712 * @returns Event mask or 0.
1713 * @param pThis The socket handle.
1714 * @param fEvents The desired events.
1715 */
1716static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents)
1717{
1718 int rc = VINF_SUCCESS;
1719 uint32_t fRetEvents = 0;
1720
1721 LogFlowFunc(("pThis=%#p fEvents=%#x\n", pThis, fEvents));
1722
1723 /* Make sure WSAEnumNetworkEvents returns what we want. */
1724 if ((pThis->fSubscribedEvts & fEvents) != fEvents)
1725 rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
1726
1727 /* Get the event mask, ASSUMES that WSAEnumNetworkEvents doesn't clear stuff. */
1728 WSANETWORKEVENTS NetEvts;
1729 RT_ZERO(NetEvts);
1730 if (WSAEnumNetworkEvents(pThis->hNative, pThis->hEvent, &NetEvts) == 0)
1731 {
1732 if ( (NetEvts.lNetworkEvents & FD_READ)
1733 && (fEvents & RTPOLL_EVT_READ)
1734 && NetEvts.iErrorCode[FD_READ_BIT] == 0)
1735 fRetEvents |= RTPOLL_EVT_READ;
1736
1737 if ( (NetEvts.lNetworkEvents & FD_WRITE)
1738 && (fEvents & RTPOLL_EVT_WRITE)
1739 && NetEvts.iErrorCode[FD_WRITE_BIT] == 0)
1740 fRetEvents |= RTPOLL_EVT_WRITE;
1741
1742 if (fEvents & RTPOLL_EVT_ERROR)
1743 {
1744 if (NetEvts.lNetworkEvents & FD_CLOSE)
1745 fRetEvents |= RTPOLL_EVT_ERROR;
1746 else
1747 for (uint32_t i = 0; i < FD_MAX_EVENTS; i++)
1748 if ( (NetEvts.lNetworkEvents & (1L << i))
1749 && NetEvts.iErrorCode[i] != 0)
1750 fRetEvents |= RTPOLL_EVT_ERROR;
1751 }
1752 }
1753 else
1754 rc = rtSocketError();
1755
1756 /* Fall back on select if we hit an error above. */
1757 if (RT_FAILURE(rc))
1758 {
1759 /** @todo */
1760 }
1761
1762 LogFlowFunc(("fRetEvents=%#x\n", fRetEvents));
1763 return fRetEvents;
1764}
1765
1766
1767/**
1768 * Internal RTPoll helper that polls the socket handle and, if @a fNoWait is
1769 * clear, starts whatever actions we've got running during the poll call.
1770 *
1771 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
1772 * Event mask (in @a fEvents) and no actions if the handle is ready
1773 * already.
1774 * UINT32_MAX (asserted) if the socket handle is busy in I/O or a
1775 * different poll set.
1776 *
1777 * @param hSocket The socket handle.
1778 * @param hPollSet The poll set handle (for access checks).
1779 * @param fEvents The events we're polling for.
1780 * @param fFinalEntry Set if this is the final entry for this handle
1781 * in this poll set. This can be used for dealing
1782 * with duplicate entries.
1783 * @param fNoWait Set if it's a zero-wait poll call. Clear if
1784 * we'll wait for an event to occur.
1785 *
1786 * @remarks There is a potential race wrt duplicate handles when @a fNoWait is
1787 * @c true, we don't currently care about that oddity...
1788 */
1789uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
1790{
1791 RTSOCKETINT *pThis = hSocket;
1792 AssertPtrReturn(pThis, UINT32_MAX);
1793 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
1794 if (rtSocketTryLock(pThis))
1795 pThis->hPollSet = hPollSet;
1796 else
1797 {
1798 AssertReturn(pThis->hPollSet == hPollSet, UINT32_MAX);
1799 ASMAtomicIncU32(&pThis->cUsers);
1800 }
1801
1802 /* (rtSocketPollCheck will reset the event object). */
1803 uint32_t fRetEvents = pThis->fEventsSaved;
1804 pThis->fEventsSaved = 0; /* Reset */
1805 fRetEvents |= rtSocketPollCheck(pThis, fEvents);
1806
1807 if ( !fRetEvents
1808 && !fNoWait)
1809 {
1810 pThis->fPollEvts |= fEvents;
1811 if ( fFinalEntry
1812 && pThis->fSubscribedEvts != pThis->fPollEvts)
1813 {
1814 int rc = rtSocketPollUpdateEvents(pThis, pThis->fPollEvts);
1815 if (RT_FAILURE(rc))
1816 {
1817 pThis->fPollEvts = 0;
1818 fRetEvents = UINT32_MAX;
1819 }
1820 }
1821 }
1822
1823 if (fRetEvents || fNoWait)
1824 {
1825 if (pThis->cUsers == 1)
1826 {
1827 rtSocketPollClearEventAndRestoreBlocking(pThis);
1828 pThis->hPollSet = NIL_RTPOLLSET;
1829 }
1830 ASMAtomicDecU32(&pThis->cUsers);
1831 }
1832
1833 return fRetEvents;
1834}
1835
1836
1837/**
1838 * Called after a WaitForMultipleObjects returned in order to check for pending
1839 * events and stop whatever actions that rtSocketPollStart() initiated.
1840 *
1841 * @returns Event mask or 0.
1842 *
1843 * @param hSocket The socket handle.
1844 * @param fEvents The events we're polling for.
1845 * @param fFinalEntry Set if this is the final entry for this handle
1846 * in this poll set. This can be used for dealing
1847 * with duplicate entries. Only keep in mind that
1848 * this method is called in reverse order, so the
1849 * first call will have this set (when the entire
1850 * set was processed).
1851 * @param fHarvestEvents Set if we should check for pending events.
1852 */
1853uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
1854{
1855 RTSOCKETINT *pThis = hSocket;
1856 AssertPtrReturn(pThis, 0);
1857 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, 0);
1858 Assert(pThis->cUsers > 0);
1859 Assert(pThis->hPollSet != NIL_RTPOLLSET);
1860
1861 /* Harvest events and clear the event mask for the next round of polling. */
1862 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
1863 pThis->fPollEvts = 0;
1864
1865 /*
1866 * Save the write event if required.
1867 * It is only posted once and might get lost if the another source in the
1868 * pollset with a higher priority has pending events.
1869 */
1870 if ( !fHarvestEvents
1871 && fRetEvents)
1872 {
1873 pThis->fEventsSaved = fRetEvents;
1874 fRetEvents = 0;
1875 }
1876
1877 /* Make the socket blocking again and unlock the handle. */
1878 if (pThis->cUsers == 1)
1879 {
1880 rtSocketPollClearEventAndRestoreBlocking(pThis);
1881 pThis->hPollSet = NIL_RTPOLLSET;
1882 }
1883 ASMAtomicDecU32(&pThis->cUsers);
1884 return fRetEvents;
1885}
1886
1887#endif /* RT_OS_WINDOWS */
Note: See TracBrowser for help on using the repository browser.

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