How to save value of buffer from recvfrom() into array? - c

I am working on BSD sockets and I use this function
int recvfrom( int socket , void *buffer , size_t nbytes , int flags , struct sockaddr *sender , int *addrlen)
but before printing a message in server I want to save value of buffer in array of char and make some operations. How to do it?
EDIT: example
Buffer stores a message "Hello", my array should look like arr[]={'h','e','l','l','o'}

recvfrom() function
int recvfrom( int socket , void *buffer , size_t nbytes ,
int flags , struct sockaddr *sender , int *addrlen);
allows the user to receive data from an UDP socket. On success (return value > 0) it returns the number of received bytes, writing up to nbytes bytes to memory area pointed by buffer. Originator's address and its len are also written by the function respectively in sender and addrlen pointers provided by the caller.
So, in order to have incoming bytes in your char array (chars are bytes!) you simply have to pass it to the recvfrom as buffer parameter.
#define MAX_RECV_BUF_LEN 100
char arr[MAX_RECV_BUF_LEN + 1];
struct sockaddr senderAddr;
int addrLen, res;
res = recvfrom( yourSocketDescr , arr, MAX_RECV_BUF_LEN, yourFlags , &senderAddr, &addrLen);
if ( res > 0 )
{
arr[res] = 0; // Add a string terminator. Useful only if you expect 'printable' data
// ... some operations
}
/* else... manage errors */

Related

parsing and sending dataframes in 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 ...

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.

linux fork socketpair sock_dgram

I'm new to socketpairs and I need my children each to pass information from a structure to the parent.I was told this can be done using SOCK_DGRAM but I don't know how to do it.I looked over the internet but i couldn't find a concrete example.Can you please show for example hoe can you pass to the parent a structure made out of 2 ints and a string maybe ?I just want an example so I can understand how I could build this kind of socketpair and send information through it.Thank you
How about the following:
int sockets[2];
if (socketpair(AF_INET, SOCK_DGRAM, 0, sockets) != -1)
{
int res = fork();
if (res == 0)
{
/* In child process */
/* We only need one socket, so close the other */
close(sockets[0]);
struct some_structure my_struct;
write(sockets[1], &my_struct, sizeof(my_struct));
/* All done */
exit(0);
}
else if (res > 0)
{
/* In parent process */
/* We only need one socket, so close the other */
close(sockets[1]);
struct some_structure my_struct;
read(sockets[0], &my_struct, sizeof(my_struct));
}
}
The above code doesn't check for, or handle, errors. It can't handle structures containing pointers, structures using arrays are okay though.
Assuming that your string is represented as a char* as in
struct data {
int i, j;
char *s;
};
you need to devise some serialization format, because sending a pointer won't work; the pointee is not passed so it won't point to anything useful in the receiver (the parent). A simple format would be to put the integers end-to-end, then directly append the string including its NUL terminator, so you'd get
int senddata(int fd, struct data const *d)
{
size_t msglen = 2 * sizeof(int) + strlen(d->s) + 1;
char *msg = malloc(msglen);
if (msg == NULL)
return -1;
((int *)msg)[0] = d->i;
((int *)msg)[1] = d->j;
strcpy(msg + 2 * sizeof(int), d->s);
ssize_t r = send(fd, msg, msglen, 0);
free(msg);
return r;
}
with a corresponding receive function for the parent. You might want to put some maximum length on the string, because the parent needs to know the size of the message in advance.

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.

Send a structure through a socket using tpl for serialization using c

After reading a few related questions I've decided to use the tpl library to serialize my structures in order to send and receive them through sockets. I'm having trouble understanding how to send and receive the tpl images using sockets. I get a segfault error on the server side when I call the tpl_dump function.
I know the sockets are working on both end because I was using the code to previously send strings back and forth. I was also able to use tpl to create and read an tpl image on the client without any issues.
This isn't the structure I eventually want to be sending back and forth, but I hope to figure this sample out so I can do this in the future. I know I'm mishandling something between the incoming buffer and the tpl_dump. I'm still learning C (as evidenced by my previous questions) so I apologize if I have glaring errors in my code.
Edits
The issues Nikolai pointed out have been corrected in the code below. However the server code logs error: tpl_load to non-root node and still segfaults at tpl_unpack(tn, 0);
Client Code:
tpl_node *tn;
void *addr;
size_t len;
struct ci {
char c;
int i;
};
struct ci sample = {'a', 1};
tn = tpl_map("S(ci)", &sample); /* pass structure address */
tpl_pack(tn, 0);
tpl_dump(tn, TPL_MEM, &addr, &len );
tpl_free(tn);
send(sockfd, addr, len, 0);
Server Code:
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
//error handling
} else {
tpl_node *tn;
struct ci {
char c;
int i;
};
struct ci recieve;
tpl_map("S(ci)", &recieve);
tpl_load(tn, TPL_MEM, &buf, &nbytes );
tpl_unpack(tn, 0);
tpl_free(tn);
In case this will come in handy - tpl user's guide
It looks like you are misusing the tpl_dump, at least on the client - the second argument is supposed to be void**, not int*. The macro stores address of the allocated buffer into your addr integer, so you are sending address (plus some garbage), not data to the server. The sequence of calls on the server side also look out of order.
Looking closer at your source:
remove ampersands (&) from buf and len; the tpl_load expects void* and size_t;
you need to free() the memory when you're done;
you need to watch out for short socket reads - you might get less (or more) then you sent on a read from TCP socket.
Here's a simple complete example without sockets:
#include <stdlib.h>
#include <stdio.h>
#include "tpl.h"
int main( int argc, char* argv[] )
{
char* buffer;
size_t i, len;
tpl_node *tn;
struct ci { char c; int i; } s = {'a', 1}, s1;
printf( "input {%c,%d}\n", s.c, s.i );
tn = tpl_map( "S(ci)", &s ); /* pass structure address */
tpl_pack( tn, 0 );
tpl_dump( tn, TPL_MEM, &buffer, &len );
tpl_free( tn );
printf( "size = %lu\n", len );
tn = tpl_map( "S(ci)", &s1 );
tpl_load( tn, TPL_MEM, buffer, len );
tpl_unpack( tn, 0 );
tpl_free( tn );
free( buffer );
printf( "output {%c,%d}\n", s1.c, s1.i );
return 0;
}
Anyone looking at this thread, Eric de Araujo's post from Jul 16 '09 at 14:49 (his corrected code) does work ONLY IF you correct one error in his Server Code section:
tpl_map("S(ci)", &receive);
must be changed to:
tn = tpl_map("S(ci)", &receive);
Per request, here is a successful implementation using sockets:
Client Code:
tpl_node *tn;
void *addr;
size_t len;
struct ci {
char c;
int i;
};
struct ci sample = {'a', 1};
tn = tpl_map("S(ci)", &sample); /* pass structure address */
tpl_pack(tn, 0);
tpl_dump(tn, TPL_MEM, &addr, &len );
tpl_free(tn);
send(sockfd, addr, len, 0);
Server Code:
char buf[256]; // buffer for client data
int nbytes;
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
//error handling
} else {
tpl_node *tn;
struct ci {
char c;
int i;
};
struct ci receive;
tpl_map("S(ci)", &receive);
tpl_load(tn, TPL_MEM, buf, nbytes );
tpl_unpack(tn, 0);
tpl_free(tn);
printf("Struct: {%c,%d}\n", receive.c, receive.i);

Resources