Network traffic encryption - c#

I have a proxy program which resend network traffic. It listens specific port, and addresses server with another port. It works, but I need to add some encryption between 2 instances of my proxy. When encryption is not enabled two sequential proxy work good, but with encryption don't work. Here is code:
public class CommunicationContext
{
/// <summary>Define buffer max size. Influence on memory usage.</summary>
public const int MaxBuffer = 16 * 1024;
/// <summary>Unique counter...</summary>
private static int _uniqueCounter = 0;
public readonly Socket SocketIn;
public readonly Socket SocketOut;
public readonly PortMapping Mapping;
public byte[] BufferIn;
public byte[] BufferOut;
public bool IsShutdown;
public readonly object SyncObject = new object();
public readonly int UniqueId;
public CommunicationContext(Socket socketIn, Socket socketOut, PortMapping map){
SocketIn = socketIn;
SocketOut = socketOut;
Mapping = map;
UniqueId = Interlocked.Increment( ref _uniqueCounter );
}
public void InitializeBuffers(){
this.BufferIn = new byte[MaxBuffer];
this.BufferOut = new byte[MaxBuffer];
}
}
private static void ReadInputSocket( IAsyncResult ar ){
CommunicationContext context = (CommunicationContext)ar.AsyncState;
try{
int length = context.SocketIn.EndReceive( ar );
if( length <= 0 )
throw new NoDataSocketException();
lock( context.SyncObject ){
Switches.GeneralLog.Verbose( "==> Client data size: " + length );
SocketFlags flags = ( context.SocketIn.Available == 0 ) ? SocketFlags.None : SocketFlags.Partial;
if(!CryptoTools.CryptEnabled){
//without encrypion works fine
}
else if(CryptoTools.CryptInner){
context.BufferIn = CryptoTools.Crypt(context.BufferIn);
}else{
context.BufferIn = CryptoTools.Decrypt(context.BufferIn);
}
context.SocketOut.Send(context.BufferIn, 0, length, flags);
}
Thread.Sleep( 0 );
context.SocketIn.BeginReceive(context.BufferIn, 0, MaxBuffer, SocketFlags.None, ReadInputSocket, context);
}
catch( Exception ex ){
Switches.GeneralLog.Verbose( ex );
Switches.GeneralLog.Info( ex.Message );
ShutdownCommunication( context );
}
}
private static void ReadOutputSocket(IAsyncResult ar ){
CommunicationContext context = (CommunicationContext)ar.AsyncState;
try{
int length = context.SocketOut.EndReceive( ar);
if( length <= 0 )
throw new NoDataSocketException();
lock( context.SyncObject )
{
Switches.GeneralLog.Verbose( "<== Server data size: " + length );
SocketFlags flags = ( context.SocketOut.Available == 0 ) ? SocketFlags.None : SocketFlags.Partial;
if (!CryptoTools.CryptEnabled){
//without encrypion works fine
}
else if (CryptoTools.CryptInner){
context.BufferOut = CryptoTools.Decrypt(context.BufferOut);
}
else{
context.BufferOut = CryptoTools.Crypt(context.BufferOut);
}
context.SocketIn.Send(context.BufferOut, 0, length, flags);
}
context.SocketOut.BeginReceive(context.BufferOut, 0, MaxBuffer, SocketFlags.None, ReadOutputSocket, context);
}
catch( Exception ex )
{
Switches.GeneralLog.Verbose( ex );
Switches.GeneralLog.Info( ex.Message );
ShutdownCommunication( context );
}
}
Edit from comments:
What not works: Data keep getting corrupted.
I get no exceptions. Just malformed data. I used different methods for Crypt/Decrypt. I made them even both equal - simple XOR. Encryption algorithm has not significance, for example, XOR was used.
My configuration is like this Client <--> Proxy1 <--enc--> Proxy2 <---> Server. Between two proxies must be the encrypted stream.

Related

How to get port a process is listening on in .net?

