This commit was manufactured by cvs2svn to create branch 'rd235'.
[vde.git] / vde / qemu / vdeq.c
blobbafe37313bdde30cd86e18a4ccb3176c10d4de15
1 /* Copyright 2003 Renzo Davoli
2 * Licensed under the GPL
3 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <errno.h>
9 #include <unistd.h>
10 #include <stdint.h>
11 #include <libgen.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15 #include <sys/uio.h>
16 #include <sys/poll.h>
17 #include "vde.h"
19 #define SWITCH_MAGIC 0xfeedface
20 #define BUFSIZE 2048
21 #define ETH_ALEN 6
23 enum request_type { REQ_NEW_CONTROL };
25 struct request_v3 {
26 uint32_t magic;
27 uint32_t version;
28 enum request_type type;
29 struct sockaddr_un sock;
33 static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int intno, int group)
35 int pid = getpid();
36 struct request_v3 req;
37 int fdctl;
39 struct sockaddr_un sock;
41 if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
42 perror("socket");
43 exit(1);
46 sock.sun_family = AF_UNIX;
47 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
48 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
49 perror("connect");
50 exit(1);
53 req.magic=SWITCH_MAGIC;
54 req.version=3;
55 req.type=REQ_NEW_CONTROL+((group > 0)?((geteuid()<<8) + group) << 8:0);
57 req.sock.sun_family=AF_UNIX;
58 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
59 sprintf(&req.sock.sun_path[1], "%5d-%2d", pid, intno);
61 if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0){
62 perror("bind");
63 exit(1);
66 if (send(fdctl,&req,sizeof(req),0) < 0) {
67 perror("send");
68 exit(1);
71 if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0)<0) {
72 perror("recv");
73 exit(1);
76 return fdctl;
79 unsigned char bufin[BUFSIZE];
81 //struct pollfd pollv[]={{STDIN_FILENO,POLLIN|POLLHUP,0},{0,POLLIN|POLLHUP,0}};
82 struct pollfd *pollv;
84 char *filename;
85 char *vdeqname;
86 char *numfd;
87 #define NUMW 10
89 static int countnics(const char *s)
91 register int nics=1;
92 while (*s) {
93 if (*s==',') nics++;
94 s++;
96 return nics;
99 static void usage()
101 if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0)
102 fprintf(stderr,"Usage: %s [-h]\n"
103 "\t %s [-vdesock sock1 [,sock2...]] qemu_options\n"
104 "\t (%s executes a qemu machine named %s)\n", vdeqname,vdeqname,vdeqname,filename);
105 else
106 fprintf(stderr,"Usage: %s [-h]\n"
107 "\t %s qemu_executable [-vdesock sock1 [,sock2...]] qemu_options\n", vdeqname, vdeqname);
108 exit(0);
111 static void leave()
113 fprintf(stderr,"qemu exited: %s quits\n", vdeqname);
114 exit(0);
117 int main(int argc, char **argv)
119 int *fddata;
120 char *argsock,**sockname;
121 struct sockaddr_un *dataout,datain;
122 int datainsize;
123 int result;
124 int group=0;
125 int *connected_fd;
126 register ssize_t nx;
127 int args;
128 int newargc;
129 char **newargv;
130 typedef int pair[2];
131 pair *sp;
132 register int i;
133 int nb_nics;
135 vdeqname=basename(argv[0]);
136 if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0) {
137 filename=vdeqname+3;
138 args=1;
140 else if (argc > 1) {
141 filename=argv[1];
142 args=2;
143 } else {
144 usage();
146 if ((argc > args && (
147 strcmp(argv[args],"-h")==0 ||
148 strcmp(argv[args],"-help")==0 ||
149 strcmp(argv[args],"--help")==0
150 )) || (
151 strcmp(filename,"-h")==0 ||
152 strcmp(filename,"-help")==0 ||
153 strcmp(filename,"--help")==0
154 )) {
155 usage();
156 } else if (argc > args+1 && strcmp(argv[args],"-vdesock")==0) {
157 argsock=argv[args+1];
158 args+=2;
159 } else
160 argsock=strdup(VDESTDSOCK);
162 nb_nics=countnics(argsock);
163 if ((sp= (pair *) malloc(nb_nics * 2 * sizeof (int)))<0) {
164 perror("malloc nics");
165 exit(1);
167 if ((numfd= (char *) malloc(nb_nics * NUMW * sizeof (char)))<0) {
168 perror("malloc numfd");
169 exit(1);
172 for (i=0; i<nb_nics; i++) {
173 char curfd[NUMW];
174 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp[i]) < 0){
175 perror("socketpair");
176 exit(1);
178 snprintf(curfd,NUMW,"%d%c",sp[i][0],(i<nb_nics-1)?',':0);
179 strcat(numfd,curfd);
182 if ((sockname= (char **) malloc(sizeof(char *) * nb_nics))<0) {
183 perror("malloc sockname");
184 exit(1);
188 register char *s=argsock;
189 register char oldch;
190 i=0;
191 do {
192 sockname[i++]=s;
193 while (*s != ',' && *s != '\0')
194 s++;
195 oldch=*s;
196 *s=0;
197 s++;
198 } while (oldch != 0);
201 /* printf("-- %s --\n",numfd);
202 printf("as %s\n",argsock);
203 for (i=0; i<nb_nics; i++)
204 printf("%d -> %s\n",i,sockname[i]); */
205 newargc=argc+3-args;
206 if ((newargv=(char **) malloc ((newargc+1)* sizeof(char *))) <0) {
207 perror("malloc");
208 exit(1);
211 newargv[0]=filename;
212 newargv[1]="-tun-fd";
213 newargv[2]=numfd;
215 for (i=3;args<argc;i++,args++) newargv[i]=argv[args];
217 newargv[i]=0;
219 if ((fddata= (int *) malloc(sizeof(int) * nb_nics))<0) {
220 perror("malloc fddata");
221 exit(1);
223 if ((connected_fd= (int *) malloc(sizeof(int) * nb_nics))<0) {
224 perror("malloc connected_fd");
225 exit(1);
227 if ((dataout= (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un) * nb_nics))<0) {
228 perror("malloc dataout");
229 exit(1);
232 if ((pollv= (struct pollfd *) malloc(sizeof(struct pollfd) * 2 * nb_nics))<0) {
233 perror("malloc fddata");
234 exit(1);
236 for (i=0; i<nb_nics; i++) {
237 if((fddata[i] = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
238 perror("socket");
239 exit(1);
241 connected_fd[i]=send_fd(sockname[i], fddata[i], &(dataout[i]), i, group);
242 pollv[2*i+1].fd=fddata[i];
243 pollv[2*i].fd=sp[i][1];
244 pollv[2*i].events= pollv[2*i+1].events=POLLIN|POLLHUP;
247 if (fork()) {
248 close(0);
249 signal(SIGCHLD, leave);
250 for (i=0; i<nb_nics; i++)
251 close(sp[i][0]);
252 for(;;) {
253 result=poll(pollv,2*nb_nics,-1);
254 for (i=0; i<nb_nics; i++) {
255 if (pollv[2*i].revents & POLLHUP || pollv[2*i+1].revents & POLLHUP)
256 break;
257 if (pollv[2*i].revents & POLLIN) {
258 nx=read(sp[i][1],bufin,sizeof(bufin));
259 //fprintf(stderr,"RX from qemu %d\n",nx);
260 //send(connected_fd,bufin,nx,0);
261 sendto(fddata[i],bufin,nx,0,(struct sockaddr *) &(dataout[i]), sizeof(struct sockaddr_un));
263 if (pollv[2*i+1].revents & POLLIN) {
264 nx=recvfrom(fddata[i],bufin,BUFSIZE,0,(struct sockaddr *) &datain, &datainsize);
265 //fprintf(stderr,"TX to qemu %d\n",nx);
266 write(sp[i][1],bufin,nx);
270 } else {
271 for (i=0; i<nb_nics; i++) {
272 close(sp[i][1]);
273 close(fddata[i]);
274 close(connected_fd[i]);
276 execvp(filename,newargv);
278 return(0);