parsing and sending dataframes in C - c

I have some trouble to implement an existing protocol in C, escpecially with creating the data packets.
The Packet looks like this:
HeaderData 1(1Byte) | HeaderData 2(1 Byte) | Length_Data (2 Byte) | Data (Length variable)
I get some data via serial port and it is saved in returnMessage:
int getMessage(char * returnMessage){
int length = 0;
//static char replay[REPLAY_MAX_SIZE];
memset(replay, 0x00, REPLAY_MAX_SIZE);
// goes into the while-loop, if some data comes in
// after a timeout of 20 seconds the program will be terminated
if(select(fd +1 , &set, NULL, NULL, &timeout )){
length = read(fd, returnMessage, REPLAY_MAX_SIZE);
//reinitialize fd_set values
FD_ZERO(&set);
FD_SET(fd, &set);
return length;
}
//printf("[%s] ERROR CANNOT GET MESSAGE\n", __FUNCTION__);
return -1;
}
This data in returnMessage I will enhance to my packet to send it further. But I dont know how.
Maybe there is a way with structs?
struct Packet{
char header1[1];
char header2[2];
char lengthData[20];
char data[MAX_DATA_LENGTH];
};
struct Packet packet;
But how can I copy the data in returnMessage to packet.data[]? And how can I concatenate the data in the struct in order to send the packet.
Have someone an introduction of creating/parsing packets for simple protocols?
Thanks a lot,
Florian

Assuming you get the full packet in your char buffer (*), it is then simple :
struct Packet{
char header1[1];
char header2[2];
short lengthData;
char data[MAX_DATA_LENGTH];
};
void buftopacket(char *buffer, Packet *pkt) {
pkt->header1 = buffer[0];
pkt->header2 = buffer[1];
pkt->lengthData = buffer[2] << 8 + buffer[3]; /* assuming network order */
memcpy(pkt->data, buffer + 4, (pkt->lengthData <= MAX_DATA_LENGTH)
? pkt->lengthData : MAX_DATA_LENGTH); /* do not write pass buffer end*/
}
(*) but nothing ensures that you get full packet in one single read ...

Related

Splitting to data packets for udp but data not send correctly

Im trying to accomplish a udp socket data send and receive, where data will be send as small packets,
my function splits the data and send serially, then at receiver end, I combine them
my data input is like this
typedef struct SenderData {
unsigned short CommandCode;
int DataSize;
void *Data;
} SenderData;
my function goes like this
int send_packets(SenderData pkt_data,int pkt_size)
{
int data_size=0;
int no_cyc=0;
int rem_data=0;
int ndx=0;
int forloop_size=0;
int pending_size=0;
// find the size of data
data_size=pkt_data.DataSize;
if(data_size>pkt_size)
{
// find no of cycle required to send data
no_cyc=data_size/pkt_size;
// find remaining data
rem_data=data_size%pkt_size;
void *complete_data = pkt_data.Data;
void*data_out;
for(ndx=0;ndx<no_cyc;ndx++)
{
// store pkt size to data out;
memmove( data_out, (complete_data+(ndx*sizeof(int)*pkt_size)),pkt_size);
if (sendto(sd, data_out, pkt_size, 0,(struct sockaddr*)&groupSock,sizeof(groupSock)) < 0)
{
perror("sending datagram message");
}
}
forloop_size=no_cyc*pkt_size;
// remaining data size is
pending_size=forloop_size-rem_data;
// send remaining data
memmove( data_out,(complete_data+forloop_size), pending_size);
if (sendto(sd, data_out, pending_size, 0,(struct sockaddr*)&groupSock,sizeof(groupSock)) < 0)
{
perror("sending datagram message");
}
}
return 0;
}
data being send is
int cont[202];
SenderData data;
data.DataSize=sizeof(cont);
data.Data=&cont;
and my function call is like this
send_packets(data,100);
im doing the reverse of this function at receipt end
but when i run the code, it seams my data transfer has some issue, when i print the count array at the receipt end, im getting long numbers instead of data