As several blogposts and Stackoverflow answers suggest, it is trivial to get this information via a combination of get-process and Get-NetTCPConnection commandlets. It is possible to execute these commands via .net code, parse the output and retrieve the information.
Is it not possible to get the port number a process is listening on in pure .net code using just the .net libraries? System.Diagnostics.Process.GetProcesByName returns a ton of information via the Process object, except for the port the process is listening on.
Any leads highly appreciated.
Unfortunately, IPGlobalProperties.GetIPGlobalProperties() does not return any information on which process is holding the socket, as it uses GetTcpTable not GetTcpTable2.
You would need to code it yourself. The below code works for TCP over IPv4. You would need similar code for UDP and IPv6.
[DllImport("Iphlpapi.dll", ExactSpelling = true)]
static extern int GetTcpTable2(
IntPtr TcpTable,
ref int SizePointer,
bool Order
);
[StructLayout(LayoutKind.Sequential)]
struct MIB_TCPTABLE
{
public int dwNumEntries;
}
[StructLayout(LayoutKind.Sequential)]
struct MIB_TCPROW2
{
public MIB_TCP_STATE dwState;
public int dwLocalAddr;
public byte localPort1;
public byte localPort2;
// Ports are only 16 bit values (in network WORD order, 3,4,1,2).
// There are reports where the high order bytes have garbage in them.
public byte ignoreLocalPort3;
public byte ignoreLocalPort4;
public int dwRemoteAddr;
public byte remotePort1;
public byte remotePort2;
// Ports are only 16 bit values (in network WORD order, 3,4,1,2).
// There are reports where the high order bytes have garbage in them.
public byte ignoreremotePort3;
public byte ignoreremotePort4;
public int dwOwningPid;
public TCP_CONNECTION_OFFLOAD_STATE dwOffloadState;
}
public enum MIB_TCP_STATE
{
Closed = 1,
Listen,
SynSent,
SynRcvd,
Established,
FinWait1,
FinWait2,
CloseWait,
Closing,
LastAck,
TimeWait,
DeleteTcb
}
enum TCP_CONNECTION_OFFLOAD_STATE
{
TcpConnectionOffloadStateInHost,
TcpConnectionOffloadStateOffloading,
TcpConnectionOffloadStateOffloaded,
TcpConnectionOffloadStateUploading,
TcpConnectionOffloadStateMax
}
static List<IPEndPoint> GetSocketsForProcess(int pid, MIB_TCP_STATE state = MIB_TCP_STATE.Established)
{
const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
var size = 0;
var result = GetTcpTable2(IntPtr.Zero, ref size, false);
if (result != ERROR_INSUFFICIENT_BUFFER)
throw new Win32Exception(result);
var ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(size);
result = GetTcpTable2(ptr, ref size, false);
if (result != 0)
throw new Win32Exception(result);
var list = new List<IPEndPoint>();
var count = Marshal.ReadInt32(ptr);
var curPtr = ptr + Marshal.SizeOf<MIB_TCPTABLE>();
var length = Marshal.SizeOf<MIB_TCPROW2>();
for(var i = 0; i < count; i++)
{
var row = Marshal.PtrToStructure<MIB_TCPROW2>(curPtr);
if(row.dwOwningPid == pid && row.dwState == state)
list.Add(new IPEndPoint(row.dwLocalAddr, row.localPort1 << 8 | row.localPort2));
curPtr += length;
}
return list;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
I had similar task not long ago. Here is complete .NET 6 code that you should be able to adopt for your particular needs:
public static int CheckConnection(string[] servers)
{
try
{
var srvs = servers.ToDictionary(k => k.Split("/", StringSplitOptions.RemoveEmptyEntries)[1], v => false);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] endPoints = ipProperties.GetActiveTcpListeners();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();
var count = 0;
foreach (var info in tcpConnections)
{
var ep = string.Format("{0}:{1}", info.RemoteEndPoint.Address, info.RemoteEndPoint.Port);
if (info.State.ToString().ToUpper() != "ESTABLISHED")
continue;
if (srvs.ContainsKey(ep))
{
count++;
srvs[ep] = true;
}
}
var sb = new StringBuilder();
foreach (var kvp in srvs)
{
sb.AppendFormat("{0,-21}: {1}", kvp.Key, kvp.Value ? "OK" : "FAIL");
sb.AppendLine();
}
Program.logger.Trace($"ZMQF. Connection check:\n{sb}");
return count;
}
catch (Exception ex)
{
Program.logger.Fatal(ex, $"ZMQF. CheckConnection exception. Servers: {(string.Join(",", servers))}");
return -1;
}
}

