man pages license/see also updates
[vde.git] / vde-2 / slirpvde / slirpvde.c
blobb3173fce54f20063c1b5e6d565d298c9ac841d1e
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 <libvdeplug/libvdeplug.h>
32 #ifdef VDE_DARWIN
33 #include <limits.h>
34 #include <syslimits.h>
35 #endif
37 #define SWITCH_MAGIC 0xfeedface
38 #define BUFSIZE 2048
39 #define ETH_ALEN 6
41 VDECONN *conn;
42 int dhcpmgmt=0;
43 static char *pidfile = NULL;
44 static char pidfile_path[_POSIX_PATH_MAX];
45 int logok=0;
46 char *prog;
47 extern FILE *lfd;
49 void printlog(int priority, const char *format, ...)
51 va_list arg;
53 va_start (arg, format);
55 if (logok)
56 vsyslog(priority,format,arg);
57 else {
58 fprintf(stderr,"%s: ",prog);
59 vfprintf(stderr,format,arg);
60 fprintf(stderr,"\n");
62 va_end (arg);
66 static void save_pidfile()
68 if(pidfile[0] != '/')
69 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
70 else
71 strcpy(pidfile_path, pidfile);
73 int fd = open(pidfile_path,
74 O_WRONLY | O_CREAT | O_EXCL,
75 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
76 FILE *f;
78 if(fd == -1) {
79 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
80 exit(1);
83 if((f = fdopen(fd, "w")) == NULL) {
84 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
85 exit(1);
88 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
89 printlog(LOG_ERR, "Error in writing pidfile");
90 exit(1);
93 fclose(f);
96 static void cleanup(void)
98 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
99 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
101 vde_close(conn);
104 static void sig_handler(int sig)
106 cleanup();
107 signal(sig, SIG_DFL);
108 kill(getpid(), sig);
111 static void setsighandlers()
113 /* setting signal handlers.
114 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
115 * ignores all the others signals which could cause termination. */
116 struct { int sig; const char *name; int ignore; } signals[] = {
117 { SIGHUP, "SIGHUP", 0 },
118 { SIGINT, "SIGINT", 0 },
119 { SIGPIPE, "SIGPIPE", 1 },
120 { SIGALRM, "SIGALRM", 1 },
121 { SIGTERM, "SIGTERM", 0 },
122 { SIGUSR1, "SIGUSR1", 1 },
123 { SIGUSR2, "SIGUSR2", 1 },
124 { SIGPROF, "SIGPROF", 1 },
125 { SIGVTALRM, "SIGVTALRM", 1 },
126 #ifdef VDE_LINUX
127 { SIGPOLL, "SIGPOLL", 1 },
128 { SIGSTKFLT, "SIGSTKFLT", 1 },
129 { SIGIO, "SIGIO", 1 },
130 { SIGPWR, "SIGPWR", 1 },
131 { SIGUNUSED, "SIGUNUSED", 1 },
132 #endif
133 #ifdef VDE_DARWIN
134 { SIGXCPU, "SIGXCPU", 1 },
135 { SIGXFSZ, "SIGXFSZ", 1 },
136 #endif
137 { 0, NULL, 0 }
140 int i;
141 for(i = 0; signals[i].sig != 0; i++)
142 if(signal(signals[i].sig,
143 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
144 perror("Setting handler");
147 unsigned char bufin[BUFSIZE];
149 int slirp_can_output(void)
151 return 1;
155 #if 0
156 #define convery2ascii(x) ((x)>=' ' && (x) <= '~')?(x):'.'
157 void dumppkt(const uint8_t *pkt, int pkt_len)
159 register int i,j;
160 printf("Packet dump len=%d\n",pkt_len);
161 if (pkt_len == 0)
162 return;
163 for (i=0;i<((pkt_len-1)/16)+1;i++) {
164 for (j=0;j<16;j++)
165 if (i*16+j > pkt_len)
166 printf(" ");
167 else
168 printf("%02x ",pkt[i*16+j]);
169 printf(" ");
170 for (j=0;j<16;j++)
171 if (i*16+j > pkt_len)
172 printf(" ");
173 else
174 printf("%c",convery2ascii(pkt[i*16+j]));
175 printf("\n");
178 #endif
180 void slirp_output(const uint8_t *pkt, int pkt_len)
182 /* slirp -> vde */
183 //fprintf(stderr,"RX from slirp %d\n",pkt_len);
184 //dumppkt(pkt,pkt_len);
185 vde_send(conn,pkt,pkt_len,0);
188 struct redirx {
189 u_int32_t inaddr;
190 int start_port;
191 int display;
192 int screen;
193 struct redirx *next;
196 struct redirtcp {
197 u_int32_t inaddr;
198 int port;
199 int lport;
200 struct redirtcp *next;
203 static struct redirtcp *parse_redir_tcp(struct redirtcp *head, char *buff)
205 u_int32_t inaddr=0;
206 int port=0;
207 int lport=0;
208 char *ipaddrstr=NULL;
209 char *portstr=NULL;
210 struct redirtcp *new;
212 if ((ipaddrstr = strchr(buff, ':'))) {
213 *ipaddrstr++ = 0;
214 if (*ipaddrstr == 0) {
215 fprintf(stderr,"redir TCP syntax error\n");
216 return head;
219 if ((portstr = strchr(ipaddrstr, ':'))) {
220 *portstr++ = 0;
221 if (*portstr == 0) {
222 fprintf(stderr,"redir TCP syntax error\n");
223 return head;
227 sscanf(buff,"%d",&lport);
228 sscanf(portstr,"%d",&port);
229 if (ipaddrstr)
230 inaddr = inet_addr(ipaddrstr);
232 if (!inaddr) {
233 fprintf(stderr,"TCP redirection error: an IP address must be specified\r\n");
234 return head;
237 if ((new=malloc(sizeof(struct redirtcp)))==NULL)
238 return head;
239 else {
240 new->inaddr=inaddr;
241 new->port=port;
242 new->lport=lport;
243 new->next=head;
244 return new;
248 static struct redirx *parse_redir_x(struct redirx *head, char *buff)
250 char *ptr=NULL;
251 u_int32_t inaddr = 0;
252 int display=0;
253 int screen=0;
254 int start_port = 0;
255 struct redirx *new;
256 if ((ptr = strchr(buff, ':'))) {
257 *ptr++ = 0;
258 if (*ptr == 0) {
259 fprintf(stderr,"X-redirection syntax error\n");
260 return head;
263 if (buff[0]) {
264 inaddr = inet_addr(buff);
265 if (inaddr == 0xffffffff) {
266 fprintf(stderr,"Error: X-redirection bad address\r\n");
267 return head;
270 if (ptr) {
271 if (strchr(ptr, '.')) {
272 if (sscanf(ptr, "%d.%d", &display, &screen) != 2)
273 return head;
274 } else {
275 if (sscanf(ptr, "%d", &display) != 1)
276 return head;
280 if (!inaddr) {
281 fprintf(stderr,"Error: X-redirection an IP address must be specified\r\n");
282 return head;
285 if ((new=malloc(sizeof(struct redirx)))==NULL)
286 return head;
287 else {
288 new->inaddr=inaddr;
289 new->display=display;
290 new->screen=screen;
291 new->start_port=start_port;
292 new->next=head;
293 return new;
297 static void do_redir_tcp(struct redirtcp *head)
299 if (head) {
300 do_redir_tcp(head->next);
301 redir_tcp(head->inaddr,head->port,head->lport);
302 free(head);
306 static void do_redir_x(struct redirx *head)
308 if (head) {
309 do_redir_x(head->next);
310 redir_x(head->inaddr,head->start_port,head->display,head->screen);
311 free(head);
315 void usage(char *name) {
316 fprintf(stderr,
317 "Usage:\n"
318 " %s [-socket vdesock] [-dhcp] [-daemon] [-network netaddr] \n"
319 "\t [-L host_port:guest_addr:guest_port] [-X guest_addr[:display[.screen]]] \n"
320 " %s [-s vdesock] [-D] [-d] [-n netaddr]\n"
321 "\t [-L host_port:guest_addr:guest_port] [-X guest_addr[:display[.screen]]] \n" ,name,name);
322 exit(-1);
325 struct option slirpvdeopts[] = {
326 {"socket",1,NULL,'s'},
327 {"sock",1,NULL,'s'},
328 {"vdesock",1,NULL,'s'},
329 {"unix",1,NULL,'s'},
330 {"pidfile", 1, 0, 'p'},
331 {"dhcp",0,NULL,'D'},
332 {"daemon",0,NULL,'d'},
333 {"network",0,NULL,'n'},
334 {"mod",1,0,'m'},
335 {"group",1,0,'g'},
336 {"port",1,0,'P'},
337 {NULL,0,0,0}};
339 int main(int argc, char **argv)
341 char *sockname=NULL;
342 int result,nfds;
343 register ssize_t nx;
344 register int i;
345 fd_set rs,ws,xs;
346 int opt,longindx;
347 char *netw=NULL;
348 int daemonize=0;
349 struct redirtcp *rtcp=NULL;
350 struct redirx *rx=NULL;
351 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
353 prog=basename(argv[0]);
355 while ((opt=GETOPT_LONG(argc,argv,"s:n:p:g:m:L:X:dD",slirpvdeopts,&longindx)) > 0) {
356 switch (opt) {
357 case 's' : sockname=optarg;
358 break;
359 case 'D' : dhcpmgmt = 1;
360 break;
361 case 'd' : daemonize = 1;
362 break;
363 case 'n' : netw=optarg;
364 break;
365 case 'm' : sscanf(optarg,"%o",&(open_args.mode));
366 break;
367 case 'g' : open_args.group=strdup(optarg);
368 break;
369 case 'p': pidfile=strdup(optarg);
370 break;
371 case 'P' : open_args.port=atoi(optarg);
372 break;
373 case 'L': rtcp=parse_redir_tcp(rtcp,optarg);
374 break;
375 case 'X': rx=parse_redir_x(rx,optarg);
376 break;
377 default : usage(prog);
378 break;
381 atexit(cleanup);
382 if (daemonize) {
383 openlog(basename(prog), LOG_PID, 0);
384 logok=1;
385 syslog(LOG_INFO,"slirpvde started");
387 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
388 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
389 exit(1);
391 strcat(pidfile_path, "/");
392 if (daemonize && daemon(0, 1)) {
393 printlog(LOG_ERR,"daemon: %s",strerror(errno));
394 exit(1);
397 conn=vde_open(sockname,"slirpvde:",&open_args);
398 lfd=stderr;
399 slirp_init(netw);
401 do_redir_tcp(rtcp);
402 do_redir_x(rx);
404 for(;;) {
405 int datafd,ctlfd;
406 FD_ZERO(&rs);
407 FD_ZERO(&ws);
408 FD_ZERO(&xs);
409 nfds= -1;
410 slirp_select_fill(&nfds,&rs,&ws,&xs);
411 datafd=vde_datafd(conn);
412 ctlfd=vde_ctlfd(conn);
413 FD_SET(datafd,&rs);
414 FD_SET(ctlfd,&rs);
415 if (datafd>nfds) nfds=datafd;
416 if (ctlfd>nfds) nfds=ctlfd;
417 result=select(nfds+1,&rs,&ws,&xs,NULL);
418 //printf("SELECT %d %d\n",nfds,result);
419 if (FD_ISSET(datafd,&rs)) {
420 nx=vde_recv(conn,bufin,BUFSIZE,0);
421 //fprintf(stderr,"TX to slirp %d\n",nx);
422 result--;
423 slirp_input(bufin,nx);
424 //fprintf(stderr,"TX to slirp %d exit\n",nx);
426 if (result > 0) {
427 //fprintf(stderr,"slirp poll\n");
428 slirp_select_poll(&rs,&ws,&xs);
429 //fprintf(stderr,"slirp poll exit\n");
431 if (FD_ISSET(ctlfd,&rs)) {
432 if(read(ctlfd,bufin,BUFSIZE)==0)
433 exit(0);
436 return(0);