Solved

handling event from another class

Posted on 2010-08-31
7
698 Views
Last Modified: 2012-06-27
i am using the embedded http server class from http://www.codeproject.com/KB/IP/http.aspx
and all i would like to do is have my app that uses this class display a plain messagebox as soon as a client has made an http request to it? What is the start of the code that I would need, or what event could I handle?

i.e. my vb app initiliazes the server like this, which makes it feed files to the client:

 http = New HttpServer(New Server(8080))
        somereader = New SubstitutingFileReader()
        http.Handlers.Add(somereader)

but i would like to now somehow make my vb app display msgbox as soon as a client has connected?

the code for the http server is below, and im not sure if needed but the supporting socket class as well (the http server class references this socket class)

the question is basically how to get a handle to an event in a different class?

any help most appreciated.
// Client-server helpers for TCP/IP
// ClientInfo: wrapper for a socket which throws
//  Receive events, and allows for messaged communication (using
//  a specified character as end-of-message)
// Server: simple TCP server that throws Connect events
// ByteBuilder: utility class to manage byte arrays built up
//  in multiple transactions

// (C) Richard Smith 2005-8
//   bobjanova@gmail.com
// You can use this for free and give it to people as much as you like
// as long as you leave a credit to me :).

// Code to connect to a SOCKS proxy modified from
//   http://www.thecodeproject.com/csharp/ZaSocks5Proxy.asp

// Define this symbol to include console output in various places
//#define DEBUG

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Collections;
using System.Net.Sockets;
using System.Security.Cryptography;

using RedCorona.Cryptography;

[assembly:System.Reflection.AssemblyVersion("1.4.2008.0330")]

namespace RedCorona.Net {	
	public delegate void ConnectionRead(ClientInfo ci, String text);
	public delegate void ConnectionClosed(ClientInfo ci);
	public delegate void ConnectionReadBytes(ClientInfo ci, byte[] bytes, int len);
	public delegate void ConnectionReadMessage(ClientInfo ci, uint code, byte[] bytes, int len);
	public delegate void ConnectionReadPartialMessage(ClientInfo ci, uint code, byte[] bytes, int start, int read, int sofar, int totallength);
	public delegate void ConnectionNotify(ClientInfo ci);
	
	public enum ClientDirection {In, Out, Left, Right, Both};
	public enum MessageType {Unmessaged, EndMarker, Length, CodeAndLength};
	// ServerDES: The server sends an encryption key on connect
	// ServerRSAClientDES: The server sends an RSA public key, the client sends back a key
	public enum EncryptionType {None, ServerKey, ServerRSAClientKey};
	
	public class EncryptionUtils {
		static RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
		public static byte[] GetRandomBytes(int length, bool addByte){
			if(addByte && (length > 255)) throw new ArgumentException("Length must be 1 byte <256");
			byte[] random = new byte[length + (addByte ? 1 : 0)];
			rng.GetBytes(random);
			if(addByte) random[0] = (byte)length;
			return random;
		}
	}
	
	// OnReadBytes: catch the raw bytes as they arrive
	// OnRead: for text ended with a marker character
	// OnReadMessage: for binary info on a messaged client
	public class ClientInfo {
		internal Server server = null;
		private Socket sock;
		private String buffer;
		public event ConnectionRead OnRead;
		public event ConnectionClosed OnClose;
		public event ConnectionReadBytes OnReadBytes;
		public event ConnectionReadMessage OnReadMessage;
		public event ConnectionReadPartialMessage OnPartialMessage;
		public event ConnectionNotify OnReady;
		public MessageType MessageType;
		private ClientDirection dir;
		int id;
		bool alreadyclosed = false;
		public static int NextID = 100;
		//private ClientThread t;
		public object Data = null;
		
		// Encryption info
		EncryptionType encType;
		int encRead = 0, encStage, encExpected;
		internal bool encComplete;
		internal byte[] encKey;
		internal RSAParameters encParams;
		
		public EncryptionType EncryptionType {
			get { return encType; }
			set {
				if(encStage != 0) throw new ArgumentException("Key exchange has already begun"); 
				encType = value;
				encComplete = encType == EncryptionType.None;
				encExpected = -1;
			}
		}
		public bool EncryptionReady { get { return encComplete; } }
		internal ICryptoTransform encryptor, decryptor;
		public ICryptoTransform Encryptor { get { return encryptor; } }
		public ICryptoTransform Decryptor { get { return decryptor; } }
		
		private string delim;
		public const int BUFSIZE = 1024;
		byte[] buf = new byte[BUFSIZE];
		ByteBuilder bytes = new ByteBuilder(10);
		
		byte[] msgheader = new byte[8];
		byte headerread = 0;
		bool wantingChecksum = true;
		
		public string Delimiter {
			get { return delim; }
			set { delim = value; }
		}
		
		public ClientDirection Direction { get { return dir; } }
		public Socket Socket { get { return sock; } }
		public Server Server { get { return server; } }
		public int ID { get { return id; } }
		
		public bool Closed {
			get { return !sock.Connected; } 
		}
		
		public ClientInfo(Socket cl, bool StartNow) : this(cl, null, null, ClientDirection.Both, StartNow, EncryptionType.None) {}
		//public ClientInfo(Socket cl, ConnectionRead read, ConnectionReadBytes readevt, ClientDirection d) : this(cl, read, readevt, d, true, EncryptionType.None) {}
		public ClientInfo(Socket cl, ConnectionRead read, ConnectionReadBytes readevt, ClientDirection d, bool StartNow) : this(cl, read, readevt, d, StartNow, EncryptionType.None) {}
		public ClientInfo(Socket cl, ConnectionRead read, ConnectionReadBytes readevt, ClientDirection d, bool StartNow, EncryptionType encryptionType){	
			sock = cl; buffer = ""; OnReadBytes = readevt; encType = encryptionType;
			encStage = 0; encComplete = encType == EncryptionType.None;
			OnRead = read;
			MessageType = MessageType.EndMarker;
			dir = d; delim = "\n";
			id = NextID; // Assign each client an application-unique ID
			unchecked{NextID++;}
			//t = new ClientThread(this);
			if(StartNow) BeginReceive();
		}
		
		public void BeginReceive(){
//			t.t.Start();
			sock.BeginReceive(buf, 0, BUFSIZE, 0, new AsyncCallback(ReadCallback), this);
		}
		
		public String Send(String text){
			byte[] ba = Encoding.UTF8.GetBytes(text);
			String s = "";
			for(int i = 0; i < ba.Length; i++) s += ba[i] + " ";
			Send(ba);
			return s;
		}
		
