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
Create(net_socket * socket,UnixEndpoint ** _endpoint)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
UnixEndpoint(net_socket * socket)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
~UnixEndpoint()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
_Bind(const struct sockaddr_un * address)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
_Bind(struct vnode * vnode)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
_Bind(int32 internalID)144 UnixEndpoint::_Bind(int32 internalID)
145 {
146 fAddress.SetTo(internalID);
147 RETURN_ERROR(B_OK);
148 }
149
150
151 status_t
_Unbind()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