VirtualBox

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

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

iprt: added RTTcpSetSendCoalescing.

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