Build your own network usage monitor in C# (raw socket)

Although there are lots of excellent network monitor available, e.g NetWorx, DU Meter, I just think to build my own network monitor. Firstly I can explore the socket programming, secondly it’s free of charge.

OK, let’s do it.

Create a new WinForm project from Visual Studio

Network monitor
Network monitor

 

 

 

 

public MainForm()
{
	//
	// Required for Windows Form Designer support
	//
	InitializeComponent();
	//
	// Set your PC ip address
	//
	rs.CreateAndBindSocket(ipaddress);
	rs.Run();
}
//when main window showing up, we update meter text
private void ShowMainWindow(object sender, System.EventArgs e)
{
	todayUsage.Text = string.Format("Today's Usage: {0}",FormatSize((ulong)rs.TotalReceivedBytes));	
}
//define ip header
[StructLayout(LayoutKind.Explicit)]  
public   struct   IPHeader  
{  
	[FieldOffset(0)]    public  byte       ip_verlen;    
	[FieldOffset(1)]    public  byte       ip_tos;    
	[FieldOffset(2)]    public  ushort     ip_totallength;  
	[FieldOffset(4)]    public  ushort     ip_id;  
	[FieldOffset(6)]    public  ushort     ip_offset;    
	[FieldOffset(8)]    public  byte       ip_ttl;    
	[FieldOffset(9)]    public  byte       ip_protocol;    
	[FieldOffset(10)]   public  ushort   ip_checksum;    
	[FieldOffset(12)]   public  uint       ip_srcaddr;    
	[FieldOffset(16)]   public  uint       ip_destaddr;    
}  
//the core function - raw socket   
public   class   RawSocket  
{
	private		bool	error_occurred;  
	private	  int	totalReceivedBytes = 0;
	private	  const   int   BUFFER_SIZE = 8192;
	private	  byte []	receive_buf = new byte[BUFFER_SIZE];
	private	  Socket	socket   =   null;    
	const	  int   SIO_R = unchecked((int)0x98000001);  
	const	  int   SIO_1 = unchecked((int)0x98000002);  
	const	  int   SIO_2 = unchecked((int)0x98000003);  

	public   int   TotalReceivedBytes
	{  
		get	{return   totalReceivedBytes;}  
		set	{totalReceivedBytes = value;}
	}

	public   RawSocket() 
	{  
		error_occurred=false;   
	}  
       
	public   void   CreateAndBindSocket(string   IP)
	{  
		socket   =   new   Socket(AddressFamily.InterNetwork,   SocketType.Raw,   ProtocolType.IP);  
		socket.Blocking   =   false; 
		socket.Bind(new   IPEndPoint(IPAddress.Parse(IP),   0));  
		if   (SetSocketOption()==false)   
			error_occurred=true;  
	}  
   
	public   bool   ErrorOccurred  
	{  
		get  { return   error_occurred;}  
	}

	public   void   Shutdown()  
	{  
		error_occurred = true;
		if(socket   !=   null)  
		{  
			socket.Shutdown(SocketShutdown.Both);  
			socket.Close();  
		}  
	}  
  
	private   bool   SetSocketOption()  
	{  
		bool   ret_value   =   true;  
		try  
		{  
			socket.SetSocketOption(SocketOptionLevel.IP,   SocketOptionName.HeaderIncluded,   1);       
			byte   []IN   =   new   byte[4]{1,   0,   0,   0};  
			byte   []OUT   =   new   byte[4];      
			int   ret_code   =   socket.IOControl(SIO_R,   IN,   OUT);
			ret_code   =   OUT[0]   +   OUT[1]   +   OUT[2]   +   OUT[3];   
			if(ret_code   !=   0)   ret_value   =   false;  
		}  
		catch(SocketException)  
		{  
			ret_value   =   false;  
		}  
		return   ret_value;  
	}

