Example #1
0
        /// <summary>
        /// Validates the specified <paramref name="connectionString"/>.
        /// </summary>
        /// <param name="connectionString">Connection string to be validated.</param>
        /// <exception cref="ArgumentException">Server property is missing.</exception>
        /// <exception cref="FormatException">Server property is invalid.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Server port value is not between <see cref="Transport.PortRangeLow"/> and <see cref="Transport.PortRangeHigh"/>.</exception>
        protected override void ValidateConnectionString(string connectionString)
        {
            m_connectData = connectionString.ParseKeyValuePairs();

            // Derive desired IP stack based on specified "interface" setting, adding setting if it's not defined
            m_ipStack = Transport.GetInterfaceIPStack(m_connectData);

            // Check if 'server' property is missing.
            if (!m_connectData.ContainsKey("server"))
                throw new ArgumentException(string.Format("Server property is missing (Example: {0})", DefaultConnectionString));

            // Backwards compatibility adjustments.
            // New Format: Server=localhost:8888
            // Old Format: Server=localhost; Port=8888
            if (m_connectData.ContainsKey("port"))
                m_connectData["server"] = string.Format("{0}:{1}", m_connectData["server"], m_connectData["port"]);

            // Check if 'server' property is valid.
            Match endpoint = Regex.Match(m_connectData["server"], Transport.EndpointFormatRegex);

            if (endpoint == Match.Empty)
                throw new FormatException(string.Format("Server property is invalid (Example: {0})", DefaultConnectionString));

            if (!Transport.IsPortNumberValid(endpoint.Groups["port"].Value))
                throw new ArgumentOutOfRangeException("connectionString", string.Format("Server port must between {0} and {1}", Transport.PortRangeLow, Transport.PortRangeHigh));
        }
Example #2
0
        /// <summary>
        /// Creates an <see cref="IPEndPoint"/> for the specified host name and port number.
        /// </summary>
        /// <param name="hostNameOrAddress">The host name or IP address to resolve.</param>
        /// <param name="port">The port number to be associated with the address.</param>
        /// <param name="stack">Desired IP stack to use.</param>
        /// <returns>An <see cref="IPEndPoint"/> object.</returns>
        public static IPEndPoint CreateEndPoint(string hostNameOrAddress, int port, IPStack stack)
        {
            // Determine system's default IP stack if the default stack was requested
            if (stack == IPStack.Default)
                stack = GetDefaultIPStack();

            // Make sure system can support specified stack
            if (stack == IPStack.IPv6 && !Socket.OSSupportsIPv6)
                throw new NotSupportedException(string.Format("IPv6 stack is not available for socket creation on {0}:{1}", hostNameOrAddress.ToNonNullNorWhiteSpace("localhost"), port));
#if !MONO
            else if (stack == IPStack.IPv4 && !Socket.OSSupportsIPv4)
                throw new NotSupportedException(string.Format("IPv4 stack is not available for socket creation on {0}:{1}", hostNameOrAddress.ToNonNullNorWhiteSpace("localhost"), port));
#endif

            if (string.IsNullOrWhiteSpace(hostNameOrAddress))
            {
                // No host name or IP address was specified, use local IPs
                if (stack == IPStack.IPv6)
                    return new IPEndPoint(IPAddress.IPv6Any, port);

                return new IPEndPoint(IPAddress.Any, port);
            }
            else
            {
                IPAddress address;
                bool ipStackMismatch = false;

                // Attempt to parse provided address name as a literal IP address
                if (IPAddress.TryParse(hostNameOrAddress, out address))
                {
                    // As long as desired IP stack matches format of specified IP address, return end point for address
                    if ((stack == IPStack.IPv6 && address.AddressFamily == AddressFamily.InterNetworkV6) ||
                        (stack == IPStack.IPv4 && address.AddressFamily == AddressFamily.InterNetwork))
                        return new IPEndPoint(address, port);

                    // User specified an IP address that is mismatch with the desired IP stack. If the DNS server
                    // responds to this IP, we can attempt to see if an IP is defined for the desired IP stack, 
                    // otherwise this is an exception
                    ipStackMismatch = true;
                }

                try
                {
                    // Handle "localhost" as a special case, returning proper loopback address for the desired IP stack
                    if (string.Compare(hostNameOrAddress, "localhost", true) == 0)
                        return new IPEndPoint(stack == IPStack.IPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, port);

                    // Failed to parse an IP address for the deisred stack - this may simply be that a host name was provided
                    // so we attempt a DNS lookup. Note that exceptions will occur if DNS lookup fails.
                    IPAddress[] dnsAddressList = Dns.GetHostEntry(hostNameOrAddress).AddressList;

                    if (dnsAddressList.Length > 0)
                    {
                        // Traverse address list looking for first match on desired IP stack
                        foreach (IPAddress dnsAddress in dnsAddressList)
                        {
                            if ((stack == IPStack.IPv6 && dnsAddress.AddressFamily == AddressFamily.InterNetworkV6) ||
                                (stack == IPStack.IPv4 && dnsAddress.AddressFamily == AddressFamily.InterNetwork))
                                return new IPEndPoint(dnsAddress, port);
                        }

                        // If no available matching address was found for desired IP stack, this is an IP stack mismatch
                        ipStackMismatch = true;
                    }

                    throw new InvalidOperationException(string.Format("No valid {0} addresses could be found for \"{1}\"", stack, hostNameOrAddress));
                }
                catch
                {
                    // Spell out a specific error message for ip stack mismatches
                    if (ipStackMismatch)
                        throw new InvalidOperationException(string.Format("IP address mismatch: unable to find an {0} address for \"{1}\"", stack, hostNameOrAddress));

                    // Otherwise report original exception
                    throw;
                }
            }
        }
