Move parsing getattrinfo() result out of dns_resolver module

This commit is contained in:
Pawel Dziepak
2012-07-05 01:25:17 +02:00
parent 2353db439e
commit 9054c96c17
8 changed files with 293 additions and 120 deletions
+31 -2
View File
@@ -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
@@ -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),
@@ -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 {
@@ -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;
ServerAddress addr;
if (gRPCServerManager->Acquire(&fServer, ip, 2049,
ProtocolUDP, CreateNFS4Server) == B_OK) {
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) {
@@ -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;
}
ServerAddress addr;
status_t result = ServerAddress::ResolveName(args, &addr);
if (result != B_OK)
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);
*_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;
@@ -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,
};
@@ -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 status_t
dns_resolve(const char* host, uint32* addr)
static void
RelocateEntries(struct addrinfo *addr)
{
mutex_lock(&gPortLock);
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
GetAddrInfo(const char* node, const char* service,
const struct addrinfo* hints, struct addrinfo** res)
{
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[] = {
@@ -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);
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));
}
if (result == B_BAD_PORT_ID)
size = read_port(gRequestPort, &code, buffer, size);
if (size < B_OK)
return 0;
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_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();
}