Description:
MgmApiSession::MgmApiSession() moves the accepted NdbSocket &&sock parameter into m_secure_socket, then later calls ndb_getpeername(sock.ndb_socket(), &addr) on the moved-from parameter.
NdbSocket move construction swaps the native socket handle into the destination and leaves the source object default-invalid. Therefore sock.ndb_socket() returns an invalid socket after the move. On POSIX this results in getpeername(-1, ...), which fails with EBADF.
As a result, the constructor does not resolve the peer address and m_name remains initialized as "unknown:0", making management API session logging/diagnostics misleading.
Relevant code path:
```cpp
MgmApiSession::MgmApiSession(class MgmtSrvr &mgm, NdbSocket &&sock,
Uint64 session_id)
: SocketServer::Session(m_secure_socket),
m_secure_socket(std::move(sock)),
...
m_name("unknown:0") {
...
ndb_sockaddr addr;
if (ndb_getpeername(sock.ndb_socket(), &addr) == 0) {
...
m_name.assfmt("%s", sockaddr_string);
}
}
```
How to repeat:
The following simplified program reproduces the ownership transfer issue using the same operation sequence as MgmApiSession: move an NdbSocket, then call ndb_getpeername() on the moved-from object versus the moved-to object.
```cpp
#include "util/NdbSocket.h"
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <iostream>
int main() {
int listener = ::socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = 0;
::bind(listener, reinterpret_cast<sockaddr *>(&addr), sizeof(addr));
::listen(listener, 1);
socklen_t addr_len = sizeof(addr);
::getsockname(listener, reinterpret_cast<sockaddr *>(&addr), &addr_len);
int client_fd = ::socket(AF_INET, SOCK_STREAM, 0);
::connect(client_fd, reinterpret_cast<sockaddr *>(&addr), addr_len);
int server_fd = ::accept(listener, nullptr, nullptr);
::close(listener);
NdbSocket sock(ndb_socket_create_from_native(server_fd));
NdbSocket m_secure_socket(std::move(sock));
ndb_sockaddr from_moved_param;
errno = 0;
int moved_result = ndb_getpeername(sock.ndb_socket(), &from_moved_param);
int moved_errno = errno;
ndb_sockaddr from_member;
errno = 0;
int member_result =
ndb_getpeername(m_secure_socket.ndb_socket(), &from_member);
int member_errno = errno;
std::cout << "moved-from sock valid: " << sock.is_valid() << "\n";
std::cout << "m_secure_socket valid: " << m_secure_socket.is_valid() << "\n";
std::cout << "ndb_getpeername(sock.ndb_socket()) result: "
<< moved_result << ", errno: " << moved_errno << "\n";
std::cout << "ndb_getpeername(m_secure_socket.ndb_socket()) result: "
<< member_result << ", errno: " << member_errno << "\n";
::close(client_fd);
::close(m_secure_socket.release_native_socket());
}
```
Observed output:
moved-from sock valid: 0
m_secure_socket valid: 1
ndb_getpeername(sock.ndb_socket()) result: 1, errno: 9
ndb_getpeername(m_secure_socket.ndb_socket()) result: 0, errno: 0
errno: 9 is EBADF, confirming that sock.ndb_socket() is invalid after std::move(sock), while m_secure_socket.ndb_socket() is valid.
Suggested fix:
Use the session-owned socket after the move:
```cpp
ndb_sockaddr addr;
if (ndb_getpeername(m_secure_socket.ndb_socket(), &addr) == 0) {
char addr_buf[NDB_ADDR_STRLEN];
char *addr_str = Ndb_inet_ntop(&addr, addr_buf, sizeof(addr_buf));
char buf[512];
char *sockaddr_string =
Ndb_combine_address_port(buf, sizeof(buf), addr_str, addr.get_port());
m_name.assfmt("%s", sockaddr_string);
}
```
Description: MgmApiSession::MgmApiSession() moves the accepted NdbSocket &&sock parameter into m_secure_socket, then later calls ndb_getpeername(sock.ndb_socket(), &addr) on the moved-from parameter. NdbSocket move construction swaps the native socket handle into the destination and leaves the source object default-invalid. Therefore sock.ndb_socket() returns an invalid socket after the move. On POSIX this results in getpeername(-1, ...), which fails with EBADF. As a result, the constructor does not resolve the peer address and m_name remains initialized as "unknown:0", making management API session logging/diagnostics misleading. Relevant code path: ```cpp MgmApiSession::MgmApiSession(class MgmtSrvr &mgm, NdbSocket &&sock, Uint64 session_id) : SocketServer::Session(m_secure_socket), m_secure_socket(std::move(sock)), ... m_name("unknown:0") { ... ndb_sockaddr addr; if (ndb_getpeername(sock.ndb_socket(), &addr) == 0) { ... m_name.assfmt("%s", sockaddr_string); } } ``` How to repeat: The following simplified program reproduces the ownership transfer issue using the same operation sequence as MgmApiSession: move an NdbSocket, then call ndb_getpeername() on the moved-from object versus the moved-to object. ```cpp #include "util/NdbSocket.h" #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #include <iostream> int main() { int listener = ::socket(AF_INET, SOCK_STREAM, 0); sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = 0; ::bind(listener, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)); ::listen(listener, 1); socklen_t addr_len = sizeof(addr); ::getsockname(listener, reinterpret_cast<sockaddr *>(&addr), &addr_len); int client_fd = ::socket(AF_INET, SOCK_STREAM, 0); ::connect(client_fd, reinterpret_cast<sockaddr *>(&addr), addr_len); int server_fd = ::accept(listener, nullptr, nullptr); ::close(listener); NdbSocket sock(ndb_socket_create_from_native(server_fd)); NdbSocket m_secure_socket(std::move(sock)); ndb_sockaddr from_moved_param; errno = 0; int moved_result = ndb_getpeername(sock.ndb_socket(), &from_moved_param); int moved_errno = errno; ndb_sockaddr from_member; errno = 0; int member_result = ndb_getpeername(m_secure_socket.ndb_socket(), &from_member); int member_errno = errno; std::cout << "moved-from sock valid: " << sock.is_valid() << "\n"; std::cout << "m_secure_socket valid: " << m_secure_socket.is_valid() << "\n"; std::cout << "ndb_getpeername(sock.ndb_socket()) result: " << moved_result << ", errno: " << moved_errno << "\n"; std::cout << "ndb_getpeername(m_secure_socket.ndb_socket()) result: " << member_result << ", errno: " << member_errno << "\n"; ::close(client_fd); ::close(m_secure_socket.release_native_socket()); } ``` Observed output: moved-from sock valid: 0 m_secure_socket valid: 1 ndb_getpeername(sock.ndb_socket()) result: 1, errno: 9 ndb_getpeername(m_secure_socket.ndb_socket()) result: 0, errno: 0 errno: 9 is EBADF, confirming that sock.ndb_socket() is invalid after std::move(sock), while m_secure_socket.ndb_socket() is valid. Suggested fix: Use the session-owned socket after the move: ```cpp ndb_sockaddr addr; if (ndb_getpeername(m_secure_socket.ndb_socket(), &addr) == 0) { char addr_buf[NDB_ADDR_STRLEN]; char *addr_str = Ndb_inet_ntop(&addr, addr_buf, sizeof(addr_buf)); char buf[512]; char *sockaddr_string = Ndb_combine_address_port(buf, sizeof(buf), addr_str, addr.get_port()); m_name.assfmt("%s", sockaddr_string); } ```