1/*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "UnixAddress.h"
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include <util/StringHash.h>
13
14#include <net_datalink.h>
15#include <NetUtilities.h>
16
17#include "unix.h"
18
19
20static const sockaddr_un kEmptyAddress = {
21	4,				// sun_len
22	AF_UNIX,		// sun_family
23	{ '\0', '\0' }	// sun_path
24};
25
26
27char*
28UnixAddress::ToString(char *buffer, size_t bufferSize) const
29{
30	if (!IsValid())
31		strlcpy(buffer, "<empty>", bufferSize);
32	else if (IsInternalAddress())
33		snprintf(buffer, bufferSize, "<%05" B_PRIx32 ">", fInternalID);
34	else {
35		snprintf(buffer, bufferSize, "<%" B_PRIdDEV ", %" B_PRIdINO ">",
36			fVolumeID, fNodeID);
37	}
38
39	return buffer;
40}
41
42
43// #pragma mark -
44
45
46static status_t
47unix_copy_address(const sockaddr *from, sockaddr **to, bool replaceWithZeros,
48	const sockaddr *mask)
49{
50	if (replaceWithZeros) {
51		sockaddr_un* newAddress = (sockaddr_un*)malloc(kEmptyAddress.sun_len);
52		if (newAddress == NULL)
53			return B_NO_MEMORY;
54
55		memcpy(newAddress, &kEmptyAddress, kEmptyAddress.sun_len);
56
57		*to = (sockaddr*)newAddress;
58		return B_OK;
59	} else {
60		if (from->sa_family != AF_UNIX)
61			return B_MISMATCHED_VALUES;
62
63		*to = (sockaddr*)malloc(from->sa_len);
64		if (*to == NULL)
65			return B_NO_MEMORY;
66
67		memcpy(*to, from, from->sa_len);
68
69		return B_OK;
70	}
71}
72
73
74static bool
75unix_equal_addresses(const sockaddr *a, const sockaddr *b)
76{
77	// NOTE: We compare syntactically only. The real check would involve
78	// looking up the node, if for FS addresses.
79	if (a->sa_len != b->sa_len)
80		return false;
81
82	return memcmp(a, b, a->sa_len) == 0;
83}
84
85
86static bool
87unix_equal_ports(const sockaddr *a, const sockaddr *b)
88{
89	// no ports
90	return true;
91}
92
93
94static bool
95unix_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b)
96{
97	return unix_equal_addresses(a, b);
98}
99
100
101static bool
102unix_equal_masked_addresses(const sockaddr *a, const sockaddr *b,
103	const sockaddr *mask)
104{
105	// no masks
106	return unix_equal_addresses(a, b);
107}
108
109
110static bool
111unix_is_empty_address(const sockaddr *address, bool checkPort)
112{
113	return address == NULL || address->sa_len == 0
114		|| address->sa_family == AF_UNSPEC
115		|| (address->sa_len >= kEmptyAddress.sun_len
116			&& memcmp(address, &kEmptyAddress, kEmptyAddress.sun_len) == 0);
117}
118
119
120static bool
121unix_is_same_family(const sockaddr *address)
122{
123	if (address == NULL)
124		return false;
125
126	return address->sa_family == AF_UNIX;
127}
128
129
130static int32
131unix_first_mask_bit(const sockaddr *mask)
132{
133	return 0;
134}
135
136
137static bool
138unix_check_mask(const sockaddr *address)
139{
140	return false;
141}
142
143
144static status_t
145unix_print_address_buffer(const sockaddr *_address, char *buffer,
146	size_t bufferSize, bool printPort)
147{
148	if (!buffer)
149		return B_BAD_VALUE;
150
151	sockaddr_un* address = (sockaddr_un*)_address;
152
153	if (address == NULL)
154		strlcpy(buffer, "<none>", bufferSize);
155	else if (address->sun_path[0] != '\0')
156		strlcpy(buffer, address->sun_path, bufferSize);
157	else if (address->sun_path[1] != '\0')
158		snprintf(buffer, bufferSize, "<%.5s>", address->sun_path + 1);
159	else
160		strlcpy(buffer, "<empty>", bufferSize);
161
162	return B_OK;
163}
164
165
166static status_t
167unix_print_address(const sockaddr *address, char **_buffer, bool printPort)
168{
169	char buffer[128];
170	status_t error = unix_print_address_buffer(address, buffer, sizeof(buffer),
171		printPort);
172	if (error != B_OK)
173		return error;
174
175	*_buffer = strdup(buffer);
176	return *_buffer != NULL ? B_OK : B_NO_MEMORY;
177}
178
179
180static uint16
181unix_get_port(const sockaddr *address)
182{
183	return 0;
184}
185
186
187static status_t
188unix_set_port(sockaddr *address, uint16 port)
189{
190	return B_BAD_VALUE;
191}
192
193
194static status_t
195unix_set_to(sockaddr *address, const sockaddr *from)
196{
197	if (address == NULL || from == NULL)
198		return B_BAD_VALUE;
199
200	if (from->sa_family != AF_UNIX)
201		return B_MISMATCHED_VALUES;
202
203	memcpy(address, from, from->sa_len);
204	return B_OK;
205}
206
207
208static status_t
209unix_set_to_empty_address(sockaddr *address)
210{
211	return unix_set_to(address, (sockaddr*)&kEmptyAddress);
212}
213
214
215static status_t
216unix_mask_address(const sockaddr *address, const sockaddr *mask,
217	sockaddr *result)
218{
219	// no masks
220	return unix_set_to(result, address);
221}
222
223
224static status_t
225unix_set_to_defaults(sockaddr *defaultMask, sockaddr *defaultBroadcast,
226	const sockaddr *address, const sockaddr *netmask)
227{
228	if (address == NULL)
229		return B_BAD_VALUE;
230
231	status_t error = B_OK;
232	if (defaultMask != NULL)
233		error = unix_set_to_empty_address(defaultMask);
234	if (error == B_OK && defaultBroadcast != NULL)
235		error = unix_set_to_empty_address(defaultBroadcast);
236
237	return error;
238}
239
240
241static status_t
242unix_update_to(sockaddr *address, const sockaddr *from)
243{
244	if (address == NULL || from == NULL)
245		return B_BAD_VALUE;
246
247	if (unix_is_empty_address(from, false))
248		return B_OK;
249
250	return unix_set_to(address, from);
251}
252
253
254static uint32
255unix_hash_address(const sockaddr* _address, bool includePort)
256{
257	sockaddr_un* address = (sockaddr_un*)_address;
258	if (address == NULL)
259		return 0;
260
261	if (address->sun_path[0] == '\0') {
262		char buffer[6];
263		strlcpy(buffer, address->sun_path + 1, 6);
264		return hash_hash_string(buffer);
265	}
266
267	return hash_hash_string(address->sun_path);
268}
269
270
271static uint32
272unix_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress)
273{
274	return unix_hash_address(ourAddress, false) * 17
275		+ unix_hash_address(peerAddress, false);
276}
277
278
279static status_t
280unix_checksum_address(Checksum *checksum, const sockaddr *_address)
281{
282	if (checksum == NULL || _address == NULL)
283		return B_BAD_VALUE;
284
285	sockaddr_un* address = (sockaddr_un*)_address;
286	int len = (char*)address + address->sun_len - address->sun_path;
287	for (int i = 0; i < len; i++)
288		(*checksum) << (uint8)address->sun_path[i];
289
290	return B_OK;
291}
292
293
294net_address_module_info gAddressModule = {
295	{
296		NULL,
297		0,
298		NULL
299	},
300	NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS,
301	unix_copy_address,
302	unix_mask_address,
303	unix_equal_addresses,
304	unix_equal_ports,
305	unix_equal_addresses_and_ports,
306	unix_equal_masked_addresses,
307	unix_is_empty_address,
308	unix_is_same_family,
309	unix_first_mask_bit,
310	unix_check_mask,
311	unix_print_address,
312	unix_print_address_buffer,
313	unix_get_port,
314	unix_set_port,
315	unix_set_to,
316	unix_set_to_empty_address,
317	unix_set_to_defaults,
318	unix_update_to,
319	unix_hash_address,
320	unix_hash_address_pair,
321	unix_checksum_address,
322	NULL	// get_loopback_address
323};
324