VirtualBox

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

Last change on this file since 78395 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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