This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/4] GDBSERVER: Listen on a unix domain (instead of TCP) socket if requested.


When invoking gdbserver, if the COMM parameter takes the form "unix::/path/name"
then a local (unix) domain socket will be created with that name and gdbserver
will listen for connections on that.

    gdb/
    * NEWS: Mention new feature.

    gdb/gdbserver/
    * configure.ac (AC_CHECK_HEADERS): Add sys/un.h.
    * configure: Regenerate.
    * remote-utils.c (remote_prepare): Create a local socket if requested.
     (remote_open):  Don't attempt to open a file if it's a socket.
     (handle_accept_event): Display the name of the socket on connection.

   gdb/common/
   * netstuff.c (parse_connection_spec)[prefixes]: New member for local domain sockets.
---
 gdb/NEWS                     |   4 ++
 gdb/common/netstuff.c        |   9 +++
 gdb/gdbserver/configure.ac   |   2 +-
 gdb/gdbserver/remote-utils.c | 148 ++++++++++++++++++++++++++++++-------------
 4 files changed, 117 insertions(+), 46 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 126e61e282..23de349324 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -15,6 +15,10 @@
   can be passed using the '[ADDRESS]:PORT' notation, or the regular
   'ADDRESS:PORT' method.
 
+* GDB and GDBserver now support local domain socket connections.  The
+  name of a local domain socket may be provided instead of the
+  [ADDRESS]:PORT notation.
+
 * DWARF index cache: GDB can now automatically save indices of DWARF
   symbols on disk to speed up further loading of the same binaries.
 
diff --git a/gdb/common/netstuff.c b/gdb/common/netstuff.c
index c1c401ccb2..8da6aba24e 100644
--- a/gdb/common/netstuff.c
+++ b/gdb/common/netstuff.c
@@ -57,6 +57,8 @@ parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint)
 			  || std::count (spec.begin (),
 					 spec.end (), ':') > 1)));
 
+  bool is_unix = hint->ai_family == AF_UNIX;
+
   if (is_ipv6)
     {
       if (spec[0] == '[')
@@ -109,6 +111,12 @@ parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint)
   if (ret.host_str.empty ())
     ret.host_str = "localhost";
 
+  if (is_unix && ret.host_str != "localhost")
+    error (_("The host name must be empty or 'localhost' for a unix domain socket."));
+
+  if (is_unix && ret.port_str.empty ())
+    error (_("A path name must be specified for a unix domain socket."));
+
   return ret;
 }
 
@@ -138,6 +146,7 @@ parse_connection_spec (const char *spec, struct addrinfo *hint)
       { "tcp4:", AF_INET,   SOCK_STREAM },
       { "udp6:", AF_INET6,  SOCK_DGRAM },
       { "tcp6:", AF_INET6,  SOCK_STREAM },
+      { "unix:", AF_LOCAL,  SOCK_STREAM },
     };
 
   for (const host_prefix prefix : prefixes)
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index fa3ca53efd..de7e7d4103 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -98,7 +98,7 @@ ACX_CONFIGURE_DIR(["../../libiberty"], ["build-libiberty-gdbserver"])
 AC_CHECK_HEADERS(termios.h sys/reg.h string.h dnl
 		 proc_service.h sys/procfs.h linux/elf.h dnl
 		 fcntl.h signal.h sys/file.h dnl
-		 sys/ioctl.h netinet/in.h sys/socket.h netdb.h dnl
+		 sys/ioctl.h netinet/in.h sys/socket.h sys/un.h netdb.h dnl
 		 netinet/tcp.h arpa/inet.h)
 AC_FUNC_FORK
 AC_CHECK_FUNCS(getauxval pread pwrite pread64 setns)
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 9199a9c7ad..0eb53c2116 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -38,6 +38,9 @@
 #if HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
@@ -193,20 +196,33 @@ handle_accept_event (int err, gdb_client_data client_data)
      descriptor open for add_file_handler to wait for a new connection.  */
   delete_file_handler (listen_desc);
 
-  /* Convert IP address to string.  */
-  char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
-
-  int r = getnameinfo ((struct sockaddr *) &sockaddr, len,
-		       orig_host, sizeof (orig_host),
-		       orig_port, sizeof (orig_port),
-		       NI_NUMERICHOST | NI_NUMERICSERV);
+  if (sockaddr.ss_family == AF_UNIX)
+    {
+      struct sockaddr_un su;
+      socklen_t len;
+      if (getsockname (listen_desc, (struct sockaddr *) &su, &len) != 0)
+	perror (_("Could not obtain remote address"));
 
-  if (r != 0)
-    fprintf (stderr, _("Could not obtain remote address: %s\n"),
-	     gai_strerror (r));
+      fprintf (stderr, _("Remote debugging on local socket bound to %s\n"),
+	       su.sun_path);
+    }
   else
-    fprintf (stderr, _("Remote debugging from host %s, port %s\n"),
-	     orig_host, orig_port);
+    {
+      /* Convert IP address to string.  */
+      char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
+
+      int r = getnameinfo ((struct sockaddr *) &sockaddr, len,
+			   orig_host, sizeof (orig_host),
+			   orig_port, sizeof (orig_port),
+			   NI_NUMERICHOST | NI_NUMERICSERV);
+
+      if (r != 0)
+	fprintf (stderr, _("Could not obtain remote address: %s\n"),
+		 gai_strerror (r));
+      else
+	fprintf (stderr, _("Remote debugging from host %s, port %s\n"),
+		 orig_host, orig_port);
+    }
 
   enable_async_notification (remote_desc);
 