	unsafe   private   bool   IsInternetTraffic(byte[] buf)  
	{  
		byte	temp_protocol=0;  
		uint	temp_version=0;  
		uint	temp_ip_srcaddr=0;  
		string  sourceIP;  
  
		fixed(byte   *fixed_buf   =   buf)  
		{  
			IPHeader   *   head   =   (IPHeader   *)   fixed_buf;  
			temp_protocol   =   head->ip_protocol;  
			temp_version   =(uint)(head->ip_verlen   &   0xF0)   >>   4;  
			temp_ip_srcaddr   =   head->ip_srcaddr;  
			sourceIP   =   new   IPAddress(temp_ip_srcaddr).ToString();  
		}
                //we only capture internet traffic  
		return !sourceIP.StartsWith("10.") 
			&& !sourceIP.StartsWith("172.16.") 
			&& !sourceIP.StartsWith("127.") 
			&& !sourceIP.StartsWith("192.168.");
	}  
       
	private void ReceiveCallback( IAsyncResult ar)
	{
		try
		{
			int received_bytes = socket.EndReceive(ar);
			if(received_bytes>0 && IsInternetTraffic(receive_buf))
			{
				totalReceivedBytes += received_bytes;
			}
		}
		finally
		{
			socket.BeginReceive(receive_buf,0,BUFFER_SIZE,SocketFlags.None,new AsyncCallback(ReceiveCallback),null);
		}
	}
		
	public   void   Run()    
	{  
		socket.BeginReceive(receive_buf,0,BUFFER_SIZE,SocketFlags.None,new AsyncCallback(ReceiveCallback),null);
	}
}

Exchange Web Services (EWS) programming with Exchange Server 2010 in C#

I have an application to sniff email notification from Exchange Server and automatically insert data record to SQL database. Because recently our IT department upgraded MS Exchange Server to 2010 and Exchange Server 2010 does not support WebDAV any more, my robust WebDAV program is dead 🙁

To revive my application, I have to migrant WebDAV to EWS, because WebDAV has been replaced by Exchange Web Services (EWS). EWS is relatively new, and there is no too much information I can use. Here to share my EWS programming experience.

