added 2 changesets to branch 'refs/remotes/pdziepak-github/nfs4' old head: b664395b9e9243f5d2de962913803bad6e3e4751 new head: 9054c96c17401b5ef4259cbba615ca8b8856473c ---------------------------------------------------------------------------- 2353db4: nfs4: Fix error checking after read_port() 9054c96: Move parsing getattrinfo() result out of dns_resolver module [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 10 files changed, 294 insertions(+), 121 deletions(-) headers/private/net/dns_resolver.h | 33 +++- .../kernel/file_systems/nfs4/Connection.cpp | 38 ++++ src/add-ons/kernel/file_systems/nfs4/Connection.h | 3 + .../kernel/file_systems/nfs4/Filesystem.cpp | 35 ++-- src/add-ons/kernel/file_systems/nfs4/IdMap.cpp | 4 +- .../kernel/file_systems/nfs4/idmapper/IdMapper.cpp | 4 +- .../kernel/file_systems/nfs4/kernel_interface.cpp | 32 +--- .../kernel/network/dns_resolver/Definitions.h | 6 +- .../dns_resolver/kernel_add_on/dns_resolver.cpp | 116 +++++++++++-- .../kernel/network/dns_resolver/server/main.cpp | 144 +++++++++++----- ############################################################################ Commit: 2353db439e3844c757adca4c7e6a2b2d4c050ccb Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Wed Jul 4 18:52:36 2012 UTC nfs4: Fix error checking after read_port() ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp index 36920c0..b53cbe9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -118,8 +118,8 @@ IdMap::_GetBuffer(T value, int32 code) if (buffer == NULL) return NULL; - result = read_port(fReplyPort, &code, buffer, size); - if (result < B_OK) { + size = read_port(fReplyPort, &code, buffer, size); + if (size < B_OK) { free(buffer); if (_Repair() != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp index 5c8d2a9..2622663 100644 --- a/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp @@ -198,13 +198,13 @@ MainLoop() return B_NO_MEMORY; int32 code; - status_t result = read_port(gRequestPort, &code, buffer, size); + size = read_port(gRequestPort, &code, buffer, size); if (size < B_OK) { free(buffer); return 0; } - result = ParseRequest(code, buffer); + status_t result = ParseRequest(code, buffer); free(buffer); if (result != B_OK) ############################################################################ Commit: 9054c96c17401b5ef4259cbba615ca8b8856473c Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Wed Jul 4 23:25:17 2012 UTC Move parsing getattrinfo() result out of dns_resolver module ---------------------------------------------------------------------------- diff --git a/headers/private/net/dns_resolver.h b/headers/private/net/dns_resolver.h index 179e9c2..0a5cf14 100644 --- a/headers/private/net/dns_resolver.h +++ b/headers/private/net/dns_resolver.h @@ -9,6 +9,9 @@ #define DNS_RESOLVER_H +#include <netdb.h> +#include <stdlib.h> + #include <module.h> @@ -16,10 +19,36 @@ struct dns_resolver_module { - module_info module; - status_t (*dns_resolve)(const char* host, uint32* addr); + module_info module; + status_t (*getaddrinfo)(const char* node, const char* service, + const struct addrinfo* hints, struct addrinfo** res); }; +static inline int +getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, + struct addrinfo** res) +{ + dns_resolver_module* dns; + status_t result = get_module(DNS_RESOLVER_MODULE_NAME, + reinterpret_cast<module_info**>(&dns)); + if (result != B_OK) + return result; + + result = dns->getaddrinfo(node, service, hints, res); + + put_module(DNS_RESOLVER_MODULE_NAME); + + return result; +} + + +static inline void +freeaddrinfo(struct addrinfo* res) +{ + free(res); +} + + #endif // DNS_RESOLVER_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 9cd6480..6a94ba7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -9,12 +9,14 @@ #include "Connection.h" +#include <arpa/inet.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <util/kernel_cpp.h> +#include <net/dns_resolver.h> #define LAST_FRAGMENT 0x80000000 @@ -48,6 +50,42 @@ ServerAddress::operator=(const ServerAddress& x) } +status_t +ServerAddress::ResolveName(const char* name, ServerAddress* addr) +{ + addr->fPort = 2049; + addr->fProtocol = ProtocolUDP; + + struct in_addr iaddr; + if (inet_aton(name, &iaddr) != 0) { + addr->fAddress = ntohl(iaddr.s_addr); + return B_OK; + } + + addrinfo* ai; + status_t result = getaddrinfo(name, NULL, NULL, &ai); + if (result != B_OK) + return result; + + addrinfo* current = ai; + while (current != NULL) { + if (current->ai_family == AF_INET) { + sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(current->ai_addr); + + addr->fAddress = ntohl(sin->sin_addr.s_addr); + + freeaddrinfo(ai); + return B_OK; + } + + current = current->ai_next; + } + + freeaddrinfo(ai); + return B_NAME_NOT_FOUND; +} + + Connection::Connection(const sockaddr_in& addr, Transport proto) : fSock(-1), diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index dcbb2c9..51d0323 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -29,6 +29,9 @@ struct ServerAddress { bool operator<(const ServerAddress& x); ServerAddress& operator=(const ServerAddress& x); + + static status_t ResolveName(const char* name, + ServerAddress* addr); }; class Connection { diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index df8b169..b128718 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -9,11 +9,9 @@ #include "Filesystem.h" -#include <arpa/inet.h> #include <string.h> #include <lock.h> -#include <net/dns_resolver.h> #include "Request.h" #include "RootInode.h" @@ -216,37 +214,25 @@ Filesystem::Migrate(const RPC::Server* serv) FSLocations* locs = reinterpret_cast<FSLocations*>(values[0].fData.fLocations); - dns_resolver_module* dns; - result = get_module(DNS_RESOLVER_MODULE_NAME, - reinterpret_cast<module_info**>(&dns)); - if (result != B_OK) { - delete[] values; - return result; - } - RPC::Server* server = fServer; for (uint32 i = 0; i < locs->fCount; i++) { for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) { - uint32 ip; - struct in_addr addr; - if (inet_aton(locs->fLocations[i].fLocations[j], &addr) == 0) { - result = dns->dns_resolve(locs->fLocations[i].fLocations[j], - &ip); - if (result != B_OK) - continue; - } else - ip = addr.s_addr; - - if (gRPCServerManager->Acquire(&fServer, ip, 2049, - ProtocolUDP, CreateNFS4Server) == B_OK) { + ServerAddress addr; + + if (ServerAddress::ResolveName(locs->fLocations[i].fLocations[j], + &addr) != B_OK) + continue; + + if (gRPCServerManager->Acquire(&fServer, addr.fAddress, addr.fPort, + addr.fProtocol, CreateNFS4Server) == B_OK) { free(const_cast<char*>(fPath)); - fPath = strdup(locs->fLocations[j].fRootPath); + fPath = strdup(locs->fLocations[i].fRootPath); if (fPath == NULL) { gRPCServerManager->Release(fServer); fServer = server; - put_module(DNS_RESOLVER_MODULE_NAME); + delete[] values; return B_NO_MEMORY; } @@ -256,7 +242,6 @@ Filesystem::Migrate(const RPC::Server* serv) } } - put_module(DNS_RESOLVER_MODULE_NAME); delete[] values; if (server == fServer) { 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 1f3c216..2edac96 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -7,10 +7,8 @@ */ -#include <arpa/inet.h> #include <stdio.h> -#include <net/dns_resolver.h> #include <fs_interface.h> #include "Connection.h" @@ -42,7 +40,7 @@ CreateNFS4Server(RPC::Server* serv) static status_t -sParseArguments(const char* _args, uint32* _ip, char* _path) +ParseArguments(const char* _args, uint32* _ip, char* _path) { if (_args == NULL) return B_BAD_VALUE; @@ -55,26 +53,12 @@ sParseArguments(const char* _args, uint32* _ip, char* _path) } *path++ = '\0'; - status_t result; - struct in_addr addr; - if (inet_aton(args, &addr) == 0) { - dns_resolver_module* dns; - result = get_module(DNS_RESOLVER_MODULE_NAME, - reinterpret_cast<module_info**>(&dns)); - if (result != B_OK) { - free(args); - return result; - } - - result = dns->dns_resolve(args, _ip); - put_module(DNS_RESOLVER_MODULE_NAME); - if (result != B_OK) { - free(args); - return result; - } - } else - *_ip = addr.s_addr; - *_ip = ntohl(*_ip); + ServerAddress addr; + status_t result = ServerAddress::ResolveName(args, &addr); + if (result != B_OK) + return result; + + *_ip = addr.fAddress; _path[255] = '\0'; strncpy(_path, path, 255); @@ -92,7 +76,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, uint32 ip; char path[256]; - result = sParseArguments(args, &ip, path); + result = ParseArguments(args, &ip, path); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/network/dns_resolver/Definitions.h b/src/add-ons/kernel/network/dns_resolver/Definitions.h index 407b2a4..6aef5c0 100644 --- a/src/add-ons/kernel/network/dns_resolver/Definitions.h +++ b/src/add-ons/kernel/network/dns_resolver/Definitions.h @@ -13,9 +13,9 @@ const char* kPortNameReq = "dns_resolver_req"; const char* kPortNameRpl = "dns_resolver_rpl"; enum MsgCodes { - MsgResolveRequest = 1, - MsgResolveReply = 2, - MsgResolveError = 3 + MsgReply, + MsgError, + MsgGetAddrInfo, }; diff --git a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp index 121c08c..40d2db4 100644 --- a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp +++ b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp @@ -9,10 +9,12 @@ #include <net/dns_resolver.h> +#include <AutoDeleter.h> #include <FindDirectory.h> #include <lock.h> #include <port.h> #include <team.h> +#include <util/AutoLock.h> #include "Definitions.h" @@ -91,40 +93,120 @@ dns_resolver_uninit() } +static void +RelocateEntries(struct addrinfo *addr) +{ + char* generalOffset = reinterpret_cast<char*>(addr); + + struct addrinfo* current = addr; + while (current != NULL) { + uint64 addrOffset = reinterpret_cast<uint64>(current->ai_addr); + uint64 nameOffset = reinterpret_cast<uint64>(current->ai_canonname); + uint64 nextOffset = reinterpret_cast<uint64>(current->ai_next); + + if (current->ai_addr != NULL) { + current->ai_addr = + reinterpret_cast<sockaddr*>(generalOffset + addrOffset); + } + + if (current->ai_canonname != NULL) + current->ai_canonname = generalOffset + nameOffset; + + if (current->ai_next != NULL) { + current->ai_next = + reinterpret_cast<addrinfo*>(generalOffset + nextOffset); + } + + current = current->ai_next; + } +} + + static status_t -dns_resolve(const char* host, uint32* addr) +GetAddrInfo(const char* node, const char* service, + const struct addrinfo* hints, struct addrinfo** res) { - mutex_lock(&gPortLock); + dprintf("SENDING GETADDRINFO %s\n", node); + + uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; + uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; + uint32 size = nodeSize + serviceSize + sizeof(*hints); + char* buffer = reinterpret_cast<char*>(malloc(size)); + if (buffer == NULL) + return B_NO_MEMORY; + MemoryDeleter _(buffer); + + off_t off = 0; + if (node != NULL) + strcpy(buffer + off, node); + else + buffer[off] = '\0'; + off += nodeSize; + + if (service != NULL) + strcpy(buffer + off, service); + else + buffer[off] = '\0'; + off += serviceSize; + + if (hints != NULL) + memcpy(buffer + off, hints, sizeof(*hints)); + else { + struct addrinfo *nullHints = + reinterpret_cast<struct addrinfo*>(buffer + off); + memset(nullHints, 0, sizeof(*nullHints)); + nullHints->ai_family = AF_UNSPEC; + } + dprintf("SENDING BUFFER %s %d\n", buffer, (int)size); + MutexLocker locker(gPortLock); do { - status_t result = write_port(gPortRequest, MsgResolveRequest, host, - strlen(host) + 1); + status_t result = write_port(gPortRequest, MsgGetAddrInfo, buffer, + size); if (result != B_OK) { result = dns_resolver_repair(); - if (result != B_OK) { - mutex_unlock(&gPortLock); + if (result != B_OK) return result; - } + continue; + } + ssize_t replySize = port_buffer_size(gPortReply); + if (replySize < B_OK) { + result = dns_resolver_repair(); + if (result != B_OK) + return result; continue; } + void* reply = malloc(replySize); + if (reply == NULL) + return B_NO_MEMORY; + int32 code; - result = read_port(gPortReply, &code, addr, sizeof(*addr)); - if (result < B_OK) { + replySize = read_port(gPortReply, &code, reply, replySize); + if (replySize < B_OK) { result = dns_resolver_repair(); if (result != B_OK) { - mutex_unlock(&gPortLock); + free(reply); return result; } - continue; } - mutex_unlock(&gPortLock); - if (code == MsgResolveReply) - return B_OK; - else - return *addr; + struct addrinfo *addr; + switch (code) { + case MsgReply: + addr = reinterpret_cast<struct addrinfo*>(reply); + RelocateEntries(addr); + *res = addr; + return B_OK; + case MsgError: + result = *reinterpret_cast<status_t*>(reply); + free(reply); + return result; + default: + free(reply); + return B_BAD_VALUE; + } } while (true); } @@ -150,7 +232,7 @@ static dns_resolver_module sDNSResolverModule = { dns_resolver_std_ops, }, - dns_resolve, + GetAddrInfo, }; module_info* modules[] = { diff --git a/src/add-ons/kernel/network/dns_resolver/server/main.cpp b/src/add-ons/kernel/network/dns_resolver/server/main.cpp index 3b4a14e..0c816ca 100644 --- a/src/add-ons/kernel/network/dns_resolver/server/main.cpp +++ b/src/add-ons/kernel/network/dns_resolver/server/main.cpp @@ -8,81 +8,133 @@ #include <stdlib.h> +#include <string.h> #include <sys/socket.h> #include <netdb.h> -#include <port.h> +#include <AutoDeleter.h> +#include <OS.h> #include <SupportDefs.h> #include "Definitions.h" +port_id gRequestPort; +port_id gReplyPort; + + status_t -resolve_dns(const char* host, uint32* addr) +GetAddrInfo(const char* buffer) { - addrinfo* ai; - addrinfo* current; - status_t result = getaddrinfo(host, NULL, NULL, &ai); + const char* node = buffer[0] == '\0' ? NULL : buffer; + uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; + + const char* service = buffer[nodeSize] == '\0' ? NULL : buffer + nodeSize; + uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; + + const struct addrinfo* hints = + reinterpret_cast<const addrinfo*>(buffer + nodeSize + serviceSize); + + struct addrinfo* ai; + status_t result = getaddrinfo(node, service, hints, &ai); if (result != B_OK) - return result; + return write_port(gReplyPort, MsgError, &result, sizeof(result)); - current = ai; + uint32 addrsSize = ai == NULL ? 0 : sizeof(addrinfo); + uint32 namesSize = 0; + uint32 socksSize = 0; + addrinfo* current = ai; while (current != NULL) { - if (current->ai_family == AF_INET) { - sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(current->ai_addr); - *addr = sin->sin_addr.s_addr; - freeaddrinfo(ai); - return B_OK; + if (current->ai_canonname != NULL) + namesSize += strlen(current->ai_canonname) + 1; + if (current->ai_addr != NULL) { + if (current->ai_family == AF_INET) + socksSize += sizeof(sockaddr_in); + else + socksSize += sizeof(sockaddr_in6); } - + if (current->ai_next != NULL) + addrsSize += sizeof(addrinfo); current = current->ai_next; } - freeaddrinfo(ai); - return B_NAME_NOT_FOUND; + uint32 totalSize = addrsSize + namesSize + socksSize; + char* reply = reinterpret_cast<char*>(malloc(totalSize)); + if (reply == NULL) { + free(reply); + + result = B_NO_MEMORY; + return write_port(gReplyPort, MsgError, &result, sizeof(result)); + } + + uint32 addrPos = 0; + uint32 namePos = addrsSize; + uint32 sockPos = addrsSize + namesSize; + + current = ai; + while (current != NULL) { + if (current->ai_canonname != NULL) { + strcpy(reply + namePos, current->ai_canonname); + uint32 nSize = strlen(current->ai_canonname) + 1; + current->ai_canonname = reinterpret_cast<char*>(namePos); + namePos += nSize; + } + if (current->ai_addr != NULL) { + if (current->ai_family == AF_INET) { + memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in)); + current->ai_addr = reinterpret_cast<sockaddr*>(sockPos); + sockPos += sizeof(sockaddr_in); + } else { + memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in6)); + current->ai_addr = reinterpret_cast<sockaddr*>(sockPos); + sockPos += sizeof(sockaddr_in6); + } + } + + addrinfo* next = current->ai_next; + current->ai_next = reinterpret_cast<addrinfo*>(addrPos) + 1; + memcpy(reply + addrPos, current, sizeof(addrinfo)); + addrPos += sizeof(addrinfo); + + current = next; + } + + return write_port(gReplyPort, MsgReply, reply, totalSize); } status_t -main_loop(port_id portReq, port_id portRpl) +MainLoop() { do { - ssize_t size = port_buffer_size(portReq); + ssize_t size = port_buffer_size(gRequestPort); if (size < B_OK) return 0; void* buffer = malloc(size); if (buffer == NULL) return B_NO_MEMORY; + MemoryDeleter _(buffer); int32 code; - status_t result = read_port(portReq, &code, buffer, size); - if (size < B_OK) { - free(buffer); + size = read_port(gRequestPort, &code, buffer, size); + if (size < B_OK) return 0; - } - - if (code != MsgResolveRequest) { - free(buffer); - continue; - } - - uint32 addr; - result = resolve_dns(reinterpret_cast<char*>(buffer), &addr); - free(buffer); - if (result == B_OK) - result = write_port(portRpl, MsgResolveReply, &addr, sizeof(addr)); - else { - result = write_port(portRpl, MsgResolveError, &result, - sizeof(result)); + status_t result; + switch (code) { + case MsgGetAddrInfo: + result = GetAddrInfo(reinterpret_cast<char*>(buffer)); + default: + result = B_BAD_VALUE; + write_port(gReplyPort, MsgError, &result, sizeof(result)); + result = B_OK; } - if (result == B_BAD_PORT_ID) + if (result != B_OK) return 0; - } while (true); } @@ -90,18 +142,18 @@ main_loop(port_id portReq, port_id portRpl) int main(int argc, char** argv) { - port_id portReq = find_port(kPortNameReq); - if (portReq == B_NAME_NOT_FOUND) { - fprintf(stderr, "%s\n", strerror(portReq)); - return portReq; + gRequestPort = find_port(kPortNameReq); + if (gRequestPort < B_OK) { + fprintf(stderr, "%s\n", strerror(gRequestPort)); + return gRequestPort; } - port_id portRpl = find_port(kPortNameRpl); - if (portRpl == B_NAME_NOT_FOUND) { - fprintf(stderr, "%s\n", strerror(portRpl)); - return portRpl; + gReplyPort = find_port(kPortNameRpl); + if (gReplyPort < B_OK) { + fprintf(stderr, "%s\n", strerror(gReplyPort)); + return gReplyPort; } - return main_loop(portReq, portRpl); + return MainLoop(); }