@@ -250,6 +266,9 @@ remote_prepare (const char *name)
   struct addrinfo hint;
   struct addrinfo *ainfo;
 
+  struct sockaddr *addr;
+  socklen_t addrlen;
+
   memset (&hint, 0, sizeof (hint));
   /* Assume no prefix will be passed, therefore we should use
      AF_UNSPEC.  */
@@ -258,7 +277,7 @@ remote_prepare (const char *name)
   hint.ai_protocol = IPPROTO_TCP;
 
   parsed_connection_spec parsed
-    = parse_connection_spec_without_prefix (name, &hint);
+    = parse_connection_spec (name, &hint);
 
   if (parsed.port_str.empty ())
     {
@@ -276,47 +295,86 @@ remote_prepare (const char *name)
     }
 #endif
 
-  int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (),
-		       &hint, &ainfo);
+  struct sockaddr_un unix_addr;
 
-  if (r != 0)
-    error (_("%s: cannot resolve name: %s"), name, gai_strerror (r));
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path)
+#endif
 
-  scoped_free_addrinfo freeaddrinfo (ainfo);
+  if (hint.ai_family == AF_LOCAL)
+    {
+      const char *sock_name = parsed.port_str.c_str ();
+      if (parsed.port_str.length() > UNIX_PATH_MAX - 1)
+	{
+	  error
+	    (_("%s is too long.  Socket names may be no longer than %s bytes."),
+	     sock_name, pulongest (UNIX_PATH_MAX - 1));
+	  return;
+	}
+      listen_desc = socket (AF_UNIX,  SOCK_STREAM,  0);
+      if (listen_desc < 0)
+	perror_with_name ("Can't open socket");
 
-  struct addrinfo *iter;
+      memset (&unix_addr, 0, sizeof (unix_addr));
+      unix_addr.sun_family = AF_UNIX;
+      strncpy (unix_addr.sun_path, sock_name, UNIX_PATH_MAX - 1);
 
-  for (iter = ainfo; iter != NULL; iter = iter->ai_next)
-    {
-      listen_desc = gdb_socket_cloexec (iter->ai_family, iter->ai_socktype,
-					iter->ai_protocol);
+      struct stat statbuf;
+      int stat_result = stat (sock_name, &statbuf);
+      if (stat_result == 0
+	  && (S_IFSOCK & statbuf.st_mode))
+	unlink (sock_name);
 
-      if (listen_desc >= 0)
-	break;
+      addr = (struct sockaddr *) &unix_addr;
+      addrlen = sizeof (unix_addr);
     }
+  else
+    {
+      struct addrinfo *iter;
 
-  if (iter == NULL)
-    perror_with_name ("Can't open socket");
+      int r = getaddrinfo (parsed.host_str.c_str (),
+			   parsed.port_str.c_str (),
+			   &hint, &ainfo);
 
-  /* Allow rapid reuse of this port. */
-  tmp = 1;
-  setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
-	      sizeof (tmp));
+      if (r != 0)
+	error (_("%s: cannot resolve name: %s"), name, gai_strerror (r));
 
-  switch (iter->ai_family)
-    {
-    case AF_INET:
-      ((struct sockaddr_in *) iter->ai_addr)->sin_addr.s_addr = INADDR_ANY;
-      break;
-    case AF_INET6:
-      ((struct sockaddr_in6 *) iter->ai_addr)->sin6_addr = in6addr_any;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Invalid 'ai_family' %d\n"), iter->ai_family);
+      scoped_free_addrinfo freeaddrinfo (ainfo);
+
+      for (iter = ainfo; iter != NULL; iter = iter->ai_next)
+	{
+	  listen_desc = gdb_socket_cloexec (iter->ai_family, iter->ai_socktype,
+					    iter->ai_protocol);
+
+	  if (listen_desc >= 0)
+	    break;
+	}
+
+      if (iter == NULL)
+	perror_with_name ("Can't open socket");
+
+      /* Allow rapid reuse of this port. */
+      tmp = 1;
+      setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
+		  sizeof (tmp));
+
+      switch (iter->ai_family)
+	{
+	case AF_INET:
+	  ((struct sockaddr_in *) iter->ai_addr)->sin_addr.s_addr = INADDR_ANY;
+	  break;
+	case AF_INET6:
+	  ((struct sockaddr_in6 *) iter->ai_addr)->sin6_addr = in6addr_any;
+	  break;
+	default:
+	  internal_error (__FILE__, __LINE__,
+			  _("Invalid 'ai_family' %d\n"), iter->ai_family);
+	}
+      addr = iter->ai_addr;
+      addrlen = iter->ai_addrlen;
     }
 
-  if (bind (listen_desc, iter->ai_addr, iter->ai_addrlen) != 0)
+  if (bind (listen_desc, addr, addrlen) != 0)
     perror_with_name ("Can't bind address");
 
   if (listen (listen_desc, 1) != 0)
@@ -354,11 +412,11 @@ remote_open (const char *name)
     }
 #ifndef USE_WIN32API
   else if (port_str == NULL)
-    {
+     {
       struct stat statbuf;
 
       if (stat (name, &statbuf) == 0
-	  && (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)))
+         && (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)))
 	remote_desc = open (name, O_RDWR);
       else
 	{
-- 
2.11.0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]