| #include <unistd.h> | |
| #include <errno.h> | |
| #include <arpa/inet.h> | |
| #include <sys/ioctl.h> | |
| #include <linux/vm_sockets.h> | |
| #include "trace-cmd-private.h" | |
| int __hidden tcmd_vsock_open(unsigned int cid, unsigned int port) | |
| { | |
| struct sockaddr_vm addr = { | |
| .svm_family = AF_VSOCK, | |
| .svm_cid = cid, | |
| .svm_port = port, | |
| }; | |
| int sd; | |
| sd = socket(AF_VSOCK, SOCK_STREAM, 0); | |
| if (sd < 0) | |
| return -errno; | |
| if (connect(sd, (struct sockaddr *)&addr, sizeof(addr))) { | |
| close(sd); | |
| return -errno; | |
| } | |
| return sd; | |
| } | |
| int __hidden tcmd_vsock_make(unsigned int port) | |
| { | |
| struct sockaddr_vm addr = { | |
| .svm_family = AF_VSOCK, | |
| .svm_cid = VMADDR_CID_ANY, | |
| .svm_port = port, | |
| }; | |
| int sd; | |
| sd = socket(AF_VSOCK, SOCK_STREAM, 0); | |
| if (sd < 0) | |
| return -errno; | |
| setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); | |
| if (bind(sd, (struct sockaddr *)&addr, sizeof(addr))) | |
| goto error; | |
| if (listen(sd, SOMAXCONN)) | |
| goto error; | |
| return sd; | |
| error: | |
| close(sd); | |
| return -errno; | |
| } | |
| int __hidden tcmd_vsock_make_any(void) | |
| { | |
| return tcmd_vsock_make(VMADDR_PORT_ANY); | |
| } | |
| int __hidden tcmd_vsock_get_port(int sd, unsigned int *port) | |
| { | |
| struct sockaddr_vm addr; | |
| socklen_t addr_len = sizeof(addr); | |
| if (getsockname(sd, (struct sockaddr *)&addr, &addr_len)) | |
| return -errno; | |
| if (addr.svm_family != AF_VSOCK) | |
| return -EINVAL; | |
| if (port) | |
| *port = addr.svm_port; | |
| return 0; | |
| } | |
| int get_vsocket_params(int fd, unsigned int *lcid, unsigned int *rcid) | |
| { | |
| struct sockaddr_vm addr; | |
| socklen_t addr_len = sizeof(addr); | |
| if (lcid) { | |
| memset(&addr, 0, sizeof(addr)); | |
| if (getsockname(fd, (struct sockaddr *)&addr, &addr_len)) | |
| return -1; | |
| if (addr.svm_family != AF_VSOCK) | |
| return -1; | |
| *lcid = addr.svm_cid; | |
| } | |
| if (rcid) { | |
| memset(&addr, 0, sizeof(addr)); | |
| addr_len = sizeof(addr); | |
| if (getpeername(fd, (struct sockaddr *)&addr, &addr_len)) | |
| return -1; | |
| if (addr.svm_family != AF_VSOCK) | |
| return -1; | |
| *rcid = addr.svm_cid; | |
| } | |
| return 0; | |
| } | |
| int trace_vsock_print_connection(int fd) | |
| { | |
| struct sockaddr_vm vm_addr; | |
| socklen_t addr_len; | |
| int cid, port; | |
| addr_len = sizeof(vm_addr); | |
| if (getpeername(fd, (struct sockaddr *)&vm_addr, &addr_len)) | |
| return -1; | |
| if (vm_addr.svm_family != AF_VSOCK) | |
| return -1; | |
| cid = vm_addr.svm_cid; | |
| port = vm_addr.svm_port; | |
| if (tracecmd_get_debug()) | |
| tracecmd_debug("Connected to @%u:%u fd:%d\n", cid, port, fd); | |
| else | |
| tracecmd_plog("Connected to @%u:%u\n", cid, port); | |
| return 0; | |
| } | |
| static int try_splice_read_vsock(void) | |
| { | |
| int ret, sd, brass[2]; | |
| sd = socket(AF_VSOCK, SOCK_STREAM, 0); | |
| if (sd < 0) | |
| return -errno; | |
| ret = pipe(brass); | |
| if (ret < 0) | |
| goto out_close_sd; | |
| /* | |
| * On kernels that don't support splice reading from vsockets | |
| * this will fail with EINVAL, or ENOTCONN otherwise. | |
| * Technically, it should never succeed but if it does, claim splice | |
| * reading is supported. | |
| */ | |
| ret = splice(sd, NULL, brass[1], NULL, 10, 0); | |
| if (ret < 0) | |
| ret = errno != EINVAL; | |
| else | |
| ret = 1; | |
| close(brass[0]); | |
| close(brass[1]); | |
| out_close_sd: | |
| close(sd); | |
| return ret; | |
| } | |
| bool __hidden tcmd_vsock_can_splice_read(void) | |
| { | |
| static bool initialized, res; | |
| if (initialized) | |
| return res; | |
| res = try_splice_read_vsock() > 0; | |
| initialized = true; | |
| return res; | |
| } | |
| #define GET_LOCAL_CID 0x7b9 | |
| int __hidden tcmd_vsock_local_cid(void) | |
| { | |
| int cid; | |
| int fd; | |
| fd = open("/dev/vsock", O_RDONLY); | |
| if (fd < 0) | |
| return -errno; | |
| if (ioctl(fd, GET_LOCAL_CID, &cid)) | |
| cid = -errno; | |
| close(fd); | |
| return cid; | |
| } |