		public void SendMessage(uint code, byte[] bytes){ SendMessage(code, bytes, 0, bytes.Length); }
		public void SendMessage(uint code, byte[] bytes, byte paramType){ SendMessage(code, bytes, paramType, bytes.Length); }
		public void SendMessage(uint code, byte[] bytes, byte paramType, int len){
			if(paramType > 0){
				ByteBuilder b = new ByteBuilder(3);
				b.AddParameter(bytes, paramType);
				bytes = b.Read(0, b.Length);
				len = bytes.Length;
			} 
			
			lock(sock){
				byte checksum = 0; byte[] ba;
				switch(MessageType){
					case MessageType.CodeAndLength:					
						Send(ba = UintToBytes(code));
						for(int i = 0; i < 4; i++) checksum += ba[i];
						Send(ba = IntToBytes(len));
						for(int i = 0; i < 4; i++) checksum += ba[i];
						if(encType != EncryptionType.None) Send(new byte[]{checksum});
						break;
					case MessageType.Length:
						Send(ba = IntToBytes(len));
						for(int i = 0; i < 4; i++) checksum += ba[i];
						if(encType != EncryptionType.None) Send(new byte[]{checksum});
						break;
				}
				Send(bytes, len);
				if(encType != EncryptionType.None){
					checksum = 0;
					for(int i = 0; i < len; i++) checksum += bytes[i];
					Send(new byte[]{checksum});
				}
			}
			
		}
		public void Send(byte[] bytes){ Send(bytes, bytes.Length); }
		public void Send(byte[] bytes, int len){
			if(!encComplete) throw new IOException("Key exchange is not yet completed");
			if(encType != EncryptionType.None){
				byte[] outbytes = new byte[len];
				Encryptor.TransformBlock(bytes, 0, len, outbytes, 0);
				bytes = outbytes;
				//Console.Write("Encryptor IV: "); LogBytes(encryptor.Key, encryptor.IV.length);
			}
			#if DEBUG
			Console.Write(ID + " Sent: "); LogBytes(bytes, len);
			#endif
			sock.Send(bytes, len, SocketFlags.None);
		}
		
		public bool MessageWaiting(){
			FillBuffer(sock);
			return buffer.IndexOf(delim) >= 0;
		}
		
		public String Read(){
			//FillBuffer(sock);
			int p = buffer.IndexOf(delim);
			if(p >= 0){
				String res = buffer.Substring(0, p);
				buffer = buffer.Substring(p + delim.Length);
				return res;
			} else return "";
		}
		
		private void FillBuffer(Socket sock){
			byte[] buf = new byte[256];
			int read;
			while(sock.Available != 0){
				read = sock.Receive(buf);
				if(OnReadBytes != null) OnReadBytes(this, buf, read);
				buffer += Encoding.UTF8.GetString(buf, 0, read);
			}
		}
		
		void ReadCallback(IAsyncResult ar){
			try {
				int read = sock.EndReceive(ar);
				//Console.WriteLine("Socket "+ID+" read "+read+" bytes");
				if(read > 0){
					DoRead(buf, read);
					BeginReceive();
				} else {
					#if DEBUG
					Console.WriteLine(ID + " zero byte read closure");
					#endif
					Close();
				}
			} catch(SocketException e){
				#if DEBUG
				Console.WriteLine(ID + " socket exception closure: "+e);
				#endif
				Close();
			} catch(ObjectDisposedException){
				#if DEBUG
				Console.WriteLine(ID + " disposed exception closure");
				#endif
				Close();
			}
		}
		
		internal void DoRead(byte[] buf, int read){
			if(read > 0){				
				if(OnRead != null){ // Simple text mode
					buffer += Encoding.UTF8.GetString(buf, 0, read);
					while(buffer.IndexOf(delim) >= 0) OnRead(this, Read());
				}
			}
			ReadInternal(buf, read, false);
		}
		
		public static void LogBytes(byte[] buf, int len){
			byte[] ba = new byte[len];
			Array.Copy(buf, ba, len);
			Console.WriteLine(ByteBuilder.FormatParameter(new Parameter(ba, ParameterType.Byte)));		
		}
		
		void ReadInternal(byte[] buf, int read, bool alreadyEncrypted){			
			if((!alreadyEncrypted) && (encType != EncryptionType.None)){
				if(encComplete){
					#if DEBUG
					Console.Write(ID + " Received: "); LogBytes(buf, read);
					#endif
					buf = decryptor.TransformFinalBlock(buf, 0, read);
					#if DEBUG
					Console.Write(ID + " Decrypted: "); LogBytes(buf, read);
					#endif
				} else {
					// Client side key exchange
					int ofs = 0;
					if(encExpected < 0){ 
						encStage++;
						ofs++; read--; encExpected = buf[0]; // length of key to come
						encKey = new byte[encExpected];
						encRead = 0;
					}
					if(read >= encExpected){
						Array.Copy(buf, ofs, encKey, encRead, encExpected);
						int togo = read - encExpected;
						encExpected = -1;
						#if DEBUG
						Console.WriteLine(ID + " Read encryption key: "+ByteBuilder.FormatParameter(new Parameter(encKey, ParameterType.Byte)));
						#endif
						if(server == null) ClientEncryptionTransferComplete();
						else ServerEncryptionTransferComplete();
						if(togo > 0){
							byte[] newbuf = new byte[togo];
							Array.Copy(buf, read + ofs - togo, newbuf, 0, togo);
							ReadInternal(newbuf, togo, false);
						}
					} else {
						Array.Copy(buf, ofs, encKey, encRead, read);
						encExpected -= read; encRead += read;					
					}
					return;
				}
			}
			
			if((!alreadyEncrypted) && (OnReadBytes != null)) OnReadBytes(this, buf, read);
			
			if((OnReadMessage != null) && (MessageType != MessageType.Unmessaged)){
				// Messaged mode
				int copied;
				uint code = 0;
				switch(MessageType){
					case MessageType.CodeAndLength:
					case MessageType.Length:
						int length;
						if(MessageType == MessageType.Length){
							copied = FillHeader(ref buf, 4, read);						
							if(headerread < 4) break;
							length = GetInt(msgheader, 0, 4);
						} else{
							copied = FillHeader(ref buf, 8, read);
							if(headerread < 8) break;
							code = (uint)GetInt(msgheader, 0, 4);
							length = GetInt(msgheader, 4, 4);
						}
						if(read == copied) break;
						// If encryption is on, the next byte is a checksum of the header
						int ofs = 0;
						if(wantingChecksum && (encType != EncryptionType.None)){
							byte checksum = buf[0];
							ofs++;
							wantingChecksum = false;
							byte headersum = 0;
							for(int i = 0; i < 8; i++) headersum += msgheader[i];
							if(checksum != headersum){
								Close();
								throw new IOException("Header checksum failed! (was "+checksum+", calculated "+headersum+")");
							}
						}
						bytes.Add(buf, ofs, read - ofs - copied);
						if(encType != EncryptionType.None) length++; // checksum byte
						
						// Now we know we are reading into the body of the message
						#if DEBUG
						Console.WriteLine(ID + " Added "+(read - ofs - copied)+" bytes, have "+bytes.Length+" of "+length);
						#endif
						if(OnPartialMessage != null) OnPartialMessage(this, code, buf, ofs, read - ofs - copied, bytes.Length, length);
						
						if(bytes.Length >= length){
							// A message was received!
							 headerread = 0; wantingChecksum = true;
							byte[] msg = bytes.Read(0, length);
							if(encType != EncryptionType.None){
								byte checksum = msg[length - 1], msgsum = 0;
								for(int i = 0; i < length - 1; i++) msgsum += msg[i];
								if(checksum != msgsum){
									Close();
									throw new IOException("Content checksum failed! (was "+checksum+", calculated "+msgsum+")");
								}
								OnReadMessage(this, code, msg, length - 1);
							} else OnReadMessage(this, code, msg, length);
							// Don't forget to put the rest through the mill
							int togo = bytes.Length - length;
							if(togo > 0){
								byte[] whatsleft = bytes.Read(length, togo);
								bytes.Clear();
								ReadInternal(whatsleft, whatsleft.Length, true);
							} else bytes.Clear();
						}
						//if(OnStatus != null) OnStatus(this, bytes.Length, length);
						break;
				}
			}
		}
		
