fix dependency
[sliver-openvswitch.git] / planetlab / vsysc / vsysc.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <sys/select.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8
9 #define VSYS_PATH "/vsys"
10
11 #define MAXPATH 1024
12 #define BUFSIZE 4096
13
14 #define IN 0
15 #define OUT 1
16
17 char ctrl[2][MAXPATH]; /* paths of vsys.in & vsys.out */
18
19 static void mkpath(int dir, const char* vsys)
20 {
21         static const char *suffix[] = { "in", "out" };
22         int n;
23
24         if ( (n = snprintf(ctrl[dir], MAXPATH, "%s/%s.%s", VSYS_PATH, vsys, suffix[dir])) < 0) {
25                 perror(vsys);
26                 exit(EXIT_FAILURE);
27         } else if (n >= MAXPATH) {
28                 fprintf(stderr, "argument too long\n");
29                 exit(EXIT_FAILURE);
30         }
31 }
32
33 static int open_ctrl(int dir)
34 {
35         int fd;
36         
37         if ( (fd = open(ctrl[dir], (dir == IN ? O_WRONLY : O_RDONLY) | O_NONBLOCK)) < 0) {
38                 perror(ctrl[dir]);
39                 exit(EXIT_FAILURE);
40         }
41         return fd;
42 }
43
44
45 static void set_nonblocking(int fd)
46 {
47         int val;
48
49         if ( (val = fcntl(fd, F_GETFL, 0)) < 0) {
50                 perror("fcntl F_GETFL");
51                 exit(EXIT_FAILURE);
52         }
53         if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) {
54                 perror("fcntl F_SETFL");
55                 exit(EXIT_FAILURE);
56         }
57 }
58
59 #if 0
60 static void print_set(const char* name, int max, const fd_set* set)
61 {
62         int i, n = 0;
63         fprintf(stderr, "%s: {", name);
64         for (i = 0; i < max; i++) {
65                 if (FD_ISSET(i, set)) {
66                         if (n++) fprintf(stderr, ", ");
67                         fprintf(stderr, "%d", i);
68                 }
69         }
70         fprintf(stderr, "}\n");
71 }
72 #endif
73
74 struct channel {
75         const char *name;
76         int active;
77         int writing;
78         char buf[BUFSIZE];
79         char *rp, *wp;
80         int rfd, wfd;
81 };
82
83 static int active_channels = 0;
84
85 static void channel_init(struct channel *c, const char* name, int rfd, int wfd)
86 {
87         c->name = name;
88         c->rp = c->buf;
89         c->wp = c->buf;
90         c->rfd = rfd;
91         c->wfd = wfd;
92         c->active = 1;
93         active_channels++;
94 }
95
96 static void channel_fdset(struct channel *c, fd_set* readset, fd_set* writeset)
97 {
98         if (!c->active)
99                 return;
100         if (c->writing) {
101                 FD_SET(c->wfd, writeset);
102         } else {
103                 FD_SET(c->rfd, readset);
104         } 
105 }
106
107 static void channel_run(struct channel *c, const fd_set* readset, const fd_set* writeset)
108 {
109         int n;
110
111         if (!c->active)
112                 return;
113         if (c->writing) {
114                 if (FD_ISSET(c->wfd, writeset)) {
115                         if ( (n = write(c->wfd, c->wp, c->rp - c->wp)) < 0) {
116                                 perror(c->name);
117                                 exit(EXIT_FAILURE);
118                         }
119                         c->wp += n;
120                         if (c->wp == c->rp) {
121                                 c->wp = c->rp = c->buf;
122                                 c->writing = 0;
123                         } 
124                 }
125         } else {
126                 if (FD_ISSET(c->rfd, readset)) {
127                         if ( (n = read(c->rfd, c->rp, BUFSIZE)) < 0) {
128                                 perror(c->name);
129                                 exit(EXIT_FAILURE);
130                         }
131                         if (n) {
132                                 c->wp = c->rp;
133                                 c->rp += n;
134                                 c->writing = 1;
135                         } else {
136                                 close(c->wfd);
137                                 c->active = 0;
138                                 active_channels--;
139                         }
140                 }
141         }
142 }
143
144 static struct channel channels[2];
145
146
147 int main(int argc, char *argv[])
148 {
149         int fd[2]; /* fds of vsys.in & vsys.out */
150         int maxfd;
151
152         fd_set readset, writeset;
153
154         if (argc != 2) {
155                 fprintf(stderr, "Usage: %s <vsys>\n", argv[0]);
156                 exit(EXIT_FAILURE);
157         }
158
159         mkpath(IN,  argv[1]);
160         mkpath(OUT, argv[1]);
161
162         maxfd = (STDOUT_FILENO > STDIN_FILENO ? STDOUT_FILENO : STDIN_FILENO);
163
164         fd[OUT] = open_ctrl(OUT);
165         if (fd[OUT] > maxfd)
166                 maxfd = fd[OUT];
167         fd[IN]  = open_ctrl(IN);
168         if (fd[IN] > maxfd)
169                 maxfd = fd[IN];
170
171         set_nonblocking(STDIN_FILENO);
172         set_nonblocking(STDOUT_FILENO);
173
174         channel_init(&channels[IN], "IN", STDIN_FILENO, fd[IN]);
175         channel_init(&channels[OUT], "OUT", fd[OUT], STDOUT_FILENO);
176
177         while (active_channels) {
178                 FD_ZERO(&readset);
179                 FD_ZERO(&writeset);
180                 channel_fdset(&channels[IN], &readset, &writeset);
181                 channel_fdset(&channels[OUT], &readset, &writeset);
182                 if (select(maxfd + 1, &readset, &writeset, NULL, NULL) < 0) {
183                         perror("select");
184                         exit(EXIT_FAILURE);
185                 }
186                 channel_run(&channels[IN], &readset, &writeset);
187                 channel_run(&channels[OUT], &readset, &writeset);
188         }
189         return EXIT_SUCCESS;
190 }
191