Saturday, September 03, 2005

Modbus TCP simulator

I got a requirement to develop a Modbus TCP simulator.
Thought of doing something quickly using VB6. Then ended up with limitaion of good threading library. Then thought of doing in VB.Net. Coded using MsFlexGrid controls. Found them looking very nice. All working fine for 15 minutes. Suddenly there is a red cross across the Grid. After 10 minutes another grid got the same. Then observed Microsoft already accepted that bug and I need to hunt for a patch to fix it. Left that option too.

Then thought of doing in VC6 using MFC Dialog. Another problem, I want to simulate 64 AI, 64 AO, 64 DO and 64 DI. So thought of using text boxes for AI and AO and CheckBoxes for DI and DO. Another limitation, I cant have more than 255 controls on a Dialog box. As all frames are inherited from Dialog boxes no option left.

Then decided to use VB UI and VC library. I am more biased towards pthread library (ftp://sources.redhat.com/pub/pthreads-win32) than Windows. Just decided to use Win API instead of going through big loop of ATL and COM stuff.

Interesting I got good working Simulator. Its not complete but easy to enhance.

I have VB6 application which essentially has code to export handles of controls to vc library.

Nice Coding practice for byte packing

I am trying to write a code to using SOCK_RAW using PACKET protocol family PF_PACKET.
My intention to find out healthiness of Target with minimum overhead. Instead of trying to call connect i want to use ICMP protocols like ping. While doing that i thought why cant I do event ARP. Then started looking for some sample code for ARP.

I found Blacky Room at fdin. He got simple codes for lower level Ethernet Protocols. Ofcourse the site is in Japanese language. But can access code samples.

One good thing i liked at these code samples is the way packing of bytes is done before calling send. In the following function , buffer is a character array. And eth and arp are just pointers.
Iinitially these pointers are just addressed to respective positions. Then as members are filled buffer is ready.

Normally i do other way around. First i update structures and then assign to each byte of buffer like buf[0] = arp->arp_hrd.

But this method essentially eliminates second copy and more secure.


int send_arprequest(int sock, struct dev *dev, struct addr *src, struct addr *dst)
{
struct sockaddr_ll sll;
struct ether_header *eth;
struct ether_arp *arp;
char buf[sizeof(struct ether_header) + sizeof(struct ether_arp)];

memset(&sll, 0, sizeof(sll));
sll.sll_family = PF_PACKET;
sll.sll_ifindex = dev->index;
sll.sll_halen = ETH_ALEN;
memcpy(&sll.sll_addr, dst->mac, ETH_ALEN);

memset(buf, 0, sizeof(buf));
eth = (struct ether_header *)buf;
arp = (struct ether_arp *)((char *)eth + sizeof(struct ether_header));

/* arp header */
arp->arp_hrd = htons(ARPHRD_ETHER);
arp->arp_pro = htons(ETH_P_IP);
arp->arp_hln = ETH_ALEN;
arp->arp_pln = IP_LEN;
arp->arp_op = htons(ARPOP_REQUEST);
memcpy(arp->arp_sha, src->mac, ETH_ALEN);
memcpy(arp->arp_spa, &(src->ip), IP_LEN);
memset(arp->arp_tha, 0, ETH_ALEN);
memcpy(arp->arp_tpa, &(dst->ip), IP_LEN);

/* ether_header */
memcpy(eth->ether_shost, src->mac, ETH_ALEN);
memcpy(eth->ether_dhost, dst->mac, ETH_ALEN);
eth->ether_type = htons(ETH_P_ARP);

/* send to arp request packet */
return sendto(sock, buf, sizeof(buf), 0, (struct sockaddr *)&sll, sizeof(sll));
}