		int FillHeader(ref byte[] buf, int to, int read) {
			int copied = 0;
			if(headerread < to){
				// First copy the header into the header variable.
				for(int i = 0; (i < read) && (headerread < to); i++, headerread++, copied++){
					msgheader[headerread] = buf[i];
				}
			}
			if(copied > 0){
				// Take the header bytes off the 'message' section
				byte[] newbuf = new byte[read - copied];
				for(int i = 0; i < newbuf.Length; i++) newbuf[i] = buf[i + copied];
				buf = newbuf;
			}
			return copied;
		}
		
		internal ICryptoTransform MakeEncryptor(){ return MakeCrypto(true); }
		internal ICryptoTransform MakeDecryptor(){ return MakeCrypto(false); }
		internal ICryptoTransform MakeCrypto(bool encrypt){
			if(encrypt) return new SimpleEncryptor(encKey);
			else return new SimpleDecryptor(encKey);
		}		
		
		void ServerEncryptionTransferComplete(){
			switch(encType){
				case EncryptionType.None:
					throw new ArgumentException("Should not have key exchange for unencrypted connection!");				
				case EncryptionType.ServerKey:
					throw new ArgumentException("Should not have server-side key exchange for server keyed connection!");				
				case EncryptionType.ServerRSAClientKey:
					// Symmetric key is in RSA-encoded encKey
					RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
					rsa.ImportParameters(encParams);
					encKey = rsa.Decrypt(encKey, false);
					#if DEBUG
					Console.WriteLine("Symmetric key is: "); LogBytes(encKey, encKey.Length);
					#endif
					MakeEncoders();
					server.KeyExchangeComplete(this);
					break;
			}
		}
		
		void ClientEncryptionTransferComplete(){
			// A part of the key exchange process has been completed, and the key is
			// in encKey
			switch(encType){
				case EncryptionType.None:
					throw new ArgumentException("Should not have key exchange for unencrypted connection!");				
				case EncryptionType.ServerKey:
					// key for transfer is now in encKey, so all is good
					MakeEncoders();
					break;
				case EncryptionType.ServerRSAClientKey:
					// Stage 1: modulus; Stage 2: exponent
					// When the exponent arrives, create a random DES key
					// and send it
					switch(encStage){
						case 1: encParams.Modulus = encKey; break;
						case 2:
							encParams.Exponent = encKey;
							RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
							rsa.ImportParameters(encParams);
							encKey = EncryptionUtils.GetRandomBytes(24, false);
							byte[] send = GetLengthEncodedVector(rsa.Encrypt(encKey, false));
							sock.Send(send);							
							MakeEncoders();
							break;
					}
					break;
			}
		}
		
		internal void MakeEncoders(){
			encryptor = MakeEncryptor();	
			decryptor = MakeDecryptor();
			if(OnReady != null) OnReady(this);
			encComplete = true;
		}
			
		public static byte[] GetLengthEncodedVector(byte[] from){
			int l = from.Length;
			if(l > 255) throw new ArgumentException("Cannot length encode more than 255");
			byte[] to = new byte[l + 1];
			to[0] = (byte)l;
			Array.Copy(from, 0, to, 1, l);
			return to;
		}
		
		public static int GetInt(byte[] ba, int from, int len){
			int r = 0;
			for(int i = 0; i < len; i++)
				r += ba[from + i] << ((len - i - 1) * 8);
			return r;
		}
		
		public static int[] GetIntArray(byte[] ba){ return GetIntArray(ba, 0, ba.Length); }
		public static int[] GetIntArray(byte[] ba, int from, int len){
			int[] res = new int[len / 4];
			for(int i = 0; i < res.Length; i++){
				res[i] = GetInt(ba, from + (i * 4), 4);
			}
			return res;
		}
		
		public static uint[] GetUintArray(byte[] ba){
			uint[] res = new uint[ba.Length / 4];
			for(int i = 0; i < res.Length; i++){
				res[i] = (uint)GetInt(ba, i * 4, 4);
			}
			return res;
		}
		
		public static byte[] IntToBytes(int val){ return UintToBytes((uint)val); }
		public static byte[] UintToBytes(uint val){
			byte[] res = new byte[4];
			for(int i = 3; i >= 0; i--){
				res[i] = (byte)val; val >>= 8;
			}
			return res;
		}
		
		public static byte[] IntArrayToBytes(int[] val){
			byte[] res = new byte[val.Length * 4];
			for(int i = 0; i < val.Length; i++){
				byte[] vb = IntToBytes(val[i]);
				res[(i * 4)] = vb[0];
				res[(i * 4) + 1] = vb[1];
				res[(i * 4) + 2] = vb[2];
				res[(i * 4) + 3] = vb[3];
			}
			return res;
		}
		
		public static byte[] UintArrayToBytes(uint[] val){
			byte[] res = new byte[val.Length * 4];
			for(uint i = 0; i < val.Length; i++){
				byte[] vb = IntToBytes((int)val[i]);
				res[(i * 4)] = vb[0];
				res[(i * 4) + 1] = vb[1];
				res[(i * 4) + 2] = vb[2];
				res[(i * 4) + 3] = vb[3];
			}
			return res;
		}
		
		public static byte[] StringArrayToBytes(string[] val, Encoding e){
			byte[][] baa = new byte[val.Length][];
			int l = 0;
			for(int i = 0; i < val.Length; i++){ baa[i] = e.GetBytes(val[i]); l += 4 + baa[i].Length; }
			byte[] r = new byte[l + 4];
			IntToBytes(val.Length).CopyTo(r, 0);
			int ofs = 4;
			for(int i = 0; i < baa.Length; i++){
				IntToBytes(baa[i].Length).CopyTo(r, ofs); ofs += 4;
				baa[i].CopyTo(r, ofs); ofs += baa[i].Length;
			}
			return r;
		}
		
		public static string[] GetStringArray(byte[] ba, Encoding e){
			int l = GetInt(ba, 0, 4), ofs = 4;
			string[] r = new string[l];
			for(int i = 0; i < l; i++){
				int thislen = GetInt(ba, ofs, 4); ofs += 4;
				r[i] = e.GetString(ba, ofs, thislen); ofs += thislen;
			}
			return r;
		}
		
		public void Close(){
			if(!alreadyclosed){
				if(server != null) server.ClientClosed(this);
				if(OnClose != null) OnClose(this);
				alreadyclosed = true;
				#if DEBUG
				Console.WriteLine("**closed client** at "+DateTime.Now.Ticks);
				#endif
			}
			sock.Close();
		}
	}
	
	public class Sockets {
		// Socks proxy inspired by http://www.thecodeproject.com/csharp/ZaSocks5Proxy.asp
		public static SocksProxy SocksProxy;
		public static bool UseSocks = false;
		
		public static Socket CreateTCPSocket(String address, int port){return CreateTCPSocket(address, port, UseSocks, SocksProxy);}
		public static Socket CreateTCPSocket(String address, int port, bool useSocks, SocksProxy proxy){
			Socket sock;
			if(useSocks) sock = ConnectToSocksProxy(proxy.host, proxy.port, address, port, proxy.username, proxy.password);
			else {
				IPAddress host = Dns.GetHostByName(address).AddressList[0];
				sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
				sock.Connect(new IPEndPoint(host, port));
			}
			return sock;
		}

		private static string[] errorMsgs=	{
			"Operation completed successfully.",
			"General SOCKS server failure.",
			"Connection not allowed by ruleset.",
			"Network unreachable.",
			"Host unreachable.",
			"Connection refused.",
			"TTL expired.",
			"Command not supported.",
			"Address type not supported.",
			"Unknown error."
		};

