/* * Copyright 2012 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Paweł Dziepak, pdziepak@quarnos.org */ #include #include #include #include #include #include #include #include #include "Definitions.h" port_id gRequestPort; port_id gReplyPort; status_t Serialize(char** _reply, uint32* _totalSize, const struct addrinfo* ai) { uint32 addrsSize = ai == NULL ? 0 : sizeof(addrinfo); uint32 namesSize = 0; uint32 socksSize = 0; const struct addrinfo* current = ai; while (current != NULL) { 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; } uint32 totalSize = addrsSize + namesSize + socksSize; char* reply = reinterpret_cast(malloc(totalSize)); if (reply == NULL) return B_NO_MEMORY; uint32 addrPos = 0; uint32 namePos = addrsSize; uint32 sockPos = addrsSize + namesSize; struct addrinfo temp; current = ai; while (current != NULL) { memcpy(&temp, current, sizeof(addrinfo)); if (current->ai_canonname != NULL) { strcpy(reply + namePos, current->ai_canonname); uint32 nSize = strlen(current->ai_canonname) + 1; temp.ai_canonname = reinterpret_cast(namePos); namePos += nSize; } if (current->ai_addr != NULL) { if (current->ai_family == AF_INET) { memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in)); temp.ai_addr = reinterpret_cast(sockPos); sockPos += sizeof(sockaddr_in); } else { memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in6)); temp.ai_addr = reinterpret_cast(sockPos); sockPos += sizeof(sockaddr_in6); } } addrinfo* next = current->ai_next; if (next != NULL) temp.ai_next = reinterpret_cast(addrPos) + 1; else temp.ai_next = NULL; memcpy(reply + addrPos, &temp, sizeof(addrinfo)); addrPos += sizeof(addrinfo); current = next; } *_reply = reply; *_totalSize = totalSize; return B_OK; } status_t GetAddrInfo(const char* buffer) { 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(buffer + nodeSize + serviceSize); struct addrinfo* ai; status_t result = getaddrinfo(node, service, hints, &ai); if (result != B_OK) return write_port(gReplyPort, MsgError, &result, sizeof(result)); uint32 totalSize; char* reply; result = Serialize(&reply, &totalSize, ai); freeaddrinfo(ai); if (result != B_OK) return write_port(gReplyPort, MsgError, &result, sizeof(result)); result = write_port(gReplyPort, MsgReply, reply, totalSize); free(reply); return result; } status_t MainLoop() { do { 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; size = read_port(gRequestPort, &code, buffer, size); if (size < B_OK) return 0; status_t result; switch (code) { case MsgGetAddrInfo: result = GetAddrInfo(reinterpret_cast(buffer)); break; default: result = B_BAD_VALUE; write_port(gReplyPort, MsgError, &result, sizeof(result)); result = B_OK; } if (result != B_OK) return 0; } while (true); } int main(int argc, char** argv) { gRequestPort = find_port(kPortNameReq); if (gRequestPort < B_OK) { fprintf(stderr, "%s\n", strerror(gRequestPort)); return gRequestPort; } gReplyPort = find_port(kPortNameRpl); if (gReplyPort < B_OK) { fprintf(stderr, "%s\n", strerror(gReplyPort)); return gReplyPort; } return MainLoop(); }