VirtualBox

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

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

socket.cpp: build fix.

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