mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
225 lines
6.2 KiB
C
225 lines
6.2 KiB
C
/* source: xio-vsock.c */
|
|
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
|
|
/* Author: Stefano Garzarella <sgarzare@redhat.com */
|
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
|
|
|
/* This file contains the source for opening addresses of VSOCK socket type */
|
|
|
|
#include "xiosysincludes.h"
|
|
|
|
#ifdef WITH_VSOCK
|
|
#include "xioopen.h"
|
|
#include "xio-listen.h"
|
|
#include "xio-socket.h"
|
|
#include "xio-vsock.h"
|
|
|
|
static int xioopen_vsock_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, const struct addrdesc *addrdesc);
|
|
static int xioopen_vsock_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, const struct addrdesc *addrdesc);
|
|
|
|
static void xiolog_vsock_cid(void);
|
|
|
|
const struct addrdesc xioaddr_vsock_connect = { "VSOCK-CONNECT", 1+XIO_RDWR, xioopen_vsock_connect, GROUP_FD|GROUP_SOCKET|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<cid>:<port>") };
|
|
#if WITH_LISTEN
|
|
const struct addrdesc xioaddr_vsock_listen = { "VSOCK-LISTEN", 1+XIO_RDWR, xioopen_vsock_listen, GROUP_FD|GROUP_SOCKET|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<port>") };
|
|
#endif /* WITH_LISTEN */
|
|
|
|
|
|
/* Initializes a sockaddr of type VSOCK */
|
|
static int vsock_addr_init(struct sockaddr_vm *sa, const char *cid_str,
|
|
const char *port_str, int pf) {
|
|
int ret;
|
|
|
|
memset(sa, 0, sizeof(*sa));
|
|
|
|
sa->svm_family = pf;
|
|
ret = sockaddr_vm_parse(sa, cid_str, port_str);
|
|
if (ret < 0)
|
|
return STAT_NORETRY;
|
|
|
|
return STAT_OK;
|
|
}
|
|
|
|
|
|
/* Performs a few steps during opening an address of type VSOCK */
|
|
static int vsock_init(struct opt *opts, struct single *sfd) {
|
|
|
|
sfd->howtoend = END_SHUTDOWN;
|
|
|
|
if (applyopts_single(sfd, opts, PH_INIT) < 0)
|
|
return STAT_NORETRY;
|
|
|
|
applyopts(sfd, -1, opts, PH_INIT);
|
|
applyopts(sfd, -1, opts, PH_EARLY);
|
|
|
|
sfd->dtype = XIODATA_STREAM;
|
|
|
|
return STAT_OK;
|
|
}
|
|
|
|
static int xioopen_vsock_connect(
|
|
int argc,
|
|
const char *argv[],
|
|
struct opt *opts,
|
|
int xioflags,
|
|
xiofile_t *xxfd,
|
|
const struct addrdesc *addrdesc)
|
|
{
|
|
/* we expect the form :cid:port */
|
|
struct single *sfd = &xxfd->stream;
|
|
struct sockaddr_vm sa, sa_local;
|
|
socklen_t sa_len = sizeof(sa);
|
|
bool needbind = false;
|
|
int socktype = SOCK_STREAM;
|
|
int pf = PF_VSOCK;
|
|
int protocol = 0;
|
|
int ret;
|
|
|
|
if (argc != 3) {
|
|
xio_syntax(argv[0], 2, argc-1, addrdesc->syntax);
|
|
return STAT_NORETRY;
|
|
}
|
|
|
|
retropt_socket_pf(opts, &pf);
|
|
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
|
retropt_int(opts, OPT_SO_PROTOTYPE, &protocol);
|
|
|
|
ret = vsock_addr_init(&sa, argv[1], argv[2], pf);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
ret = vsock_init(opts, sfd);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
xiolog_vsock_cid();
|
|
|
|
ret = retropt_bind(opts, pf, socktype, protocol,
|
|
(struct sockaddr *)&sa_local, &sa_len, 3,
|
|
sfd->para.socket.ip.ai_flags);
|
|
if (ret == STAT_NORETRY)
|
|
return ret;
|
|
if (ret == STAT_OK)
|
|
needbind = true;
|
|
|
|
ret = xioopen_connect(sfd, needbind ? (union sockaddr_union *)&sa_local : NULL,
|
|
sa_len, (struct sockaddr *)&sa, sizeof(sa),
|
|
opts, pf, socktype, protocol, false);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = _xio_openlate(sfd, opts);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return STAT_OK;
|
|
}
|
|
|
|
|
|
#if WITH_LISTEN
|
|
static int xioopen_vsock_listen(
|
|
int argc,
|
|
const char *argv[],
|
|
struct opt *opts,
|
|
int xioflags,
|
|
xiofile_t *xxfd,
|
|
const struct addrdesc *addrdesc)
|
|
{
|
|
/* we expect the form :port */
|
|
struct single *sfd = &xxfd->stream;
|
|
struct sockaddr_vm sa, sa_bind;
|
|
socklen_t sa_len = sizeof(sa_bind);
|
|
struct opt *opts0;
|
|
int socktype = SOCK_STREAM;
|
|
int pf = PF_VSOCK;
|
|
int protocol = 0;
|
|
int ret;
|
|
|
|
if (argc != 2) {
|
|
xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
|
|
return STAT_NORETRY;
|
|
}
|
|
|
|
retropt_socket_pf(opts, &pf);
|
|
retropt_int(opts, OPT_SO_TYPE, &socktype);
|
|
retropt_int(opts, OPT_SO_PROTOTYPE, &protocol);
|
|
|
|
ret = vsock_addr_init(&sa, NULL, argv[1], pf);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
ret = vsock_init(opts, sfd);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
opts0 = copyopts(opts, GROUP_ALL);
|
|
|
|
ret = retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&sa_bind,
|
|
&sa_len, 1,
|
|
sfd->para.socket.ip.ai_flags);
|
|
if (ret == STAT_NORETRY)
|
|
return ret;
|
|
if (ret == STAT_OK)
|
|
sa.svm_cid = sa_bind.svm_cid;
|
|
|
|
xiolog_vsock_cid();
|
|
|
|
/* this may fork() */
|
|
return xioopen_listen(sfd, xioflags, (struct sockaddr *)&sa, sizeof(sa),
|
|
opts, opts0, pf, socktype, protocol);
|
|
}
|
|
#endif /* WITH_LISTEN */
|
|
|
|
|
|
/* Just tries to query and log the VSOCK CID */
|
|
static void xiolog_vsock_cid(void) {
|
|
int vsock;
|
|
unsigned int cid;
|
|
#ifdef IOCTL_VM_SOCKETS_GET_LOCAL_CID
|
|
if ((vsock = Open("/dev/vsock", O_RDONLY, 0)) < 0 ) {
|
|
Warn1("open(\"/dev/vsock\", ...): %s", strerror(errno));
|
|
} else if (Ioctl(vsock, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &cid) < 0) {
|
|
Warn2("ioctl(%d, IOCTL_VM_SOCKETS_GET_LOCAL_CID, ...): %s",
|
|
vsock, strerror(errno));
|
|
} else {
|
|
Notice1("VSOCK CID=%u", cid);
|
|
}
|
|
if (vsock >= 0) {
|
|
Close(vsock);
|
|
}
|
|
#endif /* IOCTL_VM_SOCKETS_GET_LOCAL_CID */
|
|
return;
|
|
}
|
|
|
|
|
|
/* Returns information that can be used for constructing an environment
|
|
variable describing the socket address.
|
|
if idx is 0, this function writes "ADDR" into namebuff and the CID address
|
|
into valuebuff, and returns 1 (which means that one more info is there).
|
|
if idx is 1, it writes "PORT" into namebuff and the port number into
|
|
valuebuff, and returns 0 (no more info)
|
|
namelen and valuelen contain the max. allowed length of output chars in the
|
|
respective buffer.
|
|
on error this function returns -1.
|
|
*/
|
|
int
|
|
xiosetsockaddrenv_vsock(int idx, char *namebuff, size_t namelen,
|
|
char *valuebuff, size_t valuelen,
|
|
struct sockaddr_vm *sa, int ipproto) {
|
|
switch (idx) {
|
|
case 0:
|
|
strcpy(namebuff, "ADDR");
|
|
snprintf(valuebuff, valuelen, F_uint32_t, sa->svm_cid);
|
|
return 1;
|
|
case 1:
|
|
strcpy(namebuff, "PORT");
|
|
snprintf(valuebuff, valuelen, F_uint32_t, sa->svm_port);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#endif /* WITH_VSOCK */
|