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