예제 #1
0
파일: UdpServer.cs 프로젝트: rmc00/gsf
        /// <summary>
        /// Starts the <see cref="UdpServer"/> synchronously and begins accepting client connections asynchronously.
        /// </summary>
        /// <exception cref="InvalidOperationException">Attempt is made to <see cref="Start()"/> the <see cref="UdpServer"/> when it is running.</exception>
        public override void Start()
        {
            if (CurrentState == ServerState.NotRunning)
            {
                int maxSendQueueSize;

                // Initialize if unitialized
                if (!Initialized)
                    Initialize();

                // Overwrite config file if max send queue size exists in connection string.
                if (m_configData.ContainsKey("maxSendQueueSize") && int.TryParse(m_configData["maxSendQueueSize"], out maxSendQueueSize))
                    m_maxSendQueueSize = maxSendQueueSize;

                // Bind server socket to local end-point
                m_udpServer = new TransportProvider<Socket>();
                m_udpServer.SetReceiveBuffer(ReceiveBufferSize);
                m_udpServer.Provider = Transport.CreateSocket(m_configData["interface"], int.Parse(m_configData["port"]), ProtocolType.Udp, m_ipStack, m_allowDualStackSocket);

                // Disable SocketError.ConnectionReset exception from being thrown when the endpoint is not listening
                m_udpServer.Provider.IOControl(SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);

                // Notify that the server has been started successfully
                OnServerStarted();

                if ((object)m_udpServer.Provider.LocalEndPoint != null)
                {
                    m_receiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction();
                    m_receiveArgs.SocketFlags = SocketFlags.None;
                    m_receiveArgs.Completed += m_receiveHandler;
                    ReceivePayloadAsync(m_receiveArgs);
                }

                // We process the static list to clients.
                foreach (string clientString in m_configData["clients"].Replace(" ", "").Split(','))
                {
                    try
                    {
                        Match endpoint = Regex.Match(clientString, Transport.EndpointFormatRegex);

                        if (endpoint != Match.Empty)
                        {
                            UdpClientInfo clientInfo;
                            TransportProvider<EndPoint> udpClient = new TransportProvider<EndPoint>();
                            IPEndPoint clientEndpoint = Transport.CreateEndPoint(endpoint.Groups["host"].Value, int.Parse(endpoint.Groups["port"].Value), m_ipStack);

                            udpClient.SetReceiveBuffer(ReceiveBufferSize);
                            udpClient.SetSendBuffer(SendBufferSize);
                            udpClient.Provider = clientEndpoint;

                            // If the IP specified for the client is a multicast IP, subscribe to the specified multicast group.
                            if (Transport.IsMulticastIP(clientEndpoint.Address))
                            {
                                string multicastSource;

                                if (m_configData.TryGetValue("multicastSource", out multicastSource))
                                {
                                    IPAddress sourceAddress = IPAddress.Parse(multicastSource);
                                    IPAddress localAddress = (clientEndpoint.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any);

                                    if (sourceAddress.AddressFamily != clientEndpoint.AddressFamily)
                                        throw new InvalidOperationException(string.Format("Source address \"{0}\" is not in the same IP format as server address \"{1}\"", sourceAddress, clientEndpoint.Address));

                                    if (localAddress.AddressFamily != clientEndpoint.AddressFamily)
                                        throw new InvalidOperationException(string.Format("Local address \"{0}\" is not in the same IP format as server address \"{1}\"", localAddress, clientEndpoint.Address));

                                    MemoryStream membershipAddresses = new MemoryStream();

                                    byte[] serverAddressBytes = clientEndpoint.Address.GetAddressBytes();
                                    byte[] sourceAddressBytes = sourceAddress.GetAddressBytes();
                                    byte[] localAddressBytes = localAddress.GetAddressBytes();

                                    membershipAddresses.Write(serverAddressBytes, 0, serverAddressBytes.Length);
                                    membershipAddresses.Write(sourceAddressBytes, 0, sourceAddressBytes.Length);
                                    membershipAddresses.Write(localAddressBytes, 0, localAddressBytes.Length);

                                    udpClient.MulticastMembershipAddresses = membershipAddresses.ToArray();

                                    // Execute multicast subscribe for specific source
                                    SocketOptionLevel level = clientEndpoint.AddressFamily == AddressFamily.InterNetworkV6 ? SocketOptionLevel.IPv6 : SocketOptionLevel.IP;
                                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.AddSourceMembership, udpClient.MulticastMembershipAddresses);
                                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.MulticastTimeToLive, int.Parse(m_configData["multicastTimeToLive"]));
                                }
                                else
                                {
                                    // Execute multicast subscribe for any source
                                    SocketOptionLevel level = clientEndpoint.AddressFamily == AddressFamily.InterNetworkV6 ? SocketOptionLevel.IPv6 : SocketOptionLevel.IP;
                                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.AddMembership, new MulticastOption(clientEndpoint.Address));
                                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.MulticastTimeToLive, int.Parse(m_configData["multicastTimeToLive"]));
                                }
                            }

                            clientInfo = new UdpClientInfo()
                            {
                                Client = udpClient,
                                SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(),
                                SendLock = new SpinLock(),
                                SendQueue = new ConcurrentQueue<UdpServerPayload>()
                            };

                            clientInfo.SendArgs.RemoteEndPoint = udpClient.Provider;
                            clientInfo.SendArgs.SetBuffer(udpClient.SendBuffer, 0, udpClient.SendBufferSize);
                            clientInfo.SendArgs.Completed += m_sendHandler;

                            m_clientInfoLookup.TryAdd(udpClient.ID, clientInfo);
                            OnClientConnected(udpClient.ID);
                        }
                    }
                    catch (Exception ex)
                    {
                        string errorMessage = string.Format("Unable to connect to client {0}: {1}", clientString, ex.Message);
                        OnClientConnectingException(new Exception(errorMessage, ex));
                    }
                }
            }
            else
            {
                throw new InvalidOperationException("Server is currently running");
            }
        }
