VirtualBox

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

Last change on this file since 27755 was 27755, checked in by vboxsync, 15 years ago

IPRT: an attempt to implement correct socket use accounting

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 32.6 KB
Line 
1/* $Id: socket.cpp 27755 2010-03-26 17:01:53Z vboxsync $ */
2/** @file
3 * IPRT - Network Sockets.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#ifdef RT_OS_WINDOWS
36//# include <winsock.h>
37# include <winsock2.h>
38#else /* !RT_OS_WINDOWS */
39# include <errno.h>
40# include <sys/stat.h>
41# include <sys/socket.h>
42# include <netinet/in.h>
43# include <netinet/tcp.h>
44# include <arpa/inet.h>
45# ifdef IPRT_WITH_TCPIP_V6
46# include <netinet6/in6.h>
47# endif
48# include <sys/un.h>
49# include <netdb.h>
50# include <unistd.h>
51# include <fcntl.h>
52#endif /* !RT_OS_WINDOWS */
53#include <limits.h>
54
55#include "internal/iprt.h"
56#include <iprt/socket.h>
57
58#include <iprt/asm.h>
59#include <iprt/assert.h>
60#include <iprt/err.h>
61#include <iprt/mem.h>
62#include <iprt/poll.h>
63#include <iprt/string.h>
64#include <iprt/thread.h>
65#include <iprt/time.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 (RTTCPSOCKET_MAGIC). */
122 uint32_t u32Magic;
123 /** Usage bit. This is used to prevent two threads from accessing the
124 * handle concurrently. */
125 uint32_t volatile cUsers;
126 /* Number of references to this object */
127 int32_t volatile cRefs;
128 /** The native socket handle. */
129 RTSOCKETNATIVE hNative;
130#ifdef RT_OS_WINDOWS
131 /** The event semaphore we've associated with the socket handle.
132 * This is WSA_INVALID_EVENT if not done. */
133 WSAEVENT hEvent;
134 /** The pollset currently polling this socket. This is NIL if no one is
135 * polling. */
136 RTPOLLSET hPollSet;
137 /** The events we're polling for. */
138 uint32_t fPollEvts;
139 /** The events we're currently subscribing to with WSAEventSelect.
140 * This is ZERO if we're currently not subscribing to anything. */
141 uint32_t fSubscribedEvts;
142#endif /* RT_OS_WINDOWS */
143} RTSOCKETINT;
144
145
146/**
147 * Address union used internally for things like getpeername and getsockname.
148 */
149typedef union RTSOCKADDRUNION
150{
151 struct sockaddr Addr;
152 struct sockaddr_in Ipv4;
153#ifdef IPRT_WITH_TCPIP_V6
154 struct sockaddr_in6 Ipv6;
155#endif
156} RTSOCKADDRUNION;
157
158
159/**
160 * Get the last error as an iprt status code.
161 *
162 * @returns IPRT status code.
163 */
164DECLINLINE(int) rtSocketError(void)
165{
166#ifdef RT_OS_WINDOWS
167 return RTErrConvertFromWin32(WSAGetLastError());
168#else
169 return RTErrConvertFromErrno(errno);
170#endif
171}
172
173
174/**
175 * Resets the last error.
176 */
177DECLINLINE(void) rtSocketErrorReset(void)
178{
179#ifdef RT_OS_WINDOWS
180 WSASetLastError(0);
181#else
182 errno = 0;
183#endif
184}
185
186
187/**
188 * Get the last resolver error as an iprt status code.
189 *
190 * @returns iprt status code.
191 */
192int rtSocketResolverError(void)
193{
194#ifdef RT_OS_WINDOWS
195 return RTErrConvertFromWin32(WSAGetLastError());
196#else
197 switch (h_errno)
198 {
199 case HOST_NOT_FOUND:
200 return VERR_NET_HOST_NOT_FOUND;
201 case NO_DATA:
202 return VERR_NET_ADDRESS_NOT_AVAILABLE;
203 case NO_RECOVERY:
204 return VERR_IO_GEN_FAILURE;
205 case TRY_AGAIN:
206 return VERR_TRY_AGAIN;
207
208 default:
209 return VERR_UNRESOLVED_ERROR;
210 }
211#endif
212}
213
214
215/**
216 * Increase reference counter of socket. This is orthogonal to usage bit,
217 * as some users of socket may not really modify its state (such as RTSocketSelectOne())
218 * or be allowed to perform operation disregarding if socket is in use (such as RTSocketShutdown()).
219 *
220 * Call rtSocketRelease() when done with socket.
221 *
222 * @returns @c true if object valid, @c false otherwise.
223 * @param pThis The socket structure.
224 */
225DECLINLINE(bool) rtSocketAddRef(RTSOCKETINT *pThis)
226{
227 if (ASMAtomicReadS32(&pThis->cRefs) < 0)
228 return false;
229
230 ASMAtomicAddS32(&pThis->cRefs, 1);
231 return true;
232}
233
234/**
235 * Decrease reference counter of socket.
236 *
237 * @returns @c true if object valid, @c false otherwise.
238 * @param pThis The socket structure.
239 */
240DECLINLINE(bool) rtSocketRelease(RTSOCKETINT *pThis)
241{
242 if (ASMAtomicReadS32(&pThis->cRefs) <= 0)
243 return false;
244
245 ASMAtomicSubS32(&pThis->cRefs, 1);
246 return true;
247}
248
249/**
250 * Declare socket dead.
251 *
252 * @param pThis The socket structure.
253 */
254DECLINLINE(void) rtSocketNoMore(RTSOCKETINT *pThis)
255{
256 ASMAtomicWriteS32(&pThis->cRefs, -1);
257}
258
259
260/**
261 * Tries to lock the socket for exclusive usage by the calling thread.
262 *
263 * Call rtSocketUnlock() to unlock.
264 *
265 * @returns @c true if locked, @c false if not.
266 * @param pThis The socket structure.
267 */
268DECLINLINE(bool) rtSocketTryLock(RTSOCKETINT *pThis)
269{
270 bool rv = ASMAtomicCmpXchgU32(&pThis->cUsers, 1, 0);
271 if (rv)
272 {
273 rv = rtSocketAddRef(pThis);
274 AssertReturn(rv, false);
275 }
276
277 return rv;
278}
279
280
281/**
282 * Unlocks the socket.
283 *
284 * @param pThis The socket structure.
285 */
286DECLINLINE(void) rtSocketUnlock(RTSOCKETINT *pThis)
287{
288 bool rv = ASMAtomicCmpXchgU32(&pThis->cUsers, 0, 1);
289 Assert(rv);
290
291 if (rv)
292 {
293 rv = rtSocketRelease(pThis);
294 Assert(rv);
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 *)RTMemAlloc(sizeof(*pThis));
308 if (!pThis)
309 return VERR_NO_MEMORY;
310 pThis->u32Magic = RTSOCKET_MAGIC;
311 pThis->cUsers = 0;
312 pThis->hNative = hNative;
313#ifdef RT_OS_WINDOWS
314 pThis->hEvent = WSA_INVALID_EVENT;
315 pThis->hPollSet = NIL_RTPOLLSET;
316 pThis->fPollEvts = 0;
317 pThis->fSubscribedEvts = 0;
318#endif
319 *ppSocket = pThis;
320 return VINF_SUCCESS;
321}
322
323
324/**
325 * Wrapper around socket().
326 *
327 * @returns IPRT status code.
328 * @param phSocket Where to store the handle to the socket on
329 * success.
330 * @param iDomain The protocol family (PF_XXX).
331 * @param iType The socket type (SOCK_XXX).
332 * @param iProtocol Socket parameter, usually 0.
333 */
334int rtSocketCreate(PRTSOCKET phSocket, int iDomain, int iType, int iProtocol)
335{
336 /*
337 * Create the socket.
338 */
339 RTSOCKETNATIVE hNative = socket(iDomain, iType, iProtocol);
340 if (hNative == NIL_RTSOCKETNATIVE)
341 return rtSocketError();
342
343 /*
344 * Wrap it.
345 */
346 int rc = rtSocketCreateForNative(phSocket, hNative);
347 if (RT_FAILURE(rc))
348 {
349#ifdef RT_OS_WINDOWS
350 closesocket(hNative);
351#else
352 close(hNative);
353#endif
354 }
355 return rc;
356}
357
358
359RTDECL(int) RTSocketDestroy(RTSOCKET hSocket)
360{
361 RTSOCKETINT *pThis = hSocket;
362 if (pThis == NIL_RTSOCKET)
363 return VINF_SUCCESS;
364 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
365 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
366
367 Assert(pThis->cUsers == 0);
368 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSOCKET_MAGIC_DEAD, RTSOCKET_MAGIC), VERR_INVALID_HANDLE);
369
370 /*
371 * Do the cleanup.
372 */
373 int rc = VINF_SUCCESS;
374#ifdef RT_OS_WINDOWS
375 if (pThis->hEvent == WSA_INVALID_EVENT)
376 {
377 WSACloseEvent(pThis->hEvent);
378 pThis->hEvent = WSA_INVALID_EVENT;
379 }
380#endif
381
382 if (pThis->hNative != NIL_RTSOCKETNATIVE)
383 {
384#ifdef RT_OS_WINDOWS
385 if (closesocket(pThis->hNative))
386#else
387 if (close(pThis->hNative))
388#endif
389 {
390 rc = rtSocketError();
391#ifdef RT_OS_WINDOWS
392 AssertMsgFailed(("\"%s\": closesocket(%p) -> %Rrc\n", (uintptr_t)pThis->hNative, rc));
393#else
394 AssertMsgFailed(("\"%s\": close(%d) -> %Rrc\n", pThis->hNative, rc));
395#endif
396 }
397 pThis->hNative = NIL_RTSOCKETNATIVE;
398 }
399
400 rtSocketNoMore(pThis);
401
402 return rc;
403}
404
405
406RTDECL(RTHCUINTPTR) RTSocketToNative(RTSOCKET hSocket)
407{
408 RTSOCKETINT *pThis = hSocket;
409 AssertPtrReturn(pThis, RTHCUINTPTR_MAX);
410 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, RTHCUINTPTR_MAX);
411 return (RTHCUINTPTR)pThis->hNative;
412}
413
414
415RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable)
416{
417 RTSOCKETINT *pThis = hSocket;
418 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
419 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
420 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
421
422 int rc = VINF_SUCCESS;
423#ifdef RT_OS_WINDOWS
424 if (!SetHandleInformation((HANDLE)pThis->hNative, HANDLE_FLAG_INHERIT, fInheritable ? HANDLE_FLAG_INHERIT : 0))
425 rc = RTErrConvertFromWin32(GetLastError());
426#else
427 if (fcntl(pThis->hNative, F_SETFD, fInheritable ? 0 : FD_CLOEXEC) < 0)
428 rc = RTErrConvertFromErrno(errno);
429#endif
430 AssertRC(rc); /// @todo remove later.
431
432 rtSocketUnlock(pThis);
433 return rc;
434}
435
436
437RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
438{
439 /*
440 * Validate input.
441 */
442 RTSOCKETINT *pThis = hSocket;
443 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
444 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
445 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
446 AssertPtr(pvBuffer);
447 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
448
449 /*
450 * Read loop.
451 * If pcbRead is NULL we have to fill the entire buffer!
452 */
453 int rc = VINF_SUCCESS;
454 size_t cbRead = 0;
455 size_t cbToRead = cbBuffer;
456 for (;;)
457 {
458 rtSocketErrorReset();
459#ifdef RT_OS_WINDOWS
460 int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
461#else
462 size_t cbNow = cbToRead;
463#endif
464 ssize_t cbBytesRead = recv(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL);
465 if (cbBytesRead <= 0)
466 {
467 rc = rtSocketError();
468 Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
469 if (RT_SUCCESS_NP(rc))
470 {
471 if (!pcbRead)
472 rc = VERR_NET_SHUTDOWN;
473 else
474 {
475 *pcbRead = 0;
476 rc = VINF_SUCCESS;
477 }
478 }
479 break;
480 }
481 if (pcbRead)
482 {
483 /* return partial data */
484 *pcbRead = cbBytesRead;
485 break;
486 }
487
488 /* read more? */
489 cbRead += cbBytesRead;
490 if (cbRead == cbBuffer)
491 break;
492
493 /* next */
494 cbToRead = cbBuffer - cbRead;
495 }
496
497 rtSocketUnlock(pThis);
498 return rc;
499}
500
501
502RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer)
503{
504 /*
505 * Validate input.
506 */
507 RTSOCKETINT *pThis = hSocket;
508 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
509 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
510 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
511
512 /*
513 * Try write all at once.
514 */
515 int rc = VINF_SUCCESS;
516#ifdef RT_OS_WINDOWS
517 int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
518#else
519 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
520#endif
521 ssize_t cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
522 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
523 rc = VINF_SUCCESS;
524 else if (cbWritten < 0)
525 rc = rtSocketError();
526 else
527 {
528 /*
529 * Unfinished business, write the remainder of the request. Must ignore
530 * VERR_INTERRUPTED here if we've managed to send something.
531 */
532 size_t cbSentSoFar = 0;
533 for (;;)
534 {
535 /* advance */
536 cbBuffer -= (size_t)cbWritten;
537 if (!cbBuffer)
538 break;
539 cbSentSoFar += (size_t)cbWritten;
540 pvBuffer = (char const *)pvBuffer + cbWritten;
541
542 /* send */
543#ifdef RT_OS_WINDOWS
544 cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
545#else
546 cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
547#endif
548 cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
549 if (cbWritten >= 0)
550 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%zu cbBuffer=%zu rtSocketError()=%d\n",
551 cbWritten, cbBuffer, rtSocketError()));
552 else
553 {
554 rc = rtSocketError();
555 if (rc != VERR_INTERNAL_ERROR || cbSentSoFar == 0)
556 break;
557 cbWritten = 0;
558 rc = VINF_SUCCESS;
559 }
560 }
561 }
562
563 rtSocketUnlock(pThis);
564 return rc;
565}
566
567
568RTDECL(int) RTSocketSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies)
569{
570 /*
571 * Validate input.
572 */
573 RTSOCKETINT *pThis = hSocket;
574 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
575 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
576 AssertReturn(rtSocketAddRef(pThis), VERR_INVALID_HANDLE);
577
578 /*
579 * Set up the file descriptor sets and do the select.
580 */
581 fd_set fdsetR;
582 FD_ZERO(&fdsetR);
583 FD_SET(pThis->hNative, &fdsetR);
584
585 fd_set fdsetE = fdsetR;
586
587 int rc;
588 if (cMillies == RT_INDEFINITE_WAIT)
589 rc = select(pThis->hNative + 1, &fdsetR, NULL, &fdsetE, NULL);
590 else
591 {
592 struct timeval timeout;
593 timeout.tv_sec = cMillies / 1000;
594 timeout.tv_usec = (cMillies % 1000) * 1000;
595 rc = select(pThis->hNative + 1, &fdsetR, NULL, &fdsetE, &timeout);
596 }
597 if (rc > 0)
598 rc = VINF_SUCCESS;
599 else if (rc == 0)
600 rc = VERR_TIMEOUT;
601 else
602 rc = rtSocketError();
603
604 rtSocketRelease(pThis);
605 return rc;
606}
607
608
609RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite)
610{
611 /*
612 * Validate input, don't lock it because we might want to interrupt a call
613 * active on a different thread.
614 */
615 RTSOCKETINT *pThis = hSocket;
616 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
617 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
618 AssertReturn(fRead || fWrite, VERR_INVALID_PARAMETER);
619 AssertReturn(rtSocketAddRef(pThis), VERR_INVALID_HANDLE);
620
621 /*
622 * Do the job.
623 */
624 int rc = VINF_SUCCESS;
625 int fHow;
626 if (fRead && fWrite)
627 fHow = SHUT_RDWR;
628 else if (fRead)
629 fHow = SHUT_RD;
630 else
631 fHow = SHUT_WR;
632 if (shutdown(pThis->hNative, fHow) == -1)
633 rc = rtSocketError();
634
635 rtSocketRelease(pThis);
636 return rc;
637}
638
639
640/**
641 * Converts from a native socket address to a generic IPRT network address.
642 *
643 * @returns IPRT status code.
644 * @param pSrc The source address.
645 * @param cbSrc The size of the source address.
646 * @param pAddr Where to return the generic IPRT network
647 * address.
648 */
649static int rtSocketConvertAddress(RTSOCKADDRUNION const *pSrc, size_t cbSrc, PRTNETADDR pAddr)
650{
651 /*
652 * Convert the address.
653 */
654 if ( cbSrc == sizeof(struct sockaddr_in)
655 && pSrc->Addr.sa_family == AF_INET)
656 {
657 RT_ZERO(*pAddr);
658 pAddr->enmType = RTNETADDRTYPE_IPV4;
659 pAddr->uPort = RT_N2H_U16(pSrc->Ipv4.sin_port);
660 pAddr->uAddr.IPv4.u = pSrc->Ipv4.sin_addr.s_addr;
661 }
662#ifdef IPRT_WITH_TCPIP_V6
663 else if ( cbSrc == sizeof(struct sockaddr_in6)
664 && pSrc->Addr.sa_family == AF_INET6)
665 {
666 RT_ZERO(*pAddr);
667 pAddr->enmType = RTNETADDRTYPE_IPV6;
668 pAddr->uPort = RT_N2H_U16(pSrc->Ipv6.sin6_port);
669 pAddr->uAddr.IPv6.au32[0] = pSrc->Ipv6.sin6_addr.s6_addr32[0];
670 pAddr->uAddr.IPv6.au32[1] = pSrc->Ipv6.sin6_addr.s6_addr32[1];
671 pAddr->uAddr.IPv6.au32[2] = pSrc->Ipv6.sin6_addr.s6_addr32[2];
672 pAddr->uAddr.IPv6.au32[3] = pSrc->Ipv6.sin6_addr.s6_addr32[3];
673 }
674#endif
675 else
676 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
677 return VINF_SUCCESS;
678}
679
680
681RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
682{
683 /*
684 * Validate input.
685 */
686 RTSOCKETINT *pThis = hSocket;
687 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
688 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
689 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
690
691 /*
692 * Get the address and convert it.
693 */
694 int rc;
695 RTSOCKADDRUNION u;
696#ifdef RT_OS_WINDOWS
697 int cbAddr = sizeof(u);
698#else
699 socklen_t cbAddr = sizeof(u);
700#endif
701 RT_ZERO(u);
702 if (getsockname(pThis->hNative, &u.Addr, &cbAddr) == 0)
703 rc = rtSocketConvertAddress(&u, cbAddr, pAddr);
704 else
705 rc = rtSocketError();
706
707 rtSocketUnlock(pThis);
708 return rc;
709}
710
711
712RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
713{
714 /*
715 * Validate input.
716 */
717 RTSOCKETINT *pThis = hSocket;
718 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
719 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
720 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
721
722 /*
723 * Get the address and convert it.
724 */
725 int rc;
726 RTSOCKADDRUNION u;
727#ifdef RT_OS_WINDOWS
728 int cbAddr = sizeof(u);
729#else
730 socklen_t cbAddr = sizeof(u);
731#endif
732 RT_ZERO(u);
733 if (getpeername(pThis->hNative, &u.Addr, &cbAddr) == 0)
734 rc = rtSocketConvertAddress(&u, cbAddr, pAddr);
735 else
736 rc = rtSocketError();
737
738 rtSocketUnlock(pThis);
739 return rc;
740}
741
742
743
744/**
745 * Wrapper around bind.
746 *
747 * @returns IPRT status code.
748 * @param hSocket The socket handle.
749 * @param pAddr The socket address to bind to.
750 * @param cbAddr The size of the address structure @a pAddr
751 * points to.
752 */
753int rtSocketBind(RTSOCKET hSocket, const struct sockaddr *pAddr, int cbAddr)
754{
755 /*
756 * Validate input.
757 */
758 RTSOCKETINT *pThis = hSocket;
759 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
760 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
761 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
762
763 int rc = VINF_SUCCESS;
764 if (bind(pThis->hNative, pAddr, cbAddr) != 0)
765 rc = rtSocketError();
766
767 rtSocketUnlock(pThis);
768 return rc;
769}
770
771
772/**
773 * Wrapper around listen.
774 *
775 * @returns IPRT status code.
776 * @param hSocket The socket handle.
777 * @param cMaxPending The max number of pending connections.
778 */
779int rtSocketListen(RTSOCKET hSocket, int cMaxPending)
780{
781 /*
782 * Validate input.
783 */
784 RTSOCKETINT *pThis = hSocket;
785 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
786 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
787 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
788
789 int rc = VINF_SUCCESS;
790 if (listen(pThis->hNative, cMaxPending) != 0)
791 rc = rtSocketError();
792
793 rtSocketUnlock(pThis);
794 return rc;
795}
796
797
798/**
799 * Wrapper around accept.
800 *
801 * @returns IPRT status code.
802 * @param hSocket The socket handle.
803 * @param phClient Where to return the client socket handle on
804 * success.
805 * @param pAddr Where to return the client address.
806 * @param pcbAddr On input this gives the size buffer size of what
807 * @a pAddr point to. On return this contains the
808 * size of what's stored at @a pAddr.
809 */
810int rtSocketAccept(RTSOCKET hSocket, PRTSOCKET phClient, struct sockaddr *pAddr, size_t *pcbAddr)
811{
812 /*
813 * Validate input.
814 * Only lock the socket temporarily while we get the native handle, so that
815 * we can safely shutdown and destroy the socket from a different thread.
816 */
817 RTSOCKETINT *pThis = hSocket;
818 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
819 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
820
821 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
822
823 rtSocketUnlock(pThis);
824
825
826 /*
827 * Call accept().
828 */
829 rtSocketErrorReset();
830 int rc = VINF_SUCCESS;
831#ifdef RT_OS_WINDOWS
832 int cbAddr = (int)*pcbAddr;
833#else
834 socklen_t cbAddr = *pcbAddr;
835#endif
836 RTSOCKETNATIVE hNative = accept(pThis->hNative, pAddr, &cbAddr);
837 if (hNative != NIL_RTSOCKETNATIVE)
838 {
839 *pcbAddr = cbAddr;
840
841 /*
842 * Wrap the client socket.
843 */
844 rc = rtSocketCreateForNative(phClient, hNative);
845 if (RT_FAILURE(rc))
846 {
847#ifdef RT_OS_WINDOWS
848 closesocket(hNative);
849#else
850 close(hNative);
851#endif
852 }
853 }
854 else
855 rc = rtSocketError();
856 return rc;
857}
858
859
860/**
861 * Wrapper around connect.
862 *
863 * @returns IPRT status code.
864 * @param hSocket The socket handle.
865 * @param pAddr The socket address to connect to.
866 * @param cbAddr The size of the address structure @a pAddr
867 * points to.
868 */
869int rtSocketConnect(RTSOCKET hSocket, const struct sockaddr *pAddr, int cbAddr)
870{
871 /*
872 * Validate input.
873 */
874 RTSOCKETINT *pThis = hSocket;
875 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
876 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
877 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
878
879 int rc = VINF_SUCCESS;
880 if (connect(pThis->hNative, pAddr, cbAddr) != 0)
881 rc = rtSocketError();
882
883 rtSocketUnlock(pThis);
884 return rc;
885}
886
887
888/**
889 * Wrapper around setsockopt.
890 *
891 * @returns IPRT status code.
892 * @param hSocket The socket handle.
893 * @param iLevel The protocol level, e.g. IPPORTO_TCP.
894 * @param iOption The option, e.g. TCP_NODELAY.
895 * @param pvValue The value buffer.
896 * @param cbValue The size of the value pointed to by pvValue.
897 */
898int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValue, int cbValue)
899{
900 /*
901 * Validate input.
902 */
903 RTSOCKETINT *pThis = hSocket;
904 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
905 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
906 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
907
908 int rc = VINF_SUCCESS;
909 if (setsockopt(pThis->hNative, iLevel, iOption, (const char *)pvValue, cbValue) != 0)
910 rc = rtSocketError();
911
912 rtSocketUnlock(pThis);
913 return rc;
914}
915
916#ifdef RT_OS_WINDOWS
917
918/**
919 * Internal RTPollSetAdd helper that returns the handle that should be added to
920 * the pollset.
921 *
922 * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
923 * @param hSocket The socket handle.
924 * @param fEvents The events we're polling for.
925 * @param ph wher to put the primary handle.
926 */
927int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph)
928{
929 RTSOCKETINT *pThis = hSocket;
930 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
931 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
932 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
933
934 int rc = VINF_SUCCESS;
935 if (pThis->hEvent != WSA_INVALID_EVENT)
936 *ph = pThis->hEvent;
937 else
938 {
939 *ph = pThis->hEvent = WSACreateEvent();
940 if (pThis->hEvent == WSA_INVALID_EVENT)
941 rc = rtSocketError();
942 }
943
944 rtSocketUnlock(pThis);
945 return rc;
946}
947
948
949/**
950 * Undos the harm done by WSAEventSelect.
951 *
952 * @returns IPRT status code.
953 * @param pThis The socket handle.
954 */
955static int rtSocketPollClearEventAndMakeBlocking(RTSOCKETINT *pThis)
956{
957 int rc = VINF_SUCCESS;
958 if (pThis->fSubscribedEvts)
959 {
960 if (WSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
961 {
962 pThis->fSubscribedEvts = 0;
963
964 u_long fNonBlocking = 0;
965 int rc2 = ioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
966 if (rc2 != 0)
967 {
968 rc = rtSocketError();
969 AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
970 }
971 }
972 else
973 {
974 rc = rtSocketError();
975 AssertMsgFailed(("%Rrc\n", rc));
976 }
977 }
978 return rc;
979}
980
981
982/**
983 * Updates the mask of events we're subscribing to.
984 *
985 * @returns IPRT status code.
986 * @param pThis The socket handle.
987 * @param fEvents The events we want to subscribe to.
988 */
989static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
990{
991 LONG fNetworkEvents = 0;
992 if (fEvents & RTPOLL_EVT_READ)
993 fNetworkEvents |= FD_READ;
994 if (fEvents & RTPOLL_EVT_WRITE)
995 fNetworkEvents |= FD_WRITE;
996 if (fEvents & RTPOLL_EVT_ERROR)
997 fNetworkEvents |= FD_CLOSE;
998 if (WSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
999 {
1000 pThis->fSubscribedEvts = fEvents;
1001 return VINF_SUCCESS;
1002 }
1003
1004 int rc = rtSocketError();
1005 AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
1006 return rc;
1007}
1008
1009
1010/**
1011 * Checks for pending events.
1012 *
1013 * @returns Event mask or 0.
1014 * @param pThis The socket handle.
1015 * @param fEvents The desired events.
1016 */
1017static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents)
1018{
1019 int rc = VINF_SUCCESS;
1020 uint32_t fRetEvents = 0;
1021
1022 /* Make sure WSAEnumNetworkEvents returns what we want. */
1023 if ((pThis->fSubscribedEvts & fEvents) != fEvents)
1024 rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
1025
1026 /* Get the event mask, ASSUMES that WSAEnumNetworkEvents doesn't clear stuff. */
1027 WSANETWORKEVENTS NetEvts;
1028 RT_ZERO(NetEvts);
1029 if (WSAEnumNetworkEvents(pThis->hNative, pThis->hEvent, &NetEvts) == 0)
1030 {
1031 if ( (NetEvts.lNetworkEvents & FD_READ)
1032 && (fEvents & RTPOLL_EVT_READ)
1033 && NetEvts.iErrorCode[FD_READ_BIT] == 0)
1034 fRetEvents |= RTPOLL_EVT_READ;
1035
1036 if ( (NetEvts.lNetworkEvents & FD_WRITE)
1037 && (fEvents & RTPOLL_EVT_WRITE)
1038 && NetEvts.iErrorCode[FD_WRITE_BIT] == 0)
1039 fRetEvents |= RTPOLL_EVT_WRITE;
1040
1041 if (fEvents & RTPOLL_EVT_ERROR)
1042 {
1043 if (NetEvts.lNetworkEvents & FD_CLOSE)
1044 fRetEvents |= RTPOLL_EVT_ERROR;
1045 else
1046 for (uint32_t i = 0; i < FD_MAX_EVENTS; i++)
1047 if ( (NetEvts.lNetworkEvents & (1L << i))
1048 && NetEvts.iErrorCode[i] != 0)
1049 fRetEvents |= RTPOLL_EVT_ERROR;
1050 }
1051 }
1052 else
1053 rc = rtSocketError();
1054
1055 /* Fall back on select if we hit an error above. */
1056 if (RT_FAILURE(rc))
1057 {
1058 /** @todo */
1059 }
1060
1061 return fRetEvents;
1062}
1063
1064
1065/**
1066 * Internal RTPoll helper that polls the socket handle and, if @a fNoWait is
1067 * clear, starts whatever actions we've got running during the poll call.
1068 *
1069 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
1070 * Event mask (in @a fEvents) and no actions if the handle is ready
1071 * already.
1072 * UINT32_MAX (asserted) if the socket handle is busy in I/O or a
1073 * different poll set.
1074 *
1075 * @param hSocket The socket handle.
1076 * @param hPollSet The poll set handle (for access checks).
1077 * @param fEvents The events we're polling for.
1078 * @param fFinalEntry Set if this is the final entry for this handle
1079 * in this poll set. This can be used for dealing
1080 * with duplicate entries.
1081 * @param fNoWait Set if it's a zero-wait poll call. Clear if
1082 * we'll wait for an event to occur.
1083 *
1084 * @remarks There is a potential race wrt duplicate handles when @a fNoWait is
1085 * @c true, we don't currently care about that oddity...
1086 */
1087uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
1088{
1089 RTSOCKETINT *pThis = hSocket;
1090 AssertPtrReturn(pThis, UINT32_MAX);
1091 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
1092 if (rtSocketTryLock(pThis))
1093 pThis->hPollSet = hPollSet;
1094 else
1095 {
1096 AssertReturn(pThis->hPollSet == hPollSet, UINT32_MAX);
1097 ASMAtomicIncU32(&pThis->cUsers);
1098 }
1099
1100 /* (rtSocketPollCheck will reset the event object). */
1101 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
1102 if ( !fRetEvents
1103 && !fNoWait)
1104 {
1105 pThis->fPollEvts |= fEvents;
1106 if ( fFinalEntry
1107 && pThis->fSubscribedEvts != pThis->fPollEvts)
1108 {
1109 int rc = rtSocketPollUpdateEvents(pThis, pThis->fPollEvts);
1110 if (RT_FAILURE(rc))
1111 {
1112 pThis->fPollEvts = 0;
1113 fRetEvents = UINT32_MAX;
1114 }
1115 }
1116 }
1117
1118 if (fRetEvents || fNoWait)
1119 {
1120 if (pThis->cUsers == 1)
1121 {
1122 rtSocketPollClearEventAndMakeBlocking(pThis);
1123 pThis->hPollSet = NIL_RTPOLLSET;
1124 }
1125 ASMAtomicDecU32(&pThis->cUsers);
1126 }
1127
1128 return fRetEvents;
1129}
1130
1131
1132/**
1133 * Called after a WaitForMultipleObjects returned in order to check for pending
1134 * events and stop whatever actions that rtSocketPollStart() initiated.
1135 *
1136 * @returns Event mask or 0.
1137 *
1138 * @param hSocket The socket handle.
1139 * @param fEvents The events we're polling for.
1140 * @param fFinalEntry Set if this is the final entry for this handle
1141 * in this poll set. This can be used for dealing
1142 * with duplicate entries. Only keep in mind that
1143 * this method is called in reverse order, so the
1144 * first call will have this set (when the entire
1145 * set was processed).
1146 */
1147uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry)
1148{
1149 RTSOCKETINT *pThis = hSocket;
1150 AssertPtrReturn(pThis, 0);
1151 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, 0);
1152 Assert(pThis->cUsers > 0);
1153 Assert(pThis->hPollSet != NIL_RTPOLLSET);
1154
1155 /* Harvest events and clear the event mask for the next round of polling. */
1156 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
1157 pThis->fPollEvts = 0;
1158
1159 /* Make the socket blocking again and unlock the handle. */
1160 if (pThis->cUsers == 1)
1161 {
1162 rtSocketPollClearEventAndMakeBlocking(pThis);
1163 pThis->hPollSet = NIL_RTPOLLSET;
1164 }
1165 ASMAtomicDecU32(&pThis->cUsers);
1166 return fRetEvents;
1167}
1168
1169#endif /* RT_OS_WINDOWS */
Note: See TracBrowser for help on using the repository browser.

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