C# Socket ReceiveAsync

I am used to sync sockets and had a few headaches to get to the point where I am now, especially with Socket.Receive(..) not always receiveing all bytes
Here is my code what I used to use
public byte[] Receive(int size)
{
var buffer = new byte[size];
var r = 0;
do
{
// ReSharper disable once InconsistentlySynchronizedField
var c = _clientSocket.Receive(buffer, r, size - r, SocketFlags.None);
if (c == 0)
{
throw new SocketExtendedException();
}
r += c;
} while (r != buffer.Length);
return buffer;
}
Now I started to use sockets in Windows Phone BUT .Receive(..) is not available and I managed to get Socket.ReceiveAsync(..) working but I am concerned (no problems happened so far) here is my new code, I have not implemented the checking if all bytes has been recieved or not nor do I know if I have to with the following code
private byte[] ReadBySize(int size = 4)
{
var readEvent = new AutoResetEvent(false);
var buffer = new byte[size];
var recieveArgs = new SocketAsyncEventArgs()
{
UserToken = readEvent
};
recieveArgs.SetBuffer(buffer, 0, size);
recieveArgs.Completed += recieveArgs_Completed;
_connecter.ReceiveAsync(recieveArgs);
readEvent.WaitOne();
if (recieveArgs.BytesTransferred == 0)
{
if (recieveArgs.SocketError != SocketError.Success)
throw new SocketException((int)recieveArgs.SocketError);
throw new CommunicationException();
}
return buffer;
}
void recieveArgs_Completed(object sender, SocketAsyncEventArgs e)
{
var are = (AutoResetEvent)e.UserToken;
are.Set();
}
This is my first use of ReceiveAsync can someone point out anything I might have done wrong or need to change
Ok I went and took a large buffer and send it in batches with a sleep interval in between to replicate 'not all bytes received' So my code above doesn't recieve all bytes. for those who also use ReceiveAsync(..) here is my code that works
private byte[] ReadBySize(int size = 4)
{
var readEvent = new AutoResetEvent(false);
var buffer = new byte[size]; //Receive buffer
var totalRecieved = 0;
do
{
var recieveArgs = new SocketAsyncEventArgs()
{
UserToken = readEvent
};
recieveArgs.SetBuffer(buffer, totalRecieved, size - totalRecieved);//Receive bytes from x to total - x, x is the number of bytes already recieved
recieveArgs.Completed += recieveArgs_Completed;
_connecter.ReceiveAsync(recieveArgs);
readEvent.WaitOne();//Wait for recieve
if (recieveArgs.BytesTransferred == 0)//If now bytes are recieved then there is an error
{
if (recieveArgs.SocketError != SocketError.Success)
throw new ReadException(ReadExceptionCode.UnexpectedDisconnect,"Unexpected Disconnect");
throw new ReadException(ReadExceptionCode.DisconnectGracefully);
}
totalRecieved += recieveArgs.BytesTransferred;
} while (totalRecieved != size);//Check if all bytes has been received
return buffer;
}
void recieveArgs_Completed(object sender, SocketAsyncEventArgs e)
{
var are = (AutoResetEvent)e.UserToken;
are.Set();
}
The way I work with my Socket applications is to send a Buffer that consist of some variables
[0] -> 0,1,2 0 is keep alive, 1 means there are data, 2 means a type off error occured
[1,2,3,4] size of the actual buffer I am sending
[x(size of 1,2,3,4)] the actual 'Serialized' data buffer
You could create a socket extension like:
public static Task<int> ReceiveAsync(this Socket socket,
byte[] buffer, int offset, int size, SocketFlags socketFlags)
{
if (socket == null) throw new ArgumentNullException(nameof(socket));
var tcs = new TaskCompletionSource<int>();
socket.BeginReceive(buffer, offset, size, socketFlags, ar =>
{
try { tcs.TrySetResult(socket.EndReceive(ar)); }
catch (Exception e) { tcs.TrySetException(e); }
}, state: null);
return tcs.Task;
}
And then a method to read the size you want like this:
public static async Task<byte[]> ReadFixed(Socket socket, int bufferSize)
{
byte[] ret = new byte[bufferSize];
for (int read = 0; read < bufferSize; read += await socket.ReceiveAsync(ret, read, ret.Length - read, SocketFlags.None)) ;
return ret;
}

