[llvm] f21cc55 - [llvm-jitlink] Add diagnostic output and port executor to getaddrinfo(3) as well

Stefan Gränitz via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 22 03:21:30 PDT 2021


Author: Stefan Gränitz
Date: 2021-03-22T11:20:23+01:00
New Revision: f21cc55fb8a2ac10523f1c6cdf5af1feda106ea5

URL: https://github.com/llvm/llvm-project/commit/f21cc55fb8a2ac10523f1c6cdf5af1feda106ea5
DIFF: https://github.com/llvm/llvm-project/commit/f21cc55fb8a2ac10523f1c6cdf5af1feda106ea5.diff

LOG: [llvm-jitlink] Add diagnostic output and port executor to getaddrinfo(3) as well

Add diagnostic output for TCP connections on both sides, llvm-jitlink and llvm-jitlink-executor.
Port the executor to use getaddrinfo(3) as well. This makes the code more symmetric and seems to be the recommended way for implementing the server side.

Reviewed By: rzurob

Differential Revision: https://reviews.llvm.org/D98581

Added: 
    

Modified: 
    llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
    llvm/tools/llvm-jitlink/llvm-jitlink.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
index f693b0268cd8..9a92581157c5 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
@@ -17,11 +17,14 @@
 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
+#include <cstring>
 #include <sstream>
 
 #ifdef LLVM_ON_UNIX
 
+#include <netdb.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
 
@@ -46,37 +49,58 @@ void printErrorAndExit(Twine ErrMsg) {
   exit(1);
 }
 
-int openListener(std::string Host, int Port) {
+int openListener(std::string Host, std::string PortStr) {
 #ifndef LLVM_ON_UNIX
   // FIXME: Add TCP support for Windows.
   printErrorAndExit("listen option not supported");
   return 0;
 #else
-  int SockFD = socket(PF_INET, SOCK_STREAM, 0);
-  struct sockaddr_in ServerAddr, ClientAddr;
-  socklen_t ClientAddrLen = sizeof(ClientAddr);
-  memset(&ServerAddr, 0, sizeof(ServerAddr));
-  ServerAddr.sin_family = PF_INET;
-  ServerAddr.sin_family = INADDR_ANY;
-  ServerAddr.sin_port = htons(Port);
-
-  {
-    // lose the "Address already in use" error message
-    int Yes = 1;
-    if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1) {
-      errs() << "Error calling setsockopt.\n";
-      exit(1);
-    }
+  addrinfo Hints{};
+  Hints.ai_family = AF_INET;
+  Hints.ai_socktype = SOCK_STREAM;
+  Hints.ai_flags = AI_PASSIVE;
+
+  addrinfo *AI;
+  if (int EC = getaddrinfo(nullptr, PortStr.c_str(), &Hints, &AI)) {
+    errs() << "Error setting up bind address: " << gai_strerror(EC) << "\n";
+    exit(1);
+  }
+
+  // Create a socket from first addrinfo structure returned by getaddrinfo.
+  int SockFD;
+  if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) {
+    errs() << "Error creating socket: " << std::strerror(errno) << "\n";
+    exit(1);
   }
 
-  if (bind(SockFD, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) < 0) {
-    errs() << "Error on binding.\n";
+  // Avoid "Address already in use" errors.
+  const int Yes = 1;
+  if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1) {
+    errs() << "Error calling setsockopt: " << std::strerror(errno) << "\n";
     exit(1);
   }
 
-  listen(SockFD, 1);
-  return accept(SockFD, (struct sockaddr *)&ClientAddr, &ClientAddrLen);
+  // Bind the socket to the desired port.
+  if (bind(SockFD, AI->ai_addr, AI->ai_addrlen) < 0) {
+    errs() << "Error on binding: " << std::strerror(errno) << "\n";
+    exit(1);
+  }
+
+  // Listen for incomming connections.
+  static constexpr int ConnectionQueueLen = 1;
+  listen(SockFD, ConnectionQueueLen);
+
+  outs() << "Listening at " << Host << ":" << PortStr << "\n";
+
+#if defined(_AIX)
+  assert(Hi_32(AI->ai_addrlen) == 0 && "Field is a size_t on 64-bit AIX");
+  socklen_t AddrLen = Lo_32(AI->ai_addrlen);
+  return accept(SockFD, AI->ai_addr, &AddrLen);
+#else
+  return accept(SockFD, AI->ai_addr, &AI->ai_addrlen);
 #endif
+
+#endif // LLVM_ON_UNIX
 }
 
 int main(int argc, char *argv[]) {
@@ -105,9 +129,11 @@ int main(int argc, char *argv[]) {
 
       int Port = 0;
       if (PortStr.getAsInteger(10, Port))
-        printErrorAndExit("port" + PortStr + " is not a valid integer");
+        printErrorAndExit("port number '" + PortStr +
+                          "' is not a valid integer");
 
-      InFD = OutFD = openListener(Host.str(), Port);
+      InFD = OutFD = openListener(Host.str(), PortStr.str());
+      outs() << "Connection established. Running OrcRPCTPCServer...\n";
     } else
       printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
   }

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index 8d95469570f5..62303da0743a 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -42,6 +42,7 @@
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/Timer.h"
 
+#include <cstring>
 #include <list>
 #include <string>
 
@@ -668,73 +669,82 @@ LLVMJITLinkRemoteTargetProcessControl::LaunchExecutor() {
 #endif
 }
 
