VirtualBox

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

Last change on this file since 99196 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 24.5 KB
Line 
1/* $Id: udp.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - UDP/IP.
4 */
5
6/*
7 * Copyright (C) 2006-2023 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, false /*fInheritable*/);
306 if (RT_SUCCESS(rc))
307 {
308 /*
309 * Set socket options.
310 */
311 int fFlag = 1;
312 if (!rtSocketSetOpt(Sock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag)))
313 {
314 /*
315 * Bind a name to the socket.
316 */
317 rc = rtSocketBind(Sock, &LocalAddr);
318 if (RT_SUCCESS(rc))
319 {
320 /*
321 * Create the server handle.
322 */
323 PRTUDPSERVER pServer = (PRTUDPSERVER)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pServer));
324 if (pServer)
325 {
326 pServer->u32Magic = RTUDPSERVER_MAGIC;
327 pServer->enmState = RTUDPSERVERSTATE_CREATED;
328 pServer->Thread = NIL_RTTHREAD;
329 pServer->hSocket = Sock;
330 pServer->pfnServe = NULL;
331 pServer->pvUser = NULL;
332 *ppServer = pServer;
333 return VINF_SUCCESS;
334 }
335
336 /* bail out */
337 rc = VERR_NO_MEMORY;
338 }
339 }
340 else
341 AssertMsgFailed(("rtSocketSetOpt: %Rrc\n", rc));
342 rtUdpClose(Sock, "RTServerCreateEx");
343 }
344
345 return rc;
346}
347
348
349/**
350 * Listen for incoming datagrams.
351 *
352 * The function will loop waiting for datagrams and call pfnServe for
353 * each of the incoming datagrams in turn. The pfnServe function can
354 * return VERR_UDP_SERVER_STOP too terminate this loop. A stopped server
355 * can only be destroyed.
356 *
357 * @returns IPRT status code.
358 * @retval VERR_UDP_SERVER_STOP if stopped by pfnServe.
359 * @retval VERR_UDP_SERVER_SHUTDOWN if shut down by RTUdpServerShutdown.
360 *
361 * @param pServer The server handle as returned from RTUdpServerCreateEx().
362 * @param pfnServe The function which will handle incoming datagrams.
363 * @param pvUser User argument passed to pfnServe.
364 */
365RTR3DECL(int) RTUdpServerListen(PRTUDPSERVER pServer, PFNRTUDPSERVE pfnServe, void *pvUser)
366{
367 /*
368 * Validate input and retain the instance.
369 */
370 AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
371 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
372 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
373 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
374
375 int rc = VERR_INVALID_STATE;
376 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_CREATED))
377 {
378 Assert(!pServer->pfnServe);
379 Assert(!pServer->pvUser);
380 Assert(pServer->Thread == NIL_RTTHREAD);
381
382 pServer->pfnServe = pfnServe;
383 pServer->pvUser = pvUser;
384 pServer->Thread = RTThreadSelf();
385 Assert(pServer->Thread != NIL_RTTHREAD);
386 rc = rtUdpServerListen(pServer);
387 }
388 else
389 {
390 AssertMsgFailed(("enmState=%d\n", pServer->enmState));
391 rc = VERR_INVALID_STATE;
392 }
393 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
394 return rc;
395}
396
397
398/**
399 * Internal worker common for RTUdpServerListen and the thread created by
400 * RTUdpServerCreate().
401 *
402 * The caller makes sure it has its own memory reference and releases it upon
403 * return.
404 */
405static int rtUdpServerListen(PRTUDPSERVER pServer)
406{
407 /*
408 * Wait for incoming datagrams loop.
409 */
410 for (;;)
411 {
412 /*
413 * Change state, getting an extra reference to the socket so we can
414 * allow others to close it while we're stuck in rtSocketAccept.
415 */
416 RTUDPSERVERSTATE enmState = pServer->enmState;
417 RTSOCKET hSocket;
418 ASMAtomicReadHandle(&pServer->hSocket, &hSocket);
419 if (hSocket != NIL_RTSOCKET)
420 RTSocketRetain(hSocket);
421 if ( enmState != RTUDPSERVERSTATE_WAITING
422 && enmState != RTUDPSERVERSTATE_RECEIVING)
423 {
424 RTSocketRelease(hSocket);
425 return rtUdpServerListenCleanup(pServer);
426 }
427 if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, enmState))
428 {
429 RTSocketRelease(hSocket);
430 continue;
431 }
432
433 /*
434 * Wait for incoming datagrams or errors.
435 */
436 uint32_t fEvents;
437 int rc = RTSocketSelectOneEx(hSocket, RTSOCKET_EVT_READ | RTSOCKET_EVT_ERROR, &fEvents, 1000);
438 RTSocketRelease(hSocket);
439 if (rc == VERR_TIMEOUT)
440 continue;
441 if (RT_FAILURE(rc))
442 {
443 /* These are typical for what can happen during destruction. */
444 if ( rc == VERR_INVALID_HANDLE
445 || rc == VERR_INVALID_PARAMETER
446 || rc == VERR_NET_NOT_SOCKET)
447 return rtUdpServerListenCleanup(pServer);
448 continue;
449 }
450 if (fEvents & RTSOCKET_EVT_ERROR)
451 return rtUdpServerListenCleanup(pServer);
452
453 /*
454 * Run a pfnServe callback.
455 */
456 if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_RECEIVING, RTUDPSERVERSTATE_WAITING))
457 return rtUdpServerListenCleanup(pServer);
458 rc = pServer->pfnServe(hSocket, pServer->pvUser);
459
460 /*
461 * Stop the server?
462 */
463 if (rc == VERR_UDP_SERVER_STOP)
464 {
465 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, RTUDPSERVERSTATE_RECEIVING))
466 {
467 /*
468 * Reset the server socket and change the state to stopped. After that state change
469 * we cannot safely access the handle so we'll have to return here.
470 */
471 hSocket = rtUdpAtomicXchgSock(&pServer->hSocket, NIL_RTSOCKET);
472 rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING);
473 rtUdpClose(hSocket, "Listener: server stopped");
474 }
475 else
476 rtUdpServerListenCleanup(pServer); /* ignore rc */
477 return rc;
478 }
479 }
480}
481
482
483/**
484 * Clean up after listener.
485 */
486static int rtUdpServerListenCleanup(PRTUDPSERVER pServer)
487{
488 /*
489 * Close the server socket.
490 */
491 rtUdpServerDestroySocket(&pServer->hSocket, "ListenCleanup");
492
493 /*
494 * Figure the return code and make sure the state is OK.
495 */
496 RTUDPSERVERSTATE enmState = pServer->enmState;
497 switch (enmState)
498 {
499 case RTUDPSERVERSTATE_STOPPING:
500 case RTUDPSERVERSTATE_STOPPED:
501 return VERR_UDP_SERVER_SHUTDOWN;
502
503 case RTUDPSERVERSTATE_WAITING:
504 rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPED, enmState);
505 return VERR_UDP_SERVER_DESTROYED;
506
507 case RTUDPSERVERSTATE_DESTROYING:
508 return VERR_UDP_SERVER_DESTROYED;
509
510 case RTUDPSERVERSTATE_STARTING:
511 case RTUDPSERVERSTATE_RECEIVING:
512 default:
513 AssertMsgFailedReturn(("pServer=%p enmState=%d\n", pServer, enmState), VERR_INTERNAL_ERROR_4);
514 }
515}
516
517
518/**
519 * Shuts down the server.
520 *
521 * @returns IPRT status code.
522 * @param pServer Handle to the server.
523 */
524RTR3DECL(int) RTUdpServerShutdown(PRTUDPSERVER pServer)
525{
526 /*
527 * Validate input and retain the instance.
528 */
529 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
530 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
531 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
532
533 /*
534 * Try change the state to stopping, then replace and destroy the server socket.
535 */
536 for (;;)
537 {
538 RTUDPSERVERSTATE enmState = pServer->enmState;
539 if ( enmState != RTUDPSERVERSTATE_WAITING
540 && enmState != RTUDPSERVERSTATE_RECEIVING)
541 {
542 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
543 switch (enmState)
544 {
545 case RTUDPSERVERSTATE_CREATED:
546 case RTUDPSERVERSTATE_STARTING:
547 default:
548 AssertMsgFailed(("%d\n", enmState));
549 return VERR_INVALID_STATE;
550
551 case RTUDPSERVERSTATE_STOPPING:
552 case RTUDPSERVERSTATE_STOPPED:
553 return VINF_SUCCESS;
554
555 case RTUDPSERVERSTATE_DESTROYING:
556 return VERR_UDP_SERVER_DESTROYED;
557 }
558 }
559 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, enmState))
560 {
561 rtUdpServerDestroySocket(&pServer->hSocket, "RTUdpServerShutdown");
562 rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING);
563
564 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
565 return VINF_SUCCESS;
566 }
567 }
568}
569
570
571/**
572 * Closes down and frees a UDP Server.
573 *
574 * @returns iprt status code.
575 * @param pServer Handle to the server.
576 */
577RTR3DECL(int) RTUdpServerDestroy(PRTUDPSERVER pServer)
578{
579 /*
580 * Validate input and retain the instance.
581 */
582 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
583 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
584 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); /* paranoia */
585
586 /*
587 * Move the state along so the listener can figure out what's going on.
588 */
589 for (;;)
590 {
591 bool fDestroyable;
592 RTUDPSERVERSTATE enmState = pServer->enmState;
593 switch (enmState)
594 {
595 case RTUDPSERVERSTATE_STARTING:
596 case RTUDPSERVERSTATE_WAITING:
597 case RTUDPSERVERSTATE_RECEIVING:
598 case RTUDPSERVERSTATE_CREATED:
599 case RTUDPSERVERSTATE_STOPPED:
600 fDestroyable = rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_DESTROYING, enmState);
601 break;
602
603 /* destroyable states */
604 case RTUDPSERVERSTATE_STOPPING:
605 fDestroyable = true;
606 break;
607
608 /*
609 * Everything else means user or internal misbehavior.
610 */
611 default:
612 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
613 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
614 return VERR_INTERNAL_ERROR;
615 }
616 if (fDestroyable)
617 break;
618 }
619
620 /*
621 * Destroy it.
622 */
623 ASMAtomicWriteU32(&pServer->u32Magic, ~RTUDPSERVER_MAGIC);
624 rtUdpServerDestroySocket(&pServer->hSocket, "Destroyer: server");
625
626 /*
627 * Release it.
628 */
629 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
630 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
631 return VINF_SUCCESS;
632}
633
634
635/**
636 * Internal close function which does all the proper bitching.
637 */
638static int rtUdpClose(RTSOCKET Sock, const char *pszMsg)
639{
640 NOREF(pszMsg); /** @todo drop this parameter? */
641
642 /* ignore nil handles. */
643 if (Sock == NIL_RTSOCKET)
644 return VINF_SUCCESS;
645
646 /*
647 * Close the socket handle (drops our reference to it).
648 */
649 return RTSocketClose(Sock);
650}
651
652
653RTR3DECL(int) RTUdpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr)
654{
655 if (!RT_VALID_PTR(pcbRead))
656 return VERR_INVALID_POINTER;
657 return RTSocketReadFrom(Sock, pvBuffer, cbBuffer, pcbRead, pSrcAddr);
658}
659
660
661RTR3DECL(int) RTUdpWrite(PRTUDPSERVER pServer, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr)
662{
663 /*
664 * Validate input and retain the instance.
665 */
666 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
667 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
668 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
669
670 RTSOCKET hSocket;
671 ASMAtomicReadHandle(&pServer->hSocket, &hSocket);
672 if (hSocket == NIL_RTSOCKET)
673 {
674 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
675 return VERR_INVALID_HANDLE;
676 }
677 RTSocketRetain(hSocket);
678
679 int rc = VINF_SUCCESS;
680 RTUDPSERVERSTATE enmState = pServer->enmState;
681 if ( enmState != RTUDPSERVERSTATE_CREATED
682 && enmState != RTUDPSERVERSTATE_STARTING
683 && enmState != RTUDPSERVERSTATE_WAITING
684 && enmState != RTUDPSERVERSTATE_RECEIVING
685 && enmState != RTUDPSERVERSTATE_STOPPING)
686 rc = VERR_INVALID_STATE;
687
688 if (RT_SUCCESS(rc))
689 rc = RTSocketWriteTo(hSocket, pvBuffer, cbBuffer, pDstAddr);
690
691 RTSocketRelease(hSocket);
692 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
693
694 return rc;
695}
696
697
698RTR3DECL(int) RTUdpCreateClientSocket(const char *pszAddress, uint32_t uPort, PRTNETADDR pLocalAddr, PRTSOCKET pSock)
699{
700 /*
701 * Validate input.
702 */
703 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
704 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
705 AssertPtrReturn(pSock, VERR_INVALID_POINTER);
706
707 /*
708 * Resolve the address.
709 */
710 RTNETADDR Addr;
711 int rc = RTSocketParseInetAddress(pszAddress, uPort, &Addr);
712 if (RT_FAILURE(rc))
713 return rc;
714
715 /*
716 * Create the socket and connect.
717 */
718 RTSOCKET Sock;
719 rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, 0, false /*fInheritable*/);
720 if (RT_SUCCESS(rc))
721 {
722 if (pLocalAddr)
723 rc = rtSocketBind(Sock, pLocalAddr);
724 if (RT_SUCCESS(rc))
725 {
726 rc = rtSocketConnect(Sock, &Addr, RT_SOCKETCONNECT_DEFAULT_WAIT);
727 if (RT_SUCCESS(rc))
728 {
729 *pSock = Sock;
730 return VINF_SUCCESS;
731 }
732 }
733 RTSocketClose(Sock);
734 }
735 return rc;
736}
737
738
739RTR3DECL(int) RTUdpCreateServerSocket(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
740{
741 /*
742 * Validate input.
743 */
744 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
745 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
746 AssertPtrReturn(pSock, VERR_INVALID_POINTER);
747
748 /*
749 * Resolve the address.
750 */
751 RTNETADDR LocalAddr;
752 int rc = RTSocketParseInetAddress(pszAddress, uPort, &LocalAddr);
753 if (RT_FAILURE(rc))
754 return rc;
755
756 /*
757 * Setting up socket.
758 */
759 RTSOCKET Sock;
760 rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, IPPROTO_UDP, false /*fInheritable*/);
761 if (RT_SUCCESS(rc))
762 {
763 /*
764 * Set socket options.
765 */
766 int fFlag = 1;
767 if (!rtSocketSetOpt(Sock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag)))
768 {
769 /*
770 * Bind a name to the socket.
771 */
772 rc = rtSocketBind(Sock, &LocalAddr);
773 if (RT_SUCCESS(rc))
774 {
775 *pSock = Sock;
776 return VINF_SUCCESS;
777 }
778 }
779 RTSocketClose(Sock);
780 }
781 return rc;
782}
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