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