QUESTION
If a recvfrom buffer is smaller than the datagram, can the remainder be received by the next read?
UDP preserves datagram boundaries. If the receive buffer is too small, the excess is discarded; the next recv cannot continue with the rest of the same datagram. Handle truncation explicitly through MSG_TRUNC and the recvmsg return length.
A successful send does not guarantee delivery. According to its needs, the application protocol must compensate for loss, duplication, reordering, path MTU, and checksum/ICMP errors with sequence numbers, retries, and acknowledgements.
STRUCTURE
Structure diagram
Each skb is one datagram. Reading a 16-byte datagram into an 8-byte buffer discards the trailing 8 bytes instead of leaving them for the next recv.
CALL PATH
Call path
Use one datagram's length and peer address as the unit of state instead of a stream offset. Truncation is message loss, not partial progress.
This diagram is not for memorizing function names. Follow which return value, file descriptor, memory mapping, or wait queue is passed to the next stage.
SOURCE COORDINATES
Linux 6.18.37 LTS source locations
Go beyond the glibc function to the files where the syscall implementation meets kernel objects. Each link points to the original file at the same tag.
| File | Function / structure | What to inspect |
|---|---|---|
| net/ipv4/udp.c | udp_sendmsg(), udp_recvmsg() | Datagram creation and one-message receive |
| net/ipv4/udp.c | udp_queue_rcv_skb() | Socket receive queue and drop conditions |
| net/ipv4/ip_output.c | ip_make_skb(), ip_append_data() | IP packet/fragment/MTU handling |
COMPLETE PROGRAM
Complete runnable example
The code below is not pseudocode with explanatory lines omitted. It is a minimal example that can be built and run as a file.
cc -std=c17 -Wall -Wextra -O2 udp_meta.c -o udp_meta01#define _GNU_SOURCE
02#include <arpa/inet.h>
03#include <stdio.h>
04#include <string.h>
05#include <sys/socket.h>
06#include <unistd.h>
07
08int main(void)
09{
10 int fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
11 struct sockaddr_in local = { .sin_family = AF_INET,
12 .sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) } };
13 if (fd < 0 || bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
14 return 1;
15 socklen_t local_len = sizeof(local);
16 getsockname(fd, (struct sockaddr *)&local, &local_len);
17
18 const char payload[] = "0123456789abcdef";
19 if (sendto(fd, payload, sizeof(payload) - 1, 0,
20 (struct sockaddr *)&local, sizeof(local)) < 0)
21 return 1;
22
23 char small[8];
24 struct iovec iov = { .iov_base = small, .iov_len = sizeof(small) };
25 struct msghdr message = { .msg_iov = &iov, .msg_iovlen = 1 };
26 ssize_t n = recvmsg(fd, &message, MSG_TRUNC);
27 printf("datagram=%zd copied=%zu truncated=%s\n", n, sizeof(small),
28 n > (ssize_t)sizeof(small) ? "yes" : "no");
29 close(fd);
30 return n < 0;
31}
CODE NOTES
Code notes
SOCK_DGRAM | SOCK_CLOEXECCreates an unconnected datagram socket and prevents exec inheritance.
getsockname(fdUses bind with port 0, reads the ephemeral local port selected by the kernel, and uses it as the loopback destination.
sizeof(payload) - 1Does not include the terminating NUL of the string in the wire protocol. One sendto call defines the datagram length.
char small[8]Deliberately creates truncation with a receive buffer smaller than the 16-byte datagram.
MSG_TRUNCOn Linux, requests the actual datagram length so the caller can tell it exceeded the buffer. Only the buffer-sized prefix is copied.
DETAILS
Detailed behavior
Connected UDP is not a reliability feature
connect sets a default peer and simplifies filtering datagrams from other sources, using send/recv, and delivery of some asynchronous errors. It adds no handshake or delivery guarantee.
To change peers, call connect again or use a destination with sendto.
Large datagrams create MTU problems
With IP fragmentation, losing one fragment loses the whole datagram, and middleboxes may restrict fragments. Under DF/path-MTU-discovery conditions, EMSGSIZE may be returned.
The application must define a small packet size plus fragmentation/reassembly limits.
The receiver may not know about queue overflow
If the application is slow, the socket receive buffer fills and new datagrams are dropped. Observe drops with SO_RXQ_OVFL ancillary data and system UDP counters.
Tune processing batches, CPU affinity, and packet-rate limits together instead of only enlarging the buffer.
OBJECTS
Objects and lifetimes
| Object | Creation and release | Values to inspect |
|---|---|---|
UDP socket | The endpoint is created by socket/bind and owns the receive queue until close | local/peer, rcvbuf, error queue |
datagram skb | Exists as a message from network receive until recv/drop | length, source, checksum, timestamp |
ancillary metadata | Copied into the recvmsg control buffer and consumed with that datagram | pktinfo, timestamp, overflow |
FAILURE PATH
Failure conditions and common misconceptions
| Observed symptom | Likely causes | How to verify |
|---|---|---|
| The tail of the payload disappears | A datagram larger than the receive buffer was truncated | Inspect MSG_TRUNC and the actual length |
| Packets occasionally disappear | A network or socket-queue drop | Inspect sequence numbers, netstat, and SO_RXQ_OVFL |
| send EMSGSIZE | A datagram exceeds path MTU under DF | Inspect the error queue and discovered MTU |
LAB
Verify it yourself
- Remove MSG_TRUNC and compare the returned length and ability to detect truncation.
- Enable SO_TIMESTAMPNS and IP_PKTINFO, then read source/destination-interface metadata from the recvmsg control buffer.
- Induce drops with a small SO_RCVBUF and a fast sender, recording sequence gaps and SO_RXQ_OVFL.
./udp_metastrace -e trace=socket,bind,getsockname,sendto,recvmsg,close ./udp_metaPRIMARY REFERENCES