Commit 76c77829 authored by Phoebe Buckheister's avatar Phoebe Buckheister

Merge branch '959-empty-udp-packet-v6' into 'v6'

Resolve "BeeGFS services die when receiving 0 byte UDP packets"

See merge request beegfs/projects0!796
parents 2790927d f5a00d8b
......@@ -47,11 +47,19 @@ void __DatagramListener_listenLoop(DatagramListener* this)
continue;
}
else
if(unlikely(recvRes <= 0) )
{ // error
if(recvRes == 0)
{
char* fromIP = SocketTk_ipaddrToStr(&fromAddr.addr);
Logger_logFormatted(log, Log_NOTICE, logContext,
"Received an empty datagram. IP: %s; port: %d",
fromIP, fromAddr.port);
kfree(fromIP);
//if(errno == -EINTR) // ignore iterruption, because the debugger makes this happen
// continue;
continue;
}
else
if(unlikely(recvRes < 0) )
{ // error
Logger_logErrFormatted(log, logContext,
"Encountered an unrecoverable socket error. ErrCode: %d", recvRes);
......
......@@ -12,10 +12,12 @@
*/
NetMessage* AbstractNetMessageFactory::createFromBuf(char* recvBuf, size_t bufLen)
{
if(unlikely(bufLen < NETMSG_MIN_LENGTH))
return new SimpleMsg(NETMSGTYPE_Invalid);
NetMessageHeader header;
// decode the message header
NetMessage::deserializeHeader(recvBuf, bufLen, &header);
// delegate the rest of the work to another method...
......
......@@ -117,6 +117,8 @@ class NetMessage
{
Deserializer des(buf, bufLen);
des % *outHeader;
if(unlikely(!des.good()))
outHeader->msgType = NETMSGTYPE_Invalid;
}
class ResponseContext
......
......@@ -15,6 +15,7 @@
* @throw SocketException
*/
StandardSocket::StandardSocket(int domain, int type, int protocol)
: isDgramSocket(type == SOCK_DGRAM)
{
this->sockDomain = domain;
......@@ -63,6 +64,7 @@ StandardSocket::StandardSocket(int domain, int type, int protocol)
*/
StandardSocket::StandardSocket(int fd, unsigned short sockDomain, struct in_addr peerIP,
std::string peername)
: isDgramSocket(false)
{
this->sock = fd;
this->sockDomain = sockDomain;
......@@ -426,10 +428,22 @@ ssize_t StandardSocket::recv(void *buf, size_t len, int flags)
}
if(recvRes == 0)
throw SocketDisconnectException(std::string("Soft disconnect from ") + peername);
{
if (isDgramSocket)
{
LOG_TOP(GENERAL, NOTICE, "Received empty UDP datagram.", peername);
return 0;
}
else
{
throw SocketDisconnectException(std::string("Soft disconnect from ") + peername);
}
}
else
{
throw SocketDisconnectException(std::string("Recv(): Hard disconnect from ") +
peername + ". SysErr: " + System::getErrString() );
}
}
/**
......@@ -496,11 +510,25 @@ ssize_t StandardSocket::recvfrom(void *buf, size_t len, int flags,
}
if(recvRes == 0)
throw SocketDisconnectException(std::string("Soft disconnect from ") + peername);
{
if (isDgramSocket)
{
struct sockaddr_in* sin = (struct sockaddr_in*)from;
LOG_TOP(GENERAL, NOTICE, "Received empty UDP datagram.", peername,
as("IP", Socket::ipaddrToStr(&sin->sin_addr)), as("port", ntohs(sin->sin_port)));
return 0;
}
else
{
throw SocketDisconnectException(std::string("Soft disconnect from ") + peername);
}
}
else
{
throw SocketDisconnectException(
std::string("Recvfrom(): Hard disconnect from ") + peername + ": " +
System::getErrString() );
}
}
/**
......
......@@ -48,7 +48,8 @@ class StandardSocket : public PooledSocket
protected:
int sock;
unsigned short sockDomain; // socket domain (aka protocol family) e.g. PF_INET
const bool isDgramSocket;
StandardSocket(int fd, unsigned short sockDomain, struct in_addr peerIP,
std::string peername);
......
test_c = "send0byteUDP.c"
test_path = File.dirname(caller_locations(0, 1)[0].path)
test = test_path + "/" + test_c
on node do; tempdir do;
upload local: test
shell "g++ -std=gnu99 #{test_c}"
clientPort = node.properties["client"]["config"]["connClientPortUDP"]
shell "./a.out 127.0.0.1 #{clientPort}"
# give the thread some time to shut down
sleep 10
# the client does not terminate fully, only the datagram listener thread dies
shell "pidof beegfs_DGramLis"
wait_daemon_log(node, "helperd", "Received an empty datagram", 10)
end; end
name: "Empty UDP packet"
desc: "Check that server processes do not shut down when they receive a 0 byte UDP datagram."
hosts:
node:
- mgmtd
- meta
- storage
- helperd
- client:
name: client
config:
connClientPortUDP: 8504
test_c = "send0byteUDP.c"
test_path = File.dirname(caller_locations(0, 1)[0].path)
test = test_path + "/" + test_c
on node do; tempdir do;
upload local: test
shell "g++ -std=gnu99 #{test_c}"
mgmtPort = node.properties["mgmt"]["config"]["connMgmtdPortUDP"]
metaPort = node.properties["meta"]["config"]["connMetaPortUDP"]
storePort = node.properties["store"]["config"]["connStoragePortUDP"]
shell "./a.out 127.0.0.1 #{mgmtPort}"
shell "./a.out 127.0.0.1 #{metaPort}"
shell "./a.out 127.0.0.1 #{storePort}"
# give the servers some time to shut down
sleep 10
# ensure all the servers are still running
shell "pidof beegfs-mgmtd"
shell "pidof beegfs-meta"
shell "pidof beegfs-storage"
# check that they logged the empty packet
["mgmt", "meta", "store"].each do |service|
wait_daemon_log(node, service, "Received empty UDP datagram", 10)
end
end; end
name: "Empty UDP packet"
desc: "Check that server processes do not shut down when they receive a 0 byte UDP datagram."
hosts:
node:
- mgmtd:
name: mgmt
config:
# needs to be the standard port for the CTL to work
connMgmtdPortUDP: 8008
- meta:
name: meta
config:
connMgmtdPortUDP: 8008
connMetaPortUDP: 8505
- storage:
name: store
config:
connMgmtdPortUDP: 8008
connStoragePortUDP: 8503
- helperd
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
void die(char* s) {
perror(s);
exit(1);
}
int main(int argc, char** argv) {
struct sockaddr_in si_other;
const int slen = sizeof(si_other);
int sock;
int port;
char* host;
if (argc != 3) {
printf("Usage: %s ip port\n", argv[0]);
exit(1);
}
host = argv[1];
port = atoi(argv[2]);
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("socket");
memset((char*)&si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(port);
if (inet_aton(host, &si_other.sin_addr) == 0) {
fprintf(stderr, "inet_aton\n");
exit(1);
}
if (sendto(sock, 0, 0, 0, (struct sockaddr*)&si_other, slen) == -1)
die("sendto");
close(sock);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment