Ping to server for external connectivity - c#

I have a c# application that has a module for checks the server connection. The relevant code is like the following:
private void PingCheck(string hostName)
{
using (var p = new Ping())
{
try
{
var pr = p.Send(hostName, 2000);
if (pr.Status != IPStatus.Success)
{
log.ErrorFormat("Ping error! Host = {0}, Ping status = {1}", hostName, pr.Status.ToString());
}
}
catch (Exception exc)
{
log.Error("Ping error!", exc);
}
}
}
We have deployed this application to our server that is inside the same network as the target machine. That's why this method checks internal connectivity. Is there any way to check server external connectivity? Because sometimes server connection is available in our network although connection from external network is down. How can I achieve this?

No, there is not, since you are on the server itself.
Either ping some resource outside to check connectivity, or use the NetworkInterface.GetIsNetworkAvailable() method to check whether there is an active connection.

Related

Checking connection state with WinSCP .NET assembly in C#

I have a method for retrying the connection of WinSCP in C#.
How would I know if the state of my connection is opened or closed? Are there methods for this in WinSCP .Net?
using (Session session = new Session())
{
try
{
session.Open(sessionOptions);
}
catch(Exception ex)
{
//I want to reconnect here if my connection
//is timed out
//I want to reconnect here 3 times
}
// Upload file
session.PutFiles(#"C:\Test\files.dat", "var/test/files.dat");
// I want also to reconnect here if my upload failed
// reconnect to the server then upload the files that
// did not upload because of the connection errors
}
In your code, you already know, if the connection succeeded or not. Anyway, you can check Session.Opened, if you want to test explicitly for some reason.
using (Session session = new Session())
{
int attempts = 3;
do
{
try
{
session.Open(sessionOptions);
}
catch (Exception e)
{
Console.WriteLine("Failed to connect - {0}", e);
if (attempts == 0)
{
// give up
throw;
}
}
attempts--;
}
while (!session.Opened);
Console.WriteLine("Connected");
}
The file transfer operations, like the Session.PutFiles, reconnect automatically, if a connection is lost during transfer.
How long it will keep reconnecting is specified by Session.ReconnectTime.

Can't establish connection using StreamSocket (universal windows)

Im trying to follow this code sample from microsoft, who is a basic code for sending/receiving data over network from windows 10 computer/phone.
Im on VS2015, i have a phone on W10 and my computer also.
The problem is that my application seems to create packet and send one to establish the connection (i have seen this packet with wireshark), but i never received it on the server side.
Here is code to listen port from the actual internet connection available and wait for a connection :
public static async void StartServer()
{
try
{
StreamSocketListener listener = new StreamSocketListener();
//ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
//await listener.BindServiceNameAsync("5043", SocketProtectionLevel.PlainSocket, internetConnectionProfile.NetworkAdapter);
listener.ConnectionReceived += OnConnection;
await listener.BindServiceNameAsync("5043");
Debug.WriteLine("Server Started !");
}
catch (Exception)
{
Debug.WriteLine("Error StartServer Method !");
}
}
The method "OnConnection" is never reach cause the event "ConnectionReceived" is never called.
Here is the code to establish connection (the string ipDestination contain the internet ip address from my phone for example, that i get from checkip.dyndns.org) :
private static StreamSocket socket;
public static async void Connect(string ipDestination)
{
try
{
//Destination Ip address
HostName host = new HostName(ipDestination);
ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
socket = new StreamSocket();
socket.Control.KeepAlive = true;
await socket.ConnectAsync(host, "5043");
//EXCEPTION RAISE HERE after a moment "System.Runtime.InteropServices.COMException, cant join destination.
Debug.WriteLine("Connected !");
}
catch (Exception)
{
Debug.WriteLine("Erreur Connect Method !");
}
}
I think i should miss something but i dont know why and im block at this part since a long and can't continue my project...
I apologize for the bad english I try to make my best :)
Update from comments :
As Jay Zuo suggested, i have try to use local address on private
network and it works, i can establish connection, send and receive
data without problems... So the problem come when i use internet IP
address, and i still can't figure why...
As Kiewic suggested, i have simplify my code and commented the
precedent version.

