VirtualBox

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

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

iprt/socket.cpp: relaxed the locking for accept and shutdown.

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