1/*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <stdio.h>
8#include <sys/un.h>
9
10#include <new>
11
12#include <AutoDeleter.h>
13
14#include <fs/fd.h>
15#include <lock.h>
16#include <util/AutoLock.h>
17#include <vfs.h>
18
19#include <net_buffer.h>
20#include <net_protocol.h>
21#include <net_socket.h>
22#include <net_stack.h>
23
24#include "unix.h"
25#include "UnixAddressManager.h"
26#include "UnixEndpoint.h"
27
28
29#define UNIX_MODULE_DEBUG_LEVEL	0
30#define UNIX_DEBUG_LEVEL		UNIX_MODULE_DEBUG_LEVEL
31#include "UnixDebug.h"
32
33
34extern net_protocol_module_info gUnixModule;
35	// extern only for forwarding
36
37net_stack_module_info *gStackModule;
38net_socket_module_info *gSocketModule;
39net_buffer_module_info *gBufferModule;
40UnixAddressManager gAddressManager;
41
42static struct net_domain *sDomain;
43
44
45void
46destroy_scm_rights_descriptors(const ancillary_data_header* header,
47	void* data)
48{
49	int count = header->len / sizeof(file_descriptor*);
50	file_descriptor** descriptors = (file_descriptor**)data;
51	io_context* ioContext = get_current_io_context(!gStackModule->is_syscall());
52
53	for (int i = 0; i < count; i++) {
54		if (descriptors[i] != NULL) {
55			close_fd(ioContext, descriptors[i]);
56			put_fd(descriptors[i]);
57		}
58	}
59}
60
61
62// #pragma mark -
63
64
65net_protocol *
66unix_init_protocol(net_socket *socket)
67{
68	TRACE("[%" B_PRId32 "] unix_init_protocol(%p)\n", find_thread(NULL),
69		socket);
70
71	UnixEndpoint* endpoint;
72	status_t error = UnixEndpoint::Create(socket, &endpoint);
73	if (error != B_OK)
74		return NULL;
75
76	error = endpoint->Init();
77	if (error != B_OK) {
78		delete endpoint;
79		return NULL;
80	}
81
82	return endpoint;
83}
84
85
86status_t
87unix_uninit_protocol(net_protocol *_protocol)
88{
89	TRACE("[%" B_PRId32 "] unix_uninit_protocol(%p)\n", find_thread(NULL),
90		_protocol);
91	((UnixEndpoint*)_protocol)->Uninit();
92	return B_OK;
93}
94
95
96status_t
97unix_open(net_protocol *_protocol)
98{
99	return ((UnixEndpoint*)_protocol)->Open();
100}
101
102
103status_t
104unix_close(net_protocol *_protocol)
105{
106	return ((UnixEndpoint*)_protocol)->Close();
107}
108
109
110status_t
111unix_free(net_protocol *_protocol)
112{
113	return ((UnixEndpoint*)_protocol)->Free();
114}
115
116
117status_t
118unix_connect(net_protocol *_protocol, const struct sockaddr *address)
119{
120	return ((UnixEndpoint*)_protocol)->Connect(address);
121}
122
123
124status_t
125unix_accept(net_protocol *_protocol, struct net_socket **_acceptedSocket)
126{
127	return ((UnixEndpoint*)_protocol)->Accept(_acceptedSocket);
128}
129
130
131status_t
132unix_control(net_protocol *protocol, int level, int option, void *value,
133	size_t *_length)
134{
135	return B_BAD_VALUE;
136}
137
138
139status_t
140unix_getsockopt(net_protocol *protocol, int level, int option, void *value,
141	int *_length)
142{
143	UnixEndpoint* endpoint = (UnixEndpoint*)protocol;
144
145	if (level == SOL_SOCKET && option == SO_PEERCRED) {
146		if (*_length < (int)sizeof(ucred))
147			return B_BAD_VALUE;
148
149		*_length = sizeof(ucred);
150
151		return endpoint->GetPeerCredentials((ucred*)value);
152	}
153
154	return gSocketModule->get_option(protocol->socket, level, option, value,
155		_length);
156}
157
158
159status_t
160unix_setsockopt(net_protocol *protocol, int level, int option,
161	const void *_value, int length)
162{
163	UnixEndpoint* endpoint = (UnixEndpoint*)protocol;
164
165	if (level == SOL_SOCKET) {
166		if (option == SO_RCVBUF) {
167			if (length != sizeof(int))
168				return B_BAD_VALUE;
169
170			status_t error = endpoint->SetReceiveBufferSize(*(int*)_value);
171			if (error != B_OK)
172				return error;
173		} else if (option == SO_SNDBUF) {
174			// We don't have a receive buffer, so silently ignore this one.
175		}
176	}
177
178	return gSocketModule->set_option(protocol->socket, level, option,
179		_value, length);
180}
181
182
183status_t
184unix_bind(net_protocol *_protocol, const struct sockaddr *_address)
185{
186	return ((UnixEndpoint*)_protocol)->Bind(_address);
187}
188
189
190status_t
191unix_unbind(net_protocol *_protocol, struct sockaddr *_address)
192{
193	return ((UnixEndpoint*)_protocol)->Unbind();
194}
195
196
197status_t
198unix_listen(net_protocol *_protocol, int count)
199{
200	return ((UnixEndpoint*)_protocol)->Listen(count);
201}
202
203
204status_t
205unix_shutdown(net_protocol *_protocol, int direction)
206{
207	return ((UnixEndpoint*)_protocol)->Shutdown(direction);
208}
209
210
211status_t
212unix_send_routed_data(net_protocol *_protocol, struct net_route *route,
213	net_buffer *buffer)
214{
215	return B_ERROR;
216}
217
218
219status_t
220unix_send_data(net_protocol *_protocol, net_buffer *buffer)
221{
222	return B_ERROR;
223}
224
225
226ssize_t
227unix_send_avail(net_protocol *_protocol)
228{
229	return ((UnixEndpoint*)_protocol)->Sendable();
230}
231
232
233status_t
234unix_read_data(net_protocol *_protocol, size_t numBytes, uint32 flags,
235	net_buffer **_buffer)
236{
237	return B_ERROR;
238}
239
240
241ssize_t
242unix_read_avail(net_protocol *_protocol)
243{
244	return ((UnixEndpoint*)_protocol)->Receivable();
245}
246
247
248struct net_domain *
249unix_get_domain(net_protocol *protocol)
250{
251	return sDomain;
252}
253
254
255size_t
256unix_get_mtu(net_protocol *protocol, const struct sockaddr *address)
257{
258	return UNIX_MAX_TRANSFER_UNIT;
259}
260
261
262status_t
263unix_receive_data(net_buffer *buffer)
264{
265	return B_ERROR;
266}
267
268
269status_t
270unix_deliver_data(net_protocol *_protocol, net_buffer *buffer)
271{
272	return B_ERROR;
273}
274
275
276status_t
277unix_error_received(net_error error, net_buffer *data)
278{
279	return B_ERROR;
280}
281
282
283status_t
284unix_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
285	net_error_data *errorData)
286{
287	return B_ERROR;
288}
289
290
291status_t
292unix_add_ancillary_data(net_protocol *self, ancillary_data_container *container,
293	const cmsghdr *header)
294{
295	TRACE("[%" B_PRId32 "] unix_add_ancillary_data(%p, %p, %p (level: %d, type: %d, "
296		"len: %" B_PRId32 "))\n", find_thread(NULL), self, container, header,
297		header->cmsg_level, header->cmsg_type, header->cmsg_len);
298
299	// we support only SCM_RIGHTS
300	if (header->cmsg_level != SOL_SOCKET || header->cmsg_type != SCM_RIGHTS)
301		return B_BAD_VALUE;
302
303	int* fds = (int*)CMSG_DATA(header);
304	int count = (header->cmsg_len - CMSG_ALIGN(sizeof(cmsghdr))) / sizeof(int);
305	if (count == 0)
306		return B_BAD_VALUE;
307
308	file_descriptor** descriptors = new(std::nothrow) file_descriptor*[count];
309	if (descriptors == NULL)
310		return ENOBUFS;
311	ArrayDeleter<file_descriptor*> _(descriptors);
312	memset(descriptors, 0, sizeof(file_descriptor*) * count);
313
314	// get the file descriptors
315	io_context* ioContext = get_current_io_context(!gStackModule->is_syscall());
316
317	status_t error = B_OK;
318	for (int i = 0; i < count; i++) {
319		descriptors[i] = get_open_fd(ioContext, fds[i]);
320		if (descriptors[i] == NULL) {
321			error = EBADF;
322			break;
323		}
324	}
325
326	// attach the ancillary data to the container
327	if (error == B_OK) {
328		ancillary_data_header header;
329		header.level = SOL_SOCKET;
330		header.type = SCM_RIGHTS;
331		header.len = count * sizeof(file_descriptor*);
332
333		TRACE("[%" B_PRId32 "] unix_add_ancillary_data(): adding %d FDs to "
334			"container\n", find_thread(NULL), count);
335
336		error = gStackModule->add_ancillary_data(container, &header,
337			descriptors, destroy_scm_rights_descriptors, NULL);
338	}
339
340	// cleanup on error
341	if (error != B_OK) {
342		for (int i = 0; i < count; i++) {
343			if (descriptors[i] != NULL) {
344				close_fd(ioContext, descriptors[i]);
345				put_fd(descriptors[i]);
346			}
347		}
348	}
349
350	return error;
351}
352
353
354ssize_t
355unix_process_ancillary_data(net_protocol *self,
356	const ancillary_data_header *header, const void *data, void *buffer,
357	size_t bufferSize)
358{
359	TRACE("[%" B_PRId32 "] unix_process_ancillary_data(%p, %p (level: %d, "
360		"type: %d, len: %lu), %p, %p, %lu)\n", find_thread(NULL), self, header,
361		header->level, header->type, header->len, data, buffer, bufferSize);
362
363	// we support only SCM_RIGHTS
364	if (header->level != SOL_SOCKET || header->type != SCM_RIGHTS)
365		return B_BAD_VALUE;
366
367	int count = header->len / sizeof(file_descriptor*);
368	file_descriptor** descriptors = (file_descriptor**)data;
369
370	// check if there's enough space in the buffer
371	size_t neededBufferSpace = CMSG_SPACE(sizeof(int) * count);
372	if (bufferSize < neededBufferSpace)
373		return B_BAD_VALUE;
374
375	// init header
376	cmsghdr* messageHeader = (cmsghdr*)buffer;
377	messageHeader->cmsg_level = header->level;
378	messageHeader->cmsg_type = header->type;
379	messageHeader->cmsg_len = CMSG_LEN(sizeof(int) * count);
380
381	// create FDs for the current process
382	int* fds = (int*)CMSG_DATA(messageHeader);
383	io_context* ioContext = get_current_io_context(!gStackModule->is_syscall());
384
385	status_t error = B_OK;
386	for (int i = 0; i < count; i++) {
387		// Get an additional reference which will go to the FD table index. The
388		// reference and open reference acquired in unix_add_ancillary_data()
389		// will be released when the container is destroyed.
390		inc_fd_ref_count(descriptors[i]);
391		fds[i] = new_fd(ioContext, descriptors[i]);
392
393		if (fds[i] < 0) {
394			error = fds[i];
395			put_fd(descriptors[i]);
396
397			// close FD indices
398			for (int k = i - 1; k >= 0; k--)
399				close_fd_index(ioContext, fds[k]);
400			break;
401		}
402	}
403
404	return error == B_OK ? neededBufferSpace : error;
405}
406
407
408ssize_t
409unix_send_data_no_buffer(net_protocol *_protocol, const iovec *vecs,
410	size_t vecCount, ancillary_data_container *ancillaryData,
411	const struct sockaddr *address, socklen_t addressLength, int flags)
412{
413	return ((UnixEndpoint*)_protocol)->Send(vecs, vecCount, ancillaryData,
414		address, addressLength, flags);
415}
416
417
418ssize_t
419unix_read_data_no_buffer(net_protocol *_protocol, const iovec *vecs,
420	size_t vecCount, ancillary_data_container **_ancillaryData,
421	struct sockaddr *_address, socklen_t *_addressLength, int flags)
422{
423	return ((UnixEndpoint*)_protocol)->Receive(vecs, vecCount, _ancillaryData,
424		_address, _addressLength, flags);
425}
426
427
428// #pragma mark -
429
430
431status_t
432init_unix()
433{
434	new(&gAddressManager) UnixAddressManager;
435	status_t error = gAddressManager.Init();
436	if (error != B_OK)
437		return error;
438
439	error = gStackModule->register_domain_protocols(AF_UNIX, SOCK_STREAM, 0,
440		"network/protocols/unix/v1", NULL);
441	if (error == B_OK) {
442		error = gStackModule->register_domain_protocols(AF_UNIX, SOCK_DGRAM, 0,
443			"network/protocols/unix/v1", NULL);
444	}
445
446	if (error != B_OK) {
447		gAddressManager.~UnixAddressManager();
448		return error;
449	}
450
451	error = gStackModule->register_domain(AF_UNIX, "unix", &gUnixModule,
452		&gAddressModule, &sDomain);
453	if (error != B_OK) {
454		gAddressManager.~UnixAddressManager();
455		return error;
456	}
457
458	return B_OK;
459}
460
461
462status_t
463uninit_unix()
464{
465	gStackModule->unregister_domain(sDomain);
466
467	gAddressManager.~UnixAddressManager();
468
469	return B_OK;
470}
471
472
473static status_t
474unix_std_ops(int32 op, ...)
475{
476	switch (op) {
477		case B_MODULE_INIT:
478			return init_unix();
479		case B_MODULE_UNINIT:
480			return uninit_unix();
481
482		default:
483			return B_ERROR;
484	}
485}
486
487
488net_protocol_module_info gUnixModule = {
489	{
490		"network/protocols/unix/v1",
491		0,
492		unix_std_ops
493	},
494	0,	// NET_PROTOCOL_ATOMIC_MESSAGES,
495
496	unix_init_protocol,
497	unix_uninit_protocol,
498	unix_open,
499	unix_close,
500	unix_free,
501	unix_connect,
502	unix_accept,
503	unix_control,
504	unix_getsockopt,
505	unix_setsockopt,
506	unix_bind,
507	unix_unbind,
508	unix_listen,
509	unix_shutdown,
510	unix_send_data,
511	unix_send_routed_data,
512	unix_send_avail,
513	unix_read_data,
514	unix_read_avail,
515	unix_get_domain,
516	unix_get_mtu,
517	unix_receive_data,
518	unix_deliver_data,
519	unix_error_received,
520	unix_error_reply,
521	unix_add_ancillary_data,
522	unix_process_ancillary_data,
523	NULL,
524	unix_send_data_no_buffer,
525	unix_read_data_no_buffer
526};
527
528module_dependency module_dependencies[] = {
529	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
530	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
531//	{NET_DATALINK_MODULE_NAME, (module_info **)&sDatalinkModule},
532	{NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
533	{}
534};
535
536module_info *modules[] = {
537	(module_info *)&gUnixModule,
538	NULL
539};
540