xref: /haiku/src/add-ons/kernel/network/protocols/unix/UnixEndpoint.cpp (revision 7eab6b486ebadb54ca3c306601f4b04dd92359fa)
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 
23 status_t
24 UnixEndpoint::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 
47 UnixEndpoint::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 
60 UnixEndpoint::~UnixEndpoint()
61 {
62 	TRACE("[%" B_PRId32 "] %p->UnixEndpoint::UnixEndpoint()\n",
63 		find_thread(NULL), this);
64 
65 	mutex_destroy(&fLock);
66 }
67 
68 
69 status_t
70 UnixEndpoint::_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 
130 status_t
131 UnixEndpoint::_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 
143 status_t
144 UnixEndpoint::_Bind(int32 internalID)
145 {
146 	fAddress.SetTo(internalID);
147 	RETURN_ERROR(B_OK);
148 }
149 
150 
151 status_t
152 UnixEndpoint::_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