1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
#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 trace_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 trace_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 trace_vsock_make_any(void)
{
return trace_vsock_make(VMADDR_PORT_ANY);
}
int __hidden trace_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 trace_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 trace_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;
}
|