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
24port_id		gRequestPort;
25port_id		gReplyPort;
26
27
28status_t
29Serialize(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
101status_t
102GetAddrInfo(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
130status_t
131MainLoop()
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
166int
167main(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