From 16f504a9dca3fe3b70568f67b7d41241ae485288 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:49:04 +0200 Subject: Adding upstream version 7.0.6-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/Runtime/r3/udp.cpp | 782 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 782 insertions(+) create mode 100644 src/VBox/Runtime/r3/udp.cpp (limited to 'src/VBox/Runtime/r3/udp.cpp') diff --git a/src/VBox/Runtime/r3/udp.cpp b/src/VBox/Runtime/r3/udp.cpp new file mode 100644 index 00000000..2249aa62 --- /dev/null +++ b/src/VBox/Runtime/r3/udp.cpp @@ -0,0 +1,782 @@ +/* $Id: udp.cpp $ */ +/** @file + * IPRT - UDP/IP. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#ifdef RT_OS_WINDOWS +# include +#else +# include +# include +# include +# include +# include +# include +# include +#endif +#include + +#include "internal/iprt.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal/magics.h" +#include "internal/socket.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/* fixup backlevel OSes. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# define socklen_t int +#endif + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * UDP Server state. + */ +typedef enum RTUDPSERVERSTATE +{ + /** Invalid. */ + RTUDPSERVERSTATE_INVALID = 0, + /** Created. */ + RTUDPSERVERSTATE_CREATED, + /** Thread for incoming datagrams is starting up. */ + RTUDPSERVERSTATE_STARTING, + /** Waiting for incoming datagrams. */ + RTUDPSERVERSTATE_WAITING, + /** Handling an incoming datagram. */ + RTUDPSERVERSTATE_RECEIVING, + /** Thread terminating. */ + RTUDPSERVERSTATE_STOPPING, + /** Thread terminated. */ + RTUDPSERVERSTATE_STOPPED, + /** Final cleanup before being unusable. */ + RTUDPSERVERSTATE_DESTROYING +} RTUDPSERVERSTATE; + +/* + * Internal representation of the UDP Server handle. + */ +typedef struct RTUDPSERVER +{ + /** The magic value (RTUDPSERVER_MAGIC). */ + uint32_t volatile u32Magic; + /** The server state. */ + RTUDPSERVERSTATE volatile enmState; + /** The server thread. */ + RTTHREAD Thread; + /** The server socket. */ + RTSOCKET volatile hSocket; + /** The datagram receiver function. */ + PFNRTUDPSERVE pfnServe; + /** Argument to pfnServer. */ + void *pvUser; +} RTUDPSERVER; + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +static DECLCALLBACK(int) rtUdpServerThread(RTTHREAD ThreadSelf, void *pvServer); +static int rtUdpServerListen(PRTUDPSERVER pServer); +static int rtUdpServerListenCleanup(PRTUDPSERVER pServer); +static int rtUdpServerDestroySocket(RTSOCKET volatile *pSock, const char *pszMsg); +static int rtUdpClose(RTSOCKET Sock, const char *pszMsg); + + +/** + * Atomicly updates a socket variable. + * @returns The old handle value. + * @param phSock The socket handle variable to update. + * @param hNew The new socket handle value. + */ +DECLINLINE(RTSOCKET) rtUdpAtomicXchgSock(RTSOCKET volatile *phSock, const RTSOCKET hNew) +{ + RTSOCKET hRet; + ASMAtomicXchgHandle(phSock, hNew, &hRet); + return hRet; +} + + +/** + * Tries to change the UDP server state. + */ +DECLINLINE(bool) rtUdpServerTrySetState(PRTUDPSERVER pServer, RTUDPSERVERSTATE enmStateNew, RTUDPSERVERSTATE enmStateOld) +{ + bool fRc; + ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc); + return fRc; +} + +/** + * Changes the UDP server state. + */ +DECLINLINE(void) rtUdpServerSetState(PRTUDPSERVER pServer, RTUDPSERVERSTATE enmStateNew, RTUDPSERVERSTATE enmStateOld) +{ + bool fRc; + ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc); + Assert(fRc); NOREF(fRc); +} + + +/** + * Closes a socket. + * + * @returns IPRT status code. + */ +static int rtUdpServerDestroySocket(RTSOCKET volatile *pSock, const char *pszMsg) +{ + RTSOCKET hSocket = rtUdpAtomicXchgSock(pSock, NIL_RTSOCKET); + if (hSocket != NIL_RTSOCKET) + { + return rtUdpClose(hSocket, pszMsg); + } + return VINF_UDP_SERVER_NO_CLIENT; +} + + +/** + * Create single datagram at a time UDP Server in a separate thread. + * + * The thread will loop waiting for datagrams and call pfnServe for + * each of the incoming datagrams in turn. The pfnServe function can + * return VERR_UDP_SERVER_STOP too terminate this loop. RTUdpServerDestroy() + * should be used to terminate the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a datagram socket. + * If NULL or empty string the server is bound to all interfaces. + * @param uPort The port for creating a datagram socket. + * @param enmType The thread type. + * @param pszThrdName The name of the worker thread. + * @param pfnServe The function which will handle incoming datagrams. + * @param pvUser User argument passed to pfnServe. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTUdpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName, + PFNRTUDPSERVE pfnServe, void *pvUser, PPRTUDPSERVER ppServer) +{ + /* + * Validate input. + */ + AssertReturn(uPort > 0, VERR_INVALID_PARAMETER); + AssertPtrReturn(pfnServe, VERR_INVALID_POINTER); + AssertPtrReturn(pszThrdName, VERR_INVALID_POINTER); + AssertPtrReturn(ppServer, VERR_INVALID_POINTER); + + /* + * Create the server. + */ + PRTUDPSERVER pServer; + int rc = RTUdpServerCreateEx(pszAddress, uPort, &pServer); + if (RT_SUCCESS(rc)) + { + /* + * Create the listener thread. + */ + RTMemPoolRetain(pServer); + pServer->enmState = RTUDPSERVERSTATE_STARTING; + pServer->pvUser = pvUser; + pServer->pfnServe = pfnServe; + rc = RTThreadCreate(&pServer->Thread, rtUdpServerThread, pServer, 0, enmType, /*RTTHREADFLAGS_WAITABLE*/0, pszThrdName); + if (RT_SUCCESS(rc)) + { + /* done */ + if (ppServer) + *ppServer = pServer; + else + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + return rc; + } + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + + /* + * Destroy the server. + */ + rtUdpServerSetState(pServer, RTUDPSERVERSTATE_CREATED, RTUDPSERVERSTATE_STARTING); + RTUdpServerDestroy(pServer); + } + + return rc; +} + + +/** + * Server thread, loops waiting for datagrams until it's terminated. + * + * @returns iprt status code. (ignored). + * @param ThreadSelf Thread handle. + * @param pvServer Server handle. + */ +static DECLCALLBACK(int) rtUdpServerThread(RTTHREAD ThreadSelf, void *pvServer) +{ + PRTUDPSERVER pServer = (PRTUDPSERVER)pvServer; + int rc; + if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_STARTING)) + rc = rtUdpServerListen(pServer); + else + rc = rtUdpServerListenCleanup(pServer); + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + NOREF(ThreadSelf); + return VINF_SUCCESS; +} + + +/** + * Create single datagram at a time UDP Server. + * The caller must call RTUdpServerReceive() to actually start the server. + * + * @returns iprt status code. + * @param pszAddress The address for creating a datagram socket. + * If NULL the server is bound to all interfaces. + * @param uPort The port for creating a datagram socket. + * @param ppServer Where to store the serverhandle. + */ +RTR3DECL(int) RTUdpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTUDPSERVER ppServer) +{ + + /* + * Validate input. + */ + AssertReturn(uPort > 0, VERR_INVALID_PARAMETER); + AssertPtrReturn(ppServer, VERR_INVALID_PARAMETER); + + /* + * Resolve the address. + */ + RTNETADDR LocalAddr; + int rc = RTSocketParseInetAddress(pszAddress, uPort, &LocalAddr); + if (RT_FAILURE(rc)) + return rc; + + /* + * Setting up socket. + */ + RTSOCKET Sock; + rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, IPPROTO_UDP, false /*fInheritable*/); + if (RT_SUCCESS(rc)) + { + /* + * Set socket options. + */ + int fFlag = 1; + if (!rtSocketSetOpt(Sock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag))) + { + /* + * Bind a name to the socket. + */ + rc = rtSocketBind(Sock, &LocalAddr); + if (RT_SUCCESS(rc)) + { + /* + * Create the server handle. + */ + PRTUDPSERVER pServer = (PRTUDPSERVER)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pServer)); + if (pServer) + { + pServer->u32Magic = RTUDPSERVER_MAGIC; + pServer->enmState = RTUDPSERVERSTATE_CREATED; + pServer->Thread = NIL_RTTHREAD; + pServer->hSocket = Sock; + pServer->pfnServe = NULL; + pServer->pvUser = NULL; + *ppServer = pServer; + return VINF_SUCCESS; + } + + /* bail out */ + rc = VERR_NO_MEMORY; + } + } + else + AssertMsgFailed(("rtSocketSetOpt: %Rrc\n", rc)); + rtUdpClose(Sock, "RTServerCreateEx"); + } + + return rc; +} + + +/** + * Listen for incoming datagrams. + * + * The function will loop waiting for datagrams and call pfnServe for + * each of the incoming datagrams in turn. The pfnServe function can + * return VERR_UDP_SERVER_STOP too terminate this loop. A stopped server + * can only be destroyed. + * + * @returns IPRT status code. + * @retval VERR_UDP_SERVER_STOP if stopped by pfnServe. + * @retval VERR_UDP_SERVER_SHUTDOWN if shut down by RTUdpServerShutdown. + * + * @param pServer The server handle as returned from RTUdpServerCreateEx(). + * @param pfnServe The function which will handle incoming datagrams. + * @param pvUser User argument passed to pfnServe. + */ +RTR3DECL(int) RTUdpServerListen(PRTUDPSERVER pServer, PFNRTUDPSERVE pfnServe, void *pvUser) +{ + /* + * Validate input and retain the instance. + */ + AssertPtrReturn(pfnServe, VERR_INVALID_POINTER); + AssertPtrReturn(pServer, VERR_INVALID_HANDLE); + AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); + + int rc = VERR_INVALID_STATE; + if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_CREATED)) + { + Assert(!pServer->pfnServe); + Assert(!pServer->pvUser); + Assert(pServer->Thread == NIL_RTTHREAD); + + pServer->pfnServe = pfnServe; + pServer->pvUser = pvUser; + pServer->Thread = RTThreadSelf(); + Assert(pServer->Thread != NIL_RTTHREAD); + rc = rtUdpServerListen(pServer); + } + else + { + AssertMsgFailed(("enmState=%d\n", pServer->enmState)); + rc = VERR_INVALID_STATE; + } + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + return rc; +} + + +/** + * Internal worker common for RTUdpServerListen and the thread created by + * RTUdpServerCreate(). + * + * The caller makes sure it has its own memory reference and releases it upon + * return. + */ +static int rtUdpServerListen(PRTUDPSERVER pServer) +{ + /* + * Wait for incoming datagrams loop. + */ + for (;;) + { + /* + * Change state, getting an extra reference to the socket so we can + * allow others to close it while we're stuck in rtSocketAccept. + */ + RTUDPSERVERSTATE enmState = pServer->enmState; + RTSOCKET hSocket; + ASMAtomicReadHandle(&pServer->hSocket, &hSocket); + if (hSocket != NIL_RTSOCKET) + RTSocketRetain(hSocket); + if ( enmState != RTUDPSERVERSTATE_WAITING + && enmState != RTUDPSERVERSTATE_RECEIVING) + { + RTSocketRelease(hSocket); + return rtUdpServerListenCleanup(pServer); + } + if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, enmState)) + { + RTSocketRelease(hSocket); + continue; + } + + /* + * Wait for incoming datagrams or errors. + */ + uint32_t fEvents; + int rc = RTSocketSelectOneEx(hSocket, RTSOCKET_EVT_READ | RTSOCKET_EVT_ERROR, &fEvents, 1000); + RTSocketRelease(hSocket); + if (rc == VERR_TIMEOUT) + continue; + if (RT_FAILURE(rc)) + { + /* These are typical for what can happen during destruction. */ + if ( rc == VERR_INVALID_HANDLE + || rc == VERR_INVALID_PARAMETER + || rc == VERR_NET_NOT_SOCKET) + return rtUdpServerListenCleanup(pServer); + continue; + } + if (fEvents & RTSOCKET_EVT_ERROR) + return rtUdpServerListenCleanup(pServer); + + /* + * Run a pfnServe callback. + */ + if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_RECEIVING, RTUDPSERVERSTATE_WAITING)) + return rtUdpServerListenCleanup(pServer); + rc = pServer->pfnServe(hSocket, pServer->pvUser); + + /* + * Stop the server? + */ + if (rc == VERR_UDP_SERVER_STOP) + { + if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, RTUDPSERVERSTATE_RECEIVING)) + { + /* + * Reset the server socket and change the state to stopped. After that state change + * we cannot safely access the handle so we'll have to return here. + */ + hSocket = rtUdpAtomicXchgSock(&pServer->hSocket, NIL_RTSOCKET); + rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING); + rtUdpClose(hSocket, "Listener: server stopped"); + } + else + rtUdpServerListenCleanup(pServer); /* ignore rc */ + return rc; + } + } +} + + +/** + * Clean up after listener. + */ +static int rtUdpServerListenCleanup(PRTUDPSERVER pServer) +{ + /* + * Close the server socket. + */ + rtUdpServerDestroySocket(&pServer->hSocket, "ListenCleanup"); + + /* + * Figure the return code and make sure the state is OK. + */ + RTUDPSERVERSTATE enmState = pServer->enmState; + switch (enmState) + { + case RTUDPSERVERSTATE_STOPPING: + case RTUDPSERVERSTATE_STOPPED: + return VERR_UDP_SERVER_SHUTDOWN; + + case RTUDPSERVERSTATE_WAITING: + rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPED, enmState); + return VERR_UDP_SERVER_DESTROYED; + + case RTUDPSERVERSTATE_DESTROYING: + return VERR_UDP_SERVER_DESTROYED; + + case RTUDPSERVERSTATE_STARTING: + case RTUDPSERVERSTATE_RECEIVING: + default: + AssertMsgFailedReturn(("pServer=%p enmState=%d\n", pServer, enmState), VERR_INTERNAL_ERROR_4); + } +} + + +/** + * Shuts down the server. + * + * @returns IPRT status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTUdpServerShutdown(PRTUDPSERVER pServer) +{ + /* + * Validate input and retain the instance. + */ + AssertPtrReturn(pServer, VERR_INVALID_HANDLE); + AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); + + /* + * Try change the state to stopping, then replace and destroy the server socket. + */ + for (;;) + { + RTUDPSERVERSTATE enmState = pServer->enmState; + if ( enmState != RTUDPSERVERSTATE_WAITING + && enmState != RTUDPSERVERSTATE_RECEIVING) + { + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + switch (enmState) + { + case RTUDPSERVERSTATE_CREATED: + case RTUDPSERVERSTATE_STARTING: + default: + AssertMsgFailed(("%d\n", enmState)); + return VERR_INVALID_STATE; + + case RTUDPSERVERSTATE_STOPPING: + case RTUDPSERVERSTATE_STOPPED: + return VINF_SUCCESS; + + case RTUDPSERVERSTATE_DESTROYING: + return VERR_UDP_SERVER_DESTROYED; + } + } + if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, enmState)) + { + rtUdpServerDestroySocket(&pServer->hSocket, "RTUdpServerShutdown"); + rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING); + + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + return VINF_SUCCESS; + } + } +} + + +/** + * Closes down and frees a UDP Server. + * + * @returns iprt status code. + * @param pServer Handle to the server. + */ +RTR3DECL(int) RTUdpServerDestroy(PRTUDPSERVER pServer) +{ + /* + * Validate input and retain the instance. + */ + AssertPtrReturn(pServer, VERR_INVALID_HANDLE); + AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); /* paranoia */ + + /* + * Move the state along so the listener can figure out what's going on. + */ + for (;;) + { + bool fDestroyable; + RTUDPSERVERSTATE enmState = pServer->enmState; + switch (enmState) + { + case RTUDPSERVERSTATE_STARTING: + case RTUDPSERVERSTATE_WAITING: + case RTUDPSERVERSTATE_RECEIVING: + case RTUDPSERVERSTATE_CREATED: + case RTUDPSERVERSTATE_STOPPED: + fDestroyable = rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_DESTROYING, enmState); + break; + + /* destroyable states */ + case RTUDPSERVERSTATE_STOPPING: + fDestroyable = true; + break; + + /* + * Everything else means user or internal misbehavior. + */ + default: + AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState)); + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + return VERR_INTERNAL_ERROR; + } + if (fDestroyable) + break; + } + + /* + * Destroy it. + */ + ASMAtomicWriteU32(&pServer->u32Magic, ~RTUDPSERVER_MAGIC); + rtUdpServerDestroySocket(&pServer->hSocket, "Destroyer: server"); + + /* + * Release it. + */ + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + return VINF_SUCCESS; +} + + +/** + * Internal close function which does all the proper bitching. + */ +static int rtUdpClose(RTSOCKET Sock, const char *pszMsg) +{ + NOREF(pszMsg); /** @todo drop this parameter? */ + + /* ignore nil handles. */ + if (Sock == NIL_RTSOCKET) + return VINF_SUCCESS; + + /* + * Close the socket handle (drops our reference to it). + */ + return RTSocketClose(Sock); +} + + +RTR3DECL(int) RTUdpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr) +{ + if (!RT_VALID_PTR(pcbRead)) + return VERR_INVALID_POINTER; + return RTSocketReadFrom(Sock, pvBuffer, cbBuffer, pcbRead, pSrcAddr); +} + + +RTR3DECL(int) RTUdpWrite(PRTUDPSERVER pServer, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr) +{ + /* + * Validate input and retain the instance. + */ + AssertPtrReturn(pServer, VERR_INVALID_HANDLE); + AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE); + AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); + + RTSOCKET hSocket; + ASMAtomicReadHandle(&pServer->hSocket, &hSocket); + if (hSocket == NIL_RTSOCKET) + { + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + return VERR_INVALID_HANDLE; + } + RTSocketRetain(hSocket); + + int rc = VINF_SUCCESS; + RTUDPSERVERSTATE enmState = pServer->enmState; + if ( enmState != RTUDPSERVERSTATE_CREATED + && enmState != RTUDPSERVERSTATE_STARTING + && enmState != RTUDPSERVERSTATE_WAITING + && enmState != RTUDPSERVERSTATE_RECEIVING + && enmState != RTUDPSERVERSTATE_STOPPING) + rc = VERR_INVALID_STATE; + + if (RT_SUCCESS(rc)) + rc = RTSocketWriteTo(hSocket, pvBuffer, cbBuffer, pDstAddr); + + RTSocketRelease(hSocket); + RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer); + + return rc; +} + + +RTR3DECL(int) RTUdpCreateClientSocket(const char *pszAddress, uint32_t uPort, PRTNETADDR pLocalAddr, PRTSOCKET pSock) +{ + /* + * Validate input. + */ + AssertReturn(uPort > 0, VERR_INVALID_PARAMETER); + AssertPtrReturn(pszAddress, VERR_INVALID_POINTER); + AssertPtrReturn(pSock, VERR_INVALID_POINTER); + + /* + * Resolve the address. + */ + RTNETADDR Addr; + int rc = RTSocketParseInetAddress(pszAddress, uPort, &Addr); + if (RT_FAILURE(rc)) + return rc; + + /* + * Create the socket and connect. + */ + RTSOCKET Sock; + rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, 0, false /*fInheritable*/); + if (RT_SUCCESS(rc)) + { + if (pLocalAddr) + rc = rtSocketBind(Sock, pLocalAddr); + if (RT_SUCCESS(rc)) + { + rc = rtSocketConnect(Sock, &Addr, RT_SOCKETCONNECT_DEFAULT_WAIT); + if (RT_SUCCESS(rc)) + { + *pSock = Sock; + return VINF_SUCCESS; + } + } + RTSocketClose(Sock); + } + return rc; +} + + +RTR3DECL(int) RTUdpCreateServerSocket(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock) +{ + /* + * Validate input. + */ + AssertReturn(uPort > 0, VERR_INVALID_PARAMETER); + AssertPtrReturn(pszAddress, VERR_INVALID_POINTER); + AssertPtrReturn(pSock, VERR_INVALID_POINTER); + + /* + * Resolve the address. + */ + RTNETADDR LocalAddr; + int rc = RTSocketParseInetAddress(pszAddress, uPort, &LocalAddr); + if (RT_FAILURE(rc)) + return rc; + + /* + * Setting up socket. + */ + RTSOCKET Sock; + rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, IPPROTO_UDP, false /*fInheritable*/); + if (RT_SUCCESS(rc)) + { + /* + * Set socket options. + */ + int fFlag = 1; + if (!rtSocketSetOpt(Sock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag))) + { + /* + * Bind a name to the socket. + */ + rc = rtSocketBind(Sock, &LocalAddr); + if (RT_SUCCESS(rc)) + { + *pSock = Sock; + return VINF_SUCCESS; + } + } + RTSocketClose(Sock); + } + return rc; +} -- cgit v1.2.3