Example #3
0
        /// <summary>
        /// Creates a <see cref="Socket"/> for the specified <paramref name="port"/> and <paramref name="protocol"/>.
        /// </summary>
        /// <param name="address">The local address where the <see cref="Socket"/> will be bound.</param>
        /// <param name="port">The port number at which the <see cref="Socket"/> will be bound.</param>
        /// <param name="protocol">One of the <see cref="ProtocolType"/> values.</param>
        /// <param name="stack">Desired IP stack to use.</param>
        /// <param name="allowDualStackSocket">Determines if dual-mode socket is allowed when endpoint address is IPv6.</param>
        /// <returns>An <see cref="Socket"/> object.</returns>
        public static Socket CreateSocket(string address, int port, ProtocolType protocol, IPStack stack, bool allowDualStackSocket = true)
        {
            Socket socket = null;
            IPEndPoint endpoint = null;

            switch (protocol)
            {
                case ProtocolType.Tcp:
                    endpoint = CreateEndPoint(address, port, stack);
                    socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                    // If allowDualModeSocket is true and the enpoint is IPv6, we setup a dual-mode socket
                    // by setting the IPv6Only socket option to false
                    if (allowDualStackSocket && endpoint.AddressFamily == AddressFamily.InterNetworkV6 && Environment.OSVersion.Version.Major > 5)
                        socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);

                    // Associate the socket with the local endpoint
                    socket.Bind(endpoint);

                    break;
                case ProtocolType.Udp:
                    // Allow negative port number to be specified for unbound socket.
                    if (port >= 0)
                    {
                        endpoint = CreateEndPoint(address, port, stack);
                        socket = new Socket(endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);

                        // If allowDualModeSocket is true and the endpoint is IPv6, we setup a dual-mode socket
                        // by setting the IPv6Only socket option to false
                        if (allowDualStackSocket && endpoint.AddressFamily == AddressFamily.InterNetworkV6 && Environment.OSVersion.Version.Major > 5)
                            socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);

                        socket.Bind(endpoint);
                    }
                    else
                    {
                        // Create a socket with no binding when -1 is used for port number
                        endpoint = CreateEndPoint(address, 0, stack);
                        socket = new Socket(endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
                    }
                    break;
                default:
                    throw new NotSupportedException("Communications library does not support socket creation for protocol " + protocol);
            }
            return socket;
        }
