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