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