Per the man page for recvfrom()
, EFAULT
is reported when:
EFAULT
The receive buffer pointer(s) point outside the process's address space.
Assuming your maxpack
variable is > 0, recvfrom()
is expecting to be able to write bytes to the buffer pointed to by the buf
parameter, but you are passing NULL
for that parameter, hence the error.
Why are you checking errno
before calling recvfrom()
? You should be calling recvfrom()
first, and THEN check for an error. And stop looping when any error other than EWOULDBLOCK
/EAGAIN
, EINTR
, or EMSGSIZE
is reported.
Also, keep in mind that UDP supports 0-length packets, in which case recvfrom()
would return 0 instead of -1, and errno
would not be set. Make sure you account for that in your loop, too.
Try this instead:
void recvflush(int sockfd) {
ssize_t num;
do {
num = recvfrom(sockfd, NULL, 0, 0, NULL, NULL);
if (num < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
break;
if ((errno != EINTR) && (errno != EMSGSIZE)) {
error("recvfrom() failed", strerror(errno));
break;
}
}
}
while (true);
}
Or, if recvfrom()
doesn't accept a 0-length buffer, then give it a small buffer to write into:
void recvflush(int sockfd) {
ssize_t num;
char c;
do {
num = recvfrom(sockfd, &c, 1, 0, NULL, NULL);
if (num < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
break;
if ((errno != EINTR) && (errno != EMSGSIZE)) {
error("recvfrom() failed", strerror(errno));
break;
}
}
}
while (true);
}
Note that if your socket is NOT non-blocking, then EWOULDBLOCK
/EAGAIN
will not be reported since the call will block until data is available, so you should use select()
or (e)poll()
to check if the socket has any queued packets before entering the recvfrom()
loop.