HTTP over UDP adapter for Web API - c#

I need to send some data from mobile clients to an ASP.NET ApiController. I cannot wait for an connection to be established (and I don't rely on the data to arrive), so I thought UDP is the way to go. On the server I need to listen on a UDP endpoint and redirect the request to my default HTTP endpoint.
This is what I have so far (shortened):
public class HttpOverUdpAdapter
{
public static UdpClient UpdListener;
public static void Start(int udpPort, tcpPort)
{
UpdListener = new UdpClient(udpPort);
new Thread(() =>
{
while (true)
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, udpPort);
byte[] bytes = UpdListener.Receive(ref endpoint);
TcpClient client = new TcpClient();
client.Connect(IPAddress.Loopback, tcpPort);
using (NetworkStream stream = client.GetStream())
{
stream.Write(bytes, 0, bytes.Length);
}
}
}).Start();
}
}
I get the following error when no matter what port I use:
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.
Apart from that, is this going to work out at all? Is it correct to start it in Application_Start()?
Remark: WCF is no alternative.

There is no such thing as "I don't rely on the data to arrive" with HTTP. HTTP consists of requests and responses, which are usually big enough so that multiple IP packets are needed. UDP does neither guarantee the delivery nor the order of the packets, so you might end up with corrupt requests which might result in no response (which might be ok for you) or in a response for another web resource (which is probably not ok). Also, the response can be corrupt too in an unpredictable way (which is probably not ok for you).
If you would a need a more reliable transport you would add a reliability layer on top of the UDP tunnel, which is neither simpler nor faster than simply using TCP directly.

Related

Using Webclient ontop of already created TCP Socket

I need to communicate via a HTTP-Rest interface with a device.
I cannot create a connection to this device actively.
This device is creating a TCP-Socket with my program. So, I am listening on a port for this device.
After the Socket is created, I need to send HTTP-Requests to this device on top of that socket. I Am acting as HTTP-Client and the device is acting as HTTP-Server.
I cannot use WebClient for that as it creates its own TCP-Socket. But the socket as I said is already created.
My fist question would be: Is there still a way to use WebClient or another alternative to create the HTTP-Requests and read out the Responses?
If I cannot use Webclient I need to implement it by myself.
I saw that it is possible to use WebClient to create HTTP Header Bytes:
void SendHTTPRequest(string message)
{
//create Header Bytes
WebClient web = new WebClient();
web.Headers.Set(HttpRequestHeader.Connection, "keep-alive");
web.Headers.Set(HttpRequestHeader.Accept, "*/*");
web.Headers.Set(HttpRequestHeader.AcceptEncoding, "gzip, deflate, br");
//Built list with request bytes
List<byte> bytesToSend = new List<byte>();
bytesToSend.AddRange(Encoding.ASCII.GetBytes(message));
bytesToSend.AddRange(web.Headers.ToByteArray());
//Send request to the device
WriteBytes(bytesToSend.ToArray());
}
My Second Question would be: Is there a way to decode the HTTP-Headers out of the received bytes from the response? So that I only need to implement the write and read methods for the HTTP-Body.

How to get the requested target host from an SslStream as a server

With this code, for example:
private static void OnConnect(IAsyncResult ar)
{
var clientConnection = listener.EndAcceptTcpClient(ar);
listener.BeginAcceptTcpClient(OnConnect, ar.AsyncState);
try
{
// SSL the client
var clientStream = clientConnection.GetStream();
var clientSecureStream = new SslStream(clientStream, false);
clientSecureStream.AuthenticateAsServer(certificate);
...
...
I'm able to successfully establish an incoming SSL connection. The client that is connecting to this server specifies a target host when authenticating as a client:
https://learn.microsoft.com/en-us/dotnet/api/system.net.security.sslstream.authenticateasclient?view=netframework-4.7.2#System_Net_Security_SslStream_AuthenticateAsClient_System_String_
How do I retrieve the value of this target host in my code above?
I've looked into the RemoteCertificateValidationCallback parameter for the SslStream constructor, but the internet is telling me that this callback is only meant for client side, and not server side (I tried it and the targetHost argument is always an empty string).
I've searched here and online and I'm having trouble finding a solution...
Should an SslServer not be able to send different data depending on the target host? Does SslStream just not support this scenario? Am I missing some concept completely?

How to bind a specific port on a webclient object in C#

I am working on P2P application, I want to use the hole punching technique to connect peers.
here is my PHP third party Server Script.
<?php
echo "{yourIP:'".$_SERVER['REMOTE_ADDR']."',yourPort:".$_SERVER['REMOTE_PORT']."}";
?>
In my C# code I created a server socket which listens to 8765, when i want to get my public IP address and port number (in order to share with the peers), I send a request to php server using WebClient Object. The problem is the webclient object uses random local port to make request.
How to bind a webclient object to 8765 port? so that always the requests use this port as source port.
thanks!
Sorry for my poor english! :)
You will not be able to achieve this with WebClient, you can however solve it using HttpWebRequest:
public static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
{
Console.WriteLine("BindIPEndpoint called");
return new IPEndPoint(IPAddress.Any,5000);
}
public static void Main()
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create("http://MyServer");
request.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(BindIPEndPointCallback);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
}

C# Proxy Server: how to send/receive data with sockets?

I'm trying to create a simple proxy server in C#. Below is a portion of my code where I created a socket with the host name that was parsed from the browser HTTP request. The full request is in the string "header" and is sent to the destination socket. Then the while loop receives the response from the socket and sends it to the client socket.
Socket destServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
destServerSocket.Connect(host, 80);
destServerSocket.Send(ASCIIEncoding.ASCII.GetBytes(header));
byte[] response = new byte[1];
while (destServerSocket.Receive(response) != 0)
{
client.Send(response);
}
destServerSocket.Disconnect(false);
destServerSocket.Dispose();
client.Disconnect(false);
client.Dispose();
Right now my proxy only works with simple html sites. Anything else and it just endlessly loads without ever displaying any content in the browser. How do I alter my code to allow my proxy server to work on websites that are more complex than basic html ones?

How to receive/send file, data on .net(C#) Sockets and distinguish them

I have async Server and async Client on .net Sockets.
Client creates object(for example class UserInfo), serializes him, and writes in byte[].
Also Client has some file(1.png for example).
Client need to sent serialized UserInfo and 1.png to the server.
I use for file,
Socket.BeginSendFile Method (String, AsyncCallback, Object)
and for byte[] object
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
Server must receive this date together and understand what is file and what is serizalize object(because server has only one method for receive data).
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
...
AcceptCallback(IAsyncResult ar)
{...
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
and our logic in
ReadCallback(IAsyncResult ar)
{...}
How to receive this data correctly? In finally i need that server has 1.png and UserInfo object.(and distinguish them). Moreover, because the server is asynchronous, it should not be confused when receiving data from multiple clients simultaneously
i have one idea, but i think this is wrong:
Try to use on a client
Socket.BeginSendFile Method (String, Byte[], Byte[], TransmitFileOptions, AsyncCallback, Object)
with byte[] preBuffer, where i will write header, such this "..."
and on server i try to find this header, cut it, analyse and do some activity.
Is there a way easier and more correct?
Thanks.
Each channel (socket) should have definite and known protocol, in terms of implementation - well known type of objects. So introduce a main class which will encapsulate all data which could be sent via this socket:
public interface IPacketWrapper
{
IEnumerable<byte> Payload { get; }
UserInfo UserDetails { get; }
}
So client and server exchange by objects which implements IPacketWrapper so you can put together both binary data and UserInfo, then serialize/deserialize this object on client/server side respectively.

Categories