VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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