how can i define structure to the fields mentioned in recvfrom() function? - c

Below program recieves/captures the packet from the internet and writes into a file (logfile). In my other program i use read() func instead of recvfrom(),but just sending the the buffer doesn't process the packets correctly. Hence i thought of sending two more fields which are in the recvfrom function
int main()
{
int saddr_size,data_size;
struct sockaddr saddr;
unsigned char *buffer = (unsigned char *) malloc(1024);
while(1)
{
saddr_size = sizeof saddr;
//Receive a packet
data_size = recvfrom(sock_raw , buffer , 1024, 0 , &saddr ,(socklen_t*)&saddr_size);
int cont= write(logfile,buffer,data_size);
}
return 0;
}
In the above program, i need to define structure to &saddr and (socklen_t*)&saddr_size). that is instead of sending just the buffer i need to send value of &saddr and (socklen_t*)&saddr_size). How can i do it?i mean to say how to define struct to &sddr and (socklen_t*)&saddr_size)?? please somebody guide me.

No you don't send those fields, those are automatically filled in by the recvfrom function from the information in the received packet.

Related

Best practice of sending data of different sizes over the network

I want to send data in varying sizes over UDP. The size of data to be sent is not fixed. I have the following scenario:
unsigned char buffer[BUFFERSIZE];
int bytes = fill_buffer(buffer, sizeof(buffer)): // Returns number of filled bytes.
sendto(socket, buffer, bytes, 0, (struct sockaddr *)&server, sizeof(server))
In the example above, receiving side does not know how many bytes to receive. I also thought of first sending the number of bytes to receive and then sending the data. But in that case, I don't know what would happen if the packets arrive out-of-order.
Sender side would be
sendto(socket, &bytes, sizeof(bytes), 0, (struct sockaddr *)&server, sizeof(server))
sendto(socket, buffer, bytes, 0, (struct sockaddr *)&server, sizeof(server))
Receving side would be
recvfrom(socket, &bytes, sizeof(bytes), 0, NULL, NULL)
recvfrom(socket, buffer, bytes, 0, NULL, NULL)
But could it be that sent data comes out-of-order?
I think you can send both in a single datagram if you add a message header.
The sender only sends the amount of payload data it has.
The receiver always requests the maximum payload size but examines the header and the return from recvfrom to determine the actual length.
Here's some rough code that illustrates what I'm thinking of:
struct header {
u32 magic_number;
u32 seq_no;
u32 msg_type;
u32 payload_length;
} __attribute__((__packed__));
#define MAXPAYLOAD 1024
struct message {
struct header info;
unsigned char payload[MAXPAYLOAD];
} __attribute__((__packed__));
void
sendone(int sockfd,const void *buf,size_t buflen)
{
struct message msg;
static u32 seqno = 0;
memcpy(&msg.payload[0],buf,buflen);
msg.info.magic_number = 0xDEADADDE;
msg.info.seq_no = seqno++;
msg.info.payload_length = buflen;
sendto(sockfd,&msg,sizeof(struct header) + buflen,...);
}
ssize_t
getone(int sockfd,void *buf,size_t buflen)
{
struct message msg;
ssize_t rawlen;
ssize_t paylen;
static u32 seqno = 0;
rawlen = recvfrom(sockfd,&msg,sizeof(struct header) + MAXPAYLOAD,...);
paylen = msg.info.payload_length;
if (rawlen != (sizeof(struct header) + paylen))
// error ...
memcpy(buf,&msg.payload[0],paylen);
return paylen;
}
The receiver can check the magic number and sequence number to look for corruption or missing/dropped packets, etc.
In fact, you can probably get more efficiency by using sendmsg and recvmsg since they allow you to send a single message using a scatter/gather list. (i.e.) The data would not have to be copied in/out using memcpy from the message struct [you'd only need struct header], so closer to zero copy buffering.
Another option may be to use the MSG_PEEK flag with the recvfrom/recvmsg. I've never used this myself, but it would be something like:
Do recvmsg with length of sizeof(struct header) with MSG_PEEK flag
Do second recvmsg with length of sizeof(struct header) + msg.info.payload_length
This is just a nicety of not having to always provide a maximum sized buffer. Since it involves two syscalls, it may be a bit slower. But, it might allow allow some tricks with selecting a payload buffer from a pool, based on the type of message and/or length
Unlike TCP which is a stream-based protocol, meaning that calls to recv don't exactly correspond to a call to send, UDP is packet based meaning that each recvfrom matches with exactly one sendto. This also means you need to take care of how large each message you send is.
If you send a UDP datagram that is larger that what can be contained in a IP packet, the UDP message will be fragmented across multiple UDP packets, increasing the chance of data loss. That's something you want to avoid. Also, if you're using IPv6, you'll get an error when you attempt to send because IPv6 doesn't support fragmentation.
What does this mean in relation to what you're doing? It means that, roughly speaking, your messages shouldn't be any larger than about 1450 bytes, so you can use that value as the size of your input buffer. Then you can use the return value of recvfrom to see how many bytes were actually read. If your messages are larger than that, you should break them up into multiple messages.
As with any UDP based protocol, you need to account for the case where messages get lost and they need to be retransmitted, or if messages come out of order.
Actually answer to this question was quite simple.
Given:
unsigned char buffer[BUFFERSIZE];
int bytes = fill_buffer(buffer, sizeof(buffer)): // Returns number of filled bytes.
sendto(socket, buffer, bytes, 0, (struct sockaddr *)&server, sizeof(server))
The return value of recvfrom tells us how many bytes are received, although we make a full read,
int bytesReceived = recvfrom(socket, buffer, sizeof(buffer), 0, NULL, NULL);
// Process bytesReceived number of bytes in the buffer

C binary message over amqp

Currently I have a daemon listening for TCP/UDP packets on port X using the recvfrom system call:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
and then the data is send over a message queue with the msgsnd system call:
int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
I would like to replace the msgsnd system call with RabbitMQ and send the messages using amqp protocol. The problem I am facing is the format of the data received and send over the RabbitMQ. When I receive data on port then I try to send it like this:
ssize_t recvfrom(
sockfd, msgbufInst.msgContent, len, flags, src_addr, addrlen
);
send_over_rabbitmq(msgbufInst.msgContent);
where send_over_rabbitmq is pretty much
send_over_rabbitmq(char *rawData){
amqp_bytes_t payload;
payload.len = sizeof(rawData);
payload.bytes = rawData;
int result = amqp_basic_publish((*channel)->conn, 1,
amqp_cstring_bytes("myExchange"),
amqp_cstring_bytes(""), 0, 0, NULL, payload);
}
The payload is send and received successfully but some data is lose. When I consume the message from the queue the payload is not the same as when I used the system call to send/consume messages. I am sure that it has to do with the data types that I am using but can't figure it out yet.
As I noted in a comment:
In the send_over_rabbitmq() function, the value of sizeof(rawData) is probably 8, and maybe only 4 — it's the size of the pointer variable, and not the length of the data that it points at. That probably isn't what you want.
You'll need to send more information to the send_over_rabbitmq() function — most noticeably, the length of the data received from recvfrom(). That means capturing the information — you should be checking the return value from recvfrom() anyway before trying to relay information via RabbitMQ.

Bad file descriptor in recvfrom function

This is my server side code for udp
#include"headers.h"
int main(int argc,char **argv)
{
//------------udp server socket connection------//
int sd1;
struct sockaddr_in serveraddr, clientaddr;
char buffer[100];
char *bufptr = buffer;
int cnt=1,ret;
socklen_t clen;
clen=sizeof(clientaddr);
//int buflen = sizeof(buffer);
sd1=socket(AF_INET,SOCK_DGRAM,0);
printf("udp socket id=%d\n",sd1);
printf("socket created for udp..\n");
if(sd1<0)
{
perror("udp_sfd");
exit(0);
}
printf("server socket created..\n");
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(atoi(argv[1]));
serveraddr.sin_addr.s_addr=INADDR_ANY;
if(bind(sd1,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)
{
perror("bind\n");
exit(0);
}
else
{
while(1)
{
printf("server accept from client\n");
ret=recvfrom(sd1,(char *)bufptr,strlen(buffer),0,(struct sockaddr *)&clientaddr,&clen);
printf("ret=%d\n",ret);
//printf("hello\n");
if(ret<0)
{
perror("recvfrom");
exit(0);
}
else
{
printf("UDP Server received the following:\n \"%s\" message\n", bufptr);
}
//close(sd1);
}
}
close(sd1);
return 0;
}
I am sending tht buffer from client side... and in server side it is giving me an error like this....
Bad file descriptor .... what should I do...
I also changed the name of file descriptor 2 times... still it is not working...
Your recvfrom is bad. Instead of strlen(buffer), you should use sizeof(buffer). Since buffer is on the stack, you may have a large string in there and then you are overflowing the buffer if the recvfrom gets a large amount of data.
I will studying it up some more if that doesn't help.
The problem is in your call to recvfrom:
ret=recvfrom(sd1,(char *)bufptr,strlen(buffer),0,(struct sockaddr *)&clientaddr,&clen);
The third parameter should be the size of the input buffer. But instead, you're calling strlen on the buffer. Because buffer is uninitialized, calling strlen on it is reading uninitialized data which can cause undefined behavior.
Also, unless the client is sending a null terminated string (i.e. some printer characters followed by a null byte) the call to printf will also invoke undefined behavior since any bytes past what was read will be uninitialized.
Pass in the buffer size minus 1 (to leave space for a null byte) instead of calling strlen, and clear the buffer just beforehand.
memset(buffer, 0, sizeof(buffer));
ret=recvfrom(sd1,(char *)bufptr,sizeof(buffer)-1,0,(struct sockaddr *)&clientaddr,&clen);
I think you are closing the socket some where else in your program.
The Bad file descriptor may refer to an invalid file descriptor or it is closed somewhere else in your code or it is already being used somewhere else. I think you need to debug your code a little bit and then manage your socket well.
It is possible that your socket is being closed somewhere by mistake or being corrupted.
You can try creating the new socket as well with different port number.

Is this the correct way to send binary data over UDP using C?

I've been set a task to write some software to communicate from our embedded linux device to a server. The server that I'm to communicate with uses a strict protocol, the protocol is very obscure and proprietary - I wouldn't like to name it on here as the information could be sensitive to the company I work for.
So the data must be in either the form of 4 bit Nibbles (N), 32 bit unsigned ints (U), 32 bit signed ints (S), 8 bit unsigned ints (X) and chars (C). So for example a simplified login structure might be NNNN-User ID followed by XX-some more data, CCCC-access code. So I need to send NNNNXXCCCC in that order to login.
The data needs to be sent via UDP, and then listen for an acknowledgement on the same port. So the way I've done this is I've written a send_and_receive function, and then coded a struct, to send the struct through to the server.
typedef u_int8_t NN;
typedef u_int8_t X;
typedef int32_t S;
typedef u_int32_t U;
typedef char C;
#pragma pack(1)
typedef struct{
NN user_id[2];
X some_data[2];
C access_code[4];
} LogOnRequest;
I then declare and fill in the information for the struct and send it using this function:
void send_and_receive(void* message, void* reply, int do_send, int expect_reply){
struct sockaddr_in serv_addr;
int sockfd, i, slen=sizeof(serv_addr);
int buflen = BUFLEN;
void* buf = NULL;
if ( (strlen(message)) >= BUFLEN)
err("Message too big");
buf = malloc(buflen);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
err("socket");
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_aton(IP_ADDRESS, &serv_addr.sin_addr)==0)
err("inet_aton() failed\n");
if(do_send == TRUE){
strcpy(buf, message);
if (sendto(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, slen)==-1)
err("sendto()");
}
if (expect_reply == TRUE){
if (recvfrom(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, &slen)==-1)
err("recvfrom()");
}
memcpy(reply, buf, BUFLEN);
close(sockfd);
free(buf);
}
Now when I do this I get no reply, and no notice that the packet has been received on the server. Basically I would like to know if I'm doing this correctly, is there a better way to do it? Would it be possible to do the same thing using bash scripts?
Any feedback would be great, because I'm feeling out of my depth on this one.
You need to wait some amount of time for a reply. If you don't get one, you need to retransmit the query and wait again. UDP is a "best effort" delivery service and does not have any built in retries.
You also need to make sure you are sending multi-byte values the same way the other end expects them. Which byte comes first?
As usual in such cases, I'd like to encourage you to use WireShark or any other sniffer software. This will de-cypher all the magic happens after your sendto() attempt: bytes order, actual address/port applied, any feedback received etc. And yes, as #wildplasser said in the comments, you shouldn't send all the buffer. So you have to add "message size" as an input parameter.

why the sendto function needs the third parameter, in socket programming

I was new to socket program.
When learning the sendto function, as the prototype:
ssize_t sendto(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len);
I get to know that the "message" has contain the target IP, and the dest_addr argument also specifies the target IP address.
Is there other usage of the dest_addr argument?
I think you are confusing "message" and "dest_addr".
Let's look at the prototype for sendto in expanded form:
ssize_t sendto (int sockfd,
const void *buf,
size_t length,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen);
sockfd - this is the socket you created with a call to socket()
buf - this is a pointer to an ARRAY OF BYTES (i.e. they could have made buf of type char* ). That is, this is the data that you want to send across the wire encapsulated in a UDP packet.
length - this is how many bytes are in that array. If you didn't pass "length", it wouldn't know if "buf" was 1 byte or 10000 bytes.
flags - Typically 0. This is advanced stuff
dest_addr - this is a pointer to the destination address. Typically you initialize a sockaddr_in instance and cast its pointer value to a sockaddr* type.
addrlen - the size of the dest_addr. typically, sizeof(sockaddr_in). Address length is variable because dest_addr could pointer to an IPV4 address (sockaddr_in type) or an IPV6 address (sockaddr_in6 type), or some other type.
Example of sending a packet from local port 9999 to remote host "1.2.3.4" on its port 8888. Error checking of return codes left out for brevity.
int s;
sockaddr_in addrDest;
sockaddr_in addrLocal;
char* msg = "Hello World";
// create the socket
s = socket(AF_INET, SOCK_DGRAM, 0); // UDP socket
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = htons(9999);
addrLocal.sin_addr = INADDR_ANY; // zero-init sin_addr to tell it to use all available adapters on the local host
// associate this socket with local UDP port 9999
result = bind(s, (struct sockaddr*)&addrLocal, 0);
// send "Hello world" from local port 9999 to the host at 1.2.3.4 on its port 8888
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(8888);
addrDest.sin_addr.s_addr = inet_addr("1.2.3.4");
// strlen(msg)+1 for terminating null char
result = sendto(s, msg, strlen(msg)+1, 0, (struct sockaddr*)&addrDest, sizeof(addrDest));
No, Message Contains what you will send, here is an example:
int spatula_count = 3490;
char *secret_message = "The Cheese is in The Toaster";
int stream_socket, dgram_socket;
struct sockaddr_in dest;
int temp;
// first with TCP stream sockets:
// assume sockets are made and connected
//stream_socket = socket(...
//connect(stream_socket, ...
// convert to network byte order
temp = htonl(spatula_count);
// send data normally:
send(stream_socket, &temp, sizeof temp, 0);
// send secret message out of band:
send(stream_socket, secret_message, strlen(secret_message)+1, MSG_OOB);
// now with UDP datagram sockets:
//getaddrinfo(...
//dest = ... // assume "dest" holds the address of the destination
//dgram_socket = socket(...
// send secret message normally:
sendto(dgram_socket, secret_message, strlen(secret_message)+1, 0,
(struct sockaddr*)&dest, sizeof dest);
The message does not contain the destination address, only the payload bytes.
Unless you are using raw sockets... And you should not do that if you are new to socket programming.

Resources