How to handle short counts from write() and read() in Unix IO?

I am writing a multi-threaded program with C. I want to send and receive data between the server and the clients using write and read function. I've tried something like this when I am writing data with its size - payload_size.
if(payload_size != 0 && data != NULL){
ssize_t ret;
int size = payload_size;
while(size > 0){
ret = write(fd, data, payload_size);
size -= ret;
data += ret;
}
// if(write(fd, data, payload_size) < payload_size) {
// debug(" payload write less than requested");
// //return -1;
// //write the bytes that have not yet been written
// }
}
If the above works properly, I would like to use it on a struct I created. The struct have fields:
enter code heretypedef struct jeux_packet_header {
uint8_t type; // Type of the packet
uint8_t id; // Invitation ID
uint8_t role; // Role of player in game
uint16_t size; // Payload size (zero if no payload)
uint32_t timestamp_sec; // Seconds field of time packet was sent
uint32_t timestamp_nsec; // Nanoseconds field of time packet was sent
} JEUX_PACKET_HEADER;
Is this approach proper to use?
JEUX_PACKET_HEADER *hdr;
ssize_t ret_size;
int size_temp = sizeof(JEUX_PACKET_HEADER);
while(size_temp > 0){
ret_size = write(fd, hdr, sizeof(JEUX_PACKET_HEADER));
size_temp -= ret_size;
hdr += ret_size;
}
How does it work on the read() function?
read(fd, payload, hdr->size) < hdr->size);
How do I continue read from the fd when short counts happen?
Thank You!

C code to get the interface name for the IP address in Linux

