nfs4: Try connecting to all getaddrinfo() results before giving up
This commit is contained in:
@@ -189,17 +189,36 @@ PeerAddress::InAddrSize() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressResolver::AddressResolver(const char* name)
|
||||||
|
:
|
||||||
|
fHead(NULL),
|
||||||
|
fCurrent(NULL),
|
||||||
|
fForcedPort(htons(NFS4_PORT)),
|
||||||
|
fForcedProtocol(IPPROTO_TCP)
|
||||||
|
{
|
||||||
|
fStatus = ResolveAddress(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressResolver::~AddressResolver()
|
||||||
|
{
|
||||||
|
freeaddrinfo(fHead);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
PeerAddress::ResolveName(const char* name, PeerAddress* address)
|
AddressResolver::ResolveAddress(const char* name)
|
||||||
{
|
{
|
||||||
ASSERT(name != NULL);
|
ASSERT(name != NULL);
|
||||||
ASSERT(address != NULL);
|
|
||||||
|
|
||||||
address->fProtocol = IPPROTO_TCP;
|
if (fHead != NULL) {
|
||||||
|
freeaddrinfo(fHead);
|
||||||
|
fHead = NULL;
|
||||||
|
fCurrent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// getaddrinfo() is very expensive when called from kernel, so we do not
|
// getaddrinfo() is very expensive when called from kernel, so we do not
|
||||||
// want to call it unless there is no other choice.
|
// want to call it unless there is no other choice.
|
||||||
|
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
if (inet_aton(name, &addr.sin_addr) == 1) {
|
if (inet_aton(name, &addr.sin_addr) == 1) {
|
||||||
@@ -207,35 +226,74 @@ PeerAddress::ResolveName(const char* name, PeerAddress* address)
|
|||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_port = htons(NFS4_PORT);
|
addr.sin_port = htons(NFS4_PORT);
|
||||||
|
|
||||||
memcpy(&address->fAddress, &addr, sizeof(addr));
|
memcpy(&fAddress.fAddress, &addr, sizeof(addr));
|
||||||
|
fAddress.fProtocol = IPPROTO_TCP;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
addrinfo* ai;
|
status_t result = getaddrinfo(name, NULL, NULL, &fHead);
|
||||||
status_t result = getaddrinfo(name, NULL, NULL, &ai);
|
fCurrent = fHead;
|
||||||
if (result != B_OK)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
addrinfo* current = ai;
|
return result;
|
||||||
while (current != NULL) {
|
}
|
||||||
if (current->ai_family == AF_INET) {
|
|
||||||
memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in));
|
|
||||||
|
void
|
||||||
|
AddressResolver::ForceProtocol(const char* protocol)
|
||||||
|
{
|
||||||
|
ASSERT(protocol != NULL);
|
||||||
|
|
||||||
|
if (strcmp(protocol, "tcp") == 0)
|
||||||
|
fForcedProtocol = IPPROTO_TCP;
|
||||||
|
else if (strcmp(protocol, "udp") == 0)
|
||||||
|
fForcedProtocol = IPPROTO_UDP;
|
||||||
|
|
||||||
|
fAddress.SetProtocol(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AddressResolver::ForcePort(uint16 port)
|
||||||
|
{
|
||||||
|
fForcedPort = htons(port);
|
||||||
|
fAddress.SetPort(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AddressResolver::GetNextAddress(PeerAddress* address)
|
||||||
|
{
|
||||||
|
ASSERT(address != NULL);
|
||||||
|
|
||||||
|
if (fStatus != B_OK)
|
||||||
|
return fStatus;
|
||||||
|
|
||||||
|
if (fHead == NULL) {
|
||||||
|
*address = fAddress;
|
||||||
|
fStatus = B_NAME_NOT_FOUND;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
address->fProtocol = fForcedProtocol;
|
||||||
|
|
||||||
|
while (fCurrent != NULL) {
|
||||||
|
if (fCurrent->ai_family == AF_INET) {
|
||||||
|
memcpy(&address->fAddress, fCurrent->ai_addr, sizeof(sockaddr_in));
|
||||||
reinterpret_cast<sockaddr_in*>(&address->fAddress)->sin_port
|
reinterpret_cast<sockaddr_in*>(&address->fAddress)->sin_port
|
||||||
= htons(NFS4_PORT);
|
= fForcedPort;
|
||||||
} else if (current->ai_family == AF_INET6) {
|
} else if (fCurrent->ai_family == AF_INET6) {
|
||||||
memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in6));
|
memcpy(&address->fAddress, fCurrent->ai_addr, sizeof(sockaddr_in6));
|
||||||
reinterpret_cast<sockaddr_in6*>(&address->fAddress)->sin6_port
|
reinterpret_cast<sockaddr_in6*>(&address->fAddress)->sin6_port
|
||||||
= htons(NFS4_PORT);
|
= fForcedPort;
|
||||||
} else {
|
} else {
|
||||||
current = current->ai_next;
|
fCurrent = fCurrent->ai_next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
fCurrent = fCurrent->ai_next;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
return B_NAME_NOT_FOUND;
|
return B_NAME_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,33 @@ struct PeerAddress {
|
|||||||
|
|
||||||
const void* InAddr() const;
|
const void* InAddr() const;
|
||||||
size_t InAddrSize() const;
|
size_t InAddrSize() const;
|
||||||
|
};
|
||||||
|
|
||||||
static status_t ResolveName(const char* name,
|
struct addrinfo;
|
||||||
PeerAddress* address);
|
|
||||||
|
class AddressResolver {
|
||||||
|
public:
|
||||||
|
AddressResolver(const char* name);
|
||||||
|
~AddressResolver();
|
||||||
|
|
||||||
|
status_t GetNextAddress(PeerAddress* address);
|
||||||
|
|
||||||
|
void ForceProtocol(const char* protocol);
|
||||||
|
void ForcePort(uint16 port);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
status_t ResolveAddress(const char* name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
addrinfo* fHead;
|
||||||
|
addrinfo* fCurrent;
|
||||||
|
|
||||||
|
PeerAddress fAddress;
|
||||||
|
|
||||||
|
uint16 fForcedPort;
|
||||||
|
int fForcedProtocol;
|
||||||
|
|
||||||
|
status_t fStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConnectionBase {
|
class ConnectionBase {
|
||||||
|
|||||||
@@ -257,14 +257,11 @@ FileSystem::Migrate(const RPC::Server* serv)
|
|||||||
= reinterpret_cast<FSLocations*>(values[0].fData.fLocations);
|
= reinterpret_cast<FSLocations*>(values[0].fData.fLocations);
|
||||||
|
|
||||||
RPC::Server* server = fServer;
|
RPC::Server* server = fServer;
|
||||||
PeerAddress addr = fServer->ID();
|
|
||||||
for (uint32 i = 0; i < locs->fCount; i++) {
|
for (uint32 i = 0; i < locs->fCount; i++) {
|
||||||
for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) {
|
for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) {
|
||||||
if (PeerAddress::ResolveName(locs->fLocations[i].fLocations[j],
|
AddressResolver resolver(locs->fLocations[i].fLocations[j]);
|
||||||
&addr) != B_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (gRPCServerManager->Acquire(&fServer, addr,
|
if (gRPCServerManager->Acquire(&fServer, &resolver,
|
||||||
CreateNFS4Server) == B_OK) {
|
CreateNFS4Server) == B_OK) {
|
||||||
|
|
||||||
free(const_cast<char*>(fPath));
|
free(const_cast<char*>(fPath));
|
||||||
|
|||||||
@@ -312,7 +312,24 @@ ServerManager::~ServerManager()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ServerManager::Acquire(Server** _server, const PeerAddress& address,
|
ServerManager::Acquire(Server** _server, AddressResolver* resolver,
|
||||||
|
ProgramData* (*createPrivateData)(Server*))
|
||||||
|
{
|
||||||
|
PeerAddress address;
|
||||||
|
status_t result;
|
||||||
|
|
||||||
|
while ((result = resolver->GetNextAddress(&address)) == B_OK) {
|
||||||
|
result = _Acquire(_server, address, createPrivateData);
|
||||||
|
if (result == B_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ServerManager::_Acquire(Server** _server, const PeerAddress& address,
|
||||||
ProgramData* (*createPrivateData)(Server*))
|
ProgramData* (*createPrivateData)(Server*))
|
||||||
{
|
{
|
||||||
ASSERT(_server != NULL);
|
ASSERT(_server != NULL);
|
||||||
|
|||||||
@@ -171,11 +171,13 @@ public:
|
|||||||
ServerManager();
|
ServerManager();
|
||||||
~ServerManager();
|
~ServerManager();
|
||||||
|
|
||||||
status_t Acquire(Server** _server, const PeerAddress& address,
|
status_t Acquire(Server** _server, AddressResolver* resolver,
|
||||||
ProgramData* (*createPrivateData)(Server*));
|
ProgramData* (*createPrivateData)(Server*));
|
||||||
void Release(Server* server);
|
void Release(Server* server);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
status_t _Acquire(Server** _server, const PeerAddress& address,
|
||||||
|
ProgramData* (*createPrivateData)(Server*));
|
||||||
|
|
||||||
ServerNode* _Find(const PeerAddress& address);
|
ServerNode* _Find(const PeerAddress& address);
|
||||||
void _Delete(ServerNode* node);
|
void _Delete(ServerNode* node);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ CreateNFS4Server(RPC::Server* serv)
|
|||||||
// port=X - connect to port X (default: 2049)
|
// port=X - connect to port X (default: 2049)
|
||||||
// proto=X - user transport protocol X (default: tcp)
|
// proto=X - user transport protocol X (default: tcp)
|
||||||
static status_t
|
static status_t
|
||||||
ParseArguments(const char* _args, PeerAddress* address, char** _path,
|
ParseArguments(const char* _args, AddressResolver** address, char** _path,
|
||||||
MountConfiguration* conf)
|
MountConfiguration* conf)
|
||||||
{
|
{
|
||||||
if (_args == NULL)
|
if (_args == NULL)
|
||||||
@@ -92,13 +92,15 @@ ParseArguments(const char* _args, PeerAddress* address, char** _path,
|
|||||||
return B_MISMATCHED_VALUES;
|
return B_MISMATCHED_VALUES;
|
||||||
*path++ = '\0';
|
*path++ = '\0';
|
||||||
|
|
||||||
status_t result = PeerAddress::ResolveName(args, address);
|
*address = new AddressResolver(args);
|
||||||
if (result != B_OK)
|
if (*address == NULL)
|
||||||
return result;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
*_path = strdup(path);
|
*_path = strdup(path);
|
||||||
if (*_path == NULL)
|
if (*_path == NULL) {
|
||||||
|
delete *address;
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
conf->fHard = false;
|
conf->fHard = false;
|
||||||
conf->fRetryLimit = 5;
|
conf->fRetryLimit = 5;
|
||||||
@@ -127,10 +129,10 @@ ParseArguments(const char* _args, PeerAddress* address, char** _path,
|
|||||||
conf->fEmulateNamedAttrs = true;
|
conf->fEmulateNamedAttrs = true;
|
||||||
else if (strncmp(options, "port=", 5) == 0) {
|
else if (strncmp(options, "port=", 5) == 0) {
|
||||||
options += strlen("port=");
|
options += strlen("port=");
|
||||||
address->SetPort(atoi(options));
|
(*address)->ForcePort(atoi(options));
|
||||||
} else if (strncmp(options, "proto=", 6) == 0) {
|
} else if (strncmp(options, "proto=", 6) == 0) {
|
||||||
options += strlen("proto=");
|
options += strlen("proto=");
|
||||||
address->SetProtocol(options);
|
(*address)->ForceProtocol(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
options = optionsEnd;
|
options = optionsEnd;
|
||||||
@@ -165,16 +167,17 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags,
|
|||||||
}
|
}
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
PeerAddress address;
|
AddressResolver* resolver;
|
||||||
MountConfiguration config;
|
MountConfiguration config;
|
||||||
char* path;
|
char* path;
|
||||||
result = ParseArguments(args, &address, &path, &config);
|
result = ParseArguments(args, &resolver, &path, &config);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
MemoryDeleter pathDeleter(path);
|
MemoryDeleter pathDeleter(path);
|
||||||
|
|
||||||
RPC::Server* server;
|
RPC::Server* server;
|
||||||
result = gRPCServerManager->Acquire(&server, address, CreateNFS4Server);
|
result = gRPCServerManager->Acquire(&server, resolver, CreateNFS4Server);
|
||||||
|
delete resolver;
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user