		public static Socket ConnectToSocksProxy(IPAddress proxyIP, int proxyPort, String destAddress, int destPort, string userName, string password){
			byte[] request = new byte[257];
			byte[] response = new byte[257];
			ushort nIndex;
			
			IPAddress destIP = null;
			
			try{ destIP = IPAddress.Parse(destAddress); }
			catch { }
			
			IPEndPoint proxyEndPoint = new IPEndPoint(proxyIP, proxyPort);

			// open a TCP connection to SOCKS server...
			Socket s;
			s = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
			s.Connect(proxyEndPoint);	
/*			} catch(SocketException){
				throw new SocketException(0, "Could not connect to proxy server.");
			}*/

			nIndex = 0;
			request[nIndex++]=0x05; // Version 5.
			request[nIndex++]=0x02; // 2 Authentication methods are in packet...
			request[nIndex++]=0x00; // NO AUTHENTICATION REQUIRED
			request[nIndex++]=0x02; // USERNAME/PASSWORD
			// Send the authentication negotiation request...
			s.Send(request,nIndex,SocketFlags.None);

			// Receive 2 byte response...
			int nGot = s.Receive(response,2,SocketFlags.None);	
			if (nGot!=2)
				throw new ConnectionException("Bad response received from proxy server.");

			if (response[1]==0xFF)
			{	// No authentication method was accepted close the socket.
				s.Close();
				throw new ConnectionException("None of the authentication method was accepted by proxy server.");
			}

			byte[] rawBytes;

			if (/*response[1]==0x02*/true)
			{//Username/Password Authentication protocol
				nIndex = 0;
				request[nIndex++]=0x05; // Version 5.

				// add user name
				request[nIndex++]=(byte)userName.Length;
				rawBytes = Encoding.Default.GetBytes(userName);
				rawBytes.CopyTo(request,nIndex);
				nIndex+=(ushort)rawBytes.Length;

				// add password
				request[nIndex++]=(byte)password.Length;
				rawBytes = Encoding.Default.GetBytes(password);
				rawBytes.CopyTo(request,nIndex);
				nIndex+=(ushort)rawBytes.Length;

				// Send the Username/Password request
				s.Send(request,nIndex,SocketFlags.None);
				// Receive 2 byte response...
				nGot = s.Receive(response,2,SocketFlags.None);	
				if (nGot!=2)
					throw new ConnectionException("Bad response received from proxy server.");
				if (response[1] != 0x00)
					throw new ConnectionException("Bad Usernaem/Password.");
			}
			// This version only supports connect command. 
			// UDP and Bind are not supported.

			// Send connect request now...
			nIndex = 0;
			request[nIndex++]=0x05;	// version 5.
			request[nIndex++]=0x01;	// command = connect.
			request[nIndex++]=0x00;	// Reserve = must be 0x00

			if (destIP != null)
			{// Destination adress in an IP.
				switch(destIP.AddressFamily)
				{
					case AddressFamily.InterNetwork:
						// Address is IPV4 format
						request[nIndex++]=0x01;
						rawBytes = destIP.GetAddressBytes();
						rawBytes.CopyTo(request,nIndex);
						nIndex+=(ushort)rawBytes.Length;
						break;
					case AddressFamily.InterNetworkV6:
						// Address is IPV6 format
						request[nIndex++]=0x04;
						rawBytes = destIP.GetAddressBytes();
						rawBytes.CopyTo(request,nIndex);
						nIndex+=(ushort)rawBytes.Length;
						break;
				}
			}
			else
			{// Dest. address is domain name.
				request[nIndex++]=0x03;	// Address is full-qualified domain name.
				request[nIndex++]=Convert.ToByte(destAddress.Length); // length of address.
				rawBytes = Encoding.Default.GetBytes(destAddress);
				rawBytes.CopyTo(request,nIndex);
				nIndex+=(ushort)rawBytes.Length;
			}

			// using big-edian byte order
			byte[] portBytes = BitConverter.GetBytes((ushort)destPort);
			for (int i=portBytes.Length-1;i>=0;i--)
				request[nIndex++]=portBytes[i];

			// send connect request.
			s.Send(request,nIndex,SocketFlags.None);
			s.Receive(response);	// Get variable length response...
			if (response[1]!=0x00)
				throw new ConnectionException(errorMsgs[response[1]]);
			// Success Connected...
			return s;
		}
	}
	
	public struct SocksProxy {
		public IPAddress host;
		public ushort port;
		public string username, password;
		
		public SocksProxy(String hostname, ushort port, String username, String password){
			this.port = port;
			host = Dns.GetHostByName(hostname).AddressList[0];
			this.username = username; this.password = password;
		}
	}
	
	public class ConnectionException: Exception {
		public ConnectionException(string message) : base(message) {}
	}
	
	// Server code cribbed from Framework Help
	public delegate bool ClientEvent(Server serv, ClientInfo new_client); // whether to accept the client
	public class Server {
		class ClientState {
			// To hold the state information about a client between transactions
			internal Socket Socket = null;
			internal const int BufferSize = 1024;
			internal byte[] buffer = new byte[BufferSize];
			internal StringBuilder sofar = new StringBuilder();  

			internal ClientState(Socket sock){
				Socket = sock;
			}
		}
  
  ArrayList clients = new ArrayList();
  Socket ss;
  
  public event ClientEvent Connect, ClientReady;
  public IEnumerable Clients {
  	get { return clients; }
  }
  
  public Socket ServerSocket {
  	get { return ss; }
  }
  
  public ClientInfo this[int id]{
  	get {
  		foreach(ClientInfo ci in Clients)
  			if(ci.ID == id) return ci;
  		return null;
  	}
  }

		private EncryptionType encType;
		public EncryptionType DefaultEncryptionType {
			get { return encType; }
			set { encType = value; }
		}
  
  public int Port {
  	get { return ((IPEndPoint)ss.LocalEndPoint).Port; }
  }
  
  public Server(int port) : this(port, null) {}
  public Server(int port, ClientEvent connDel) {
  	Connect = connDel;
  	
  	ss = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
  	ss.Bind(new IPEndPoint(IPAddress.Any, port));
   ss.Listen(100);
   
   // Start the accept process. When a connection is accepted, the callback
   // must do this again to accept another connection
   ss.BeginAccept(new AsyncCallback(AcceptCallback), ss);
  }
  
  internal void ClientClosed(ClientInfo ci){
  	clients.Remove(ci);
  }
  
  public void Broadcast(byte[] bytes){
  	foreach(ClientInfo ci in clients) ci.Send(bytes);
  }
  
  public void BroadcastMessage(uint code, byte[] bytes){BroadcastMessage(code, bytes, 0); }
  public void BroadcastMessage(uint code, byte[] bytes, byte paramType){
  	foreach(ClientInfo ci in clients) ci.SendMessage(code, bytes, paramType);
  }
  
