| /* 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, groups_t groups, int abstract, |
| int dummy2, int dummy3); |
| static int xioopen_vsock_listen(int argc, const char *argv[], struct opt *opts, |
| int xioflags, xiofile_t *xxfd, groups_t groups, int abstract, |
| int dummy2, int dummy3); |
| |
| static void xiolog_vsock_cid(void); |
| |
| const struct addrdesc addr_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 addr_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 *xfd) { |
| |
| xfd->howtoend = END_SHUTDOWN; |
| |
| if (applyopts_single(xfd, opts, PH_INIT) < 0) |
| return STAT_NORETRY; |
| |
| applyopts(-1, opts, PH_INIT); |
| applyopts(-1, opts, PH_EARLY); |
| |
| xfd->dtype = XIODATA_STREAM; |
| |
| return STAT_OK; |
| } |
| |
| static int xioopen_vsock_connect(int argc, const char *argv[], struct opt *opts, |
| int xioflags, xiofile_t *xxfd, groups_t groups, |
| int abstract, int dummy2, int dummy3) { |
| /* we expect the form :cid:port */ |
| struct single *xfd = &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) { |
| Error2("%s: wrong number of parameters (%d instead of 2)", |
| argv[0], argc-1); |
| 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, xfd); |
| if (ret) { |
| return ret; |
| } |
| |
| xiolog_vsock_cid(); |
| |
| ret = retropt_bind(opts, pf, socktype, protocol, |
| (struct sockaddr *)&sa_local, &sa_len, 3, 0, 0); |
| if (ret == STAT_NORETRY) |
| return ret; |
| if (ret == STAT_OK) |
| needbind = true; |
| |
| ret = xioopen_connect(xfd, 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(xfd, 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, groups_t groups, int abstract, |
| int dummy2, int dummy3) { |
| /* we expect the form :port */ |
| struct single *xfd = &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) { |
| Error2("%s: wrong number of parameters (%d instead of 1)", |
| argv[0], argc-1); |
| 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, xfd); |
| if (ret) { |
| return ret; |
| } |
| |
| opts0 = copyopts(opts, GROUP_ALL); |
| |
| ret = retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&sa_bind, |
| &sa_len, 1, 0, 0); |
| 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(xfd, 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 */ |