1/* 2 * Copyright 2012 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Pawe�� Dziepak, pdziepak@quarnos.org 7 */ 8 9 10#include <net/dns_resolver.h> 11 12#include <AutoDeleter.h> 13#include <FindDirectory.h> 14#include <lock.h> 15#include <port.h> 16#include <team.h> 17#include <util/AutoLock.h> 18 19#include "Definitions.h" 20 21 22static mutex gPortLock; 23static port_id gPortRequest = -1; 24static port_id gPortReply = -1; 25 26static const int32 kQueueLength = 1; 27 28 29static status_t 30dns_resolver_repair() 31{ 32 status_t result = B_OK; 33 34 gPortRequest = create_port(kQueueLength, kPortNameReq); 35 if (gPortRequest < B_OK) 36 return gPortRequest; 37 38 gPortReply = create_port(kQueueLength, kPortNameRpl); 39 if (gPortReply < B_OK) { 40 delete_port(gPortRequest); 41 return gPortReply; 42 } 43 44 char path[256]; 45 if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, static_cast<dev_t>(-1), 46 false, path, sizeof(path)) != B_OK) { 47 delete_port(gPortReply); 48 delete_port(gPortRequest); 49 return B_NAME_NOT_FOUND; 50 } 51 strlcat(path, "/dns_resolver_server", sizeof(path)); 52 53 const char* args[] = { path, NULL }; 54 thread_id thread = load_image_etc(1, args, NULL, B_NORMAL_PRIORITY, 55 B_SYSTEM_TEAM, 0); 56 if (thread < B_OK) { 57 delete_port(gPortReply); 58 delete_port(gPortRequest); 59 return thread; 60 } 61 62 set_port_owner(gPortRequest, thread); 63 set_port_owner(gPortReply, thread); 64 65 result = resume_thread(thread); 66 if (result != B_OK) { 67 kill_thread(thread); 68 delete_port(gPortReply); 69 delete_port(gPortRequest); 70 return result; 71 } 72 73 return B_OK; 74} 75 76 77static status_t 78dns_resolver_init() 79{ 80 mutex_init(&gPortLock, NULL); 81 return dns_resolver_repair(); 82} 83 84 85static status_t 86dns_resolver_uninit() 87{ 88 delete_port(gPortRequest); 89 delete_port(gPortReply); 90 mutex_destroy(&gPortLock); 91 92 return B_OK; 93} 94 95 96static void 97RelocateEntries(struct addrinfo* addr) 98{ 99 char* generalOffset = reinterpret_cast<char*>(addr); 100 101 struct addrinfo* current = addr; 102 while (current != NULL) { 103 uint64 addrOffset = reinterpret_cast<uint64>(current->ai_addr); 104 uint64 nameOffset = reinterpret_cast<uint64>(current->ai_canonname); 105 uint64 nextOffset = reinterpret_cast<uint64>(current->ai_next); 106 107 if (current->ai_addr != NULL) { 108 current->ai_addr 109 = reinterpret_cast<sockaddr*>(generalOffset + addrOffset); 110 } 111 112 if (current->ai_canonname != NULL) 113 current->ai_canonname = generalOffset + nameOffset; 114 115 if (current->ai_next != NULL) { 116 current->ai_next 117 = reinterpret_cast<addrinfo*>(generalOffset + nextOffset); 118 } 119 120 current = current->ai_next; 121 } 122} 123 124 125static status_t 126GetAddrInfo(const char* node, const char* service, 127 const struct addrinfo* hints, struct addrinfo** res) 128{ 129 uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; 130 uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; 131 uint32 size = nodeSize + serviceSize + sizeof(*hints); 132 char* buffer = reinterpret_cast<char*>(malloc(size)); 133 if (buffer == NULL) 134 return B_NO_MEMORY; 135 MemoryDeleter _(buffer); 136 137 off_t off = 0; 138 if (node != NULL) 139 strcpy(buffer + off, node); 140 else 141 buffer[off] = '\0'; 142 off += nodeSize; 143 144 if (service != NULL) 145 strcpy(buffer + off, service); 146 else 147 buffer[off] = '\0'; 148 off += serviceSize; 149 150 if (hints != NULL) 151 memcpy(buffer + off, hints, sizeof(*hints)); 152 else { 153 struct addrinfo *nullHints 154 = reinterpret_cast<struct addrinfo*>(buffer + off); 155 memset(nullHints, 0, sizeof(*nullHints)); 156 nullHints->ai_family = AF_UNSPEC; 157 } 158 159 MutexLocker locker(gPortLock); 160 do { 161 status_t result = write_port(gPortRequest, MsgGetAddrInfo, buffer, 162 size); 163 if (result != B_OK) { 164 result = dns_resolver_repair(); 165 if (result != B_OK) 166 return result; 167 continue; 168 } 169 170 ssize_t replySize = port_buffer_size(gPortReply); 171 if (replySize < B_OK) { 172 result = dns_resolver_repair(); 173 if (result != B_OK) 174 return result; 175 continue; 176 } 177 178 void* reply = malloc(replySize); 179 if (reply == NULL) 180 return B_NO_MEMORY; 181 182 int32 code; 183 replySize = read_port(gPortReply, &code, reply, replySize); 184 if (replySize < B_OK) { 185 free(reply); 186 result = dns_resolver_repair(); 187 if (result != B_OK) 188 return result; 189 continue; 190 } 191 192 struct addrinfo* addr; 193 switch (code) { 194 case MsgReply: 195 addr = reinterpret_cast<struct addrinfo*>(reply); 196 RelocateEntries(addr); 197 *res = addr; 198 return B_OK; 199 case MsgError: 200 result = *reinterpret_cast<status_t*>(reply); 201 free(reply); 202 return result; 203 default: 204 free(reply); 205 return B_BAD_VALUE; 206 } 207 208 } while (true); 209} 210 211 212static status_t 213dns_resolver_std_ops(int32 op, ...) 214{ 215 switch (op) { 216 case B_MODULE_INIT: 217 return dns_resolver_init(); 218 case B_MODULE_UNINIT: 219 return dns_resolver_uninit(); 220 default: 221 return B_ERROR; 222 } 223} 224 225 226static dns_resolver_module sDNSResolverModule = { 227 { 228 DNS_RESOLVER_MODULE_NAME, 229 0, 230 dns_resolver_std_ops, 231 }, 232 233 GetAddrInfo, 234}; 235 236module_info* modules[] = { 237 (module_info*)&sDNSResolverModule, 238 NULL 239}; 240 241