VirtualBox

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

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

Runtime/TCP: add proper handling of error codes from resolver. Platform-dependent, so squeezed it a bit into the existing code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.6 KB
Line 
1/* $Id: tcp.cpp 15509 2008-12-15 15:10:55Z 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 * @returns iprt status code.
147 */
148DECLINLINE(int) rtTcpError(bool fHErrNo)
149{
150#ifdef RT_OS_WINDOWS
151 return RTErrConvertFromWin32(WSAGetLastError());
152#else
153 if (fHErrNo)
154 {
155 switch (h_errno)
156 {
157 case HOST_NOT_FOUND:
158 return VERR_NET_HOST_NOT_FOUND;
159 break;
160 case NO_DATA:
161 return VERR_NET_ADDRESS_NOT_AVAILABLE;
162 break;
163 case NO_RECOVERY:
164 return VERR_IO_GEN_FAILURE;
165 break;
166 case TRY_AGAIN:
167 return VERR_TRY_AGAIN;
168 break;
169 default:
170 return VERR_UNRESOLVED_ERROR;
171 }
172 }
173 else
174 return RTErrConvertFromErrno(errno);
175#endif
176}
177
178
179/**
180 * Atomicly updates a socket variable.
181 * @returns The old value.
182 * @param pSock The socket variable to update.
183 * @param Sock The new value.
184 */
185DECLINLINE(RTSOCKET) rtTcpAtomicXchgSock(RTSOCKET volatile *pSock, const RTSOCKET Sock)
186{
187 switch (sizeof(RTSOCKET))
188 {
189 case 4: return (RTSOCKET)ASMAtomicXchgS32((int32_t volatile *)pSock, (int32_t)Sock);
190 default:
191 AssertReleaseFailed();
192 return NIL_RTSOCKET;
193 }
194}
195
196
197/**
198 * Changes the TCP server state.
199 */
200DECLINLINE(bool) rtTcpServerSetState(PRTTCPSERVER pServer, RTTCPSERVERSTATE enmStateNew, RTTCPSERVERSTATE enmStateOld)
201{
202 bool fRc;
203 ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc);
204 return fRc;
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 * Do params checking
231 */
232 if (!uPort || !pfnServe || !pszThrdName || !ppServer)
233 {
234 AssertMsgFailed(("Invalid params\n"));
235 return VERR_INVALID_PARAMETER;
236 }
237
238 /*
239 * Create the server.
240 */
241 PRTTCPSERVER pServer;
242 int rc = RTTcpServerCreateEx(pszAddress, uPort, &pServer);
243 if (RT_SUCCESS(rc))
244 {
245 /*
246 * Create the listener thread.
247 */
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 return rc;
258 }
259
260 /*
261 * Destroy the server.
262 */
263 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_CREATED, RTTCPSERVERSTATE_STARTING);
264 RTTcpServerDestroy(pServer);
265 }
266
267 return rc;
268}
269
270
271/**
272 * Server thread, loops accepting connections until it's terminated.
273 *
274 * @returns iprt status code. (ignored).
275 * @param ThreadSelf Thread handle.
276 * @param pvServer Server handle.
277 */
278static DECLCALLBACK(int) rtTcpServerThread(RTTHREAD ThreadSelf, void *pvServer)
279{
280 PRTTCPSERVER pServer = (PRTTCPSERVER)pvServer;
281 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_ACCEPTING, RTTCPSERVERSTATE_STARTING))
282 return rtTcpServerListen(pServer);
283 rcTcpServerListenCleanup(pServer);
284 NOREF(ThreadSelf);
285 return VINF_SUCCESS;
286}
287
288
289/**
290 * Create single connection at a time TCP Server.
291 * The caller must call RTTcpServerListen() to actually start the server.
292 *
293 * @returns iprt status code.
294 * @param pszAddress The address for creating a listening socket.
295 * If NULL the server is bound to all interfaces.
296 * @param uPort The port for creating a listening socket.
297 * @param ppServer Where to store the serverhandle.
298 */
299RTR3DECL(int) RTTcpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTTCPSERVER ppServer)
300{
301 int rc;
302
303 /*
304 * Do params checking
305 */
306 if (!uPort || !ppServer)
307 {
308 AssertMsgFailed(("Invalid params\n"));
309 return VERR_INVALID_PARAMETER;
310 }
311
312#ifdef RT_OS_WINDOWS
313 /*
314 * Initialize WinSock and check version.
315 */
316 WORD wVersionRequested = MAKEWORD(1, 1);
317 WSADATA wsaData;
318 rc = WSAStartup(wVersionRequested, &wsaData);
319 if (wsaData.wVersion != wVersionRequested)
320 {
321 AssertMsgFailed(("Wrong winsock version\n"));
322 return VERR_NOT_SUPPORTED;
323 }
324#endif
325
326 /*
327 * Get host listening address.
328 */
329 struct hostent *pHostEnt = NULL;
330 if (pszAddress != NULL && *pszAddress)
331 {
332 pHostEnt = gethostbyname(pszAddress);
333 if (!pHostEnt)
334 {
335 struct in_addr InAddr;
336 InAddr.s_addr = inet_addr(pszAddress);
337 pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
338 if (!pHostEnt)
339 {
340 rc = rtTcpError(true);
341 AssertMsgFailed(("Could not get host address rc=%Rrc\n", rc));
342 return rc;
343 }
344 }
345 }
346
347 /*
348 * Setting up socket.
349 */
350 RTSOCKET WaitSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
351 if (WaitSock != -1)
352 {
353 /*
354 * Set socket options.
355 */
356 int fFlag = 1;
357 if (!setsockopt(WaitSock, SOL_SOCKET, SO_REUSEADDR, (const char *)&fFlag, sizeof(fFlag)))
358 {
359 /*
360 * Set socket family, address and port.
361 */
362 struct sockaddr_in LocalAddr = {0};
363 LocalAddr.sin_family = AF_INET;
364 LocalAddr.sin_port = htons(uPort);
365 /* if address not specified, use INADDR_ANY. */
366 if (!pHostEnt)
367 LocalAddr.sin_addr.s_addr = INADDR_ANY;
368 else
369 LocalAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
370
371 /*
372 * Bind a name to a socket.
373 */
374 if (bind(WaitSock, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr)) != -1)
375 {
376 /*
377 * Listen for connections on a socket.
378 */
379 if (listen(WaitSock, BACKLOG) != -1)
380 {
381 /*
382 * Create the server handle.
383 */
384 PRTTCPSERVER pServer = (PRTTCPSERVER)RTMemAllocZ(sizeof(*pServer));
385 if (pServer)
386 {
387 pServer->SockServer = WaitSock;
388 pServer->SockClient = NIL_RTSOCKET;
389 pServer->Thread = NIL_RTTHREAD;
390 pServer->enmState = RTTCPSERVERSTATE_CREATED;
391 *ppServer = pServer;
392 return VINF_SUCCESS;
393 }
394 else
395 rc = VERR_NO_MEMORY;
396 }
397 else
398 {
399 rc = rtTcpError(false);
400 AssertMsgFailed(("listen() %Rrc\n", rc));
401 }
402 }
403 else
404 {
405 rc = rtTcpError(false);
406 }
407 }
408 else
409 {
410 rc = rtTcpError(false);
411 AssertMsgFailed(("setsockopt() %Rrc\n", rc));
412 }
413 rtTcpClose(WaitSock, "RTServerCreateEx");
414 }
415 else
416 {
417 rc = rtTcpError(false);
418 AssertMsgFailed(("socket() %Rrc\n", rc));
419 }
420
421 return rc;
422}
423
424
425/**
426 * Listen for incoming connections.
427 *
428 * The function will loop accepting connections and call pfnServe for
429 * each of the incoming connections in turn. The pfnServe function can
430 * return VERR_TCP_SERVER_STOP too terminate this loop. A stopped server
431 * can only be destroyed.
432 *
433 * @returns iprt status code.
434 * @param pServer The server handle as returned from RTTcpServerCreateEx().
435 * @param pfnServe The function which will serve a new client connection.
436 * @param pvUser User argument passed to pfnServe.
437 */
438RTR3DECL(int) RTTcpServerListen(PRTTCPSERVER pServer, PFNRTTCPSERVE pfnServe, void *pvUser)
439{
440 /*
441 * Validate input.
442 */
443 if (!pfnServe || !pServer)
444 {
445 AssertMsgFailed(("pfnServer=%p pServer=%p\n", pfnServe, pServer));
446 return VERR_INVALID_PARAMETER;
447 }
448 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_ACCEPTING, RTTCPSERVERSTATE_CREATED))
449 {
450 Assert(!pServer->pfnServe);
451 Assert(!pServer->pvUser);
452 Assert(pServer->Thread == NIL_RTTHREAD);
453 Assert(pServer->SockClient == NIL_RTSOCKET);
454
455 pServer->pfnServe = pfnServe;
456 pServer->pvUser = pvUser;
457 pServer->Thread = RTThreadSelf();
458 Assert(pServer->Thread != NIL_RTTHREAD);
459 return rtTcpServerListen(pServer);
460 }
461 AssertMsgFailed(("pServer->enmState=%d\n", pServer->enmState));
462 return VERR_INVALID_PARAMETER;
463}
464
465
466/**
467 * Closes the client socket.
468 */
469static int rtTcpServerDestroyClientSock(RTSOCKET volatile *pSock, const char *pszMsg)
470{
471 RTSOCKET Sock = rtTcpAtomicXchgSock(pSock, NIL_RTSOCKET);
472 if (Sock != NIL_RTSOCKET)
473 shutdown(Sock, SHUT_RDWR);
474 return rtTcpClose(Sock, pszMsg);
475}
476
477
478/**
479 * Internal worker common for RTTcpServerListen and the thread created by RTTcpServerCreate().
480 */
481static int rtTcpServerListen(PRTTCPSERVER pServer)
482{
483 /*
484 * Accept connection loop.
485 */
486 int rc = VINF_SUCCESS;
487 for (;;)
488 {
489 /*
490 * Change state.
491 */
492 RTTCPSERVERSTATE enmState = pServer->enmState;
493 if ( enmState != RTTCPSERVERSTATE_ACCEPTING
494 && enmState != RTTCPSERVERSTATE_SERVING)
495 break;
496 if (!rtTcpServerSetState(pServer, RTTCPSERVERSTATE_ACCEPTING, enmState))
497 continue;
498
499 /*
500 * Accept connection.
501 */
502 struct sockaddr_in RemoteAddr = {0};
503 socklen_t Len = sizeof(RemoteAddr);
504 RTSOCKET Socket = accept(pServer->SockServer, (struct sockaddr *)&RemoteAddr, &Len);
505 if (Socket == -1)
506 {
507#ifndef RT_OS_WINDOWS
508 /* These are typical for what can happen during destruction. */
509 if (errno == EBADF || errno == EINVAL || errno == ENOTSOCK)
510 break;
511#endif
512 continue;
513 }
514
515 /*
516 * Run a pfnServe callback.
517 */
518 if (!rtTcpServerSetState(pServer, RTTCPSERVERSTATE_SERVING, RTTCPSERVERSTATE_ACCEPTING))
519 break;
520 rtTcpAtomicXchgSock(&pServer->SockClient, Socket);
521 rc = pServer->pfnServe(Socket, pServer->pvUser);
522 rtTcpServerDestroyClientSock(&pServer->SockClient, "Listener: client");
523
524 /*
525 * Stop the server?
526 */
527 if (rc == VERR_TCP_SERVER_STOP)
528 {
529 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPING, RTTCPSERVERSTATE_SERVING))
530 {
531 /*
532 * Reset the server socket and change the state to stopped. After that state change
533 * we cannot safely access the handle so we'll have to return here.
534 */
535 RTSOCKET SockServer = rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET);
536 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_STOPPED, RTTCPSERVERSTATE_STOPPING);
537 rtTcpClose(SockServer, "Listener: server stopped");
538 return rc;
539 }
540 break;
541 }
542 }
543
544 /*
545 * Perform any pending clean and be gone.
546 */
547 rcTcpServerListenCleanup(pServer);
548 return rc;
549}
550
551
552/**
553 * Clean up after listener.
554 */
555static void rcTcpServerListenCleanup(PRTTCPSERVER pServer)
556{
557 /*
558 * Wait for any destroyers to finish signaling us.
559 */
560 for (unsigned cTries = 99; cTries > 0; cTries--)
561 {
562 RTTCPSERVERSTATE enmState = pServer->enmState;
563 switch (enmState)
564 {
565 /*
566 * Intermediate state while the destroyer closes the client socket.
567 */
568 case RTTCPSERVERSTATE_SIGNALING:
569 if (!RTThreadYield())
570 RTThreadSleep(1);
571 break;
572
573 /*
574 * Free the handle.
575 */
576 case RTTCPSERVERSTATE_DESTROYING:
577 {
578 rtTcpClose(rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET), "Listener-cleanup: server");
579 rtTcpServerSetState(pServer, RTTCPSERVERSTATE_FREED, RTTCPSERVERSTATE_DESTROYING);
580 RTMemFree(pServer);
581 return;
582 }
583
584 /*
585 * Everything else means failure.
586 */
587 default:
588 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
589 return;
590 }
591 }
592 AssertMsgFailed(("Timed out when trying to clean up after listener. pServer=%p enmState=%d\n", pServer, pServer->enmState));
593}
594
595
596/**
597 * Terminate the open connection to the server.
598 *
599 * @returns iprt status code.
600 * @param pServer Handle to the server.
601 */
602RTR3DECL(int) RTTcpServerDisconnectClient(PRTTCPSERVER pServer)
603{
604 /*
605 * Validate input.
606 */
607 if ( !pServer
608 || pServer->enmState <= RTTCPSERVERSTATE_INVALID
609 || pServer->enmState >= RTTCPSERVERSTATE_FREED)
610 {
611 AssertMsgFailed(("Invalid parameter!\n"));
612 return VERR_INVALID_PARAMETER;
613 }
614
615 return rtTcpServerDestroyClientSock(&pServer->SockClient, "DisconnectClient: client");
616}
617
618
619/**
620 * Closes down and frees a TCP Server.
621 * This will also terminate any open connections to the server.
622 *
623 * @returns iprt status code.
624 * @param pServer Handle to the server.
625 */
626RTR3DECL(int) RTTcpServerDestroy(PRTTCPSERVER pServer)
627{
628 /*
629 * Validate input.
630 */
631 if ( !pServer
632 || pServer->enmState <= RTTCPSERVERSTATE_INVALID
633 || pServer->enmState >= RTTCPSERVERSTATE_FREED)
634 {
635 AssertMsgFailed(("Invalid parameter!\n"));
636 return VERR_INVALID_PARAMETER;
637 }
638
639/** @todo r=bird: Some of this horrible code can probably be exchanged with a RTThreadWait(). (It didn't exist when this code was written.) */
640
641 /*
642 * Move it to the destroying state.
643 */
644 RTSOCKET SockServer = rtTcpAtomicXchgSock(&pServer->SockServer, NIL_RTSOCKET);
645 for (unsigned cTries = 99; cTries > 0; cTries--)
646 {
647 RTTCPSERVERSTATE enmState = pServer->enmState;
648 switch (enmState)
649 {
650 /*
651 * Try move it to the destroying state.
652 */
653 case RTTCPSERVERSTATE_STARTING:
654 case RTTCPSERVERSTATE_ACCEPTING:
655 case RTTCPSERVERSTATE_SERVING:
656 {
657 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_SIGNALING, enmState))
658 {
659 /* client */
660 rtTcpServerDestroyClientSock(&pServer->SockClient, "Destroyer: client");
661
662 bool fRc = rtTcpServerSetState(pServer, RTTCPSERVERSTATE_DESTROYING, RTTCPSERVERSTATE_SIGNALING);
663 Assert(fRc); NOREF(fRc);
664
665 /* server */
666 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server destroying");
667 RTThreadYield();
668
669 return VINF_SUCCESS;
670 }
671 break;
672 }
673
674
675 /*
676 * Intermediate state.
677 */
678 case RTTCPSERVERSTATE_STOPPING:
679 if (!RTThreadYield())
680 RTThreadSleep(1);
681 break;
682
683 /*
684 * Just release the handle.
685 */
686 case RTTCPSERVERSTATE_CREATED:
687 case RTTCPSERVERSTATE_STOPPED:
688 if (rtTcpServerSetState(pServer, RTTCPSERVERSTATE_FREED, enmState))
689 {
690 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server freeing");
691 RTMemFree(pServer);
692 return VINF_TCP_SERVER_STOP;
693 }
694 break;
695
696 /*
697 * Everything else means failure.
698 */
699 default:
700 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
701 return VERR_INTERNAL_ERROR;
702 }
703 }
704
705 AssertMsgFailed(("Giving up! pServer=%p enmState=%d\n", pServer, pServer->enmState));
706 rtTcpServerDestroyServerSock(SockServer, "Destroyer: server timeout");
707 return VERR_INTERNAL_ERROR;
708}
709
710
711/**
712 * Shutdowns the server socket.
713 */
714static void rtTcpServerDestroyServerSock(RTSOCKET SockServer, const char *pszMsg)
715{
716 if (SockServer == NIL_RTSOCKET)
717 return;
718 shutdown(SockServer, SHUT_RDWR);
719 rtTcpClose(SockServer, "Destroyer: server destroying");
720}
721
722
723
724RTR3DECL(int) RTTcpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
725{
726 /*
727 * Do params checking
728 */
729 if (!pvBuffer || !cbBuffer)
730 {
731 AssertMsgFailed(("Invalid params\n"));
732 return VERR_INVALID_PARAMETER;
733 }
734
735 /*
736 * Read loop.
737 * If pcbRead is NULL we have to fill the entire buffer!
738 */
739 size_t cbRead = 0;
740 size_t cbToRead = cbBuffer;
741 for (;;)
742 {
743 ssize_t cbBytesRead = recv(Sock, (char *)pvBuffer + cbRead, cbToRead, MSG_NOSIGNAL);
744 if (cbBytesRead < 0)
745 return rtTcpError(false);
746 if (cbBytesRead == 0 && rtTcpError(false))
747 return rtTcpError(false);
748 if (pcbRead)
749 {
750 /* return partial data */
751 *pcbRead = cbBytesRead;
752 break;
753 }
754
755 /* read more? */
756 cbRead += cbBytesRead;
757 if (cbRead == cbBuffer)
758 break;
759
760 /* next */
761 cbToRead = cbBuffer - cbRead;
762 }
763
764 return VINF_SUCCESS;
765}
766
767
768RTR3DECL(int) RTTcpWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
769{
770 do
771 {
772 ssize_t cbWritten = send(Sock, (const char *)pvBuffer, cbBuffer, MSG_NOSIGNAL);
773 if (cbWritten < 0)
774 return rtTcpError(false);
775 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d rtTcpError()=%d\n",
776 cbWritten, cbBuffer, rtTcpError(false)));
777 cbBuffer -= cbWritten;
778 pvBuffer = (char *)pvBuffer + cbWritten;
779 } while (cbBuffer);
780
781 return VINF_SUCCESS;
782}
783
784
785RTR3DECL(int) RTTcpFlush(RTSOCKET Sock)
786{
787 int fFlag = 1;
788 setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&fFlag, sizeof(fFlag));
789 fFlag = 0;
790 setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&fFlag, sizeof(fFlag));
791
792 return VINF_SUCCESS;
793}
794
795
796RTR3DECL(int) RTTcpSelectOne(RTSOCKET Sock, unsigned cMillies)
797{
798 fd_set fdsetR;
799 FD_ZERO(&fdsetR);
800 FD_SET(Sock, &fdsetR);
801
802 fd_set fdsetE = fdsetR;
803
804 int rc;
805 if (cMillies == RT_INDEFINITE_WAIT)
806 rc = select(Sock + 1, &fdsetR, NULL, &fdsetE, NULL);
807 else
808 {
809 struct timeval timeout;
810 timeout.tv_sec = cMillies / 1000;
811 timeout.tv_usec = (cMillies % 1000) * 1000;
812 rc = select(Sock + 1, &fdsetR, NULL, &fdsetE, &timeout);
813 }
814 if (rc > 0)
815 return VINF_SUCCESS;
816 if (rc == 0)
817 return VERR_TIMEOUT;
818 return rtTcpError(false);
819}
820
821
822RTR3DECL(int) RTTcpClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
823{
824 int rc;
825
826 /*
827 * Do params checking
828 */
829 AssertReturn(uPort, VERR_INVALID_PARAMETER);
830 AssertReturn(VALID_PTR(pszAddress), VERR_INVALID_PARAMETER);
831
832#ifdef RT_OS_WINDOWS
833 /*
834 * Initialize WinSock and check version.
835 */
836 WORD wVersionRequested = MAKEWORD(1, 1);
837 WSADATA wsaData;
838 rc = WSAStartup(wVersionRequested, &wsaData);
839 if (wsaData.wVersion != wVersionRequested)
840 {
841 AssertMsgFailed(("Wrong winsock version\n"));
842 return VERR_NOT_SUPPORTED;
843 }
844#endif
845
846 /*
847 * Resolve the address.
848 */
849 struct hostent *pHostEnt = NULL;
850 pHostEnt = gethostbyname(pszAddress);
851 if (!pHostEnt)
852 {
853 struct in_addr InAddr;
854 InAddr.s_addr = inet_addr(pszAddress);
855 pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
856 if (!pHostEnt)
857 {
858 rc = rtTcpError(false);
859 AssertMsgFailed(("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
860 return rc;
861 }
862 }
863
864 /*
865 * Create the socket and connect.
866 */
867 RTSOCKET Sock = socket(PF_INET, SOCK_STREAM, 0);
868 if (Sock != -1)
869 {
870 struct sockaddr_in InAddr = {0};
871 InAddr.sin_family = AF_INET;
872 InAddr.sin_port = htons(uPort);
873 InAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
874 if (!connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
875 {
876 *pSock = Sock;
877 return VINF_SUCCESS;
878 }
879 rc = rtTcpError(false);
880 rtTcpClose(Sock, "RTTcpClientConnect");
881 }
882 else
883 rc = rtTcpError(false);
884 return rc;
885}
886
887
888RTR3DECL(int) RTTcpClientClose(RTSOCKET Sock)
889{
890 return rtTcpClose(Sock, "RTTcpClientClose");
891}
892
893
894/**
895 * Internal close function which does all the proper bitching.
896 */
897static int rtTcpClose(RTSOCKET Sock, const char *pszMsg)
898{
899 /* ignore nil handles. */
900 if (Sock == NIL_RTSOCKET)
901 return VINF_SUCCESS;
902
903 /*
904 * Attempt to close it.
905 */
906#ifdef RT_OS_WINDOWS
907 int rc = closesocket(Sock);
908#else
909 int rc = close(Sock);
910#endif
911 if (!rc)
912 return VINF_SUCCESS;
913 rc = rtTcpError(false);
914 AssertMsgFailed(("\"%s\": close(%d) -> %Rrc\n", pszMsg, Sock, rc));
915 return rc;
916}
917
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