PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/debugserver/source/RNBSocket.cpp

https://gitlab.com/jorjpimm/lldb
C++ | 421 lines | 322 code | 63 blank | 36 comment | 83 complexity | 39ec37ca7cb86b993d04cb06452c7c11 MD5 | raw file
  1. //===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // Created by Greg Clayton on 12/12/07.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "RNBSocket.h"
  14. #include <arpa/inet.h>
  15. #include <errno.h>
  16. #include <fcntl.h>
  17. #include <netdb.h>
  18. #include <netinet/in.h>
  19. #include <netinet/tcp.h>
  20. #include <termios.h>
  21. #include "DNBLog.h"
  22. #include "DNBError.h"
  23. #ifdef WITH_LOCKDOWN
  24. #include "lockdown.h"
  25. #endif
  26. /* Once we have a RNBSocket object with a port # specified,
  27. this function is called to wait for an incoming connection.
  28. This function blocks while waiting for that connection. */
  29. bool
  30. ResolveIPV4HostName (const char *hostname, in_addr_t &addr)
  31. {
  32. if (hostname == NULL ||
  33. hostname[0] == '\0' ||
  34. strcmp(hostname, "localhost") == 0 ||
  35. strcmp(hostname, "127.0.0.1") == 0)
  36. {
  37. addr = htonl (INADDR_LOOPBACK);
  38. return true;
  39. }
  40. else if (strcmp(hostname, "*") == 0)
  41. {
  42. addr = htonl (INADDR_ANY);
  43. return true;
  44. }
  45. else
  46. {
  47. // See if an IP address was specified as numbers
  48. int inet_pton_result = ::inet_pton (AF_INET, hostname, &addr);
  49. if (inet_pton_result == 1)
  50. return true;
  51. struct hostent *host_entry = gethostbyname (hostname);
  52. if (host_entry)
  53. {
  54. std::string ip_str (::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list));
  55. inet_pton_result = ::inet_pton (AF_INET, ip_str.c_str(), &addr);
  56. if (inet_pton_result == 1)
  57. return true;
  58. }
  59. }
  60. return false;
  61. }
  62. rnb_err_t
  63. RNBSocket::Listen (const char *listen_host, uint16_t port, PortBoundCallback callback, const void *callback_baton)
  64. {
  65. //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
  66. // Disconnect without saving errno
  67. Disconnect (false);
  68. // Now figure out the hostname that will be attaching and palce it into
  69. struct sockaddr_in listen_addr;
  70. ::memset (&listen_addr, 0, sizeof listen_addr);
  71. listen_addr.sin_len = sizeof listen_addr;
  72. listen_addr.sin_family = AF_INET;
  73. listen_addr.sin_port = htons (port);
  74. listen_addr.sin_addr.s_addr = INADDR_ANY;
  75. if (!ResolveIPV4HostName(listen_host, listen_addr.sin_addr.s_addr))
  76. {
  77. DNBLogThreaded("error: failed to resolve connecting host '%s'", listen_host);
  78. return rnb_err;
  79. }
  80. DNBError err;
  81. int listen_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
  82. if (listen_fd == -1)
  83. err.SetError(errno, DNBError::POSIX);
  84. if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
  85. err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_fd);
  86. if (err.Fail())
  87. return rnb_err;
  88. // enable local address reuse
  89. SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1);
  90. struct sockaddr_in sa;
  91. ::memset (&sa, 0, sizeof sa);
  92. sa.sin_len = sizeof sa;
  93. sa.sin_family = AF_INET;
  94. sa.sin_port = htons (port);
  95. sa.sin_addr.s_addr = INADDR_ANY; // Let incoming connections bind to any host network interface (this is NOT who can connect to us)
  96. int error = ::bind (listen_fd, (struct sockaddr *) &sa, sizeof(sa));
  97. if (error == -1)
  98. err.SetError(errno, DNBError::POSIX);
  99. if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
  100. err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_fd);
  101. if (err.Fail())
  102. {
  103. ClosePort (listen_fd, false);
  104. return rnb_err;
  105. }
  106. error = ::listen (listen_fd, 5);
  107. if (error == -1)
  108. err.SetError(errno, DNBError::POSIX);
  109. if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
  110. err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd);
  111. if (err.Fail())
  112. {
  113. ClosePort (listen_fd, false);
  114. return rnb_err;
  115. }
  116. if (callback)
  117. {
  118. // We were asked to listen on port zero which means we
  119. // must now read the actual port that was given to us
  120. // as port zero is a special code for "find an open port
  121. // for me".
  122. if (port == 0)
  123. {
  124. socklen_t sa_len = sizeof (sa);
  125. if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0)
  126. {
  127. port = ntohs (sa.sin_port);
  128. callback (callback_baton, port);
  129. }
  130. }
  131. else
  132. {
  133. callback (callback_baton, port);
  134. }
  135. }
  136. struct sockaddr_in accept_addr;
  137. ::memset (&accept_addr, 0, sizeof accept_addr);
  138. accept_addr.sin_len = sizeof accept_addr;
  139. bool accept_connection = false;
  140. // Loop until we are happy with our connection
  141. while (!accept_connection)
  142. {
  143. socklen_t accept_addr_len = sizeof accept_addr;
  144. m_fd = ::accept (listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len);
  145. if (m_fd == -1)
  146. err.SetError(errno, DNBError::POSIX);
  147. if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
  148. err.LogThreaded("::accept ( socket = %i, address = %p, address_len = %u )", listen_fd, &accept_addr, accept_addr_len);
  149. if (err.Fail())
  150. break;
  151. if (listen_addr.sin_addr.s_addr == INADDR_ANY)
  152. accept_connection = true;
  153. else
  154. {
  155. if (accept_addr_len == listen_addr.sin_len &&
  156. accept_addr.sin_addr.s_addr == listen_addr.sin_addr.s_addr)
  157. {
  158. accept_connection = true;
  159. }
  160. else
  161. {
  162. ::close (m_fd);
  163. m_fd = -1;
  164. const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
  165. const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sin_addr.s_addr;
  166. ::fprintf (stderr,
  167. "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n",
  168. accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
  169. listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
  170. DNBLogThreaded ("error: rejecting connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)",
  171. accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
  172. listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
  173. }
  174. }
  175. }
  176. ClosePort (listen_fd, false);
  177. if (err.Fail())
  178. {
  179. return rnb_err;
  180. }
  181. else
  182. {
  183. // Keep our TCP packets coming without any delays.
  184. SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
  185. }
  186. return rnb_success;
  187. }
  188. rnb_err_t
  189. RNBSocket::Connect (const char *host, uint16_t port)
  190. {
  191. Disconnect (false);
  192. // Create the socket
  193. m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
  194. if (m_fd == -1)
  195. return rnb_err;
  196. // Enable local address reuse
  197. SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
  198. struct sockaddr_in sa;
  199. ::memset (&sa, 0, sizeof (sa));
  200. sa.sin_family = AF_INET;
  201. sa.sin_port = htons (port);
  202. if (!ResolveIPV4HostName(host, sa.sin_addr.s_addr))
  203. {
  204. DNBLogThreaded("error: failed to resolve host '%s'", host);
  205. Disconnect (false);
  206. return rnb_err;
  207. }
  208. if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa)))
  209. {
  210. Disconnect (false);
  211. return rnb_err;
  212. }
  213. // Keep our TCP packets coming without any delays.
  214. SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
  215. return rnb_success;
  216. }
  217. rnb_err_t
  218. RNBSocket::useFD(int fd)
  219. {
  220. if (fd < 0) {
  221. DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in.");
  222. return rnb_err;
  223. }
  224. m_fd = fd;
  225. return rnb_success;
  226. }
  227. #ifdef WITH_LOCKDOWN
  228. rnb_err_t
  229. RNBSocket::ConnectToService()
  230. {
  231. DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
  232. // Disconnect from any previous connections
  233. Disconnect(false);
  234. if (::secure_lockdown_checkin (&m_ld_conn, NULL, NULL) != kLDESuccess)
  235. {
  236. DNBLogThreadedIf(LOG_RNB_COMM, "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed");
  237. m_fd = -1;
  238. return rnb_not_connected;
  239. }
  240. m_fd = ::lockdown_get_socket (m_ld_conn);
  241. if (m_fd == -1)
  242. {
  243. DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed");
  244. return rnb_not_connected;
  245. }
  246. m_fd_from_lockdown = true;
  247. return rnb_success;
  248. }
  249. #endif
  250. rnb_err_t
  251. RNBSocket::OpenFile (const char *path)
  252. {
  253. DNBError err;
  254. m_fd = open (path, O_RDWR);
  255. if (m_fd == -1)
  256. {
  257. err.SetError(errno, DNBError::POSIX);
  258. err.LogThreaded ("can't open file '%s'", path);
  259. return rnb_not_connected;
  260. }
  261. else
  262. {
  263. struct termios stdin_termios;
  264. if (::tcgetattr (m_fd, &stdin_termios) == 0)
  265. {
  266. stdin_termios.c_lflag &= ~ECHO; // Turn off echoing
  267. stdin_termios.c_lflag &= ~ICANON; // Get one char at a time
  268. ::tcsetattr (m_fd, TCSANOW, &stdin_termios);
  269. }
  270. }
  271. return rnb_success;
  272. }
  273. int
  274. RNBSocket::SetSocketOption(int fd, int level, int option_name, int option_value)
  275. {
  276. return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value));
  277. }
  278. rnb_err_t
  279. RNBSocket::Disconnect (bool save_errno)
  280. {
  281. #ifdef WITH_LOCKDOWN
  282. if (m_fd_from_lockdown)
  283. {
  284. m_fd_from_lockdown = false;
  285. m_fd = -1;
  286. lockdown_disconnect (m_ld_conn);
  287. return rnb_success;
  288. }
  289. #endif
  290. return ClosePort (m_fd, save_errno);
  291. }
  292. rnb_err_t
  293. RNBSocket::Read (std::string &p)
  294. {
  295. char buf[1024];
  296. p.clear();
  297. // Note that BUF is on the stack so we must be careful to keep any
  298. // writes to BUF from overflowing or we'll have security issues.
  299. if (m_fd == -1)
  300. return rnb_err;
  301. //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
  302. DNBError err;
  303. int bytesread = read (m_fd, buf, sizeof (buf));
  304. if (bytesread <= 0)
  305. err.SetError(errno, DNBError::POSIX);
  306. else
  307. p.append(buf, bytesread);
  308. if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
  309. err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof (buf), (uint64_t)bytesread);
  310. // Our port went away - we have to mark this so IsConnected will return the truth.
  311. if (bytesread == 0)
  312. {
  313. m_fd = -1;
  314. return rnb_not_connected;
  315. }
  316. else if (bytesread == -1)
  317. {
  318. m_fd = -1;
  319. return rnb_err;
  320. }
  321. // Strip spaces from the end of the buffer
  322. while (!p.empty() && isspace (p[p.size() - 1]))
  323. p.erase (p.size () - 1);
  324. // Most data in the debugserver packets valid printable characters...
  325. DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
  326. return rnb_success;
  327. }
  328. rnb_err_t
  329. RNBSocket::Write (const void *buffer, size_t length)
  330. {
  331. if (m_fd == -1)
  332. return rnb_err;
  333. DNBError err;
  334. int bytessent = write (m_fd, buffer, length);
  335. if (bytessent < 0)
  336. err.SetError(errno, DNBError::POSIX);
  337. if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
  338. err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i", m_fd, buffer, length, (uint64_t)bytessent);
  339. if (bytessent < 0)
  340. return rnb_err;
  341. if (bytessent != length)
  342. return rnb_err;
  343. DNBLogThreadedIf(LOG_RNB_PACKETS, "putpkt: %*s", (int)length, (char *)buffer); // All data is string based in debugserver, so this is safe
  344. DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer);
  345. return rnb_success;
  346. }
  347. rnb_err_t
  348. RNBSocket::ClosePort (int& fd, bool save_errno)
  349. {
  350. int close_err = 0;
  351. if (fd > 0)
  352. {
  353. errno = 0;
  354. close_err = close (fd);
  355. fd = -1;
  356. }
  357. return close_err != 0 ? rnb_err : rnb_success;
  358. }