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