VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/udp.cpp@ 37563

Last change on this file since 37563 was 37197, checked in by vboxsync, 13 years ago

Runtime/udp: build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.6 KB
Line 
1/* $Id: udp.cpp 37197 2011-05-24 14:56:02Z vboxsync $ */
2/** @file
3 * IPRT - UDP/IP.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#ifdef RT_OS_WINDOWS
32# include <winsock2.h>
33#else
34# include <sys/types.h>
35# include <sys/socket.h>
36# include <errno.h>
37# include <netinet/in.h>
38# include <netinet/udp.h>
39# include <arpa/inet.h>
40# include <netdb.h>
41#endif
42#include <limits.h>
43
44#include "internal/iprt.h"
45#include <iprt/udp.h>
46
47#include <iprt/asm.h>
48#include <iprt/assert.h>
49#include <iprt/err.h>
50#include <iprt/mempool.h>
51#include <iprt/mem.h>
52#include <iprt/string.h>
53#include <iprt/socket.h>
54#include <iprt/thread.h>
55#include <iprt/time.h>
56
57#include "internal/magics.h"
58#include "internal/socket.h"
59
60
61/*******************************************************************************
62* Defined Constants And Macros *
63*******************************************************************************/
64/* fixup backlevel OSes. */
65#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
66# define socklen_t int
67#endif
68
69
70/*******************************************************************************
71* Structures and Typedefs *
72*******************************************************************************/
73/**
74 * UDP Server state.
75 */
76typedef enum RTUDPSERVERSTATE
77{
78 /** Invalid. */
79 RTUDPSERVERSTATE_INVALID = 0,
80 /** Created. */
81 RTUDPSERVERSTATE_CREATED,
82 /** Thread for incoming datagrams is starting up. */
83 RTUDPSERVERSTATE_STARTING,
84 /** Waiting for incoming datagrams. */
85 RTUDPSERVERSTATE_WAITING,
86 /** Handling an incoming datagram. */
87 RTUDPSERVERSTATE_RECEIVING,
88 /** Thread terminating. */
89 RTUDPSERVERSTATE_STOPPING,
90 /** Thread terminated. */
91 RTUDPSERVERSTATE_STOPPED,
92 /** Final cleanup before being unusable. */
93 RTUDPSERVERSTATE_DESTROYING
94} RTUDPSERVERSTATE;
95
96/*
97 * Internal representation of the UDP Server handle.
98 */
99typedef struct RTUDPSERVER
100{
101 /** The magic value (RTUDPSERVER_MAGIC). */
102 uint32_t volatile u32Magic;
103 /** The server state. */
104 RTUDPSERVERSTATE volatile enmState;
105 /** The server thread. */
106 RTTHREAD Thread;
107 /** The server socket. */
108 RTSOCKET volatile hSocket;
109 /** The datagram receiver function. */
110 PFNRTUDPSERVE pfnServe;
111 /** Argument to pfnServer. */
112 void *pvUser;
113} RTUDPSERVER;
114
115
116/*******************************************************************************
117* Internal Functions *
118*******************************************************************************/
119static DECLCALLBACK(int) rtUdpServerThread(RTTHREAD ThreadSelf, void *pvServer);
120static int rtUdpServerListen(PRTUDPSERVER pServer);
121static int rtUdpServerListenCleanup(PRTUDPSERVER pServer);
122static int rtUdpServerDestroySocket(RTSOCKET volatile *pSock, const char *pszMsg);
123static int rtUdpClose(RTSOCKET Sock, const char *pszMsg);
124
125
126/**
127 * Atomicly updates a socket variable.
128 * @returns The old handle value.
129 * @param phSock The socket handle variable to update.
130 * @param hSock The new socket handle value.
131 */
132DECLINLINE(RTSOCKET) rtUdpAtomicXchgSock(RTSOCKET volatile *phSock, const RTSOCKET hNew)
133{
134 RTSOCKET hRet;
135 ASMAtomicXchgHandle(phSock, hNew, &hRet);
136 return hRet;
137}
138
139
140/**
141 * Tries to change the UDP server state.
142 */
143DECLINLINE(bool) rtUdpServerTrySetState(PRTUDPSERVER pServer, RTUDPSERVERSTATE enmStateNew, RTUDPSERVERSTATE enmStateOld)
144{
145 bool fRc;
146 ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc);
147 return fRc;
148}
149
150/**
151 * Changes the UDP server state.
152 */
153DECLINLINE(void) rtUdpServerSetState(PRTUDPSERVER pServer, RTUDPSERVERSTATE enmStateNew, RTUDPSERVERSTATE enmStateOld)
154{
155 bool fRc;
156 ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc);
157 Assert(fRc); NOREF(fRc);
158}
159
160
161/**
162 * Closes a socket.
163 *
164 * @returns IPRT status code.
165 */
166static int rtUdpServerDestroySocket(RTSOCKET volatile *pSock, const char *pszMsg)
167{
168 RTSOCKET hSocket = rtUdpAtomicXchgSock(pSock, NIL_RTSOCKET);
169 if (hSocket != NIL_RTSOCKET)
170 {
171 return rtUdpClose(hSocket, pszMsg);
172 }
173 return VINF_UDP_SERVER_NO_CLIENT;
174}
175
176
177/**
178 * Create single datagram at a time UDP Server in a separate thread.
179 *
180 * The thread will loop waiting for datagrams and call pfnServe for
181 * each of the incoming datagrams in turn. The pfnServe function can
182 * return VERR_UDP_SERVER_STOP too terminate this loop. RTUdpServerDestroy()
183 * should be used to terminate the server.
184 *
185 * @returns iprt status code.
186 * @param pszAddress The address for creating a datagram socket.
187 * If NULL or empty string the server is bound to all interfaces.
188 * @param uPort The port for creating a datagram socket.
189 * @param enmType The thread type.
190 * @param pszThrdName The name of the worker thread.
191 * @param pfnServe The function which will handle incoming datagrams.
192 * @param pvUser User argument passed to pfnServe.
193 * @param ppServer Where to store the serverhandle.
194 */
195RTR3DECL(int) RTUdpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName,
196 PFNRTUDPSERVE pfnServe, void *pvUser, PPRTUDPSERVER ppServer)
197{
198 /*
199 * Validate input.
200 */
201 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
202 AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
203 AssertPtrReturn(pszThrdName, VERR_INVALID_POINTER);
204 AssertPtrReturn(ppServer, VERR_INVALID_POINTER);
205
206 /*
207 * Create the server.
208 */
209 PRTUDPSERVER pServer;
210 int rc = RTUdpServerCreateEx(pszAddress, uPort, &pServer);
211 if (RT_SUCCESS(rc))
212 {
213 /*
214 * Create the listener thread.
215 */
216 RTMemPoolRetain(pServer);
217 pServer->enmState = RTUDPSERVERSTATE_STARTING;
218 pServer->pvUser = pvUser;
219 pServer->pfnServe = pfnServe;
220 rc = RTThreadCreate(&pServer->Thread, rtUdpServerThread, pServer, 0, enmType, /*RTTHREADFLAGS_WAITABLE*/0, pszThrdName);
221 if (RT_SUCCESS(rc))
222 {
223 /* done */
224 if (ppServer)
225 *ppServer = pServer;
226 else
227 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
228 return rc;
229 }
230 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
231
232 /*
233 * Destroy the server.
234 */
235 rtUdpServerSetState(pServer, RTUDPSERVERSTATE_CREATED, RTUDPSERVERSTATE_STARTING);
236 RTUdpServerDestroy(pServer);
237 }
238
239 return rc;
240}
241
242
243/**
244 * Server thread, loops waiting for datagrams until it's terminated.
245 *
246 * @returns iprt status code. (ignored).
247 * @param ThreadSelf Thread handle.
248 * @param pvServer Server handle.
249 */
250static DECLCALLBACK(int) rtUdpServerThread(RTTHREAD ThreadSelf, void *pvServer)
251{
252 PRTUDPSERVER pServer = (PRTUDPSERVER)pvServer;
253 int rc;
254 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_STARTING))
255 rc = rtUdpServerListen(pServer);
256 else
257 rc = rtUdpServerListenCleanup(pServer);
258 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
259 NOREF(ThreadSelf);
260 return VINF_SUCCESS;
261}
262
263
264/**
265 * Create single datagram at a time UDP Server.
266 * The caller must call RTUdpServerReceive() to actually start the server.
267 *
268 * @returns iprt status code.
269 * @param pszAddress The address for creating a datagram socket.
270 * If NULL the server is bound to all interfaces.
271 * @param uPort The port for creating a datagram socket.
272 * @param ppServer Where to store the serverhandle.
273 */
274RTR3DECL(int) RTUdpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTUDPSERVER ppServer)
275{
276 int rc;
277
278 /*
279 * Validate input.
280 */
281 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
282 AssertPtrReturn(ppServer, VERR_INVALID_PARAMETER);
283
284#ifdef RT_OS_WINDOWS
285 /*
286 * Initialize WinSock and check version.
287 */
288 WORD wVersionRequested = MAKEWORD(1, 1);
289 WSADATA wsaData;
290 rc = WSAStartup(wVersionRequested, &wsaData);
291 if (wsaData.wVersion != wVersionRequested)
292 {
293 AssertMsgFailed(("Wrong winsock version\n"));
294 return VERR_NOT_SUPPORTED;
295 }
296#endif
297
298 /*
299 * Get host listening address.
300 */
301 struct hostent *pHostEnt = NULL;
302 if (pszAddress != NULL && *pszAddress)
303 {
304 pHostEnt = gethostbyname(pszAddress);
305 if (!pHostEnt)
306 {
307 struct in_addr InAddr;
308 InAddr.s_addr = inet_addr(pszAddress);
309 pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
310 if (!pHostEnt)
311 {
312 rc = rtSocketResolverError();
313 return rc;
314 }
315 }
316 }
317
318 /*
319 * Setting up socket.
320 */
321 RTSOCKET Sock;
322 rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, IPPROTO_UDP);
323 if (RT_SUCCESS(rc))
324 {
325 RTSocketSetInheritance(Sock, false /*fInheritable*/);
326
327 /*
328 * Set socket options.
329 */
330 int fFlag = 1;
331 if (!rtSocketSetOpt(Sock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag)))
332 {
333 /*
334 * Set socket family, address and port.
335 */
336 struct sockaddr_in LocalAddr;
337 RT_ZERO(LocalAddr);
338 LocalAddr.sin_family = AF_INET;
339 LocalAddr.sin_port = htons(uPort);
340 /* if address not specified, use INADDR_ANY. */
341 if (!pHostEnt)
342 LocalAddr.sin_addr.s_addr = INADDR_ANY;
343 else
344 LocalAddr.sin_addr = *((struct in_addr *)pHostEnt->h_addr);
345
346 /*
347 * Bind a name to the socket.
348 */
349 rc = rtSocketBind(Sock, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr));
350 if (RT_SUCCESS(rc))
351 {
352 /*
353 * Create the server handle.
354 */
355 PRTUDPSERVER pServer = (PRTUDPSERVER)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pServer));
356 if (pServer)
357 {
358 pServer->u32Magic = RTUDPSERVER_MAGIC;
359 pServer->enmState = RTUDPSERVERSTATE_CREATED;
360 pServer->Thread = NIL_RTTHREAD;
361 pServer->hSocket = Sock;
362 pServer->pfnServe = NULL;
363 pServer->pvUser = NULL;
364 *ppServer = pServer;
365 return VINF_SUCCESS;
366 }
367
368 /* bail out */
369 rc = VERR_NO_MEMORY;
370 }
371 }
372 else
373 AssertMsgFailed(("rtSocketSetOpt: %Rrc\n", rc));
374 rtUdpClose(Sock, "RTServerCreateEx");
375 }
376
377 return rc;
378}
379
380
381/**
382 * Listen for incoming datagrams.
383 *
384 * The function will loop waiting for datagrams and call pfnServe for
385 * each of the incoming datagrams in turn. The pfnServe function can
386 * return VERR_UDP_SERVER_STOP too terminate this loop. A stopped server
387 * can only be destroyed.
388 *
389 * @returns IPRT status code.
390 * @retval VERR_UDP_SERVER_STOP if stopped by pfnServe.
391 * @retval VERR_UDP_SERVER_SHUTDOWN if shut down by RTUdpServerShutdown.
392 *
393 * @param pServer The server handle as returned from RTUdpServerCreateEx().
394 * @param pfnServe The function which will handle incoming datagrams.
395 * @param pvUser User argument passed to pfnServe.
396 */
397RTR3DECL(int) RTUdpServerListen(PRTUDPSERVER pServer, PFNRTUDPSERVE pfnServe, void *pvUser)
398{
399 /*
400 * Validate input and retain the instance.
401 */
402 AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
403 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
404 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
405 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
406
407 int rc = VERR_INVALID_STATE;
408 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_CREATED))
409 {
410 Assert(!pServer->pfnServe);
411 Assert(!pServer->pvUser);
412 Assert(pServer->Thread == NIL_RTTHREAD);
413
414 pServer->pfnServe = pfnServe;
415 pServer->pvUser = pvUser;
416 pServer->Thread = RTThreadSelf();
417 Assert(pServer->Thread != NIL_RTTHREAD);
418 rc = rtUdpServerListen(pServer);
419 }
420 else
421 {
422 AssertMsgFailed(("enmState=%d\n", pServer->enmState));
423 rc = VERR_INVALID_STATE;
424 }
425 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
426 return rc;
427}
428
429
430/**
431 * Internal worker common for RTUdpServerListen and the thread created by
432 * RTUdpServerCreate().
433 *
434 * The caller makes sure it has its own memory reference and releases it upon
435 * return.
436 */
437static int rtUdpServerListen(PRTUDPSERVER pServer)
438{
439 /*
440 * Wait for incoming datagrams loop.
441 */
442 for (;;)
443 {
444 /*
445 * Change state, getting an extra reference to the socket so we can
446 * allow others to close it while we're stuck in rtSocketAccept.
447 */
448 RTUDPSERVERSTATE enmState = pServer->enmState;
449 RTSOCKET hSocket;
450 ASMAtomicReadHandle(&pServer->hSocket, &hSocket);
451 if (hSocket != NIL_RTSOCKET)
452 RTSocketRetain(hSocket);
453 if ( enmState != RTUDPSERVERSTATE_WAITING
454 && enmState != RTUDPSERVERSTATE_RECEIVING)
455 {
456 RTSocketRelease(hSocket);
457 return rtUdpServerListenCleanup(pServer);
458 }
459 if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, enmState))
460 {
461 RTSocketRelease(hSocket);
462 continue;
463 }
464
465 /*
466 * Wait for incoming datagrams or errors.
467 */
468 uint32_t fEvents;
469 int rc = RTSocketSelectOneEx(hSocket, RTSOCKET_EVT_READ | RTSOCKET_EVT_ERROR, &fEvents, 1000);
470 RTSocketRelease(hSocket);
471 if (rc == VERR_TIMEOUT)
472 continue;
473 if (RT_FAILURE(rc))
474 {
475 /* These are typical for what can happen during destruction. */
476 if ( rc == VERR_INVALID_HANDLE
477 || rc == VERR_INVALID_PARAMETER
478 || rc == VERR_NET_NOT_SOCKET)
479 return rtUdpServerListenCleanup(pServer);
480 continue;
481 }
482 if (fEvents & RTSOCKET_EVT_ERROR)
483 return rtUdpServerListenCleanup(pServer);
484
485 /*
486 * Run a pfnServe callback.
487 */
488 if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_RECEIVING, RTUDPSERVERSTATE_WAITING))
489 return rtUdpServerListenCleanup(pServer);
490 rc = pServer->pfnServe(hSocket, pServer->pvUser);
491
492 /*
493 * Stop the server?
494 */
495 if (rc == VERR_UDP_SERVER_STOP)
496 {
497 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, RTUDPSERVERSTATE_RECEIVING))
498 {
499 /*
500 * Reset the server socket and change the state to stopped. After that state change
501 * we cannot safely access the handle so we'll have to return here.
502 */
503 hSocket = rtUdpAtomicXchgSock(&pServer->hSocket, NIL_RTSOCKET);
504 rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING);
505 rtUdpClose(hSocket, "Listener: server stopped");
506 }
507 else
508 rtUdpServerListenCleanup(pServer); /* ignore rc */
509 return rc;
510 }
511 }
512}
513
514
515/**
516 * Clean up after listener.
517 */
518static int rtUdpServerListenCleanup(PRTUDPSERVER pServer)
519{
520 /*
521 * Close the server socket.
522 */
523 rtUdpServerDestroySocket(&pServer->hSocket, "ListenCleanup");
524
525 /*
526 * Figure the return code and make sure the state is OK.
527 */
528 RTUDPSERVERSTATE enmState = pServer->enmState;
529 switch (enmState)
530 {
531 case RTUDPSERVERSTATE_STOPPING:
532 case RTUDPSERVERSTATE_STOPPED:
533 return VERR_UDP_SERVER_SHUTDOWN;
534
535 case RTUDPSERVERSTATE_WAITING:
536 rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPED, enmState);
537 return VERR_UDP_SERVER_DESTROYED;
538
539 case RTUDPSERVERSTATE_DESTROYING:
540 return VERR_UDP_SERVER_DESTROYED;
541
542 case RTUDPSERVERSTATE_STARTING:
543 case RTUDPSERVERSTATE_RECEIVING:
544 default:
545 AssertMsgFailedReturn(("pServer=%p enmState=%d\n", pServer, enmState), VERR_INTERNAL_ERROR_4);
546 }
547}
548
549
550/**
551 * Shuts down the server.
552 *
553 * @returns IPRT status code.
554 * @param pServer Handle to the server.
555 */
556RTR3DECL(int) RTUdpServerShutdown(PRTUDPSERVER pServer)
557{
558 /*
559 * Validate input and retain the instance.
560 */
561 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
562 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
563 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
564
565 /*
566 * Try change the state to stopping, then replace and destroy the server socket.
567 */
568 for (;;)
569 {
570 RTUDPSERVERSTATE enmState = pServer->enmState;
571 if ( enmState != RTUDPSERVERSTATE_WAITING
572 && enmState != RTUDPSERVERSTATE_RECEIVING)
573 {
574 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
575 switch (enmState)
576 {
577 case RTUDPSERVERSTATE_CREATED:
578 case RTUDPSERVERSTATE_STARTING:
579 default:
580 AssertMsgFailed(("%d\n", enmState));
581 return VERR_INVALID_STATE;
582
583 case RTUDPSERVERSTATE_STOPPING:
584 case RTUDPSERVERSTATE_STOPPED:
585 return VINF_SUCCESS;
586
587 case RTUDPSERVERSTATE_DESTROYING:
588 return VERR_UDP_SERVER_DESTROYED;
589 }
590 }
591 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, enmState))
592 {
593 rtUdpServerDestroySocket(&pServer->hSocket, "RTUdpServerShutdown");
594 rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING);
595
596 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
597 return VINF_SUCCESS;
598 }
599 }
600}
601
602
603/**
604 * Closes down and frees a UDP Server.
605 *
606 * @returns iprt status code.
607 * @param pServer Handle to the server.
608 */
609RTR3DECL(int) RTUdpServerDestroy(PRTUDPSERVER pServer)
610{
611 /*
612 * Validate input and retain the instance.
613 */
614 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
615 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
616 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); /* paranoia */
617
618 /*
619 * Move the state along so the listener can figure out what's going on.
620 */
621 for (;;)
622 {
623 bool fDestroyable;
624 RTUDPSERVERSTATE enmState = pServer->enmState;
625 switch (enmState)
626 {
627 case RTUDPSERVERSTATE_STARTING:
628 case RTUDPSERVERSTATE_WAITING:
629 case RTUDPSERVERSTATE_RECEIVING:
630 case RTUDPSERVERSTATE_CREATED:
631 case RTUDPSERVERSTATE_STOPPED:
632 fDestroyable = rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_DESTROYING, enmState);
633 break;
634
635 /* destroyable states */
636 case RTUDPSERVERSTATE_STOPPING:
637 fDestroyable = true;
638 break;
639
640 /*
641 * Everything else means user or internal misbehavior.
642 */
643 default:
644 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
645 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
646 return VERR_INTERNAL_ERROR;
647 }
648 if (fDestroyable)
649 break;
650 }
651
652 /*
653 * Destroy it.
654 */
655 ASMAtomicWriteU32(&pServer->u32Magic, ~RTUDPSERVER_MAGIC);
656 rtUdpServerDestroySocket(&pServer->hSocket, "Destroyer: server");
657
658 /*
659 * Release it.
660 */
661 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
662 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
663 return VINF_SUCCESS;
664}
665
666
667/**
668 * Internal close function which does all the proper bitching.
669 */
670static int rtUdpClose(RTSOCKET Sock, const char *pszMsg)
671{
672 /* ignore nil handles. */
673 if (Sock == NIL_RTSOCKET)
674 return VINF_SUCCESS;
675
676 /*
677 * Close the socket handle (drops our reference to it).
678 */
679 return RTSocketClose(Sock);
680}
681
682
683RTR3DECL(int) RTUdpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr)
684{
685 if (!RT_VALID_PTR(pcbRead))
686 return VERR_INVALID_POINTER;
687 return RTSocketReadFrom(Sock, pvBuffer, cbBuffer, pcbRead, pSrcAddr);
688}
689
690
691RTR3DECL(int) RTUdpWrite(PRTUDPSERVER pServer, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr)
692{
693 /*
694 * Validate input and retain the instance.
695 */
696 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
697 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
698 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
699
700 RTSOCKET hSocket;
701 ASMAtomicReadHandle(&pServer->hSocket, &hSocket);
702 if (hSocket == NIL_RTSOCKET)
703 {
704 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
705 return VERR_INVALID_HANDLE;
706 }
707 RTSocketRetain(hSocket);
708
709 int rc = VINF_SUCCESS;
710 RTUDPSERVERSTATE enmState = pServer->enmState;
711 if ( enmState != RTUDPSERVERSTATE_CREATED
712 && enmState != RTUDPSERVERSTATE_STARTING
713 && enmState != RTUDPSERVERSTATE_WAITING
714 && enmState != RTUDPSERVERSTATE_RECEIVING
715 && enmState != RTUDPSERVERSTATE_STOPPING)
716 rc = VERR_INVALID_STATE;
717
718 if (RT_SUCCESS(rc))
719 rc = RTSocketWriteTo(hSocket, pvBuffer, cbBuffer, pDstAddr);
720
721 RTSocketRelease(hSocket);
722 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
723
724 return rc;
725}
726
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