Version 1.8.0.0
[socat.git] / xio-vsock.c
blobfcd09bcbeafe3ff143dd3dd5b7c3ee578a6df580
1 /* source: xio-vsock.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Author: Stefano Garzarella <sgarzare@redhat.com */
4 /* Published under the GNU General Public License V.2, see file COPYING */
6 /* This file contains the source for opening addresses of VSOCK socket type */
8 #include "xiosysincludes.h"
10 #ifdef WITH_VSOCK
11 #include "xioopen.h"
12 #include "xio-listen.h"
13 #include "xio-socket.h"
14 #include "xio-vsock.h"
16 static int xioopen_vsock_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, const struct addrdesc *addrdesc);
17 static int xioopen_vsock_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, const struct addrdesc *addrdesc);
19 static void xiolog_vsock_cid(void);
21 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>") };
22 #if WITH_LISTEN
23 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>") };
24 #endif /* WITH_LISTEN */
27 /* Initializes a sockaddr of type VSOCK */
28 static int vsock_addr_init(struct sockaddr_vm *sa, const char *cid_str,
29 const char *port_str, int pf) {
30 int ret;
32 memset(sa, 0, sizeof(*sa));
34 sa->svm_family = pf;
35 ret = sockaddr_vm_parse(sa, cid_str, port_str);
36 if (ret < 0)
37 return STAT_NORETRY;
39 return STAT_OK;
43 /* Performs a few steps during opening an address of type VSOCK */
44 static int vsock_init(struct opt *opts, struct single *sfd) {
46 if (sfd->howtoend == END_UNSPEC)
47 sfd->howtoend = END_SHUTDOWN;
49 if (applyopts_single(sfd, opts, PH_INIT) < 0)
50 return STAT_NORETRY;
52 applyopts(sfd, -1, opts, PH_INIT);
53 applyopts(sfd, -1, opts, PH_EARLY);
55 sfd->dtype = XIODATA_STREAM;
57 return STAT_OK;
60 static int xioopen_vsock_connect(
61 int argc,
62 const char *argv[],
63 struct opt *opts,
64 int xioflags,
65 xiofile_t *xxfd,
66 const struct addrdesc *addrdesc)
68 /* we expect the form :cid:port */
69 struct single *sfd = &xxfd->stream;
70 struct sockaddr_vm sa, sa_local;
71 socklen_t sa_len = sizeof(sa);
72 bool needbind = false;
73 int socktype = SOCK_STREAM;
74 int pf = PF_VSOCK;
75 int protocol = 0;
76 int ret;
78 if (argc != 3) {
79 xio_syntax(argv[0], 2, argc-1, addrdesc->syntax);
80 return STAT_NORETRY;
83 retropt_socket_pf(opts, &pf);
84 retropt_int(opts, OPT_SO_TYPE, &socktype);
85 retropt_int(opts, OPT_SO_PROTOTYPE, &protocol);
87 ret = vsock_addr_init(&sa, argv[1], argv[2], pf);
88 if (ret) {
89 return ret;
92 ret = vsock_init(opts, sfd);
93 if (ret) {
94 return ret;
97 xiolog_vsock_cid();
99 ret = retropt_bind(opts, pf, socktype, protocol,
100 (struct sockaddr *)&sa_local, &sa_len, 3,
101 sfd->para.socket.ip.ai_flags);
102 if (ret == STAT_NORETRY)
103 return ret;
104 if (ret == STAT_OK)
105 needbind = true;
107 ret = xioopen_connect(sfd, needbind ? (union sockaddr_union *)&sa_local : NULL,
108 sa_len, (struct sockaddr *)&sa, sizeof(sa),
109 opts, pf, socktype, protocol, false);
110 if (ret)
111 return ret;
113 ret = _xio_openlate(sfd, opts);
114 if (ret < 0)
115 return ret;
117 return STAT_OK;
121 #if WITH_LISTEN
122 static int xioopen_vsock_listen(
123 int argc,
124 const char *argv[],
125 struct opt *opts,
126 int xioflags,
127 xiofile_t *xxfd,
128 const struct addrdesc *addrdesc)
130 /* we expect the form :port */
131 struct single *sfd = &xxfd->stream;
132 struct sockaddr_vm sa, sa_bind;
133 socklen_t sa_len = sizeof(sa_bind);
134 struct opt *opts0;
135 int socktype = SOCK_STREAM;
136 int pf = PF_VSOCK;
137 int protocol = 0;
138 int ret;
140 if (argc != 2) {
141 xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
142 return STAT_NORETRY;
145 retropt_socket_pf(opts, &pf);
146 retropt_int(opts, OPT_SO_TYPE, &socktype);
147 retropt_int(opts, OPT_SO_PROTOTYPE, &protocol);
149 ret = vsock_addr_init(&sa, NULL, argv[1], pf);
150 if (ret) {
151 return ret;
154 ret = vsock_init(opts, sfd);
155 if (ret) {
156 return ret;
159 opts0 = copyopts(opts, GROUP_ALL);
161 ret = retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&sa_bind,
162 &sa_len, 1,
163 sfd->para.socket.ip.ai_flags);
164 if (ret == STAT_NORETRY)
165 return ret;
166 if (ret == STAT_OK)
167 sa.svm_cid = sa_bind.svm_cid;
169 xiolog_vsock_cid();
171 /* this may fork() */
172 return xioopen_listen(sfd, xioflags, (struct sockaddr *)&sa, sizeof(sa),
173 opts, opts0, pf, socktype, protocol);
175 #endif /* WITH_LISTEN */
178 /* Just tries to query and log the VSOCK CID */
179 static void xiolog_vsock_cid(void) {
180 int vsock;
181 unsigned int cid;
182 #ifdef IOCTL_VM_SOCKETS_GET_LOCAL_CID
183 if ((vsock = Open("/dev/vsock", O_RDONLY, 0)) < 0 ) {
184 Warn1("open(\"/dev/vsock\", ...): %s", strerror(errno));
185 } else if (Ioctl(vsock, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &cid) < 0) {
186 Warn2("ioctl(%d, IOCTL_VM_SOCKETS_GET_LOCAL_CID, ...): %s",
187 vsock, strerror(errno));
188 } else {
189 Notice1("VSOCK CID=%u", cid);
191 if (vsock >= 0) {
192 Close(vsock);
194 #endif /* IOCTL_VM_SOCKETS_GET_LOCAL_CID */
195 return;
199 /* Returns information that can be used for constructing an environment
200 variable describing the socket address.
201 if idx is 0, this function writes "ADDR" into namebuff and the CID address
202 into valuebuff, and returns 1 (which means that one more info is there).
203 if idx is 1, it writes "PORT" into namebuff and the port number into
204 valuebuff, and returns 0 (no more info)
205 namelen and valuelen contain the max. allowed length of output chars in the
206 respective buffer.
207 on error this function returns -1.
210 xiosetsockaddrenv_vsock(int idx, char *namebuff, size_t namelen,
211 char *valuebuff, size_t valuelen,
212 struct sockaddr_vm *sa, int ipproto) {
213 switch (idx) {
214 case 0:
215 strcpy(namebuff, "ADDR");
216 snprintf(valuebuff, valuelen, F_uint32_t, sa->svm_cid);
217 return 1;
218 case 1:
219 strcpy(namebuff, "PORT");
220 snprintf(valuebuff, valuelen, F_uint32_t, sa->svm_port);
221 return 0;
223 return -1;
226 #endif /* WITH_VSOCK */