private void ReceiveEmail(object sender, EventArgs e)
{
    ExchangeServiceBinding esb = new ExchangeServiceBinding();
    esb.Credentials = new NetworkCredential(username, password, domain);
    ServicePointManager.ServerCertificateValidationCallback =
      delegate(Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
      {
          // trust any certificate
          return true;
      };

    esb.Url = @"https://exchangeserver/EWS/Exchange.asmx";

    FindItemType findRequest = new FindItemType();
    findRequest.ItemShape = new ItemResponseShapeType();
    findRequest.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;

    DistinguishedFolderIdType inbox = new DistinguishedFolderIdType();
    inbox.Id = DistinguishedFolderIdNameType.inbox;
    findRequest.ParentFolderIds = new []{inbox};
    findRequest.Traversal = ItemQueryTraversalType.Shallow;


    findRequest.ItemShape.BodyType = BodyTypeResponseType.Text;
    findRequest.ItemShape.BodyTypeSpecified = true;

    FindItemResponseType response = esb.FindItem(findRequest);
    FindItemResponseMessageType responseMessage =
      response.ResponseMessages.Items[0]
          as FindItemResponseMessageType;
    ArrayOfRealItemsType items = responseMessage.RootFolder.Item as ArrayOfRealItemsType;


    foreach (MessageType item in items.Items)
    {
         MessageType msg = (MessageType) item;
         string emailBody = GetMessageBody(esb, msg);
         //delete email
         this.DeleteMessage(esb,msg);
    }
}

private string GetMessageBody(ExchangeServiceBinding binding, MessageType message)
{
    string messageBody = string.Empty;
    MessageType temp = null;

    // Call GetItem on each ItemId to retrieve the
    // item’s Body property and any AttachmentIds.
    //
    // Form the GetItem request.
    GetItemType getItemRequest = new GetItemType();

    getItemRequest.ItemShape = new ItemResponseShapeType();
    // AllProperties on a GetItem request WILL return
    // the message body.
    getItemRequest.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;

    getItemRequest.ItemIds = new ItemIdType[1];
    getItemRequest.ItemIds[0] = (BaseItemIdType)message.ItemId;

    // Here is the call to exchange.
    GetItemResponseType getItemResponse = binding.GetItem(getItemRequest);

    // We only passed in one ItemId to the GetItem
    // request. Therefore, we can assume that
    // we got at most one Item back.
    ItemInfoResponseMessageType getItemResponseMessage =
        getItemResponse.ResponseMessages.Items[0]
        as ItemInfoResponseMessageType;

    if (getItemResponseMessage != null)
    {
        if (getItemResponseMessage.ResponseClass ==
            ResponseClassType.Success
            && getItemResponseMessage.Items.Items != null
            && getItemResponseMessage.Items.Items.Length > 0)
            {
                temp = (MessageType)getItemResponseMessage.Items.Items[0];

                if (temp.Body != null)
                    messageBody = temp.Body.Value;
            }
    }
    return messageBody;
}

private void DeleteMessage(ExchangeServiceBinding binding, MessageType message)
{
    // Call DeleteItem on each ItemId to delete the message
    // Form the DeleteItem request.
    DeleteItemType delItemRequest = new DeleteItemType();

    delItemRequest.ItemIds = new ItemIdType[1];
    delItemRequest.ItemIds[0] = (BaseItemIdType)message.ItemId;
    
    // Here is the call to exchange.
    DeleteItemResponseType delItemResponse = binding.DeleteItem(delItemRequest);
}

Dynamically update parity bit during serial communication in C#

Today boss asked me to implement a serial com port simulator. I used MSCommLib COM library in C# to develop this simulator.

The serial protocol I am working on is a bit strange:

The message synchronization is achieved via a technique utilizing the parity bit of serially of transmitted data. The parity bit sent with each byte no longer denotes the byte’s parity, but the parity bit is used instead to indicate the start of new messages.  In this mode, the parity bit is often referred to as the “wake-up bit”.  The parity bit is now used in the following manner:  when the parity bit is set, this denotes the start (i.e. the first byte) of a new message. , the parity bit (or wake-up bit), is only ever set on the first byte (i.e. the address byte) of a message.  The remainder of the message has parity forced to zero.

Therefore, this protocol needs dynamically update the parity bit settings during the message sending. There are many articles about generic serial com programming. However,  it’s hard to find the parity bit toggling. After few hours exploring, I found a way to achieve this.

Like other serial protocol, we have to initialize com port

public void InitComPort(int portNumber)
{
	// Set the com port to be 1
	m_ComPort.CommPort = (short)portNumber;

	// This port is already open, close it to reset it.
	if (m_ComPort.PortOpen)
		m_ComPort.PortOpen = false;

	// Trigger the OnComm event whenever data is received
	m_ComPort.RThreshold = 1;  

	//e, Even. m, Mark. m, (Default) None. o, Odd. s, Space
	// Set the port to 19200 baud, even parity bit, 8 data bits, 1 stop bit (all standard)
	m_ComPort.Settings = "19200,e,8,1";

	// Force the DTR line high, used sometimes to hang up modems
	m_ComPort.DTREnable = true;

	// No handshaking is used
	m_ComPort.Handshaking = MSCommLib.HandshakeConstants.comNone;

	// Use this line instead for byte array input, best for most communications
	m_ComPort.InputMode = MSCommLib.InputModeConstants.comInputModeBinary;

	// Read the entire waiting data when com.Input is used
	m_ComPort.InputLen = 0;

	// Don't discard nulls, 0x00 is a useful byte
	m_ComPort.NullDiscard = false;

	// Attach the event handler
	m_ComPort.OnComm += new MSCommLib.DMSCommEvents_OnCommEventHandler(OnComm);

	m_ComPort.ParityReplace = "0";

	// Open the com port
	m_ComPort.PortOpen = true;
}

Here is the way to toggle the parity bit during sending message

private void SendThread()
{
	while(m_ComPort.PortOpen)
	{
		m_ComPort.PortOpen = false;
		// Change port setting, toggle the parity bit to 1
		m_ComPort.Settings = "19200,m,8,1";
		m_ComPort.PortOpen = true;
		m_ComPort.Output = addr;

		// wait 10 ms to toggle parity bit
		Thread.Sleep(10);
		m_ComPort.PortOpen = false;
		// Change port setting, toggle the parity bit to 0
		m_ComPort.Settings = "19200,s,8,1";
		m_ComPort.PortOpen = true;
		m_ComPort.Output = packet;
	}
}

Edit password protected MS Word document

Some Microsoft Word document has editing restrictions, which is protected by password. If you want to edit the content of the document, you need the password.

Protect Word document
Protect Word document
Password protected
Password protected

What you need to do is to save the document as html format

Save as html
Save as html

 

Open html by using Notepad and delete the password inside of <w:UnprotectPassword> section.

Remove password protection
Remove password protection

Re-open the document by using MS Word. You can freely edit the Word document without inputting any password.

 

2011 Australasian Gaming Expo (AGE) at Darling Harbour

Australasian Gaming Expo (AGE) is one of the largest gaming exhibitions in the world. This year it’s from 21 August to 23 August at Sydney Convention and Exhibition Centre.
AGE entrance

AGE extrance
AGE extrance

Aristocrat show stand

Aristocrat show stand
Aristocrat show stand
Aristocrat poker machine
Aristocrat poker machine

IGT new game theme – Sex and the City

IGT new game theme
IGT new game theme

Konami show stand

Konami show stand
Konami show stand

Shuffle Master show stand

Shuffle Master show stand
Shuffle Master show stand

AGT show stand

AGT show stand
AGT show stand

Cyclic Redundancy Check (CRC) in C#

Microsoft .Net Framework is so powerful, and it provides so many common libraries to use. However, recently I am working on a legacy project to work out CRC32, and I can find no where. OK, I have to DIY. If you need it by chance, here are the source code.

/// 
/// Calculates a 32bit Cyclic Redundancy Checksum (CRC) using the
/// same polynomial used by Zip.
/// 
public class CRC32 : HashAlgorithm
{

    private static readonly UInt32[] crc32Table =
    {
	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
	0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
	0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
	0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
	0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
	0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
	0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
	0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
	0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
	0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
	0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
	0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
	0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
	0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
	0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
	0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
	0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
	0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
	0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
	0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
	0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
	0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
	0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
	0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
	0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
	0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
	0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
	0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
	0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
	0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
	0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
	0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
	0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
	0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
	0x2d02ef8d
    };

    private UInt32 hash;
    private UInt32 seed;
    private const UInt32 DefaultSeed = 0xffffffff;

    /// 
    /// Construct an instance of the CRC32 class, pre-initialising the table
    /// for speed of lookup.
    /// 
    public CRC32()
    {
        this.seed = DefaultSeed;
        Initialize();
    }

    public override int HashSize
    {
        get
        {
            return 32;
        }
    }

    public CRC32(UInt32 seed)
    {
        this.seed = seed;
        Initialize();
    }

    protected override byte[] HashFinal()
    {
        hash = ~hash;
        this.HashValue = new byte[] {
						(byte)((hash>>24) & 0xff),
						(byte)((hash>>16) & 0xff),
						(byte)((hash>>8) & 0xff),
						(byte)(hash & 0xff)
						};
        return HashValue;
    }

    protected override void HashCore(byte[] buffer, int start, int length)
    {
        for (int i = start; i>8) 
                          ^ crc32Table[(buffer[i]) ^ ((hash) & 0x000000FF)];
            }
        }
    }

    public override void Initialize()
    {
        hash = seed;
    }
}

