[Lldb-commits] [lldb] [lldb-dap] Refactoring lldb-dap port listening mode to allow multiple connections. (PR #116392)

John Harrison via lldb-commits lldb-commits at lists.llvm.org
Fri Nov 22 17:13:13 PST 2024


================
@@ -137,42 +141,232 @@ lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t variablesReference) {
   }
 }
 
-SOCKET AcceptConnection(DAP &dap, int portno) {
-  // Accept a socket connection from any host on "portno".
-  SOCKET newsockfd = -1;
-  struct sockaddr_in serv_addr, cli_addr;
+/// Redirect stdout and stderr fo the IDE's console output.
+///
+/// Errors in this operation will be printed to the log file and the IDE's
+/// console output as well.
+///
+/// \return
+///     A fd pointing to the original stdout.
+void SetupRedirection(DAP &dap, int stdoutfd = -1, int stderrfd = -1) {
+  auto output_callback_stderr = [&dap](llvm::StringRef data) {
+    dap.SendOutput(OutputType::Stderr, data);
+  };
+  auto output_callback_stdout = [&dap](llvm::StringRef data) {
+    dap.SendOutput(OutputType::Stdout, data);
+  };
+
+  llvm::Expected<int> new_stdout_fd =
+      RedirectFd(stdoutfd, output_callback_stdout);
+  if (auto err = new_stdout_fd.takeError()) {
+    std::string error_message = llvm::toString(std::move(err));
+    if (dap.log)
+      *dap.log << error_message << std::endl;
+    output_callback_stderr(error_message);
+  }
+  dap.out = lldb::SBFile(new_stdout_fd.get(), "w", false);
+
+  llvm::Expected<int> new_stderr_fd =
+      RedirectFd(stderrfd, output_callback_stderr);
+  if (auto err = new_stderr_fd.takeError()) {
+    std::string error_message = llvm::toString(std::move(err));
+    if (dap.log)
+      *dap.log << error_message << std::endl;
+    output_callback_stderr(error_message);
+  }
+  dap.err = lldb::SBFile(new_stderr_fd.get(), "w", false);
+}
+
+void HandleClient(int clientfd, llvm::StringRef program_path,
+                  const std::vector<std::string> &pre_init_commands,
+                  std::shared_ptr<std::ofstream> log,
+                  ReplMode default_repl_mode) {
+  if (log)
+    *log << "client[" << clientfd << "] connected\n";
+  DAP dap = DAP(program_path, log, default_repl_mode, pre_init_commands);
+  dap.debug_adaptor_path = program_path;
+
+  SetupRedirection(dap);
+  RegisterRequestCallbacks(dap);
+
+  dap.input.descriptor = StreamDescriptor::from_socket(clientfd, false);
+  dap.output.descriptor = StreamDescriptor::from_socket(clientfd, false);
+
+  for (const std::string &arg : pre_init_commands) {
+    dap.pre_init_commands.push_back(arg);
+  }
+
+  if (auto Err = dap.Loop()) {
+    if (log)
+      *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n";
+  }
+
+  if (log)
+    *log << "client[" << clientfd << "] connection closed\n";
+#if defined(_WIN32)
+  closesocket(clientfd);
+#else
+  close(clientfd);
+#endif
+}
+
+std::error_code getLastSocketErrorCode() {
+#ifdef _WIN32
+  return std::error_code(::WSAGetLastError(), std::system_category());
+#else
+  return llvm::errnoAsErrorCode();
+#endif
+}
+
+llvm::Expected<int> getSocketFD(llvm::StringRef path) {
+  if (llvm::sys::fs::exists(path) && (::remove(path.str().c_str()) == -1)) {
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Remove existing socket failed");
+  }
+
+  SOCKET sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (sockfd == -1) {
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Create socket failed");
+  }
+
+  struct sockaddr_un addr;
+  bzero(&addr, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, path.str().c_str(), sizeof(addr.sun_path) - 1);
+
+  if (::bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+#if defined(_WIN32)
+    closesocket(sockfd);
+#else
+    close(sockfd);
+#endif
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Socket bind() failed");
+  }
+
+  if (listen(sockfd, llvm::hardware_concurrency().compute_thread_count()) < 0) {
+#if defined(_WIN32)
+    closesocket(sockfd);
+#else
+    close(sockfd);
+#endif
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Socket listen() failed");
+  }
+
+  return sockfd;
+}
+
+llvm::Expected<int> getSocketFD(int portno) {
   SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if (sockfd < 0) {
-    if (dap.log)
-      *dap.log << "error: opening socket (" << strerror(errno) << ")"
-               << std::endl;
-  } else {
-    memset((char *)&serv_addr, 0, sizeof(serv_addr));
-    serv_addr.sin_family = AF_INET;
-    // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-    serv_addr.sin_port = htons(portno);
-    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
-      if (dap.log)
-        *dap.log << "error: binding socket (" << strerror(errno) << ")"
-                 << std::endl;
-    } else {
-      listen(sockfd, 5);
-      socklen_t clilen = sizeof(cli_addr);
-      newsockfd =
-          llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd,
-                                      (struct sockaddr *)&cli_addr, &clilen);
-      if (newsockfd < 0)
-        if (dap.log)
-          *dap.log << "error: accept (" << strerror(errno) << ")" << std::endl;
-    }
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Create socket failed");
+  }
+
+  struct sockaddr_in serv_addr;
+  bzero(&serv_addr, sizeof(serv_addr));
+  serv_addr.sin_family = AF_INET;
+  // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  serv_addr.sin_port = htons(portno);
+  if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
 #if defined(_WIN32)
     closesocket(sockfd);
 #else
     close(sockfd);
 #endif
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Socket bind() failed");
   }