  // ASYNC CALLBACK CODE
		void AcceptCallback(IAsyncResult ar) {
			try{
				Socket server = (Socket) ar.AsyncState;
				Socket cs = server.EndAccept(ar);

				// Start the thing listening again
				server.BeginAccept(new AsyncCallback(AcceptCallback), server);

				ClientInfo c = new ClientInfo(cs, null, null, ClientDirection.Both, false);
				c.server = this;
				// Allow the new client to be rejected by the application
				if(Connect != null){
					if(!Connect(this, c)){
						// Rejected
						cs.Close();
						return;
					}
				}
				// Initiate key exchange
				c.EncryptionType = encType;
				switch(encType){
					case EncryptionType.None: KeyExchangeComplete(c); break;
					case EncryptionType.ServerKey:
						c.encKey = GetSymmetricKey();
						byte[] key = ClientInfo.GetLengthEncodedVector(c.encKey);
						cs.Send(key);
						c.MakeEncoders();
						KeyExchangeComplete(c); 
						break;
					case EncryptionType.ServerRSAClientKey:
						RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
						RSAParameters p = rsa.ExportParameters(true);
						cs.Send(ClientInfo.GetLengthEncodedVector(p.Modulus));
						cs.Send(ClientInfo.GetLengthEncodedVector(p.Exponent));
						c.encParams = p;
						break;
					default: throw new ArgumentException("Unknown or unsupported encryption type "+encType);
				}
				clients.Add(c);
				c.BeginReceive();
			} catch(ObjectDisposedException) {  }
			catch(SocketException) { }
			catch(Exception e) { Console.WriteLine(e); }			
		}
		
		protected virtual byte[] GetSymmetricKey(){
			return EncryptionUtils.GetRandomBytes(24, false);
		}
		
		internal void KeyExchangeComplete(ClientInfo ci){
			// Key exchange is complete on this client. Client ready
			// handlers may still force a close of the connection
			if(ClientReady != null)
				if(!ClientReady(this, ci)) ci.Close();
		}
		
		~Server() { Close(); }
		public void Close(){
			ArrayList cl2 = new ArrayList();
			foreach(ClientInfo c in clients) cl2.Add(c);
			foreach(ClientInfo c in cl2) c.Close();
			
			ss.Close();
		}
	}
	
	public class ByteBuilder : MarshalByRefObject {
		byte[][] data;
		int packsize, used;
		
		public int Length {
			get {
				int len = 0;
				for(int i = 0; i < used; i++) len += data[i].Length;
				return len;
			}
		}
		
		public byte this[int i]{
			get { return Read(i, 1)[0]; }
		}
		
		public ByteBuilder() : this(10) {}
		public ByteBuilder(int packsize){
			this.packsize = packsize; used = 0;
			data = new byte[packsize][];
		}
		
		public ByteBuilder(byte[] data) {
			packsize = 1;
			used = 1;
			this.data = new byte[][] { data };
		}
		
		public ByteBuilder(byte[] data, int len) : this(data, 0, len) {}
		public ByteBuilder(byte[] data, int from, int len) : this(1) {
			Add(data, from, len);
		}
		public void Add(byte[] moredata){ Add(moredata, 0, moredata.Length); }
		public void Add(byte[] moredata, int from, int len){
//Console.WriteLine("Getting "+from+" to "+(from+len-1)+" of "+moredata.Length);
			if(used < packsize){
				data[used] = new byte[len];
				for(int j = from; j < from + len; j++)
					data[used][j - from] = moredata[j];
				used++;
			} else {
				// Compress the existing items into the first array
				byte[] newdata = new byte[Length + len];
				int np = 0;
				for(int i = 0; i < used; i++)
					for(int j = 0; j < data[i].Length; j++)
						newdata[np++] = data[i][j];
				for(int j = from; j < from + len; j++)
					newdata[np++] = moredata[j];
				data[0] = newdata;
				for(int i = 1; i < used; i++) data[i] = null;
				used = 1;
			}
		}
		
		public byte[] Read(int from, int len){
			if(len == 0) return new byte[0];
			byte[] res = new byte[len];
			int done = 0, start = 0;
			
			for(int i = 0; i < used; i++){
				if((start + data[i].Length) <= from){
					start += data[i].Length; continue;
				}
				// Now we're in the data block
				for(int j = 0; j < data[i].Length; j++){
					if((j + start) < from) continue;
					res[done++] = data[i][j];
					if(done == len) return res;
				}
			}
			
			throw new ArgumentException("Datapoints "+from+" and "+(from+len)+" must be less than "+Length);
		}
		
		public void Clear(){
			used = 0;
			for(int i = 0; i < used; i++) data[i] = null;			
		}
		
		public Parameter GetParameter(ref int index){
			Parameter res = new Parameter();
			res.Type = Read(index++, 1)[0];
			byte[] lenba = Read(index, 4);
			index += 4;
			int len = ClientInfo.GetInt(lenba, 0, 4);
			res.content = Read(index, len);
			index += len;
			return res;
		}
		
		public void AddParameter(Parameter param){ AddParameter(param.content, param.Type); }
		public void AddParameter(byte[] content, byte Type){
			Add(new byte[]{Type});
			Add(ClientInfo.IntToBytes(content.Length));
			Add(content);
		}
		
		public static String FormatParameter(Parameter p){
			switch(p.Type){
				case ParameterType.Int:
					int[] ia = ClientInfo.GetIntArray(p.content);
					StringBuilder sb = new StringBuilder();
					foreach(int i in ia) sb.Append(i + " ");
					return sb.ToString();
				case ParameterType.Uint:
					ia = ClientInfo.GetIntArray(p.content);
					sb = new StringBuilder();
					foreach(int i in ia) sb.Append(i.ToString("X8") + " ");
					return sb.ToString();
				case ParameterType.String:
					return Encoding.UTF8.GetString(p.content);
				case ParameterType.StringArray:
					string[] sa = ClientInfo.GetStringArray(p.content, Encoding.UTF8);
					sb = new StringBuilder();
					foreach(string s in sa) sb.Append(s + "; ");
					return sb.ToString();
				case ParameterType.Byte:
					sb = new StringBuilder();
					foreach(int b in p.content) sb.Append(b.ToString("X2") + " ");
					return sb.ToString();
				default: return "??";
			}
		}		
	}
	
	[Serializable]
	public struct Parameter {
		public byte Type;
		public byte[] content;
		
		public Parameter(byte[] content, byte type){
			this.content = content; Type = type;
		}
	}
	
	public struct ParameterType {
		public const byte Unparameterised = 0;
		public const byte Int = 1;
		public const byte Uint = 2;
		public const byte String = 3;
		public const byte Byte = 4;
		public const byte StringArray = 5;
	}
}

namespace RedCorona.Cryptography {
	// Cryptographic classes
	public abstract class BaseCrypto : ICryptoTransform {
		public int InputBlockSize { get { return 1; } }
		public int OutputBlockSize { get { return 1; } }
		public bool CanTransformMultipleBlocks { get { return true; } }
		public bool CanReuseTransform { get { return true; } }		
		
		protected byte[] key;
		protected byte currentKey;
		protected int done = 0, keyinx = 0;
		
		protected BaseCrypto(byte[] key){
			if(key.Length == 0) throw new ArgumentException("Must provide a key");
			this.key = key;
			currentKey = 0;
			for(int i = 0; i < key.Length; i++) currentKey += key[i];
		}
		
		protected abstract byte DoByte(byte b);
		public int TransformBlock(byte[] from, int frominx, int len, byte[] to, int toinx){
			for(int i = 0; i < len; i++){			
				byte oldkey = currentKey;
				to[toinx + i] = DoByte(from[frominx + i]);
				#if DEBUG
//				Console.WriteLine("  encrypting "+from[frominx + i]+" to "+to[toinx + i]+", key is "+oldkey);
				#endif
				BumpKey();
			}
			return len;
		}
		public byte[] TransformFinalBlock(byte[] from, int frominx, int len){
			byte[] to = new byte[len];
			TransformBlock(from, frominx, len, to, 0);
			return to;
		}
		protected void BumpKey(){
			keyinx = (keyinx + 1) % key.Length;
			currentKey = Multiply257(key[keyinx], currentKey);
		}
		