Sending lots data disconnects the server

I'm building a network library to use in further projects, I know a bit of networking (in general and programming) but I still encounter problems when I want to transfer larger packets on a high frequency. How would this be possible in TCP?
One possible solution would be chuncking, that is not a problem at all I'll just put them in a buffer and have the whole packet again. This causes overhead at the server, handling lots of data is consuming lots of resources. And it affects the stability because the server get somewhere stuck and the client throws an ObjectDisposedException at BeginSend (connection is closed). Of course its probably my fault but consider a 'relative' small packet of 2048 bytes (2 kB) which get chunked in 512 bytes (4 chunks):
//main.cs
static void Main(string[] args)
{
client = new Client("82.72.201.150", 2345);
client.SendCompleted += OnSend;
Console.WriteLine(client.Connect());
var bytes = new byte[2048];
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)((i*i + 0x25)%byte.MaxValue);
}
while (true)
{
SendChuncked(bytes);
Thread.Sleep(500);
}
}
static void SendChuncked(byte[] buffer, int chunksize = 512)
{
var chunks = buffer.Length/chunksize;
var rest = buffer.Length%chunksize;
var size = BitConverter.GetBytes(buffer.Length);
client.Send(size, 0, size.Length);
for (int i = 0; i < chunks; i++)
{
client.Send(buffer, i * chunksize, chunksize);
}
if (rest > 0)
client.Send(buffer, chunks * chunksize, rest);
}
//....
//client.cs
public struct TransferState
{
public byte[] buffer;
public int offset;
public int count;
public int handled;
public ManualResetEvent waitHandle;
public bool wait;
}
public void Send(byte[] buffer, int offset, int count)
{
var size = BitConverter.GetBytes(count);
Send(size, 0, size.Length, true);
Send(buffer, offset, count, false);
}
private void Send(byte[] buffer, int offset, int count, bool wait, TransferState? state = null)
{
state = state ?? new TransferState
{
buffer = buffer,
offset = offset,
count = count,
handled = 0,
wait = wait,
waitHandle = new ManualResetEvent(false)
};
socket.BeginSend(buffer, offset, count, SocketFlags.None, SendCallback, state);
if (wait)
{
((TransferState) state).waitHandle.WaitOne();
}
}
private void Send(byte[] buffer, int offset, int count, bool wait, TransferState? state = null)
{
state = state ?? new TransferState
{
buffer = buffer,
offset = offset,
count = count,
handled = 0,
wait = wait,
waitHandle = new ManualResetEvent(false)
};
socket.BeginSend(buffer, offset, count, SocketFlags.None, SendCallback, state);
if (wait)
{
((TransferState) state).waitHandle.WaitOne();
}
}
private void SendCallback(IAsyncResult result)
{
if (result.AsyncState is TransferState == false)
throw new ArgumentException("Invalid type of state.", "state");
var state = (TransferState)result.AsyncState;
var sent = socket.EndSend(result);
state.handled += sent;
var tosent = state.count - state.handled;
var offset = state.offset + state.handled;
if (tosent > 0)
{
Send(state.buffer, offset, tosent, state.wait, state);
}
else
{
state.waitHandle.Set();
SendCompleted(this, new TransferCompletedArgs(this, state));
}
}
//....
public void Receive(TransferState? state = null)
{
if (state == null)
{
var buffer = new byte[sizeof(int)];
socket.BeginReceive(buffer, 0, sizeof (int), SocketFlags.None, ReceiveCallback, buffer);
}
else
{
var transferState = state.Value;
socket.BeginReceive(transferState.buffer, transferState.offset, transferState.count - transferState.handled, SocketFlags.None, ReceiveCallback, transferState);
}
}
private void ReceiveCallback(IAsyncResult result)
{
//receiving the amount to receive
if (result.AsyncState is byte[])
{
var buffer = (byte[])result.AsyncState;
var rec = socket.EndReceive(result);
if (rec != 4) //TODO: HANDLE MORE PROPERLY
throw new NotImplementedException("Error while receiving the amoount to receive.");
var toreceive = BitConverter.ToInt32(buffer, 0);
var state = new TransferState
{
buffer = new byte[toreceive],
count = toreceive,
wait = false
};
Receive(state);
}
//know we know the amount we can receive it till the end
else if (result.AsyncState is TransferState)
{
var state = (TransferState)result.AsyncState;
var rec = socket.EndReceive(result);
state.offset += rec;
state.handled += rec;
var toreceive = state.count - state.handled;
if (toreceive > 0)
{
Receive(state);
Debug.WriteLine("[{2}] size mismatch: {0}/{1}", state.handled, state.count, DateTime.Now.ToString("mm:ss.fff"));
}
else
{
ReceiveCompleted(this, new TransferCompletedArgs(this, state));
Receive();
}
}
else
{
throw new ArgumentException("State is not typeof byte[] or TransferState.");
}
}
So if its hard to follow:
The client tries to connect with the server
The server accepts
the client
The client first sends how long the buffer is
The
client starts sending the buffer (and loops this)
The server reads
how long the buffer is and allocates a buffer for it
The server
reads until the buffer is read and invokes an event (and loops this
proces as well)
So I don't know what actually happens, but the server stops receiving. While connected clients still sending data, after couple seconds an ObjectDisposedException is thrown at BeginSend. How would I resolve this from happening? (And have a stable server that can handle lots of traffic.)

