VirtualBox

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

Last change on this file since 34079 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 46.0 KB
Line 
1/* $Id: socket.cpp 33540 2010-10-28 09:27:05Z 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
961 /*
962 * Set up the file descriptor sets and do the select.
963 */
964 fd_set fdsetR;
965 FD_ZERO(&fdsetR);
966 FD_SET(pThis->hNative, &fdsetR);
967
968 fd_set fdsetE = fdsetR;
969
970 int rc;
971 if (cMillies == RT_INDEFINITE_WAIT)
972 rc = select(pThis->hNative + 1, &fdsetR, NULL, &fdsetE, NULL);
973 else
974 {
975 struct timeval timeout;
976 timeout.tv_sec = cMillies / 1000;
977 timeout.tv_usec = (cMillies % 1000) * 1000;
978 rc = select(pThis->hNative + 1, &fdsetR, NULL, &fdsetE, &timeout);
979 }
980 if (rc > 0)
981 rc = VINF_SUCCESS;
982 else if (rc == 0)
983 rc = VERR_TIMEOUT;
984 else
985 rc = rtSocketError();
986
987 return rc;
988}
989
990
991RTDECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents,
992 RTMSINTERVAL cMillies)
993{
994 /*
995 * Validate input.
996 */
997 RTSOCKETINT *pThis = hSocket;
998 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
999 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1000 AssertPtrReturn(pfEvents, VERR_INVALID_PARAMETER);
1001 AssertReturn(!(fEvents & ~RTSOCKET_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
1002 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1003
1004 *pfEvents = 0;
1005
1006 /*
1007 * Set up the file descriptor sets and do the select.
1008 */
1009 fd_set fdsetR;
1010 fd_set fdsetW;
1011 fd_set fdsetE;
1012 FD_ZERO(&fdsetR);
1013 FD_ZERO(&fdsetW);
1014 FD_ZERO(&fdsetE);
1015
1016 if (fEvents & RTSOCKET_EVT_READ)
1017 FD_SET(pThis->hNative, &fdsetR);
1018 if (fEvents & RTSOCKET_EVT_WRITE)
1019 FD_SET(pThis->hNative, &fdsetW);
1020 if (fEvents & RTSOCKET_EVT_ERROR)
1021 FD_SET(pThis->hNative, &fdsetE);
1022
1023 int rc;
1024 if (cMillies == RT_INDEFINITE_WAIT)
1025 rc = select(pThis->hNative + 1, &fdsetR, &fdsetW, &fdsetE, NULL);
1026 else
1027 {
1028 struct timeval timeout;
1029 timeout.tv_sec = cMillies / 1000;
1030 timeout.tv_usec = (cMillies % 1000) * 1000;
1031 rc = select(pThis->hNative + 1, &fdsetR, &fdsetW, &fdsetE, &timeout);
1032 }
1033 if (rc > 0)
1034 {
1035 if (FD_ISSET(pThis->hNative, &fdsetR))
1036 *pfEvents |= RTSOCKET_EVT_READ;
1037 if (FD_ISSET(pThis->hNative, &fdsetW))
1038 *pfEvents |= RTSOCKET_EVT_WRITE;
1039 if (FD_ISSET(pThis->hNative, &fdsetE))
1040 *pfEvents |= RTSOCKET_EVT_ERROR;
1041
1042 rc = VINF_SUCCESS;
1043 }
1044 else if (rc == 0)
1045 rc = VERR_TIMEOUT;
1046 else
1047 rc = rtSocketError();
1048
1049 return rc;
1050}
1051
1052
1053RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite)
1054{
1055 /*
1056 * Validate input, don't lock it because we might want to interrupt a call
1057 * active on a different thread.
1058 */
1059 RTSOCKETINT *pThis = hSocket;
1060 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1061 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1062 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1063 AssertReturn(fRead || fWrite, VERR_INVALID_PARAMETER);
1064
1065 /*
1066 * Do the job.
1067 */
1068 int rc = VINF_SUCCESS;
1069 int fHow;
1070 if (fRead && fWrite)
1071 fHow = SHUT_RDWR;
1072 else if (fRead)
1073 fHow = SHUT_RD;
1074 else
1075 fHow = SHUT_WR;
1076 if (shutdown(pThis->hNative, fHow) == -1)
1077 rc = rtSocketError();
1078
1079 return rc;
1080}
1081
1082
1083/**
1084 * Converts from a native socket address to a generic IPRT network address.
1085 *
1086 * @returns IPRT status code.
1087 * @param pSrc The source address.
1088 * @param cbSrc The size of the source address.
1089 * @param pAddr Where to return the generic IPRT network
1090 * address.
1091 */
1092static int rtSocketConvertAddress(RTSOCKADDRUNION const *pSrc, size_t cbSrc, PRTNETADDR pAddr)
1093{
1094 /*
1095 * Convert the address.
1096 */
1097 if ( cbSrc == sizeof(struct sockaddr_in)
1098 && pSrc->Addr.sa_family == AF_INET)
1099 {
1100 RT_ZERO(*pAddr);
1101 pAddr->enmType = RTNETADDRTYPE_IPV4;
1102 pAddr->uPort = RT_N2H_U16(pSrc->Ipv4.sin_port);
1103 pAddr->uAddr.IPv4.u = pSrc->Ipv4.sin_addr.s_addr;
1104 }
1105#ifdef IPRT_WITH_TCPIP_V6
1106 else if ( cbSrc == sizeof(struct sockaddr_in6)
1107 && pSrc->Addr.sa_family == AF_INET6)
1108 {
1109 RT_ZERO(*pAddr);
1110 pAddr->enmType = RTNETADDRTYPE_IPV6;
1111 pAddr->uPort = RT_N2H_U16(pSrc->Ipv6.sin6_port);
1112 pAddr->uAddr.IPv6.au32[0] = pSrc->Ipv6.sin6_addr.s6_addr32[0];
1113 pAddr->uAddr.IPv6.au32[1] = pSrc->Ipv6.sin6_addr.s6_addr32[1];
1114 pAddr->uAddr.IPv6.au32[2] = pSrc->Ipv6.sin6_addr.s6_addr32[2];
1115 pAddr->uAddr.IPv6.au32[3] = pSrc->Ipv6.sin6_addr.s6_addr32[3];
1116 }
1117#endif
1118 else
1119 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
1120 return VINF_SUCCESS;
1121}
1122
1123
1124RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
1125{
1126 /*
1127 * Validate input.
1128 */
1129 RTSOCKETINT *pThis = hSocket;
1130 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1131 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1132 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1133
1134 /*
1135 * Get the address and convert it.
1136 */
1137 int rc;
1138 RTSOCKADDRUNION u;
1139#ifdef RT_OS_WINDOWS
1140 int cbAddr = sizeof(u);
1141#else
1142 socklen_t cbAddr = sizeof(u);
1143#endif
1144 RT_ZERO(u);
1145 if (getsockname(pThis->hNative, &u.Addr, &cbAddr) == 0)
1146 rc = rtSocketConvertAddress(&u, cbAddr, pAddr);
1147 else
1148 rc = rtSocketError();
1149
1150 return rc;
1151}
1152
1153
1154RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
1155{
1156 /*
1157 * Validate input.
1158 */
1159 RTSOCKETINT *pThis = hSocket;
1160 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1161 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1162 AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
1163
1164 /*
1165 * Get the address and convert it.
1166 */
1167 int rc;
1168 RTSOCKADDRUNION u;
1169#ifdef RT_OS_WINDOWS
1170 int cbAddr = sizeof(u);
1171#else
1172 socklen_t cbAddr = sizeof(u);
1173#endif
1174 RT_ZERO(u);
1175 if (getpeername(pThis->hNative, &u.Addr, &cbAddr) == 0)
1176 rc = rtSocketConvertAddress(&u, cbAddr, pAddr);
1177 else
1178 rc = rtSocketError();
1179
1180 return rc;
1181}
1182
1183
1184
1185/**
1186 * Wrapper around bind.
1187 *
1188 * @returns IPRT status code.
1189 * @param hSocket The socket handle.
1190 * @param pAddr The socket address to bind to.
1191 * @param cbAddr The size of the address structure @a pAddr
1192 * points to.
1193 */
1194int rtSocketBind(RTSOCKET hSocket, const struct sockaddr *pAddr, int cbAddr)
1195{
1196 /*
1197 * Validate input.
1198 */
1199 RTSOCKETINT *pThis = hSocket;
1200 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1201 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1202 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1203
1204 int rc = VINF_SUCCESS;
1205 if (bind(pThis->hNative, pAddr, cbAddr) != 0)
1206 rc = rtSocketError();
1207
1208 rtSocketUnlock(pThis);
1209 return rc;
1210}
1211
1212
1213/**
1214 * Wrapper around listen.
1215 *
1216 * @returns IPRT status code.
1217 * @param hSocket The socket handle.
1218 * @param cMaxPending The max number of pending connections.
1219 */
1220int rtSocketListen(RTSOCKET hSocket, int cMaxPending)
1221{
1222 /*
1223 * Validate input.
1224 */
1225 RTSOCKETINT *pThis = hSocket;
1226 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1227 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1228 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1229
1230 int rc = VINF_SUCCESS;
1231 if (listen(pThis->hNative, cMaxPending) != 0)
1232 rc = rtSocketError();
1233
1234 rtSocketUnlock(pThis);
1235 return rc;
1236}
1237
1238
1239/**
1240 * Wrapper around accept.
1241 *
1242 * @returns IPRT status code.
1243 * @param hSocket The socket handle.
1244 * @param phClient Where to return the client socket handle on
1245 * success.
1246 * @param pAddr Where to return the client address.
1247 * @param pcbAddr On input this gives the size buffer size of what
1248 * @a pAddr point to. On return this contains the
1249 * size of what's stored at @a pAddr.
1250 */
1251int rtSocketAccept(RTSOCKET hSocket, PRTSOCKET phClient, struct sockaddr *pAddr, size_t *pcbAddr)
1252{
1253 /*
1254 * Validate input.
1255 * Only lock the socket temporarily while we get the native handle, so that
1256 * we can safely shutdown and destroy the socket from a different thread.
1257 */
1258 RTSOCKETINT *pThis = hSocket;
1259 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1260 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1261 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1262
1263 /*
1264 * Call accept().
1265 */
1266 rtSocketErrorReset();
1267 int rc = VINF_SUCCESS;
1268#ifdef RT_OS_WINDOWS
1269 int cbAddr = (int)*pcbAddr;
1270#else
1271 socklen_t cbAddr = *pcbAddr;
1272#endif
1273 RTSOCKETNATIVE hNativeClient = accept(pThis->hNative, pAddr, &cbAddr);
1274 if (hNativeClient != NIL_RTSOCKETNATIVE)
1275 {
1276 *pcbAddr = cbAddr;
1277
1278 /*
1279 * Wrap the client socket.
1280 */
1281 rc = rtSocketCreateForNative(phClient, hNativeClient);
1282 if (RT_FAILURE(rc))
1283 {
1284#ifdef RT_OS_WINDOWS
1285 closesocket(hNativeClient);
1286#else
1287 close(hNativeClient);
1288#endif
1289 }
1290 }
1291 else
1292 rc = rtSocketError();
1293
1294 rtSocketUnlock(pThis);
1295 return rc;
1296}
1297
1298
1299/**
1300 * Wrapper around connect.
1301 *
1302 * @returns IPRT status code.
1303 * @param hSocket The socket handle.
1304 * @param pAddr The socket address to connect to.
1305 * @param cbAddr The size of the address structure @a pAddr
1306 * points to.
1307 */
1308int rtSocketConnect(RTSOCKET hSocket, const struct sockaddr *pAddr, int cbAddr)
1309{
1310 /*
1311 * Validate input.
1312 */
1313 RTSOCKETINT *pThis = hSocket;
1314 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1315 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1316 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1317
1318 int rc = VINF_SUCCESS;
1319 if (connect(pThis->hNative, pAddr, cbAddr) != 0)
1320 rc = rtSocketError();
1321
1322 rtSocketUnlock(pThis);
1323 return rc;
1324}
1325
1326
1327/**
1328 * Wrapper around setsockopt.
1329 *
1330 * @returns IPRT status code.
1331 * @param hSocket The socket handle.
1332 * @param iLevel The protocol level, e.g. IPPORTO_TCP.
1333 * @param iOption The option, e.g. TCP_NODELAY.
1334 * @param pvValue The value buffer.
1335 * @param cbValue The size of the value pointed to by pvValue.
1336 */
1337int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValue, int cbValue)
1338{
1339 /*
1340 * Validate input.
1341 */
1342 RTSOCKETINT *pThis = hSocket;
1343 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1344 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1345 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1346
1347 int rc = VINF_SUCCESS;
1348 if (setsockopt(pThis->hNative, iLevel, iOption, (const char *)pvValue, cbValue) != 0)
1349 rc = rtSocketError();
1350
1351 rtSocketUnlock(pThis);
1352 return rc;
1353}
1354
1355#ifdef RT_OS_WINDOWS
1356
1357/**
1358 * Internal RTPollSetAdd helper that returns the handle that should be added to
1359 * the pollset.
1360 *
1361 * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
1362 * @param hSocket The socket handle.
1363 * @param fEvents The events we're polling for.
1364 * @param ph where to put the primary handle.
1365 */
1366int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph)
1367{
1368 RTSOCKETINT *pThis = hSocket;
1369 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1370 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
1371 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
1372
1373 int rc = VINF_SUCCESS;
1374 if (pThis->hEvent != WSA_INVALID_EVENT)
1375 *ph = pThis->hEvent;
1376 else
1377 {
1378 *ph = pThis->hEvent = WSACreateEvent();
1379 if (pThis->hEvent == WSA_INVALID_EVENT)
1380 rc = rtSocketError();
1381 }
1382
1383 rtSocketUnlock(pThis);
1384 return rc;
1385}
1386
1387
1388/**
1389 * Undos the harm done by WSAEventSelect.
1390 *
1391 * @returns IPRT status code.
1392 * @param pThis The socket handle.
1393 */
1394static int rtSocketPollClearEventAndRestoreBlocking(RTSOCKETINT *pThis)
1395{
1396 int rc = VINF_SUCCESS;
1397 if (pThis->fSubscribedEvts)
1398 {
1399 if (WSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
1400 {
1401 pThis->fSubscribedEvts = 0;
1402
1403 /*
1404 * Switch back to blocking mode if that was the state before the
1405 * operation.
1406 */
1407 if (pThis->fBlocking)
1408 {
1409 u_long fNonBlocking = 0;
1410 int rc2 = ioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
1411 if (rc2 != 0)
1412 {
1413 rc = rtSocketError();
1414 AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
1415 }
1416 }
1417 }
1418 else
1419 {
1420 rc = rtSocketError();
1421 AssertMsgFailed(("%Rrc\n", rc));
1422 }
1423 }
1424 return rc;
1425}
1426
1427
1428/**
1429 * Updates the mask of events we're subscribing to.
1430 *
1431 * @returns IPRT status code.
1432 * @param pThis The socket handle.
1433 * @param fEvents The events we want to subscribe to.
1434 */
1435static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
1436{
1437 LONG fNetworkEvents = 0;
1438 if (fEvents & RTPOLL_EVT_READ)
1439 fNetworkEvents |= FD_READ;
1440 if (fEvents & RTPOLL_EVT_WRITE)
1441 fNetworkEvents |= FD_WRITE;
1442 if (fEvents & RTPOLL_EVT_ERROR)
1443 fNetworkEvents |= FD_CLOSE;
1444 LogFlowFunc(("fNetworkEvents=%#x\n", fNetworkEvents));
1445 if (WSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
1446 {
1447 pThis->fSubscribedEvts = fEvents;
1448 return VINF_SUCCESS;
1449 }
1450
1451 int rc = rtSocketError();
1452 AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
1453 return rc;
1454}
1455
1456
1457/**
1458 * Checks for pending events.
1459 *
1460 * @returns Event mask or 0.
1461 * @param pThis The socket handle.
1462 * @param fEvents The desired events.
1463 */
1464static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents)
1465{
1466 int rc = VINF_SUCCESS;
1467 uint32_t fRetEvents = 0;
1468
1469 LogFlowFunc(("pThis=%#p fEvents=%#x\n", pThis, fEvents));
1470
1471 /* Make sure WSAEnumNetworkEvents returns what we want. */
1472 if ((pThis->fSubscribedEvts & fEvents) != fEvents)
1473 rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
1474
1475 /* Get the event mask, ASSUMES that WSAEnumNetworkEvents doesn't clear stuff. */
1476 WSANETWORKEVENTS NetEvts;
1477 RT_ZERO(NetEvts);
1478 if (WSAEnumNetworkEvents(pThis->hNative, pThis->hEvent, &NetEvts) == 0)
1479 {
1480 if ( (NetEvts.lNetworkEvents & FD_READ)
1481 && (fEvents & RTPOLL_EVT_READ)
1482 && NetEvts.iErrorCode[FD_READ_BIT] == 0)
1483 fRetEvents |= RTPOLL_EVT_READ;
1484
1485 if ( (NetEvts.lNetworkEvents & FD_WRITE)
1486 && (fEvents & RTPOLL_EVT_WRITE)
1487 && NetEvts.iErrorCode[FD_WRITE_BIT] == 0)
1488 fRetEvents |= RTPOLL_EVT_WRITE;
1489
1490 if (fEvents & RTPOLL_EVT_ERROR)
1491 {
1492 if (NetEvts.lNetworkEvents & FD_CLOSE)
1493 fRetEvents |= RTPOLL_EVT_ERROR;
1494 else
1495 for (uint32_t i = 0; i < FD_MAX_EVENTS; i++)
1496 if ( (NetEvts.lNetworkEvents & (1L << i))
1497 && NetEvts.iErrorCode[i] != 0)
1498 fRetEvents |= RTPOLL_EVT_ERROR;
1499 }
1500 }
1501 else
1502 rc = rtSocketError();
1503
1504 /* Fall back on select if we hit an error above. */
1505 if (RT_FAILURE(rc))
1506 {
1507 /** @todo */
1508 }
1509
1510 LogFlowFunc(("fRetEvents=%#x\n", fRetEvents));
1511 return fRetEvents;
1512}
1513
1514
1515/**
1516 * Internal RTPoll helper that polls the socket handle and, if @a fNoWait is
1517 * clear, starts whatever actions we've got running during the poll call.
1518 *
1519 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
1520 * Event mask (in @a fEvents) and no actions if the handle is ready
1521 * already.
1522 * UINT32_MAX (asserted) if the socket handle is busy in I/O or a
1523 * different poll set.
1524 *
1525 * @param hSocket The socket handle.
1526 * @param hPollSet The poll set handle (for access checks).
1527 * @param fEvents The events we're polling for.
1528 * @param fFinalEntry Set if this is the final entry for this handle
1529 * in this poll set. This can be used for dealing
1530 * with duplicate entries.
1531 * @param fNoWait Set if it's a zero-wait poll call. Clear if
1532 * we'll wait for an event to occur.
1533 *
1534 * @remarks There is a potential race wrt duplicate handles when @a fNoWait is
1535 * @c true, we don't currently care about that oddity...
1536 */
1537uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
1538{
1539 RTSOCKETINT *pThis = hSocket;
1540 AssertPtrReturn(pThis, UINT32_MAX);
1541 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
1542 if (rtSocketTryLock(pThis))
1543 pThis->hPollSet = hPollSet;
1544 else
1545 {
1546 AssertReturn(pThis->hPollSet == hPollSet, UINT32_MAX);
1547 ASMAtomicIncU32(&pThis->cUsers);
1548 }
1549
1550 /* (rtSocketPollCheck will reset the event object). */
1551 uint32_t fRetEvents = pThis->fEventsSaved;
1552 pThis->fEventsSaved = 0; /* Reset */
1553 fRetEvents |= rtSocketPollCheck(pThis, fEvents);
1554
1555 if ( !fRetEvents
1556 && !fNoWait)
1557 {
1558 pThis->fPollEvts |= fEvents;
1559 if ( fFinalEntry
1560 && pThis->fSubscribedEvts != pThis->fPollEvts)
1561 {
1562 int rc = rtSocketPollUpdateEvents(pThis, pThis->fPollEvts);
1563 if (RT_FAILURE(rc))
1564 {
1565 pThis->fPollEvts = 0;
1566 fRetEvents = UINT32_MAX;
1567 }
1568 }
1569 }
1570
1571 if (fRetEvents || fNoWait)
1572 {
1573 if (pThis->cUsers == 1)
1574 {
1575 rtSocketPollClearEventAndRestoreBlocking(pThis);
1576 pThis->hPollSet = NIL_RTPOLLSET;
1577 }
1578 ASMAtomicDecU32(&pThis->cUsers);
1579 }
1580
1581 return fRetEvents;
1582}
1583
1584
1585/**
1586 * Called after a WaitForMultipleObjects returned in order to check for pending
1587 * events and stop whatever actions that rtSocketPollStart() initiated.
1588 *
1589 * @returns Event mask or 0.
1590 *
1591 * @param hSocket The socket handle.
1592 * @param fEvents The events we're polling for.
1593 * @param fFinalEntry Set if this is the final entry for this handle
1594 * in this poll set. This can be used for dealing
1595 * with duplicate entries. Only keep in mind that
1596 * this method is called in reverse order, so the
1597 * first call will have this set (when the entire
1598 * set was processed).
1599 * @param fHarvestEvents Set if we should check for pending events.
1600 */
1601uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, bool fHarvestEvents)
1602{
1603 RTSOCKETINT *pThis = hSocket;
1604 AssertPtrReturn(pThis, 0);
1605 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, 0);
1606 Assert(pThis->cUsers > 0);
1607 Assert(pThis->hPollSet != NIL_RTPOLLSET);
1608
1609 /* Harvest events and clear the event mask for the next round of polling. */
1610 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
1611 pThis->fPollEvts = 0;
1612
1613 /*
1614 * Save the write event if required.
1615 * It is only posted once and might get lost if the another source in the
1616 * pollset with a higher priority has pending events.
1617 */
1618 if ( !fHarvestEvents
1619 && fRetEvents)
1620 {
1621 pThis->fEventsSaved = fRetEvents;
1622 fRetEvents = 0;
1623 }
1624
1625 /* Make the socket blocking again and unlock the handle. */
1626 if (pThis->cUsers == 1)
1627 {
1628 rtSocketPollClearEventAndRestoreBlocking(pThis);
1629 pThis->hPollSet = NIL_RTPOLLSET;
1630 }
1631 ASMAtomicDecU32(&pThis->cUsers);
1632 return fRetEvents;
1633}
1634
1635#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