8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/* $Id$ */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/** @file
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * IPRT - UDP/IP.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2012 Oracle Corporation
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * available from http://www.virtualbox.org. This file is free software;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * you can redistribute it and/or modify it under the terms of the GNU
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * General Public License (GPL) as published by the Free Software
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * The contents of this file may alternatively be used under the terms
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * of the Common Development and Distribution License Version 1.0
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * VirtualBox OSE distribution, in which case the provisions of the
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * CDDL are applicable instead of those of the GPL.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * You may elect to license modified versions of this file under the
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * terms and conditions of either the GPL or the CDDL or both.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/*******************************************************************************
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync* Header Files *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync*******************************************************************************/
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#ifdef RT_OS_WINDOWS
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# include <winsock2.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#else
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# include <sys/types.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# include <sys/socket.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# include <errno.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# include <netinet/in.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# include <netinet/udp.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# include <arpa/inet.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# include <netdb.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#endif
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <limits.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include "internal/iprt.h"
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/udp.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/asm.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/assert.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/err.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/mempool.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/mem.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/string.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/socket.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/thread.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include <iprt/time.h>
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include "internal/magics.h"
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#include "internal/socket.h"
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/*******************************************************************************
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync* Defined Constants And Macros *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync*******************************************************************************/
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/* fixup backlevel OSes. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync# define socklen_t int
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync#endif
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/*******************************************************************************
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync* Structures and Typedefs *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync*******************************************************************************/
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * UDP Server state.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsynctypedef enum RTUDPSERVERSTATE
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Invalid. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE_INVALID = 0,
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Created. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE_CREATED,
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Thread for incoming datagrams is starting up. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE_STARTING,
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Waiting for incoming datagrams. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE_WAITING,
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Handling an incoming datagram. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE_RECEIVING,
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Thread terminating. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE_STOPPING,
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Thread terminated. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE_STOPPED,
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Final cleanup before being unusable. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE_DESTROYING
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync} RTUDPSERVERSTATE;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Internal representation of the UDP Server handle.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsynctypedef struct RTUDPSERVER
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** The magic value (RTUDPSERVER_MAGIC). */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync uint32_t volatile u32Magic;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** The server state. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE volatile enmState;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** The server thread. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTTHREAD Thread;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** The server socket. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSOCKET volatile hSocket;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** The datagram receiver function. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync PFNRTUDPSERVE pfnServe;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /** Argument to pfnServer. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync void *pvUser;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync} RTUDPSERVER;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/*******************************************************************************
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync* Internal Functions *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync*******************************************************************************/
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic DECLCALLBACK(int) rtUdpServerThread(RTTHREAD ThreadSelf, void *pvServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic int rtUdpServerListen(PRTUDPSERVER pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic int rtUdpServerListenCleanup(PRTUDPSERVER pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic int rtUdpServerDestroySocket(RTSOCKET volatile *pSock, const char *pszMsg);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic int rtUdpClose(RTSOCKET Sock, const char *pszMsg);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Atomicly updates a socket variable.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @returns The old handle value.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param phSock The socket handle variable to update.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param hSock The new socket handle value.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncDECLINLINE(RTSOCKET) rtUdpAtomicXchgSock(RTSOCKET volatile *phSock, const RTSOCKET hNew)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSOCKET hRet;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync ASMAtomicXchgHandle(phSock, hNew, &hRet);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return hRet;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Tries to change the UDP server state.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncDECLINLINE(bool) rtUdpServerTrySetState(PRTUDPSERVER pServer, RTUDPSERVERSTATE enmStateNew, RTUDPSERVERSTATE enmStateOld)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync bool fRc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return fRc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Changes the UDP server state.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncDECLINLINE(void) rtUdpServerSetState(PRTUDPSERVER pServer, RTUDPSERVERSTATE enmStateNew, RTUDPSERVERSTATE enmStateOld)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync bool fRc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync ASMAtomicCmpXchgSize(&pServer->enmState, enmStateNew, enmStateOld, fRc);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync Assert(fRc); NOREF(fRc);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Closes a socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @returns IPRT status code.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic int rtUdpServerDestroySocket(RTSOCKET volatile *pSock, const char *pszMsg)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSOCKET hSocket = rtUdpAtomicXchgSock(pSock, NIL_RTSOCKET);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (hSocket != NIL_RTSOCKET)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rtUdpClose(hSocket, pszMsg);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VINF_UDP_SERVER_NO_CLIENT;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Create single datagram at a time UDP Server in a separate thread.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * The thread will loop waiting for datagrams and call pfnServe for
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * each of the incoming datagrams in turn. The pfnServe function can
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * return VERR_UDP_SERVER_STOP too terminate this loop. RTUdpServerDestroy()
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * should be used to terminate the server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @returns iprt status code.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pszAddress The address for creating a datagram socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * If NULL or empty string the server is bound to all interfaces.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param uPort The port for creating a datagram socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param enmType The thread type.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pszThrdName The name of the worker thread.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pfnServe The function which will handle incoming datagrams.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pvUser User argument passed to pfnServe.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param ppServer Where to store the serverhandle.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncRTR3DECL(int) RTUdpServerCreate(const char *pszAddress, unsigned uPort, RTTHREADTYPE enmType, const char *pszThrdName,
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync PFNRTUDPSERVE pfnServe, void *pvUser, PPRTUDPSERVER ppServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Validate input.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(pszThrdName, VERR_INVALID_POINTER);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(ppServer, VERR_INVALID_POINTER);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Create the server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync PRTUDPSERVER pServer;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync int rc = RTUdpServerCreateEx(pszAddress, uPort, &pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (RT_SUCCESS(rc))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Create the listener thread.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRetain(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->enmState = RTUDPSERVERSTATE_STARTING;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->pvUser = pvUser;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->pfnServe = pfnServe;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = RTThreadCreate(&pServer->Thread, rtUdpServerThread, pServer, 0, enmType, /*RTTHREADFLAGS_WAITABLE*/0, pszThrdName);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (RT_SUCCESS(rc))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /* done */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (ppServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *ppServer = pServer;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync else
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Destroy the server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpServerSetState(pServer, RTUDPSERVERSTATE_CREATED, RTUDPSERVERSTATE_STARTING);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUdpServerDestroy(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Server thread, loops waiting for datagrams until it's terminated.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @returns iprt status code. (ignored).
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param ThreadSelf Thread handle.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pvServer Server handle.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic DECLCALLBACK(int) rtUdpServerThread(RTTHREAD ThreadSelf, void *pvServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync PRTUDPSERVER pServer = (PRTUDPSERVER)pvServer;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync int rc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_STARTING))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = rtUdpServerListen(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync else
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = rtUdpServerListenCleanup(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync NOREF(ThreadSelf);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VINF_SUCCESS;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Create single datagram at a time UDP Server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * The caller must call RTUdpServerReceive() to actually start the server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @returns iprt status code.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pszAddress The address for creating a datagram socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * If NULL the server is bound to all interfaces.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param uPort The port for creating a datagram socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param ppServer Where to store the serverhandle.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncRTR3DECL(int) RTUdpServerCreateEx(const char *pszAddress, uint32_t uPort, PPRTUDPSERVER ppServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Validate input.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(ppServer, VERR_INVALID_PARAMETER);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
280173a9a1d01b33c087a762ffb9e522efe5c0d5vboxsync * Resolve the address.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
280173a9a1d01b33c087a762ffb9e522efe5c0d5vboxsync RTNETADDR LocalAddr;
280173a9a1d01b33c087a762ffb9e522efe5c0d5vboxsync int rc = RTSocketParseInetAddress(pszAddress, uPort, &LocalAddr);
280173a9a1d01b33c087a762ffb9e522efe5c0d5vboxsync if (RT_FAILURE(rc))
280173a9a1d01b33c087a762ffb9e522efe5c0d5vboxsync return rc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Setting up socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSOCKET Sock;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = rtSocketCreate(&Sock, AF_INET, SOCK_DGRAM, IPPROTO_UDP);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (RT_SUCCESS(rc))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSocketSetInheritance(Sock, false /*fInheritable*/);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Set socket options.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync int fFlag = 1;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (!rtSocketSetOpt(Sock, SOL_SOCKET, SO_REUSEADDR, &fFlag, sizeof(fFlag)))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Bind a name to the socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
280173a9a1d01b33c087a762ffb9e522efe5c0d5vboxsync rc = rtSocketBind(Sock, &LocalAddr);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (RT_SUCCESS(rc))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Create the server handle.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync PRTUDPSERVER pServer = (PRTUDPSERVER)RTMemPoolAlloc(RTMEMPOOL_DEFAULT, sizeof(*pServer));
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (pServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->u32Magic = RTUDPSERVER_MAGIC;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->enmState = RTUDPSERVERSTATE_CREATED;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->Thread = NIL_RTTHREAD;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->hSocket = Sock;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->pfnServe = NULL;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->pvUser = NULL;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *ppServer = pServer;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VINF_SUCCESS;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /* bail out */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = VERR_NO_MEMORY;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync else
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertMsgFailed(("rtSocketSetOpt: %Rrc\n", rc));
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpClose(Sock, "RTServerCreateEx");
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Listen for incoming datagrams.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * The function will loop waiting for datagrams and call pfnServe for
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * each of the incoming datagrams in turn. The pfnServe function can
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * return VERR_UDP_SERVER_STOP too terminate this loop. A stopped server
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * can only be destroyed.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @returns IPRT status code.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @retval VERR_UDP_SERVER_STOP if stopped by pfnServe.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @retval VERR_UDP_SERVER_SHUTDOWN if shut down by RTUdpServerShutdown.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pServer The server handle as returned from RTUdpServerCreateEx().
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pfnServe The function which will handle incoming datagrams.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pvUser User argument passed to pfnServe.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncRTR3DECL(int) RTUdpServerListen(PRTUDPSERVER pServer, PFNRTUDPSERVE pfnServe, void *pvUser)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Validate input and retain the instance.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(pfnServe, VERR_INVALID_POINTER);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync int rc = VERR_INVALID_STATE;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, RTUDPSERVERSTATE_CREATED))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync Assert(!pServer->pfnServe);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync Assert(!pServer->pvUser);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync Assert(pServer->Thread == NIL_RTTHREAD);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->pfnServe = pfnServe;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->pvUser = pvUser;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync pServer->Thread = RTThreadSelf();
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync Assert(pServer->Thread != NIL_RTTHREAD);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = rtUdpServerListen(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync else
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertMsgFailed(("enmState=%d\n", pServer->enmState));
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = VERR_INVALID_STATE;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Internal worker common for RTUdpServerListen and the thread created by
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * RTUdpServerCreate().
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * The caller makes sure it has its own memory reference and releases it upon
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * return.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic int rtUdpServerListen(PRTUDPSERVER pServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Wait for incoming datagrams loop.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync for (;;)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Change state, getting an extra reference to the socket so we can
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * allow others to close it while we're stuck in rtSocketAccept.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE enmState = pServer->enmState;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSOCKET hSocket;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync ASMAtomicReadHandle(&pServer->hSocket, &hSocket);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (hSocket != NIL_RTSOCKET)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSocketRetain(hSocket);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if ( enmState != RTUDPSERVERSTATE_WAITING
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync && enmState != RTUDPSERVERSTATE_RECEIVING)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSocketRelease(hSocket);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rtUdpServerListenCleanup(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_WAITING, enmState))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSocketRelease(hSocket);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync continue;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Wait for incoming datagrams or errors.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync uint32_t fEvents;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync int rc = RTSocketSelectOneEx(hSocket, RTSOCKET_EVT_READ | RTSOCKET_EVT_ERROR, &fEvents, 1000);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSocketRelease(hSocket);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (rc == VERR_TIMEOUT)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync continue;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (RT_FAILURE(rc))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /* These are typical for what can happen during destruction. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if ( rc == VERR_INVALID_HANDLE
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync || rc == VERR_INVALID_PARAMETER
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync || rc == VERR_NET_NOT_SOCKET)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rtUdpServerListenCleanup(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync continue;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (fEvents & RTSOCKET_EVT_ERROR)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rtUdpServerListenCleanup(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Run a pfnServe callback.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (!rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_RECEIVING, RTUDPSERVERSTATE_WAITING))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rtUdpServerListenCleanup(pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = pServer->pfnServe(hSocket, pServer->pvUser);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Stop the server?
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (rc == VERR_UDP_SERVER_STOP)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, RTUDPSERVERSTATE_RECEIVING))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Reset the server socket and change the state to stopped. After that state change
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * we cannot safely access the handle so we'll have to return here.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync hSocket = rtUdpAtomicXchgSock(&pServer->hSocket, NIL_RTSOCKET);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpClose(hSocket, "Listener: server stopped");
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync else
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpServerListenCleanup(pServer); /* ignore rc */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Clean up after listener.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic int rtUdpServerListenCleanup(PRTUDPSERVER pServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Close the server socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpServerDestroySocket(&pServer->hSocket, "ListenCleanup");
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Figure the return code and make sure the state is OK.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE enmState = pServer->enmState;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync switch (enmState)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STOPPING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STOPPED:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VERR_UDP_SERVER_SHUTDOWN;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_WAITING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPED, enmState);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VERR_UDP_SERVER_DESTROYED;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_DESTROYING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VERR_UDP_SERVER_DESTROYED;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STARTING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_RECEIVING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync default:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertMsgFailedReturn(("pServer=%p enmState=%d\n", pServer, enmState), VERR_INTERNAL_ERROR_4);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Shuts down the server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @returns IPRT status code.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pServer Handle to the server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncRTR3DECL(int) RTUdpServerShutdown(PRTUDPSERVER pServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Validate input and retain the instance.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Try change the state to stopping, then replace and destroy the server socket.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync for (;;)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE enmState = pServer->enmState;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if ( enmState != RTUDPSERVERSTATE_WAITING
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync && enmState != RTUDPSERVERSTATE_RECEIVING)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync switch (enmState)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_CREATED:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STARTING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync default:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertMsgFailed(("%d\n", enmState));
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VERR_INVALID_STATE;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STOPPING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STOPPED:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VINF_SUCCESS;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_DESTROYING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VERR_UDP_SERVER_DESTROYED;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_STOPPING, enmState))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpServerDestroySocket(&pServer->hSocket, "RTUdpServerShutdown");
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpServerSetState(pServer, RTUDPSERVERSTATE_STOPPED, RTUDPSERVERSTATE_STOPPING);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VINF_SUCCESS;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Closes down and frees a UDP Server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync *
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @returns iprt status code.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * @param pServer Handle to the server.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncRTR3DECL(int) RTUdpServerDestroy(PRTUDPSERVER pServer)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Validate input and retain the instance.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE); /* paranoia */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Move the state along so the listener can figure out what's going on.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync for (;;)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync bool fDestroyable;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE enmState = pServer->enmState;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync switch (enmState)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STARTING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_WAITING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_RECEIVING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_CREATED:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STOPPED:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync fDestroyable = rtUdpServerTrySetState(pServer, RTUDPSERVERSTATE_DESTROYING, enmState);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync break;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /* destroyable states */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync case RTUDPSERVERSTATE_STOPPING:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync fDestroyable = true;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync break;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Everything else means user or internal misbehavior.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync default:
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertMsgFailed(("pServer=%p enmState=%d\n", pServer, enmState));
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VERR_INTERNAL_ERROR;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (fDestroyable)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync break;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Destroy it.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync ASMAtomicWriteU32(&pServer->u32Magic, ~RTUDPSERVER_MAGIC);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rtUdpServerDestroySocket(&pServer->hSocket, "Destroyer: server");
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Release it.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VINF_SUCCESS;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync/**
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Internal close function which does all the proper bitching.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncstatic int rtUdpClose(RTSOCKET Sock, const char *pszMsg)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsync NOREF(pszMsg); /** @todo drop this parameter? */
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /* ignore nil handles. */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (Sock == NIL_RTSOCKET)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VINF_SUCCESS;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Close the socket handle (drops our reference to it).
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return RTSocketClose(Sock);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncRTR3DECL(int) RTUdpRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (!RT_VALID_PTR(pcbRead))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VERR_INVALID_POINTER;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return RTSocketReadFrom(Sock, pvBuffer, cbBuffer, pcbRead, pSrcAddr);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsyncRTR3DECL(int) RTUdpWrite(PRTUDPSERVER pServer, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pDstAddr)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync{
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync /*
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync * Validate input and retain the instance.
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync */
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertPtrReturn(pServer, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(pServer->u32Magic == RTUDPSERVER_MAGIC, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync AssertReturn(RTMemPoolRetain(pServer) != UINT32_MAX, VERR_INVALID_HANDLE);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSOCKET hSocket;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync ASMAtomicReadHandle(&pServer->hSocket, &hSocket);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (hSocket == NIL_RTSOCKET)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync {
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return VERR_INVALID_HANDLE;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync }
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSocketRetain(hSocket);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync int rc = VINF_SUCCESS;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTUDPSERVERSTATE enmState = pServer->enmState;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if ( enmState != RTUDPSERVERSTATE_CREATED
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync && enmState != RTUDPSERVERSTATE_STARTING
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync && enmState != RTUDPSERVERSTATE_WAITING
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync && enmState != RTUDPSERVERSTATE_RECEIVING
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync && enmState != RTUDPSERVERSTATE_STOPPING)
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = VERR_INVALID_STATE;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync if (RT_SUCCESS(rc))
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync rc = RTSocketWriteTo(hSocket, pvBuffer, cbBuffer, pDstAddr);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTSocketRelease(hSocket);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync RTMemPoolRelease(RTMEMPOOL_DEFAULT, pServer);
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync return rc;
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync}
8c48cf39dfb84c1f26e0e7fbd1c407e25a34eef1vboxsync