gem5-dev@gem5.org

The gem5 Developer List

View all threads

[M] Change in gem5/gem5[develop]: util: Make m5term able to connect to unix domain sockets.

GB
Gabe Black (Gerrit)
Tue, Mar 21, 2023 10:53 PM

Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/69167?usp=email )

Change subject: util: Make m5term able to connect to unix domain sockets.
......................................................................

util: Make m5term able to connect to unix domain sockets.

To connect to a unix domain socket, it must start with a non-digit
character to avoid being confused with a TCP port. If it starts with an
"@" character, then it is treated as an abstract socket.

Change-Id: I3a71eb8ef80018546f3bbf9d781770bd37ecec09

M util/term/term.c
1 file changed, 117 insertions(+), 29 deletions(-)

diff --git a/util/term/term.c b/util/term/term.c
index 529712c..8cbd202 100644
--- a/util/term/term.c
+++ b/util/term/term.c
@@ -27,26 +27,30 @@
*/

#include <arpa/telnet.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/termios.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/un.h>
+#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
+#include <linux/limits.h>
#include <netdb.h>
+#include <netinet/in.h>
#include <poll.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
+#include <sys/termios.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
#include <unistd.h>

ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
void    readwrite(int);
-int    remote_connect(char *, char *, struct addrinfo);
+int    remote_connect_inet(char *, char *);
+int    remote_connect_unix(char *);

struct  termios saved_ios;
void    raw_term();
@@ -60,7 +64,6 @@
{
int ch, s, ret;
char *host, *port, *endp;

  • struct addrinfo hints;
    socklen_t len;

    ret = 1;
    @@ -87,33 +90,40 @@

    raw_term();

  • if (isdigit(port[0])) {
  •    s = remote_connect_inet(host, port);
    
  • } else {
  •    if (argc != 2)
    
  •        errx(1, "host specified with local socket");
    
  •    s = remote_connect_unix(port);
    
  • }
  • if (s != -1) {
  •    readwrite(s);
    
  •    close(s);
    
  • }
  • exit(0);
    +}

+/*

    • remote_connect_inet()
    • Return's a socket connected to a remote host. Properly bind's to a local
    • port or source address if needed. Return's -1 on failure.
  • */
    +int
    +remote_connect_inet(char *host, char *port)
    +{
  • struct addrinfo hints;
  • struct addrinfo *res, *res0;
  • int s, error;
  • /* Initialize addrinfo structure */
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    
  • s = remote_connect(host, port, hints);
  • ret = 0;
  • readwrite(s);
  • if (s)
  •    close(s);
    
  • exit(ret);
    -}

-/*

    • remote_connect()
    • Return's a socket connected to a remote host. Properly bind's to a local
    • port or source address if needed. Return's -1 on failure.
  • */
    -int
    -remote_connect(char *host, char *port, struct addrinfo hints)
    -{
  • struct addrinfo *res, *res0;
  • int s, error;
  • if ((error = getaddrinfo(host, port, &hints, &res)))
        errx(1, "getaddrinfo: %s", gai_strerror(error));
    

@@ -136,6 +146,84 @@
}

