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