vdeq cleanup. unused sockets were left in /tmp.
[vde.git] / vde-2 / qemu / vdeq.c
blob0e7e81d533d7cace09cb0c2117d1c6576bfff4b0
1 /* Copyright 2003 Renzo Davoli
2 * TNX: 2005.11.18 new syntax mgmt patch by Iain McFarlane <imcfarla@tiscali.co.uk>
3 * Licensed under the GPL
4 */
6 #include <config.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <errno.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <stdint.h>
14 #include <libgen.h>
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <sys/uio.h>
19 #include <sys/poll.h>
20 #include <pwd.h>
22 #include <vde.h>
24 #define SWITCH_MAGIC 0xfeedface
25 #define BUFSIZE 2048
26 #define ETH_ALEN 6
27 #define MAXDESCR 128
29 enum request_type { REQ_NEW_CONTROL };
31 struct request_v3 {
32 uint32_t magic;
33 uint32_t version;
34 enum request_type type;
35 struct sockaddr_un sock;
36 char description[MAXDESCR];
39 static struct passwd *callerpwd;
41 static int nb_nics;
42 static char** inpath;
44 static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int intno, int port)
46 int pid = getpid();
47 struct request_v3 req;
48 int fdctl;
49 struct sockaddr_un sock;
51 if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
52 perror("socket");
53 exit(1);
56 if (name == NULL)
57 name=VDESTDSOCK;
58 else {
59 char *split;
60 if(name[strlen(name)-1] == ']' && (split=rindex(name,'[')) != NULL) {
61 *split=0;
62 split++;
63 port=atoi(split);
64 if (*name==0) name=VDESTDSOCK;
68 sock.sun_family = AF_UNIX;
69 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s/ctl", name);
70 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
71 if (name == VDESTDSOCK) {
72 name=VDETMPSOCK;
73 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s/ctl", name);
74 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
75 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
76 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
77 perror("connect");
78 exit(1);
84 req.magic=SWITCH_MAGIC;
85 req.version=3;
86 req.type=REQ_NEW_CONTROL+(port << 8);
87 req.sock.sun_family=AF_UNIX;
89 /* First choice, return socket from the switch close to the control dir*/
90 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
91 sprintf(req.sock.sun_path, "%s.%05d-%02d", name, pid, intno);
92 if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0){
93 /* if it is not possible -> /tmp */
94 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
95 sprintf(req.sock.sun_path, "/tmp/vde.%05d-%02d", pid, intno);
96 if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0) {
97 perror("bind");
98 exit(1);
102 snprintf(req.description,MAXDESCR,"vdeqemu user=%s PID=%d SOCK=%s INT=%d",
103 callerpwd->pw_name,pid,req.sock.sun_path,intno);
105 inpath[intno]=strdup(req.sock.sun_path);
107 if (send(fdctl,&req,sizeof(req),0) < 0) {
108 perror("send");
109 exit(1);
112 if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0)<0) {
113 perror("recv");
114 exit(1);
117 return fdctl;
120 unsigned char bufin[BUFSIZE];
122 struct pollfd *pollv;
124 char *filename;
125 char *vdeqname;
126 #define NUMW 10
128 static int countnics(const char *s)
130 register int nics=1;
131 while (*s) {
132 if (*s==',') nics++;
133 s++;
135 return nics;
138 static int countnewnics(int argc,char *argv[])
140 register int nics=0;
141 register int netflag=0;
142 while (argc > 0) {
143 if (strcmp(argv[0],"-net")==0)
144 netflag=1;
145 else {
146 if (netflag && (strncmp(argv[0],"vde",3)==0))
147 nics++;
148 netflag=0;
150 argv++;
151 argc--;
153 return nics;
156 static void usage(void)
158 if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0)
159 fprintf(stderr,"Usage: %s [-h]\n"
160 "\t %s ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
161 "Old syntax:\n"
162 "\t %s [-sock sock1 [,sock2...]] qemu_options\n"
163 "\t (%s executes a qemu machine named %s)\n", vdeqname,vdeqname,vdeqname,vdeqname,filename);
164 else
165 fprintf(stderr,"Usage: %s [-h]\n"
166 "\t %s qemu_executable ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
167 "Old syntax:\n"
168 "\t %s qemu_executable [-sock sock1 [,sock2...]] qemu_options\n", vdeqname,vdeqname, vdeqname);
169 exit(0);
172 static void cleanup()
174 register int i;
175 for (i=0; i<nb_nics; i++) {
176 if (inpath[i] != NULL)
177 unlink(inpath[i]);
181 static void leave(void)
183 fprintf(stderr,"qemu exited: %s quits\n", vdeqname);
184 cleanup();
185 exit(0);
188 static int checkver(char *prog)
190 char *newargv[3];
191 int fd[2];
192 int f,len,version=0;
193 char buf[257];
194 newargv[0]=prog;
195 newargv[1]="-h";
196 newargv[2]=0;
197 buf[256]=0;
198 pipe(fd);
199 if ((f=fork()) > 0) {
200 int status;
201 close(fd[1]);
202 len=read(fd[0],buf,256);
203 if (len>0) {
204 int i;
205 for(i=0;i<len && version==0;i++) {
206 if(strncmp(buf+i,"version ",8)==0) {
207 int v1,v2,v3;
208 sscanf(buf+i+8,"%d.%d.%d",&v1,&v2,&v3);
209 version=(v1 << 16) + (v2 << 8) + v3;
213 waitpid(f,&status,0);
214 close(fd[0]);
216 else if (f==0) {
217 close(fd[0]);
218 dup2(fd[1],1);
219 dup2(fd[1],2);
220 close(fd[1]);
221 if (execvp(prog,newargv) < 0) {
222 exit(1);
225 return version;
228 static char *parsevdearg(char *arg,char **sock,int *pport, int fd)
230 char newarg[128];
231 int vlan=0;
232 *sock=VDESTDSOCK;
233 while (*arg==',') arg++;
234 if (strncmp(arg,"vlan=",5)==0) {
235 vlan=atoi(arg+5);
236 while (*arg != 0 && *arg != ',')
237 arg++;
239 while (*arg==',') arg++;
240 if (strncmp(arg,"sock=",5)==0) {
241 arg+=5;
242 if (*arg=='\"') {
243 arg++;
244 *sock=arg;
245 while (*arg != 0 && *arg != '\"')
246 arg++;
247 } else {
248 *sock=arg;
249 while (*arg != 0 && *arg != ',')
250 arg++;
252 if (*arg != 0) {
253 *arg=0; arg++;
256 while (*arg==',') arg++;
257 if (strncmp(arg,"port=",5)==0) {
258 *pport=atoi(arg+5);
259 while (*arg != 0 && *arg != ',')
260 arg++;
262 while (*arg==',') arg++;
264 snprintf(newarg,128,"tap,vlan=%d,fd=%d%s%s",vlan,fd,(*arg == 0)?"":",",arg);
265 return strdup(newarg);
268 int main(int argc, char **argv)
270 int *fddata;
271 char *argsock,**sockname;
272 int *ports;
273 struct sockaddr_un *dataout,datain;
274 socklen_t datainsize;
275 int result;
276 int *connected_fd;
277 register ssize_t nx;
278 int args;
279 int newargc;
280 char **newargv;
281 typedef int pair[2];
282 pair *sp;
283 register int i;
284 int oldsyntax=0;
285 int newsyntax=0;
286 int ver;
288 vdeqname=basename(argv[0]);
289 callerpwd=getpwuid(getuid());
290 /* OLD SYNTAX MGMT */
291 if (strncmp(vdeqname,"vdeo",4) == 0) {
292 oldsyntax=1;
293 if (strcmp(vdeqname,"vdeoq") != 0) {
294 filename=vdeqname+4;
295 args=1;
298 else if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0) {
299 filename=vdeqname+3;
300 args=1;
302 else if (argc > 1) {
303 filename=argv[1];
304 args=2;
305 } else {
306 usage();
308 if ((ver=checkver(filename)) < 0x800)
309 oldsyntax=1;
310 if (!oldsyntax) {
311 nb_nics=countnewnics(argc-args,argv+args);
312 if (nb_nics > 0)
313 newsyntax=1;
315 if ((argc > args && (
316 strcmp(argv[args],"-h")==0 ||
317 strcmp(argv[args],"-help")==0 ||
318 strcmp(argv[args],"--help")==0
319 )) || (
320 strcmp(filename,"-h")==0 ||
321 strcmp(filename,"-help")==0 ||
322 strcmp(filename,"--help")==0
323 )) {
324 usage();
325 } else if (argc > args+1 && (
326 (strcmp(argv[args],"-vdesock")==0) ||
327 (strcmp(argv[args],"-sock")==0) ||
328 (strcmp(argv[args],"-unix")==0) ||
329 (strcmp(argv[args],"-s")==0))
331 argsock=argv[args+1];
332 args+=2;
333 } else
334 argsock=NULL;
336 if (!newsyntax) {
337 if (argsock == NULL)
338 nb_nics=1;
339 else
340 nb_nics=countnics(argsock);
341 if (!oldsyntax && nb_nics > 1)
342 fprintf(stderr,
343 "Warning: all the vde connections will be connected to one net interface\n"
344 " to configure several interface use the new syntax -net vde\n");
346 if ((sp= (pair *) malloc(nb_nics * 2 * sizeof (int)))<0) {
347 perror("malloc nics");
348 exit(1);
350 if ((inpath=(char **) malloc (nb_nics * sizeof(char *))) <0) {
351 perror("malloc inpath");
352 exit(1);
354 memset(inpath,0,(nb_nics * sizeof(char *)));
356 for (i=0; i<nb_nics; i++) {
357 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp[i]) < 0){
358 perror("socketpair");
359 exit(1);
363 if ((sockname= (char **) malloc(sizeof(char *) * nb_nics))<0) {
364 perror("malloc sockname");
365 exit(1);
367 if ((ports= (int *) malloc(sizeof(int) * nb_nics))<0) {
368 perror("malloc ports");
369 exit(1);
372 if (newsyntax)
374 int netflag;
375 int vdeint;
376 newargv=argv;
377 newargc=argc;
378 for (i=0,netflag=0,vdeint=0;i<argc;i++) {
379 if (strcmp(argv[i],"-net")==0)
380 netflag=1;
381 else {
382 if (netflag && strncmp(argv[i],"vde",3) == 0)
384 argv[i]=parsevdearg(argv[i]+3,&sockname[vdeint],&ports[vdeint],sp[vdeint][0]);
385 vdeint++;
387 netflag=0;
390 } else
392 if (argsock==NULL)
393 sockname[0]=VDESTDSOCK;
394 else
396 register char *s=argsock;
397 register char oldch;
398 i=0;
399 do {
400 sockname[i++]=s;
401 while (*s != ',' && *s != '\0')
402 s++;
403 oldch=*s;
404 *s=0;
405 s++;
406 } while (oldch != 0);
409 /* printf("-- %s --\n",numfd);
410 printf("as %s\n",argsock);
411 for (i=0; i<nb_nics; i++)
412 printf("%d -> %s\n",i,sockname[i]); */
413 newargc=argc+3+(2*nb_nics)-args;
414 if ((newargv=(char **) malloc ((newargc+1)* sizeof(char *))) <0) {
415 perror("malloc");
416 exit(1);
419 newargv[0]=filename;
420 if (oldsyntax) {
421 for (i=0; i<nb_nics; i++) {
422 char numfd[10];
423 ports[i]=0;
424 sprintf(numfd,"%d",sp[i][0]);
425 newargv[2*i+1]="-tun-fd";
426 newargv[2*i+2]=strdup(numfd);
429 char nnics[10];
430 sprintf(nnics,"%d",nb_nics);
431 newargv[2*nb_nics+1]="-nics";
432 newargv[2*nb_nics+2]=strdup(nnics);
434 } else {
435 for (i=0; i<nb_nics; i++) {
436 char numfd[30];
437 ports[i]=0;
438 sprintf(numfd,"tap,vlan=0,fd=%d",sp[i][0]);
439 newargv[2*i+1]="-net";
440 newargv[2*i+2]=strdup(numfd);
442 newargv[2*nb_nics+1]="-net";
443 newargv[2*nb_nics+2]="nic";
445 for (i=(2*nb_nics)+3;args<argc;i++,args++) newargv[i]=argv[args];
447 newargv[i]=0;
450 if ((fddata= (int *) malloc(sizeof(int) * nb_nics))<0) {
451 perror("malloc fddata");
452 exit(1);
454 if ((connected_fd= (int *) malloc(sizeof(int) * nb_nics))<0) {
455 perror("malloc connected_fd");
456 exit(1);
458 if ((dataout= (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un) * nb_nics))<0) {
459 perror("malloc dataout");
460 exit(1);
463 if ((pollv= (struct pollfd *) malloc(sizeof(struct pollfd) * 2 * nb_nics))<0) {
464 perror("malloc fddata");
465 exit(1);
467 for (i=0; i<nb_nics; i++) {
468 if((fddata[i] = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
469 perror("socket");
470 exit(1);
472 connected_fd[i]=send_fd(sockname[i], fddata[i], &(dataout[i]), i, ports[i]);
473 pollv[2*i+1].fd=fddata[i];
474 pollv[2*i].fd=sp[i][1];
475 pollv[2*i].events= pollv[2*i+1].events=POLLIN|POLLHUP;
478 if (fork()) {
479 close(0);
480 signal(SIGCHLD, leave);
481 for (i=0; i<nb_nics; i++)
482 close(sp[i][0]);
483 for(;;) {
484 result=poll(pollv,2*nb_nics,-1);
485 for (i=0; i<nb_nics; i++) {
486 if (pollv[2*i].revents & POLLHUP || pollv[2*i+1].revents & POLLHUP)
487 break;
488 if (pollv[2*i].revents & POLLIN) {
489 nx=read(sp[i][1],bufin,sizeof(bufin));
490 //fprintf(stderr,"RX from qemu %d\n",nx);
491 //send(connected_fd,bufin,nx,0);
492 sendto(fddata[i],bufin,nx,0,(struct sockaddr *) &(dataout[i]), sizeof(struct sockaddr_un));
494 if (pollv[2*i+1].revents & POLLIN) {
495 datainsize=sizeof(datain);
496 nx=recvfrom(fddata[i],bufin,BUFSIZE,0,(struct sockaddr *) &datain, &datainsize);
497 //fprintf(stderr,"TX to qemu %d\n",nx);
498 write(sp[i][1],bufin,nx);
502 } else {
503 for (i=0; i<nb_nics; i++) {
504 close(sp[i][1]);
505 close(fddata[i]);
506 close(connected_fd[i]);
508 execvp(filename,newargv);
510 cleanup();
511 return(0);