/*

    • remote_connect_inet()
    • Return's a socket connected to a remote host. Properly bind's to a local
    • port or source address if needed. Return's -1 on failure.
  • */
    +int
    +remote_connect_unix(char *path)
    +{
  • struct sockaddr_un addr;
  • // Create a copy of path so we can safely modify it in place.
  • char *pathc = strdup(path);
  • path = pathc;
  • // Create a unix domain socket.
  • int s = socket(AF_UNIX, SOCK_STREAM, 0);
  • if (s == -1)
  •    return s;
    
  • // Prepare the scokaddr_un.
  • memset(&addr, 0, sizeof(addr));
  • addr.sun_family = AF_UNIX;
  • // Keep track of where we're filling in the path, and the remaining
    space.
  • int path_size = sizeof(addr.sun_path);
  • char *sun_path = &addr.sun_path[0];
  • // Keep track of the current directory in case we change it to maximize
  • // what we can fit in the limited space in sun_path.
  • char *cwd = NULL;
  • if (path[0] == '@') {
  •    // If this is an abstract socket, prefix it with a null byte.
    
  •    *sun_path++ = '\0';
    
  •    path++;
    
  •    path_size--;
    
  •    // Keep track of how much of sun_path is actual data since  
    

everything

  •    // we include will be part of the lookup.
    
  •    int len = strlen(path);
    
  •    if (len < path_size)
    
  •        path_size = len;
    
  • } else {
  •    // Switch to the parent directory of the socket.
    
  •    cwd = (char *)malloc(PATH_MAX);
    
  •    getcwd(cwd, PATH_MAX);
    
  •    char *dirc = strdup(path);
    
  •    char *dname = dirname(dirc);
    
  •    chdir(dname);
    
  •    free(dirc);
    
  •    // Replace the path with just the filename part. We still have a
    
  •    // pointer to our copy of "path" so we can clean it up later.
    
  •    path = basename(path);
    
  • }
  • // Copy the path into sun_path.
  • strncpy(sun_path, path, path_size);
  • // Figure out how much actual data we have in sockaddr_un.
  • int struct_len = (char *)sun_path + path_size - (char *)&addr;
  • // Actually connect to the socket.
  • if (connect(s, (struct sockaddr *)&addr, struct_len) == -1) {
  •    // If that didn't work, switch our dir back and error out.
    
  •    if (cwd)
    
  •        chdir(cwd);
    
  •    errx(1, "Failed to connect");
    
  • }
  • // We're connected, clean up memory and switch the current dir back.
  • free(pathc);
  • if (cwd)
  •    chdir(cwd);
    
  • // Return the FD of our new connection.
  • return s;
    +}