Sockets in C++ and C# under Windows not working properly

I'm using UDP sockets to communicate a C++ application with a C# application.
In the C# -> C++ direction everything seems to be working fine, but the other way around is the one that's driving me nuts.
Communication does work, but messages are getting way late (like 2 secs delay) in the C# app, even though they're being sent every frame (it's a 3D app), and the receiving code is executing every 10 ms.
I need real time so this is a very painful problem. Do you think this might be related to packet losses? Then why don't they get lost in the other direction?
EDIT:
C# app code for syncing data:
public void RecibeDatos()
{
if (MessageReceived && U != null && S != null)
{
MessageReceived = false;
//Console.WriteLine("listening for messages");
U.BeginReceive(ReceiveCallback, S);
}
}
public void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = ((UdpState)(ar.AsyncState)).U;
IPEndPoint e = ((UdpState)(ar.AsyncState)).E;
receivedBytes = u.EndReceive(ar, ref e);
//int currentProtocol = (int) numero;
//ResetSignal = reset > 0;
//Console.WriteLine("Received: " + currentProtocol);
MessageReceived = true;
}
C++ Code for sending data:
float indiceFloat[1];
indiceFloat[0] = indice_protocolo_actual;
sender->setBuffer((void *)indiceFloat, sizeof(indiceFloat));
sender->sync();
sync method on J_Enviar (sender) class:
void J_Enviar::sync( void )
{
if(!_initialized) init();
if( _buffer == 0L )
{
fprintf( stderr, "Broadcaster::sync() - No buffer\n" );
return;
}
#if defined (WIN32) && !defined(__CYGWIN__)
unsigned int size = sizeof( SOCKADDR_IN );
sendto( _so, (const char *)_buffer, _buffer_size, 0, (struct sockaddr *)&saddr, size );
int err = WSAGetLastError ();
if (err!=0)
fprintf( stderr, "Broadcaster::sync() - error %d\n",err );
#else
unsigned int size = sizeof( struct sockaddr_in );
sendto( _so, (const void *)_buffer, _buffer_size, 0, (struct sockaddr *)&saddr, size );
#endif
}
Providing full SocketManager code for Receiving C# end:
using System;
using System.Net;
using System.Net.Sockets;
namespace WpfApplication1
{
public class SocketManager
{
private static SocketManager _instance = null;
static readonly object Padlock = new object();
private IPEndPoint E;
private UdpClient U;
private UdpState S;
private byte[] receivedBytes;
public static bool MessageReceived = true;
private SocketManager()
{
}
public byte[] ReceivedBytes
{
get { return receivedBytes; }
}
public static SocketManager Instance
{
get
{
lock(Padlock)
{
return _instance ?? (_instance = new SocketManager());
}
}
}
public void CreateReceivingSocket(IPAddress a, int puerto)
{
if(E==null || (E.Address != a && E.Port != puerto))
{
E = new IPEndPoint(a, puerto);
U = new UdpClient(puerto);
S = new UdpState { E = E, U = U };
}
}
public void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = ((UdpState)(ar.AsyncState)).U;
IPEndPoint e = ((UdpState)(ar.AsyncState)).E;
receivedBytes = u.EndReceive(ar, ref e);
//int currentProtocol = (int) numero;
//ResetSignal = reset > 0;
//Console.WriteLine("Received: " + currentProtocol);
MessageReceived = true;
}
public void RecibeDatos()
{
if (MessageReceived && U != null && S != null)
{
MessageReceived = false;
//Console.WriteLine("listening for messages");
U.BeginReceive(ReceiveCallback, S);
}
}
public void CloseConnection()
{
if (E != null)
{
E.Port = 5502;
E = null;
}
if (U != null)
U.Close();
}
}
public class UdpState
{
public IPEndPoint E;
public UdpClient U;
}
}
And this is my dispatchertimerclick which makes the program receive each 10 ms:
_dispatcherTimer.Tick += DispatcherTimerTick;
_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1);
_dispatcherTimer.Start();
private void DispatcherTimerTick(object sender, EventArgs e)
{
_exp1Class.sendData();
_sm.RecibeDatos();
byte[] recibidos = _sm.ReceivedBytes;
if (recibidos != null)
{
float numero = BitConverter.ToSingle(recibidos, 0);
_exp1Class.CurrentProtocol = (int) numero;
}
}
I don't see when you kick off your first BeginReceive. (Ah, it is done from your first timer tick I think?) It should be initaited as soon as you are ready to receive data. Secondly, your ReceiveCallback should take the received data and place it into a queue of some sort and immediately call BeginReceive again. Otherwise you are holding up thge arrival of the next data frame until the prior was consumed. Finally, watch for threading issues, as the Threading timer and the UDP callback each will run on seperate threads from your application main thread.
The only reason your code works at all is because you pre-initialized MessageReceived = true even before you receive any callbacks. When the first tick happens the call to RecibeDatos invokes BeginReceive because that bool was set to true.
Think of BeginReceive as saying "call me back when you have some data from the network". You don't need to poll the network using your timer. (You can choose to consume that data via your timer if your application requires that, but lets leave that aside for the moment).
Here are the rough steps:
First, upon start (or enable, run, etc) you should call BeginReceive. You will now receive a notification when data arrives.
Secondly, when the callback happens you complete that read of the data bytes using EndReceive. That data would typically be buffered or otherwise dispatched. You should then call BeginReceive again (within the callback) so that upon the next set of data being available you will again get notified. It becomes a kind of async loop.
The question is what to do with the data you are reading. You might consider placing the data into a queue, and then having your Timer pop these data frames off of the queue for processing. Be aware that the data can arrive multiple times between your Ticks.