		protected static byte Multiply257(byte a, byte b){
		 	return (byte)((((a + 1) * (b + 1)) % 257) - 1);
		}
		
		protected static byte[] complements = {0,128,85,192,102,42,146,224,199,179,186,149,177,201,119,240,120,99,229,89,48,221,189,74,71,88,237,100,194,59,198,248,147,188,234,49,131,114,144,44,162,152,5,110,39,94,174,165,20,35,125,172,96,118,242,178,247,225,60,29,58,227,101,252,86,73,233,222,148,245,180,24,168,65,23,185,246,200,243,150,164,209,95,204,126,2,64,183,25,19,208,175,151,215,45,82,52,138,134,17,27,62,4,214,163,176,244,187,223,249,43,217,115,123,37,112,133,158,53,14,16,157,139,113,219,50,84,254,1,171,205,36,142,116,98,239,241,202,97,122,143,218,132,140,38,212,6,32,68,11,79,92,41,251,193,228,238,121,117,203,173,210,40,104,80,47,236,230,72,191,253,129,51,160,46,91,105,12,55,9,70,232,190,87,231,75,10,107,33,22,182,169,3,154,28,197,226,195,30,8,77,13,137,159,83,130,220,235,90,81,161,216,145,250,103,93,211,111,141,124,206,21,67,108,7,57,196,61,155,18,167,184,181,66,34,207,166,26,156,135,15,136,54,78,106,69,76,56,31,109,213,153,63,170,127,255};
		protected static byte Complement257(byte b){ return complements[b]; }
		
		public void Dispose(){} // for IDisposable
	}
	
	public class SimpleEncryptor : BaseCrypto {
		public SimpleEncryptor(byte[] key) : base(key) {}
		
		protected override byte DoByte(byte b){
			byte b2 = Multiply257((byte)(b+currentKey), currentKey);
			currentKey = Multiply257((byte)(b+b2), currentKey);
			return b2;
		}
	}
	public class SimpleDecryptor : BaseCrypto {
		public SimpleDecryptor(byte[] key) : base(key) {}
		
		protected override byte DoByte(byte b){
			byte b2 = (byte)(Multiply257(b, Complement257(currentKey)) - currentKey);
			currentKey = Multiply257((byte)(b+b2), currentKey);
			return b2;
		}
	}
}

Open in new window

// Embedded HTTP server, partial 1.1 support with keep-alive and session management
// REQUIRES: Sockets.dll (or Sockets.cs)

// HttpServer: Main class that implements a HTTP server on top of Sockets server.
//   Includes session management via cookies, keep-alive, UTF8 transfer of text
//   and simple query string parsing (via GET or POST).
// HttpRequest: Represents the request made by the user, with header fields,
//   query string and cookies pre-parsed. Typical server code will read the 
//   properties of this request to determine what to do.
// HttpResponse: The response which is to be sent back to the user. A simple
//   server will set the Content property, but you can send binary information
//   via RawContent, and change the mime type or response code.
// Session: A container into which you may put state information that will be
//  available in future requests from the same user.
// IHttpHandler: You must implement this interface in order to process
//   requests.
// SubstitutingFileHandler: An implementation of IHttpHandler that reads files
//   from disk and allows substitutions of <%pseudotags> within text documents.

// (C) Richard Smith 2008
//   bobjanova@gmail.com
// If downloaded from CodeProject, this file is subject to the CodeProject Open Licence 1.0.
// If downloaded from elsewhere, you may freely distribute the source code, as long as this
// header is not removed or modified. You may not charge for the source code or any compiled
// library that includes this class; however you may link to it from commercial software. Please
// leave a credit to the original download location in your documentation or About box.

// Simple HTTP server
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;

namespace RedCorona.Net {
	public class HttpServer {
		Server s;
		Hashtable hostmap = new Hashtable();	// Map<string, string>: Host => Home folder
		ArrayList handlers = new ArrayList();		// List<IHttpHandler>
		Hashtable sessions = new Hashtable();		// Map<string,Session>
		
		int sessionTimeout = 600;
		
		public Hashtable Hostmap { get { return hostmap; } }
		public Server Server { get { return s ; } }
		public ArrayList Handlers { get { return handlers; } }
		public int SessionTimeout {
			get { return sessionTimeout; }
			set { sessionTimeout = value; CleanUpSessions(); }
		}
		
		public HttpServer(Server s){
			this.s = s; 
			s.Connect += new ClientEvent(ClientConnect);
			handlers.Add(new FallbackHandler());
		}
		
		bool ClientConnect(Server s, ClientInfo ci){
			ci.Delimiter = "\r\n\r\n";
			ci.Data = new ClientData(ci);
			ci.OnRead += new ConnectionRead(ClientRead);
			ci.OnReadBytes += new ConnectionReadBytes(ClientReadBytes);
			return true;
		}
		
		void ClientRead(ClientInfo ci, string text){
			// Read header, if in right state
			ClientData data = (ClientData)ci.Data;
			if(data.state != ClientState.Header) return; // already done; must be some text in content, which will be handled elsewhere
			text = text.Substring(data.headerskip);
			Console.WriteLine("Read header: "+text+" (skipping first "+data.headerskip+")");
			data.headerskip = 0;
			string[] lines = text.Replace("\r\n", "\n").Split('\n');
			data.req.HeaderText = text;
			// First line: METHOD /path/url HTTP/version
			string[] firstline = lines[0].Split(' ');
			if(firstline.Length != 3){ SendResponse(ci, data.req, new HttpResponse(400, "Incorrect first header line "+lines[0]), true); return; }
			if(firstline[2].Substring(0, 4) != "HTTP"){ SendResponse(ci, data.req, new HttpResponse(400, "Unknown protocol "+firstline[2]), true); return; }
			data.req.Method = firstline[0];
			data.req.Url = firstline[1];
			data.req.HttpVersion = firstline[2].Substring(5);
			int p;
			for(int i = 1; i < lines.Length; i++){
				p = lines[i].IndexOf(':');
				if(p > 0) data.req.Header[lines[i].Substring(0, p)] = lines[i].Substring(p+2);
				else Console.WriteLine("Warning, incorrect header line "+lines[i]);
			}
			// If ? in URL, split out query information
			p = firstline[1].IndexOf('?');
			if(p > 0){
				data.req.Page = data.req.Url.Substring(0, p);
				data.req.QueryString = data.req.Url.Substring(p+1);
			} else {
				data.req.Page = data.req.Url;
				data.req.QueryString = "";
			}
			
			if(data.req.Page.IndexOf("..") >= 0) { SendResponse(ci, data.req, new HttpResponse(400, "Invalid path"), true); return; }			
			
			data.req.Host = (string)data.req.Header["Host"];
			if(null == data.req.Host){ SendResponse(ci, data.req, new HttpResponse(400, "No Host specified"), true); return; }			
			
			if(null != data.req.Header["Cookie"]){
				string[] cookies = ((string)data.req.Header["Cookie"]).Split(';');
				foreach(string cookie in cookies){
					p = cookie.IndexOf('=');
					if(p > 0){
						data.req.Cookies[cookie.Substring(0, p).Trim()] = cookie.Substring(p+1);
					} else {
						data.req.Cookies[cookie.Trim()] = "";
					}				
				}
			}
			
			if(null == data.req.Header["Content-Length"]) data.req.ContentLength = 0;
			else data.req.ContentLength = Int32.Parse((string)data.req.Header["Content-Length"]);
			
			//if(data.req.ContentLength > 0){
				data.state = ClientState.PreContent;
				data.skip = text.Length + 4;
			//} else DoProcess(ci);
			
			//ClientReadBytes(ci, new byte[0], 0); // For content length 0 body
		}
		
