xref: /haiku/src/add-ons/kernel/network/dns_resolver/server/main.cpp (revision 410ed2fbba58819ac21e27d3676739728416761d)
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 	return write_port(gReplyPort, MsgReply, reply, totalSize);
125 }
126 
127 
128 status_t
129 MainLoop()
130 {
131 	do {
132 		ssize_t size = port_buffer_size(gRequestPort);
133 		if (size < B_OK)
134 			return 0;
135 
136 		void* buffer = malloc(size);
137 		if (buffer == NULL)
138 			return B_NO_MEMORY;
139 		MemoryDeleter _(buffer);
140 
141 		int32 code;
142 		size = read_port(gRequestPort, &code, buffer, size);
143 		if (size < B_OK)
144 			return 0;
145 
146 		status_t result;
147 		switch (code) {
148 			case MsgGetAddrInfo:
149 				result = GetAddrInfo(reinterpret_cast<char*>(buffer));
150 				break;
151 
152 			default:
153 				result = B_BAD_VALUE;
154 				write_port(gReplyPort, MsgError, &result, sizeof(result));
155 				result = B_OK;
156 		}
157 
158 		if (result != B_OK)
159 			return 0;
160 	} while (true);
161 }
162 
163 
164 int
165 main(int argc, char** argv)
166 {
167 	gRequestPort = find_port(kPortNameReq);
168 	if (gRequestPort < B_OK) {
169 		fprintf(stderr, "%s\n", strerror(gRequestPort));
170 		return gRequestPort;
171 	}
172 
173 	gReplyPort = find_port(kPortNameRpl);
174 	if (gReplyPort < B_OK) {
175 		fprintf(stderr, "%s\n", strerror(gReplyPort));
176 		return gReplyPort;
177 	}
178 
179 	return MainLoop();
180 }
181 
182