How to reconnect to a socket gracefully

I have a following method that connects to an end point when my program starts
ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var remoteIpAddress = IPAddress.Parse(ChannelIp);
ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort);
ChannelSocket.Connect(ChannelEndPoint);
I also have a timer that is set to trigger every 60 seconds to call CheckConnectivity, that attempts to send an arbitrary byte array to the end point to make sure that the connection is still alive, and if the send fails, it will attempt to reconnect.
public bool CheckConnectivity(bool isReconnect)
{
if (ChannelSocket != null)
{
var blockingState = ChannelSocket.Blocking;
try
{
var tmp = new byte[] { 0 };
ChannelSocket.Blocking = false;
ChannelSocket.Send(tmp);
}
catch (SocketException e)
{
try
{
ReconnectChannel();
}
catch (Exception ex)
{
return false;
}
}
}
else
{
ConnectivityLog.Warn(string.Format("{0}:{1} is null!", ChannelIp, ChannelPort));
return false;
}
return true;
}
private void ReconnectChannel()
{
try
{
ChannelSocket.Shutdown(SocketShutdown.Both);
ChannelSocket.Disconnect(true);
ChannelSocket.Close();
}
catch (Exception ex)
{
ConnectivityLog.Error(ex);
}
ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var remoteIpAddress = IPAddress.Parse(ChannelIp);
ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort);
ChannelSocket.Connect(ChannelEndPoint);
Thread.Sleep(1000);
if (ChannelSocket.Connected)
{
ConnectivityLog.Info(string.Format("{0}:{1} is reconnected!", ChannelIp, ChannelPort));
}
else
{
ConnectivityLog.Warn(string.Format("{0}:{1} failed to reconnect!", ChannelIp, ChannelPort));
}
}
So how I'd test the above, is to physically unplug the LAN cable from my ethernet device, allowing my code to attempt to reconnect (which fails obviously) and reconnect back the LAN cable.
However, even after reconnecting the LAN cable (able to ping), ChannelSocket.Connect(ChannelEndPoint) in my Reconnect method always throws this error
No connection could be made because the target machine actively refused it 192.168.168.160:4001
If I were to restart my whole application, it connects successfully. How can I tweak my reconnect method such that I don't have to restart my application to reconnect back to my Ethernet device?
If an application closes a TCP/IP port, the protocol dictates that the port stays in TIME_WAIT state for a certain duration (default of 240 seconds on a windows machine).
See following for references -
http://en.wikipedia.org/wiki/Transmission_Control_Protocol
http://support.microsoft.com/kb/137984
http://www.pctools.com/guides/registry/detail/878/
What this means for your scenario - is that you cannot expect to close (willingly or unwillingly) and re-open a port within a short period of time (even several seconds). Despite some registry tweaks which you'd find on internet.. the port will be un-available for any app on windows, for a minimum of 30 seconds. (Again, default is 240 seconds)
Your options - here are limited...
From the documentation at http://msdn.microsoft.com/en-us/library/4xzx2d41(v=vs.110).aspx -
"If the socket has been previously disconnected, then you cannot use this (Connect) method to restore the connection. Use one of the asynchronous BeginConnect methods to reconnect. This is a limitation of the underlying provider."
The reason why documentation suggests that BeginConnect must be used is what I mentioned above.. It simply doesn't expect to be able to establish the connection right away.. and hence the only option is to make the call asynchronously, and while you wait for the connection to get established in several minutes, do expect and plan for it to fail. Essentially, likely not an ideal option.
If the long wait and uncertainty is not acceptable, then your other option is to somehow negotiate a different port between the client and server. (For example, in theory you could use UDP, which is connectionless, to negotiate the new TCP port you'd re-establish the connection on). Communication using UDP, in theory of course, itself is not guaranteed by design. But should work most of the times (Today, networking in typical org is not that flaky / unreliable). Subjective to scenario / opinion, perhaps better than option 1, but more work and smaller but finite chance of not working.
As suggested in one of the comments, this is where application layer protocols like http and http services have an advantage. Use them, instead of low level sockets, if you can.
If acceptable, this is the best option to go with.
(PS - FYI - For HTTP, there is a lot of special handling built into OS, including windows - For example, there is a dedicated driver Http.sys, specially for dealing with multiple apps trying to listen on same port 80 etc.. The details here are a topic for another time.. point is, there is lots of goodness and hard work done for you, when it comes to HTTP)
Maybe you should switch to a higher abstraction class, which better deals with all these nifty little details?
I'm going to use for these network connections the TcpListener and TcpClient classes. The usage of these classes is quite easy:
The client side:
public void GetInformationAsync(IPAddress ipAddress)
{
_Log.Info("Start retrieving informations from address " + ipAddress + ".");
var tcpClient = new TcpClient();
tcpClient.BeginConnect(ipAddress, _PortNumber, OnTcpClientConnected, tcpClient);
}
private void OnTcpClientConnected(IAsyncResult asyncResult)
{
try
{
using (var tcpClient = (TcpClient)asyncResult.AsyncState)
{
tcpClient.EndConnect(asyncResult);
var ipAddress = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address;
var stream = tcpClient.GetStream();
stream.ReadTimeout = 5000;
_Log.Debug("Connection established to " + ipAddress + ".");
var formatter = new BinaryFormatter();
var information = (MyInformation)formatter.Deserialize(stream);
_Log.Info("Successfully retrieved information from address " + ipAddress + ".");
InformationAvailable.FireEvent(this, new InformationEventArgs(information));
}
}
catch (Exception ex)
{
_Log.Error("Error in retrieving informations.", ex);
return;
}
}
The server side:
public void Start()
{
ThrowIfDisposed();
if (_TcpServer != null;)
_TcpServer.Stop();
_TcpServer = new TcpListener(IPAddress.Any, _PortNumber);
_TcpServer.Start();
_TcpServer.BeginAcceptTcpClient(OnClientConnected, _TcpServer);
_Log.Info("Start listening for incoming connections on " + _TcpServer.LocalEndpoint + ".");
}
private void OnClientConnected(IAsyncResult asyncResult)
{
var tcpServer = (TcpListener)asyncResult.AsyncState;
IPAddress address = IPAddress.None;
try
{
if (tcpServer.Server != null
&& tcpServer.Server.IsBound)
tcpServer.BeginAcceptTcpClient(OnClientConnected, tcpServer);
using (var client = tcpServer.EndAcceptTcpClient(asyncResult))
{
address = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
_Log.Debug("Client connected from address " + address + ".");
var formatter = new BinaryFormatter();
var informations = new MyInformation()
{
// Initialize properties with desired values.
};
var stream = client.GetStream();
formatter.Serialize(stream, description);
_Log.Debug("Sucessfully serialized information into network stream.");
}
}
catch (ObjectDisposedException)
{
// This normally happens, when the server will be stopped
// and their exists no other reliable way to check this state
// before calling EndAcceptTcpClient().
}
catch (Exception ex)
{
_Log.Error(String.Format("Cannot send instance information to {0}.", address), ex);
}
}
This code works and doesn't make any problems with a lost connection on the client side. If you have a lost connection on the server side you have to re-establish the listener, but that's another story.
In ReconnectChannel just dispose the ChannelSocket object.
try
{
`//ChannelSocket.Shutdown(SocketShutdown.Both);
//ChannelSocket.Disconnect(true);
//ChannelSocket.Close();
ChannelSocket.Dispose();`
}
This is working for me. Let me know if it doesn't work for you.

Check if a port is open

I can't seem to find anything that tells me if a port in my router is open or not.
Is this even possible?
The code I have right now doesn't really seem to work...
private void ScanPort()
{
string hostname = "localhost";
int portno = 9081;
IPAddress ipa = (IPAddress) Dns.GetHostAddresses(hostname)[0];
try
{
System.Net.Sockets.Socket sock =
new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork,
System.Net.Sockets.SocketType.Stream,
System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true) // Port is in use and connection is successful
MessageBox.Show("Port is Closed");
sock.Close();
}
catch (System.Net.Sockets.SocketException ex)
{
if (ex.ErrorCode == 10061) // Port is unused and could not establish connection
MessageBox.Show("Port is Open!");
else
MessageBox.Show(ex.Message);
}
}
Try this:
using(TcpClient tcpClient = new TcpClient())
{
try {
tcpClient.Connect("127.0.0.1", 9081);
Console.WriteLine("Port open");
} catch (Exception) {
Console.WriteLine("Port closed");
}
}
You should probably change 127.0.0.1 to something like 192.168.0.1 or whatever your router's IP address is.
A better solution where you can even specify a timeout:
using System;
using System.Net.Sockets;
// ...
bool IsPortOpen(string host, int port, TimeSpan timeout)
{
try
{
using(var client = new TcpClient())
{
var result = client.BeginConnect(host, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(timeout);
client.EndConnect(result);
return success;
}
}
catch
{
return false;
}
}
And, in F#:
open System
open System.Net.Sockets
let isPortOpen (host: string) (port: int) (timeout: TimeSpan): bool =
try
use client = new TcpClient()
let result = client.BeginConnect(host, port, null, null)
let success = result.AsyncWaitHandle.WaitOne timeout
client.EndConnect result
success
with
| _ -> false
let available = isPortOpen "stackoverflow.com" 80 (TimeSpan.FromSeconds 10.)
printf "Is stackoverflow available? %b" available
There is no way to know if the port is forwarded in your router, except if there is a program listening on that port.
As you may see in the Clinton answer, the .Net class being used is TcpClient and that is because you are using a TCP socket to connect to. That is the way operating systems make connections: using a socket. However, a router just forwards the packets (layer 3 of the OSI Model) in or out. In your case, what your router is doing is called: NAT. It is one public IP shared by a one or more private IPs. That´s why you are making a port forwarding.
There may be a lot of routers in the path of the packets, and you will never know what had happened.
Let´s imagine you are sending a letter in the traditional way. Perhaps you can write in the letter that the receiver must answer, in order to check he/she is there (you and the receiver are the sockets). If you receive an answer you will be sure he/she is there, but if you don´t receive anything you don´t know if the mailman (in your case the router) forgot to deliver the letter, or the receiver hadn´t answered. You would also never know if the mailman has asked a friend to deliver that letter. Moreover, the mailman won´t open the letter in order to know he/she may answer because you are waiting for a reply. All you may do is wait some time to receive the answer. If you don´t receive anything in that period you will assume that the receiver isn´t where you sent the letter. That is a "timeout".
I saw an answer mentioning the nmap software. It´s really a very good and complex soft, but I think it will work in the same way. If there is no app listening in that port, there is no way to know if it is open or not.
Please, let me know if I was clear.
If you're connecting to the loopback adapter — localhost or 127.0.0.1 (there's no place like 127.0.0.1!), you're unlikely to ever go out to the router. The OS is smart enough to recognize that it's a special address. Dunno if that holds true as well if you actually specify your machine's "real" IP address.
See also this question: What is the purpose of the Microsoft Loopback Adapter?
Also note that running traceroute localhost (tracert localhost in Windows) shows that the only network node involved is your own machine. The router is never involved.
Other than BeginConnect you can also use ConnectAsync (added in .NET Framework 4.5 I think?).
TcpClient client = null;
try {
client = new TcpClient();
var task = client.ConnectAsync(host, port);
if (task.Wait(timeout)) {//if fails within timeout, task.Wait still returns true.
if (client.Connected) {
// port reachable
}
else
// connection refused probably
}
else
// timed out
}
catch (Exception ex) {
// connection failed
}
finally {
client.Close();
}
Full project is here because paping refuses to run and I couldn't find another "ping host:port" tool to my likes.
A port forward on the router cannot be tested from inside the LAN, you need to connect from the WAN (internet) side to see if a port forward is working or not.
Several internet sites offer services to check if a port is open:
What's My IP Port Scanner
GRC | ShieldsUP!
If you want to check with your own code, then you need to make sure the TCP/IP connection is rerouted via an external proxy or setup a tunnel. This has nothing to do with your code, it's basic networking 101.
public static bool PortInUse(int port)
{
bool inUse = false;
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint [] ipEndPoints = ipProperties.GetActiveTcpListeners();
foreach(IPEndPoint endPoint in ipEndPoints)
{
if(endPoint.Port == port)
{
inUse = true;
break;
}
}
return inUse;
}
For me, I needed something blocking until the connection to the port is available or after a certain amount of retries. So, I figured out this code:
public bool IsPortOpen(string host, int port, int timeout, int retry)
{
var retryCount = 0;
while (retryCount < retry)
{
if (retryCount > 0)
Thread.Sleep(timeout);
try
{
using (var client = new TcpClient())
{
var result = client.BeginConnect(host, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(timeout);
if (success)
return true;
client.EndConnect(result);
}
}
catch
{
// ignored
}
finally { retryCount++; }
}
return false;
}
Hope this helps!
also you can use ConnectAsync like
public async Task<bool> IsIPAndPortOpen(string hostOrIPAddress, int port, TimeSpan timeOut)
{
try
{
using (var client = new TcpClient())
{
var ct = new CancellationTokenSource(timeOut).Token;
await client.ConnectAsync(hostOrIPAddress, port, ct);
return true;
}
}
catch
{
return false;
}
}
public string GetAvailablePort()
{int startingPort=1000;
string portnumberinformation = string.Empty;
IPEndPoint[] endPoints;
List<int> portArray = new List<int>();
IPGlobalPr`enter code here`operties properties = IPGlobalProperties.GetIPGlobalProperties();`enter code here`
//getting active tcp listners
endPoints = properties.GetActiveTcpListeners();
portArray.AddRange(from n in endPoints
where n.Port >= startingPort
select n.Port);
portArray.Sort();
for (int i = 0; i < portArray.Count; i++)
{
if (check condition)
{
do somting
}
}
return portnumberinformation;
}
If it is Router the simplest way to check it through online services like
Port Checker
Port Forwarding Test
You can also try using telenet to chek wether port is accessible or not
telenet [ip-address] [port]

Can I say that domain doesn't exist if Socket.Connect fails?

I want to check if some email domain exist.
When Dns.GetHostEntry(domain) throw an exception I know for sure that the domain doesn't exist.
Can I say that if Dns.GetHostEntry(domain) succeeded then the domain does exists or even if Dns.GetHostEntry(domain) succeeded that doesn't mean (yet) that domain exists?
Can I say the same when s.Connect fails to connect? I mean if connect throw an exception can I say that such domain doesn't exist?
If (1) is true, so in order to check if domain exists (1) will be enough, right?
public static bool Lookup(string domain)
{
if (domain == null) throw new ArgumentNullException("domain");
try {
IPHostEntry ipHost = Dns.GetHostEntry(domain);
var endPoint = new IPEndPoint(ipHost.AddressList[0], _dnsPort);
return Transfer(endPoint);
}
catch (SocketException ex)
{
++attempts;
}
return false;
}
public static bool Transfer(IPEndPoint endPoint)
{
int attempts = 0;
while(attempts <= _attempts)
{
try
{
var s = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
s.Connect(endPoint);
}
catch (SocketException ex)
{
++attempts;
}
finally
{
s.Close();
}
}
}
When trying to connect with a socket you're saying a few things:
There is a network path from my machine to the target machine
The network path is clear of firewall and other restrictions
The target machine is hosting a service on the target port
The target machine is accepting my connections on that target service
All of these occur after the hostname has been resolved to an IP.
So the answer to your question is no. If Socket.Connect fails it could be that the domain doesn't exist, or any of the above reasons (and perhaps more).
after some research I found out that checking mx records against dns will tell me if domain can receive emails or not. If DNS server do return mx records for the domain it only means that domain can receive emails. If no mx records are returned, so domain can not receive emails == such domain doesn't exist

Categories