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);
}