-  return newsockfd;
+
+  if (listen(sockfd, llvm::hardware_concurrency().compute_thread_count()) < 0) {
+#if defined(_WIN32)
+    closesocket(sockfd);
+#else
+    close(sockfd);
+#endif
+    return llvm::make_error<llvm::StringError>(getLastSocketErrorCode(),
+                                               "Socket listen() failed");
+  }
+
+  return sockfd;
+}
+
+int AcceptConnection(llvm::StringRef program_path,
+                     const std::vector<std::string> &pre_init_commands,
+                     std::shared_ptr<std::ofstream> log,
+                     ReplMode default_repl_mode,
+                     llvm::StringRef unix_socket_path) {
+  auto listening = getSocketFD(unix_socket_path);
+  if (auto E = listening.takeError()) {
+    llvm::errs() << "Listening on " << unix_socket_path
+                 << " failed: " << llvm::toString(std::move(E)) << "\n";
+    return EXIT_FAILURE;
+  }
+
+  while (true) {
+    struct sockaddr_un cli_addr;
+    bzero(&cli_addr, sizeof(struct sockaddr_un));
+    socklen_t clilen = sizeof(cli_addr);
+    SOCKET clientfd =
+        llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, *listening,
+                                    (struct sockaddr *)&cli_addr, &clilen);
+    if (clientfd < 0) {
+      llvm::errs() << "Client accept failed: "
+                   << getLastSocketErrorCode().message() << "\n";
+      return EXIT_FAILURE;
+    }
+
+    std::thread t(HandleClient, clientfd, program_path, pre_init_commands, log,
+                  default_repl_mode);
+    t.detach();
+  }
+
+#if defined(_WIN32)
+  closesocket(*listening);
+#else
+  close(*listening);
+#endif
+  return 0;
+}
+
+int AcceptConnection(llvm::StringRef program_path,
+                     const std::vector<std::string> &pre_init_commands,
+                     std::shared_ptr<std::ofstream> log,
+                     ReplMode default_repl_mode, int portno) {
+  auto listening = getSocketFD(portno);
----------------
ashgti wrote:

I refactored this and made some helpers for creating sockets and listening. LMKWYT

https://github.com/llvm/llvm-project/pull/116392


More information about the lldb-commits mailing list