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