VirtualBox

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

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

IPRT: Build fix for FreeBSD

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