How can I get the interface name for the IP address in linux from C code ?
e.g. I'd like to get the interface name ( like etho , eth1 , l0 ) assigned for the IP address 192.168.0.1
Using /proc/net/arp you can match it. Here is a command line tool example.
usage: getdevicebyip 192.168.0.1
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv){
if (argc < 2) return 1;
FILE *fp = fopen("/proc/net/arp", "r");
char ip[99], hw[99], flags[99], mac[99], mask[99], dev[99], dummy[99];
fgets(dummy, 99, fp); //header line
while (fscanf(fp, "%s %s %s %s %s %s\n", ip, hw, flags, mac, mask, dev) != EOF)
if (!strcmp(argv[1],ip))
printf("%s\n",dev);
return 0;
}
You can use getifaddrs. See man 3 getifaddrs for usage information. This will only work on a Unix-like systems.
netlink is a way to do this on Linux. I think it might even be a proper way to do it on Linux (even though it isn't portable).
The strategy is:
Get a list of addresses on interfaces from the kernel by sending a netlink message.
Find the address you want (I have hard coded the one I want as address_dq) and record its interface (a number at this stage)
Get a list of interfaces by sending another netlink message,
Find the number of the interface matching the number you recorded in step (2).
Get the name of the interface.
The code below is not pretty, but I'm sure you could do a better job of it. I have been a especially sloppy by not checking for a multipart message (checking for the NLM_F_MULTI flag and for a message type of NLMSG_DONE is the way to do it). Instead I have just assumed the response to the first message is multipart -- it is on my machine -- and chewed up the NLMSG_DONE message which follows.
Code...
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, void ** argv) {
// This is the address we want the interface name for,
// expressed in dotted-quad format
char * address_dq = "127.0.0.1";
// Convert it to decimal format
unsigned int address;
inet_pton(AF_INET, address_dq, &address);
char buf[16384];
// Our first message will be a header followed by an address payload
struct {
struct nlmsghdr nlhdr;
struct ifaddrmsg addrmsg;
} msg;
// Our second message will be a header followed by a link payload
struct {
struct nlmsghdr nlhdr;
struct ifinfomsg infomsg;
} msg2;
struct nlmsghdr *retmsg;
// Set up the netlink socket
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
// Fill in the message
// NLM_F_REQUEST means we are asking the kernel for data
// NLM_F_ROOT means provide all the addresses
// RTM_GETADDR means we want address information
// AF_INET means limit the response to ipv4 addresses
memset(&msg, 0, sizeof(msg));
msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg.nlhdr.nlmsg_type = RTM_GETADDR;
msg.addrmsg.ifa_family = AF_INET;
// As above, but RTM_GETLINK means we want link information
memset(&msg2, 0, sizeof(msg2));
msg2.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
msg2.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg2.nlhdr.nlmsg_type = RTM_GETLINK;
msg2.infomsg.ifi_family = AF_UNSPEC;
// Send the first netlink message
send(sock, &msg, msg.nlhdr.nlmsg_len, 0);
int len;
// Get the netlink reply
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
// Loop through the reply messages (one for each address)
// Each message has a ifaddrmsg structure in it, which
// contains the prefix length as a member. The ifaddrmsg
// structure is followed by one or more rtattr structures,
// some of which (should) contain raw addresses.
while NLMSG_OK(retmsg, len) {
struct ifaddrmsg *retaddr;
retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);
int iface_idx = retaddr->ifa_index;
struct rtattr *retrta;
retrta = (struct rtattr *)IFA_RTA(retaddr);
int attlen;
attlen = IFA_PAYLOAD(retmsg);
char pradd[128];
// Loop through the routing information to look for the
// raw address.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFA_ADDRESS) {
// Found one -- is it the one we want?
unsigned int * tmp = RTA_DATA(retrta);
if (address == *tmp) {
// Yes!
inet_ntop(AF_INET, RTA_DATA(retrta), pradd, sizeof(pradd));
printf("Address %s ", pradd);
// Now we need to get the interface information
// First eat up the "DONE" message waiting for us
len = recv(sock, buf, sizeof(buf), 0);
// Send the second netlink message and get the reply
send(sock, &msg2, msg2.nlhdr.nlmsg_len, 0);
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
while NLMSG_OK(retmsg, len) {
struct ifinfomsg *retinfo;
retinfo = NLMSG_DATA(retmsg);
if (retinfo->ifi_index == iface_idx) {
retrta = IFLA_RTA(retinfo);
attlen = IFLA_PAYLOAD(retmsg);
char prname[128];
// Loop through the routing information
// to look for the interface name.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFLA_IFNAME) {
strcpy(prname, RTA_DATA(retrta));
printf("on %s\n", prname);
exit(EXIT_SUCCESS);
}
retrta = RTA_NEXT(retrta, attlen);
}
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
}
retrta = RTA_NEXT(retrta, attlen);
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
When run as above, returns Address 127.0.0.1 on lo.
Using "192.168.1.x" instead of "127.0.0.1" it instead returns Address 192.168.1.x on eth0.

Raw Sockets : Receiver printing garbage values

I am trying to send across a character array using a transmitter and a receiver program using raw sockets. I am able to get the correct number of bytes sent at the receiver side, but the values printed out are garbage. Could someone help me out here?
Transmitter:
int create_raw_socket(char *dev)
{
struct sockaddr_ll sll;
struct ifreq ifr;
int fd, ifi, rb;
bzero(&sll, sizeof(sll));
bzero(&ifr, sizeof(ifr));
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
assert(fd != -1);
strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ);
ifi = ioctl(fd, SIOCGIFINDEX, &ifr);
assert(ifi != -1);
sll.sll_protocol = htons(ETH_P_ALL);
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
rb = bind(fd, (struct sockaddr *)&sll,sizeof(sll));
assert(rb != -1);
return fd;
}
int SendPacket(char *dev ,unsigned char *send_packet, int packet_len)
{
int num_sent= 0;
int sockaddress = create_raw_socket(dev);
if((num_sent = write(sockaddress, &send_packet, packet_len)) != packet_len)
{
close(sockaddress);
return 0;
}
else
{
close(sockaddress);
return 1;
}
}
int main(int argc, char**argv)
{
int x,fd,s;
char *send_packet="HELLO";
int len = sizeof(send_packet);
while(1)
{
if(!SendPacket((argv[1]), send_packet, len))
perror("Error sending packet");
else
printf("Packet sent successfully with payload : %s\n" ,send_packet);
}
return 0;
}
Receiver :
int main(int argc, char **argv)
{
struct sockaddr addr;
int sock_fd, fromlen,s;
char buf[PACKET_LENGTH];
char *dev = argv[1];
while(1)
{
fromlen=sizeof(addr);
sock_fd = create_raw_socket(dev); /* Creating the raw socket */
int x= recvfrom(sock_fd,&buf,sizeof(buf),0,&addr,&fromlen);
printf("\n Number of bytes of data received is %d \n",x);
printf("\nPayload Received from client... is %s \n", buf);
close(sock_fd);
}
return 0;
}
Change
write(sockaddress, &send_packet, packet_len)
to
write(sockaddress, send_packet, packet_len)
send_packet is already the address of the buffer to be sent, if you take the address of this address (more precisely the address of the variable holding the address), you will read the wrong memory for the buffer
Similarly for recvfrom:
recvfrom(sock_fd, buf, sizeof(buf), 0, &addr, &fromlen)
You have several problems:
This line
if((num_sent = write(sockaddress, &send_packet, packet_len)) != packet_len)
Should say just send_packet instead of &send_packet. send_packet is a pointer that points to the desired packet data, so there's no need to take its address -- you don't want to write out the literal address of that pointer into the packet, that just simply won't work.
This is wrong:
char *send_packet="HELLO";
int len = sizeof(send_packet);
sizeof(send_packet) will always be the size of a pointer on your system, typically either 4 or 8 bytes. You really want to either declare send_packet as an array type (e.g. char send_packet[] = ...), or use strlen to compute its length at runtime (e.g. int len = strlen(send_packet) + 1;). In your case, you're either sending too little data (4 bytes) or too much data (8 bytes), both of which are problematic.
Your printf code in the client assumes that the data it receives is null-terminated, which it is not necessarily. You should either manually null-terminate the data before printing it (or using any other string functions, for that matter), or tell printf the limit of how much data to print. I'd suggest null-terminating it like so:
char buf[PACKET_LENGTH + 1]; // +1 for null terminator
int x = recvfrom(sock_fd,buf,PACKET_LENGTH,0,&addr,&fromlen);
if(x >= 0)
buf[x] = 0;
Your code has poor const correctness. SendPacket should take a const char* instead of char* parameter, and send_packet should either be declared as char[] or as const char*. The conversion from string literals to char* is deprecated and should be avoided in all new C code.
Using printf to print the buffer will print a string until the en of string character is reached. If you see the original string followed by garbage characters, this may be the reason.
You should probably introduce a 0 after the last byte returned by recvfrom, or you will print whatever value was in the memory that recvfrom did not overwrite. It could even try to access memory outside the buffer.
Try adding something like:
int x= recvfrom(sock_fd,&buf,sizeof(buf) - 1,0,&addr,&fromlen);
buf[x - 1] = 0;
Note: that changes the maximum size of what is read, it is just an example of how to do it.

