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 <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <sys/socket.h> 15 #include <netdb.h> 16 17 #include <AutoDeleter.h> 18 #include <OS.h> 19 #include <SupportDefs.h> 20 21 #include "Definitions.h" 22 23 24 port_id gRequestPort; 25 port_id gReplyPort; 26 27 28 status_t 29 Serialize(char** _reply, uint32* _totalSize, const struct addrinfo* ai) 30 { 31 uint32 addrsSize = ai == NULL ? 0 : sizeof(addrinfo); 32 uint32 namesSize = 0; 33 uint32 socksSize = 0; 34 35 const struct addrinfo* current = ai; 36 while (current != NULL) { 37 if (current->ai_canonname != NULL) 38 namesSize += strlen(current->ai_canonname) + 1; 39 if (current->ai_addr != NULL) { 40 if (current->ai_family == AF_INET) 41 socksSize += sizeof(sockaddr_in); 42 else 43 socksSize += sizeof(sockaddr_in6); 44 } 45 if (current->ai_next != NULL) 46 addrsSize += sizeof(addrinfo); 47 current = current->ai_next; 48 } 49 50 uint32 totalSize = addrsSize + namesSize + socksSize; 51 char* reply = reinterpret_cast<char*>(malloc(totalSize)); 52 if (reply == NULL) 53 return B_NO_MEMORY; 54 55 uint32 addrPos = 0; 56 uint32 namePos = addrsSize; 57 uint32 sockPos = addrsSize + namesSize; 58 59 struct addrinfo temp; 60 61 current = ai; 62 while (current != NULL) { 63 memcpy(&temp, current, sizeof(addrinfo)); 64 65 if (current->ai_canonname != NULL) { 66 strcpy(reply + namePos, current->ai_canonname); 67 uint32 nSize = strlen(current->ai_canonname) + 1; 68 temp.ai_canonname = reinterpret_cast<char*>(namePos); 69 namePos += nSize; 70 } 71 if (current->ai_addr != NULL) { 72 if (current->ai_family == AF_INET) { 73 memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in)); 74 temp.ai_addr = reinterpret_cast<sockaddr*>(sockPos); 75 sockPos += sizeof(sockaddr_in); 76 } else { 77 memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in6)); 78 temp.ai_addr = reinterpret_cast<sockaddr*>(sockPos); 79 sockPos += sizeof(sockaddr_in6); 80 } 81 } 82 83 addrinfo* next = current->ai_next; 84 if (next != NULL) 85 temp.ai_next = reinterpret_cast<addrinfo*>(addrPos) + 1; 86 else 87 temp.ai_next = NULL; 88 89 memcpy(reply + addrPos, &temp, sizeof(addrinfo)); 90 addrPos += sizeof(addrinfo); 91 92 current = next; 93 } 94 95 *_reply = reply; 96 *_totalSize = totalSize; 97 return B_OK; 98 } 99 100 101 status_t 102 GetAddrInfo(const char* buffer) 103 { 104 const char* node = buffer[0] == '\0' ? NULL : buffer; 105 uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; 106 107 const char* service = buffer[nodeSize] == '\0' ? NULL : buffer + nodeSize; 108 uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; 109 110 const struct addrinfo* hints 111 = reinterpret_cast<const addrinfo*>(buffer + nodeSize + serviceSize); 112 113 struct addrinfo* ai; 114 status_t result = getaddrinfo(node, service, hints, &ai); 115 if (result != B_OK) 116 return write_port(gReplyPort, MsgError, &result, sizeof(result)); 117 118 uint32 totalSize; 119 char* reply; 120 result = Serialize(&reply, &totalSize, ai); 121 freeaddrinfo(ai); 122 if (result != B_OK) 123 return write_port(gReplyPort, MsgError, &result, sizeof(result)); 124 result = write_port(gReplyPort, MsgReply, reply, totalSize); 125 free(reply); 126 return result; 127 } 128 129 130 status_t 131 MainLoop() 132 { 133 do { 134 ssize_t size = port_buffer_size(gRequestPort); 135 if (size < B_OK) 136 return 0; 137 138 void* buffer = malloc(size); 139 if (buffer == NULL) 140 return B_NO_MEMORY; 141 MemoryDeleter _(buffer); 142 143 int32 code; 144 size = read_port(gRequestPort, &code, buffer, size); 145 if (size < B_OK) 146 return 0; 147 148 status_t result; 149 switch (code) { 150 case MsgGetAddrInfo: 151 result = GetAddrInfo(reinterpret_cast<char*>(buffer)); 152 break; 153 154 default: 155 result = B_BAD_VALUE; 156 write_port(gReplyPort, MsgError, &result, sizeof(result)); 157 result = B_OK; 158 } 159 160 if (result != B_OK) 161 return 0; 162 } while (true); 163 } 164 165 166 int 167 main(int argc, char** argv) 168 { 169 gRequestPort = find_port(kPortNameReq); 170 if (gRequestPort < B_OK) { 171 fprintf(stderr, "%s\n", strerror(gRequestPort)); 172 return gRequestPort; 173 } 174 175 gReplyPort = find_port(kPortNameRpl); 176 if (gReplyPort < B_OK) { 177 fprintf(stderr, "%s\n", strerror(gReplyPort)); 178 return gReplyPort; 179 } 180 181 return MainLoop(); 182 } 183 184