using System; using System.Net.Sockets; using System.Threading; using KaduhServer; namespace PatcherServer.FileCheck { public sealed class NormalProxy { private Socket inSocket; private Socket outSocket; private const int MAXBUFFER = 16000; byte[] OutBuffer = new byte[MAXBUFFER]; byte[] InBuffer = new byte[MAXBUFFER]; public bool Connected = true; private LockFreeQueue mInSendSegments = new LockFreeQueue(); private int mInSending = 0; private LockFreeQueue mOutSendSegments = new LockFreeQueue(); private int mOutSending = 0; private string mToIP = ""; public ushort mToPort; bool gotGUID = false; public NormalProxy(Socket sock, ushort toPort, string toIP) { inSocket = sock; mToIP = toIP; mToPort = toPort; try { inSocket.BeginReceive(InBuffer, 0, MAXBUFFER, SocketFlags.None, new AsyncCallback(OnInPacket), inSocket); } catch { } } private void OnOutconnect(IAsyncResult ar) { try { outSocket.EndConnect(ar); if (!gotGUID) //here we finish the loop & make sure it continues { gotGUID = true; inSocket.BeginReceive(InBuffer, 0, MAXBUFFER, SocketFlags.None, new AsyncCallback(OnInPacket), inSocket); } } catch { Log.WriteLine(ELogLevel.Error, "Could not connect to destination."); CloseSessions(); return; } try { outSocket.BeginReceive(OutBuffer, 0, MAXBUFFER, SocketFlags.None, new AsyncCallback(OnOutPacket), outSocket); } catch { CloseSessions(); } } private void SendToIn(byte[] data) { try { if (!Connected) return; mInSendSegments.Enqueue(new ByteArraySegment(data)); if (Interlocked.CompareExchange(ref mInSending, 1, 0) == 0) BeginInSend(); } catch { CloseSessions(); } } private void SendToOut(byte[] data) { try { if (!Connected) return; mOutSendSegments.Enqueue(new ByteArraySegment(data)); if (Interlocked.CompareExchange(ref mOutSending, 1, 0) == 0) BeginOutSend(); } catch { CloseSessions(); } } private void BeginOutSend() { SocketAsyncEventArgs args = new SocketAsyncEventArgs(); args.Completed += (s, a) => EndOutSend(a); ByteArraySegment segment = mOutSendSegments.Next; args.SetBuffer(segment.Buffer, segment.Start, segment.Length); try { if (!outSocket.SendAsync(args)) EndOutSend(args); } catch (ObjectDisposedException) { } } private void EndOutSend(SocketAsyncEventArgs pArguments) { if (!Connected) return; if (pArguments.BytesTransferred <= 0) { Connected = false; return; } if (mOutSendSegments.Next.Advance(pArguments.BytesTransferred)) mOutSendSegments.Dequeue(); if (mOutSendSegments.Next != null) BeginOutSend(); else mOutSending = 0; } private void BeginInSend() { try { SocketAsyncEventArgs args = new SocketAsyncEventArgs(); args.Completed += (s, a) => EndInSend(a); ByteArraySegment segment = mInSendSegments.Next; args.SetBuffer(segment.Buffer, segment.Start, segment.Length); try { if (!inSocket.SendAsync(args)) EndInSend(args); } catch (ObjectDisposedException) { } } catch { } } private void EndInSend(SocketAsyncEventArgs pArguments) { if (!Connected) return; if (pArguments.BytesTransferred <= 0) { Connected = false; return; } if (mInSendSegments.Next.Advance(pArguments.BytesTransferred)) mInSendSegments.Dequeue(); if (mInSendSegments.Next != null) BeginInSend(); else mInSending = 0; } private void OnOutPacket(IAsyncResult ar) { if (!Connected) return; int len = 0; try { len = outSocket.EndReceive(ar); } catch { Connected = false; CloseSessions(); return; } if (len <= 0 || !Connected) { CloseSessions(); return; } byte[] toSend = new byte[len]; Buffer.BlockCopy(OutBuffer, 0, toSend, 0, len); SendToIn(toSend); outSocket.BeginReceive(OutBuffer, 0, MAXBUFFER, SocketFlags.None, new AsyncCallback(OnOutPacket), outSocket); } void CloseSessions() { if (!Connected) return; Connected = false; try { outSocket.Shutdown(SocketShutdown.Both); } catch { } try { inSocket.Shutdown(SocketShutdown.Both); } catch { } } private void OnInPacket(IAsyncResult ar) { int len = 0; try { len = inSocket.EndReceive(ar); } catch { CloseSessions(); return; } if (len <= 0 || !Connected) { CloseSessions(); return; } if (!gotGUID) { string guid = System.Text.Encoding.ASCII.GetString(InBuffer, 0, len); string IP = inSocket.RemoteEndPoint.ToString().Split(':')[0]; if (guid == "fapsecks") { gotGUID = true; outSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); outSocket.BeginConnect(mToIP, mToPort, new AsyncCallback(OnOutconnect), outSocket); return; } if (!FileSecurity.Server.Sessions.ContainsKey(IP)) { Log.WriteLine(ELogLevel.Warn, "Invalid connection. Not authenciated."); inSocket.Shutdown(SocketShutdown.Both); return; } if (FileSecurity.Server.Sessions[IP].GUID.ToLower() != guid.ToLower()) { Log.WriteLine(ELogLevel.Warn, "Client has sent an invalid GUID. Closing socket."); inSocket.Shutdown(SocketShutdown.Both); return; } outSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); outSocket.BeginConnect(mToIP, mToPort, new AsyncCallback(OnOutconnect), outSocket); return; } byte[] toSend = new byte[len]; Buffer.BlockCopy(InBuffer, 0, toSend, 0, len); SendToOut(toSend); inSocket.BeginReceive(InBuffer, 0, MAXBUFFER, SocketFlags.None, new AsyncCallback(OnInPacket), inSocket); } } }