		public string GetFilename(HttpRequest req){
			string folder = (string)hostmap[req.Host];
			if(folder == null) folder = "webhome";
			if(req.Page == "/") return folder + "/index.html";
			else return folder + req.Page;
		}
		
		void DoProcess(ClientInfo ci){
			ClientData data = (ClientData)ci.Data;
			string sessid = (string)data.req.Cookies["_sessid"];
			if(sessid != null) data.req.Session = (Session)sessions[sessid];
			bool closed = Process(ci, data.req);
			data.state = closed ? ClientState.Closed : ClientState.Header;
			data.read = 0;
			HttpRequest oldreq = data.req;
			data.req = new HttpRequest(); // Once processed, the connection will be used for a new request
			data.req.Session = oldreq.Session; // ... but session is persisted
			data.req.From = ((IPEndPoint)ci.Socket.RemoteEndPoint).Address;
		}
		
		void ClientReadBytes(ClientInfo ci, byte[] bytes, int len){
			CleanUpSessions();
			int ofs = 0;
			ClientData data = (ClientData)ci.Data;
			Console.WriteLine("Reading "+len+" bytes of content, in state "+data.state+", skipping "+data.skip+", read "+data.read);
			switch(data.state){
				case ClientState.Content: break;
				case ClientState.PreContent: 
					data.state = ClientState.Content; 					
					if((data.skip - data.read) > len) { data.skip -= len; return; }
					ofs = data.skip - data.read; data.skip = 0;
					break;
				//case ClientState.Header: data.read += len - data.headerskip; return;
				default: data.read += len; return;
			}
			data.req.Content += Encoding.Default.GetString(bytes, ofs, len-ofs);
			data.req.BytesRead += len - ofs;
			data.headerskip += len - ofs;
			Console.WriteLine("Reading "+(len-ofs)+" bytes of content. Got "+data.req.BytesRead+" of "+data.req.ContentLength);
			if(data.req.BytesRead >= data.req.ContentLength){
				if(data.req.Method == "POST"){
					if(data.req.QueryString == "")data.req.QueryString = data.req.Content;
					else data.req.QueryString += "&" + data.req.Content;
				}
				ParseQuery(data.req);
				DoProcess(ci);
			}
		}
		
		void ParseQuery(HttpRequest req){
			if(req.QueryString == "") return;
			string[] sections = req.QueryString.Split('&');
			for(int i = 0; i < sections.Length; i++){
				int p = sections[i].IndexOf('=');
				if(p < 0) req.Query[sections[i]] = "";
				else req.Query[sections[i].Substring(0, p)] = sections[i].Substring(p+1);
			}
		}
		
		protected virtual bool Process(ClientInfo ci, HttpRequest req){
			HttpResponse resp = new HttpResponse();
			resp.Url = req.Url;
			for(int i = handlers.Count - 1; i >= 0; i--){
				IHttpHandler handler = (IHttpHandler)handlers[i];
				if(handler.Process(this, req, resp)){
					SendResponse(ci, req, resp, resp.ReturnCode != 200);
					return resp.ReturnCode != 200;
				}
			}
			return true;
		}
		
		enum ClientState { Closed, Header, PreContent, Content };
		class ClientData {
			internal HttpRequest req = new HttpRequest();
			internal ClientState state = ClientState.Header;
			internal int skip, read, headerskip;
			
			internal ClientData(ClientInfo ci){
				req.From = ((IPEndPoint)ci.Socket.RemoteEndPoint).Address;
			}
		}
		
		public Session RequestSession(HttpRequest req){
			if(req.Session != null){
				if(sessions[req.Session.ID] == req.Session) return req.Session;
			}
			req.Session = new Session(req.From);
			sessions[req.Session.ID] = req.Session;
			return req.Session;
		}
		
		void CleanUpSessions(){
			ICollection keys = sessions.Keys;
			ArrayList toRemove = new ArrayList();
			foreach(string k in keys){
				Session s = (Session)sessions[k];
				int time = (int)((DateTime.Now - s.LastTouched).TotalSeconds);
				if(time > sessionTimeout){
					toRemove.Add(k);
					Console.WriteLine("Removed session "+k);
				}
			}
			foreach(object k in toRemove) sessions.Remove(k);
		}
		
		// Response stuff
		static Hashtable Responses = new Hashtable();
		static HttpServer(){
			Responses[200] = "OK";
			Responses[302] = "Found";
			Responses[303] = "See Other";
			Responses[400] = "Bad Request";
			Responses[404] = "Not Found";
			Responses[500] = "Misc Server Error";
			Responses[502] = "Server Busy";
		}
		
		void SendResponse(ClientInfo ci, HttpRequest req, HttpResponse resp, bool close){
			ci.Send("HTTP/1.1 " + resp.ReturnCode + Responses[resp.ReturnCode] + 
			        "\r\nDate: "+DateTime.Now.ToString("R")+
			        "\r\nServer: RedCoronaEmbedded/1.0"+
			        "\r\nConnection: "+(close ? "close" : "Keep-Alive"));
			if(resp.RawContent == null ) 
				ci.Send("\r\nContent-Encoding: utf-8"+
					"\r\nContent-Length: "+resp.Content.Length);
			else 
				ci.Send("\r\nContent-Length: "+resp.RawContent.Length);
			if(req.Session != null) ci.Send("\r\nSet-Cookie: _sessid="+req.Session.ID+"; path=/");
			foreach(DictionaryEntry de in resp.Header) ci.Send("\r\n" + de.Key + ": " + de.Value);
			ci.Send("\r\n\r\n"); // End of header
			if(resp.RawContent != null) ci.Send(resp.RawContent);
			else ci.Send(resp.Content);
			//Console.WriteLine("** SENDING\n"+Encoding.Default.GetString(resp.Content));
			if(close) ci.Close();
		}
		
		class FallbackHandler : IHttpHandler {
			public bool Process(HttpServer server, HttpRequest req, HttpResponse resp){
				server.RequestSession(req);
				StringBuilder sb = new StringBuilder();
				sb.Append("<h3>Session</h3>");
				sb.Append("<p>ID: "+req.Session.ID+"<br>User: "+req.Session.User);
				sb.Append("<h3>Header</h3>");
				sb.Append("Method: "+req.Method+"; URL: '"+req.Url+"'; HTTP version "+req.HttpVersion+"<p>");
				foreach(DictionaryEntry ide in req.Header) sb.Append(" "+ide.Key +": "+ide.Value+"<br>");
				sb.Append("<h3>Cookies</h3>");
				foreach(DictionaryEntry ide in req.Cookies) sb.Append(" "+ide.Key +": "+ide.Value+"<br>");
				sb.Append("<h3>Query</h3>");
				foreach(DictionaryEntry ide in req.Query) sb.Append(" "+ide.Key +": "+ide.Value+"<br>");
				sb.Append("<h3>Content</h3>");
				sb.Append(req.Content);
				resp.Content = sb.ToString();
				return true;
			}
		}
	}
	