예제 #2
0
        private TransportProvider<EndPoint> AddUdpClient(EndPoint udpClientEndPoint)
        {
            TransportProvider<EndPoint> udpClient = new TransportProvider<EndPoint>();
            IPEndPoint udpClientIPEndPoint = udpClientEndPoint as IPEndPoint;
            UdpClientInfo udpClientInfo;

            // Set up client
            udpClient.SetReceiveBuffer(ReceiveBufferSize);
            udpClient.SetSendBuffer(SendBufferSize);
            udpClient.Provider = udpClientIPEndPoint;

            // If the IP specified for the client is a multicast IP, subscribe to the specified multicast group.
            if ((object)udpClientIPEndPoint != null && Transport.IsMulticastIP(udpClientIPEndPoint.Address))
            {
                SocketOptionLevel level = udpClientIPEndPoint.AddressFamily == AddressFamily.InterNetworkV6 ? SocketOptionLevel.IPv6 : SocketOptionLevel.IP;
                string multicastSource;

                if (m_configData.TryGetValue("multicastSource", out multicastSource))
                {
                    IPAddress sourceAddress = IPAddress.Parse(multicastSource);
                    IPAddress localAddress = (udpClientIPEndPoint.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any);

                    if (sourceAddress.AddressFamily != udpClientIPEndPoint.AddressFamily)
                        throw new InvalidOperationException($"Source address \"{sourceAddress}\" is not in the same IP format as server address \"{udpClientIPEndPoint.Address}\"");

                    if (localAddress.AddressFamily != udpClientIPEndPoint.AddressFamily)
                        throw new InvalidOperationException($"Local address \"{localAddress}\" is not in the same IP format as server address \"{udpClientIPEndPoint.Address}\"");

                    using (BlockAllocatedMemoryStream membershipAddresses = new BlockAllocatedMemoryStream())
                    {
                        byte[] serverAddressBytes = udpClientIPEndPoint.Address.GetAddressBytes();
                        byte[] sourceAddressBytes = sourceAddress.GetAddressBytes();
                        byte[] localAddressBytes = localAddress.GetAddressBytes();

                        membershipAddresses.Write(serverAddressBytes, 0, serverAddressBytes.Length);
                        membershipAddresses.Write(sourceAddressBytes, 0, sourceAddressBytes.Length);
                        membershipAddresses.Write(localAddressBytes, 0, localAddressBytes.Length);

                        udpClient.MulticastMembershipAddresses = membershipAddresses.ToArray();
                    }

                    // Execute multicast subscribe for specific source
                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.AddSourceMembership, udpClient.MulticastMembershipAddresses);
                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.MulticastTimeToLive, int.Parse(m_configData["multicastTimeToLive"]));
                }
                else
                {
                    // Execute multicast subscribe for any source
                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.AddMembership, new MulticastOption(udpClientIPEndPoint.Address));
                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.MulticastTimeToLive, int.Parse(m_configData["multicastTimeToLive"]));
                }
            }

            // Create client info object
            udpClientInfo = new UdpClientInfo
            {
                Client = udpClient,
                SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(),
                SendLock = new object(),
                SendQueue = new ConcurrentQueue<UdpServerPayload>()
            };

            udpClientInfo.DumpPayloadsOperation = new ShortSynchronizedOperation(() =>
            {
                UdpServerPayload payload;

                // Check to see if the client has reached the maximum send queue size.
                if (m_maxSendQueueSize > 0 && udpClientInfo.SendQueue.Count >= m_maxSendQueueSize)
                {
                    for (int i = 0; i < m_maxSendQueueSize; i++)
                    {
                        if (udpClientInfo.SendQueue.TryDequeue(out payload))
                        {
                            payload.WaitHandle.Set();
                            payload.WaitHandle.Dispose();
                            payload.WaitHandle = null;
                        }
                    }

                    throw new InvalidOperationException($"Client {udpClientInfo.Client.ID} connected to UDP server reached maximum send queue size. {m_maxSendQueueSize} payloads dumped from the queue.");
                }
            }, ex => OnSendClientDataException(udpClientInfo.Client.ID, ex));

            // Set up SocketAsyncEventArgs
            udpClientInfo.SendArgs.RemoteEndPoint = udpClient.Provider;
            udpClientInfo.SendArgs.SetBuffer(udpClient.SendBuffer, 0, udpClient.SendBufferSize);
            udpClientInfo.SendArgs.Completed += m_sendHandler;

            // Add new client to the lookup
            m_clientInfoLookup.TryAdd(udpClient.ID, udpClientInfo);
            OnClientConnected(udpClient.ID);

            return udpClient;
        }
