1/*
2 * Copyright 2023, Trung Nguyen, trungnt282910@gmail.com.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <stdio.h>
8
9#include <new>
10
11#include "UnixEndpoint.h"
12
13#include "UnixAddressManager.h"
14#include "UnixDatagramEndpoint.h"
15#include "UnixStreamEndpoint.h"
16
17
18#define UNIX_ENDPOINT_DEBUG_LEVEL	1
19#define UNIX_DEBUG_LEVEL    		UNIX_ENDPOINT_DEBUG_LEVEL
20#include "UnixDebug.h"
21
22
23status_t
24UnixEndpoint::Create(net_socket* socket, UnixEndpoint** _endpoint)
25{
26	TRACE("[%" B_PRId32 "] UnixEndpoint::Create(%p, %p)\n", find_thread(NULL),
27		socket, _endpoint);
28
29	if (socket == NULL || _endpoint == NULL)
30		return B_BAD_ADDRESS;
31
32	switch (socket->type) {
33		case SOCK_STREAM:
34			*_endpoint = new(std::nothrow) UnixStreamEndpoint(socket);
35			break;
36		case SOCK_DGRAM:
37			*_endpoint = new(std::nothrow) UnixDatagramEndpoint(socket);
38			break;
39		default:
40			return EPROTOTYPE;
41	}
42
43	return *_endpoint == NULL ? B_NO_MEMORY : B_OK;
44}
45
46
47UnixEndpoint::UnixEndpoint(net_socket* socket)
48	:
49	ProtocolSocket(socket),
50	fAddress(),
51	fAddressHashLink()
52{
53	TRACE("[%" B_PRId32 "] %p->UnixEndpoint::UnixEndpoint()\n",
54		find_thread(NULL), this);
55
56	mutex_init(&fLock, "unix endpoint");
57}
58
59
60UnixEndpoint::~UnixEndpoint()
61{
62	TRACE("[%" B_PRId32 "] %p->UnixEndpoint::UnixEndpoint()\n",
63		find_thread(NULL), this);
64
65	mutex_destroy(&fLock);
66}
67
68
69status_t
70UnixEndpoint::_Bind(const struct sockaddr_un* address)
71{
72	TRACE("[%" B_PRId32 "] %p->UnixEndpoint::_Bind(\"%s\")\n",
73		find_thread(NULL), this,
74		ConstSocketAddress(&gAddressModule, (struct sockaddr*)address).AsString().Data());
75
76	if (address->sun_path[0] == '\0') {
77		UnixAddressManagerLocker addressLocker(gAddressManager);
78
79		// internal address space (or empty address)
80		int32 internalID;
81		if (UnixAddress::IsEmptyAddress(*address))
82			internalID = gAddressManager.NextUnusedInternalID();
83		else
84			internalID = UnixAddress::InternalID(*address);
85		if (internalID < 0)
86			RETURN_ERROR(internalID);
87
88		status_t error = _Bind(internalID);
89		if (error != B_OK)
90			RETURN_ERROR(error);
91
92		sockaddr_un* outAddress = (sockaddr_un*)&socket->address;
93		outAddress->sun_path[0] = '\0';
94		sprintf(outAddress->sun_path + 1, "%05" B_PRIx32, internalID);
95		outAddress->sun_len = INTERNAL_UNIX_ADDRESS_LEN;
96			// null-byte + 5 hex digits
97
98		gAddressManager.Add(this);
99	} else {
100		// FS address space
101		size_t pathLen = strnlen(address->sun_path, sizeof(address->sun_path));
102		if (pathLen == 0 || pathLen == sizeof(address->sun_path))
103			RETURN_ERROR(B_BAD_VALUE);
104
105		struct vnode* vnode;
106		status_t error = vfs_create_special_node(address->sun_path,
107			NULL, S_IFSOCK | 0644, 0, !gStackModule->is_syscall(), NULL,
108			&vnode);
109		if (error != B_OK)
110			RETURN_ERROR(error == B_FILE_EXISTS ? EADDRINUSE : error);
111
112		error = _Bind(vnode);
113		if (error != B_OK) {
114			vfs_put_vnode(vnode);
115			RETURN_ERROR(error);
116		}
117
118		size_t addressLen = address->sun_path + pathLen + 1 - (char*)address;
119		memcpy(&socket->address, address, addressLen);
120		socket->address.ss_len = addressLen;
121
122		UnixAddressManagerLocker addressLocker(gAddressManager);
123		gAddressManager.Add(this);
124	}
125
126	RETURN_ERROR(B_OK);
127}
128
129
130status_t
131UnixEndpoint::_Bind(struct vnode* vnode)
132{
133	struct stat st;
134	status_t error = vfs_stat_vnode(vnode, &st);
135	if (error != B_OK)
136		RETURN_ERROR(error);
137
138	fAddress.SetTo(st.st_dev, st.st_ino, vnode);
139	RETURN_ERROR(B_OK);
140}
141
142
143status_t
144UnixEndpoint::_Bind(int32 internalID)
145{
146	fAddress.SetTo(internalID);
147	RETURN_ERROR(B_OK);
148}
149
150
151status_t
152UnixEndpoint::_Unbind()
153{
154	UnixAddressManagerLocker addressLocker(gAddressManager);
155	gAddressManager.Remove(this);
156	if (struct vnode* vnode = fAddress.Vnode())
157		vfs_put_vnode(vnode);
158
159	fAddress.Unset();
160	RETURN_ERROR(B_OK);
161}
162