-Expected<std::unique_ptr<TargetProcessControl>>
-LLVMJITLinkRemoteTargetProcessControl::ConnectToExecutor() {
-#ifndef LLVM_ON_UNIX
-  // FIXME: Add TCP support for Windows.
-  return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr +
-                                     " not supported on non-unix platforms",
-                                 inconvertibleErrorCode());
-#else
-
-  shared::registerStringError<LLVMJITLinkChannel>();
-
-  StringRef HostNameStr, PortStr;
-  std::tie(HostNameStr, PortStr) =
-      StringRef(OutOfProcessExecutorConnect).split(':');
-
-  if (HostNameStr.empty())
-    return make_error<StringError>("host name for -" +
-                                       OutOfProcessExecutorConnect.ArgStr +
-                                       " can not be empty",
-                                   inconvertibleErrorCode());
-  if (PortStr.empty())
-    return make_error<StringError>(
-        "port for -" + OutOfProcessExecutorConnect.ArgStr + " can not be empty",
-        inconvertibleErrorCode());
-
-  std::string HostName = HostNameStr.str();
-  int Port = 0;
-  if (PortStr.getAsInteger(10, Port))
-    return make_error<StringError>("port number " + PortStr +
-                                       " is not a valid integer",
-                                   inconvertibleErrorCode());
+static Error createTCPSocketError(Twine Details) {
+  return make_error<StringError>(
+      formatv("Failed to connect TCP socket '{0}': {1}",
+              OutOfProcessExecutorConnect, Details),
+      inconvertibleErrorCode());
+}
 
+static Expected<int> connectTCPSocket(std::string Host, std::string PortStr) {
   addrinfo *AI;
   addrinfo Hints{};
   Hints.ai_family = AF_INET;
   Hints.ai_socktype = SOCK_STREAM;
   Hints.ai_flags = AI_NUMERICSERV;
-  if (int EC =
-          getaddrinfo(HostName.c_str(), PortStr.str().c_str(), &Hints, &AI))
-    return make_error<StringError>(formatv("Failed to resolve {0}:{1} ({2})",
-                                           HostName, Port, gai_strerror(EC)),
-                                   inconvertibleErrorCode());
 
-  // getaddrinfo returns a list of address structures.  Go through the list
-  // to find one we can connect to.
+  if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))
+    return createTCPSocketError("Address resolution failed (" +
+                                StringRef(gai_strerror(EC)) + ")");
+
+  // Cycle through the returned addrinfo structures and connect to the first
+  // reachable endpoint.
   int SockFD;
-  int ConnectRC = -1;
-  for (addrinfo *Server = AI; Server; Server = Server->ai_next) {
-    // If socket fails, maybe it's because the address family is not supported.
-    // Skip to the next addrinfo structure.
+  addrinfo *Server;
+  for (Server = AI; Server != nullptr; Server = Server->ai_next) {
+    // socket might fail, e.g. if the address family is not supported. Skip to
+    // the next addrinfo structure in such a case.
     if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
       continue;
 
-    ConnectRC = connect(SockFD, Server->ai_addr, Server->ai_addrlen);
-    if (ConnectRC == 0)
+    // If connect returns null, we exit the loop with a working socket.
+    if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
       break;
 
     close(SockFD);
   }
   freeaddrinfo(AI);
-  if (ConnectRC == -1)
-    return make_error<StringError>("Failed to connect to " + HostName + ":" +
-                                       Twine(Port),
-                                   inconvertibleErrorCode());
+
+  // If we reached the end of the loop without connecting to a valid endpoint,
+  // dump the last error that was logged in socket() or connect().
+  if (Server == nullptr)
+    return createTCPSocketError(std::strerror(errno));
+
+  return SockFD;
+}
+
+Expected<std::unique_ptr<TargetProcessControl>>
+LLVMJITLinkRemoteTargetProcessControl::ConnectToExecutor() {
+#ifndef LLVM_ON_UNIX
+  // FIXME: Add TCP support for Windows.
+  return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr +
+                                     " not supported on non-unix platforms",
+                                 inconvertibleErrorCode());
+#else
+
+  shared::registerStringError<LLVMJITLinkChannel>();
+
+  StringRef Host, PortStr;
+  std::tie(Host, PortStr) = StringRef(OutOfProcessExecutorConnect).split(':');
+  if (Host.empty())
+    return createTCPSocketError("Host name for -" +
+                                OutOfProcessExecutorConnect.ArgStr +
+                                " can not be empty");
+  if (PortStr.empty())
+    return createTCPSocketError("Port number in -" +
+                                OutOfProcessExecutorConnect.ArgStr +
+                                " can not be empty");
+  int Port = 0;
+  if (PortStr.getAsInteger(10, Port))
+    return createTCPSocketError("Port number '" + PortStr +
+                                "' is not a valid integer");
+
+  Expected<int> SockFD = connectTCPSocket(Host.str(), PortStr.str());
+  if (!SockFD)
+    return SockFD.takeError();
 
   auto SSP = std::make_shared<SymbolStringPool>();
-  auto Channel = std::make_unique<shared::FDRawByteChannel>(SockFD, SockFD);
+  auto Channel = std::make_unique<shared::FDRawByteChannel>(*SockFD, *SockFD);
   auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
 
   auto ReportError = [](Error Err) {


        


More information about the llvm-commits mailing list