diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 10b576cced..17e41cf6c5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -19,6 +19,8 @@ #include +#define NFS4_PORT 2049 + #define LAST_FRAGMENT 0x80000000 #define MAX_PACKET_SIZE 65535 @@ -26,17 +28,15 @@ bool ServerAddress::operator==(const ServerAddress& address) { - return fAddress == address.fAddress && fPort == address.fPort - && fProtocol == address.fProtocol; + return memcmp(&fAddress, &address.fAddress, sizeof(fAddress)) == 0 + && fProtocol == address.fProtocol; } bool ServerAddress::operator<(const ServerAddress& address) { - return fAddress < address.fAddress || - (fAddress == address.fAddress && fPort < address.fPort) || - (fAddress == address.fAddress && fPort == address.fPort && - fProtocol < address.fProtocol); + int compare = memcmp(&fAddress, &address.fAddress, sizeof(fAddress)); + return compare < 0 || (compare == 0 && fProtocol < address.fProtocol); } @@ -44,21 +44,34 @@ ServerAddress& ServerAddress::operator=(const ServerAddress& address) { fAddress = address.fAddress; - fPort = address.fPort; fProtocol = address.fProtocol; return *this; } +ServerAddress::ServerAddress() + : + fProtocol(0) +{ + memset(&fAddress, 0, sizeof(fAddress)); +} + + status_t ServerAddress::ResolveName(const char* name, ServerAddress* address) { - address->fPort = 2049; address->fProtocol = IPPROTO_UDP; - struct in_addr iaddr; - if (inet_aton(name, &iaddr) != 0) { - address->fAddress = ntohl(iaddr.s_addr); + // 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) { + addr.sin_family = AF_INET; + addr.sin_port = htons(NFS4_PORT); + + memcpy(&address->fAddress, &addr, sizeof(addr)); return B_OK; } @@ -70,16 +83,20 @@ ServerAddress::ResolveName(const char* name, ServerAddress* address) addrinfo* current = ai; while (current != NULL) { if (current->ai_family == AF_INET) { - sockaddr_in* sin = - reinterpret_cast(current->ai_addr); - - address->fAddress = ntohl(sin->sin_addr.s_addr); - - freeaddrinfo(ai); - return B_OK; + memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in)); + reinterpret_cast(&address->fAddress)->sin_port + = htons(NFS4_PORT); + } else if (current->ai_family == AF_INET6) { + memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in6)); + reinterpret_cast(&address->fAddress)->sin6_port + = htons(NFS4_PORT); + } else { + current = current->ai_next; + continue; } - current = current->ai_next; + freeaddrinfo(ai); + return B_OK; } freeaddrinfo(ai); @@ -87,27 +104,26 @@ ServerAddress::ResolveName(const char* name, ServerAddress* address) } -Connection::Connection(const sockaddr_in& address, int protocol) +Connection::Connection(const ServerAddress& address) : fWaitCancel(create_sem(0, NULL)), fSocket(-1), - fProtocol(protocol), fServerAddress(address) { mutex_init(&fSocketLock, NULL); } -ConnectionStream::ConnectionStream(const sockaddr_in& address, int protocol) +ConnectionStream::ConnectionStream(const ServerAddress& address) : - Connection(address, protocol) + Connection(address) { } -ConnectionPacket::ConnectionPacket(const sockaddr_in& address, int protocol) +ConnectionPacket::ConnectionPacket(const ServerAddress& address) : - Connection(address, protocol) + Connection(address) { } @@ -124,17 +140,22 @@ Connection::~Connection() status_t Connection::GetLocalAddress(ServerAddress* address) { - struct sockaddr_in saddr; - socklen_t slen = sizeof(saddr); - status_t result = getsockname(fSocket, (struct sockaddr*)&saddr, &slen); - if (result != B_OK) - return result; + address->fProtocol = fServerAddress.fProtocol; - address->fProtocol = fProtocol; - address->fPort = ntohs(saddr.sin_port); - address->fAddress = ntohl(saddr.sin_addr.s_addr); + socklen_t addressSize; + switch (reinterpret_cast(&fServerAddress)->sa_family) { + case AF_INET: + addressSize = sizeof(sockaddr_in); + break; + case AF_INET6: + addressSize = sizeof(sockaddr_in6); + break; + default: + return B_BAD_VALUE; + } - return B_OK; + return getsockname(fSocket, + (struct sockaddr*)&address->fAddress, &addressSize); } @@ -315,21 +336,13 @@ ConnectionPacket::Receive(void** _buffer, uint32* _size) status_t Connection::Connect(Connection **_connection, const ServerAddress& address) { - struct sockaddr_in addr; - - memset(&addr, 0, sizeof(addr)); - addr.sin_len = sizeof(struct sockaddr_in); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(address.fAddress); - addr.sin_port = htons(address.fPort); - Connection* conn; switch (address.fProtocol) { case IPPROTO_TCP: - conn = new(std::nothrow) ConnectionStream(addr, address.fProtocol); + conn = new(std::nothrow) ConnectionStream(address); break; case IPPROTO_UDP: - conn = new(std::nothrow) ConnectionPacket(addr, address.fProtocol); + conn = new(std::nothrow) ConnectionPacket(address); break; default: return B_BAD_VALUE; @@ -352,12 +365,15 @@ Connection::Connect(Connection **_connection, const ServerAddress& address) status_t Connection::Connect() { - switch (fProtocol) { + const sockaddr& address = + *reinterpret_cast(&fServerAddress); + + switch (fServerAddress.fProtocol) { case IPPROTO_TCP: - fSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + fSocket = socket(address.sa_family, SOCK_STREAM, IPPROTO_TCP); break; case IPPROTO_UDP: - fSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fSocket = socket(address.sa_family, SOCK_DGRAM, IPPROTO_UDP); break; default: return B_BAD_VALUE; @@ -365,8 +381,19 @@ Connection::Connect() if (fSocket < 0) return errno; - status_t result = connect(fSocket, (struct sockaddr*)&fServerAddress, - fServerAddress.sin_len); + socklen_t addressSize; + switch (address.sa_family) { + case AF_INET: + addressSize = sizeof(sockaddr_in); + break; + case AF_INET6: + addressSize = sizeof(sockaddr_in6); + break; + default: + return B_BAD_VALUE; + } + + status_t result = connect(fSocket, &address, addressSize); if (result < 0) { result = errno; close(fSocket); diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index d6f996a04d..2da2f6e5b2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -16,8 +16,7 @@ struct ServerAddress { - uint32 fAddress; - uint16 fPort; + sockaddr_storage fAddress; int fProtocol; bool operator==(const ServerAddress& address); @@ -25,6 +24,8 @@ struct ServerAddress { ServerAddress& operator=(const ServerAddress& address); + ServerAddress(); + static status_t ResolveName(const char* name, ServerAddress* address); }; @@ -44,22 +45,19 @@ public: void Disconnect(); protected: - Connection(const sockaddr_in& address, - int protocol); + Connection(const ServerAddress& address); status_t Connect(); sem_id fWaitCancel; int fSocket; mutex fSocketLock; - const int fProtocol; - const sockaddr_in fServerAddress; + const ServerAddress fServerAddress; }; class ConnectionStream : public Connection { public: - ConnectionStream(const sockaddr_in& address, - int protocol); + ConnectionStream(const ServerAddress& address); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); @@ -67,8 +65,7 @@ public: class ConnectionPacket : public Connection { public: - ConnectionPacket(const sockaddr_in& address, - int protocol); + ConnectionPacket(const ServerAddress& address); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index e9007fad0f..738f854d75 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -9,6 +9,7 @@ #include "RequestBuilder.h" +#include #include #include "Cookie.h" @@ -592,7 +593,7 @@ RequestBuilder::SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr, status_t -RequestBuilder::SetClientID(const RPC::Server* serv) +RequestBuilder::SetClientID(const RPC::Server* server) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -604,19 +605,9 @@ RequestBuilder::SetClientID(const RPC::Server* serv) verifier = verifier << 32 | rand(); fRequest->Stream().AddUHyper(verifier); - char id[128] = "HAIKU:kernel:"; - int pos = strlen(id); - *(uint32*)(id + pos) = serv->ID().fAddress; - pos += sizeof(uint32); - *(uint16*)(id + pos) = serv->ID().fPort; - pos += sizeof(uint16); - *(uint16*)(id + pos) = serv->ID().fProtocol; - pos += sizeof(uint16); - - *(uint32*)(id + pos) = serv->LocalID().fAddress; - pos += sizeof(uint32); - - fRequest->Stream().AddOpaque(id, pos); + status_t result = _GenerateClientId(fRequest->Stream(), server); + if (result != B_OK) + return result; // Callbacks are currently not supported fRequest->Stream().AddUInt(0); @@ -630,6 +621,64 @@ RequestBuilder::SetClientID(const RPC::Server* serv) } +status_t +RequestBuilder::_GenerateClientId(XDR::WriteStream& stream, + const RPC::Server* server) +{ + char id[512] = "HAIKU:kernel:"; + int pos = strlen(id); + + const sockaddr* remoteAddress = + reinterpret_cast(&server->ID().fAddress); + + ServerAddress local = server->LocalID(); + const sockaddr* localAddress = reinterpret_cast(&local.fAddress); + + const sockaddr_in* address4; + const sockaddr_in6* address6; + switch (remoteAddress->sa_family) { + case AF_INET: + address4 = reinterpret_cast(remoteAddress); + + memcpy(id + pos, &address4->sin_addr, sizeof(address4->sin_addr)); + pos += sizeof(address4->sin_addr); + + memcpy(id + pos, + &reinterpret_cast(localAddress)->sin_addr, + sizeof(address4->sin_addr)); + pos += sizeof(address4->sin_addr); + + *(uint16*)(id + pos) = address4->sin_port; + break; + + case AF_INET6: + address6 = reinterpret_cast(remoteAddress); + + memcpy(id + pos, &address6->sin6_addr, sizeof(address6->sin6_addr)); + pos += sizeof(address6->sin6_addr); + + memcpy(id + pos, + &reinterpret_cast(localAddress)->sin6_addr, + sizeof(address6->sin6_addr)); + pos += sizeof(address6->sin6_addr); + + *(uint16*)(id + pos) = address6->sin6_port; + break; + + default: + return B_BAD_VALUE; + } + pos += sizeof(uint16); + + *(uint16*)(id + pos) = server->ID().fProtocol; + pos += sizeof(uint16); + + stream.AddOpaque(id, pos); + + return B_OK; +} + + status_t RequestBuilder::SetClientIDConfirm(uint64 id, uint64 ver) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 753a8378bd..17800c9eca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -68,7 +68,7 @@ public: status_t SaveFH(); status_t SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr, uint32 count); - status_t SetClientID(const RPC::Server* serv); + status_t SetClientID(const RPC::Server* server); status_t SetClientIDConfirm(uint64 id, uint64 ver); status_t Verify(AttrValue* attr, uint32 count); status_t Write(const uint32* id, uint32 stateSeq, @@ -85,6 +85,8 @@ private: void _GenerateLockOwner(XDR::WriteStream& stream, OpenFileCookie* cookie, LockOwner* owner); + status_t _GenerateClientId(XDR::WriteStream& stream, + const RPC::Server* server); void _EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, uint32 count); diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index b497f6e07f..fdd79f3d11 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -39,8 +39,10 @@ CreateNFS4Server(RPC::Server* serv) } + +// TODO: IPv6 address will cause problems static status_t -ParseArguments(const char* _args, uint32* _ip, char* _path) +ParseArguments(const char* _args, ServerAddress* address, char* _path) { if (_args == NULL) return B_BAD_VALUE; @@ -53,13 +55,10 @@ ParseArguments(const char* _args, uint32* _ip, char* _path) } *path++ = '\0'; - ServerAddress addr; - status_t result = ServerAddress::ResolveName(args, &addr); + status_t result = ServerAddress::ResolveName(args, address); if (result != B_OK) return result; - *_ip = addr.fAddress; - _path[255] = '\0'; strncpy(_path, path, 255); @@ -74,19 +73,14 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, { status_t result; - uint32 ip; + ServerAddress address; char path[256]; - result = ParseArguments(args, &ip, path); + result = ParseArguments(args, &address, path); if (result != B_OK) return result; - ServerAddress id; - id.fAddress = ip; - id.fPort = 2049; - id.fProtocol = IPPROTO_UDP; - RPC::Server *server; - result = gRPCServerManager->Acquire(&server, id, CreateNFS4Server); + result = gRPCServerManager->Acquire(&server, address, CreateNFS4Server); if (result != B_OK) return result;