	public class HttpRequest {
		public bool GotHeader = false;
		public string Method, Url, Page, HttpVersion, Host, Content, HeaderText, QueryString;
		public IPAddress From;
		//public byte[] RawContent;
		public Hashtable Query = new Hashtable(), Header = new Hashtable(), Cookies = new Hashtable();		
		
		public int ContentLength, BytesRead;
		public Session Session;
	}
	
	public class HttpResponse {
		public int ReturnCode = 200;
		public Hashtable Header = new Hashtable();
		public string Url, Content, ContentType = "text/html";
		public byte[] RawContent = null;
		
		public HttpResponse(){}
		public HttpResponse(int code, string content){ ReturnCode = code; Content = content; }
		
		public void MakeRedirect(string newurl){
			ReturnCode = 303;
			Header["Location"] = newurl;
			Content = "This document is requesting a redirection to <a href="+newurl+">"+newurl+"</a>";
		}
	}
	
	public interface IHttpHandler {
		bool Process(HttpServer server, HttpRequest request, HttpResponse response);
	}	
	
	public class Session {
		string id;
		IPAddress user;
		DateTime lasttouched;
		
		Hashtable data = new Hashtable();
		
		public string ID { get { return id; } }
		public DateTime LastTouched { get { return lasttouched; } }
		public IPAddress User { get { return user; } }
		
		public object this[object key]{
			get { return data[key]; }
			set { data[key] = value; Touch(); }
		}
		
		public Session(IPAddress user){
			this.user = user;
			this.id = Guid.NewGuid().ToString();
			Touch();
		}
		
		public void Touch(){ lasttouched = DateTime.Now; }
	}
	
	public class SubstitutingFileReader : IHttpHandler {
		// Reads a file, and substitutes <%x>
		HttpRequest req;
		bool substitute = true;
		
		public bool Substitute { get { return substitute; } set { substitute = value; } }
		
		public static Hashtable MimeTypes;
		
		static SubstitutingFileReader(){
			MimeTypes = new Hashtable();
			MimeTypes[".html"] = "text/html";
			MimeTypes[".htm"] = "text/html";
			MimeTypes[".css"] = "text/css";
			MimeTypes[".js"] = "text/javascript";
			
			MimeTypes[".png"] = "image/png";
			MimeTypes[".gif"] = "image/gif";
			MimeTypes[".jpg"] = "image/jpeg";
			MimeTypes[".jpeg"] = "image/jpeg";
		}
		
		public virtual bool Process(HttpServer server, HttpRequest request, HttpResponse response){
			string fn = server.GetFilename(request);
			if(!File.Exists(fn)){
				response.ReturnCode = 404;
				response.Content = "File not found.";
				return true;
			}
			string ext = Path.GetExtension(fn);
			string mime = (string)MimeTypes[ext];
			if(mime == null) mime = "application/octet-stream";
			response.ContentType =  mime;
			try {
				if(substitute && (mime.Substring(0, 5) == "text/")) {
					// Mime type 'text' is substituted
					StreamReader sr = new StreamReader(fn);
					response.Content = sr.ReadToEnd();
					sr.Close();
					// Do substitutions
					Regex regex = new Regex(@"\<\%(?<tag>[^>]+)\>");
					lock(this){
						req = request;
						response.Content = regex.Replace(response.Content, new MatchEvaluator(RegexMatch));
					}
				} else {
					FileStream fs = File.Open(fn, FileMode.Open);
					byte[] buf = new byte[fs.Length];
					fs.Read(buf, 0, buf.Length);
					fs.Close();
					response.RawContent = buf;
				}
			} catch(Exception e) {
				response.ReturnCode = 500;
				response.Content = "Error reading file: "+e;
				return true;
			}
			return true;
		}	
		
		public virtual string GetValue(HttpRequest req, string tag){
			return "<span class=error>Unknown substitution: "+tag+"</span>";
		}
		
		string RegexMatch(Match m){
			try {
				return GetValue(req, m.Groups["tag"].Value);
			} catch(Exception e) {
				return "<span class=error>Error substituting "+m.Groups["tag"].Value+"</span>";
			}
		}
	}
}

Open in new window

0
Comment
Question by:KristjanLaane
  • 4
  • 3
7 Comments
 
LVL 16

Accepted Solution

by:
SriVaddadi earned 500 total points
ID: 33566475
1. Create a class similar to EventArgs as belowpublic class ClientConnectedEventArgs    {        //You could expose the necessary info as properties            }2. Create a delegate as below outside of your HttpServer classpublic delegate ClientConnectedEventArgs ClientConnectedEventHandler();3. Declare the event in your HttpServer class as below public event ClientConnectedEventHandler ClientConnected;4. Raise the event in the ClientConnect method as belowbool ClientConnect(Server s, ClientInfo ci){                  ci.Delimiter = "\r\n\r\n";                  ci.Data = new ClientData(ci);                  ci.OnRead += new ConnectionRead(ClientRead);                  ci.OnReadBytes += new ConnectionReadBytes(ClientReadBytes);            if (ClientConnected != null) //Raise the event                ClientConnected();                  return true;            }
0
 
LVL 16

Expert Comment

by:SriVaddadi
ID: 33566486
And ofcourse you will have to register for the event using AddHandler in your vb code.
0
 

Author Comment

by:KristjanLaane
ID: 33566815
thank you so much !!!!! this is amazing help !!!!!!

i added the below code on top of making the changes 1 to 4, and it works except the original function has now stopped working "my vb app initiliazes the server like this, which makes it feed files to the client"
i.e. the msgbox part of the code below now works but the SubstitutingFileReader feeding files part does not: any ideas y?

thanks again!!!

  Private http As HttpServer

    Private somereader As SubstitutingFileReader



    Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        http = New HttpServer(New Server(8080)) '80 '5902

        somereader = New SubstitutingFileReader()

        http.Handlers.Add(somereader)

        AddHandler http.ClientConnected, AddressOf ActionHere

    End Sub



    Private Function ActionHere()

        MsgBox("tore")

        Return True

    End Function

Open in new window

0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 16

Expert Comment

by:SriVaddadi
ID: 33566896
I m not sure if you adding the right object. Handlers is an arraylist for httphandlers and you are trying to add some file reader which is not correct. You should add any object that implements IHttpHandler interface else it would fail
0
 

Author Closing Comment

by:KristjanLaane
ID: 33567147
the file feeding works without the line AddHandler http.ClientConnected, AddressOf ActionHere and i got this SubstitutingFileReader code from the author at http://www.codeproject.com/KB/IP/http.aspx
so it seems that the http.ClientConnected handling somehow intereferes...

you have answered my main question though, so ill work on this independently, thank you for an amazing answer !!!
0
 
LVL 16

Expert Comment

by:SriVaddadi
ID: 33567387
You are right. SubstitutingFileReader is infact implements IHttpHandler interface. You could try this and see

Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
        http = New HttpServer(New Server(8080)) '80 '5902
AddHandler http.ClientConnected, AddressOf ActionHere
        somereader = New SubstitutingFileReader()
        http.Handlers.Add(somereader)
            End Sub
0
 

Author Comment

by:KristjanLaane
ID: 33567589
tried it but didnt help. thanks anyway!
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
Introduction HyperText Transfer Protocol (http://www.ietf.org/rfc/rfc2616.txt) or "HTTP" is the underpinning of internet communication.  As a teacher of web development I have heard many questions, mostly from my younger students who have come to t…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now