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