Udp readfrom until the end - c

Socket Used : udp
I have a client who sends 5000 bytes and a server with this code :
Client code :
cod = sendto (sFd, (void *) buffer, 5000, 0, (struct sockaddr *)
&soc, sizeof (struct sockaddr_in));
Server code :
//leghtBuffer = 5000
while (lenghtBuffer > 0 )
{
//I will insert a signal if pass more than 30 s ...
cod = recvfrom (sFd, buffer,256 , 0, (struct sockaddr *) &clientSoc, &lungimeSocket);
printf("Am received %d bytes " ,cod );
lenghtBuffer = lenghtBuffer - cod;
}
How can I read more than 1 time 256 bytes from this while (still using Udp socket)?

UDP is a message (datagram) based transport protocol and not stream based like TCP. Each sendto/recvfrom works in terms of complete messages.
On the sending end, each call to sendto() creates a datagram of the specified size and data, which in your case is 5000 bytes.
On the receiving end, each call to recvfrom() copies the next message in the receive buffer. Since your datagrams are 5000 bytes, but you're only providing a 256 byte buffer, your datagram is being truncated to 256 bytes as it's copied.
The recvfrom() OpenGroup specification clarifies the behavior in this case:
For message-based sockets such as SOCK_DGRAM and SOCK_SEQPACKET, the entire message must be read in a single operation. If a message is too long to fit in the supplied buffer, and MSG_PEEK is not set in the flags argument, the excess bytes are discarded.
You'll want to increase your buffer on the receive end to be 5000 bytes to account for the entire datagram

Related

How does recvfrom know when to stop reading packets?

in C recvfrom can be used to read UDP messages form a socket as such:
int length = recvfrom(socket, buffer, max_length, 0, NULL, 0);
max_length only tells the maximum number of bytes the buffer can hold, and not the actual length of course.
Assume my message is the following and is sent with sendto:
char *message = "hi";
sendto(sock, message, strlen(message), 0, NULL, 0);
Now recvfrom will immediately stop reading after the i character is received. length will be set to 2.
How does it know when to stop?
does sendto append any data to the packet with result of strlen saying what the data length is? or does it look for null terminating char?
Unlike a TCP socket which is stream based, UDP sockets are datagram based.
That means that a single call to sendto will send one UDP datagram and a single call to recvfrom will receive a single UDP datagram. This also means that the buffer supplied to recvfrom should be large enough to hold a single datagram. If it is not large enough, any bytes from that datagram that don't fit in the buffer will be discarded.

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

How to send a SNMP-Packet via UDP

The idea of my socket is receiving and sending SNMP-packets - GetRequest/GetResponse. However, the socket already receive SNMP-packets
...
unsigned char buf[8192];
...
for (;;) {
// Receive snmp message from snmp manager
recv_len = recvfrom(my_socket, buf, BUFSIZE, 0, (struct sockaddr
*)&remote_addr, &addr_len);
...
Now I want answer the request by a SNMP-Packet which is represents as string. Note: The response contains a GetResponse-PDU (a2).
unsigned char * packet = "302902010004067075626c6963a21c...";
int r = sendto(my_socket, packet, strlen(packet), 0, (struct sockaddr *)&remote_addr, addr_len);
The return value or r is 4 and is definitely wrong because my responding SNMP-packet packet is larger than 4. Why, because it's a pointer?.
Further, the response SNMP-Packet packet is not send as SNMP-Packet, it looks different compare to packet and is not interpret as a SNMP-Packet in Wireshark. It looks like that:
How can I send a valid SNMP-Packet?
Your problem is the strlen(packet) value, which is 4 due to the 00 byte.
strlen is meant to be used with ASCII strings, not binary strings.

I set SO_RCVLOWAT (Receive Low Water Mark ) option on a UDP socket but it doesn't work

I am using C network programming to set the socket option SO_RCVLOWAT on a UDP socket. I succeeded as shown by the return value of getsockopt(). The problem: I can still receive any data sizes greater than zero.
Example: I set the socket option SO_RCVLOWAT value to 1024 byte on the client side and server sent 256 byte to the client. It can receive the 256 byte, but it actually shouldn't receive this message because the receive low water mark is 1024 byte.
Relevant code:
rc = setsockopt(sd, SOL_SOCKET, SO_RCVLOWAT, (char *)&recvlowat, sizeof(recvlowat));
if(rc < 0){
VL_MISC_ERR(("Setting SO_RCVLOWAT option error, %s",strerror(errno)));
return -1;
}
sd : a valid file descriptor
Then I use recvfrom:
c = recvfrom(sd, databuf, datalen, 0, (struct sockaddr_in *)&localSock, &addrlen);
It isn't supposed to have that effect in UDP. recvfrom() receives one datagram at a time, period. If you want to receive more than one at a time, use recvmsg().

How to detect receipt of a 0-length UDP datagram

I was considering writing/implementing a UDP-based protocol that would use a zero-length datagram as a 'hello' message. And while I don't expect to have a problem sending a zero-length datagram, I'm not certain I can receive one.
recvfrom returns the number of bytes read, but 0 is reserved for an orderly shutdown.
read returns number of bytes read, but 0 is reserved for EOF.
select "will be watched to see if characters become available for reading".
How would one detect the receipt of a zero-length datagram?
When calling recvfrom on a TCP Socket, you will receive a zero byte read if a FIN packet has been received (an orderly shutdown). UDP has no concept of orderly shutdowns, and no data is transmitted from the sender to receiver to indicate a socket being closed. The protocol is completely stateless and every datagram received is independent from the receiver's point of view. As such, I am not aware of any scenerios in which a zero byte return code from recvfrom on a UDP socket would be caused by anything other than a zero length datagram being received.
For udp, a normal call to recvfrom will return 0 when receiving a udp packet with 0 length payload (see Under Linux, can recv ever return 0 on UDP?).
You can test this by doing a simple sendto/recvfrom test:
const int howManyBytesToSend = 0;
if(sendto(sock, buf, howManyBytesToSend, 0, (struct sockaddr*) &addr, addrlen) < 0)
{
return EXIT_FAILURE;
}
if((recv_len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &addr, (socklen_t*)&addrlen)) < 0)
{
return EXIT_FAILURE;
}
The documentation you are quoting is from the man page for recvfrom: "returns the number of bytes read, but 0 is reserved for an orderly shutdown". That statement applies only to TCP.

Resources