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