Arithmetic operation overflow while reading socket in C#

So i decided to start learning it by giving myself some interesting task.
As a web developer i wanted to have my very own WebSocket server.
So i've written it but it only accepts the first request. After that there is Arithmetic operation onverflow.
Here is some code for you to see what am i doing wrong :S I'm really out of ideas.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using WebSocket.Utils;
namespace WebSocket
{
class SocketReader
{
public EndPoint ipAddr { get; set; }
private Socket userSocket;
private byte[] buffer;
private string SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
public SocketReader(Socket socket)
{
userSocket = socket;
ipAddr = socket.RemoteEndPoint;
Read();
}
private void Read()
{
//Read packet size
buffer = new byte[2];
userSocket.BeginReceive(buffer, 0, 2, SocketFlags.None, ReadCallbackStatic, null);
}
private void ReadCallbackStatic(IAsyncResult ar)
{
try
{
if (userSocket.EndReceive(ar) >= 1)
{
int bufferSize = BitConverter.ToInt16(buffer, 0);
buffer = new byte[bufferSize - 2];
//Read Packet
userSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReadCallback, null);
}
}
catch (Exception se)
{
Console.WriteLine("Something blew on ReadCallbackStatic");
Console.WriteLine(se.Message);
Console.WriteLine(se.StackTrace);
Disconnect();
}
}
private void ReadCallback(IAsyncResult ar)
{
try
{
//Copy the buffer so we can receive the next packet ASAP
byte[] buff = new byte[buffer.Length];
Array.Copy(buffer, buff, buffer.Length);
Read();
string handshakeStr = System.Text.Encoding.UTF8.GetString(buff);
string[] list = Regex.Split(handshakeStr, "\r\n");
//Sec-WebSocket-Key: S5o6fCVLRMJhdXTF3H9w3Q==
//Sec-WebSocket-Version: 8
string key = "";
string clientProtocol = "0";
foreach (string str in list)
{
if (String.IsNullOrEmpty(str)) { continue; }
if (str.Length > 20 && str.Substring(0, 19) == "Sec-WebSocket-Key: ")
{
key = str.Substring(19);
continue;
}
if (str.Length > 20 && str.Substring(0, 23) == "Sec-WebSocket-Version: ")
{
clientProtocol = str.Substring(23);
continue;
}
}
if (String.IsNullOrEmpty(key))
{
Disconnect();
}
SHA1 shaEnc = new SHA1CryptoServiceProvider();
byte[] byteString = ASCIIEncoding.ASCII.GetBytes(key + SOCKET_GUID);
byte[] hash = shaEnc.ComputeHash(byteString, 0, byteString.Length);
string acceptKey = Convert.ToBase64String(hash);
List<string> headers = new List<string>();
headers.Add("HTTP/1.1 101 Switching Protocols");
headers.Add("Upgrade: websocket");
headers.Add("Connection: Upgrade");
headers.Add("Sec-WebSocket-Accept: " + acceptKey);
foreach (string header in headers)
{
SendString(header + "\r\n");
}
Console.WriteLine(acceptKey);
SendString("\r\n");
}
catch (SocketException se)
{
Console.WriteLine("Something blew on ReadCallback");
Console.WriteLine(se.Message);
Disconnect();
}
}
private void SendString(string str)
{
userSocket.Send(Encoding.UTF8.GetBytes(str));
}
private void Disconnect()
{
userSocket.Disconnect(false);
Console.WriteLine("Client with ip {0} Disconnected", ipAddr);
}
}
}
It's shortened version of my class but the problem that is bugging me appears in "ReadCallbackStatic" on this line:
buffer = new byte[bufferSize - 2];
i really don't know what am i doing wrong :S.
The thing is that ... i actually handshake properly but then when i sent some information from the client to my server this exception is thrown
I did some debugging and it appears that somehow the buffer variable becomes negative number O.O
My guess would be that you're blowing up when the MSB is set, i.e. maybe the client is sending a number >= 32768 and < 65536, which (via your ToInt16) is becoming a large negative 16-bit number (or, alternatively, throwing an arithmetic overflow issue). I would try using ToUInt16 instead.
To be honest, you really don't need BitConverter here; depending on the endianness this is either:
int bufferSize = (buffer[0] << 8) | buffer[1];
or
int bufferSize = buffer[0] | (buffer[1] << 8);
I believe problem could be in case when buffer contains of zero numbers, so:
int bufferSize = BitConverter.ToInt16(buffer, 0); // 0
buffer = new byte[bufferSize - 2]; // 0 - 2 == -2
Which results in the overflow exception whilst executing new byte[-2]
I do not know the logic behind your code but I believe you should allocate a new buffer considering buffer.Length value

Categories

Resources