Socket.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibCore/Socket.h>
  8. #include <LibCore/System.h>
  9. namespace Core {
  10. ErrorOr<int> Socket::create_fd(SocketDomain domain, SocketType type)
  11. {
  12. int socket_domain;
  13. switch (domain) {
  14. case SocketDomain::Inet:
  15. socket_domain = AF_INET;
  16. break;
  17. case SocketDomain::Local:
  18. socket_domain = AF_LOCAL;
  19. break;
  20. default:
  21. VERIFY_NOT_REACHED();
  22. }
  23. int socket_type;
  24. switch (type) {
  25. case SocketType::Stream:
  26. socket_type = SOCK_STREAM;
  27. break;
  28. case SocketType::Datagram:
  29. socket_type = SOCK_DGRAM;
  30. break;
  31. default:
  32. VERIFY_NOT_REACHED();
  33. }
  34. // Let's have a safe default of CLOEXEC. :^)
  35. #ifdef SOCK_CLOEXEC
  36. return System::socket(socket_domain, socket_type | SOCK_CLOEXEC, 0);
  37. #else
  38. auto fd = TRY(System::socket(socket_domain, socket_type, 0));
  39. TRY(System::fcntl(fd, F_SETFD, FD_CLOEXEC));
  40. return fd;
  41. #endif
  42. }
  43. ErrorOr<IPv4Address> Socket::resolve_host(ByteString const& host, SocketType type)
  44. {
  45. int socket_type;
  46. switch (type) {
  47. case SocketType::Stream:
  48. socket_type = SOCK_STREAM;
  49. break;
  50. case SocketType::Datagram:
  51. socket_type = SOCK_DGRAM;
  52. break;
  53. default:
  54. VERIFY_NOT_REACHED();
  55. }
  56. struct addrinfo hints = {};
  57. hints.ai_family = AF_UNSPEC;
  58. hints.ai_socktype = socket_type;
  59. hints.ai_flags = 0;
  60. hints.ai_protocol = 0;
  61. auto const results = TRY(Core::System::getaddrinfo(host.characters(), nullptr, hints));
  62. for (auto const& result : results.addresses()) {
  63. if (result.ai_family == AF_INET) {
  64. auto* socket_address = bit_cast<struct sockaddr_in*>(result.ai_addr);
  65. NetworkOrdered<u32> const network_ordered_address { socket_address->sin_addr.s_addr };
  66. return IPv4Address { network_ordered_address };
  67. }
  68. }
  69. return Error::from_string_literal("Could not resolve to IPv4 address");
  70. }
  71. ErrorOr<void> Socket::connect_local(int fd, ByteString const& path)
  72. {
  73. auto address = SocketAddress::local(path);
  74. auto maybe_sockaddr = address.to_sockaddr_un();
  75. if (!maybe_sockaddr.has_value()) {
  76. dbgln("Core::Socket::connect_local: Could not obtain a sockaddr_un");
  77. return Error::from_errno(EINVAL);
  78. }
  79. auto addr = maybe_sockaddr.release_value();
  80. return System::connect(fd, bit_cast<struct sockaddr*>(&addr), sizeof(addr));
  81. }
  82. ErrorOr<void> Socket::connect_inet(int fd, SocketAddress const& address)
  83. {
  84. auto addr = address.to_sockaddr_in();
  85. return System::connect(fd, bit_cast<struct sockaddr*>(&addr), sizeof(addr));
  86. }
  87. ErrorOr<Bytes> PosixSocketHelper::read(Bytes buffer, int flags)
  88. {
  89. if (!is_open()) {
  90. return Error::from_errno(ENOTCONN);
  91. }
  92. ssize_t nread = TRY(System::recv(m_fd, buffer.data(), buffer.size(), flags));
  93. m_last_read_was_eof = nread == 0;
  94. // If a socket read is EOF, then no more data can be read from it because
  95. // the protocol has disconnected. In this case, we can just disable the
  96. // notifier if we have one.
  97. if (m_last_read_was_eof && m_notifier)
  98. m_notifier->set_enabled(false);
  99. return buffer.trim(nread);
  100. }
  101. ErrorOr<size_t> PosixSocketHelper::write(ReadonlyBytes buffer, int flags)
  102. {
  103. if (!is_open()) {
  104. return Error::from_errno(ENOTCONN);
  105. }
  106. return TRY(System::send(m_fd, buffer.data(), buffer.size(), flags));
  107. }
  108. void PosixSocketHelper::close()
  109. {
  110. if (!is_open()) {
  111. return;
  112. }
  113. if (m_notifier)
  114. m_notifier->set_enabled(false);
  115. ErrorOr<void> result;
  116. do {
  117. result = System::close(m_fd);
  118. } while (result.is_error() && result.error().code() == EINTR);
  119. VERIFY(!result.is_error());
  120. m_fd = -1;
  121. }
  122. ErrorOr<bool> PosixSocketHelper::can_read_without_blocking(int timeout) const
  123. {
  124. struct pollfd the_fd = { .fd = m_fd, .events = POLLIN, .revents = 0 };
  125. ErrorOr<int> result { 0 };
  126. do {
  127. result = Core::System::poll({ &the_fd, 1 }, timeout);
  128. } while (result.is_error() && result.error().code() == EINTR);
  129. if (result.is_error())
  130. return result.release_error();
  131. return (the_fd.revents & POLLIN) > 0;
  132. }
  133. ErrorOr<void> PosixSocketHelper::set_blocking(bool enabled)
  134. {
  135. int value = enabled ? 0 : 1;
  136. return System::ioctl(m_fd, FIONBIO, &value);
  137. }
  138. ErrorOr<void> PosixSocketHelper::set_close_on_exec(bool enabled)
  139. {
  140. int flags = TRY(System::fcntl(m_fd, F_GETFD));
  141. if (enabled)
  142. flags |= FD_CLOEXEC;
  143. else
  144. flags &= ~FD_CLOEXEC;
  145. TRY(System::fcntl(m_fd, F_SETFD, flags));
  146. return {};
  147. }
  148. ErrorOr<void> PosixSocketHelper::set_receive_timeout(Duration timeout)
  149. {
  150. auto timeout_spec = timeout.to_timespec();
  151. return System::setsockopt(m_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout_spec, sizeof(timeout_spec));
  152. }
  153. void PosixSocketHelper::setup_notifier()
  154. {
  155. if (!m_notifier)
  156. m_notifier = Core::Notifier::construct(m_fd, Core::Notifier::Type::Read);
  157. }
  158. ErrorOr<NonnullOwnPtr<TCPSocket>> TCPSocket::connect(ByteString const& host, u16 port)
  159. {
  160. auto ip_address = TRY(resolve_host(host, SocketType::Stream));
  161. return connect(SocketAddress { ip_address, port });
  162. }
  163. ErrorOr<NonnullOwnPtr<TCPSocket>> TCPSocket::connect(SocketAddress const& address)
  164. {
  165. auto socket = TRY(adopt_nonnull_own_or_enomem(new (nothrow) TCPSocket()));
  166. auto fd = TRY(create_fd(SocketDomain::Inet, SocketType::Stream));
  167. socket->m_helper.set_fd(fd);
  168. TRY(connect_inet(fd, address));
  169. socket->setup_notifier();
  170. return socket;
  171. }
  172. ErrorOr<NonnullOwnPtr<TCPSocket>> TCPSocket::adopt_fd(int fd)
  173. {
  174. if (fd < 0) {
  175. return Error::from_errno(EBADF);
  176. }
  177. auto socket = TRY(adopt_nonnull_own_or_enomem(new (nothrow) TCPSocket()));
  178. socket->m_helper.set_fd(fd);
  179. socket->setup_notifier();
  180. return socket;
  181. }
  182. ErrorOr<size_t> PosixSocketHelper::pending_bytes() const
  183. {
  184. if (!is_open()) {
  185. return Error::from_errno(ENOTCONN);
  186. }
  187. int value;
  188. TRY(System::ioctl(m_fd, FIONREAD, &value));
  189. return static_cast<size_t>(value);
  190. }
  191. ErrorOr<NonnullOwnPtr<UDPSocket>> UDPSocket::connect(ByteString const& host, u16 port, Optional<Duration> timeout)
  192. {
  193. auto ip_address = TRY(resolve_host(host, SocketType::Datagram));
  194. return connect(SocketAddress { ip_address, port }, timeout);
  195. }
  196. ErrorOr<NonnullOwnPtr<UDPSocket>> UDPSocket::connect(SocketAddress const& address, Optional<Duration> timeout)
  197. {
  198. auto socket = TRY(adopt_nonnull_own_or_enomem(new (nothrow) UDPSocket()));
  199. auto fd = TRY(create_fd(SocketDomain::Inet, SocketType::Datagram));
  200. socket->m_helper.set_fd(fd);
  201. if (timeout.has_value()) {
  202. TRY(socket->m_helper.set_receive_timeout(timeout.value()));
  203. }
  204. TRY(connect_inet(fd, address));
  205. socket->setup_notifier();
  206. return socket;
  207. }
  208. ErrorOr<NonnullOwnPtr<LocalSocket>> LocalSocket::connect(ByteString const& path, PreventSIGPIPE prevent_sigpipe)
  209. {
  210. auto socket = TRY(adopt_nonnull_own_or_enomem(new (nothrow) LocalSocket(prevent_sigpipe)));
  211. auto fd = TRY(create_fd(SocketDomain::Local, SocketType::Stream));
  212. socket->m_helper.set_fd(fd);
  213. TRY(connect_local(fd, path));
  214. socket->setup_notifier();
  215. return socket;
  216. }
  217. ErrorOr<NonnullOwnPtr<LocalSocket>> LocalSocket::adopt_fd(int fd, PreventSIGPIPE prevent_sigpipe)
  218. {
  219. if (fd < 0) {
  220. return Error::from_errno(EBADF);
  221. }
  222. auto socket = TRY(adopt_nonnull_own_or_enomem(new (nothrow) LocalSocket(prevent_sigpipe)));
  223. socket->m_helper.set_fd(fd);
  224. socket->setup_notifier();
  225. return socket;
  226. }
  227. ErrorOr<int> LocalSocket::receive_fd(int flags)
  228. {
  229. #if defined(AK_OS_SERENITY)
  230. return Core::System::recvfd(m_helper.fd(), flags);
  231. #elif defined(AK_OS_LINUX) || defined(AK_OS_GNU_HURD) || defined(AK_OS_BSD_GENERIC) || defined(AK_OS_HAIKU)
  232. union {
  233. struct cmsghdr cmsghdr;
  234. char control[CMSG_SPACE(sizeof(int))];
  235. } cmsgu {};
  236. char c = 0;
  237. struct iovec iov {
  238. .iov_base = &c,
  239. .iov_len = 1,
  240. };
  241. struct msghdr msg = {};
  242. msg.msg_iov = &iov;
  243. msg.msg_iovlen = 1;
  244. msg.msg_control = cmsgu.control;
  245. msg.msg_controllen = sizeof(cmsgu.control);
  246. TRY(Core::System::recvmsg(m_helper.fd(), &msg, 0));
  247. struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
  248. if (!cmsg || cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
  249. return Error::from_string_literal("Malformed message when receiving file descriptor");
  250. VERIFY(cmsg->cmsg_level == SOL_SOCKET);
  251. VERIFY(cmsg->cmsg_type == SCM_RIGHTS);
  252. int fd = *((int*)CMSG_DATA(cmsg));
  253. if (flags & O_CLOEXEC) {
  254. auto fd_flags = TRY(Core::System::fcntl(fd, F_GETFD));
  255. TRY(Core::System::fcntl(fd, F_SETFD, fd_flags | FD_CLOEXEC));
  256. }
  257. return fd;
  258. #else
  259. (void)flags;
  260. return Error::from_string_literal("File descriptor passing not supported on this platform");
  261. #endif
  262. }
  263. ErrorOr<void> LocalSocket::send_fd(int fd)
  264. {
  265. #if defined(AK_OS_SERENITY)
  266. return Core::System::sendfd(m_helper.fd(), fd);
  267. #elif defined(AK_OS_LINUX) || defined(AK_OS_GNU_HURD) || defined(AK_OS_BSD_GENERIC) || defined(AK_OS_HAIKU)
  268. char c = 'F';
  269. struct iovec iov {
  270. .iov_base = &c,
  271. .iov_len = sizeof(c)
  272. };
  273. union {
  274. struct cmsghdr cmsghdr;
  275. char control[CMSG_SPACE(sizeof(int))];
  276. } cmsgu {};
  277. struct msghdr msg = {};
  278. msg.msg_iov = &iov;
  279. msg.msg_iovlen = 1;
  280. msg.msg_control = cmsgu.control;
  281. msg.msg_controllen = sizeof(cmsgu.control);
  282. struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
  283. cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  284. cmsg->cmsg_level = SOL_SOCKET;
  285. cmsg->cmsg_type = SCM_RIGHTS;
  286. *((int*)CMSG_DATA(cmsg)) = fd;
  287. TRY(Core::System::sendmsg(m_helper.fd(), &msg, 0));
  288. return {};
  289. #else
  290. (void)fd;
  291. return Error::from_string_literal("File descriptor passing not supported on this platform");
  292. #endif
  293. }
  294. ErrorOr<pid_t> LocalSocket::peer_pid() const
  295. {
  296. #ifdef AK_OS_MACOS
  297. pid_t pid;
  298. socklen_t pid_size = sizeof(pid);
  299. #elif defined(AK_OS_FREEBSD)
  300. struct xucred creds = {};
  301. socklen_t creds_size = sizeof(creds);
  302. #elif defined(AK_OS_OPENBSD)
  303. struct sockpeercred creds = {};
  304. socklen_t creds_size = sizeof(creds);
  305. #elif defined(AK_OS_NETBSD)
  306. struct sockcred creds = {};
  307. socklen_t creds_size = sizeof(creds);
  308. #elif defined(AK_OS_SOLARIS)
  309. ucred_t* creds = NULL;
  310. socklen_t creds_size = sizeof(creds);
  311. #elif defined(AK_OS_GNU_HURD)
  312. return Error::from_errno(ENOTSUP);
  313. #else
  314. struct ucred creds = {};
  315. socklen_t creds_size = sizeof(creds);
  316. #endif
  317. #ifdef AK_OS_MACOS
  318. TRY(System::getsockopt(m_helper.fd(), SOL_LOCAL, LOCAL_PEERPID, &pid, &pid_size));
  319. return pid;
  320. #elif defined(AK_OS_FREEBSD)
  321. TRY(System::getsockopt(m_helper.fd(), SOL_LOCAL, LOCAL_PEERCRED, &creds, &creds_size));
  322. return creds.cr_pid;
  323. #elif defined(AK_OS_NETBSD)
  324. TRY(System::getsockopt(m_helper.fd(), SOL_SOCKET, SCM_CREDS, &creds, &creds_size));
  325. return creds.sc_pid;
  326. #elif defined(AK_OS_SOLARIS)
  327. TRY(System::getsockopt(m_helper.fd(), SOL_SOCKET, SO_RECVUCRED, &creds, &creds_size));
  328. return ucred_getpid(creds);
  329. #elif !defined(AK_OS_GNU_HURD)
  330. TRY(System::getsockopt(m_helper.fd(), SOL_SOCKET, SO_PEERCRED, &creds, &creds_size));
  331. return creds.pid;
  332. #endif
  333. }
  334. ErrorOr<Bytes> LocalSocket::read_without_waiting(Bytes buffer)
  335. {
  336. return m_helper.read(buffer, MSG_DONTWAIT);
  337. }
  338. Optional<int> LocalSocket::fd() const
  339. {
  340. if (!is_open())
  341. return {};
  342. return m_helper.fd();
  343. }
  344. ErrorOr<int> LocalSocket::release_fd()
  345. {
  346. if (!is_open()) {
  347. return Error::from_errno(ENOTCONN);
  348. }
  349. auto fd = m_helper.fd();
  350. m_helper.set_fd(-1);
  351. return fd;
  352. }
  353. }