I'm currently working with a measurement device that has an embedded Linux web server build in and could be controlled with the so called CGI-Interface over LAN. If one wants to change the settings of the device, one has to send at first a TCP/IP login packet and after this a key-code to control a specified function or receive data.
By using a TCP/IP packet tool, for example Paket Sender, everything works fine. A login packet to 192.168.0.1(Device) at port 80 from 192.168.0.2(PC) with the ASCII Text (These are standard password and login name, so I don't blur this out):
GET /cgi-bin/login.cgi?username=long&password=nga HTTP/1.0 \n \n
gets successfully received and acknowledged from the devices, as shown in the wireshark protocol:
Wireshark Screenshot
But the same request with the Standard C# TCP/IP Client provided by Microsoft returns a Bad Request Error Message. Somewhat C# does not send the [FIN,ACK] Packet like "Packet Sender". The modified code from Microsoft is as follows:
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 80);
// Create a TCP/IP socket.
Socket sender = new Socket(IPAddress.Parse("192.168.0.1").AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes("GET /cgi-bin/login.cgi?username=long&password=nga HTTP/1.0 \n \n");
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Output for this snippet:
Socket connected to 192.168.0.1:80
Echoed test = HTTP/1.0 408 Request Timeout
Content-type: text/html
Date: Mon, 26 Mar 2018 16:41:34 GMT
Connection: close
<HTML><HEAD><TITLE>408 Request Timeout</TITLE></HEAD>
<BODY><H1>408 Request Timeout</H1>
No request appeared within 60 seconds
</BODY></HTML>
Wireshark Screenshot of this communication.
Well, I don't know, why C# doesn't send the [FIN,ACK] message. Maybe anyone has experienced the same? Or there is an easy explanation for this? Maybe I'm missing an option in the TCP/IP Sockets? If it helps, I could also provide the Wireshark protocol files.
I'm guessing that the server requires the sender to send the FIN/ACK before it sends the response, yes? FIN means shutting down that (directional) stream, so if the problem really is the missing FIN, I'm guessing that what you need here is after sending the request but before listening for the response, to add:
sender.Shutdown(SocketShutdown.Send);
which should FIN the outbound connection.
However, see also Dirk's comment on the question; it could simply be that you aren't correctly forming a complete request, and that the FIN is currently making it work indirectly.
Note that you might also want to set sender.NoDelay = true;, although that should be unrelated.
Related
I need to obtain UDP datagram from Asynchronous Socket Server but an exception occurred in my application :
Problem appear there :
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
The full source code:
class Program
{
static void Main(string[] args)
{
const int PORT = 30485;
IPAddress IP;
IPAddress.TryParse("92.56.23.87", out IP);
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient(PORT);
Socket receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
try
{
udpClient.Connect("92.56.23.87", PORT);
if (udpClient.Client.Connected)
Console.WriteLine("Connected.");
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("CONNECT");
udpClient.Send(sendBytes, sendBytes.Length);
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IP, PORT);
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " + returnData.ToString());
Console.WriteLine("This message was sent from " + RemoteIpEndPoint.Address.ToString() + " on their port number " + RemoteIpEndPoint.Port.ToString());
udpClient.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
Exception:
Connected.
System.Net.Sockets.SocketException (0x80004005): An existing connection
was forcibly closed by the remote host at System.Net.Sockets.Socket.ReceiveFrom(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint& remoteEP) at ystem.Net.Sockets.UdpClient.Receive(IPEndPoint& remoteEP) at ConsoleApplication7.Program.Main(String[] args) in c:\users\user\documents\visual studio 2010\Projects\ConsoleApplication7\ConsoleApplication7\Program.cs
What can be the problem?
To provide more information, i bought the private socks connection on this page: http://rapidsocks.com/
this services give me a list of IP and port who in really is not a proxy .. just a connection that give me a proxyIP:proxyPort from a pool on server in response...
How to get that answer with proxyIP:proxyPort from the server?
In UDP land, one way this can occur is when you send a UDP packet to a host, and the remote host doesn't have a listener on that port, and bounces an ICMP host unreachable message in response.
In plain English, what this exception tells you that no process is listening on the far-end on that port.
Update: You should be able to avoid that behavior with the following code:
var udpClient = new UdpClient();
uint IOC_IN = 0x80000000;
uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
udpClient.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
Microsoft Article 263823 said this on the subject: [hard to find as of 2019]
SYMPTOMS
In Windows 2000, a User Datagram Protocol (UDP) program may
not work and may generate a WSAECONNRESET response.
CAUSE
If sending a datagram using the sendto function results in an
"ICMP port unreachable" response and the select function is set for
readfds, the program returns 1 and the subsequent call to the recvfrom
function does not work with a WSAECONNRESET (10054) error response. In
Microsoft Windows NT 4.0, this situation causes the select function to
block or time out.
RESOLUTION
A new sockets IOCTL called "SIO_UDP_CONNRESET" has been
introduced in Windows 2000. When this IOCTL is used, the program must
be rewritten specifically for Windows 2000 to obtain the original
Windows NT 4.0 behavior. Windows NT 4.0, Microsoft Windows 95, and
Microsoft Windows 98 have no support for this new IOCTL. In addition
to rewriting your application, you will need the hotfix referenced
further down in this article.
This really is a generic error message that could mean anything. Time to get the low level network traffic sniffers to filter what is actually going wrong. Adding extra error handling try catch blocks on the server with decent logging is always a great place to start.
I want to establish connection with server and communicate with ActiveMQ running on that server
I take code from MSDN:
TcpClient client = new TcpClient(machineName, port); // ActiveMQ is running on that port on the server
Console.WriteLine("Client connected.");
SslStream sslStream = new SslStream(
client.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
try
{
sslStream.AuthenticateAsClient(machineName, certificates, SslProtocols.Tls, true);
}
catch (AuthenticationException e)
{
Console.WriteLine("Exception: {0}", e.Message);
if (e.InnerException != null)
{
Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
}
Console.WriteLine("Authentication failed - closing the connection.");
client.Close();
return;
}
and I am able to establish connection. I send request to the server:
byte[] messsage = Encoding.UTF8.GetBytes("Hello from the client.<EOF>");
// Send hello message to the server.
sslStream.Write(messsage);
sslStream.Flush();
// Read message from the server.
string serverMessage = ReadMessage(sslStream);
Console.WriteLine("Server says: {0}", serverMessage);
In the response, server says:
?ActiveMQ y TcpNoDelayEnabled SizePrefixDisabled CacheSize ProviderName
ActiveMQ StackTraceEnabled PlatformDetails TJVM: 1.8.0_202, 25.202-b08, Oracle Corporation, OS: Windows Server
So, it means communication with Server AMQ established. My question is, how can I use now that AMQ channel for sending and receiving messages? Normally, I have to specify message queue I want to use. How and where I have to do that?
Should it be in message I send to server? Something like:
string message_queue = "test.message.tosend";
byte[] request = Encoding.UTF8.GetBytes(String.Format(<formatted queue name with message content>, machineName));
Example of code would be very much appreciated.
ActiveMQ is a message broker which supports lots of different messaging protocols (e.g. OpenWire, AMQP 1.0, STOMP, & MQTT). Each of these protocols is similar in that they support the exchange of messages between a client and the broker, but they are different in what specific functionality they support, their protocol handshakes, wire formats, etc.
For whatever reason you are not using any of the client implementations for these protocols. You are using the low level TcpClient which means you'll need to find the specification for the protocol you wish to speak (e.g. AMPQ 1.0, STOMP 1.2) and implement a client for it. Depending on the protocol you choose this could be a significant amount of work.
However, instead of reimplementing a client you could use one which already exists, e.g.:
AmqpNetLite
Stomp.Net
MQTTnet
I followed the example in MSDN about C# socket programming.
private static void StartClient() {
// Connect to a remote device.
try {
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect( remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// Send test data to the remote device.
Send(client,"This is a test<EOF>");
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Response received : {0}", response);
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
I've created a simple test application that works.
The app sends and receives the response almost instantaneous.
So now the challenge is to implement the solution where the socket connects to an external device that will process the information from the socket and then send back a response.
At the line "Send test data to the remote device" --> the device receives this information at processes.
The debug keeps on going. The process is still going on in the remote device because I can see the data churning away.
But once it gets to receiveDone.WaitOne(); the debug is gone and the application hangs.
The problem here is the remote server is still processing. When it is done it is supposed to send back a response. Nothing happens.
Since I'm not that experienced with socket coding, I was wondering if anyone has run into this before. And if yes, how would I go about solving this issues so I can get a response back and the application doesn't hang?
Update:
I feel like smacking myself in the head.
The issue isn't with the WaitOne().
The debug is gone from WaitOne() because it's waiting for a response.
When the response comes, it goes to Receive() which then calls ReceiveCallback().
private void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
//THIS IS WHERE THE CODE DOESN'T CONTINUE.
}
catch (Exception e)
{
string error = e.InnerException.ToString();
}
}
When ReceiveCallback() is complete and it finishes getting all the data - it stops. It doesn't go back to my code where I initiate the sending and receiving of data.
It's supposed to go:
1. Get input request string
2. Pass it to the socket code
3. Socket code sends input request string
4. Socket code receives response string
5. Take the response string and do something with it
So it stops at #4 and ends without completing all the steps.
Am i missing code for it to continue the flow? Or have I set the process up incorrectly?
Thanks again for the help.
#John - thanks for updating my title. I'll try to keep the title in mind for the future.
========================================
UPDATE 2:
If I change the code and do not use the Receive() as it is in the MSDN sample, MSDN sample link and do something like:
var response = client.Receive(buffer);
var message = Encoding.ASCII.GetString(buffer);
This would work and everything continues. I need to make sure that the response isn't cut off though. But then that would defeat the purpose of it by async client correct?
Hmm....
thanks again for everyone's input.
OK. I got it after seeing how I went wrong.
I didn't check for the end response. I assumed that the end of the buffer transmission would set off the method that would return the response.
Thanks to everyone for your help. I couldn't have come to the solution without your help.
cheers!
Apparently ICMP isn't the only way to create a Traceroute. This and this answer indicates it's possible to send a UDP packet (or any other) with a low TTL and wait for the ICMP message.
How would I go about implementing this in C#? System.IO.Sockets? The TCP objects? Anyone know of an easy/best way?
Update 1:
The following code seems to correctly throw an exception when the TTL is hit. How do I extract information from the returned UDP Packet?
How do I know that the UDP packet I'm receiving is intended for me (and not some other application on my host?)
public void PingUDPAsync(IPAddress _destination, short ttl)
{
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient(21000);
udpClient.Ttl = ttl;
// udpClient.DontFragment = true;
try
{
udpClient.Connect(_destination, 21000);
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("Is anybody there?");
udpClient.Send(sendBytes, sendBytes.Length);
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " +
returnData.ToString());
Console.WriteLine("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());
udpClient.Close();
}
catch (SocketException socketException)
{
Console.WriteLine(socketException.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
Yes, System.Net.Sockets should provide you all the primitive objects you would need to send/receive UDP/TCP packets. Plenty of documentation and samples online, the two articles you included in your question are very interesting and a good starting point :)
https://learningnetwork.cisco.com/thread/87497
You can check out the answer here that goes into detail on Cisco's UPD traceroute implementation. It is rather comprehensive and can easily adapted to target a specific UDP port. You do not get a UDP packet back from the target. Rather, you get an ICMP reply to indicate the traffic was not received. The UDP packet that you originate has a random response port number included and your host tracks what ports are used by what applications. When the ICMP response is sent back, it is sent to the host IP and the response port included in the UDP header. Your host will then see the port and know it is bound to your application. It then delivers the packet to your application.
I need to obtain UDP datagram from Asynchronous Socket Server but an exception occurred in my application :
Problem appear there :
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
The full source code:
class Program
{
static void Main(string[] args)
{
const int PORT = 30485;
IPAddress IP;
IPAddress.TryParse("92.56.23.87", out IP);
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient(PORT);
Socket receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
try
{
udpClient.Connect("92.56.23.87", PORT);
if (udpClient.Client.Connected)
Console.WriteLine("Connected.");
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("CONNECT");
udpClient.Send(sendBytes, sendBytes.Length);
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IP, PORT);
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " + returnData.ToString());
Console.WriteLine("This message was sent from " + RemoteIpEndPoint.Address.ToString() + " on their port number " + RemoteIpEndPoint.Port.ToString());
udpClient.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
Exception:
Connected.
System.Net.Sockets.SocketException (0x80004005): An existing connection
was forcibly closed by the remote host at System.Net.Sockets.Socket.ReceiveFrom(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint& remoteEP) at ystem.Net.Sockets.UdpClient.Receive(IPEndPoint& remoteEP) at ConsoleApplication7.Program.Main(String[] args) in c:\users\user\documents\visual studio 2010\Projects\ConsoleApplication7\ConsoleApplication7\Program.cs
What can be the problem?
To provide more information, i bought the private socks connection on this page: http://rapidsocks.com/
this services give me a list of IP and port who in really is not a proxy .. just a connection that give me a proxyIP:proxyPort from a pool on server in response...
How to get that answer with proxyIP:proxyPort from the server?
In UDP land, one way this can occur is when you send a UDP packet to a host, and the remote host doesn't have a listener on that port, and bounces an ICMP host unreachable message in response.
In plain English, what this exception tells you that no process is listening on the far-end on that port.
Update: You should be able to avoid that behavior with the following code:
var udpClient = new UdpClient();
uint IOC_IN = 0x80000000;
uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
udpClient.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
Microsoft Article 263823 said this on the subject: [hard to find as of 2019]
SYMPTOMS
In Windows 2000, a User Datagram Protocol (UDP) program may
not work and may generate a WSAECONNRESET response.
CAUSE
If sending a datagram using the sendto function results in an
"ICMP port unreachable" response and the select function is set for
readfds, the program returns 1 and the subsequent call to the recvfrom
function does not work with a WSAECONNRESET (10054) error response. In
Microsoft Windows NT 4.0, this situation causes the select function to
block or time out.
RESOLUTION
A new sockets IOCTL called "SIO_UDP_CONNRESET" has been
introduced in Windows 2000. When this IOCTL is used, the program must
be rewritten specifically for Windows 2000 to obtain the original
Windows NT 4.0 behavior. Windows NT 4.0, Microsoft Windows 95, and
Microsoft Windows 98 have no support for this new IOCTL. In addition
to rewriting your application, you will need the hotfix referenced
further down in this article.
This really is a generic error message that could mean anything. Time to get the low level network traffic sniffers to filter what is actually going wrong. Adding extra error handling try catch blocks on the server with decent logging is always a great place to start.