VirtualBox

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

Last change on this file since 96441 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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