/// <summary>
        /// Sends provided bytes.
        /// </summary>
        /// <param name="buf">Serialized message bytes to send.</param>
        /// <returns>Whether the send was successful.</returns>
        protected override async Task <bool> SendBytesAsync(byte[] buf)
        {
            if (this.socket == null)
            {
                Debug.WriteLine("Cannot write to a disconnected link");
                return(false);
            }

            // Await-able task for waiting on send completion
            var asyncSendSource = new TaskCompletionSource <int>();

            // Callback when send completes
            AsyncCallback sendCallback = result =>
            {
                int bytesSent = 0;

                // Retrieve the NewCtrlConnectorImpl instance from the state object
                CtrlConnectorImpl instance = ( CtrlConnectorImpl )result.AsyncState;

                try
                {
                    // Complete the send if the socket hasn't been closed
                    if (instance.socket != null)
                    {
                        bytesSent = instance.socket.EndSend(result);
                    }
                }
                catch (ObjectDisposedException)
                {
                    // If we're being stopped, the socket may already have
                    // been disposed before the callback runs
                }

                asyncSendSource.SetResult(bytesSent);
            };

#if DEBUG2
            Debug.WriteLine("Sending " + buf.Length + " bytes");
#endif

            // Wait for send
            this.socket.BeginSend(buf, 0, buf.Length, 0, sendCallback, this);
            await asyncSendSource.Task;

#if DEBUG2
            Debug.WriteLine("Sent " + buf.Length + " bytes");
#endif

            return(true);
        }
        /// <summary>
        /// Disconnect from the protocol server
        /// </summary>
        /// <returns>Await-able task.</returns>
        protected override async Task DisconnectAsync()
        {
            if (this.socket != null && this.socket.Connected)
            {
                // Await-able task for waiting on connect completion
                var asyncDisconnectSource = new TaskCompletionSource <object>();

                // Callback when connect completes
                AsyncCallback disconnectCallback = result =>
                {
                    // Retrieve the NewCtrlConnectorImpl instance from the state object
                    CtrlConnectorImpl instance = ( CtrlConnectorImpl )result.AsyncState;

                    try
                    {
                        // Complete the connection if the socket hasn't been closed
                        if (instance.socket != null)
                        {
                            instance.socket.EndDisconnect(result);
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                        // If we're being stopped, the socket may already have
                        // been disposed before the callback runs
                    }

                    // Finish connect task
                    asyncDisconnectSource.SetResult(null);
                };

#if DEBUG
                Debug.WriteLine("Disconnecting");
#endif

                // Wait for disconnect
                this.socket.BeginDisconnect(false, disconnectCallback, this);
                await asyncDisconnectSource.Task;

#if DEBUG
                Debug.WriteLine("Disconnected");
#endif
            }

            this.CleanupConnectorImpl();
        }
        /// <summary>
        /// Connect to the protocol server.
        /// </summary>
        /// <returns>A value indicating whether the connect was successful.</returns>
        protected override async Task <bool> ConnectAsync()
        {
            IPEndPoint endpoint = new IPEndPoint(
                Dns.GetHostAddresses(this.HostName)
                .Where(ip => ip.AddressFamily == AddressFamily.InterNetwork).First(),
                int.Parse(this.Port));

            this.socket         = new Socket(SocketType.Stream, ProtocolType.Tcp);
            this.socket.NoDelay = true;

            // Await-able task for waiting on connect completion
            var asyncConnectSource = new TaskCompletionSource <object>();

            // Callback when connect completes
            AsyncCallback connectCallback = result =>
            {
                // Retrieve the NewCtrlConnectorImpl instance from the state object
                CtrlConnectorImpl instance = ( CtrlConnectorImpl )result.AsyncState;

                try
                {
                    // Complete the connection if the socket hasn't been closed
                    if (instance.socket != null)
                    {
                        instance.socket.EndConnect(result);
                    }
                }
                catch (SocketException)
                {
                    asyncConnectSource.SetResult(false);
                    return;
                }
                catch (ObjectDisposedException)
                {
                    // If we're being stopped, the socket may already have
                    // been disposed before the callback runs
                }

                // Finish connect task
                asyncConnectSource.SetResult(instance.socket != null && instance.socket.Connected);
            };

#if DEBUG
            Debug.WriteLine("Connecting to " + endpoint.ToString());
#endif

            // Wait for connect
            this.socket.BeginConnect(endpoint, connectCallback, this);
            bool success = ( bool )await asyncConnectSource.Task;

            if (!success)
            {
#if DEBUG
                Debug.WriteLine("Failed to connect to " + endpoint.ToString());
#endif

                return(false);
            }

#if DEBUG
            Debug.WriteLine("Connected to " + endpoint.ToString());
#endif

            // Start link once connected
            await this.StartLinkAsync(new CtrlReaderImpl ( this.socket ));

            return(true);
        }