예제 #3
0
파일: TcpServer.cs 프로젝트: rmc00/gsf
        /// <summary>
        /// Callback method for asynchronous accept operation.
        /// </summary>
        private void ProcessAccept(SocketAsyncEventArgs acceptArgs)
        {
            TransportProvider<Socket> client = new TransportProvider<Socket>();
            SocketAsyncEventArgs receiveArgs = null;
            WindowsPrincipal clientPrincipal = null;
            TcpClientInfo clientInfo;

            try
            {
                if (CurrentState == ServerState.NotRunning)
                    return;

                // If acceptArgs was disposed, m_acceptArgs will either
                // be null or another instance of SocketAsyncEventArgs.
                // This check will tell us whether it's been disposed.
                if ((object)acceptArgs != m_acceptArgs)
                    return;

                if (acceptArgs.SocketError != SocketError.Success)
                {
                    // Error is unrecoverable.
                    // We need to make sure to restart the
                    // server before we throw the error.
                    SocketError error = acceptArgs.SocketError;
                    ThreadPool.QueueUserWorkItem(state => ReStart());
                    throw new SocketException((int)error);
                }

                // Process the newly connected client.
                client.Provider = acceptArgs.AcceptSocket;
                client.Provider.ReceiveBufferSize = ReceiveBufferSize;

                // Set up SocketAsyncEventArgs for receive operations.
                receiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction();
                receiveArgs.Completed += ReceiveHandler;

                // Return to accepting new connections.
                acceptArgs.AcceptSocket = null;

                if (!m_tcpServer.AcceptAsync(acceptArgs))
                {
                    ThreadPool.QueueUserWorkItem(state => ProcessAccept(acceptArgs));
                }

#if !MONO
                // Authenticate the connected client Windows credentials.
                if (m_integratedSecurity)
                {
                    NetworkStream socketStream = null;
                    NegotiateStream authenticationStream = null;
                    try
                    {
                        socketStream = new NetworkStream(client.Provider);
                        authenticationStream = new NegotiateStream(socketStream);
                        authenticationStream.AuthenticateAsServer();

                        if (authenticationStream.RemoteIdentity is WindowsIdentity)
                            clientPrincipal = new WindowsPrincipal((WindowsIdentity)authenticationStream.RemoteIdentity);
                    }
                    catch (InvalidCredentialException)
                    {
                        if (!m_ignoreInvalidCredentials)
                            throw;
                    }
                    finally
                    {
                        if (socketStream != null)
                            socketStream.Dispose();

                        if (authenticationStream != null)
                            authenticationStream.Dispose();
                    }
                }
#endif

                if (MaxClientConnections != -1 && ClientIDs.Length >= MaxClientConnections)
                {
                    // Reject client connection since limit has been reached.
                    TerminateConnection(client, receiveArgs, false);
                }
                else
                {
                    // We can proceed further with receiving data from the client.
                    clientInfo = new TcpClientInfo
                    {
                        Client = client,
                        SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(),
                        SendLock = new object(),
                        SendQueue = new ConcurrentQueue<TcpServerPayload>(),
                        ClientPrincipal = clientPrincipal
                    };

                    // Create operation to dump send queue payloads when the queue grows too large.
                    clientInfo.DumpPayloadsOperation = new ShortSynchronizedOperation(() =>
                    {
                        TcpServerPayload payload;

                        // Check to see if the client has reached the maximum send queue size.
                        if (m_maxSendQueueSize > 0 && clientInfo.SendQueue.Count >= m_maxSendQueueSize)
                        {
                            for (int i = 0; i < m_maxSendQueueSize; i++)
                            {
                                if (clientInfo.SendQueue.TryDequeue(out payload))
                                {
                                    payload.WaitHandle.Set();
                                    payload.WaitHandle.Dispose();
                                    payload.WaitHandle = null;
                                }
                            }

                            throw new InvalidOperationException(string.Format("Client {0} connected to TCP server reached maximum send queue size. {1} payloads dumped from the queue.", clientInfo.Client.ID, m_maxSendQueueSize));
                        }
                    }, ex => OnSendClientDataException(clientInfo.Client.ID, ex));

                    // Set up socket args.
                    client.SetSendBuffer(SendBufferSize);
                    clientInfo.SendArgs.Completed += m_sendHandler;
                    clientInfo.SendArgs.SetBuffer(client.SendBuffer, 0, client.SendBufferSize);

                    m_clientInfoLookup.TryAdd(client.ID, clientInfo);

                    OnClientConnected(client.ID);

                    if (!m_payloadAware)
                    {
                        receiveArgs.UserToken = client;
                    }
                    else
                    {
                        EventArgs<TransportProvider<Socket>, bool> userToken = FastObjectFactory<EventArgs<TransportProvider<Socket>, bool>>.CreateObjectFunction();
                        userToken.Argument1 = client;
                        receiveArgs.UserToken = userToken;
                    }

                    ReceivePayloadAsync(client, receiveArgs);
                }
            }
            catch (ObjectDisposedException)
            {
                // m_acceptArgs may be disposed while in the middle of accepting a connection
            }
            catch (Exception ex)
            {
                // Notify of the exception.
                if ((object)client.Provider != null && (object)client.Provider.RemoteEndPoint != null)
                {
                    string clientAddress = ((IPEndPoint)client.Provider.RemoteEndPoint).Address.ToString();
                    string errorMessage = string.Format("Unable to accept connection to client [{0}]: {1}", clientAddress, ex.Message);
                    OnClientConnectingException(new Exception(errorMessage, ex));
                }
                else
                {
                    string errorMessage = string.Format("Unable to accept connection to client [unknown]: {0}", ex.Message);
                    OnClientConnectingException(new Exception(errorMessage, ex));
                }

                if ((object)receiveArgs != null)
                {
                    TerminateConnection(client, receiveArgs, false);
                }
            }
        }
