nfs4: Support callbacks over IPv6

This commit is contained in:
Pawel Dziepak
2013-02-13 01:14:45 +01:00
parent 07b3bd59ab
commit 266b99b7e9
8 changed files with 172 additions and 59 deletions
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Haiku, Inc. All rights reserved. * Copyright 2012-2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -61,6 +61,26 @@ PeerAddress::PeerAddress()
} }
PeerAddress::PeerAddress(int networkFamily)
:
fProtocol(0)
{
ASSERT(networkFamily == AF_INET || networkFamily == AF_INET6);
memset(&fAddress, 0, sizeof(fAddress));
fAddress.ss_family = networkFamily;
switch (networkFamily) {
case AF_INET:
fAddress.ss_len = sizeof(sockaddr_in);
break;
case AF_INET6:
fAddress.ss_len = sizeof(sockaddr_in6);
break;
}
}
const char* const char*
PeerAddress::ProtocolString() const PeerAddress::ProtocolString() const
{ {
@@ -94,13 +114,11 @@ PeerAddress::SetProtocol(const char* protocol)
char* char*
PeerAddress::UniversalAddress() const PeerAddress::UniversalAddress() const
{ {
const sockaddr* address = reinterpret_cast<const sockaddr*>(&fAddress);
char* uAddr = reinterpret_cast<char*>(malloc(INET6_ADDRSTRLEN + 16)); char* uAddr = reinterpret_cast<char*>(malloc(INET6_ADDRSTRLEN + 16));
if (uAddr == NULL) if (uAddr == NULL)
return NULL; return NULL;
if (inet_ntop(address->sa_family, InAddr(), uAddr, AddressSize()) == NULL) if (inet_ntop(fAddress.ss_family, InAddr(), uAddr, AddressSize()) == NULL)
return NULL; return NULL;
char port[16]; char port[16];
@@ -114,7 +132,7 @@ PeerAddress::UniversalAddress() const
socklen_t socklen_t
PeerAddress::AddressSize() const PeerAddress::AddressSize() const
{ {
switch (reinterpret_cast<const sockaddr*>(&fAddress)->sa_family) { switch (Family()) {
case AF_INET: case AF_INET:
return sizeof(sockaddr_in); return sizeof(sockaddr_in);
case AF_INET6: case AF_INET6:
@@ -130,7 +148,7 @@ PeerAddress::Port() const
{ {
uint16 port; uint16 port;
switch (reinterpret_cast<const sockaddr*>(&fAddress)->sa_family) { switch (Family()) {
case AF_INET: case AF_INET:
port = reinterpret_cast<const sockaddr_in*>(&fAddress)->sin_port; port = reinterpret_cast<const sockaddr_in*>(&fAddress)->sin_port;
break; break;
@@ -150,7 +168,7 @@ PeerAddress::SetPort(uint16 port)
{ {
port = htons(port); port = htons(port);
switch (reinterpret_cast<sockaddr*>(&fAddress)->sa_family) { switch (Family()) {
case AF_INET: case AF_INET:
reinterpret_cast<sockaddr_in*>(&fAddress)->sin_port = port; reinterpret_cast<sockaddr_in*>(&fAddress)->sin_port = port;
break; break;
@@ -160,11 +178,10 @@ PeerAddress::SetPort(uint16 port)
} }
} }
const void* const void*
PeerAddress::InAddr() const PeerAddress::InAddr() const
{ {
switch (reinterpret_cast<const sockaddr*>(&fAddress)->sa_family) { switch (Family()) {
case AF_INET: case AF_INET:
return &reinterpret_cast<const sockaddr_in*>(&fAddress)->sin_addr; return &reinterpret_cast<const sockaddr_in*>(&fAddress)->sin_addr;
case AF_INET6: case AF_INET6:
@@ -178,7 +195,7 @@ PeerAddress::InAddr() const
size_t size_t
PeerAddress::InAddrSize() const PeerAddress::InAddrSize() const
{ {
switch (reinterpret_cast<const sockaddr*>(&fAddress)->sa_family) { switch (Family()) {
case AF_INET: case AF_INET:
return sizeof(in_addr); return sizeof(in_addr);
case AF_INET6: case AF_INET6:
@@ -723,21 +740,23 @@ ConnectionBase::Disconnect()
status_t status_t
ConnectionListener::Listen(ConnectionListener** listener, uint16 port) ConnectionListener::Listen(ConnectionListener** listener, int networkFamily,
uint16 port)
{ {
ASSERT(listener != NULL); ASSERT(listener != NULL);
ASSERT(networkFamily == AF_INET || networkFamily == AF_INET6);
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); int sock = socket(networkFamily, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) if (sock < 0)
return errno; return errno;
sockaddr_in addr; PeerAddress address(networkFamily);
memset(&addr, 0, sizeof(addr)); address.SetPort(port);
addr.sin_len = sizeof(addr); address.fProtocol = IPPROTO_TCP;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY; status_t result = bind(sock, (sockaddr*)&address.fAddress,
addr.sin_port = htons(port); address.AddressSize());
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) != B_OK) { if (result != B_OK) {
close(sock); close(sock);
return errno; return errno;
} }
@@ -747,17 +766,12 @@ ConnectionListener::Listen(ConnectionListener** listener, uint16 port)
return errno; return errno;
} }
PeerAddress address;
address.fProtocol = IPPROTO_TCP;
memset(&address.fAddress, 0, sizeof(address.fAddress));
*listener = new(std::nothrow) ConnectionListener(address); *listener = new(std::nothrow) ConnectionListener(address);
if (*listener == NULL) { if (*listener == NULL) {
close(sock); close(sock);
return B_NO_MEMORY; return B_NO_MEMORY;
} }
status_t result;
if ((*listener)->fWaitCancel < B_OK) { if ((*listener)->fWaitCancel < B_OK) {
result = (*listener)->fWaitCancel; result = (*listener)->fWaitCancel;
close(sock); close(sock);
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Haiku, Inc. All rights reserved. * Copyright 2012-2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -25,6 +25,9 @@ struct PeerAddress {
PeerAddress& operator=(const PeerAddress& address); PeerAddress& operator=(const PeerAddress& address);
PeerAddress(); PeerAddress();
PeerAddress(int networkFamily);
inline int Family() const;
const char* ProtocolString() const; const char* ProtocolString() const;
void SetProtocol(const char* protocol); void SetProtocol(const char* protocol);
@@ -40,6 +43,14 @@ struct PeerAddress {
size_t InAddrSize() const; size_t InAddrSize() const;
}; };
inline int
PeerAddress::Family() const
{
return fAddress.ss_family;
}
struct addrinfo; struct addrinfo;
class AddressResolver { class AddressResolver {
@@ -122,7 +133,8 @@ public:
class ConnectionListener : public ConnectionBase { class ConnectionListener : public ConnectionBase {
public: public:
static status_t Listen(ConnectionListener** listener, uint16 port = 0); static status_t Listen(ConnectionListener** listener, int networkFamily,
uint16 port = 0);
status_t AcceptConnection(Connection** connection); status_t AcceptConnection(Connection** connection);
@@ -14,6 +14,7 @@
namespace RPC { namespace RPC {
class CallbackServer;
class CallbackRequest; class CallbackRequest;
class Server; class Server;
@@ -24,10 +25,14 @@ public:
inline void SetID(int32 id); inline void SetID(int32 id);
inline int32 ID(); inline int32 ID();
inline void SetCBServer(CallbackServer* server);
inline CallbackServer* CBServer();
status_t EnqueueRequest(CallbackRequest* request, status_t EnqueueRequest(CallbackRequest* request,
Connection* connection); Connection* connection);
private: private:
CallbackServer* fCBServer;
Server* fServer; Server* fServer;
int32 fID; int32 fID;
}; };
@@ -47,6 +52,20 @@ Callback::ID()
} }
inline void
Callback::SetCBServer(CallbackServer* server)
{
fCBServer = server;
}
inline CallbackServer*
Callback::CBServer()
{
return fCBServer;
}
} // namespace RPC } // namespace RPC
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Haiku, Inc. All rights reserved. * Copyright 2012-2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -13,22 +13,25 @@
#include "RPCCallback.h" #include "RPCCallback.h"
#include "RPCCallbackReply.h" #include "RPCCallbackReply.h"
#include "RPCCallbackRequest.h" #include "RPCCallbackRequest.h"
#include "RPCServer.h"
using namespace RPC; using namespace RPC;
CallbackServer* gRPCCallbackServer = NULL; CallbackServer* gRPCCallbackServer = NULL;
CallbackServer* gRPCCallbackServer6 = NULL;
CallbackServer::CallbackServer() CallbackServer::CallbackServer(int networkFamily)
: :
fConnectionList(NULL), fConnectionList(NULL),
fListener(NULL), fListener(NULL),
fThreadRunning(false), fThreadRunning(false),
fCallbackArray(NULL), fCallbackArray(NULL),
fArraySize(0), fArraySize(0),
fFreeSlot(-1) fFreeSlot(-1),
fNetworkFamily(networkFamily)
{ {
mutex_init(&fConnectionLock, NULL); mutex_init(&fConnectionLock, NULL);
mutex_init(&fThreadLock, NULL); mutex_init(&fThreadLock, NULL);
@@ -47,6 +50,47 @@ CallbackServer::~CallbackServer()
} }
CallbackServer*
CallbackServer::Get(Server* server)
{
ASSERT(server != NULL);
int family = server->ID().Family();
ASSERT(family == AF_INET || family == AF_INET6);
int idx;
switch (family) {
case AF_INET:
idx = 0;
break;
case AF_INET6:
idx = 1;
break;
default:
return NULL;
}
MutexLocker _(fServerCreationLock);
if (fServers[idx] == NULL)
fServers[idx] = new CallbackServer(family);
return fServers[idx];
}
void
CallbackServer::ShutdownAll()
{
MutexLocker _(fServerCreationLock);
for (unsigned int i = 0; i < sizeof(fServers) / sizeof(fServers[0]); i++)
delete fServers[i];
memset(&fServers, 0, sizeof(fServers));
}
mutex CallbackServer::fServerCreationLock = MUTEX_INITIALIZER(NULL);
CallbackServer* CallbackServer::fServers[2] = { NULL, NULL };
status_t status_t
CallbackServer::RegisterCallback(Callback* callback) CallbackServer::RegisterCallback(Callback* callback)
{ {
@@ -82,6 +126,7 @@ CallbackServer::RegisterCallback(Callback* callback)
fCallbackArray[id].fCallback = callback; fCallbackArray[id].fCallback = callback;
callback->SetID(id); callback->SetID(id);
callback->SetCBServer(this);
return B_OK; return B_OK;
} }
@@ -91,6 +136,7 @@ status_t
CallbackServer::UnregisterCallback(Callback* callback) CallbackServer::UnregisterCallback(Callback* callback)
{ {
ASSERT(callback != NULL); ASSERT(callback != NULL);
ASSERT(callback->CBServer() == this);
int32 id = callback->ID(); int32 id = callback->ID();
@@ -98,6 +144,7 @@ CallbackServer::UnregisterCallback(Callback* callback)
fCallbackArray[id].fNext = fFreeSlot; fCallbackArray[id].fNext = fFreeSlot;
fFreeSlot = id; fFreeSlot = id;
callback->SetCBServer(NULL);
return B_OK; return B_OK;
} }
@@ -109,7 +156,7 @@ CallbackServer::StartServer()
if (fThreadRunning) if (fThreadRunning)
return B_OK; return B_OK;
status_t result = ConnectionListener::Listen(&fListener); status_t result = ConnectionListener::Listen(&fListener, fNetworkFamily);
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Haiku, Inc. All rights reserved. * Copyright 2012-2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -17,6 +17,7 @@
namespace RPC { namespace RPC {
class Callback; class Callback;
class Server;
struct ConnectionEntry { struct ConnectionEntry {
Connection* fConnection; Connection* fConnection;
@@ -33,13 +34,16 @@ union CallbackSlot {
class CallbackServer { class CallbackServer {
public: public:
CallbackServer(); CallbackServer(int networkFamily);
~CallbackServer(); ~CallbackServer();
static CallbackServer* Get(Server* server);
static void ShutdownAll();
status_t RegisterCallback(Callback* callback); status_t RegisterCallback(Callback* callback);
status_t UnregisterCallback(Callback* callback); status_t UnregisterCallback(Callback* callback);
inline PeerAddress LocalID(); inline PeerAddress LocalID();
protected: protected:
status_t StartServer(); status_t StartServer();
@@ -57,6 +61,9 @@ protected:
inline Callback* GetCallback(int32 id); inline Callback* GetCallback(int32 id);
private: private:
static mutex fServerCreationLock;
static CallbackServer* fServers[2];
mutex fConnectionLock; mutex fConnectionLock;
ConnectionEntry* fConnectionList; ConnectionEntry* fConnectionList;
ConnectionListener* fListener; ConnectionListener* fListener;
@@ -69,6 +76,8 @@ private:
CallbackSlot* fCallbackArray; CallbackSlot* fCallbackArray;
uint32 fArraySize; uint32 fArraySize;
int32 fFreeSlot; int32 fFreeSlot;
int fNetworkFamily;
}; };
@@ -76,6 +85,8 @@ inline PeerAddress
CallbackServer::LocalID() CallbackServer::LocalID()
{ {
PeerAddress address; PeerAddress address;
ASSERT(fListener != NULL);
fListener->GetLocalAddress(&address); fListener->GetLocalAddress(&address);
return address; return address;
} }
@@ -93,9 +104,5 @@ CallbackServer::GetCallback(int32 id)
} // namespace RPC } // namespace RPC
extern RPC::CallbackServer* gRPCCallbackServer;
#endif // RPCCALLBACKSERVER_H #endif // RPCCALLBACKSERVER_H
@@ -97,7 +97,7 @@ Server::Server(Connection* connection, PeerAddress* address)
Server::~Server() Server::~Server()
{ {
if (fCallback != NULL) if (fCallback != NULL)
gRPCCallbackServer->UnregisterCallback(fCallback); fCallback->CBServer()->UnregisterCallback(fCallback);
delete fCallback; delete fCallback;
mutex_destroy(&fCallbackLock); mutex_destroy(&fCallbackLock);
mutex_destroy(&fRepairLock); mutex_destroy(&fRepairLock);
@@ -235,9 +235,22 @@ Callback*
Server::GetCallback() Server::GetCallback()
{ {
MutexLocker _(fCallbackLock); MutexLocker _(fCallbackLock);
if (fCallback == NULL) { if (fCallback == NULL) {
fCallback = new(std::nothrow) Callback(this); fCallback = new(std::nothrow) Callback(this);
gRPCCallbackServer->RegisterCallback(fCallback); if (fCallback == NULL)
return NULL;
CallbackServer* server = CallbackServer::Get(this);
if (server == NULL) {
delete fCallback;
return NULL;
}
if (server->RegisterCallback(fCallback) != B_OK) {
delete fCallback;
return NULL;
}
} }
return fCallback; return fCallback;
@@ -671,21 +671,29 @@ RequestBuilder::SetClientID(RPC::Server* server)
fRequest->Stream().AddUInt(0x40000000); fRequest->Stream().AddUInt(0x40000000);
uint32 id = server->GetCallback()->ID(); if (server->GetCallback() != NULL) {
ASSERT(server->GetCallback()->CBServer() != NULL);
PeerAddress local = gRPCCallbackServer->LocalID(); uint32 id = server->GetCallback()->ID();
PeerAddress servAddr = server->LocalID();
servAddr.SetPort(local.Port());
fRequest->Stream().AddString(local.ProtocolString()); PeerAddress local = server->GetCallback()->CBServer()->LocalID();
PeerAddress servAddr = server->LocalID();
servAddr.SetPort(local.Port());
char* uAddr = servAddr.UniversalAddress(); fRequest->Stream().AddString(local.ProtocolString());
if (uAddr == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddString(uAddr);
free(uAddr);
fRequest->Stream().AddUInt(id); char* uAddr = servAddr.UniversalAddress();
if (uAddr == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddString(uAddr);
free(uAddr);
fRequest->Stream().AddUInt(id);
} else {
fRequest->Stream().AddString("");
fRequest->Stream().AddString("");
fRequest->Stream().AddUInt(0);
}
fOpCount++; fOpCount++;
@@ -1367,14 +1367,6 @@ nfs4_init()
return B_NO_MEMORY; return B_NO_MEMORY;
} }
gRPCCallbackServer = new(std::nothrow) RPC::CallbackServer;
if (gRPCCallbackServer == NULL) {
mutex_destroy(&gIdMapperLock);
delete gWorkQueue;
delete gRPCServerManager;
return B_NO_MEMORY;
}
return B_OK; return B_OK;
} }
@@ -1382,7 +1374,8 @@ nfs4_init()
status_t status_t
nfs4_uninit() nfs4_uninit()
{ {
delete gRPCCallbackServer; RPC::CallbackServer::ShutdownAll();
delete gIdMapper; delete gIdMapper;
delete gWorkQueue; delete gWorkQueue;
delete gRPCServerManager; delete gRPCServerManager;