VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.3 KB
Line 
1/* $Id: udp.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - UDP/IP.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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
187RTR3DECL(int) RTUdpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName,
188 PFNRTUDPSERVE pfnServe, void *pvUser, PPRTUDPSERVER ppServer)
189{
190 /*
191 * Validate input.
192 */
193 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
194 AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
195 AssertPtrReturn(pszThrdName, VERR_INVALID_POINTER);
196 AssertPtrReturn(ppServer, VERR_INVALID_POINTER);
197
198 /*
199 * Create the server.
200 */
201 PRTUDPSERVER pServer;
202 int rc = RTUdpServerCreateEx(pszAddress, uPort, &pServer);
203 if (RT_SUCCESS(rc))
204 {
205 /*
206 * Create the listener thread.
207 */
208 RTMemPoolRetain(pServer);
209 pServer->enmState = RTUDPSERVERSTATE_STARTING;
210 pServer->pvUser = pvUser;
211 pServer->pfnServe = pfnServe;
212 rc = RTThreadCreate(&pServer->Thread, rtUdpServerThread, pServer, 0, enmType, /*RTTHREADFLAGS_WAITABLE*/0, pszThrdName);
213 if (RT_SUCCESS(rc))
214 {
215 /* done */
216 if (ppServer)
217 *ppServer = pServer;
218 else
219 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
220 return rc;
221 }
222 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
223
224 /*
225 * Destroy the server.
226 */
227 rtUdpServerSetState(pServer, RTUDPSERVERSTATE_CREATED, RTUDPSERVERSTATE_STARTING);
228 RTUdpServerDestroy(pServer);
229 }
230
231 return rc;
232}
233
234
235/**
236 * Server thread, loops waiting for datagrams until it's terminated.
237 *
238 * @returns iprt status code. (ignored).
239 * @param ThreadSelf Thread handle.
240 * @param pvServer Server handle.
241 */
242static DECLCALLBACK(int) rtUdpServerThread(RTTHREAD ThreadSelf, void *pvServer)
243{
244 PRTUDPSERVER pServer = (PRTUDPSERVER)pvServer;
245 int rc;
246 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_STARTING))
247 rc = rtUdpServerListen(pServer);
248 else
249 rc = rtUdpServerListenCleanup(pServer);
250 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
251 NOREF(ThreadSelf);
252 return VINF_SUCCESS;
253}
254
255
256RTR3DECL(int) RTUdpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTUDPSERVER ppServer)
257{
258
259 /*
260 * Validate input.
261 */
262 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
263 AssertPtrReturn(ppServer, VERR_INVALID_PARAMETER);
264
265 /*
266 * Resolve the address.
267 */
268 RTNETADDR LocalAddr;
269 int rc = RTSocketParseInetAddress(pszAddress, uPort, &LocalAddr);
270 if (RT_FAILURE(rc))
271 return rc;
272
273 /*
274 * Setting up socket.
275 */
276 RTSOCKET Sock;
277 rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, IPPROTO_UDP, false /*fInheritable*/);
278 if (RT_SUCCESS(rc))
279 {
280 /*
281 * Set socket options.
282 */
283 int fFlag = 1;
284 if (!rtSocketSetOpt(Sock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag)))
285 {
286 /*
287 * Bind a name to the socket.
288 */
289 rc = rtSocketBind(Sock, &LocalAddr);
290 if (RT_SUCCESS(rc))
291 {
292 /*
293 * Create the server handle.
294 */
295 PRTUDPSERVER pServer = (PRTUDPSERVER)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pServer));
296 if (pServer)
297 {
298 pServer->u32Magic = RTUDPSERVER_MAGIC;
299 pServer->enmState = RTUDPSERVERSTATE_CREATED;
300 pServer->Thread = NIL_RTTHREAD;
301 pServer->hSocket = Sock;
302 pServer->pfnServe = NULL;
303 pServer->pvUser = NULL;
304 *ppServer = pServer;
305 return VINF_SUCCESS;
306 }
307
308 /* bail out */
309 rc = VERR_NO_MEMORY;
310 }
311 }
312 else
313 AssertMsgFailed(("rtSocketSetOpt: %Rrc\n", rc));
314 rtUdpClose(Sock, "RTServerCreateEx");
315 }
316
317 return rc;
318}
319
320
321RTR3DECL(int) RTUdpServerListen(PRTUDPSERVER pServer, PFNRTUDPSERVE pfnServe, void *pvUser)
322{
323 /*
324 * Validate input and retain the instance.
325 */
326 AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
327 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
328 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
329 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
330
331 int rc = VERR_INVALID_STATE;
332 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_CREATED))
333 {
334 Assert(!pServer->pfnServe);
335 Assert(!pServer->pvUser);
336 Assert(pServer->Thread == NIL_RTTHREAD);
337
338 pServer->pfnServe = pfnServe;
339 pServer->pvUser = pvUser;
340 pServer->Thread = RTThreadSelf();
341 Assert(pServer->Thread != NIL_RTTHREAD);
342 rc = rtUdpServerListen(pServer);
343 }
344 else
345 {
346 AssertMsgFailed(("enmState=%d\n", pServer->enmState));
347 rc = VERR_INVALID_STATE;
348 }
349 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
350 return rc;
351}
352
353
354/**
355 * Internal worker common for RTUdpServerListen and the thread created by
356 * RTUdpServerCreate().
357 *
358 * The caller makes sure it has its own memory reference and releases it upon
359 * return.
360 */
361static int rtUdpServerListen(PRTUDPSERVER pServer)
362{
363 /*
364 * Wait for incoming datagrams loop.
365 */
366 for (;;)
367 {
368 /*
369 * Change state, getting an extra reference to the socket so we can
370 * allow others to close it while we're stuck in rtSocketAccept.
371 */
372 RTUDPSERVERSTATE enmState = pServer->enmState;
373 RTSOCKET hSocket;
374 ASMAtomicReadHandle(&pServer->hSocket, &hSocket);
375 if (hSocket != NIL_RTSOCKET)
376 RTSocketRetain(hSocket);
377 if ( enmState != RTUDPSERVERSTATE_WAITING
378 && enmState != RTUDPSERVERSTATE_RECEIVING)
379 {
380 RTSocketRelease(hSocket);
381 return rtUdpServerListenCleanup(pServer);
382 }
383 if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, enmState))
384 {
385 RTSocketRelease(hSocket);
386 continue;
387 }
388
389 /*
390 * Wait for incoming datagrams or errors.
391 */
392 uint32_t fEvents;
393 int rc = RTSocketSelectOneEx(hSocket, RTSOCKET_EVT_READ | RTSOCKET_EVT_ERROR, &fEvents, 1000);
394 RTSocketRelease(hSocket);
395 if (rc == VERR_TIMEOUT)
396 continue;
397 if (RT_FAILURE(rc))
398 {
399 /* These are typical for what can happen during destruction. */
400 if ( rc == VERR_INVALID_HANDLE
401 || rc == VERR_INVALID_PARAMETER
402 || rc == VERR_NET_NOT_SOCKET)
403 return rtUdpServerListenCleanup(pServer);
404 continue;
405 }
406 if (fEvents & RTSOCKET_EVT_ERROR)
407 return rtUdpServerListenCleanup(pServer);
408
409 /*
410 * Run a pfnServe callback.
411 */
412 if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_RECEIVING, RTUDPSERVERSTATE_WAITING))
413 return rtUdpServerListenCleanup(pServer);
414 rc = pServer->pfnServe(hSocket, pServer->pvUser);
415
416 /*
417 * Stop the server?
418 */
419 if (rc == VERR_UDP_SERVER_STOP)
420 {
421 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, RTUDPSERVERSTATE_RECEIVING))
422 {
423 /*
424 * Reset the server socket and change the state to stopped. After that state change
425 * we cannot safely access the handle so we'll have to return here.
426 */
427 hSocket = rtUdpAtomicXchgSock(&pServer->hSocket, NIL_RTSOCKET);
428 rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING);
429 rtUdpClose(hSocket, "Listener: server stopped");
430 }
431 else
432 rtUdpServerListenCleanup(pServer); /* ignore rc */
433 return rc;
434 }
435 }
436}
437
438
439/**
440 * Clean up after listener.
441 */
442static int rtUdpServerListenCleanup(PRTUDPSERVER pServer)
443{
444 /*
445 * Close the server socket.
446 */
447 rtUdpServerDestroySocket(&pServer->hSocket, "ListenCleanup");
448
449 /*
450 * Figure the return code and make sure the state is OK.
451 */
452 RTUDPSERVERSTATE enmState = pServer->enmState;
453 switch (enmState)
454 {
455 case RTUDPSERVERSTATE_STOPPING:
456 case RTUDPSERVERSTATE_STOPPED:
457 return VERR_UDP_SERVER_SHUTDOWN;
458
459 case RTUDPSERVERSTATE_WAITING:
460 rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPED, enmState);
461 return VERR_UDP_SERVER_DESTROYED;
462
463 case RTUDPSERVERSTATE_DESTROYING:
464 return VERR_UDP_SERVER_DESTROYED;
465
466 case RTUDPSERVERSTATE_STARTING:
467 case RTUDPSERVERSTATE_RECEIVING:
468 default:
469 AssertMsgFailedReturn(("pServer=%p enmState=%d\n", pServer, enmState), VERR_INTERNAL_ERROR_4);
470 }
471}
472
473
474RTR3DECL(int) RTUdpServerShutdown(PRTUDPSERVER pServer)
475{
476 /*
477 * Validate input and retain the instance.
478 */
479 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
480 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
481 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
482
483 /*
484 * Try change the state to stopping, then replace and destroy the server socket.
485 */
486 for (;;)
487 {
488 RTUDPSERVERSTATE enmState = pServer->enmState;
489 if ( enmState != RTUDPSERVERSTATE_WAITING
490 && enmState != RTUDPSERVERSTATE_RECEIVING)
491 {
492 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
493 switch (enmState)
494 {
495 case RTUDPSERVERSTATE_CREATED:
496 case RTUDPSERVERSTATE_STARTING:
497 default:
498 AssertMsgFailed(("%d\n", enmState));
499 return VERR_INVALID_STATE;
500
501 case RTUDPSERVERSTATE_STOPPING:
502 case RTUDPSERVERSTATE_STOPPED:
503 return VINF_SUCCESS;
504
505 case RTUDPSERVERSTATE_DESTROYING:
506 return VERR_UDP_SERVER_DESTROYED;
507 }
508 }
509 if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, enmState))
510 {
511 rtUdpServerDestroySocket(&pServer->hSocket, "RTUdpServerShutdown");
512 rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING);
513
514 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
515 return VINF_SUCCESS;
516 }
517 }
518}
519
520
521RTR3DECL(int) RTUdpServerDestroy(PRTUDPSERVER pServer)
522{
523 /*
524 * Validate input and retain the instance.
525 */
526 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
527 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
528 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); /* paranoia */
529
530 /*
531 * Move the state along so the listener can figure out what's going on.
532 */
533 for (;;)
534 {
535 bool fDestroyable;
536 RTUDPSERVERSTATE enmState = pServer->enmState;
537 switch (enmState)
538 {
539 case RTUDPSERVERSTATE_STARTING:
540 case RTUDPSERVERSTATE_WAITING:
541 case RTUDPSERVERSTATE_RECEIVING:
542 case RTUDPSERVERSTATE_CREATED:
543 case RTUDPSERVERSTATE_STOPPED:
544 fDestroyable = rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_DESTROYING, enmState);
545 break;
546
547 /* destroyable states */
548 case RTUDPSERVERSTATE_STOPPING:
549 fDestroyable = true;
550 break;
551
552 /*
553 * Everything else means user or internal misbehavior.
554 */
555 default:
556 AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
557 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
558 return VERR_INTERNAL_ERROR;
559 }
560 if (fDestroyable)
561 break;
562 }
563
564 /*
565 * Destroy it.
566 */
567 ASMAtomicWriteU32(&pServer->u32Magic, ~RTUDPSERVER_MAGIC);
568 rtUdpServerDestroySocket(&pServer->hSocket, "Destroyer: server");
569
570 /*
571 * Release it.
572 */
573 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
574 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
575 return VINF_SUCCESS;
576}
577
578
579/**
580 * Internal close function which does all the proper bitching.
581 */
582static int rtUdpClose(RTSOCKET Sock, const char *pszMsg)
583{
584 NOREF(pszMsg); /** @todo drop this parameter? */
585
586 /* ignore nil handles. */
587 if (Sock == NIL_RTSOCKET)
588 return VINF_SUCCESS;
589
590 /*
591 * Close the socket handle (drops our reference to it).
592 */
593 return RTSocketClose(Sock);
594}
595
596
597RTR3DECL(int) RTUdpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr)
598{
599 if (!RT_VALID_PTR(pcbRead))
600 return VERR_INVALID_POINTER;
601 return RTSocketReadFrom(Sock, pvBuffer, cbBuffer, pcbRead, pSrcAddr);
602}
603
604
605RTR3DECL(int) RTUdpWrite(PRTUDPSERVER pServer, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr)
606{
607 /*
608 * Validate input and retain the instance.
609 */
610 AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
611 AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
612 AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
613
614 RTSOCKET hSocket;
615 ASMAtomicReadHandle(&pServer->hSocket, &hSocket);
616 if (hSocket == NIL_RTSOCKET)
617 {
618 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
619 return VERR_INVALID_HANDLE;
620 }
621 RTSocketRetain(hSocket);
622
623 int rc = VINF_SUCCESS;
624 RTUDPSERVERSTATE enmState = pServer->enmState;
625 if ( enmState != RTUDPSERVERSTATE_CREATED
626 && enmState != RTUDPSERVERSTATE_STARTING
627 && enmState != RTUDPSERVERSTATE_WAITING
628 && enmState != RTUDPSERVERSTATE_RECEIVING
629 && enmState != RTUDPSERVERSTATE_STOPPING)
630 rc = VERR_INVALID_STATE;
631
632 if (RT_SUCCESS(rc))
633 rc = RTSocketWriteTo(hSocket, pvBuffer, cbBuffer, pDstAddr);
634
635 RTSocketRelease(hSocket);
636 RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
637
638 return rc;
639}
640
641
642RTR3DECL(int) RTUdpCreateClientSocket(const char *pszAddress, uint32_t uPort, PRTNETADDR pLocalAddr, PRTSOCKET pSock)
643{
644 /*
645 * Validate input.
646 */
647 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
648 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
649 AssertPtrReturn(pSock, VERR_INVALID_POINTER);
650
651 /*
652 * Resolve the address.
653 */
654 RTNETADDR Addr;
655 int rc = RTSocketParseInetAddress(pszAddress, uPort, &Addr);
656 if (RT_FAILURE(rc))
657 return rc;
658
659 /*
660 * Create the socket and connect.
661 */
662 RTSOCKET Sock;
663 rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, 0, false /*fInheritable*/);
664 if (RT_SUCCESS(rc))
665 {
666 if (pLocalAddr)
667 rc = rtSocketBind(Sock, pLocalAddr);
668 if (RT_SUCCESS(rc))
669 {
670 rc = rtSocketConnect(Sock, &Addr, RT_SOCKETCONNECT_DEFAULT_WAIT);
671 if (RT_SUCCESS(rc))
672 {
673 *pSock = Sock;
674 return VINF_SUCCESS;
675 }
676 }
677 RTSocketClose(Sock);
678 }
679 return rc;
680}
681
682
683RTR3DECL(int) RTUdpCreateServerSocket(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
684{
685 /*
686 * Validate input.
687 */
688 AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
689 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
690 AssertPtrReturn(pSock, VERR_INVALID_POINTER);
691
692 /*
693 * Resolve the address.
694 */
695 RTNETADDR LocalAddr;
696 int rc = RTSocketParseInetAddress(pszAddress, uPort, &LocalAddr);
697 if (RT_FAILURE(rc))
698 return rc;
699
700 /*
701 * Setting up socket.
702 */
703 RTSOCKET Sock;
704 rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, IPPROTO_UDP, false /*fInheritable*/);
705 if (RT_SUCCESS(rc))
706 {
707 /*
708 * Set socket options.
709 */
710 int fFlag = 1;
711 if (!rtSocketSetOpt(Sock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag)))
712 {
713 /*
714 * Bind a name to the socket.
715 */
716 rc = rtSocketBind(Sock, &LocalAddr);
717 if (RT_SUCCESS(rc))
718 {
719 *pSock = Sock;
720 return VINF_SUCCESS;
721 }
722 }
723 RTSocketClose(Sock);
724 }
725 return rc;
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