VDE 2.1.6, 2006-12-21
[vde.git] / vde-2 / slirpvde / slirpvde.c
blob8e08fedf0c4dc5e109f6689845a2b1d7f92eb8d5
1 /* Copyright 2003 Renzo Davoli
2 * Licensed under the GPL
3 * Modified by Ludovico Gardenghi 2005
4 */
6 #include <config.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <string.h>
11 #include <syslog.h>
12 #include <errno.h>
13 #include <unistd.h>
14 #include <stdint.h>
15 #include <libgen.h>
16 #include <sys/ioctl.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <sys/uio.h>
20 #include <sys/poll.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <libslirp.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #include <getopt.h>
27 #include <stdarg.h>
28 #include <fcntl.h>
29 #include <vde.h>
30 #include <netinet/in.h>
31 #include <libvdeplug/libvdeplug.h>
33 #include "misc.h"
35 #ifdef VDE_DARWIN
36 # include <limits.h>
37 # if defined HAVE_SYSLIMITS_H
38 # include <syslimits.h>
39 # elif defined HAVE_SYS_SYSLIMITS_H
40 # include <sys/syslimits.h>
41 # else
42 # error "No syslimits.h found"
43 # endif
44 #endif
46 #define SWITCH_MAGIC 0xfeedface
47 #define BUFSIZE 2048
48 #define ETH_ALEN 6
50 VDECONN *conn;
51 int dhcpmgmt=0;
52 static char *pidfile = NULL;
53 static char pidfile_path[_POSIX_PATH_MAX];
54 int logok=0;
55 char *prog;
56 extern FILE *lfd;
58 void printlog(int priority, const char *format, ...)
60 va_list arg;
62 va_start (arg, format);
64 if (logok)
65 vsyslog(priority,format,arg);
66 else {
67 fprintf(stderr,"%s: ",prog);
68 vfprintf(stderr,format,arg);
69 fprintf(stderr,"\n");
71 va_end (arg);
75 static void save_pidfile()
77 if(pidfile[0] != '/')
78 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
79 else
80 strcpy(pidfile_path, pidfile);
82 int fd = open(pidfile_path,
83 O_WRONLY | O_CREAT | O_EXCL,
84 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
85 FILE *f;
87 if(fd == -1) {
88 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
89 exit(1);
92 if((f = fdopen(fd, "w")) == NULL) {
93 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
94 exit(1);
97 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
98 printlog(LOG_ERR, "Error in writing pidfile");
99 exit(1);
102 fclose(f);
105 static void cleanup(void)
107 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
108 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
110 vde_close(conn);
113 static void sig_handler(int sig)
115 cleanup();
116 signal(sig, SIG_DFL);
117 kill(getpid(), sig);
120 static void setsighandlers()
122 /* setting signal handlers.
123 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
124 * ignores all the others signals which could cause termination. */
125 struct { int sig; const char *name; int ignore; } signals[] = {
126 { SIGHUP, "SIGHUP", 0 },
127 { SIGINT, "SIGINT", 0 },
128 { SIGPIPE, "SIGPIPE", 1 },
129 { SIGALRM, "SIGALRM", 1 },
130 { SIGTERM, "SIGTERM", 0 },
131 { SIGUSR1, "SIGUSR1", 1 },
132 { SIGUSR2, "SIGUSR2", 1 },
133 { SIGPROF, "SIGPROF", 1 },
134 { SIGVTALRM, "SIGVTALRM", 1 },
135 #ifdef VDE_LINUX
136 { SIGPOLL, "SIGPOLL", 1 },
137 #ifdef SIGSTKFLT
138 { SIGSTKFLT, "SIGSTKFLT", 1 },
139 #endif
140 { SIGIO, "SIGIO", 1 },
141 { SIGPWR, "SIGPWR", 1 },
142 #ifdef SIGUNUSED
143 { SIGUNUSED, "SIGUNUSED", 1 },
144 #endif
145 #endif
146 #ifdef VDE_DARWIN
147 { SIGXCPU, "SIGXCPU", 1 },
148 { SIGXFSZ, "SIGXFSZ", 1 },
149 #endif
150 { 0, NULL, 0 }
153 int i;
154 for(i = 0; signals[i].sig != 0; i++)
155 if(signal(signals[i].sig,
156 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
157 perror("Setting handler");
160 unsigned char bufin[BUFSIZE];
162 int slirp_can_output(void)
164 return 1;
168 #if 0
169 #define convery2ascii(x) ((x)>=' ' && (x) <= '~')?(x):'.'
170 void dumppkt(const uint8_t *pkt, int pkt_len)
172 register int i,j;
173 printf("Packet dump len=%d\n",pkt_len);
174 if (pkt_len == 0)
175 return;
176 for (i=0;i<((pkt_len-1)/16)+1;i++) {
177 for (j=0;j<16;j++)
178 if (i*16+j > pkt_len)
179 printf(" ");
180 else
181 printf("%02x ",pkt[i*16+j]);
182 printf(" ");
183 for (j=0;j<16;j++)
184 if (i*16+j > pkt_len)
185 printf(" ");
186 else
187 printf("%c",convery2ascii(pkt[i*16+j]));
188 printf("\n");
191 #endif
193 void slirp_output(const uint8_t *pkt, int pkt_len)
195 /* slirp -> vde */
196 //fprintf(stderr,"RX from slirp %d\n",pkt_len);
197 //dumppkt(pkt,pkt_len);
198 vde_send(conn,pkt,pkt_len,0);
201 struct redirx {
202 u_int32_t inaddr;
203 int start_port;
204 int display;
205 int screen;
206 struct redirx *next;
209 struct redirtcp {
210 u_int32_t inaddr;
211 int port;
212 int lport;
213 struct redirtcp *next;
216 static struct redirtcp *parse_redir_tcp(struct redirtcp *head, char *buff)
218 u_int32_t inaddr=0;
219 int port=0;
220 int lport=0;
221 char *ipaddrstr=NULL;
222 char *portstr=NULL;
223 struct redirtcp *new;
225 if ((ipaddrstr = strchr(buff, ':'))) {
226 *ipaddrstr++ = 0;
227 if (*ipaddrstr == 0) {
228 fprintf(stderr,"redir TCP syntax error\n");
229 return head;
232 if ((portstr = strchr(ipaddrstr, ':'))) {
233 *portstr++ = 0;
234 if (*portstr == 0) {
235 fprintf(stderr,"redir TCP syntax error\n");
236 return head;
240 sscanf(buff,"%d",&lport);
241 sscanf(portstr,"%d",&port);
242 if (ipaddrstr)
243 inaddr = inet_addr(ipaddrstr);
245 if (!inaddr) {
246 fprintf(stderr,"TCP redirection error: an IP address must be specified\r\n");
247 return head;
250 if ((new=malloc(sizeof(struct redirtcp)))==NULL)
251 return head;
252 else {
253 new->inaddr=inaddr;
254 new->port=port;
255 new->lport=lport;
256 new->next=head;
257 return new;
261 static struct redirx *parse_redir_x(struct redirx *head, char *buff)
263 char *ptr=NULL;
264 u_int32_t inaddr = 0;
265 int display=0;
266 int screen=0;
267 int start_port = 0;
268 struct redirx *new;
269 if ((ptr = strchr(buff, ':'))) {
270 *ptr++ = 0;
271 if (*ptr == 0) {
272 fprintf(stderr,"X-redirection syntax error\n");
273 return head;
276 if (buff[0]) {
277 inaddr = inet_addr(buff);
278 if (inaddr == 0xffffffff) {
279 fprintf(stderr,"Error: X-redirection bad address\r\n");
280 return head;
283 if (ptr) {
284 if (strchr(ptr, '.')) {
285 if (sscanf(ptr, "%d.%d", &display, &screen) != 2)
286 return head;
287 } else {
288 if (sscanf(ptr, "%d", &display) != 1)
289 return head;
293 if (!inaddr) {
294 fprintf(stderr,"Error: X-redirection an IP address must be specified\r\n");
295 return head;
298 if ((new=malloc(sizeof(struct redirx)))==NULL)
299 return head;
300 else {
301 new->inaddr=inaddr;
302 new->display=display;
303 new->screen=screen;
304 new->start_port=start_port;
305 new->next=head;
306 return new;
310 static void do_redir_tcp(struct redirtcp *head)
312 if (head) {
313 do_redir_tcp(head->next);
314 redir_tcp(head->inaddr,head->port,head->lport);
315 free(head);
319 static void do_redir_x(struct redirx *head)
321 if (head) {
322 do_redir_x(head->next);
323 redir_x(head->inaddr,head->start_port,head->display,head->screen);
324 free(head);
328 void usage(char *name) {
329 fprintf(stderr,
330 "Usage:\n"
331 " %s [-socket vdesock] [-dhcp] [-daemon] [-network netaddr] \n"
332 "\t [-L host_port:guest_addr:guest_port] [-X guest_addr[:display[.screen]]] \n"
333 " %s [-s vdesock] [-D] [-d] [-n netaddr]\n"
334 "\t [-L host_port:guest_addr:guest_port] [-X guest_addr[:display[.screen]]] \n" ,name,name);
335 exit(-1);
338 struct option slirpvdeopts[] = {
339 {"socket",1,NULL,'s'},
340 {"sock",1,NULL,'s'},
341 {"vdesock",1,NULL,'s'},
342 {"unix",1,NULL,'s'},
343 {"pidfile", 1, 0, 'p'},
344 {"dhcp",0,NULL,'D'},
345 {"daemon",0,NULL,'d'},
346 {"network",0,NULL,'n'},
347 {"mod",1,0,'m'},
348 {"group",1,0,'g'},
349 {"port",1,0,'P'},
350 {NULL,0,0,0}};
352 int main(int argc, char **argv)
354 char *sockname=NULL;
355 int result,nfds;
356 register ssize_t nx;
357 register int i;
358 fd_set rs,ws,xs;
359 int opt,longindx;
360 char *netw=NULL;
361 int daemonize=0;
362 struct redirtcp *rtcp=NULL;
363 struct redirx *rx=NULL;
364 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
366 prog=basename(argv[0]);
368 while ((opt=GETOPT_LONG(argc,argv,"s:n:p:g:m:L:X:dD",slirpvdeopts,&longindx)) > 0) {
369 switch (opt) {
370 case 's' : sockname=optarg;
371 break;
372 case 'D' : dhcpmgmt = 1;
373 break;
374 case 'd' : daemonize = 1;
375 break;
376 case 'n' : netw=optarg;
377 break;
378 case 'm' : sscanf(optarg,"%o",&(open_args.mode));
379 break;
380 case 'g' : open_args.group=strdup(optarg);
381 break;
382 case 'p': pidfile=strdup(optarg);
383 break;
384 case 'P' : open_args.port=atoi(optarg);
385 break;
386 case 'L': rtcp=parse_redir_tcp(rtcp,optarg);
387 break;
388 case 'X': rx=parse_redir_x(rx,optarg);
389 break;
390 default : usage(prog);
391 break;
394 atexit(cleanup);
395 if (daemonize) {
396 openlog(basename(prog), LOG_PID, 0);
397 logok=1;
398 syslog(LOG_INFO,"slirpvde started");
400 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
401 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
402 exit(1);
404 strcat(pidfile_path, "/");
405 if (daemonize && daemon(0, 0)) {
406 printlog(LOG_ERR,"daemon: %s",strerror(errno));
407 exit(1);
410 if(pidfile) save_pidfile();
412 conn=vde_open(sockname,"slirpvde:",&open_args);
413 lfd=stderr;
414 slirp_init(netw);
416 do_redir_tcp(rtcp);
417 do_redir_x(rx);
419 for(;;) {
420 int datafd,ctlfd;
421 FD_ZERO(&rs);
422 FD_ZERO(&ws);
423 FD_ZERO(&xs);
424 nfds= -1;
425 slirp_select_fill(&nfds,&rs,&ws,&xs);
426 datafd=vde_datafd(conn);
427 ctlfd=vde_ctlfd(conn);
428 FD_SET(datafd,&rs);
429 FD_SET(ctlfd,&rs);
430 if (datafd>nfds) nfds=datafd;
431 if (ctlfd>nfds) nfds=ctlfd;
432 result=select(nfds+1,&rs,&ws,&xs,NULL);
433 //printf("SELECT %d %d\n",nfds,result);
434 if (FD_ISSET(datafd,&rs)) {
435 nx=vde_recv(conn,bufin,BUFSIZE,0);
436 //fprintf(stderr,"TX to slirp %d\n",nx);
437 result--;
438 slirp_input(bufin,nx);
439 //fprintf(stderr,"TX to slirp %d exit\n",nx);
441 if (result > 0) {
442 //fprintf(stderr,"slirp poll\n");
443 slirp_select_poll(&rs,&ws,&xs);
444 //fprintf(stderr,"slirp poll exit\n");
446 if (FD_ISSET(ctlfd,&rs)) {
447 if(read(ctlfd,bufin,BUFSIZE)==0)
448 exit(0);
451 return(0);