VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/tcp.cpp@ 27503

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

iprt/socket.h: RTSocket API.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 32.0 KB
Line 
1/* $Id: tcp.cpp 27503 2010-03-18 20:52:02Z vboxsync $ */
2/** @file
3 * IPRT - TCP/IP.
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.215389.xyz. 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#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/tcp.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/mem.h>
62#include <iprt/string.h>
63#include <iprt/socket.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#ifndef SHUT_RDWR
79# ifdef SD_BOTH
80# define SHUT_RDWR SD_BOTH
81# else
82# define SHUT_RDWR 2
83# endif
84#endif
85#ifndef SHUT_WR
86# ifdef SD_SEND
87# define SHUT_WR SD_SEND
88# else
89# define SHUT_WR 1
90# endif
91#endif
92
93/* fixup backlevel OSes. */
94#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
95# define socklen_t int
96#endif
97
98/** How many pending connection. */
99#define RTTCP_SERVER_BACKLOG 10
100
101
102/*******************************************************************************
103* Structures and Typedefs *
104*******************************************************************************/
105/**
106 * Socket handle data.
107 *
108 * This is mainly required for implementing RTPollSet on Windows.
109 */
110typedef struct RTSOCKETINT
111{
112 /** Magic number (RTTCPSOCKET_MAGIC). */
113 uint32_t u32Magic;
114 /** Usage count. This is used to prevent two threads from accessing the
115 * handle concurrently. */
116 uint32_t volatile cUsers;
117#ifdef RT_OS_WINDOWS
118 /** The native socket handle. */
119 SOCKET hNative;
120 /** The event semaphore we've associated with the socket handle.
121 * This is INVALID_HANDLE_VALUE if not done. */
122 WSAEVENT hEvent;
123 /** The pollset currently polling this socket. This is NIL if no one is
124 * polling. */
125 RTPOLLSET hPollSet;
126 /** The events we're polling for. */
127 uint32_t fPollEvts;
128#else
129 /** The native socket handle. */
130 int hNative;
131#endif
132} RTSOCKETINT;
133
134
135/**
136 * Address union used internally for things like getpeername and getsockname.
137 */
138typedef union RTSOCKADDRUNION
139{
140 struct sockaddr Addr;
141 struct sockaddr_in Ipv4;
142#ifdef IPRT_WITH_TCPIP_V6
143 struct sockaddr_in6 Ipv6;
144#endif
145} RTSOCKADDRUNION;
146
147
148
149/**
150 * TCP Server state.
151 */
152typedef enum RTTCPSERVERSTATE
153{
154 /** Invalid. */
155 RTTCPSERVERSTATE_INVALID = 0,
156 /** Created. */
157 RTTCPSERVERSTATE_CREATED,
158 /** Listener thread is starting up. */
159 RTTCPSERVERSTATE_STARTING,
160 /** Accepting client connections. */
161 RTTCPSERVERSTATE_ACCEPTING,
162 /** Serving a client. */
163 RTTCPSERVERSTATE_SERVING,
164 /** Listener terminating. */
165 RTTCPSERVERSTATE_STOPPING,
166 /** Listener terminated. */
167 RTTCPSERVERSTATE_STOPPED,
168 /** Listener cleans up. */
169 RTTCPSERVERSTATE_DESTROYING
170} RTTCPSERVERSTATE;
171
172/*
173 * Internal representation of the TCP Server handle.
174 */
175typedef struct RTTCPSERVER
176{
177 /** The magic value (RTTCPSERVER_MAGIC). */
178 uint32_t volatile u32Magic;
179 /** The server state. */
180 RTTCPSERVERSTATE volatile enmState;
181 /** The server thread. */
182 RTTHREAD Thread;
183 /** The server socket. */
184 RTSOCKET volatile SockServer;
185 /** The socket to the client currently being serviced.
186 * This is NIL_RTSOCKET when no client is serviced. */
187 RTSOCKET volatile SockClient;
188 /** The connection function. */
189 PFNRTTCPSERVE pfnServe;
190 /** Argument to pfnServer. */
191 void *pvUser;
192} RTTCPSERVER;
193
194
195/*******************************************************************************
196* Internal Functions *
197*******************************************************************************/
198static DECLCALLBACK(int) rtTcpServerThread(RTTHREAD ThreadSelf, void *pvServer);
199static int rtTcpServerListen(PRTTCPSERVER pServer);
200static int rtTcpServerListenCleanup(PRTTCPSERVER pServer);
201static int rtTcpServerDestroySocket(RTSOCKET volatile *pSockClient, const char *pszMsg);
202static int rtTcpClose(RTSOCKET Sock, const char *pszMsg, bool fTryGracefulShutdown);
203
204
205/**
206 * Atomicly updates a socket variable.
207 * @returns The old handle value.
208 * @param phSock The socket handle variable to update.
209 * @param hSock The new socket handle value.
210 */
211DECLINLINE(RTSOCKET) rtTcpAtomicXchgSock(RTSOCKET volatile *phSock, const RTSOCKET hNew)
212{
213 RTSOCKET hRet;
214 ASMAtomicXchgHandle(phSock, hNew, &hRet);
215 return hRet;
216}
217
218
219/**
220 * Tries to change the TCP server state.
221 */
222DECLINLINE(bool) rtTcpServerTrySetState(PRTTCPSERVER pServer, RTTCPSERVERSTATE enmStateNew, RTTCPSERVERSTATE enmStateOld)
223{
224 bool fRc;
225 ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc);
226 return fRc;
227}
228
229/**
230 * Changes the TCP server state.
231 */
232DECLINLINE(void) rtTcpServerSetState(PRTTCPSERVER pServer, RTTCPSERVERSTATE enmStateNew, RTTCPSERVERSTATE enmStateOld)
233{
234 bool fRc;
235 ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc);
236 Assert(fRc); NOREF(fRc);
237}
238
239
240/**
241 * Closes the a socket (client or server).
242 *
243 * @returns IPRT status code.
244 */
245static int rtTcpServerDestroySocket(RTSOCKET volatile *pSock, const char *pszMsg, bool fTryGracefulShutdown)
246{
247 RTSOCKET hSocket = rtTcpAtomicXchgSock(pSock, NIL_RTSOCKET);
248 if (hSocket != NIL_RTSOCKET)
249 {
250 if (!fTryGracefulShutdown)
251 RTSocketShutdown(hSocket, true /*fRead*/, true /*fWrite*/);
252 return rtTcpClose(hSocket, pszMsg, fTryGracefulShutdown);
253 }
254 return VINF_TCP_SERVER_NO_CLIENT;
255}
256
257
258/**
259 * Create single connection at a time TCP Server in a separate thread.
260 *
261 * The thread will loop accepting connections and call pfnServe for
262 * each of the incoming connections in turn. The pfnServe function can
263 * return VERR_TCP_SERVER_STOP too terminate this loop. RTTcpServerDestroy()
264 * should be used to terminate the server.
265 *
266 * @returns iprt status code.
267 * @param pszAddress The address for creating a listening socket.
268 * If NULL or empty string the server is bound to all interfaces.
269 * @param uPort The port for creating a listening socket.
270 * @param enmType The thread type.
271 * @param pszThrdName The name of the worker thread.
272 * @param pfnServe The function which will serve a new client connection.
273 * @param pvUser User argument passed to pfnServe.
274 * @param ppServer Where to store the serverhandle.
275 */
276RTR3DECL(int) RTTcpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName,
277 PFNRTTCPSERVE pfnServe, void *pvUser, PPRTTCPSERVER ppServer)
278{
279 /*
280 * Validate input.
281 */
282 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
283 AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
284 AssertPtrReturn(pszThrdName, VERR_INVALID_POINTER);
285 AssertPtrReturn(ppServer, VERR_INVALID_POINTER);
286
287 /*
288 * Create the server.
289 */
290 PRTTCPSERVER pServer;
291 int rc = RTTcpServerCreateEx(pszAddress, uPort, &pServer);
292 if (RT_SUCCESS(rc))
293 {
294 /*
295 * Create the listener thread.
296 */
297 RTMemPoolRetain(pServer);
298 pServer->enmState = RTTCPSERVERSTATE_STARTING;
299 pServer->pvUser = pvUser;
300 pServer->pfnServe = pfnServe;
301 rc = RTThreadCreate(&pServer->Thread, rtTcpServerThread, pServer, 0, enmType, /*RTTHREADFLAGS_WAITABLE*/0, pszThrdName);
302 if (RT_SUCCESS(rc))
303 {
304 /* done */
305 if (ppServer)
306 *ppServer = pServer;
307 else
308 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
309 return rc;
310 }
311 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
312
313 /*
314 * Destroy the server.
315 */
316 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_CREATED, RTTCPSERVERSTATE_STARTING);
317 RTTcpServerDestroy(pServer);
318 }
319
320 return rc;
321}
322
323
324/**
325 * Server thread, loops accepting connections until it's terminated.
326 *
327 * @returns iprt status code. (ignored).
328 * @param ThreadSelf Thread handle.
329 * @param pvServer Server handle.
330 */
331static DECLCALLBACK(int) rtTcpServerThread(RTTHREAD ThreadSelf, void *pvServer)
332{
333 PRTTCPSERVER pServer = (PRTTCPSERVER)pvServer;
334 int rc;
335 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_ACCEPTING, RTTCPSERVERSTATE_STARTING))
336 rc = rtTcpServerListen(pServer);
337 else
338 rc = rtTcpServerListenCleanup(pServer);
339 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
340 NOREF(ThreadSelf);
341 return VINF_SUCCESS;
342}
343
344
345/**
346 * Create single connection at a time TCP Server.
347 * The caller must call RTTcpServerListen() to actually start the server.
348 *
349 * @returns iprt status code.
350 * @param pszAddress The address for creating a listening socket.
351 * If NULL the server is bound to all interfaces.
352 * @param uPort The port for creating a listening socket.
353 * @param ppServer Where to store the serverhandle.
354 */
355RTR3DECL(int) RTTcpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTTCPSERVER ppServer)
356{
357 int rc;
358
359 /*
360 * Validate input.
361 */
362 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
363 AssertPtrReturn(ppServer, VERR_INVALID_PARAMETER);
364
365#ifdef RT_OS_WINDOWS
366 /*
367 * Initialize WinSock and check version.
368 */
369 WORD wVersionRequested = MAKEWORD(1, 1);
370 WSADATA wsaData;
371 rc = WSAStartup(wVersionRequested, &wsaData);
372 if (wsaData.wVersion != wVersionRequested)
373 {
374 AssertMsgFailed(("Wrong winsock version\n"));
375 return VERR_NOT_SUPPORTED;
376 }
377#endif
378
379 /*
380 * Get host listening address.
381 */
382 struct hostent *pHostEnt = NULL;
383 if (pszAddress != NULL && *pszAddress)
384 {
385 pHostEnt = gethostbyname(pszAddress);
386 if (!pHostEnt)
387 {
388 struct in_addr InAddr;
389 InAddr.s_addr = inet_addr(pszAddress);
390 pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
391 if (!pHostEnt)
392 {
393 rc = rtSocketResolverError();
394 AssertMsgFailed(("Could not get host address rc=%Rrc\n", rc));
395 return rc;
396 }
397 }
398 }
399
400 /*
401 * Setting up socket.
402 */
403 RTSOCKET WaitSock;
404 rc = rtSocketCreate(&WaitSock, AF_INET, SOCK_STREAM, IPPROTO_TCP);
405 if (RT_SUCCESS(rc))
406 {
407 RTSocketSetInheritance(WaitSock, false /*fInheritable*/);
408
409 /*
410 * Set socket options.
411 */
412 int fFlag = 1;
413 if (!rtSocketSetOpt(WaitSock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag)))
414 {
415 /*
416 * Set socket family, address and port.
417 */
418 struct sockaddr_in LocalAddr;
419 RT_ZERO(LocalAddr);
420 LocalAddr.sin_family = AF_INET;
421 LocalAddr.sin_port = htons(uPort);
422 /* if address not specified, use INADDR_ANY. */
423 if (!pHostEnt)
424 LocalAddr.sin_addr.s_addr = INADDR_ANY;
425 else
426 LocalAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
427
428 /*
429 * Bind a name to a socket and set it listening for connections.
430 */
431 rc = rtSocketBind(WaitSock, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr));
432 if (RT_SUCCESS(rc))
433 rc = rtSocketListen(WaitSock, RTTCP_SERVER_BACKLOG);
434 if (RT_SUCCESS(rc))
435 {
436 /*
437 * Create the server handle.
438 */
439 PRTTCPSERVER pServer = (PRTTCPSERVER)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pServer));
440 if (pServer)
441 {
442 pServer->u32Magic = RTTCPSERVER_MAGIC;
443 pServer->enmState = RTTCPSERVERSTATE_CREATED;
444 pServer->Thread = NIL_RTTHREAD;
445 pServer->SockServer = WaitSock;
446 pServer->SockClient = NIL_RTSOCKET;
447 pServer->pfnServe = NULL;
448 pServer->pvUser = NULL;
449 *ppServer = pServer;
450 return VINF_SUCCESS;
451 }
452
453 /* bail out */
454 rc = VERR_NO_MEMORY;
455 }
456 }
457 else
458 AssertMsgFailed(("rtSocketSetOpt: %Rrc\n", rc));
459 rtTcpClose(WaitSock, "RTServerCreateEx", false /*fTryGracefulShutdown*/);
460 }
461
462 return rc;
463}
464
465
466/**
467 * Listen for incoming connections.
468 *
469 * The function will loop accepting connections and call pfnServe for
470 * each of the incoming connections in turn. The pfnServe function can
471 * return VERR_TCP_SERVER_STOP too terminate this loop. A stopped server
472 * can only be destroyed.
473 *
474 * @returns IPRT status code.
475 * @retval VERR_TCP_SERVER_STOP if stopped by pfnServe.
476 * @retval VERR_TCP_SERVER_SHUTDOWN if shut down by RTTcpServerShutdown.
477 *
478 * @param pServer The server handle as returned from RTTcpServerCreateEx().
479 * @param pfnServe The function which will serve a new client connection.
480 * @param pvUser User argument passed to pfnServe.
481 */
482RTR3DECL(int) RTTcpServerListen(PRTTCPSERVER pServer, PFNRTTCPSERVE pfnServe, void *pvUser)
483{
484 /*
485 * Validate input and retain the instance.
486 */
487 AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
488 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
489 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
490 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
491
492 int rc = VERR_INVALID_STATE;
493 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_ACCEPTING, RTTCPSERVERSTATE_CREATED))
494 {
495 Assert(!pServer->pfnServe);
496 Assert(!pServer->pvUser);
497 Assert(pServer->Thread == NIL_RTTHREAD);
498 Assert(pServer->SockClient == NIL_RTSOCKET);
499
500 pServer->pfnServe = pfnServe;
501 pServer->pvUser = pvUser;
502 pServer->Thread = RTThreadSelf();
503 Assert(pServer->Thread != NIL_RTTHREAD);
504 rc = rtTcpServerListen(pServer);
505 }
506 else
507 {
508 AssertMsgFailed(("enmState=%d\n", pServer->enmState));
509 rc = VERR_INVALID_STATE;
510 }
511 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
512 return rc;
513}
514
515
516/**
517 * Internal worker common for RTTcpServerListen and the thread created by
518 * RTTcpServerCreate().
519 *
520 * The caller makes sure it has its own memory reference and releases it upon
521 * return.
522 */
523static int rtTcpServerListen(PRTTCPSERVER pServer)
524{
525 /*
526 * Accept connection loop.
527 */
528 for (;;)
529 {
530 /*
531 * Change state.
532 */
533 RTTCPSERVERSTATE enmState = pServer->enmState;
534 RTSOCKET SockServer = pServer->SockServer;
535 if ( enmState != RTTCPSERVERSTATE_ACCEPTING
536 && enmState != RTTCPSERVERSTATE_SERVING)
537 return rtTcpServerListenCleanup(pServer);
538 if (!rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_ACCEPTING, enmState))
539 continue;
540
541 /*
542 * Accept connection.
543 */
544 struct sockaddr_in RemoteAddr;
545 size_t cbRemoteAddr = sizeof(RemoteAddr);
546 RTSOCKET Socket;
547 RT_ZERO(RemoteAddr);
548 int rc = rtSocketAccept(SockServer, &Socket, (struct sockaddr *)&RemoteAddr, &cbRemoteAddr);
549 if (RT_FAILURE(rc))
550 {
551 /* These are typical for what can happen during destruction. */
552 if ( rc == VERR_INVALID_HANDLE
553 || rc == VERR_INVALID_PARAMETER
554 || rc == VERR_NET_NOT_SOCKET)
555 return rtTcpServerListenCleanup(pServer);
556 continue;
557 }
558 RTSocketSetInheritance(Socket, false /*fInheritable*/);
559
560 /*
561 * Run a pfnServe callback.
562 */
563 if (!rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_SERVING, RTTCPSERVERSTATE_ACCEPTING))
564 {
565 rtTcpClose(Socket, "rtTcpServerListen", true /*fTryGracefulShutdown*/);
566 return rtTcpServerListenCleanup(pServer);
567 }
568 rtTcpAtomicXchgSock(&pServer->SockClient, Socket);
569 rc = pServer->pfnServe(Socket, pServer->pvUser);
570 rtTcpServerDestroySocket(&pServer->SockClient, "Listener: client", true /*fTryGracefulShutdown*/);
571
572 /*
573 * Stop the server?
574 */
575 if (rc == VERR_TCP_SERVER_STOP)
576 {
577 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_STOPPING, RTTCPSERVERSTATE_SERVING))
578 {
579 /*
580 * Reset the server socket and change the state to stopped. After that state change
581 * we cannot safely access the handle so we'll have to return here.
582 */
583 SockServer = rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET);
584 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPED, RTTCPSERVERSTATE_STOPPING);
585 rtTcpClose(SockServer, "Listener: server stopped", false /*fTryGracefulShutdown*/);
586 }
587 else
588 rtTcpServerListenCleanup(pServer); /* ignore rc */
589 return rc;
590 }
591 }
592}
593
594
595/**
596 * Clean up after listener.
597 */
598static int rtTcpServerListenCleanup(PRTTCPSERVER pServer)
599{
600 /*
601 * Close the server socket, the client one shouldn't be set.
602 */
603 rtTcpServerDestroySocket(&pServer->SockServer, "ListenCleanup", false /*fTryGracefulShutdown*/);
604 Assert(pServer->SockClient == NIL_RTSOCKET);
605
606 /*
607 * Figure the return code and make sure the state is OK.
608 */
609 RTTCPSERVERSTATE enmState = pServer->enmState;
610 switch (enmState)
611 {
612 case RTTCPSERVERSTATE_STOPPING:
613 case RTTCPSERVERSTATE_STOPPED:
614 return VERR_TCP_SERVER_SHUTDOWN;
615
616 case RTTCPSERVERSTATE_ACCEPTING:
617 rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_STOPPED, enmState);
618 return VERR_TCP_SERVER_DESTROYED;
619
620 case RTTCPSERVERSTATE_DESTROYING:
621 return VERR_TCP_SERVER_DESTROYED;
622
623 case RTTCPSERVERSTATE_STARTING:
624 case RTTCPSERVERSTATE_SERVING:
625 default:
626 AssertMsgFailedReturn(("pServer=%p enmState=%d\n", pServer, enmState), VERR_INTERNAL_ERROR_4);
627 }
628}
629
630
631/**
632 * Listen and accept one incomming connection.
633 *
634 * This is an alternative to RTTcpServerListen for the use the callbacks are not
635 * possible.
636 *
637 * @returns IPRT status code.
638 * @retval VERR_TCP_SERVER_SHUTDOWN if shut down by RTTcpServerShutdown.
639 * @retval VERR_INTERRUPTED if the listening was interrupted.
640 *
641 * @param pServer The server handle as returned from RTTcpServerCreateEx().
642 * @param pSockClient Where to return the socket handle to the client
643 * connection (on success only). Use
644 * RTTcpServerDisconnectClient() to clean it, this must
645 * be done before the next call to RTTcpServerListen2.
646 *
647 * @todo This can easily be extended to support multiple connections by
648 * adding a new state and a RTTcpServerDisconnectClient variant for
649 * closing client sockets.
650 */
651RTR3DECL(int) RTTcpServerListen2(PRTTCPSERVER pServer, PRTSOCKET pSockClient)
652{
653 /*
654 * Validate input and retain the instance.
655 */
656 AssertPtrReturn(pSockClient, VERR_INVALID_HANDLE);
657 *pSockClient = NIL_RTSOCKET;
658 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
659 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
660
661 int rc = VERR_INVALID_STATE;
662 for (;;)
663 {
664 /*
665 * Change state to accepting.
666 */
667 RTTCPSERVERSTATE enmState = pServer->enmState;
668 RTSOCKET SockServer = pServer->SockServer;
669 if ( enmState != RTTCPSERVERSTATE_SERVING
670 && enmState != RTTCPSERVERSTATE_CREATED)
671 {
672 rc = rtTcpServerListenCleanup(pServer);
673 break;
674 }
675 if (!rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_ACCEPTING, enmState))
676 continue;
677 Assert(!pServer->pfnServe);
678 Assert(!pServer->pvUser);
679 Assert(pServer->Thread == NIL_RTTHREAD);
680 Assert(pServer->SockClient == NIL_RTSOCKET);
681
682 /*
683 * Accept connection.
684 */
685 struct sockaddr_in RemoteAddr;
686 size_t cbRemoteAddr = sizeof(RemoteAddr);
687 RTSOCKET Socket;
688 RT_ZERO(RemoteAddr);
689 rc = rtSocketAccept(SockServer, &Socket, (struct sockaddr *)&RemoteAddr, &cbRemoteAddr);
690 if (RT_FAILURE(rc))
691 {
692 if (!rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_CREATED, RTTCPSERVERSTATE_ACCEPTING))
693 rc = rtTcpServerListenCleanup(pServer);
694 if (RT_FAILURE(rc))
695 break;
696 continue;
697 }
698 RTSocketSetInheritance(Socket, false /*fInheritable*/);
699
700 /*
701 * Chance to the 'serving' state and return the socket.
702 */
703 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_SERVING, RTTCPSERVERSTATE_ACCEPTING))
704 {
705 RTSOCKET OldSocket = rtTcpAtomicXchgSock(&pServer->SockClient, Socket);
706 Assert(OldSocket == NIL_RTSOCKET); NOREF(OldSocket);
707 *pSockClient = Socket;
708 rc = VINF_SUCCESS;
709 }
710 else
711 {
712 rtTcpClose(Socket, "RTTcpServerListen2", true /*fTryGracefulShutdown*/);
713 rc = rtTcpServerListenCleanup(pServer);
714 }
715 break;
716 }
717
718 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
719 return rc;
720}
721
722
723/**
724 * Terminate the open connection to the server.
725 *
726 * @returns iprt status code.
727 * @param pServer Handle to the server.
728 */
729RTR3DECL(int) RTTcpServerDisconnectClient(PRTTCPSERVER pServer)
730{
731 /*
732 * Validate input and retain the instance.
733 */
734 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
735 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
736 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
737
738 int rc = rtTcpServerDestroySocket(&pServer->SockClient, "DisconnectClient: client", true /*fTryGracefulShutdown*/);
739
740 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
741 return rc;
742}
743
744
745/**
746 * Shuts down the server, leaving client connections open.
747 *
748 * @returns IPRT status code.
749 * @param pServer Handle to the server.
750 */
751RTR3DECL(int) RTTcpServerShutdown(PRTTCPSERVER pServer)
752{
753 /*
754 * Validate input and retain the instance.
755 */
756 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
757 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
758 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
759
760 /*
761 * Try change the state to stopping, then replace and destroy the server socket.
762 */
763 for (;;)
764 {
765 RTTCPSERVERSTATE enmState = pServer->enmState;
766 if ( enmState != RTTCPSERVERSTATE_ACCEPTING
767 && enmState != RTTCPSERVERSTATE_SERVING)
768 {
769 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
770 switch (enmState)
771 {
772 case RTTCPSERVERSTATE_CREATED:
773 case RTTCPSERVERSTATE_STARTING:
774 default:
775 AssertMsgFailed(("%d\n", enmState));
776 return VERR_INVALID_STATE;
777
778 case RTTCPSERVERSTATE_STOPPING:
779 case RTTCPSERVERSTATE_STOPPED:
780 return VINF_SUCCESS;
781
782 case RTTCPSERVERSTATE_DESTROYING:
783 return VERR_TCP_SERVER_DESTROYED;
784 }
785 }
786 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_STOPPING, enmState))
787 {
788 rtTcpServerDestroySocket(&pServer->SockServer, "RTTcpServerShutdown", false /*fTryGracefulShutdown*/);
789 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPED, RTTCPSERVERSTATE_STOPPING);
790
791 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
792 return VINF_SUCCESS;
793 }
794 }
795}
796
797
798/**
799 * Closes down and frees a TCP Server.
800 * This will also terminate any open connections to the server.
801 *
802 * @returns iprt status code.
803 * @param pServer Handle to the server.
804 */
805RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer)
806{
807 /*
808 * Validate input and retain the instance.
809 */
810 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
811 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
812 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); /* paranoia */
813
814 /*
815 * Move the state along so the listener can figure out what's going on.
816 */
817 for (;;)
818 {
819 bool fDestroyable;
820 RTTCPSERVERSTATE enmState = pServer->enmState;
821 switch (enmState)
822 {
823 case RTTCPSERVERSTATE_STARTING:
824 case RTTCPSERVERSTATE_ACCEPTING:
825 case RTTCPSERVERSTATE_SERVING:
826 case RTTCPSERVERSTATE_CREATED:
827 case RTTCPSERVERSTATE_STOPPED:
828 fDestroyable = rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_DESTROYING, enmState);
829 break;
830
831 /* destroyable states */
832 case RTTCPSERVERSTATE_STOPPING:
833 fDestroyable = true;
834 break;
835
836 /*
837 * Everything else means user or internal misbehavior.
838 */
839 default:
840 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
841 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
842 return VERR_INTERNAL_ERROR;
843 }
844 if (fDestroyable)
845 break;
846 }
847
848 /*
849 * Destroy it.
850 */
851 ASMAtomicWriteU32(&pServer->u32Magic, ~RTTCPSERVER_MAGIC);
852 rtTcpServerDestroySocket(&pServer->SockServer, "Destroyer: server", false /*fTryGracefulShutdown*/);
853 rtTcpServerDestroySocket(&pServer->SockClient, "Destroyer: client", true /*fTryGracefulShutdown*/);
854
855 /*
856 * Release it.
857 */
858 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
859 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
860 return VINF_SUCCESS;
861}
862
863
864RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
865{
866 int rc;
867
868 /*
869 * Validate input.
870 */
871 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
872 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
873
874#ifdef RT_OS_WINDOWS
875 /*
876 * Initialize WinSock and check version.
877 */
878 WORD wVersionRequested = MAKEWORD(1, 1);
879 WSADATA wsaData;
880 rc = WSAStartup(wVersionRequested, &wsaData);
881 if (wsaData.wVersion != wVersionRequested)
882 {
883 AssertMsgFailed(("Wrong winsock version\n"));
884 return VERR_NOT_SUPPORTED;
885 }
886#endif
887
888 /*
889 * Resolve the address.
890 */
891 struct hostent *pHostEnt = NULL;
892 pHostEnt = gethostbyname(pszAddress);
893 if (!pHostEnt)
894 {
895 struct in_addr InAddr;
896 InAddr.s_addr = inet_addr(pszAddress);
897 pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
898 if (!pHostEnt)
899 {
900 rc = rtSocketResolverError();
901 AssertMsgFailed(("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
902 return rc;
903 }
904 }
905
906 /*
907 * Create the socket and connect.
908 */
909 RTSOCKET Sock;
910 rc = rtSocketCreate(&Sock, PF_INET, SOCK_STREAM, 0);
911 if (RT_SUCCESS(rc))
912 {
913 RTSocketSetInheritance(Sock, false /*fInheritable*/);
914
915 struct sockaddr_in InAddr;
916 RT_ZERO(InAddr);
917 InAddr.sin_family = AF_INET;
918 InAddr.sin_port = htons(uPort);
919 InAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
920 rc = rtSocketConnect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr));
921 if (RT_SUCCESS(rc))
922 {
923 *pSock = Sock;
924 return VINF_SUCCESS;
925 }
926
927 rtTcpClose(Sock, "RTTcpClientConnect", false /*fTryGracefulShutdown*/);
928 }
929 return rc;
930}
931
932
933RTR3DECL(int) RTTcpClientClose(RTSOCKET Sock)
934{
935 return rtTcpClose(Sock, "RTTcpClientClose", true /*fTryGracefulShutdown*/);
936}
937
938
939/**
940 * Internal close function which does all the proper bitching.
941 */
942static int rtTcpClose(RTSOCKET Sock, const char *pszMsg, bool fTryGracefulShutdown)
943{
944 int rc;
945
946 /* ignore nil handles. */
947 if (Sock == NIL_RTSOCKET)
948 return VINF_SUCCESS;
949
950 /*
951 * Try to gracefully shut it down.
952 */
953 if (fTryGracefulShutdown)
954 {
955 rc = RTSocketShutdown(Sock, false /*fRead*/, true /*fWrite*/);
956 if (RT_SUCCESS(rc))
957 {
958 uint64_t u64Start = RTTimeMilliTS();
959 for (;;)
960 {
961 rc = RTSocketSelectOne(Sock, 1000);
962 if (rc == VERR_TIMEOUT)
963 {
964 if (RTTimeMilliTS() - u64Start > 30000)
965 break;
966 }
967 else if (rc != VINF_SUCCESS)
968 break;
969 {
970 char abBitBucket[16*_1K];
971 ssize_t cbBytesRead = recv(RTSocketToNative(Sock), &abBitBucket[0], sizeof(abBitBucket), MSG_NOSIGNAL);
972 if (cbBytesRead == 0)
973 break; /* orderly shutdown in progress */
974 if (cbBytesRead < 0)
975 break; /* some kind of error, never mind which... */
976 }
977 } /* forever */
978 }
979 }
980
981 /*
982 * Destroy the socket handle.
983 */
984 return RTSocketDestroy(Sock);
985}
986
987
988RTR3DECL(int) RTTcpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
989{
990 return RTSocketRead(Sock, pvBuffer, cbBuffer, pcbRead);
991}
992
993
994RTR3DECL(int) RTTcpWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
995{
996 return RTSocketWrite(Sock, pvBuffer, cbBuffer);
997}
998
999
1000RTR3DECL(int) RTTcpFlush(RTSOCKET Sock)
1001{
1002
1003 int fFlag = 1;
1004 int rc = rtSocketSetOpt(Sock, IPPROTO_TCP, TCP_NODELAY, &fFlag, sizeof(fFlag));
1005 if (RT_SUCCESS(rc))
1006 {
1007 fFlag = 0;
1008 rc = rtSocketSetOpt(Sock, IPPROTO_TCP, TCP_NODELAY, &fFlag, sizeof(fFlag));
1009 }
1010 return rc;
1011}
1012
1013
1014RTR3DECL(int) RTTcpSelectOne(RTSOCKET Sock, RTMSINTERVAL cMillies)
1015{
1016 return RTSocketSelectOne(Sock, cMillies);
1017}
1018
1019
1020RTR3DECL(int) RTTcpGetLocalAddress(RTSOCKET Sock, PRTNETADDR pAddr)
1021{
1022 return RTSocketGetLocalAddress(Sock, pAddr);
1023}
1024
1025
1026RTR3DECL(int) RTTcpGetPeerAddress(RTSOCKET Sock, PRTNETADDR pAddr)
1027{
1028 return RTSocketGetPeerAddress(Sock, pAddr);
1029}
1030
Note: See TracBrowser for help on using the repository browser.

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