VirtualBox

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

Last change on this file since 32801 was 32801, checked in by vboxsync, 14 years ago

rtTcpClose: The trunk fix for the graceful shutdown hang.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 33.6 KB
Line 
1/* $Id: tcp.cpp 32801 2010-09-28 16:17:46Z 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 return rc;
341 }
342 }
343 }
344
345 /*
346 * Setting up socket.
347 */
348 RTSOCKET WaitSock;
349 rc = rtSocketCreate(&WaitSock, AF_INET, SOCK_STREAM, IPPROTO_TCP);
350 if (RT_SUCCESS(rc))
351 {
352 RTSocketSetInheritance(WaitSock, false /*fInheritable*/);
353
354 /*
355 * Set socket options.
356 */
357 int fFlag = 1;
358 if (!rtSocketSetOpt(WaitSock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag)))
359 {
360 /*
361 * Set socket family, address and port.
362 */
363 struct sockaddr_in LocalAddr;
364 RT_ZERO(LocalAddr);
365 LocalAddr.sin_family = AF_INET;
366 LocalAddr.sin_port = htons(uPort);
367 /* if address not specified, use INADDR_ANY. */
368 if (!pHostEnt)
369 LocalAddr.sin_addr.s_addr = INADDR_ANY;
370 else
371 LocalAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
372
373 /*
374 * Bind a name to a socket and set it listening for connections.
375 */
376 rc = rtSocketBind(WaitSock, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr));
377 if (RT_SUCCESS(rc))
378 rc = rtSocketListen(WaitSock, RTTCP_SERVER_BACKLOG);
379 if (RT_SUCCESS(rc))
380 {
381 /*
382 * Create the server handle.
383 */
384 PRTTCPSERVER pServer = (PRTTCPSERVER)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pServer));
385 if (pServer)
386 {
387 pServer->u32Magic = RTTCPSERVER_MAGIC;
388 pServer->enmState = RTTCPSERVERSTATE_CREATED;
389 pServer->Thread = NIL_RTTHREAD;
390 pServer->hServerSocket = WaitSock;
391 pServer->hClientSocket = NIL_RTSOCKET;
392 pServer->pfnServe = NULL;
393 pServer->pvUser = NULL;
394 *ppServer = pServer;
395 return VINF_SUCCESS;
396 }
397
398 /* bail out */
399 rc = VERR_NO_MEMORY;
400 }
401 }
402 else
403 AssertMsgFailed(("rtSocketSetOpt: %Rrc\n", rc));
404 rtTcpClose(WaitSock, "RTServerCreateEx", false /*fTryGracefulShutdown*/);
405 }
406
407 return rc;
408}
409
410
411/**
412 * Listen for incoming connections.
413 *
414 * The function will loop accepting connections and call pfnServe for
415 * each of the incoming connections in turn. The pfnServe function can
416 * return VERR_TCP_SERVER_STOP too terminate this loop. A stopped server
417 * can only be destroyed.
418 *
419 * @returns IPRT status code.
420 * @retval VERR_TCP_SERVER_STOP if stopped by pfnServe.
421 * @retval VERR_TCP_SERVER_SHUTDOWN if shut down by RTTcpServerShutdown.
422 *
423 * @param pServer The server handle as returned from RTTcpServerCreateEx().
424 * @param pfnServe The function which will serve a new client connection.
425 * @param pvUser User argument passed to pfnServe.
426 */
427RTR3DECL(int) RTTcpServerListen(PRTTCPSERVER pServer, PFNRTTCPSERVE pfnServe, void *pvUser)
428{
429 /*
430 * Validate input and retain the instance.
431 */
432 AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
433 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
434 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
435 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
436
437 int rc = VERR_INVALID_STATE;
438 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_ACCEPTING, RTTCPSERVERSTATE_CREATED))
439 {
440 Assert(!pServer->pfnServe);
441 Assert(!pServer->pvUser);
442 Assert(pServer->Thread == NIL_RTTHREAD);
443 Assert(pServer->hClientSocket == NIL_RTSOCKET);
444
445 pServer->pfnServe = pfnServe;
446 pServer->pvUser = pvUser;
447 pServer->Thread = RTThreadSelf();
448 Assert(pServer->Thread != NIL_RTTHREAD);
449 rc = rtTcpServerListen(pServer);
450 }
451 else
452 {
453 AssertMsgFailed(("enmState=%d\n", pServer->enmState));
454 rc = VERR_INVALID_STATE;
455 }
456 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
457 return rc;
458}
459
460
461/**
462 * Internal worker common for RTTcpServerListen and the thread created by
463 * RTTcpServerCreate().
464 *
465 * The caller makes sure it has its own memory reference and releases it upon
466 * return.
467 */
468static int rtTcpServerListen(PRTTCPSERVER pServer)
469{
470 /*
471 * Accept connection loop.
472 */
473 for (;;)
474 {
475 /*
476 * Change state, getting an extra reference to the socket so we can
477 * allow others to close it while we're stuck in rtSocketAccept.
478 */
479 RTTCPSERVERSTATE enmState = pServer->enmState;
480 RTSOCKET hServerSocket;
481 ASMAtomicXchgHandle(&pServer->hServerSocket, NIL_RTSOCKET, &hServerSocket);
482 if (hServerSocket != NIL_RTSOCKET)
483 {
484 RTSocketRetain(hServerSocket);
485 ASMAtomicWriteHandle(&pServer->hServerSocket, hServerSocket);
486 }
487 if ( enmState != RTTCPSERVERSTATE_ACCEPTING
488 && enmState != RTTCPSERVERSTATE_SERVING)
489 {
490 RTSocketRelease(hServerSocket);
491 return rtTcpServerListenCleanup(pServer);
492 }
493 if (!rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_ACCEPTING, enmState))
494 {
495 RTSocketRelease(hServerSocket);
496 continue;
497 }
498
499 /*
500 * Accept connection.
501 */
502 struct sockaddr_in RemoteAddr;
503 size_t cbRemoteAddr = sizeof(RemoteAddr);
504 RTSOCKET hClientSocket;
505 RT_ZERO(RemoteAddr);
506 int rc = rtSocketAccept(hServerSocket, &hClientSocket, (struct sockaddr *)&RemoteAddr, &cbRemoteAddr);
507 RTSocketRelease(hServerSocket);
508 if (RT_FAILURE(rc))
509 {
510 /* These are typical for what can happen during destruction. */
511 if ( rc == VERR_INVALID_HANDLE
512 || rc == VERR_INVALID_PARAMETER
513 || rc == VERR_NET_NOT_SOCKET)
514 return rtTcpServerListenCleanup(pServer);
515 continue;
516 }
517 RTSocketSetInheritance(hClientSocket, false /*fInheritable*/);
518
519 /*
520 * Run a pfnServe callback.
521 */
522 if (!rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_SERVING, RTTCPSERVERSTATE_ACCEPTING))
523 {
524 rtTcpClose(hClientSocket, "rtTcpServerListen", true /*fTryGracefulShutdown*/);
525 return rtTcpServerListenCleanup(pServer);
526 }
527 RTSocketRetain(hClientSocket);
528 rtTcpAtomicXchgSock(&pServer->hClientSocket, hClientSocket);
529 rc = pServer->pfnServe(hClientSocket, pServer->pvUser);
530 rtTcpServerDestroySocket(&pServer->hClientSocket, "Listener: client (secondary)", true /*fTryGracefulShutdown*/);
531 RTSocketRelease(hClientSocket);
532
533 /*
534 * Stop the server?
535 */
536 if (rc == VERR_TCP_SERVER_STOP)
537 {
538 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_STOPPING, RTTCPSERVERSTATE_SERVING))
539 {
540 /*
541 * Reset the server socket and change the state to stopped. After that state change
542 * we cannot safely access the handle so we'll have to return here.
543 */
544 hServerSocket = rtTcpAtomicXchgSock(&pServer->hServerSocket, NIL_RTSOCKET);
545 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPED, RTTCPSERVERSTATE_STOPPING);
546 rtTcpClose(hServerSocket, "Listener: server stopped", false /*fTryGracefulShutdown*/);
547 }
548 else
549 rtTcpServerListenCleanup(pServer); /* ignore rc */
550 return rc;
551 }
552 }
553}
554
555
556/**
557 * Clean up after listener.
558 */
559static int rtTcpServerListenCleanup(PRTTCPSERVER pServer)
560{
561 /*
562 * Close the server socket, the client one shouldn't be set.
563 */
564 rtTcpServerDestroySocket(&pServer->hServerSocket, "ListenCleanup", false /*fTryGracefulShutdown*/);
565 Assert(pServer->hClientSocket == NIL_RTSOCKET);
566
567 /*
568 * Figure the return code and make sure the state is OK.
569 */
570 RTTCPSERVERSTATE enmState = pServer->enmState;
571 switch (enmState)
572 {
573 case RTTCPSERVERSTATE_STOPPING:
574 case RTTCPSERVERSTATE_STOPPED:
575 return VERR_TCP_SERVER_SHUTDOWN;
576
577 case RTTCPSERVERSTATE_ACCEPTING:
578 rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_STOPPED, enmState);
579 return VERR_TCP_SERVER_DESTROYED;
580
581 case RTTCPSERVERSTATE_DESTROYING:
582 return VERR_TCP_SERVER_DESTROYED;
583
584 case RTTCPSERVERSTATE_STARTING:
585 case RTTCPSERVERSTATE_SERVING:
586 default:
587 AssertMsgFailedReturn(("pServer=%p enmState=%d\n", pServer, enmState), VERR_INTERNAL_ERROR_4);
588 }
589}
590
591
592/**
593 * Listen and accept one incomming connection.
594 *
595 * This is an alternative to RTTcpServerListen for the use the callbacks are not
596 * possible.
597 *
598 * @returns IPRT status code.
599 * @retval VERR_TCP_SERVER_SHUTDOWN if shut down by RTTcpServerShutdown.
600 * @retval VERR_INTERRUPTED if the listening was interrupted.
601 *
602 * @param pServer The server handle as returned from RTTcpServerCreateEx().
603 * @param phClientSocket Where to return the socket handle to the client
604 * connection (on success only). This must be closed
605 * by calling RTTcpServerDisconnectClient2().
606 */
607RTR3DECL(int) RTTcpServerListen2(PRTTCPSERVER pServer, PRTSOCKET phClientSocket)
608{
609 /*
610 * Validate input and retain the instance.
611 */
612 AssertPtrReturn(phClientSocket, VERR_INVALID_HANDLE);
613 *phClientSocket = 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, getting an extra reference to the socket so we can
622 * allow others to close it while we're stuck in rtSocketAccept.
623 */
624 RTTCPSERVERSTATE enmState = pServer->enmState;
625 RTSOCKET hServerSocket;
626 ASMAtomicXchgHandle(&pServer->hServerSocket, NIL_RTSOCKET, &hServerSocket);
627 if (hServerSocket != NIL_RTSOCKET)
628 {
629 RTSocketRetain(hServerSocket);
630 ASMAtomicWriteHandle(&pServer->hServerSocket, hServerSocket);
631 }
632 if ( enmState != RTTCPSERVERSTATE_SERVING
633 && enmState != RTTCPSERVERSTATE_CREATED)
634 {
635 RTSocketRelease(hServerSocket);
636 return rtTcpServerListenCleanup(pServer);
637 }
638 if (!rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_ACCEPTING, enmState))
639 {
640 RTSocketRelease(hServerSocket);
641 continue;
642 }
643 Assert(!pServer->pfnServe);
644 Assert(!pServer->pvUser);
645 Assert(pServer->Thread == NIL_RTTHREAD);
646 Assert(pServer->hClientSocket == NIL_RTSOCKET);
647
648 /*
649 * Accept connection.
650 */
651 struct sockaddr_in RemoteAddr;
652 size_t cbRemoteAddr = sizeof(RemoteAddr);
653 RTSOCKET hClientSocket;
654 RT_ZERO(RemoteAddr);
655 rc = rtSocketAccept(hServerSocket, &hClientSocket, (struct sockaddr *)&RemoteAddr, &cbRemoteAddr);
656 RTSocketRelease(hServerSocket);
657 if (RT_FAILURE(rc))
658 {
659 if (!rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_CREATED, RTTCPSERVERSTATE_ACCEPTING))
660 rc = rtTcpServerListenCleanup(pServer);
661 if (RT_FAILURE(rc))
662 break;
663 continue;
664 }
665 RTSocketSetInheritance(hClientSocket, false /*fInheritable*/);
666
667 /*
668 * Chance to the 'serving' state and return the socket.
669 */
670 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_SERVING, RTTCPSERVERSTATE_ACCEPTING))
671 {
672 *phClientSocket = hClientSocket;
673 rc = VINF_SUCCESS;
674 }
675 else
676 {
677 rtTcpClose(hClientSocket, "RTTcpServerListen2", true /*fTryGracefulShutdown*/);
678 rc = rtTcpServerListenCleanup(pServer);
679 }
680 break;
681 }
682
683 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
684 return rc;
685}
686
687
688/**
689 * Terminate the open connection to the server.
690 *
691 * @returns iprt status code.
692 * @param pServer Handle to the server.
693 */
694RTR3DECL(int) RTTcpServerDisconnectClient(PRTTCPSERVER pServer)
695{
696 /*
697 * Validate input and retain the instance.
698 */
699 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
700 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
701 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
702
703 int rc = rtTcpServerDestroySocket(&pServer->hClientSocket, "DisconnectClient: client", true /*fTryGracefulShutdown*/);
704
705 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
706 return rc;
707}
708
709
710/**
711 * Terminates an open client connect when using RTTcpListen2
712 *
713 * @returns IPRT status code.
714 * @param hClientSocket The client socket handle. This will be invalid upon
715 * return, whether successful or not. NIL is quietly
716 * ignored (VINF_SUCCESS).
717 */
718RTR3DECL(int) RTTcpServerDisconnectClient2(RTSOCKET hClientSocket)
719{
720 return rtTcpClose(hClientSocket, "RTTcpServerDisconnectClient2", true /*fTryGracefulShutdown*/);
721}
722
723
724/**
725 * Shuts down the server, leaving client connections open.
726 *
727 * @returns IPRT status code.
728 * @param pServer Handle to the server.
729 */
730RTR3DECL(int) RTTcpServerShutdown(PRTTCPSERVER pServer)
731{
732 /*
733 * Validate input and retain the instance.
734 */
735 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
736 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
737 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
738
739 /*
740 * Try change the state to stopping, then replace and destroy the server socket.
741 */
742 for (;;)
743 {
744 RTTCPSERVERSTATE enmState = pServer->enmState;
745 if ( enmState != RTTCPSERVERSTATE_ACCEPTING
746 && enmState != RTTCPSERVERSTATE_SERVING)
747 {
748 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
749 switch (enmState)
750 {
751 case RTTCPSERVERSTATE_CREATED:
752 case RTTCPSERVERSTATE_STARTING:
753 default:
754 AssertMsgFailed(("%d\n", enmState));
755 return VERR_INVALID_STATE;
756
757 case RTTCPSERVERSTATE_STOPPING:
758 case RTTCPSERVERSTATE_STOPPED:
759 return VINF_SUCCESS;
760
761 case RTTCPSERVERSTATE_DESTROYING:
762 return VERR_TCP_SERVER_DESTROYED;
763 }
764 }
765 if (rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_STOPPING, enmState))
766 {
767 rtTcpServerDestroySocket(&pServer->hServerSocket, "RTTcpServerShutdown", false /*fTryGracefulShutdown*/);
768 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPED, RTTCPSERVERSTATE_STOPPING);
769
770 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
771 return VINF_SUCCESS;
772 }
773 }
774}
775
776
777/**
778 * Closes down and frees a TCP Server.
779 * This will also terminate any open connections to the server.
780 *
781 * @returns iprt status code.
782 * @param pServer Handle to the server.
783 */
784RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer)
785{
786 /*
787 * Validate input and retain the instance.
788 */
789 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
790 AssertReturn(pServer->u32Magic == RTTCPSERVER_MAGIC, VERR_INVALID_HANDLE);
791 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); /* paranoia */
792
793 /*
794 * Move the state along so the listener can figure out what's going on.
795 */
796 for (;;)
797 {
798 bool fDestroyable;
799 RTTCPSERVERSTATE enmState = pServer->enmState;
800 switch (enmState)
801 {
802 case RTTCPSERVERSTATE_STARTING:
803 case RTTCPSERVERSTATE_ACCEPTING:
804 case RTTCPSERVERSTATE_SERVING:
805 case RTTCPSERVERSTATE_CREATED:
806 case RTTCPSERVERSTATE_STOPPED:
807 fDestroyable = rtTcpServerTrySetState(pServer, RTTCPSERVERSTATE_DESTROYING, enmState);
808 break;
809
810 /* destroyable states */
811 case RTTCPSERVERSTATE_STOPPING:
812 fDestroyable = true;
813 break;
814
815 /*
816 * Everything else means user or internal misbehavior.
817 */
818 default:
819 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
820 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
821 return VERR_INTERNAL_ERROR;
822 }
823 if (fDestroyable)
824 break;
825 }
826
827 /*
828 * Destroy it.
829 */
830 ASMAtomicWriteU32(&pServer->u32Magic, ~RTTCPSERVER_MAGIC);
831 rtTcpServerDestroySocket(&pServer->hServerSocket, "Destroyer: server", false /*fTryGracefulShutdown*/);
832 rtTcpServerDestroySocket(&pServer->hClientSocket, "Destroyer: client", true /*fTryGracefulShutdown*/);
833
834 /*
835 * Release it.
836 */
837 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
838 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
839 return VINF_SUCCESS;
840}
841
842
843RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
844{
845 int rc;
846
847 /*
848 * Validate input.
849 */
850 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
851 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
852
853#ifdef RT_OS_WINDOWS
854 /*
855 * Initialize WinSock and check version.
856 */
857 WORD wVersionRequested = MAKEWORD(1, 1);
858 WSADATA wsaData;
859 rc = WSAStartup(wVersionRequested, &wsaData);
860 if (wsaData.wVersion != wVersionRequested)
861 {
862 AssertMsgFailed(("Wrong winsock version\n"));
863 return VERR_NOT_SUPPORTED;
864 }
865#endif
866
867 /*
868 * Resolve the address.
869 */
870 struct hostent *pHostEnt = NULL;
871 pHostEnt = gethostbyname(pszAddress);
872 if (!pHostEnt)
873 {
874 struct in_addr InAddr;
875 InAddr.s_addr = inet_addr(pszAddress);
876 pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
877 if (!pHostEnt)
878 {
879 rc = rtSocketResolverError();
880 AssertMsgFailed(("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
881 return rc;
882 }
883 }
884
885 /*
886 * Create the socket and connect.
887 */
888 RTSOCKET Sock;
889 rc = rtSocketCreate(&Sock, PF_INET, SOCK_STREAM, 0);
890 if (RT_SUCCESS(rc))
891 {
892 RTSocketSetInheritance(Sock, false /*fInheritable*/);
893
894 struct sockaddr_in InAddr;
895 RT_ZERO(InAddr);
896 InAddr.sin_family = AF_INET;
897 InAddr.sin_port = htons(uPort);
898 InAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
899 rc = rtSocketConnect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr));
900 if (RT_SUCCESS(rc))
901 {
902 *pSock = Sock;
903 return VINF_SUCCESS;
904 }
905
906 rtTcpClose(Sock, "RTTcpClientConnect", false /*fTryGracefulShutdown*/);
907 }
908 return rc;
909}
910
911
912RTR3DECL(int) RTTcpClientClose(RTSOCKET Sock)
913{
914 return rtTcpClose(Sock, "RTTcpClientClose", true /*fTryGracefulShutdown*/);
915}
916
917
918/**
919 * Internal close function which does all the proper bitching.
920 */
921static int rtTcpClose(RTSOCKET Sock, const char *pszMsg, bool fTryGracefulShutdown)
922{
923 int rc;
924
925 /* ignore nil handles. */
926 if (Sock == NIL_RTSOCKET)
927 return VINF_SUCCESS;
928
929 /*
930 * Try to gracefully shut it down.
931 */
932 if (fTryGracefulShutdown)
933 {
934 rc = RTSocketShutdown(Sock, false /*fRead*/, true /*fWrite*/);
935 if (RT_SUCCESS(rc))
936 {
937 size_t cbReceived = 0;
938 uint64_t u64Start = RTTimeMilliTS();
939 while ( cbReceived < _1G
940 && RTTimeMilliTS() - u64Start < 30000)
941 {
942 uint32_t fEvents;
943 rc = RTSocketSelectOneEx(Sock, RTSOCKET_EVT_READ | RTSOCKET_EVT_ERROR, &fEvents, 1000);
944 if (rc == VERR_TIMEOUT)
945 continue;
946 if (RT_FAILURE(rc))
947 break;
948 if (fEvents & RTSOCKET_EVT_ERROR)
949 break;
950
951 char abBitBucket[16*_1K];
952 size_t cbRead;
953 rc = RTSocketReadNB(Sock, &abBitBucket[0], sizeof(abBitBucket), &cbRead);
954 if (RT_FAILURE(rc))
955 break; /* some kind of error, never mind which... */
956 if (rc != VINF_TRY_AGAIN && !cbRead)
957 break; /* orderly shutdown in progress */
958
959 cbReceived += cbRead;
960 }
961 }
962 }
963
964 /*
965 * Close the socket handle (drops our reference to it).
966 */
967 return RTSocketClose(Sock);
968}
969
970
971RTR3DECL(int) RTTcpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
972{
973 return RTSocketRead(Sock, pvBuffer, cbBuffer, pcbRead);
974}
975
976
977RTR3DECL(int) RTTcpWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
978{
979 return RTSocketWrite(Sock, pvBuffer, cbBuffer);
980}
981
982
983RTR3DECL(int) RTTcpFlush(RTSOCKET Sock)
984{
985 int fFlag = 1;
986 int rc = rtSocketSetOpt(Sock, IPPROTO_TCP, TCP_NODELAY, &fFlag, sizeof(fFlag));
987 if (RT_SUCCESS(rc))
988 {
989 fFlag = 0;
990 rc = rtSocketSetOpt(Sock, IPPROTO_TCP, TCP_NODELAY, &fFlag, sizeof(fFlag));
991 }
992 return rc;
993}
994
995
996RTR3DECL(int) RTTcpSetSendCoalescing(RTSOCKET Sock, bool fEnable)
997{
998 int fFlag = fEnable ? 0 : 1;
999 return rtSocketSetOpt(Sock, IPPROTO_TCP, TCP_NODELAY, &fFlag, sizeof(fFlag));
1000}
1001
1002
1003RTR3DECL(int) RTTcpSelectOne(RTSOCKET Sock, RTMSINTERVAL cMillies)
1004{
1005 return RTSocketSelectOne(Sock, cMillies);
1006}
1007
1008
1009RTR3DECL(int) RTTcpSelectOneEx(RTSOCKET Sock, uint32_t fEvents, uint32_t *pfEvents,
1010 RTMSINTERVAL cMillies)
1011{
1012 return RTSocketSelectOneEx(Sock, fEvents, pfEvents, cMillies);
1013}
1014
1015
1016RTR3DECL(int) RTTcpGetLocalAddress(RTSOCKET Sock, PRTNETADDR pAddr)
1017{
1018 return RTSocketGetLocalAddress(Sock, pAddr);
1019}
1020
1021
1022RTR3DECL(int) RTTcpGetPeerAddress(RTSOCKET Sock, PRTNETADDR pAddr)
1023{
1024 return RTSocketGetPeerAddress(Sock, pAddr);
1025}
1026
1027
1028RTR3DECL(int) RTTcpSgWrite(RTSOCKET Sock, PCRTSGBUF pSgBuf)
1029{
1030 return RTSocketSgWrite(Sock, pSgBuf);
1031}
1032
1033
1034RTR3DECL(int) RTTcpSgWriteL(RTSOCKET hSocket, size_t cSegs, ...)
1035{
1036 va_list va;
1037 va_start(va, cSegs);
1038 int rc = RTSocketSgWriteLV(hSocket, cSegs, va);
1039 va_end(va);
1040 return rc;
1041}
1042
1043
1044RTR3DECL(int) RTTcpSgWriteLV(RTSOCKET hSocket, size_t cSegs, va_list va)
1045{
1046 return RTSocketSgWriteLV(hSocket, cSegs, va);
1047}
1048
1049
1050RTR3DECL(int) RTTcpReadNB(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
1051{
1052 return RTSocketReadNB(Sock, pvBuffer, cbBuffer, pcbRead);
1053}
1054
1055
1056RTR3DECL(int) RTTcpWriteNB(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten)
1057{
1058 return RTSocketWriteNB(Sock, pvBuffer, cbBuffer, pcbWritten);
1059}
1060
1061
1062RTR3DECL(int) RTTcpSgWriteNB(RTSOCKET Sock, PCRTSGBUF pSgBuf, size_t *pcbWritten)
1063{
1064 return RTSocketSgWriteNB(Sock, pSgBuf, pcbWritten);
1065}
1066
1067
1068RTR3DECL(int) RTTcpSgWriteLNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, ...)
1069{
1070 va_list va;
1071 va_start(va, pcbWritten);
1072 int rc = RTSocketSgWriteLVNB(hSocket, cSegs, pcbWritten, va);
1073 va_end(va);
1074 return rc;
1075}
1076
1077
1078RTR3DECL(int) RTTcpSgWriteLVNB(RTSOCKET hSocket, size_t cSegs, size_t *pcbWritten, va_list va)
1079{
1080 return RTSocketSgWriteLVNB(hSocket, cSegs, pcbWritten, va);
1081}
1082
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