xref: /haiku/src/add-ons/kernel/network/dns_resolver/server/main.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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