Socket.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/ByteBuffer.h>
  7. #include <AK/ByteReader.h>
  8. #include <AK/Debug.h>
  9. #include <LibCore/Notifier.h>
  10. #include <LibCore/Socket.h>
  11. #include <arpa/inet.h>
  12. #include <errno.h>
  13. #include <fcntl.h>
  14. #include <netdb.h>
  15. #include <netinet/in.h>
  16. #include <sys/socket.h>
  17. namespace Core {
  18. Socket::Socket(Type type, Object* parent)
  19. : IODevice(parent)
  20. , m_type(type)
  21. {
  22. register_property(
  23. "source_address", [this] { return m_source_address.to_string(); },
  24. [](auto&) { return false; });
  25. register_property(
  26. "destination_address", [this] { return m_destination_address.to_string(); },
  27. [](auto&) { return false; });
  28. register_property(
  29. "source_port", [this] { return m_source_port; },
  30. [](auto&) { return false; });
  31. register_property(
  32. "destination_port", [this] { return m_destination_port; },
  33. [](auto&) { return false; });
  34. register_property(
  35. "connected", [this] { return m_connected; },
  36. [](auto&) { return false; });
  37. }
  38. Socket::~Socket()
  39. {
  40. close();
  41. }
  42. bool Socket::connect(const String& hostname, int port)
  43. {
  44. auto* hostent = gethostbyname(hostname.characters());
  45. if (!hostent) {
  46. dbgln("Socket::connect: Unable to resolve '{}'", hostname);
  47. return false;
  48. }
  49. // On macOS, the pointer in the hostent structure is misaligned. Load it using ByteReader to avoid UB
  50. auto* host_addr = AK::ByteReader::load_pointer<u8 const>(reinterpret_cast<u8 const*>(&hostent->h_addr_list[0]));
  51. IPv4Address host_address(host_addr);
  52. dbgln_if(CSOCKET_DEBUG, "Socket::connect: Resolved '{}' to {}", hostname, host_address);
  53. return connect(host_address, port);
  54. }
  55. void Socket::set_blocking(bool blocking)
  56. {
  57. int flags = fcntl(fd(), F_GETFL, 0);
  58. VERIFY(flags >= 0);
  59. if (blocking)
  60. flags = fcntl(fd(), F_SETFL, flags & ~O_NONBLOCK);
  61. else
  62. flags = fcntl(fd(), F_SETFL, flags | O_NONBLOCK);
  63. VERIFY(flags == 0);
  64. }
  65. bool Socket::connect(const SocketAddress& address, int port)
  66. {
  67. VERIFY(!is_connected());
  68. VERIFY(address.type() == SocketAddress::Type::IPv4);
  69. dbgln_if(CSOCKET_DEBUG, "{} connecting to {}...", *this, address);
  70. VERIFY(port > 0 && port <= 65535);
  71. struct sockaddr_in addr;
  72. memset(&addr, 0, sizeof(addr));
  73. auto ipv4_address = address.ipv4_address();
  74. memcpy(&addr.sin_addr.s_addr, &ipv4_address, sizeof(IPv4Address));
  75. addr.sin_family = AF_INET;
  76. addr.sin_port = htons(port);
  77. m_destination_address = address;
  78. m_destination_port = port;
  79. return common_connect((struct sockaddr*)&addr, sizeof(addr));
  80. }
  81. bool Socket::connect(const SocketAddress& address)
  82. {
  83. VERIFY(!is_connected());
  84. VERIFY(address.type() == SocketAddress::Type::Local);
  85. dbgln_if(CSOCKET_DEBUG, "{} connecting to {}...", *this, address);
  86. sockaddr_un saddr;
  87. saddr.sun_family = AF_LOCAL;
  88. auto dest_address = address.to_string();
  89. bool fits = dest_address.copy_characters_to_buffer(saddr.sun_path, sizeof(saddr.sun_path));
  90. if (!fits) {
  91. warnln("Core::Socket: Failed to connect() to {}: Path is too long!", dest_address);
  92. errno = EINVAL;
  93. return false;
  94. }
  95. m_destination_address = address;
  96. return common_connect((const sockaddr*)&saddr, sizeof(saddr));
  97. }
  98. bool Socket::common_connect(const struct sockaddr* addr, socklen_t addrlen)
  99. {
  100. auto connected = [this] {
  101. int so_error;
  102. socklen_t so_error_len = sizeof(so_error);
  103. int rc = getsockopt(fd(), SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
  104. if (rc < 0) {
  105. dbgln_if(CSOCKET_DEBUG, "Failed to check the status of SO_ERROR");
  106. m_connected = false;
  107. if (on_error)
  108. on_error();
  109. }
  110. if (so_error == 0) {
  111. dbgln_if(CSOCKET_DEBUG, "{} connected!", *this);
  112. m_connected = true;
  113. ensure_read_notifier();
  114. if (on_connected)
  115. on_connected();
  116. } else {
  117. dbgln_if(CSOCKET_DEBUG, "Failed to connect to {}", *this);
  118. m_connected = false;
  119. if (on_error)
  120. on_error();
  121. }
  122. if (m_notifier) {
  123. m_notifier->remove_from_parent();
  124. m_notifier = nullptr;
  125. }
  126. };
  127. int rc = ::connect(fd(), addr, addrlen);
  128. if (rc < 0) {
  129. if (errno == EINPROGRESS) {
  130. dbgln_if(CSOCKET_DEBUG, "{} connection in progress (EINPROGRESS)", *this);
  131. m_notifier = Notifier::construct(fd(), Notifier::Event::Write, this);
  132. m_notifier->on_ready_to_write = move(connected);
  133. return true;
  134. }
  135. int saved_errno = errno;
  136. warnln("Core::Socket: Failed to connect() to {}: {}", destination_address().to_string(), strerror(saved_errno));
  137. errno = saved_errno;
  138. return false;
  139. }
  140. dbgln_if(CSOCKET_DEBUG, "{} connected ok!", *this);
  141. connected();
  142. return true;
  143. }
  144. ByteBuffer Socket::receive(int max_size)
  145. {
  146. auto buffer = read(max_size);
  147. if (eof())
  148. m_connected = false;
  149. return buffer;
  150. }
  151. bool Socket::send(ReadonlyBytes data)
  152. {
  153. auto remaining_bytes = data.size();
  154. while (remaining_bytes > 0) {
  155. ssize_t nsent = ::send(fd(), data.data() + (data.size() - remaining_bytes), remaining_bytes, 0);
  156. if (nsent < 0) {
  157. set_error(errno);
  158. return false;
  159. }
  160. remaining_bytes -= nsent;
  161. }
  162. return true;
  163. }
  164. void Socket::did_update_fd(int fd)
  165. {
  166. if (fd < 0) {
  167. if (m_read_notifier) {
  168. m_read_notifier->remove_from_parent();
  169. m_read_notifier = nullptr;
  170. }
  171. if (m_notifier) {
  172. m_notifier->remove_from_parent();
  173. m_notifier = nullptr;
  174. }
  175. return;
  176. }
  177. if (m_connected) {
  178. ensure_read_notifier();
  179. } else {
  180. // I don't think it would be right if we updated the fd while not connected *but* while having a notifier..
  181. VERIFY(!m_read_notifier);
  182. }
  183. }
  184. void Socket::ensure_read_notifier()
  185. {
  186. VERIFY(m_connected);
  187. m_read_notifier = Notifier::construct(fd(), Notifier::Event::Read, this);
  188. m_read_notifier->on_ready_to_read = [this] {
  189. if (!can_read())
  190. return;
  191. if (on_ready_to_read)
  192. on_ready_to_read();
  193. };
  194. }
  195. }