Example #4
0
        /// <summary>
        /// Validates the specified <paramref name="configurationString"/>.
        /// </summary>
        /// <param name="configurationString">Configuration string to be validated.</param>
        /// <exception cref="ArgumentException">Port property is missing.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Port property value is not between <see cref="Transport.PortRangeLow"/> and <see cref="Transport.PortRangeHigh"/>.</exception>
        protected override void ValidateConfigurationString(string configurationString)
        {
            m_configData = configurationString.ParseKeyValuePairs();

            // Derive desired IP stack based on specified "interface" setting, adding setting if it's not defined
            m_ipStack = Transport.GetInterfaceIPStack(m_configData);

            if (!m_configData.ContainsKey("port"))
                throw new ArgumentException($"Port property is missing (Example: {DefaultConfigurationString})");

            if (!Transport.IsPortNumberValid(m_configData["port"]))
                throw new ArgumentOutOfRangeException(nameof(configurationString), $"Port number must be between {Transport.PortRangeLow} and {Transport.PortRangeHigh}");
        }
Example #5
0
        /// <summary>
        /// Creates a <see cref="Socket"/> for the specified <paramref name="port"/> and <paramref name="protocol"/>.
        /// </summary>
        /// <param name="address">The local address where the <see cref="Socket"/> will be bound.</param>
        /// <param name="port">The port number at which the <see cref="Socket"/> will be bound.</param>
        /// <param name="protocol">One of the <see cref="ProtocolType"/> values.</param>
        /// <param name="stack">Desired IP stack to use.</param>
        /// <param name="allowDualStackSocket">Determines if dual-mode socket is allowed when endpoint address is IPv6.</param>
        /// <returns>An <see cref="Socket"/> object.</returns>
        public static Socket CreateSocket(string address, int port, ProtocolType protocol, IPStack stack, bool allowDualStackSocket = true)
        {
            Socket     socket;
            IPEndPoint endpoint;

            switch (protocol)
            {
            case ProtocolType.Tcp:
                endpoint = CreateEndPoint(address, port, stack);
                socket   = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                #if !MONO
                // If allowDualModeSocket is true and the endpoint is IPv6, we setup a dual-mode socket
                // by setting the IPv6Only socket option to false
                if (allowDualStackSocket && endpoint.AddressFamily == AddressFamily.InterNetworkV6 && Environment.OSVersion.Version.Major > 5)
                {
                    socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);
                }
                #endif
                // Associate the socket with the local endpoint
                socket.Bind(endpoint);

                break;

            case ProtocolType.Udp:
                // Allow negative port number to be specified for unbound socket.
                if (port >= 0)
                {
                    endpoint = CreateEndPoint(address, port, stack);
                    socket   = new Socket(endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
                    #if !MONO
                    // If allowDualModeSocket is true and the endpoint is IPv6, we setup a dual-mode socket
                    // by setting the IPv6Only socket option to false
                    if (allowDualStackSocket && endpoint.AddressFamily == AddressFamily.InterNetworkV6 && Environment.OSVersion.Version.Major > 5)
                    {
                        socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);
                    }
                    #endif
                    socket.Bind(endpoint);
                }
                else
                {
                    // Create a socket with no binding when -1 is used for port number
                    endpoint = CreateEndPoint(address, 0, stack);
                    socket   = new Socket(endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
                }
                break;

            default:
                throw new NotSupportedException($"Communications library does not support socket creation for protocol {protocol}");
            }
            return(socket);
        }
