VirtualBox

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

Last change on this file since 34834 was 34507, checked in by vboxsync, 14 years ago

IPRT: Visual C++ warnings.

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

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