VirtualBox

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

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

fix.

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