1 /**
2 * @file
3 * @section AUTHORS
4 *
5 * Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
6 *
7 * Authors:
8 * Rafal Wojtczuk <rafal@invisiblethingslab.com>
9 * Daniel De Graaf <dgdegra@tycho.nsa.gov>
10 *
11 * @section LICENSE
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this program; If not, see <http://www.gnu.org/licenses/>.
25 *
26 * @section DESCRIPTION
27 *
28 * This is a test program for libxenvchan. Communications are bidirectional,
29 * with either server (grant offeror) or client able to read and write.
30 */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <errno.h>
38
39 #include <libxenvchan.h>
40
usage(char ** argv)41 static void usage(char** argv)
42 {
43 fprintf(stderr, "usage:\n"
44 "\t%s [client|server] domainid nodepath [rbufsiz wbufsiz]\n",
45 argv[0]);
46 exit(1);
47 }
48
49 #define BUFSIZE 5000
50 char inbuf[BUFSIZE];
51 char outbuf[BUFSIZE];
52 int insiz = 0;
53 int outsiz = 0;
54 struct libxenvchan *ctrl = 0;
55
vchan_wr(void)56 static void vchan_wr(void) {
57 int ret;
58
59 if (!insiz)
60 return;
61 ret = libxenvchan_write(ctrl, inbuf, insiz);
62 if (ret < 0) {
63 fprintf(stderr, "vchan write failed\n");
64 exit(1);
65 }
66 if (ret > 0) {
67 insiz -= ret;
68 memmove(inbuf, inbuf + ret, insiz);
69 }
70 }
71
stdout_wr(void)72 static void stdout_wr(void) {
73 int ret;
74
75 if (!outsiz)
76 return;
77 ret = write(1, outbuf, outsiz);
78 if (ret < 0 && errno != EAGAIN)
79 exit(1);
80 if (ret > 0) {
81 outsiz -= ret;
82 memmove(outbuf, outbuf + ret, outsiz);
83 }
84 }
85
set_nonblocking(int fd,int nonblocking)86 static int set_nonblocking(int fd, int nonblocking) {
87 int flags = fcntl(fd, F_GETFL);
88 if (flags == -1)
89 return -1;
90
91 if (nonblocking)
92 flags |= O_NONBLOCK;
93 else
94 flags &= ~O_NONBLOCK;
95
96 if (fcntl(fd, F_SETFL, flags) == -1)
97 return -1;
98
99 return 0;
100 }
101
102 /**
103 Simple libxenvchan application, both client and server.
104 Both sides may write and read, both from the libxenvchan and from
105 stdin/stdout (just like netcat).
106 */
107
main(int argc,char ** argv)108 int main(int argc, char **argv)
109 {
110 int ret;
111 int libxenvchan_fd;
112 if (argc < 4 || argv[3][0] != '/')
113 usage(argv);
114 if (!strcmp(argv[1], "server")) {
115 int rsiz = argc > 4 ? atoi(argv[4]) : 0;
116 int wsiz = argc > 5 ? atoi(argv[5]) : 0;
117 ctrl = libxenvchan_server_init(NULL, atoi(argv[2]), argv[3], rsiz, wsiz);
118 } else if (!strcmp(argv[1], "client"))
119 ctrl = libxenvchan_client_init(NULL, atoi(argv[2]), argv[3]);
120 else
121 usage(argv);
122 if (!ctrl) {
123 perror("libxenvchan_*_init");
124 exit(1);
125 }
126
127 if (set_nonblocking(0, 1) || set_nonblocking(1, 1)) {
128 perror("set_nonblocking");
129 exit(1);
130 }
131
132 libxenvchan_fd = libxenvchan_fd_for_select(ctrl);
133 for (;;) {
134 fd_set rfds;
135 fd_set wfds;
136 FD_ZERO(&rfds);
137 FD_ZERO(&wfds);
138 if (insiz != BUFSIZE)
139 FD_SET(0, &rfds);
140 if (outsiz)
141 FD_SET(1, &wfds);
142 FD_SET(libxenvchan_fd, &rfds);
143 ret = select(libxenvchan_fd + 1, &rfds, &wfds, NULL, NULL);
144 if (ret < 0) {
145 perror("select");
146 exit(1);
147 }
148 if (FD_ISSET(0, &rfds)) {
149 ret = read(0, inbuf + insiz, BUFSIZE - insiz);
150 if (ret < 0 && errno != EAGAIN)
151 exit(1);
152 if (ret == 0) {
153 while (insiz) {
154 vchan_wr();
155 libxenvchan_wait(ctrl);
156 }
157 return 0;
158 }
159 if (ret)
160 insiz += ret;
161 vchan_wr();
162 }
163 if (FD_ISSET(libxenvchan_fd, &rfds)) {
164 libxenvchan_wait(ctrl);
165 vchan_wr();
166 }
167 if (FD_ISSET(1, &wfds))
168 stdout_wr();
169 while (libxenvchan_data_ready(ctrl) && outsiz < BUFSIZE) {
170 ret = libxenvchan_read(ctrl, outbuf + outsiz, BUFSIZE - outsiz);
171 if (ret < 0)
172 exit(1);
173 outsiz += ret;
174 stdout_wr();
175 }
176 if (!libxenvchan_is_open(ctrl)) {
177 if (set_nonblocking(1, 0)) {
178 perror("set_nonblocking");
179 exit(1);
180 }
181 while (outsiz)
182 stdout_wr();
183 return 0;
184 }
185 }
186 }
187