+/*

  • readwrite()
  • Loop that selects on the network file descriptor and stdin.
  • Changed from poll() by Ali Saidi to make work on Mac OS X >= 10.4

--
To view, visit
https://gem5-review.googlesource.com/c/public/gem5/+/69167?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I3a71eb8ef80018546f3bbf9d781770bd37ecec09
Gerrit-Change-Number: 69167
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black gabe.black@gmail.com
Gerrit-CC: Gabe Black gabeblack@google.com
Gerrit-MessageType: newchange

Gabe Black has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/69167?usp=email ) Change subject: util: Make m5term able to connect to unix domain sockets. ...................................................................... util: Make m5term able to connect to unix domain sockets. To connect to a unix domain socket, it must start with a non-digit character to avoid being confused with a TCP port. If it starts with an "@" character, then it is treated as an abstract socket. Change-Id: I3a71eb8ef80018546f3bbf9d781770bd37ecec09 --- M util/term/term.c 1 file changed, 117 insertions(+), 29 deletions(-) diff --git a/util/term/term.c b/util/term/term.c index 529712c..8cbd202 100644 --- a/util/term/term.c +++ b/util/term/term.c @@ -27,26 +27,30 @@ */ #include <arpa/telnet.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/termios.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/un.h> +#include <ctype.h> #include <err.h> #include <errno.h> #include <fcntl.h> +#include <libgen.h> +#include <linux/limits.h> #include <netdb.h> +#include <netinet/in.h> #include <poll.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/socket.h> +#include <sys/termios.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/un.h> #include <unistd.h> ssize_t atomicio(ssize_t (*)(), int, void *, size_t); void readwrite(int); -int remote_connect(char *, char *, struct addrinfo); +int remote_connect_inet(char *, char *); +int remote_connect_unix(char *); struct termios saved_ios; void raw_term(); @@ -60,7 +64,6 @@ { int ch, s, ret; char *host, *port, *endp; - struct addrinfo hints; socklen_t len; ret = 1; @@ -87,33 +90,40 @@ raw_term(); + if (isdigit(port[0])) { + s = remote_connect_inet(host, port); + } else { + if (argc != 2) + errx(1, "host specified with local socket"); + s = remote_connect_unix(port); + } + + if (s != -1) { + readwrite(s); + close(s); + } + + exit(0); +} + +/* + * remote_connect_inet() + * Return's a socket connected to a remote host. Properly bind's to a local + * port or source address if needed. Return's -1 on failure. + */ +int +remote_connect_inet(char *host, char *port) +{ + struct addrinfo hints; + struct addrinfo *res, *res0; + int s, error; + /* Initialize addrinfo structure */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; - s = remote_connect(host, port, hints); - ret = 0; - readwrite(s); - - if (s) - close(s); - - exit(ret); -} - -/* - * remote_connect() - * Return's a socket connected to a remote host. Properly bind's to a local - * port or source address if needed. Return's -1 on failure. - */ -int -remote_connect(char *host, char *port, struct addrinfo hints) -{ - struct addrinfo *res, *res0; - int s, error; - if ((error = getaddrinfo(host, port, &hints, &res))) errx(1, "getaddrinfo: %s", gai_strerror(error)); @@ -136,6 +146,84 @@ } /* + * remote_connect_inet() + * Return's a socket connected to a remote host. Properly bind's to a local + * port or source address if needed. Return's -1 on failure. + */ +int +remote_connect_unix(char *path) +{ + struct sockaddr_un addr; + + // Create a copy of path so we can safely modify it in place. + char *pathc = strdup(path); + path = pathc; + + // Create a unix domain socket. + int s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s == -1) + return s; + + // Prepare the scokaddr_un. + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + + // Keep track of where we're filling in the path, and the remaining space. + int path_size = sizeof(addr.sun_path); + char *sun_path = &addr.sun_path[0]; + + // Keep track of the current directory in case we change it to maximize + // what we can fit in the limited space in sun_path. + char *cwd = NULL; + + if (path[0] == '@') { + // If this is an abstract socket, prefix it with a null byte. + *sun_path++ = '\0'; + path++; + path_size--; + // Keep track of how much of sun_path is actual data since everything + // we include will be part of the lookup. + int len = strlen(path); + if (len < path_size) + path_size = len; + } else { + // Switch to the parent directory of the socket. + cwd = (char *)malloc(PATH_MAX); + getcwd(cwd, PATH_MAX); + char *dirc = strdup(path); + char *dname = dirname(dirc); + chdir(dname); + free(dirc); + + // Replace the path with just the filename part. We still have a + // pointer to our copy of "path" so we can clean it up later. + path = basename(path); + } + + // Copy the path into sun_path. + strncpy(sun_path, path, path_size); + + // Figure out how much actual data we have in sockaddr_un. + int struct_len = (char *)sun_path + path_size - (char *)&addr; + + // Actually connect to the socket. + if (connect(s, (struct sockaddr *)&addr, struct_len) == -1) { + // If that didn't work, switch our dir back and error out. + if (cwd) + chdir(cwd); + errx(1, "Failed to connect"); + } + + // We're connected, clean up memory and switch the current dir back. + free(pathc); + if (cwd) + chdir(cwd); + + // Return the FD of our new connection. + return s; +} + +/* * readwrite() * Loop that selects on the network file descriptor and stdin. * Changed from poll() by Ali Saidi to make work on Mac OS X >= 10.4 -- To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/69167?usp=email To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings Gerrit-Project: public/gem5 Gerrit-Branch: develop Gerrit-Change-Id: I3a71eb8ef80018546f3bbf9d781770bd37ecec09 Gerrit-Change-Number: 69167 Gerrit-PatchSet: 1 Gerrit-Owner: Gabe Black <gabe.black@gmail.com> Gerrit-CC: Gabe Black <gabeblack@google.com> Gerrit-MessageType: newchange