VirtualBox

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

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

RT: temporary commented out owner assert in RT socket's shutdown() - we do that concurrently sometimes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 31.4 KB
Line 
1/* $Id: socket.cpp 27541 2010-03-19 15:31: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 count. This is used to prevent two threads from accessing the
124 * handle concurrently. */
125 uint32_t volatile cUsers;
126#ifdef RT_OS_WINDOWS
127 /** The native socket handle. */
128 SOCKET hNative;
129 /** The event semaphore we've associated with the socket handle.
130 * This is WSA_INVALID_EVENT if not done. */
131 WSAEVENT hEvent;
132 /** The pollset currently polling this socket. This is NIL if no one is
133 * polling. */
134 RTPOLLSET hPollSet;
135 /** The events we're polling for. */
136 uint32_t fPollEvts;
137 /** The events we're currently subscribing to with WSAEventSelect.
138 * This is ZERO if we're currently not subscribing to anything. */
139 uint32_t fSubscribedEvts;
140#else
141 /** The native socket handle. */
142 int hNative;
143#endif
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,
249#ifdef RT_OS_WINDOWS
250 SOCKET hNative
251#else
252 int hNative
253#endif
254 )
255{
256 RTSOCKETINT *pThis = (RTSOCKETINT *)RTMemAlloc(sizeof(*pThis));
257 if (!pThis)
258 return VERR_NO_MEMORY;
259 pThis->u32Magic = RTSOCKET_MAGIC;
260 pThis->cUsers = 0;
261 pThis->hNative = hNative;
262#ifdef RT_OS_WINDOWS
263 pThis->hEvent = WSA_INVALID_EVENT;
264 pThis->hPollSet = NIL_RTPOLLSET;
265 pThis->fPollEvts = 0;
266 pThis->fSubscribedEvts = 0;
267#endif
268 *ppSocket = pThis;
269 return VINF_SUCCESS;
270}
271
272
273/**
274 * Wrapper around socket().
275 *
276 * @returns IPRT status code.
277 * @param phSocket Where to store the handle to the socket on
278 * success.
279 * @param iDomain The protocol family (PF_XXX).
280 * @param iType The socket type (SOCK_XXX).
281 * @param iProtocol Socket parameter, usually 0.
282 */
283int rtSocketCreate(PRTSOCKET phSocket, int iDomain, int iType, int iProtocol)
284{
285 /*
286 * Create the socket.
287 */
288#ifdef RT_OS_WINDOWS
289 SOCKET hNative = socket(iDomain, iType, iProtocol);
290 if (hNative == INVALID_SOCKET)
291 return rtSocketError();
292#else
293 int hNative = socket(iDomain, iType, iProtocol);
294 if (hNative == -1)
295 return rtSocketError();
296#endif
297
298 /*
299 * Wrap it.
300 */
301 int rc = rtSocketCreateForNative(phSocket, hNative);
302 if (RT_FAILURE(rc))
303 {
304#ifdef RT_OS_WINDOWS
305 closesocket(hNative);
306#else
307 close(hNative);
308#endif
309 }
310 return rc;
311}
312
313
314RTDECL(int) RTSocketDestroy(RTSOCKET hSocket)
315{
316 RTSOCKETINT *pThis = hSocket;
317 if (pThis == NIL_RTSOCKET)
318 return VINF_SUCCESS;
319 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
320 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
321
322 Assert(pThis->cUsers == 0);
323 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSOCKET_MAGIC_DEAD, RTSOCKET_MAGIC), VERR_INVALID_HANDLE);
324
325 /*
326 * Do the cleanup.
327 */
328 int rc = VINF_SUCCESS;
329#ifdef RT_OS_WINDOWS
330 if (pThis->hEvent == WSA_INVALID_EVENT)
331 {
332 WSACloseEvent(pThis->hEvent);
333 pThis->hEvent = WSA_INVALID_EVENT;
334 }
335
336 if (pThis->hNative != INVALID_SOCKET)
337 {
338 rc = closesocket(pThis->hNative);
339 if (!rc)
340 rc = VINF_SUCCESS;
341 else
342 {
343 rc = rtSocketError();
344 AssertMsgFailed(("\"%s\": closesocket(%p) -> %Rrc\n", pThis->hNative, rc));
345 }
346 pThis->hNative = INVALID_SOCKET;
347 }
348
349#else
350 if (pThis->hNative != -1)
351 {
352 if (close(pThis->hNative))
353 {
354 rc = rtSocketError();
355 AssertMsgFailed(("\"%s\": close(%d) -> %Rrc\n", pThis->hNative, rc));
356 }
357 pThis->hNative = -1;
358 }
359#endif
360
361 return rc;
362}
363
364
365RTDECL(RTHCUINTPTR) RTSocketToNative(RTSOCKET hSocket)
366{
367 RTSOCKETINT *pThis = hSocket;
368 AssertPtrReturn(pThis, RTHCUINTPTR_MAX);
369 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, RTHCUINTPTR_MAX);
370 return (RTHCUINTPTR)pThis->hNative;
371}
372
373
374RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable)
375{
376 RTSOCKETINT *pThis = hSocket;
377 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
378 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
379 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
380
381 int rc = VINF_SUCCESS;
382#ifdef RT_OS_WINDOWS
383 if (!SetHandleInformation((HANDLE)pThis->hNative, HANDLE_FLAG_INHERIT, fInheritable ? HANDLE_FLAG_INHERIT : 0))
384 rc = RTErrConvertFromWin32(GetLastError());
385#else
386 if (fcntl(pThis->hNative, F_SETFD, fInheritable ? 0 : FD_CLOEXEC) < 0)
387 rc = RTErrConvertFromErrno(errno);
388#endif
389 AssertRC(rc); /// @todo remove later.
390
391 rtSocketUnlock(pThis);
392 return rc;
393}
394
395
396RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
397{
398 /*
399 * Validate input.
400 */
401 RTSOCKETINT *pThis = hSocket;
402 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
403 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
404 AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
405 AssertPtr(pvBuffer);
406 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
407
408 /*
409 * Read loop.
410 * If pcbRead is NULL we have to fill the entire buffer!
411 */
412 int rc = VINF_SUCCESS;
413 size_t cbRead = 0;
414 size_t cbToRead = cbBuffer;
415 for (;;)
416 {
417 rtSocketErrorReset();
418#ifdef RT_OS_WINDOWS
419 int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
420#else
421 size_t cbNow = cbToRead;
422#endif
423 ssize_t cbBytesRead = recv(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL);
424 if (cbBytesRead <= 0)
425 {
426 rc = rtSocketError();
427 Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
428 if (RT_SUCCESS_NP(rc))
429 {
430 if (!pcbRead)
431 rc = VERR_NET_SHUTDOWN;
432 else
433 {
434 *pcbRead = 0;
435 rc = VINF_SUCCESS;
436 }
437 }
438 break;
439 }
440 if (pcbRead)
441 {
442 /* return partial data */
443 *pcbRead = cbBytesRead;
444 break;
445 }
446
447 /* read more? */
448 cbRead += cbBytesRead;
449 if (cbRead == cbBuffer)
450 break;
451
452 /* next */
453 cbToRead = cbBuffer - cbRead;
454 }
455
456 rtSocketUnlock(pThis);
457 return rc;
458}
459
460
461RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer)
462{
463 /*
464 * Validate input.
465 */
466 RTSOCKETINT *pThis = hSocket;
467 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
468 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
469 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
470
471 /*
472 * Try write all at once.
473 */
474 int rc = VINF_SUCCESS;
475#ifdef RT_OS_WINDOWS
476 int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
477#else
478 size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
479#endif
480 ssize_t cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
481 if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
482 rc = VINF_SUCCESS;
483 else if (cbWritten < 0)
484 rc = rtSocketError();
485 else
486 {
487 /*
488 * Unfinished business, write the remainder of the request. Must ignore
489 * VERR_INTERRUPTED here if we've managed to send something.
490 */
491 size_t cbSentSoFar = 0;
492 for (;;)
493 {
494 /* advance */
495 cbBuffer -= (size_t)cbWritten;
496 if (!cbBuffer)
497 break;
498 cbSentSoFar += (size_t)cbWritten;
499 pvBuffer = (char const *)pvBuffer + cbWritten;
500
501 /* send */
502#ifdef RT_OS_WINDOWS
503 cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer;
504#else
505 cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
506#endif
507 cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL);
508 if (cbWritten >= 0)
509 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%zu cbBuffer=%zu rtSocketError()=%d\n",
510 cbWritten, cbBuffer, rtSocketError()));
511 else
512 {
513 rc = rtSocketError();
514 if (rc != VERR_INTERNAL_ERROR || cbSentSoFar == 0)
515 break;
516 cbWritten = 0;
517 rc = VINF_SUCCESS;
518 }
519 }
520 }
521
522 rtSocketUnlock(pThis);
523 return rc;
524}
525
526
527RTDECL(int) RTSocketSelectOne(RTSOCKET hSocket, RTMSINTERVAL cMillies)
528{
529 /*
530 * Validate input.
531 */
532 RTSOCKETINT *pThis = hSocket;
533 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
534 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
535 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
536
537 /*
538 * Set up the file descriptor sets and do the select.
539 */
540 fd_set fdsetR;
541 FD_ZERO(&fdsetR);
542 FD_SET(pThis->hNative, &fdsetR);
543
544 fd_set fdsetE = fdsetR;
545
546 int rc;
547 if (cMillies == RT_INDEFINITE_WAIT)
548 rc = select(pThis->hNative + 1, &fdsetR, NULL, &fdsetE, NULL);
549 else
550 {
551 struct timeval timeout;
552 timeout.tv_sec = cMillies / 1000;
553 timeout.tv_usec = (cMillies % 1000) * 1000;
554 rc = select(pThis->hNative + 1, &fdsetR, NULL, &fdsetE, &timeout);
555 }
556 if (rc > 0)
557 rc = VINF_SUCCESS;
558 else if (rc == 0)
559 rc = VERR_TIMEOUT;
560 else
561 rc = rtSocketError();
562
563 rtSocketUnlock(pThis);
564 return rc;
565}
566
567
568RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite)
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(fRead || fWrite, VERR_INVALID_PARAMETER);
577 //AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
578
579 /*
580 * Do the job.
581 */
582 int rc = VINF_SUCCESS;
583 int fHow;
584 if (fRead && fWrite)
585 fHow = SHUT_RDWR;
586 else if (fRead)
587 fHow = SHUT_RD;
588 else
589 fHow = SHUT_WR;
590 if (shutdown(pThis->hNative, fHow) == -1)
591 rc = rtSocketError();
592
593 rtSocketUnlock(pThis);
594 return rc;
595}
596
597
598/**
599 * Converts from a native socket address to a generic IPRT network address.
600 *
601 * @returns IPRT status code.
602 * @param pSrc The source address.
603 * @param cbSrc The size of the source address.
604 * @param pAddr Where to return the generic IPRT network
605 * address.
606 */
607static int rtSocketConvertAddress(RTSOCKADDRUNION const *pSrc, size_t cbSrc, PRTNETADDR pAddr)
608{
609 /*
610 * Convert the address.
611 */
612 if ( cbSrc == sizeof(struct sockaddr_in)
613 && pSrc->Addr.sa_family == AF_INET)
614 {
615 RT_ZERO(*pAddr);
616 pAddr->enmType = RTNETADDRTYPE_IPV4;
617 pAddr->uPort = RT_N2H_U16(pSrc->Ipv4.sin_port);
618 pAddr->uAddr.IPv4.u = pSrc->Ipv4.sin_addr.s_addr;
619 }
620#ifdef IPRT_WITH_TCPIP_V6
621 else if ( cbSrc == sizeof(struct sockaddr_in6)
622 && pSrc->Addr.sa_family == AF_INET6)
623 {
624 RT_ZERO(*pAddr);
625 pAddr->enmType = RTNETADDRTYPE_IPV6;
626 pAddr->uPort = RT_N2H_U16(pSrc->Ipv6.sin6_port);
627 pAddr->uAddr.IPv6.au32[0] = pSrc->Ipv6.sin6_addr.s6_addr32[0];
628 pAddr->uAddr.IPv6.au32[1] = pSrc->Ipv6.sin6_addr.s6_addr32[1];
629 pAddr->uAddr.IPv6.au32[2] = pSrc->Ipv6.sin6_addr.s6_addr32[2];
630 pAddr->uAddr.IPv6.au32[3] = pSrc->Ipv6.sin6_addr.s6_addr32[3];
631 }
632#endif
633 else
634 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
635 return VINF_SUCCESS;
636}
637
638
639RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
640{
641 /*
642 * Validate input.
643 */
644 RTSOCKETINT *pThis = hSocket;
645 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
646 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
647 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
648
649 /*
650 * Get the address and convert it.
651 */
652 int rc;
653 RTSOCKADDRUNION u;
654#ifdef RT_OS_WINDOWS
655 int cbAddr = sizeof(u);
656#else
657 socklen_t cbAddr = sizeof(u);
658#endif
659 RT_ZERO(u);
660 if (getsockname(pThis->hNative, &u.Addr, &cbAddr) == 0)
661 rc = rtSocketConvertAddress(&u, cbAddr, pAddr);
662 else
663 rc = rtSocketError();
664
665 rtSocketUnlock(pThis);
666 return rc;
667}
668
669
670RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
671{
672 /*
673 * Validate input.
674 */
675 RTSOCKETINT *pThis = hSocket;
676 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
677 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
678 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
679
680 /*
681 * Get the address and convert it.
682 */
683 int rc;
684 RTSOCKADDRUNION u;
685#ifdef RT_OS_WINDOWS
686 int cbAddr = sizeof(u);
687#else
688 socklen_t cbAddr = sizeof(u);
689#endif
690 RT_ZERO(u);
691 if (getpeername(pThis->hNative, &u.Addr, &cbAddr) == 0)
692 rc = rtSocketConvertAddress(&u, cbAddr, pAddr);
693 else
694 rc = rtSocketError();
695
696 rtSocketUnlock(pThis);
697 return rc;
698}
699
700
701
702/**
703 * Wrapper around bind.
704 *
705 * @returns IPRT status code.
706 * @param hSocket The socket handle.
707 * @param pAddr The socket address to bind to.
708 * @param cbAddr The size of the address structure @a pAddr
709 * points to.
710 */
711int rtSocketBind(RTSOCKET hSocket, const struct sockaddr *pAddr, int cbAddr)
712{
713 /*
714 * Validate input.
715 */
716 RTSOCKETINT *pThis = hSocket;
717 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
718 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
719 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
720
721 int rc = VINF_SUCCESS;
722 if (bind(pThis->hNative, pAddr, cbAddr) != 0)
723 rc = rtSocketError();
724
725 rtSocketUnlock(pThis);
726 return rc;
727}
728
729
730/**
731 * Wrapper around listen.
732 *
733 * @returns IPRT status code.
734 * @param hSocket The socket handle.
735 * @param cMaxPending The max number of pending connections.
736 */
737int rtSocketListen(RTSOCKET hSocket, int cMaxPending)
738{
739 /*
740 * Validate input.
741 */
742 RTSOCKETINT *pThis = hSocket;
743 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
744 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
745 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
746
747 int rc = VINF_SUCCESS;
748 if (listen(pThis->hNative, cMaxPending) != 0)
749 rc = rtSocketError();
750
751 rtSocketUnlock(pThis);
752 return rc;
753}
754
755
756/**
757 * Wrapper around accept.
758 *
759 * @returns IPRT status code.
760 * @param hSocket The socket handle.
761 * @param phClient Where to return the client socket handle on
762 * success.
763 * @param pAddr Where to return the client address.
764 * @param pcbAddr On input this gives the size buffer size of what
765 * @a pAddr point to. On return this contains the
766 * size of what's stored at @a pAddr.
767 */
768int rtSocketAccept(RTSOCKET hSocket, PRTSOCKET phClient, struct sockaddr *pAddr, size_t *pcbAddr)
769{
770 /*
771 * Validate input.
772 */
773 RTSOCKETINT *pThis = hSocket;
774 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
775 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
776 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
777
778 /*
779 * Call accept().
780 */
781 rtSocketErrorReset();
782 int rc = VINF_SUCCESS;
783#ifdef RT_OS_WINDOWS
784 int cbAddr = (int)*pcbAddr;
785 SOCKET hNative = accept(pThis->hNative, pAddr, &cbAddr);
786 if (hNative != INVALID_SOCKET)
787#else
788 socklen_t cbAddr = *pcbAddr;
789 int hNative = accept(pThis->hNative, pAddr, &cbAddr);
790 if (hNative != -1)
791#endif
792 {
793 *pcbAddr = cbAddr;
794
795 /*
796 * Wrap the client socket.
797 */
798 rc = rtSocketCreateForNative(phClient, hNative);
799 if (RT_FAILURE(rc))
800 {
801#ifdef RT_OS_WINDOWS
802 closesocket(hNative);
803#else
804 close(hNative);
805#endif
806 }
807 }
808 else
809 rc = rtSocketError();
810
811 rtSocketUnlock(pThis);
812 return rc;
813}
814
815
816/**
817 * Wrapper around connect.
818 *
819 * @returns IPRT status code.
820 * @param hSocket The socket handle.
821 * @param pAddr The socket address to connect to.
822 * @param cbAddr The size of the address structure @a pAddr
823 * points to.
824 */
825int rtSocketConnect(RTSOCKET hSocket, const struct sockaddr *pAddr, int cbAddr)
826{
827 /*
828 * Validate input.
829 */
830 RTSOCKETINT *pThis = hSocket;
831 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
832 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
833 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
834
835 int rc = VINF_SUCCESS;
836 if (connect(pThis->hNative, pAddr, cbAddr) != 0)
837 rc = rtSocketError();
838
839 rtSocketUnlock(pThis);
840 return rc;
841}
842
843
844/**
845 * Wrapper around setsockopt.
846 *
847 * @returns IPRT status code.
848 * @param hSocket The socket handle.
849 * @param iLevel The protocol level, e.g. IPPORTO_TCP.
850 * @param iOption The option, e.g. TCP_NODELAY.
851 * @param pvValue The value buffer.
852 * @param cbValue The size of the value pointed to by pvValue.
853 */
854int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValue, int cbValue)
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 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
863
864 int rc = VINF_SUCCESS;
865 if (setsockopt(pThis->hNative, iLevel, iOption, (const char *)pvValue, cbValue) != 0)
866 rc = rtSocketError();
867
868 rtSocketUnlock(pThis);
869 return rc;
870}
871
872#ifdef RT_OS_WINDOWS
873
874/**
875 * Internal RTPollSetAdd helper that returns the handle that should be added to
876 * the pollset.
877 *
878 * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure.
879 * @param hSocket The socket handle.
880 * @param fEvents The events we're polling for.
881 * @param ph wher to put the primary handle.
882 */
883int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph)
884{
885 RTSOCKETINT *pThis = hSocket;
886 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
887 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
888 AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
889
890 int rc = VINF_SUCCESS;
891 if (pThis->hEvent != WSA_INVALID_EVENT)
892 *ph = pThis->hEvent;
893 else
894 {
895 *ph = pThis->hEvent = WSACreateEvent();
896 if (pThis->hEvent == WSA_INVALID_EVENT)
897 rc = rtSocketError();
898 }
899
900 rtSocketUnlock(pThis);
901 return rc;
902}
903
904
905/**
906 * Undos the harm done by WSAEventSelect.
907 *
908 * @returns IPRT status code.
909 * @param pThis The socket handle.
910 */
911static int rtSocketPollClearEventAndMakeBlocking(RTSOCKETINT *pThis)
912{
913 int rc = VINF_SUCCESS;
914 if (pThis->fSubscribedEvts)
915 {
916 if (WSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
917 {
918 pThis->fSubscribedEvts = 0;
919
920 u_long fNonBlocking = 0;
921 int rc2 = ioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
922 if (rc2 != 0)
923 {
924 rc = rtSocketError();
925 AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
926 }
927 }
928 else
929 {
930 rc = rtSocketError();
931 AssertMsgFailed(("%Rrc\n", rc));
932 }
933 }
934 return rc;
935}
936
937
938/**
939 * Updates the mask of events we're subscribing to.
940 *
941 * @returns IPRT status code.
942 * @param pThis The socket handle.
943 * @param fEvents The events we want to subscribe to.
944 */
945static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
946{
947 LONG fNetworkEvents = 0;
948 if (fEvents & RTPOLL_EVT_READ)
949 fNetworkEvents |= FD_READ;
950 if (fEvents & RTPOLL_EVT_WRITE)
951 fNetworkEvents |= FD_WRITE;
952 if (fEvents & RTPOLL_EVT_ERROR)
953 fNetworkEvents |= FD_CLOSE;
954 if (WSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
955 {
956 pThis->fSubscribedEvts = fEvents;
957 return VINF_SUCCESS;
958 }
959
960 int rc = rtSocketError();
961 AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
962 return rc;
963}
964
965
966/**
967 * Checks for pending events.
968 *
969 * @returns Event mask or 0.
970 * @param pThis The socket handle.
971 * @param fEvents The desired events.
972 */
973static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents)
974{
975 int rc = VINF_SUCCESS;
976 uint32_t fRetEvents = 0;
977
978 /* Make sure WSAEnumNetworkEvents returns what we want. */
979 if ((pThis->fSubscribedEvts & fEvents) != fEvents)
980 rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
981
982 /* Get the event mask, ASSUMES that WSAEnumNetworkEvents doesn't clear stuff. */
983 WSANETWORKEVENTS NetEvts;
984 RT_ZERO(NetEvts);
985 if (WSAEnumNetworkEvents(pThis->hNative, pThis->hEvent, &NetEvts) == 0)
986 {
987 if ( (NetEvts.lNetworkEvents & FD_READ)
988 && (fEvents & RTPOLL_EVT_READ)
989 && NetEvts.iErrorCode[FD_READ_BIT] == 0)
990 fRetEvents |= RTPOLL_EVT_READ;
991
992 if ( (NetEvts.lNetworkEvents & FD_WRITE)
993 && (fEvents & RTPOLL_EVT_WRITE)
994 && NetEvts.iErrorCode[FD_WRITE_BIT] == 0)
995 fRetEvents |= RTPOLL_EVT_WRITE;
996
997 if (fEvents & RTPOLL_EVT_ERROR)
998 {
999 if (NetEvts.lNetworkEvents & FD_CLOSE)
1000 fRetEvents |= RTPOLL_EVT_ERROR;
1001 else
1002 for (uint32_t i = 0; i < FD_MAX_EVENTS; i++)
1003 if ( (NetEvts.lNetworkEvents & (1L << i))
1004 && NetEvts.iErrorCode[i] != 0)
1005 fRetEvents |= RTPOLL_EVT_ERROR;
1006 }
1007 }
1008 else
1009 rc = rtSocketError();
1010
1011 /* Fall back on select if we hit an error above. */
1012 if (RT_FAILURE(rc))
1013 {
1014 /** @todo */
1015 }
1016
1017 return fRetEvents;
1018}
1019
1020
1021/**
1022 * Internal RTPoll helper that polls the socket handle and, if @a fNoWait is
1023 * clear, starts whatever actions we've got running during the poll call.
1024 *
1025 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear.
1026 * Event mask (in @a fEvents) and no actions if the handle is ready
1027 * already.
1028 * UINT32_MAX (asserted) if the socket handle is busy in I/O or a
1029 * different poll set.
1030 *
1031 * @param hSocket The socket handle.
1032 * @param hPollSet The poll set handle (for access checks).
1033 * @param fEvents The events we're polling for.
1034 * @param fFinalEntry Set if this is the final entry for this handle
1035 * in this poll set. This can be used for dealing
1036 * with duplicate entries.
1037 * @param fNoWait Set if it's a zero-wait poll call. Clear if
1038 * we'll wait for an event to occur.
1039 *
1040 * @remarks There is a potential race wrt duplicate handles when @a fNoWait is
1041 * @c true, we don't currently care about that oddity...
1042 */
1043uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvents, bool fFinalEntry, bool fNoWait)
1044{
1045 RTSOCKETINT *pThis = hSocket;
1046 AssertPtrReturn(pThis, UINT32_MAX);
1047 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX);
1048 if (rtSocketTryLock(pThis))
1049 pThis->hPollSet = hPollSet;
1050 else
1051 {
1052 AssertReturn(pThis->hPollSet == hPollSet, UINT32_MAX);
1053 ASMAtomicIncU32(&pThis->cUsers);
1054 }
1055
1056 /* (rtSocketPollCheck will reset the event object). */
1057 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
1058 if ( !fRetEvents
1059 && !fNoWait)
1060 {
1061 pThis->fPollEvts |= fEvents;
1062 if ( fFinalEntry
1063 && pThis->fSubscribedEvts != pThis->fPollEvts)
1064 {
1065 int rc = rtSocketPollUpdateEvents(pThis, pThis->fPollEvts);
1066 if (RT_FAILURE(rc))
1067 {
1068 pThis->fPollEvts = 0;
1069 fRetEvents = UINT32_MAX;
1070 }
1071 }
1072 }
1073
1074 if (fRetEvents || fNoWait)
1075 {
1076 if (pThis->cUsers == 1)
1077 {
1078 rtSocketPollClearEventAndMakeBlocking(pThis);
1079 pThis->hPollSet = NIL_RTPOLLSET;
1080 }
1081 ASMAtomicDecU32(&pThis->cUsers);
1082 }
1083
1084 return fRetEvents;
1085}
1086
1087
1088/**
1089 * Called after a WaitForMultipleObjects returned in order to check for pending
1090 * events and stop whatever actions that rtSocketPollStart() initiated.
1091 *
1092 * @returns Event mask or 0.
1093 *
1094 * @param hSocket The socket handle.
1095 * @param fEvents The events we're polling for.
1096 * @param fFinalEntry Set if this is the final entry for this handle
1097 * in this poll set. This can be used for dealing
1098 * with duplicate entries. Only keep in mind that
1099 * this method is called in reverse order, so the
1100 * first call will have this set (when the entire
1101 * set was processed).
1102 */
1103uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry)
1104{
1105 RTSOCKETINT *pThis = hSocket;
1106 AssertPtrReturn(pThis, 0);
1107 AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, 0);
1108 Assert(pThis->cUsers > 0);
1109 Assert(pThis->hPollSet != NIL_RTPOLLSET);
1110
1111 /* Harvest events and clear the event mask for the next round of polling. */
1112 uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
1113 pThis->fPollEvts = 0;
1114
1115 /* Make the socket blocking again and unlock the handle. */
1116 if (pThis->cUsers == 1)
1117 {
1118 rtSocketPollClearEventAndMakeBlocking(pThis);
1119 pThis->hPollSet = NIL_RTPOLLSET;
1120 }
1121 ASMAtomicDecU32(&pThis->cUsers);
1122 return fRetEvents;
1123}
1124
1125#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