Example #6
0
        /// <summary>
        /// Creates an <see cref="IPEndPoint"/> for the specified host name and port number.
        /// </summary>
        /// <param name="hostNameOrAddress">The host name or IP address to resolve.</param>
        /// <param name="port">The port number to be associated with the address.</param>
        /// <param name="stack">Desired IP stack to use.</param>
        /// <returns>An <see cref="IPEndPoint"/> object.</returns>
        public static IPEndPoint CreateEndPoint(string hostNameOrAddress, int port, IPStack stack)
        {
            // Determine system's default IP stack if the default stack was requested
            if (stack == IPStack.Default)
            {
                stack = GetDefaultIPStack();
            }

            // Make sure system can support specified stack
            if (stack == IPStack.IPv6 && !Socket.OSSupportsIPv6)
            {
                throw new NotSupportedException($"IPv6 stack is not available for socket creation on {hostNameOrAddress.ToNonNullNorWhiteSpace("localhost")}:{port}");
            }
        #if !MONO
            if (stack == IPStack.IPv4 && !Socket.OSSupportsIPv4)
            {
                throw new NotSupportedException($"IPv4 stack is not available for socket creation on {hostNameOrAddress.ToNonNullNorWhiteSpace("localhost")}:{port}");
            }
#endif

            // No host name or IP address was specified, use local IPs
            if (string.IsNullOrWhiteSpace(hostNameOrAddress))
            {
                return(stack == IPStack.IPv6 ? new IPEndPoint(IPAddress.IPv6Any, port) : new IPEndPoint(IPAddress.Any, port));
            }

            bool ipStackMismatch = false;

            // Attempt to parse provided address name as a literal IP address
            if (IPAddress.TryParse(hostNameOrAddress, out IPAddress address))
            {
                // As long as desired IP stack matches format of specified IP address, return end point for address
                if (stack == IPStack.IPv6 && address.AddressFamily == AddressFamily.InterNetworkV6 ||
                    stack == IPStack.IPv4 && address.AddressFamily == AddressFamily.InterNetwork)
                {
                    return(new IPEndPoint(address, port));
                }

                // User specified an IP address that is mismatch with the desired IP stack. If the DNS server
                // responds to this IP, we can attempt to see if an IP is defined for the desired IP stack,
                // otherwise this is an exception
                ipStackMismatch = true;
            }

            try
            {
                // Handle "localhost" as a special case, returning proper loopback address for the desired IP stack
                if (string.Compare(hostNameOrAddress, "localhost", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    return(new IPEndPoint(stack == IPStack.IPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, port));
                }

                // Failed to parse an IP address for the desired stack - this may simply be that a host name was provided
                // so we attempt a DNS lookup. Note that exceptions will occur if DNS lookup fails.
                IPAddress[] dnsAddressList = Dns.GetHostEntry(hostNameOrAddress).AddressList;

                if (dnsAddressList.Length > 0)
                {
                    // Traverse address list looking for first match on desired IP stack
                    foreach (IPAddress dnsAddress in dnsAddressList)
                    {
                        if (stack == IPStack.IPv6 && dnsAddress.AddressFamily == AddressFamily.InterNetworkV6 ||
                            stack == IPStack.IPv4 && dnsAddress.AddressFamily == AddressFamily.InterNetwork)
                        {
                            return(new IPEndPoint(dnsAddress, port));
                        }
                    }

                    // If no available matching address was found for desired IP stack, this is an IP stack mismatch
                    ipStackMismatch = true;
                }

                throw new InvalidOperationException($"No valid {stack} addresses could be found for \"{hostNameOrAddress}\"");
            }
            catch
            {
                // Spell out a specific error message for IP stack mismatches
                if (ipStackMismatch)
                {
                    throw new InvalidOperationException($"IP address mismatch: unable to find an {stack} address for \"{hostNameOrAddress}\"");
                }

                // Otherwise report original exception
                throw;
            }
        }
Example #7
0
 public static Socket CreateSocket(string address, int port, ProtocolType protocol, IPStack stack)
 {
     return(CreateSocket(address, port, protocol, stack, true));
 }
Example #8
0
        /// <summary>
        /// Validates the specified <paramref name="configurationString"/>.
        /// </summary>
        /// <param name="configurationString">Configuration string to be validated.</param>
        /// <exception cref="ArgumentException">Port property is missing.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Port property value is not between <see cref="Transport.PortRangeLow"/> and <see cref="Transport.PortRangeHigh"/>.</exception>
        protected override void ValidateConfigurationString(string configurationString)
        {
            string setting;
            int value;

            m_configData = configurationString.ParseKeyValuePairs();

            // Derive desired IP stack based on specified "interface" setting, adding setting if it's not defined
            m_ipStack = Transport.GetInterfaceIPStack(m_configData);

            if (!m_configData.ContainsKey("port"))
                throw new ArgumentException(string.Format("Port is missing (Example: {0})", DefaultConfigurationString));

            if (!Transport.IsPortNumberValid(m_configData["port"]) && int.Parse(m_configData["port"]) != -1)
                throw new ArgumentOutOfRangeException("configurationString", string.Format("Port number must be {0} or between {1} and {2}", -1, Transport.PortRangeLow, Transport.PortRangeHigh));

            if (!m_configData.ContainsKey("multicastTimeToLive"))
                m_configData.Add("multicastTimeToLive", "10");

            // Make sure a valid multi-cast time-to-live value is defined in the configuration data
            if (!(m_configData.TryGetValue("multicastTimeToLive", out setting) && int.TryParse(setting, out value)))
                m_configData["multicastTimeToLive"] = "10";
        }