Skip to content

Commit

Permalink
nall: make gdb server accept only one connection at a time. (#1369)
Browse files Browse the repository at this point in the history
This closes the socket server after each successful connection so that
new connections are immediately refused. Before, given that the server
socket was always in listen mode, one additional connection could always
be estabilished at the TCP level, even though the server wouldn't accept
it right away.
  • Loading branch information
rasky authored Jan 22, 2024
1 parent 322c99c commit e2caf17
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 66 deletions.
143 changes: 78 additions & 65 deletions nall/tcptext/tcp-socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,92 +70,105 @@ NALL_HEADER_INLINE auto Socket::open(u32 port, bool useIPv4) -> bool {
auto threadServer = std::thread([this, port, useIPv4]() {
serverRunning = true;

fdServer = socket(useIPv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0);
if(fdServer < 0) {
serverRunning = false;
return;
}
while (!stopServer) {
fdServer = socket(useIPv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0);
if(fdServer < 0)
break;

{
s32 valueOn = 1;
#if defined(SO_NOSIGPIPE) //BSD, OSX
setsockopt(fdServer, SOL_SOCKET, SO_NOSIGPIPE, &valueOn, sizeof(s32));
#endif

{
s32 valueOn = 1;
#if defined(SO_NOSIGPIPE) //BSD, OSX
setsockopt(fdServer, SOL_SOCKET, SO_NOSIGPIPE, &valueOn, sizeof(s32));
#endif
#if defined(SO_REUSEADDR) //BSD, Linux, OSX
setsockopt(fdServer, SOL_SOCKET, SO_REUSEADDR, &valueOn, sizeof(s32));
#endif

#if defined(SO_REUSEADDR) //BSD, Linux, OSX
setsockopt(fdServer, SOL_SOCKET, SO_REUSEADDR, &valueOn, sizeof(s32));
#endif
#if defined(SO_REUSEPORT) //BSD, OSX
setsockopt(fdServer, SOL_SOCKET, SO_REUSEPORT, &valueOn, sizeof(s32));
#endif

#if defined(SO_REUSEPORT) //BSD, OSX
setsockopt(fdServer, SOL_SOCKET, SO_REUSEPORT, &valueOn, sizeof(s32));
#endif
#if defined(TCP_NODELAY)
setsockopt(fdServer, IPPROTO_TCP, TCP_NODELAY, &valueOn, sizeof(s32));
#endif

#if defined(TCP_NODELAY)
setsockopt(fdServer, IPPROTO_TCP, TCP_NODELAY, &valueOn, sizeof(s32));
#endif
if(!socketSetBlockingMode(fdServer, true)) {
print("TCP: failed to set to blocking mode!\n");
}

if(!socketSetBlockingMode(fdServer, true)) {
print("TCP: failed to set to blocking mode!\n");
#if defined(SO_RCVTIMEO)
#if defined(PLATFORM_WINDOWS)
DWORD rcvTimeMs = 1000 * RECEIVE_TIMEOUT_SEC;
setsockopt(fdServer, SOL_SOCKET, SO_RCVTIMEO, &rcvTimeMs, sizeof(rcvTimeMs));
#else
struct timeval rcvtimeo;
rcvtimeo.tv_sec = RECEIVE_TIMEOUT_SEC;
rcvtimeo.tv_usec = 0;
setsockopt(fdServer, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(rcvtimeo));
#endif
#endif
}

#if defined(SO_RCVTIMEO)
#if defined(PLATFORM_WINDOWS)
DWORD rcvTimeMs = 1000 * RECEIVE_TIMEOUT_SEC;
setsockopt(fdServer, SOL_SOCKET, SO_RCVTIMEO, &rcvTimeMs, sizeof(rcvTimeMs));
#else
struct timeval rcvtimeo;
rcvtimeo.tv_sec = RECEIVE_TIMEOUT_SEC;
rcvtimeo.tv_usec = 0;
setsockopt(fdServer, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(rcvtimeo));
#endif
#endif
}
s32 bindRes;
if(useIPv4) {
sockaddr_in serverAddrV4{};
serverAddrV4.sin_family = AF_INET;
serverAddrV4.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddrV4.sin_port = htons(port);

s32 bindRes;
if(useIPv4) {
sockaddr_in serverAddrV4{};
serverAddrV4.sin_family = AF_INET;
serverAddrV4.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddrV4.sin_port = htons(port);

bindRes = ::bind(fdServer, (sockaddr*)&serverAddrV4, sizeof(serverAddrV4)) < 0;
} else {
sockaddr_in6 serverAddrV6{};
serverAddrV6.sin6_family = AF_INET6;
serverAddrV6.sin6_addr = in6addr_loopback;
serverAddrV6.sin6_port = htons(port);

bindRes = ::bind(fdServer, (sockaddr*)&serverAddrV6, sizeof(serverAddrV6)) < 0;
}
bindRes = ::bind(fdServer, (sockaddr*)&serverAddrV4, sizeof(serverAddrV4)) < 0;
} else {
sockaddr_in6 serverAddrV6{};
serverAddrV6.sin6_family = AF_INET6;
serverAddrV6.sin6_addr = in6addr_loopback;
serverAddrV6.sin6_port = htons(port);

if(bindRes < 0 || listen(fdServer, 1) < 0) {
bindRes = ::bind(fdServer, (sockaddr*)&serverAddrV6, sizeof(serverAddrV6)) < 0;
}

if(bindRes < 0 || listen(fdServer, 1) < 0) {
printf("error binding socket on port %d! (%s)\n", port, strerror(errno));
stopServer = true;
}
break;
}

while(!stopServer)
{
// scan for new connections
if(fdClient < 0) {
while(fdClient < 0) {
fdClient = ::accept(fdServer, nullptr, nullptr);
if(fdClient < 0) {
if(errno != EAGAIN) {
if(!stopServer)
printf("error accepting connection! (%s)\n", strerror(errno));
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(CLIENT_SLEEP_MS));
}
}

// Kick client if we need to
if(fdClient >= 0 && wantKickClient) {
socketClose(fdClient);
fdClient = -1;
wantKickClient = false;
onDisconnect();
if (fdClient < 0) {
break;
}

std::this_thread::sleep_for(std::chrono::milliseconds(CLIENT_SLEEP_MS));
// close the server socket, we only want one client
socketClose(fdServer);
fdServer = -1;

while (!stopServer && fdClient >= 0) {
// Kick client if we need to
if(wantKickClient) {
socketClose(fdClient);
fdClient = -1;
wantKickClient = false;
onDisconnect();
break;
}

std::this_thread::sleep_for(std::chrono::milliseconds(CLIENT_SLEEP_MS));
}
}

printf("Stopping TCP-server...\n");

socketClose(fdClient);
socketClose(fdServer);
fdServer = -1;
fdClient = -1;

wantKickClient = false;
Expand Down
2 changes: 1 addition & 1 deletion nall/tcptext/tcp-socket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Socket {

auto disconnectClient() -> void;

auto isStarted() const -> bool { return fdServer >= 0; }
auto isStarted() const -> bool { return serverRunning; }
auto hasClient() const -> bool { return fdClient >= 0; }

auto getURL(u32 port, bool useIPv4) const -> string;
Expand Down

0 comments on commit e2caf17

Please sign in to comment.