예제 #4
0
파일: TcpServer.cs 프로젝트: rmc00/gsf
        /// <summary>
        /// Callback method for asynchronous accept operation.
        /// </summary>
        private void ProcessAccept()
        {
            TransportProvider<Socket> client = new TransportProvider<Socket>();
            SocketAsyncEventArgs receiveArgs = null;
            TcpClientInfo clientInfo;

            try
            {
                if (CurrentState == ServerState.NotRunning)
                    return;

                if (m_acceptArgs.SocketError != SocketError.Success)
                {
                    // Error is unrecoverable.
                    // We need to make sure to restart the
                    // server before we throw the error.
                    SocketError error = m_acceptArgs.SocketError;
                    ThreadPool.QueueUserWorkItem(state => ReStart());
                    throw new SocketException((int)error);
                }

                // Process the newly connected client.
                client.Provider = m_acceptArgs.AcceptSocket;

                // Set up SocketAsyncEventArgs for receive operations.
                receiveArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction();
                receiveArgs.Completed += ReceiveHandler;

                // Return to accepting new connections.
                m_acceptArgs.AcceptSocket = null;

                if (!m_tcpServer.AcceptAsync(m_acceptArgs))
                {
                    ThreadPool.QueueUserWorkItem(state => ProcessAccept());
                }

#if !MONO
                // Authenticate the connected client Windows credentials.
                if (m_integratedSecurity)
                {
                    NetworkStream socketStream = null;
                    NegotiateStream authenticationStream = null;
                    try
                    {
                        socketStream = new NetworkStream(client.Provider);
                        authenticationStream = new NegotiateStream(socketStream);
                        authenticationStream.AuthenticateAsServer();

                        if (authenticationStream.RemoteIdentity is WindowsIdentity)
                            Thread.CurrentPrincipal = new WindowsPrincipal((WindowsIdentity)authenticationStream.RemoteIdentity);
                    }
                    finally
                    {
                        if (socketStream != null)
                            socketStream.Dispose();

                        if (authenticationStream != null)
                            authenticationStream.Dispose();
                    }
                }
#endif

                if (MaxClientConnections != -1 && ClientIDs.Length >= MaxClientConnections)
                {
                    // Reject client connection since limit has been reached.
                    TerminateConnection(client, receiveArgs, false);
                }
                else
                {
                    // We can proceed further with receiving data from the client.
                    clientInfo = new TcpClientInfo()
                    {
                        Client = client,
                        SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(),
                        SendLock = new SpinLock(),
                        SendQueue = new ConcurrentQueue<TcpServerPayload>()
                    };

                    // Set up socket args.
                    client.SetSendBuffer(SendBufferSize);
                    clientInfo.SendArgs.Completed += m_sendHandler;
                    clientInfo.SendArgs.SetBuffer(client.SendBuffer, 0, client.SendBufferSize);

                    m_clientInfoLookup.TryAdd(client.ID, clientInfo);

                    OnClientConnected(client.ID);

                    if (!m_payloadAware)
                    {
                        receiveArgs.UserToken = client;
                    }
                    else
                    {
                        EventArgs<TransportProvider<Socket>, bool> userToken = ReusableObjectPool<EventArgs<TransportProvider<Socket>, bool>>.Default.TakeObject();
                        userToken.Argument1 = client;
                        receiveArgs.UserToken = userToken;
                    }

                    ReceivePayloadAsync(client, receiveArgs);
                }
            }
            catch (Exception ex)
            {
                // Notify of the exception.
                if ((object)client.Provider != null)
                {
                    string clientAddress = ((IPEndPoint)client.Provider.RemoteEndPoint).Address.ToString();
                    string errorMessage = string.Format("Unable to accept connection to client [{0}]: {1}", clientAddress, ex.Message);
                    OnClientConnectingException(new Exception(errorMessage, ex));
                }

                if ((object)receiveArgs != null)
                {
                    TerminateConnection(client, receiveArgs, false);
                }
            }
        }
예제 #5
0
파일: UdpServer.cs 프로젝트: avs009/gsf
        private TransportProvider<EndPoint> AddUdpClient(EndPoint udpClientEndPoint)
        {
            TransportProvider<EndPoint> udpClient = new TransportProvider<EndPoint>();
            IPEndPoint udpClientIPEndPoint = udpClientEndPoint as IPEndPoint;
            UdpClientInfo udpClientInfo;

            // Set up client
            udpClient.SetReceiveBuffer(ReceiveBufferSize);
            udpClient.SetSendBuffer(SendBufferSize);
            udpClient.Provider = udpClientIPEndPoint;

            // If the IP specified for the client is a multicast IP, subscribe to the specified multicast group.
            if ((object)udpClientIPEndPoint != null && Transport.IsMulticastIP(udpClientIPEndPoint.Address))
            {
                SocketOptionLevel level = udpClientIPEndPoint.AddressFamily == AddressFamily.InterNetworkV6 ? SocketOptionLevel.IPv6 : SocketOptionLevel.IP;
                string multicastSource;

                if (m_configData.TryGetValue("multicastSource", out multicastSource))
                {
                    IPAddress sourceAddress = IPAddress.Parse(multicastSource);
                    IPAddress localAddress = (udpClientIPEndPoint.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any);

                    if (sourceAddress.AddressFamily != udpClientIPEndPoint.AddressFamily)
                        throw new InvalidOperationException(string.Format("Source address \"{0}\" is not in the same IP format as server address \"{1}\"", sourceAddress, udpClientIPEndPoint.Address));

                    if (localAddress.AddressFamily != udpClientIPEndPoint.AddressFamily)
                        throw new InvalidOperationException(string.Format("Local address \"{0}\" is not in the same IP format as server address \"{1}\"", localAddress, udpClientIPEndPoint.Address));

                    MemoryStream membershipAddresses = new MemoryStream();

                    byte[] serverAddressBytes = udpClientIPEndPoint.Address.GetAddressBytes();
                    byte[] sourceAddressBytes = sourceAddress.GetAddressBytes();
                    byte[] localAddressBytes = localAddress.GetAddressBytes();

                    membershipAddresses.Write(serverAddressBytes, 0, serverAddressBytes.Length);
                    membershipAddresses.Write(sourceAddressBytes, 0, sourceAddressBytes.Length);
                    membershipAddresses.Write(localAddressBytes, 0, localAddressBytes.Length);

                    udpClient.MulticastMembershipAddresses = membershipAddresses.ToArray();

                    // Execute multicast subscribe for specific source
                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.AddSourceMembership, udpClient.MulticastMembershipAddresses);
                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.MulticastTimeToLive, int.Parse(m_configData["multicastTimeToLive"]));
                }
                else
                {
                    // Execute multicast subscribe for any source
                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.AddMembership, new MulticastOption(udpClientIPEndPoint.Address));
                    m_udpServer.Provider.SetSocketOption(level, SocketOptionName.MulticastTimeToLive, int.Parse(m_configData["multicastTimeToLive"]));
                }
            }

            // Create client info object
            udpClientInfo = new UdpClientInfo()
            {
                Client = udpClient,
                SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(),
                SendLock = new SpinLock(),
                SendQueue = new ConcurrentQueue<UdpServerPayload>()
            };

            // Set up SocketAsyncEventArgs
            udpClientInfo.SendArgs.RemoteEndPoint = udpClient.Provider;
            udpClientInfo.SendArgs.SetBuffer(udpClient.SendBuffer, 0, udpClient.SendBufferSize);
            udpClientInfo.SendArgs.Completed += m_sendHandler;

            // Add new client to the lookup
            m_clientInfoLookup.TryAdd(udpClient.ID, udpClientInfo);
            OnClientConnected(udpClient.ID);

            return udpClient;
        }