corrade-vassal – Rev 1

Subversion Repositories:
Rev:
/*
 * Copyright (c) 2006-2014, openmetaverse.org
 * All rights reserved.
 *
 * - Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * - Neither the name of the openmetaverse.org nor the names
 *   of its contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Net;
using System.Net.Sockets;

namespace OpenMetaverse.Voice
{
    public class TCPPipe
    {
        protected class SocketPacket
        {
            public System.Net.Sockets.Socket TCPSocket;
            public byte[] DataBuffer = new byte[1];
        }

        public delegate void OnReceiveLineCallback(string line);
        public delegate void OnDisconnectedCallback(SocketException se);

        public event OnReceiveLineCallback OnReceiveLine;
        public event OnDisconnectedCallback OnDisconnected;

        protected Socket _TCPSocket;
        protected IAsyncResult _Result;
        protected AsyncCallback _Callback;
        protected string _Buffer = String.Empty;

        public bool Connected
        {
            get
            {
                if (_TCPSocket != null && _TCPSocket.Connected)
                    return true;
                else
                    return false;
            }
        }

        public TCPPipe()
        {
        }

        public SocketException Connect(string address, int port)
        {
            if (_TCPSocket != null && _TCPSocket.Connected)
                Disconnect();

            try
            {
                IPAddress ip;
                if (!IPAddress.TryParse(address, out ip))
                {
                    IPAddress[] ips = Dns.GetHostAddresses(address);
                    ip = ips[0];
                }
                _TCPSocket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint ipEndPoint = new IPEndPoint(ip, port);
                _TCPSocket.Connect(ipEndPoint);
                if (_TCPSocket.Connected)
                {
                    WaitForData();
                    return null;
                }
                else
                {
                    return new SocketException(10000);
                }
            }
            catch (SocketException se)
            {
                return se;
            }
        }

        public void Disconnect()
        {
            _TCPSocket.Disconnect(true);
        }

        public void SendData(byte[] data)
        {
            if (Connected)
                _TCPSocket.Send(data);
            else
                throw new InvalidOperationException("socket is not connected");
        }

        public void SendLine(string message)
        {
            if (Connected)
            {
                byte[] byData = System.Text.Encoding.ASCII.GetBytes(message + "\n");
                _TCPSocket.Send(byData);
            }
            else
            {
                throw new InvalidOperationException("socket is not connected");
            }
        }

        void WaitForData()
        {
            try
            {
                if (_Callback == null) _Callback = new AsyncCallback(OnDataReceived);
                SocketPacket packet = new SocketPacket();
                packet.TCPSocket = _TCPSocket;
                _Result = _TCPSocket.BeginReceive(packet.DataBuffer, 0, packet.DataBuffer.Length, SocketFlags.None, _Callback, packet);
            }
            catch (SocketException se)
            {
                Console.WriteLine(se.Message);
            }
        }

        static char[] splitNull = { '\0' };
        static string[] splitLines = { "\r", "\n", "\r\n" };

        void ReceiveData(string data)
        {
            if (OnReceiveLine == null) return;

            //string[] splitNull = { "\0" };
            string[] line = data.Split(splitNull, StringSplitOptions.None);
            _Buffer += line[0];
            //string[] splitLines = { "\r\n", "\r", "\n" };
            string[] lines = _Buffer.Split(splitLines, StringSplitOptions.None);
            if (lines.Length > 1)
            {
                int i;
                for (i = 0; i < lines.Length - 1; i++)
                {
                    if (lines[i].Trim().Length > 0) OnReceiveLine(lines[i]);
                }
                _Buffer = lines[i];
            }
        }

        void OnDataReceived(IAsyncResult asyn)
        {
            try
            {
                SocketPacket packet = (SocketPacket)asyn.AsyncState;
                int end = packet.TCPSocket.EndReceive(asyn);
                char[] chars = new char[end + 1];
                System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
                d.GetChars(packet.DataBuffer, 0, end, chars, 0);
                System.String data = new System.String(chars);
                ReceiveData(data);
                WaitForData();
            }
            catch (ObjectDisposedException)
            {
                Console.WriteLine("WARNING: Socket closed unexpectedly");
            }
            catch (SocketException se)
            {
                if (!_TCPSocket.Connected)
                {
                    if (OnDisconnected != null)
                        OnDisconnected(se);
                }
            }
        }

    }
}