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