VirtualBox

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

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

IPRT/tcp.cpp: separated the resolver errors from the other ones, clear the last error before recv to ensure correct handling of 0 byte reads.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.7 KB
Line 
1/* $Id: tcp.cpp 15655 2008-12-18 13:28:02Z 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.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 <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 else
416 rc = VERR_NO_MEMORY;
417 }
418 else
419 {
420 rc = rtTcpError();
421 AssertMsgFailed(("listen() %Rrc\n", rc));
422 }
423 }
424 else
425 {
426 rc = rtTcpError();
427 }
428 }
429 else
430 {
431 rc = rtTcpError();
432 AssertMsgFailed(("setsockopt() %Rrc\n", rc));
433 }
434 rtTcpClose(WaitSock, "RTServerCreateEx");
435 }
436 else
437 {
438 rc = rtTcpError();
439 AssertMsgFailed(("socket() %Rrc\n", rc));
440 }
441
442 return rc;
443}
444
445
446/**
447 * Listen for incoming connections.
448 *
449 * The function will loop accepting connections and call pfnServe for
450 * each of the incoming connections in turn. The pfnServe function can
451 * return VERR_TCP_SERVER_STOP too terminate this loop. A stopped server
452 * can only be destroyed.
453 *
454 * @returns iprt status code.
455 * @param pServer The server handle as returned from RTTcpServerCreateEx().
456 * @param pfnServe The function which will serve a new client connection.
457 * @param pvUser User argument passed to pfnServe.
458 */
459RTR3DECL(int) RTTcpServerListen(PRTTCPSERVER pServer, PFNRTTCPSERVE pfnServe, void *pvUser)
460{
461 /*
462 * Validate input.
463 */
464 if (!pfnServe || !pServer)
465 {
466 AssertMsgFailed(("pfnServer=%p pServer=%p\n", pfnServe, pServer));
467 return VERR_INVALID_PARAMETER;
468 }
469 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_ACCEPTING, RTTCPSERVERSTATE_CREATED))
470 {
471 Assert(!pServer->pfnServe);
472 Assert(!pServer->pvUser);
473 Assert(pServer->Thread == NIL_RTTHREAD);
474 Assert(pServer->SockClient == NIL_RTSOCKET);
475
476 pServer->pfnServe = pfnServe;
477 pServer->pvUser = pvUser;
478 pServer->Thread = RTThreadSelf();
479 Assert(pServer->Thread != NIL_RTTHREAD);
480 return rtTcpServerListen(pServer);
481 }
482 AssertMsgFailed(("pServer->enmState=%d\n", pServer->enmState));
483 return VERR_INVALID_PARAMETER;
484}
485
486
487/**
488 * Closes the client socket.
489 */
490static int rtTcpServerDestroyClientSock(RTSOCKET volatile *pSock, const char *pszMsg)
491{
492 RTSOCKET Sock = rtTcpAtomicXchgSock(pSock, NIL_RTSOCKET);
493 if (Sock != NIL_RTSOCKET)
494 shutdown(Sock, SHUT_RDWR);
495 return rtTcpClose(Sock, pszMsg);
496}
497
498
499/**
500 * Internal worker common for RTTcpServerListen and the thread created by RTTcpServerCreate().
501 */
502static int rtTcpServerListen(PRTTCPSERVER pServer)
503{
504 /*
505 * Accept connection loop.
506 */
507 int rc = VINF_SUCCESS;
508 for (;;)
509 {
510 /*
511 * Change state.
512 */
513 RTTCPSERVERSTATE enmState = pServer->enmState;
514 if ( enmState != RTTCPSERVERSTATE_ACCEPTING
515 && enmState != RTTCPSERVERSTATE_SERVING)
516 break;
517 if (!rtTcpServerSetState(pServer, RTTCPSERVERSTATE_ACCEPTING, enmState))
518 continue;
519
520 /*
521 * Accept connection.
522 */
523 struct sockaddr_in RemoteAddr = {0};
524 socklen_t Len = sizeof(RemoteAddr);
525 RTSOCKET Socket = accept(pServer->SockServer, (struct sockaddr *)&RemoteAddr, &Len);
526 if (Socket == -1)
527 {
528#ifndef RT_OS_WINDOWS
529 /* These are typical for what can happen during destruction. */
530 if (errno == EBADF || errno == EINVAL || errno == ENOTSOCK)
531 break;
532#endif
533 continue;
534 }
535
536 /*
537 * Run a pfnServe callback.
538 */
539 if (!rtTcpServerSetState(pServer, RTTCPSERVERSTATE_SERVING, RTTCPSERVERSTATE_ACCEPTING))
540 break;
541 rtTcpAtomicXchgSock(&pServer->SockClient, Socket);
542 rc = pServer->pfnServe(Socket, pServer->pvUser);
543 rtTcpServerDestroyClientSock(&pServer->SockClient, "Listener: client");
544
545 /*
546 * Stop the server?
547 */
548 if (rc == VERR_TCP_SERVER_STOP)
549 {
550 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPING, RTTCPSERVERSTATE_SERVING))
551 {
552 /*
553 * Reset the server socket and change the state to stopped. After that state change
554 * we cannot safely access the handle so we'll have to return here.
555 */
556 RTSOCKET SockServer = rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET);
557 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPED, RTTCPSERVERSTATE_STOPPING);
558 rtTcpClose(SockServer, "Listener: server stopped");
559 return rc;
560 }
561 break;
562 }
563 }
564
565 /*
566 * Perform any pending clean and be gone.
567 */
568 rcTcpServerListenCleanup(pServer);
569 return rc;
570}
571
572
573/**
574 * Clean up after listener.
575 */
576static void rcTcpServerListenCleanup(PRTTCPSERVER pServer)
577{
578 /*
579 * Wait for any destroyers to finish signaling us.
580 */
581 for (unsigned cTries = 99; cTries > 0; cTries--)
582 {
583 RTTCPSERVERSTATE enmState = pServer->enmState;
584 switch (enmState)
585 {
586 /*
587 * Intermediate state while the destroyer closes the client socket.
588 */
589 case RTTCPSERVERSTATE_SIGNALING:
590 if (!RTThreadYield())
591 RTThreadSleep(1);
592 break;
593
594 /*
595 * Free the handle.
596 */
597 case RTTCPSERVERSTATE_DESTROYING:
598 {
599 rtTcpClose(rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET), "Listener-cleanup: server");
600 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_FREED, RTTCPSERVERSTATE_DESTROYING);
601 RTMemFree(pServer);
602 return;
603 }
604
605 /*
606 * Everything else means failure.
607 */
608 default:
609 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
610 return;
611 }
612 }
613 AssertMsgFailed(("Timed out when trying to clean up after listener. pServer=%p enmState=%d\n", pServer, pServer->enmState));
614}
615
616
617/**
618 * Terminate the open connection to the server.
619 *
620 * @returns iprt status code.
621 * @param pServer Handle to the server.
622 */
623RTR3DECL(int) RTTcpServerDisconnectClient(PRTTCPSERVER pServer)
624{
625 /*
626 * Validate input.
627 */
628 if ( !pServer
629 || pServer->enmState <= RTTCPSERVERSTATE_INVALID
630 || pServer->enmState >= RTTCPSERVERSTATE_FREED)
631 {
632 AssertMsgFailed(("Invalid parameter!\n"));
633 return VERR_INVALID_PARAMETER;
634 }
635
636 return rtTcpServerDestroyClientSock(&pServer->SockClient, "DisconnectClient: client");
637}
638
639
640/**
641 * Closes down and frees a TCP Server.
642 * This will also terminate any open connections to the server.
643 *
644 * @returns iprt status code.
645 * @param pServer Handle to the server.
646 */
647RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer)
648{
649 /*
650 * Validate input.
651 */
652 if ( !pServer
653 || pServer->enmState <= RTTCPSERVERSTATE_INVALID
654 || pServer->enmState >= RTTCPSERVERSTATE_FREED)
655 {
656 AssertMsgFailed(("Invalid parameter!\n"));
657 return VERR_INVALID_PARAMETER;
658 }
659
660/** @todo r=bird: Some of this horrible code can probably be exchanged with a RTThreadWait(). (It didn't exist when this code was written.) */
661
662 /*
663 * Move it to the destroying state.
664 */
665 RTSOCKET SockServer = rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET);
666 for (unsigned cTries = 99; cTries > 0; cTries--)
667 {
668 RTTCPSERVERSTATE enmState = pServer->enmState;
669 switch (enmState)
670 {
671 /*
672 * Try move it to the destroying state.
673 */
674 case RTTCPSERVERSTATE_STARTING:
675 case RTTCPSERVERSTATE_ACCEPTING:
676 case RTTCPSERVERSTATE_SERVING:
677 {
678 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_SIGNALING, enmState))
679 {
680 /* client */
681 rtTcpServerDestroyClientSock(&pServer->SockClient, "Destroyer: client");
682
683 bool fRc = rtTcpServerSetState(pServer, RTTCPSERVERSTATE_DESTROYING, RTTCPSERVERSTATE_SIGNALING);
684 Assert(fRc); NOREF(fRc);
685
686 /* server */
687 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server destroying");
688 RTThreadYield();
689
690 return VINF_SUCCESS;
691 }
692 break;
693 }
694
695
696 /*
697 * Intermediate state.
698 */
699 case RTTCPSERVERSTATE_STOPPING:
700 if (!RTThreadYield())
701 RTThreadSleep(1);
702 break;
703
704 /*
705 * Just release the handle.
706 */
707 case RTTCPSERVERSTATE_CREATED:
708 case RTTCPSERVERSTATE_STOPPED:
709 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_FREED, enmState))
710 {
711 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server freeing");
712 RTMemFree(pServer);
713 return VINF_TCP_SERVER_STOP;
714 }
715 break;
716
717 /*
718 * Everything else means failure.
719 */
720 default:
721 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
722 return VERR_INTERNAL_ERROR;
723 }
724 }
725
726 AssertMsgFailed(("Giving up! pServer=%p enmState=%d\n", pServer, pServer->enmState));
727 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server timeout");
728 return VERR_INTERNAL_ERROR;
729}
730
731
732/**
733 * Shutdowns the server socket.
734 */
735static void rtTcpServerDestroyServerSock(RTSOCKET SockServer, const char *pszMsg)
736{
737 if (SockServer == NIL_RTSOCKET)
738 return;
739 shutdown(SockServer, SHUT_RDWR);
740 rtTcpClose(SockServer, "Destroyer: server destroying");
741}
742
743
744
745RTR3DECL(int) RTTcpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
746{
747 /*
748 * Do params checking
749 */
750 if (!pvBuffer || !cbBuffer)
751 {
752 AssertMsgFailed(("Invalid params\n"));
753 return VERR_INVALID_PARAMETER;
754 }
755
756 /*
757 * Read loop.
758 * If pcbRead is NULL we have to fill the entire buffer!
759 */
760 size_t cbRead = 0;
761 size_t cbToRead = cbBuffer;
762 for (;;)
763 {
764 rtTcpErrorReset();
765 ssize_t cbBytesRead = recv(Sock, (char *)pvBuffer + cbRead, cbToRead, MSG_NOSIGNAL);
766 if (cbBytesRead < 0)
767 return rtTcpError();
768 if (cbBytesRead == 0 && rtTcpError())
769 return rtTcpError();
770 if (pcbRead)
771 {
772 /* return partial data */
773 *pcbRead = cbBytesRead;
774 break;
775 }
776
777 /* read more? */
778 cbRead += cbBytesRead;
779 if (cbRead == cbBuffer)
780 break;
781
782 /* next */
783 cbToRead = cbBuffer - cbRead;
784 }
785
786 return VINF_SUCCESS;
787}
788
789
790RTR3DECL(int) RTTcpWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
791{
792 do
793 {
794 ssize_t cbWritten = send(Sock, (const char *)pvBuffer, cbBuffer, MSG_NOSIGNAL);
795 if (cbWritten < 0)
796 return rtTcpError();
797 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d rtTcpError()=%d\n",
798 cbWritten, cbBuffer, rtTcpError()));
799 cbBuffer -= cbWritten;
800 pvBuffer = (char *)pvBuffer + cbWritten;
801 } while (cbBuffer);
802
803 return VINF_SUCCESS;
804}
805
806
807RTR3DECL(int) RTTcpFlush(RTSOCKET Sock)
808{
809 int fFlag = 1;
810 setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&fFlag, sizeof(fFlag));
811 fFlag = 0;
812 setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&fFlag, sizeof(fFlag));
813
814 return VINF_SUCCESS;
815}
816
817
818RTR3DECL(int) RTTcpSelectOne(RTSOCKET Sock, unsigned cMillies)
819{
820 fd_set fdsetR;
821 FD_ZERO(&fdsetR);
822 FD_SET(Sock, &fdsetR);
823
824 fd_set fdsetE = fdsetR;
825
826 int rc;
827 if (cMillies == RT_INDEFINITE_WAIT)
828 rc = select(Sock + 1, &fdsetR, NULL, &fdsetE, NULL);
829 else
830 {
831 struct timeval timeout;
832 timeout.tv_sec = cMillies / 1000;
833 timeout.tv_usec = (cMillies % 1000) * 1000;
834 rc = select(Sock + 1, &fdsetR, NULL, &fdsetE, &timeout);
835 }
836 if (rc > 0)
837 return VINF_SUCCESS;
838 if (rc == 0)
839 return VERR_TIMEOUT;
840 return rtTcpError();
841}
842
843
844RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
845{
846 int rc;
847
848 /*
849 * Do params checking
850 */
851 AssertReturn(uPort, VERR_INVALID_PARAMETER);
852 AssertReturn(VALID_PTR(pszAddress), VERR_INVALID_PARAMETER);
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 = rtTcpError();
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 = socket(PF_INET, SOCK_STREAM, 0);
890 if (Sock != -1)
891 {
892 struct sockaddr_in InAddr = {0};
893 InAddr.sin_family = AF_INET;
894 InAddr.sin_port = htons(uPort);
895 InAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
896 if (!connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
897 {
898 *pSock = Sock;
899 return VINF_SUCCESS;
900 }
901 rc = rtTcpError();
902 rtTcpClose(Sock, "RTTcpClientConnect");
903 }
904 else
905 rc = rtTcpError();
906 return rc;
907}
908
909
910RTR3DECL(int) RTTcpClientClose(RTSOCKET Sock)
911{
912 return rtTcpClose(Sock, "RTTcpClientClose");
913}
914
915
916/**
917 * Internal close function which does all the proper bitching.
918 */
919static int rtTcpClose(RTSOCKET Sock, const char *pszMsg)
920{
921 /* ignore nil handles. */
922 if (Sock == NIL_RTSOCKET)
923 return VINF_SUCCESS;
924
925 /*
926 * Attempt to close it.
927 */
928#ifdef RT_OS_WINDOWS
929 int rc = closesocket(Sock);
930#else
931 int rc = close(Sock);
932#endif
933 if (!rc)
934 return VINF_SUCCESS;
935 rc = rtTcpError();
936 AssertMsgFailed(("\"%s\": close(%d) -> %Rrc\n", pszMsg, Sock, rc));
937 return rc;
938}
939
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