Socket.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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/Debug.h>
  8. #include <LibCore/Notifier.h>
  9. #include <LibCore/Socket.h>
  10. #include <arpa/inet.h>
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <netdb.h>
  14. #include <netinet/in.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <sys/socket.h>
  18. #include <unistd.h>
  19. namespace Core {
  20. Socket::Socket(Type type, Object* parent)
  21. : IODevice(parent)
  22. , m_type(type)
  23. {
  24. register_property(
  25. "source_address", [this] { return m_source_address.to_string(); },
  26. [](auto&) { return false; });
  27. register_property(
  28. "destination_address", [this] { return m_destination_address.to_string(); },
  29. [](auto&) { return false; });
  30. register_property(
  31. "source_port", [this] { return m_source_port; },
  32. [](auto&) { return false; });
  33. register_property(
  34. "destination_port", [this] { return m_destination_port; },
  35. [](auto&) { return false; });
  36. register_property(
  37. "connected", [this] { return m_connected; },
  38. [](auto&) { return false; });
  39. }
  40. Socket::~Socket()
  41. {
  42. close();
  43. }
  44. bool Socket::connect(const String& hostname, int port)
  45. {
  46. auto* hostent = gethostbyname(hostname.characters());
  47. if (!hostent) {
  48. dbgln("Socket::connect: Unable to resolve '{}'", hostname);
  49. return false;
  50. }
  51. IPv4Address host_address((const u8*)hostent->h_addr_list[0]);
  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. dbgln_if(CSOCKET_DEBUG, "{} connected!", *this);
  102. if (!m_connected) {
  103. m_connected = true;
  104. ensure_read_notifier();
  105. if (m_notifier) {
  106. m_notifier->remove_from_parent();
  107. m_notifier = nullptr;
  108. }
  109. if (on_connected)
  110. on_connected();
  111. }
  112. };
  113. int rc = ::connect(fd(), addr, addrlen);
  114. if (rc < 0) {
  115. if (errno == EINPROGRESS) {
  116. dbgln_if(CSOCKET_DEBUG, "{} connection in progress (EINPROGRESS)", *this);
  117. m_notifier = Notifier::construct(fd(), Notifier::Event::Write, this);
  118. m_notifier->on_ready_to_write = move(connected);
  119. return true;
  120. }
  121. int saved_errno = errno;
  122. warnln("Core::Socket: Failed to connect() to {}: {}", destination_address().to_string(), strerror(saved_errno));
  123. errno = saved_errno;
  124. return false;
  125. }
  126. dbgln_if(CSOCKET_DEBUG, "{} connected ok!", *this);
  127. connected();
  128. return true;
  129. }
  130. ByteBuffer Socket::receive(int max_size)
  131. {
  132. auto buffer = read(max_size);
  133. if (eof())
  134. m_connected = false;
  135. return buffer;
  136. }
  137. bool Socket::send(ReadonlyBytes data)
  138. {
  139. auto remaining_bytes = data.size();
  140. while (remaining_bytes > 0) {
  141. ssize_t nsent = ::send(fd(), data.data() + (data.size() - remaining_bytes), remaining_bytes, 0);
  142. if (nsent < 0) {
  143. set_error(errno);
  144. return false;
  145. }
  146. remaining_bytes -= nsent;
  147. }
  148. return true;
  149. }
  150. void Socket::did_update_fd(int fd)
  151. {
  152. if (fd < 0) {
  153. if (m_read_notifier) {
  154. m_read_notifier->remove_from_parent();
  155. m_read_notifier = nullptr;
  156. }
  157. if (m_notifier) {
  158. m_notifier->remove_from_parent();
  159. m_notifier = nullptr;
  160. }
  161. return;
  162. }
  163. if (m_connected) {
  164. ensure_read_notifier();
  165. } else {
  166. // I don't think it would be right if we updated the fd while not connected *but* while having a notifier..
  167. VERIFY(!m_read_notifier);
  168. }
  169. }
  170. void Socket::ensure_read_notifier()
  171. {
  172. VERIFY(m_connected);
  173. m_read_notifier = Notifier::construct(fd(), Notifier::Event::Read, this);
  174. m_read_notifier->on_ready_to_read = [this] {
  175. if (!can_read())
  176. return;
  177. if (on_ready_to_read)
  178. on_ready_to_read();
  179. };
  180. }
  181. }