VirtualBox

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

Last change on this file since 23613 was 23613, checked in by vboxsync, 16 years ago

tcp.cpp: nippicking: No else after return.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.7 KB
Line 
1/* $Id: tcp.cpp 23613 2009-10-08 10:10:06Z vboxsync $ */
2/** @file
3 * IPRT - TCP/IP.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#ifdef RT_OS_WINDOWS
36#include <winsock.h>
37#else /* !RT_OS_WINDOWS */
38#include <errno.h>
39#include <sys/stat.h>
40#include <sys/socket.h>
41#include <netinet/in.h>
42#include <netinet/tcp.h>
43#include <arpa/inet.h>
44#include <sys/un.h>
45#include <netdb.h>
46#include <unistd.h>
47#endif /* !RT_OS_WINDOWS */
48
49#include <iprt/tcp.h>
50#include <iprt/thread.h>
51#include <iprt/alloc.h>
52#include <iprt/assert.h>
53#include <iprt/asm.h>
54#include <iprt/err.h>
55#include <iprt/string.h>
56
57
58/* non-standard linux stuff (it seems). */
59#ifndef MSG_NOSIGNAL
60# define MSG_NOSIGNAL 0
61#endif
62#ifndef SHUT_RDWR
63# ifdef SD_BOTH
64# define SHUT_RDWR SD_BOTH
65# else
66# define SHUT_RDWR 2
67# endif
68#endif
69
70/* fixup backlevel OSes. */
71#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
72# define socklen_t int
73#endif
74
75
76/*******************************************************************************
77* Defined Constants And Macros *
78*******************************************************************************/
79#define BACKLOG 10 /* how many pending connections queue will hold */
80
81
82/*******************************************************************************
83* Structures and Typedefs *
84*******************************************************************************/
85/**
86 * TCP Server state.
87 */
88typedef enum RTTCPSERVERSTATE
89{
90 /** Invalid. */
91 RTTCPSERVERSTATE_INVALID = 0,
92 /** Created. */
93 RTTCPSERVERSTATE_CREATED,
94 /** Listener thread is starting up. */
95 RTTCPSERVERSTATE_STARTING,
96 /** Accepting client connections. */
97 RTTCPSERVERSTATE_ACCEPTING,
98 /** Serving a client. */
99 RTTCPSERVERSTATE_SERVING,
100 /** Listener terminating. */
101 RTTCPSERVERSTATE_STOPPING,
102 /** Listener terminated. */
103 RTTCPSERVERSTATE_STOPPED,
104 /** Destroying signaling to the listener, listener will wait. */
105 RTTCPSERVERSTATE_SIGNALING,
106 /** Listener cleans up. */
107 RTTCPSERVERSTATE_DESTROYING,
108 /** Freed. */
109 RTTCPSERVERSTATE_FREED
110} RTTCPSERVERSTATE;
111
112/*
113 * Internal representation of the TCP Server handle.
114 */
115typedef struct RTTCPSERVER
116{
117 /** The server state. */
118 RTTCPSERVERSTATE volatile enmState;
119 /** The server thread. */
120 RTTHREAD Thread;
121 /** The server socket. */
122 RTSOCKET volatile SockServer;
123 /** The socket to the client currently being serviced.
124 * This is NIL_RTSOCKET when no client is serviced. */
125 RTSOCKET volatile SockClient;
126 /** The connection function. */
127 PFNRTTCPSERVE pfnServe;
128 /** Argument to pfnServer. */
129 void *pvUser;
130} RTTCPSERVER;
131
132
133/*******************************************************************************
134* Internal Functions *
135*******************************************************************************/
136static DECLCALLBACK(int) rtTcpServerThread(RTTHREAD ThreadSelf, void *pvServer);
137static int rtTcpServerListen(PRTTCPSERVER pServer);
138static void rcTcpServerListenCleanup(PRTTCPSERVER pServer);
139static void rtTcpServerDestroyServerSock(RTSOCKET SockServer, const char *pszMsg);
140static int rtTcpClose(RTSOCKET Sock, const char *pszMsg);
141
142
143
144/**
145 * Get the last error as an iprt status code.
146 *
147 * @returns iprt status code.
148 */
149DECLINLINE(int) rtTcpError(void)
150{
151#ifdef RT_OS_WINDOWS
152 return RTErrConvertFromWin32(WSAGetLastError());
153#else
154 return RTErrConvertFromErrno(errno);
155#endif
156}
157
158
159/**
160 * Resets the last error.
161 */
162DECLINLINE(void) rtTcpErrorReset(void)
163{
164#ifdef RT_OS_WINDOWS
165 WSASetLastError(0);
166#else
167 errno = 0;
168#endif
169}
170
171
172/**
173 * Get the last resolver error as an iprt status code.
174 *
175 * @returns iprt status code.
176 */
177DECLINLINE(int) rtTcpResolverError(void)
178{
179#ifdef RT_OS_WINDOWS
180 return RTErrConvertFromWin32(WSAGetLastError());
181#else
182 switch (h_errno)
183 {
184 case HOST_NOT_FOUND:
185 return VERR_NET_HOST_NOT_FOUND;
186 case NO_DATA:
187 return VERR_NET_ADDRESS_NOT_AVAILABLE;
188 case NO_RECOVERY:
189 return VERR_IO_GEN_FAILURE;
190 case TRY_AGAIN:
191 return VERR_TRY_AGAIN;
192
193 default:
194 return VERR_UNRESOLVED_ERROR;
195 }
196#endif
197}
198
199
200/**
201 * Atomicly updates a socket variable.
202 * @returns The old value.
203 * @param pSock The socket variable to update.
204 * @param Sock The new value.
205 */
206DECLINLINE(RTSOCKET) rtTcpAtomicXchgSock(RTSOCKET volatile *pSock, const RTSOCKET Sock)
207{
208 switch (sizeof(RTSOCKET))
209 {
210 case 4: return (RTSOCKET)ASMAtomicXchgS32((int32_t volatile *)pSock, (int32_t)Sock);
211 default:
212 AssertReleaseFailed();
213 return NIL_RTSOCKET;
214 }
215}
216
217
218/**
219 * Changes the TCP server state.
220 */
221DECLINLINE(bool) rtTcpServerSetState(PRTTCPSERVER pServer, RTTCPSERVERSTATE enmStateNew, RTTCPSERVERSTATE enmStateOld)
222{
223 bool fRc;
224 ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc);
225 return fRc;
226}
227
228
229/**
230 * Create single connection at a time TCP Server in a separate thread.
231 *
232 * The thread will loop accepting connections and call pfnServe for
233 * each of the incoming connections in turn. The pfnServe function can
234 * return VERR_TCP_SERVER_STOP too terminate this loop. RTTcpServerDestroy()
235 * should be used to terminate the server.
236 *
237 * @returns iprt status code.
238 * @param pszAddress The address for creating a listening socket.
239 * If NULL or empty string the server is bound to all interfaces.
240 * @param uPort The port for creating a listening socket.
241 * @param enmType The thread type.
242 * @param pszThrdName The name of the worker thread.
243 * @param pfnServe The function which will serve a new client connection.
244 * @param pvUser User argument passed to pfnServe.
245 * @param ppServer Where to store the serverhandle.
246 */
247RTR3DECL(int) RTTcpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName,
248 PFNRTTCPSERVE pfnServe, void *pvUser, PPRTTCPSERVER ppServer)
249{
250 /*
251 * Do params checking
252 */
253 if (!uPort || !pfnServe || !pszThrdName || !ppServer)
254 {
255 AssertMsgFailed(("Invalid params\n"));
256 return VERR_INVALID_PARAMETER;
257 }
258
259 /*
260 * Create the server.
261 */
262 PRTTCPSERVER pServer;
263 int rc = RTTcpServerCreateEx(pszAddress, uPort, &pServer);
264 if (RT_SUCCESS(rc))
265 {
266 /*
267 * Create the listener thread.
268 */
269 pServer->enmState = RTTCPSERVERSTATE_STARTING;
270 pServer->pvUser = pvUser;
271 pServer->pfnServe = pfnServe;
272 rc = RTThreadCreate(&pServer->Thread, rtTcpServerThread, pServer, 0, enmType, /*RTTHREADFLAGS_WAITABLE*/0, pszThrdName);
273 if (RT_SUCCESS(rc))
274 {
275 /* done */
276 if (ppServer)
277 *ppServer = pServer;
278 return rc;
279 }
280
281 /*
282 * Destroy the server.
283 */
284 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_CREATED, RTTCPSERVERSTATE_STARTING);
285 RTTcpServerDestroy(pServer);
286 }
287
288 return rc;
289}
290
291
292/**
293 * Server thread, loops accepting connections until it's terminated.
294 *
295 * @returns iprt status code. (ignored).
296 * @param ThreadSelf Thread handle.
297 * @param pvServer Server handle.
298 */
299static DECLCALLBACK(int) rtTcpServerThread(RTTHREAD ThreadSelf, void *pvServer)
300{
301 PRTTCPSERVER pServer = (PRTTCPSERVER)pvServer;
302 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_ACCEPTING, RTTCPSERVERSTATE_STARTING))
303 return rtTcpServerListen(pServer);
304 rcTcpServerListenCleanup(pServer);
305 NOREF(ThreadSelf);
306 return VINF_SUCCESS;
307}
308
309
310/**
311 * Create single connection at a time TCP Server.
312 * The caller must call RTTcpServerListen() to actually start the server.
313 *
314 * @returns iprt status code.
315 * @param pszAddress The address for creating a listening socket.
316 * If NULL the server is bound to all interfaces.
317 * @param uPort The port for creating a listening socket.
318 * @param ppServer Where to store the serverhandle.
319 */
320RTR3DECL(int) RTTcpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTTCPSERVER ppServer)
321{
322 int rc;
323
324 /*
325 * Do params checking
326 */
327 if (!uPort || !ppServer)
328 {
329 AssertMsgFailed(("Invalid params\n"));
330 return VERR_INVALID_PARAMETER;
331 }
332
333#ifdef RT_OS_WINDOWS
334 /*
335 * Initialize WinSock and check version.
336 */
337 WORD wVersionRequested = MAKEWORD(1, 1);
338 WSADATA wsaData;
339 rc = WSAStartup(wVersionRequested, &wsaData);
340 if (wsaData.wVersion != wVersionRequested)
341 {
342 AssertMsgFailed(("Wrong winsock version\n"));
343 return VERR_NOT_SUPPORTED;
344 }
345#endif
346
347 /*
348 * Get host listening address.
349 */
350 struct hostent *pHostEnt = NULL;
351 if (pszAddress != NULL && *pszAddress)
352 {
353 pHostEnt = gethostbyname(pszAddress);
354 if (!pHostEnt)
355 {
356 struct in_addr InAddr;
357 InAddr.s_addr = inet_addr(pszAddress);
358 pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
359 if (!pHostEnt)
360 {
361 rc = rtTcpResolverError();
362 AssertMsgFailed(("Could not get host address rc=%Rrc\n", rc));
363 return rc;
364 }
365 }
366 }
367
368 /*
369 * Setting up socket.
370 */
371 RTSOCKET WaitSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
372 if (WaitSock != -1)
373 {
374 /*
375 * Set socket options.
376 */
377 int fFlag = 1;
378 if (!setsockopt(WaitSock, SOL_SOCKET, SO_REUSEADDR, (const char *)&fFlag, sizeof(fFlag)))
379 {
380 /*
381 * Set socket family, address and port.
382 */
383 struct sockaddr_in LocalAddr = {0};
384 LocalAddr.sin_family = AF_INET;
385 LocalAddr.sin_port = htons(uPort);
386 /* if address not specified, use INADDR_ANY. */
387 if (!pHostEnt)
388 LocalAddr.sin_addr.s_addr = INADDR_ANY;
389 else
390 LocalAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
391
392 /*
393 * Bind a name to a socket.
394 */
395 if (bind(WaitSock, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr)) != -1)
396 {
397 /*
398 * Listen for connections on a socket.
399 */
400 if (listen(WaitSock, BACKLOG) != -1)
401 {
402 /*
403 * Create the server handle.
404 */
405 PRTTCPSERVER pServer = (PRTTCPSERVER)RTMemAllocZ(sizeof(*pServer));
406 if (pServer)
407 {
408 pServer->SockServer = WaitSock;
409 pServer->SockClient = NIL_RTSOCKET;
410 pServer->Thread = NIL_RTTHREAD;
411 pServer->enmState = RTTCPSERVERSTATE_CREATED;
412 *ppServer = pServer;
413 return VINF_SUCCESS;
414 }
415
416 /* bail out */
417 rc = VERR_NO_MEMORY;
418 }
419 else
420 {
421 rc = rtTcpError();
422 AssertMsgFailed(("listen() %Rrc\n", rc));
423 }
424 }
425 else
426 {
427 rc = rtTcpError();
428 }
429 }
430 else
431 {
432 rc = rtTcpError();
433 AssertMsgFailed(("setsockopt() %Rrc\n", rc));
434 }
435 rtTcpClose(WaitSock, "RTServerCreateEx");
436 }
437 else
438 {
439 rc = rtTcpError();
440 AssertMsgFailed(("socket() %Rrc\n", rc));
441 }
442
443 return rc;
444}
445
446
447/**
448 * Listen for incoming connections.
449 *
450 * The function will loop accepting connections and call pfnServe for
451 * each of the incoming connections in turn. The pfnServe function can
452 * return VERR_TCP_SERVER_STOP too terminate this loop. A stopped server
453 * can only be destroyed.
454 *
455 * @returns iprt status code.
456 * @param pServer The server handle as returned from RTTcpServerCreateEx().
457 * @param pfnServe The function which will serve a new client connection.
458 * @param pvUser User argument passed to pfnServe.
459 */
460RTR3DECL(int) RTTcpServerListen(PRTTCPSERVER pServer, PFNRTTCPSERVE pfnServe, void *pvUser)
461{
462 /*
463 * Validate input.
464 */
465 if (!pfnServe || !pServer)
466 {
467 AssertMsgFailed(("pfnServer=%p pServer=%p\n", pfnServe, pServer));
468 return VERR_INVALID_PARAMETER;
469 }
470 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_ACCEPTING, RTTCPSERVERSTATE_CREATED))
471 {
472 Assert(!pServer->pfnServe);
473 Assert(!pServer->pvUser);
474 Assert(pServer->Thread == NIL_RTTHREAD);
475 Assert(pServer->SockClient == NIL_RTSOCKET);
476
477 pServer->pfnServe = pfnServe;
478 pServer->pvUser = pvUser;
479 pServer->Thread = RTThreadSelf();
480 Assert(pServer->Thread != NIL_RTTHREAD);
481 return rtTcpServerListen(pServer);
482 }
483 AssertMsgFailed(("pServer->enmState=%d\n", pServer->enmState));
484 return VERR_INVALID_PARAMETER;
485}
486
487
488/**
489 * Closes the client socket.
490 */
491static int rtTcpServerDestroyClientSock(RTSOCKET volatile *pSock, const char *pszMsg)
492{
493 RTSOCKET Sock = rtTcpAtomicXchgSock(pSock, NIL_RTSOCKET);
494 if (Sock != NIL_RTSOCKET)
495 shutdown(Sock, SHUT_RDWR);
496 return rtTcpClose(Sock, pszMsg);
497}
498
499
500/**
501 * Internal worker common for RTTcpServerListen and the thread created by RTTcpServerCreate().
502 */
503static int rtTcpServerListen(PRTTCPSERVER pServer)
504{
505 /*
506 * Accept connection loop.
507 */
508 int rc = VINF_SUCCESS;
509 for (;;)
510 {
511 /*
512 * Change state.
513 */
514 RTTCPSERVERSTATE enmState = pServer->enmState;
515 if ( enmState != RTTCPSERVERSTATE_ACCEPTING
516 && enmState != RTTCPSERVERSTATE_SERVING)
517 break;
518 if (!rtTcpServerSetState(pServer, RTTCPSERVERSTATE_ACCEPTING, enmState))
519 continue;
520
521 /*
522 * Accept connection.
523 */
524 struct sockaddr_in RemoteAddr = {0};
525 socklen_t Len = sizeof(RemoteAddr);
526 RTSOCKET Socket = accept(pServer->SockServer, (struct sockaddr *)&RemoteAddr, &Len);
527 if (Socket == -1)
528 {
529#ifndef RT_OS_WINDOWS
530 /* These are typical for what can happen during destruction. */
531 if (errno == EBADF || errno == EINVAL || errno == ENOTSOCK)
532 break;
533#endif
534 continue;
535 }
536
537 /*
538 * Run a pfnServe callback.
539 */
540 if (!rtTcpServerSetState(pServer, RTTCPSERVERSTATE_SERVING, RTTCPSERVERSTATE_ACCEPTING))
541 break;
542 rtTcpAtomicXchgSock(&pServer->SockClient, Socket);
543 rc = pServer->pfnServe(Socket, pServer->pvUser);
544 rtTcpServerDestroyClientSock(&pServer->SockClient, "Listener: client");
545
546 /*
547 * Stop the server?
548 */
549 if (rc == VERR_TCP_SERVER_STOP)
550 {
551 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPING, RTTCPSERVERSTATE_SERVING))
552 {
553 /*
554 * Reset the server socket and change the state to stopped. After that state change
555 * we cannot safely access the handle so we'll have to return here.
556 */
557 RTSOCKET SockServer = rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET);
558 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPED, RTTCPSERVERSTATE_STOPPING);
559 rtTcpClose(SockServer, "Listener: server stopped");
560 return rc;
561 }
562 break;
563 }
564 }
565
566 /*
567 * Perform any pending clean and be gone.
568 */
569 rcTcpServerListenCleanup(pServer);
570 return rc;
571}
572
573
574/**
575 * Clean up after listener.
576 */
577static void rcTcpServerListenCleanup(PRTTCPSERVER pServer)
578{
579 /*
580 * Wait for any destroyers to finish signaling us.
581 */
582 for (unsigned cTries = 99; cTries > 0; cTries--)
583 {
584 RTTCPSERVERSTATE enmState = pServer->enmState;
585 switch (enmState)
586 {
587 /*
588 * Intermediate state while the destroyer closes the client socket.
589 */
590 case RTTCPSERVERSTATE_SIGNALING:
591 if (!RTThreadYield())
592 RTThreadSleep(1);
593 break;
594
595 /*
596 * Free the handle.
597 */
598 case RTTCPSERVERSTATE_DESTROYING:
599 {
600 rtTcpClose(rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET), "Listener-cleanup: server");
601 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_FREED, RTTCPSERVERSTATE_DESTROYING);
602 RTMemFree(pServer);
603 return;
604 }
605
606 /*
607 * Everything else means failure.
608 */
609 default:
610 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
611 return;
612 }
613 }
614 AssertMsgFailed(("Timed out when trying to clean up after listener. pServer=%p enmState=%d\n", pServer, pServer->enmState));
615}
616
617
618/**
619 * Terminate the open connection to the server.
620 *
621 * @returns iprt status code.
622 * @param pServer Handle to the server.
623 */
624RTR3DECL(int) RTTcpServerDisconnectClient(PRTTCPSERVER pServer)
625{
626 /*
627 * Validate input.
628 */
629 if ( !pServer
630 || pServer->enmState <= RTTCPSERVERSTATE_INVALID
631 || pServer->enmState >= RTTCPSERVERSTATE_FREED)
632 {
633 AssertMsgFailed(("Invalid parameter!\n"));
634 return VERR_INVALID_PARAMETER;
635 }
636
637 return rtTcpServerDestroyClientSock(&pServer->SockClient, "DisconnectClient: client");
638}
639
640
641/**
642 * Closes down and frees a TCP Server.
643 * This will also terminate any open connections to the server.
644 *
645 * @returns iprt status code.
646 * @param pServer Handle to the server.
647 */
648RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer)
649{
650 /*
651 * Validate input.
652 */
653 if ( !pServer
654 || pServer->enmState <= RTTCPSERVERSTATE_INVALID
655 || pServer->enmState >= RTTCPSERVERSTATE_FREED)
656 {
657 AssertMsgFailed(("Invalid parameter!\n"));
658 return VERR_INVALID_PARAMETER;
659 }
660
661/** @todo r=bird: Some of this horrible code can probably be exchanged with a RTThreadWait(). (It didn't exist when this code was written.) */
662
663 /*
664 * Move it to the destroying state.
665 */
666 RTSOCKET SockServer = rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET);
667 for (unsigned cTries = 99; cTries > 0; cTries--)
668 {
669 RTTCPSERVERSTATE enmState = pServer->enmState;
670 switch (enmState)
671 {
672 /*
673 * Try move it to the destroying state.
674 */
675 case RTTCPSERVERSTATE_STARTING:
676 case RTTCPSERVERSTATE_ACCEPTING:
677 case RTTCPSERVERSTATE_SERVING:
678 {
679 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_SIGNALING, enmState))
680 {
681 /* client */
682 rtTcpServerDestroyClientSock(&pServer->SockClient, "Destroyer: client");
683
684 bool fRc = rtTcpServerSetState(pServer, RTTCPSERVERSTATE_DESTROYING, RTTCPSERVERSTATE_SIGNALING);
685 Assert(fRc); NOREF(fRc);
686
687 /* server */
688 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server destroying");
689 RTThreadYield();
690
691 return VINF_SUCCESS;
692 }
693 break;
694 }
695
696
697 /*
698 * Intermediate state.
699 */
700 case RTTCPSERVERSTATE_STOPPING:
701 if (!RTThreadYield())
702 RTThreadSleep(1);
703 break;
704
705 /*
706 * Just release the handle.
707 */
708 case RTTCPSERVERSTATE_CREATED:
709 case RTTCPSERVERSTATE_STOPPED:
710 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_FREED, enmState))
711 {
712 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server freeing");
713 RTMemFree(pServer);
714 return VINF_TCP_SERVER_STOP;
715 }
716 break;
717
718 /*
719 * Everything else means failure.
720 */
721 default:
722 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
723 return VERR_INTERNAL_ERROR;
724 }
725 }
726
727 AssertMsgFailed(("Giving up! pServer=%p enmState=%d\n", pServer, pServer->enmState));
728 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server timeout");
729 return VERR_INTERNAL_ERROR;
730}
731
732
733/**
734 * Shutdowns the server socket.
735 */
736static void rtTcpServerDestroyServerSock(RTSOCKET SockServer, const char *pszMsg)
737{
738 if (SockServer == NIL_RTSOCKET)
739 return;
740 shutdown(SockServer, SHUT_RDWR);
741 rtTcpClose(SockServer, "Destroyer: server destroying");
742}
743
744
745
746RTR3DECL(int) RTTcpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
747{
748 /*
749 * Do params checking
750 */
751 if (!pvBuffer || !cbBuffer)
752 {
753 AssertMsgFailed(("Invalid params\n"));
754 return VERR_INVALID_PARAMETER;
755 }
756
757 /*
758 * Read loop.
759 * If pcbRead is NULL we have to fill the entire buffer!
760 */
761 size_t cbRead = 0;
762 size_t cbToRead = cbBuffer;
763 for (;;)
764 {
765 rtTcpErrorReset();
766 ssize_t cbBytesRead = recv(Sock, (char *)pvBuffer + cbRead, cbToRead, MSG_NOSIGNAL);
767 if (cbBytesRead < 0)
768 return rtTcpError();
769 if (cbBytesRead == 0 && rtTcpError())
770 return rtTcpError();
771 if (pcbRead)
772 {
773 /* return partial data */
774 *pcbRead = cbBytesRead;
775 break;
776 }
777
778 /* read more? */
779 cbRead += cbBytesRead;
780 if (cbRead == cbBuffer)
781 break;
782
783 /* next */
784 cbToRead = cbBuffer - cbRead;
785 }
786
787 return VINF_SUCCESS;
788}
789
790
791RTR3DECL(int) RTTcpWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
792{
793 do
794 {
795 ssize_t cbWritten = send(Sock, (const char *)pvBuffer, cbBuffer, MSG_NOSIGNAL);
796 if (cbWritten < 0)
797 return rtTcpError();
798 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d rtTcpError()=%d\n",
799 cbWritten, cbBuffer, rtTcpError()));
800 cbBuffer -= cbWritten;
801 pvBuffer = (char *)pvBuffer + cbWritten;
802 } while (cbBuffer);
803
804 return VINF_SUCCESS;
805}
806
807
808RTR3DECL(int) RTTcpFlush(RTSOCKET Sock)
809{
810 int fFlag = 1;
811 setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&fFlag, sizeof(fFlag));
812 fFlag = 0;
813 setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&fFlag, sizeof(fFlag));
814
815 return VINF_SUCCESS;
816}
817
818
819RTR3DECL(int) RTTcpSelectOne(RTSOCKET Sock, unsigned cMillies)
820{
821 fd_set fdsetR;
822 FD_ZERO(&fdsetR);
823 FD_SET(Sock, &fdsetR);
824
825 fd_set fdsetE = fdsetR;
826
827 int rc;
828 if (cMillies == RT_INDEFINITE_WAIT)
829 rc = select(Sock + 1, &fdsetR, NULL, &fdsetE, NULL);
830 else
831 {
832 struct timeval timeout;
833 timeout.tv_sec = cMillies / 1000;
834 timeout.tv_usec = (cMillies % 1000) * 1000;
835 rc = select(Sock + 1, &fdsetR, NULL, &fdsetE, &timeout);
836 }
837 if (rc > 0)
838 return VINF_SUCCESS;
839 if (rc == 0)
840 return VERR_TIMEOUT;
841 return rtTcpError();
842}
843
844
845RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
846{
847 int rc;
848
849 /*
850 * Do params checking
851 */
852 AssertReturn(uPort, VERR_INVALID_PARAMETER);
853 AssertReturn(VALID_PTR(pszAddress), VERR_INVALID_PARAMETER);
854
855#ifdef RT_OS_WINDOWS
856 /*
857 * Initialize WinSock and check version.
858 */
859 WORD wVersionRequested = MAKEWORD(1, 1);
860 WSADATA wsaData;
861 rc = WSAStartup(wVersionRequested, &wsaData);
862 if (wsaData.wVersion != wVersionRequested)
863 {
864 AssertMsgFailed(("Wrong winsock version\n"));
865 return VERR_NOT_SUPPORTED;
866 }
867#endif
868
869 /*
870 * Resolve the address.
871 */
872 struct hostent *pHostEnt = NULL;
873 pHostEnt = gethostbyname(pszAddress);
874 if (!pHostEnt)
875 {
876 struct in_addr InAddr;
877 InAddr.s_addr = inet_addr(pszAddress);
878 pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
879 if (!pHostEnt)
880 {
881 rc = rtTcpError();
882 AssertMsgFailed(("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
883 return rc;
884 }
885 }
886
887 /*
888 * Create the socket and connect.
889 */
890 RTSOCKET Sock = socket(PF_INET, SOCK_STREAM, 0);
891 if (Sock != -1)
892 {
893 struct sockaddr_in InAddr = {0};
894 InAddr.sin_family = AF_INET;
895 InAddr.sin_port = htons(uPort);
896 InAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
897 if (!connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
898 {
899 *pSock = Sock;
900 return VINF_SUCCESS;
901 }
902 rc = rtTcpError();
903 rtTcpClose(Sock, "RTTcpClientConnect");
904 }
905 else
906 rc = rtTcpError();
907 return rc;
908}
909
910
911RTR3DECL(int) RTTcpClientClose(RTSOCKET Sock)
912{
913 return rtTcpClose(Sock, "RTTcpClientClose");
914}
915
916
917/**
918 * Internal close function which does all the proper bitching.
919 */
920static int rtTcpClose(RTSOCKET Sock, const char *pszMsg)
921{
922 /* ignore nil handles. */
923 if (Sock == NIL_RTSOCKET)
924 return VINF_SUCCESS;
925
926 /*
927 * Attempt to close it.
928 */
929#ifdef RT_OS_WINDOWS
930 int rc = closesocket(Sock);
931#else
932 int rc = close(Sock);
933#endif
934 if (!rc)
935 return VINF_SUCCESS;
936 rc = rtTcpError();
937 AssertMsgFailed(("\"%s\": close(%d) -> %Rrc\n", pszMsg, Sock, rc));
938 return rc;
939}
940
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette