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

namespace SharpQuake
{
	internal class net_tcp_ip : INetLanDriver
	{
		public static net_tcp_ip Instance
		{
			get
			{
				return net_tcp_ip._Singletone;
			}
		}

		private net_tcp_ip()
		{
		}

		public string Name
		{
			get
			{
				return "TCP/IP";
			}
		}

		public bool IsInitialized
		{
			get
			{
				return this._IsInitialized;
			}
		}

		public Socket ControlSocket
		{
			get
			{
				return this._ControlSocket;
			}
		}

		public bool Init()
		{
			this._IsInitialized = false;
			if (common.HasParam("-noudp"))
			{
				return false;
			}
			string text;
			try
			{
				text = Dns.GetHostName();
			}
			catch (SocketException ex)
			{
				Con.DPrint("Cannot get host name: {0}\n", new object[]
				{
					ex.Message
				});
				return false;
			}
			if (net.HostName == "UNNAMED")
			{
				IPAddress ipaddress;
				if (!IPAddress.TryParse(text, out ipaddress))
				{
					int num = text.IndexOf('.');
					if (num != -1)
					{
						text = text.Substring(0, num);
					}
				}
				cvar.Set("hostname", text);
			}
			int num2 = common.CheckParm("-ip");
			if (num2 > 0)
			{
				if (num2 < common.Argc - 1)
				{
					string text2 = common.Argv(num2 + 1);
					if (!IPAddress.TryParse(text2, out this._MyAddress))
					{
						sys.Error("{0} is not a valid IP address!", new object[]
						{
							text2
						});
					}
					net.MyTcpIpAddress = text2;
				}
				else
				{
					sys.Error("Net.Init: you must specify an IP address after -ip", Array.Empty<object>());
				}
			}
			else
			{
				this._MyAddress = IPAddress.Any;
				net.MyTcpIpAddress = "INADDR_ANY";
			}
			this._ControlSocket = this.OpenSocket(0);
			if (this._ControlSocket == null)
			{
				Con.Print("TCP/IP: Unable to open control socket\n", Array.Empty<object>());
				return false;
			}
			this._BroadcastAddress = new IPEndPoint(IPAddress.Broadcast, net.HostPort);
			this._IsInitialized = true;
			Con.Print("TCP/IP Initialized\n", Array.Empty<object>());
			return true;
		}

		public void Shutdown()
		{
			this.Listen(false);
			this.CloseSocket(this._ControlSocket);
		}

		public void Listen(bool state)
		{
			if (state)
			{
				if (this._AcceptSocket == null)
				{
					this._AcceptSocket = this.OpenSocket(net.HostPort);
					if (this._AcceptSocket == null)
					{
						sys.Error("UDP_Listen: Unable to open accept socket\n", Array.Empty<object>());
						return;
					}
				}
			}
			else if (this._AcceptSocket != null)
			{
				this.CloseSocket(this._AcceptSocket);
				this._AcceptSocket = null;
			}
		}

		public Socket OpenSocket(int port)
		{
			Socket socket = null;
			try
			{
				socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
				socket.Blocking = false;
				EndPoint localEP = new IPEndPoint(this._MyAddress, port);
				socket.Bind(localEP);
			}
			catch (Exception ex)
			{
				if (socket != null)
				{
					socket.Close();
					socket = null;
				}
				Con.Print("Unable to create socket: " + ex.Message, Array.Empty<object>());
			}
			return socket;
		}

		public int CloseSocket(Socket socket)
		{
			if (socket == this._BroadcastSocket)
			{
				this._BroadcastSocket = null;
			}
			socket.Close();
			return 0;
		}

		public int Connect(Socket socket, EndPoint addr)
		{
			return 0;
		}

		public string GetNameFromAddr(EndPoint addr)
		{
			try
			{
				return Dns.GetHostEntry(((IPEndPoint)addr).Address).HostName;
			}
			catch (SocketException)
			{
			}
			return string.Empty;
		}

		public EndPoint GetAddrFromName(string name)
		{
			try
			{
				int num = name.IndexOf(':');
				int port = net.HostPort;
				string ipString;
				if (num != -1)
				{
					ipString = name.Substring(0, num);
					int num2;
					if (int.TryParse(name.Substring(num + 1), out num2))
					{
						port = num2;
					}
				}
				else
				{
					ipString = name;
				}
				IPAddress address;
				if (IPAddress.TryParse(ipString, out address))
				{
					return new IPEndPoint(address, port);
				}
				IPAddress[] addressList = Dns.GetHostEntry(name).AddressList;
				int num3 = 0;
				if (num3 < addressList.Length)
				{
					return new IPEndPoint(addressList[num3], port);
				}
			}
			catch (SocketException)
			{
			}
			return null;
		}

		public int AddrCompare(EndPoint addr1, EndPoint addr2)
		{
			if (addr1.AddressFamily != addr2.AddressFamily)
			{
				return -1;
			}
			IPEndPoint ipendPoint = addr1 as IPEndPoint;
			IPEndPoint ipendPoint2 = addr2 as IPEndPoint;
			if (ipendPoint == null || ipendPoint2 == null)
			{
				return -1;
			}
			if (!ipendPoint.Address.Equals(ipendPoint2.Address))
			{
				return -1;
			}
			if (ipendPoint.Port != ipendPoint2.Port)
			{
				return 1;
			}
			return 0;
		}

		public int GetSocketPort(EndPoint addr)
		{
			return ((IPEndPoint)addr).Port;
		}

		public int SetSocketPort(EndPoint addr, int port)
		{
			((IPEndPoint)addr).Port = port;
			return 0;
		}

		public Socket CheckNewConnections()
		{
			if (this._AcceptSocket == null)
			{
				return null;
			}
			if (this._AcceptSocket.Available > 0)
			{
				return this._AcceptSocket;
			}
			return null;
		}

		public int Read(Socket socket, byte[] buf, int len, ref EndPoint ep)
		{
			int result = 0;
			try
			{
				result = socket.ReceiveFrom(buf, len, SocketFlags.None, ref ep);
			}
			catch (SocketException ex)
			{
				if (ex.ErrorCode == 10035 || ex.ErrorCode == 10061)
				{
					result = 0;
				}
				else
				{
					result = -1;
				}
			}
			return result;
		}

		public int Write(Socket socket, byte[] buf, int len, EndPoint ep)
		{
			int result = 0;
			try
			{
				result = socket.SendTo(buf, len, SocketFlags.None, ep);
			}
			catch (SocketException ex)
			{
				if (ex.ErrorCode == 10035)
				{
					result = 0;
				}
				else
				{
					result = -1;
				}
			}
			return result;
		}

		public int Broadcast(Socket socket, byte[] buf, int len)
		{
			if (socket != this._BroadcastSocket)
			{
				if (this._BroadcastSocket != null)
				{
					sys.Error("Attempted to use multiple broadcasts sockets\n", Array.Empty<object>());
				}
				try
				{
					socket.EnableBroadcast = true;
				}
				catch (SocketException ex)
				{
					Con.Print("Unable to make socket broadcast capable: {0}\n", new object[]
					{
						ex.Message
					});
					return -1;
				}
			}
			return this.Write(socket, buf, len, this._BroadcastAddress);
		}

		private const int WSAEWOULDBLOCK = 10035;

		private const int WSAECONNREFUSED = 10061;

		private static net_tcp_ip _Singletone = new net_tcp_ip();

		private bool _IsInitialized;

		private IPAddress _MyAddress;

		private Socket _ControlSocket;

		private Socket _BroadcastSocket;

		private EndPoint _BroadcastAddress;

		private Socket _AcceptSocket;
	}
}