Let’s go skiing this snow season!

Last weekend, we drove almost 500km from Sydney to Thredbo.

Sydney to Snowy Montain
Sydney to Snowy Montain

Friday night, it was freezing and the temperature drops to -5°. We left few bottles outside. Saturday morning, they all iced up. Saturday was sunny but cold. The cold weather still can not stop our passion.

From top of the mountain

Ski is fun but dangerous. I saw at least two people was sent to the hospital by ambulance. My ski pole was also broken.

Domino’s Pizza $5.95 mobile ordering site exploit

Domino’s Pizza has new mobile ordering site, and any value or traditional pizza only $5.95 each pick up.
This deal is for mobile user only. It will re-direct non-mobile user to normal online ordering site, and the price jumps up to $7.95.

From technical perceptive, how does Domino’s server determine a mobile user? Normally a web request contains “User-Agent” to help web server tell who is visiting. This is a typical example of web request. If we change the “User-Agent” content, we can cheat domino’s web server and order $5.95 pizza.

GET / HTTP/1.1
Host: www.dominos.com.au
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive

OK, let’s do it!

  1. Download user agent switcher for your Firefox and install.
  2. Change user agent to iPhone
  3. Star ordering from http://dominos.com.au/mobile.aspx and enjoy $5.95 pizza