how to handle packets in multi-threaded server client program?

I currently have a client app that works but it is single threaded.
my packets look like this: < len_of_data>|< data>"
"|" is used as a separator for my data.
< len_of_data> is always 4 digits long followed.
< data> looks like: |< transaction id>|< command>|< buflen>|< buf>|< checksum>|
my code to create the packets is:
_snprintf_s(data_buffer, WS_MAX_DATA_PACKET_SIZE,
WS_MAX_DATA_PACKET_SIZE - 1,
"%s%d%s%d%s%d%s%s%s%d%s",
WS_PACKET_SEP, pkt->transaction_id,
WS_PACKET_SEP, pkt->command,
WS_PACKET_SEP, pkt->bufsize,
WS_PACKET_SEP, pkt->buf,
WS_PACKET_SEP, pkt->checksum, WS_PACKET_SEP);
buf_len = strlen(data_buffer);
_snprintf_s(send_buffer, WS_MAX_DATA_PACKET_SIZE,
WS_MAX_DATA_PACKET_SIZE - 1, "%04d%s%s",
buf_len, WS_PACKET_SEP, data_buffer);
buf_len = strlen(send_buffer);
// Send buffer
bytes_sent = send(ConnectSocket, send_buffer, buf_len, 0);
The client thread sends a command to the server, then calls a GetIncomingPackets() function. In GetIncomingPackets(), I call recv() to get 5 bytes, this should be the len of the rest of packet, I parse these 5 bytes and verify that they match my expected format. Then I convert the first 4 bytes to an integer, x. Then I call recv() again to get x bytes more and then parse those out into my packet structure.
The problem happens when I add another thread to do the same thing (send and receive commands).
I start my app and fire 2 threads and send them to send different commands and wait for responses. When the threads call GetIncomingPackets(), the data I am getting back is invalid. The first 5 bytes I am expecting are missing sometimes, and I just get the following 5 bytes, therefore I am unable to get my < len_of_data > packet.
I even added a critical section block between the 2 recv() calls in my GetIncomingPackets() so the treads dont interrupt each other while getting a full packet.
Without some extra code for error checking, this how the function looks like
#define WS_SIZE_OF_LEN_PACKET 5
bool GetIncomingPackets(SOCKET sd, dev_sim_packet_t *pkt )
{
char len_str_buf[WS_SIZE_OF_LEN_PACKET + 1] = {0}; // + 1 for NULL char
char data_buf[WS_MAX_DATA_PACKET_SIZE + 1] = {0};
int ret = 0;
int data_len = 0;
EnterCriticalSection( &recv_critical_section );
nReadBytes = WS_RecvAll(sd, len_str_buf, WS_SIZE_OF_LEN_PACKET );
ret = WS_VerifyLenPacket(len_str_buf);
// Convert data packet lenght string received to int
data_len = WS_ConvertNumberFromString(len_str_buf, WS_SIZE_OF_LEN_PACKET );
// Get data from packet
nReadBytes = WS_RecvAll(sd, data_buf, data_len);
LeaveCriticalSection( &recv_critical_section );
ret = ParseMessager(data_buf, data_len, pkt);
}
My question is, what could be causing this problem, and how could I fix it? Or is there better ways to do what i am trying to do. The reason that I'm trying to make it multi-threaded is because my app will communicate with 2 other sources, and I want to have a thread to handle each request that comes in from either source.
thanks in advance and feel free to ask any questions if I didn't explain something well.
Here's the code for WS_RecvAll(). The buffer is a static buffer declared in GetIncomingPackets() like this:
char data_buf[WS_MAX_DATA_PACKET_SIZE + 1] = {0}; // + 1 for NULL char
int WS_RecvAll(SOCKET socket_handle, char* buffer, int size)
{
int ret = 0;
int read = 0;
int i = 0;
char err_buf[100] = {0};
while(size)
{
ret = recv(socket_handle, &buffer[read], size, 0);
if (ret == SOCKET_ERROR)
{
printf("***ERROR***: recv failed, error = %d\n", WSAGetLastError());
return WS_ERROR_RECV_FAILED;
}
if (ret == 0) {
break;
}
read += ret;
size -= ret;
}
return read;
}
It's very difficult to debug MT problems, particularly at one remove, but if you are using astatic buffer, should not:
LeaveCriticalSection( &recv_critical_section );
ret = ParseMessager(data_buf, data_len, pkt);
be:
ret = ParseMessager(data_buf, data_len, pkt);
LeaveCriticalSection( &recv_critical_section );
And why use a static buffer in any case?
Im curious to know whether you have used the same socked descriptor in both the threads to connect to the server.

Resources