AF_IPN is no longer protocol #34 (assigned to AF_ISDN).
[vde.git] / vde-2 / src / slirpvde / slirpvde.c
blob016aa45dff56b8f621dee27999029141cbc2abcf
1 /* Copyright 2003-2007 Renzo Davoli
2 * Licensed under the GPL
3 * Modified by Ludovico Gardenghi 2005
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <signal.h>
9 #include <string.h>
10 #include <syslog.h>
11 #include <errno.h>
12 #include <unistd.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/types.h>
20 #include <sys/stat.h>
21 #include <libslirp.h>
22 #include <pwd.h>
23 #include <grp.h>
24 #include <getopt.h>
25 #include <stdarg.h>
26 #include <fcntl.h>
27 #include <netinet/in.h>
28 #include <limits.h>
31 #include <config.h>
32 #include <vde.h>
33 #include <vdecommon.h>
35 #include <libvdeplug.h>
36 #include "misc.h"
37 #include "tcp2unix.h"
39 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
40 # if defined HAVE_SYSLIMITS_H
41 # include <syslimits.h>
42 # elif defined HAVE_SYS_SYSLIMITS_H
43 # include <sys/syslimits.h>
44 # else
45 # error "No syslimits.h found"
46 # endif
47 #endif
49 #define SWITCH_MAGIC 0xfeedface
50 #define BUFSIZE 2048
51 #define ETH_ALEN 6
53 VDECONN *conn;
54 int dhcpmgmt=0;
55 static char *pidfile = NULL;
56 static char pidfile_path[PATH_MAX];
57 int logok=0;
58 char *prog;
59 extern FILE *lfd;
61 void printlog(int priority, const char *format, ...)
63 va_list arg;
65 va_start (arg, format);
67 if (logok)
68 vsyslog(priority,format,arg);
69 else {
70 fprintf(stderr,"%s: ",prog);
71 vfprintf(stderr,format,arg);
72 fprintf(stderr,"\n");
74 va_end (arg);
78 static void save_pidfile()
80 if(pidfile[0] != '/')
81 strncat(pidfile_path, pidfile, sizeof(pidfile_path) - strlen(pidfile_path) -1);
82 else {
83 pidfile_path[0] = 0;
84 strncat(pidfile_path, pidfile, sizeof(pidfile_path)-1);
87 int fd = open(pidfile_path,
88 O_WRONLY | O_CREAT | O_EXCL,
89 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
90 FILE *f;
92 if(fd == -1) {
93 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
94 exit(1);
97 if((f = fdopen(fd, "w")) == NULL) {
98 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
99 exit(1);
102 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
103 printlog(LOG_ERR, "Error in writing pidfile");
104 exit(1);
107 fclose(f);
110 static void cleanup(void)
112 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
113 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
115 vde_close(conn);
118 /* XXX Apparently unused... check if ok to be removed */
120 /*static void sig_handler(int sig)
122 cleanup();
123 signal(sig, SIG_DFL);
124 kill(getpid(), sig);
129 /*static void setsighandlers()
131 |+ setting signal handlers.
132 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
133 * ignores all the others signals which could cause termination. +|
134 struct { int sig; const char *name; int ignore; } signals[] = {
135 { SIGHUP, "SIGHUP", 0 },
136 { SIGINT, "SIGINT", 0 },
137 { SIGPIPE, "SIGPIPE", 1 },
138 { SIGALRM, "SIGALRM", 1 },
139 { SIGTERM, "SIGTERM", 0 },
140 { SIGUSR1, "SIGUSR1", 1 },
141 { SIGUSR2, "SIGUSR2", 1 },
142 { SIGPROF, "SIGPROF", 1 },
143 { SIGVTALRM, "SIGVTALRM", 1 },
144 #ifdef VDE_LINUX
145 { SIGPOLL, "SIGPOLL", 1 },
146 #ifdef SIGSTKFLT
147 { SIGSTKFLT, "SIGSTKFLT", 1 },
148 #endif
149 { SIGIO, "SIGIO", 1 },
150 { SIGPWR, "SIGPWR", 1 },
151 #ifdef SIGUNUSED
152 { SIGUNUSED, "SIGUNUSED", 1 },
153 #endif
154 #endif
155 #ifdef VDE_DARWIN
156 { SIGXCPU, "SIGXCPU", 1 },
157 { SIGXFSZ, "SIGXFSZ", 1 },
158 #endif
159 { 0, NULL, 0 }
162 int i;
163 for(i = 0; signals[i].sig != 0; i++)
164 if(signal(signals[i].sig,
165 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
166 perror("Setting handler");
169 unsigned char bufin[BUFSIZE];
171 int slirp_can_output(void)
173 return 1;
177 #if 0
178 #define convery2ascii(x) ((x)>=' ' && (x) <= '~')?(x):'.'
179 void dumppkt(const uint8_t *pkt, int pkt_len)
181 register int i,j;
182 printf("Packet dump len=%d\n",pkt_len);
183 if (pkt_len == 0)
184 return;
185 for (i=0;i<((pkt_len-1)/16)+1;i++) {
186 for (j=0;j<16;j++)
187 if (i*16+j > pkt_len)
188 printf(" ");
189 else
190 printf("%02x ",pkt[i*16+j]);
191 printf(" ");
192 for (j=0;j<16;j++)
193 if (i*16+j > pkt_len)
194 printf(" ");
195 else
196 printf("%c",convery2ascii(pkt[i*16+j]));
197 printf("\n");
200 #endif
202 void slirp_output(const uint8_t *pkt, int pkt_len)
204 /* slirp -> vde */
205 //fprintf(stderr,"RX from slirp %d\n",pkt_len);
206 //dumppkt(pkt,pkt_len);
207 vde_send(conn,pkt,pkt_len,0);
210 struct redirx {
211 u_int32_t inaddr;
212 int start_port;
213 int display;
214 int screen;
215 struct redirx *next;
218 struct redirtcp {
219 u_int32_t inaddr;
220 int port;
221 int lport;
222 struct redirtcp *next;
225 static struct redirtcp *parse_redir_tcp(struct redirtcp *head, char *buff)
227 u_int32_t inaddr=0;
228 int port=0;
229 int lport=0;
230 char *ipaddrstr=NULL;
231 char *portstr=NULL;
232 struct redirtcp *new;
234 if ((ipaddrstr = strchr(buff, ':'))) {
235 *ipaddrstr++ = 0;
236 if (*ipaddrstr == 0) {
237 fprintf(stderr,"redir TCP syntax error\n");
238 return head;
241 if ((portstr = strchr(ipaddrstr, ':'))) {
242 *portstr++ = 0;
243 if (*portstr == 0) {
244 fprintf(stderr,"redir TCP syntax error\n");
245 return head;
249 sscanf(buff,"%d",&lport);
250 sscanf(portstr,"%d",&port);
251 if (ipaddrstr)
252 inaddr = inet_addr(ipaddrstr);
254 if (!inaddr) {
255 fprintf(stderr,"TCP redirection error: an IP address must be specified\r\n");
256 return head;
259 if ((new=malloc(sizeof(struct redirtcp)))==NULL)
260 return head;
261 else {
262 new->inaddr=inaddr;
263 new->port=port;
264 new->lport=lport;
265 new->next=head;
266 return new;
270 static struct redirx *parse_redir_x(struct redirx *head, char *buff)
272 char *ptr=NULL;
273 u_int32_t inaddr = 0;
274 int display=0;
275 int screen=0;
276 int start_port = 0;
277 struct redirx *new;
278 if ((ptr = strchr(buff, ':'))) {
279 *ptr++ = 0;
280 if (*ptr == 0) {
281 fprintf(stderr,"X-redirection syntax error\n");
282 return head;
285 if (buff[0]) {
286 inaddr = inet_addr(buff);
287 if (inaddr == 0xffffffff) {
288 fprintf(stderr,"Error: X-redirection bad address\r\n");
289 return head;
292 if (ptr) {
293 if (strchr(ptr, '.')) {
294 if (sscanf(ptr, "%d.%d", &display, &screen) != 2)
295 return head;
296 } else {
297 if (sscanf(ptr, "%d", &display) != 1)
298 return head;
302 if (!inaddr) {
303 fprintf(stderr,"Error: X-redirection an IP address must be specified\r\n");
304 return head;
307 if ((new=malloc(sizeof(struct redirx)))==NULL)
308 return head;
309 else {
310 new->inaddr=inaddr;
311 new->display=display;
312 new->screen=screen;
313 new->start_port=start_port;
314 new->next=head;
315 return new;
319 static void parse_redir_locx(char *buff)
321 char *path;
322 int port=atoi(buff);
323 if ((path = strchr(buff, ':'))) {
324 *path++=0;
325 tcp2unix_add(port,path);
326 } else
327 fprintf(stderr,"Error: tcp2unix redirection sytax error -x port:path e.g. -x 6000:/tmp/.X11-unix/X0\r\n");
330 static void do_redir_tcp(struct redirtcp *head)
332 if (head) {
333 do_redir_tcp(head->next);
334 redir_tcp(head->inaddr,head->port,head->lport);
335 free(head);
339 static void do_redir_x(struct redirx *head)
341 if (head) {
342 do_redir_x(head->next);
343 redir_x(head->inaddr,head->start_port,head->display,head->screen);
344 free(head);
348 void usage(char *name) {
349 fprintf(stderr,
350 "Usage:\n"
351 " %s [-socket vdesock] [-dhcp] [-daemon] [-network netaddr] \n"
352 "\t [-L host_port:guest_addr:guest_port] [-X guest_addr[:display[.screen]]] \n"
353 "\t [-x portno:unix_socket_path]\n"
354 " %s [-s vdesock] [-D] [-d] [-n netaddr]\n"
355 "\t [-L host_port:guest_addr:guest_port] [-X guest_addr[:display[.screen]]] \n"
356 "\t [-x portno:unix_socket_path]\n"
357 ,name,name);
358 exit(-1);
361 struct option slirpvdeopts[] = {
362 {"socket",1,NULL,'s'},
363 {"sock",1,NULL,'s'},
364 {"vdesock",1,NULL,'s'},
365 {"unix",1,NULL,'s'},
366 {"pidfile", 1, 0, 'p'},
367 {"dhcp",0,NULL,'D'},
368 {"daemon",0,NULL,'d'},
369 {"network",1,NULL,'n'},
370 {"mod",1,0,'m'},
371 {"group",1,0,'g'},
372 {"port",1,0,'P'},
373 {NULL,0,0,0}};
375 int main(int argc, char **argv)
377 char *sockname=NULL;
378 int result,nfds;
379 register ssize_t nx;
380 /*register int i;*/
381 fd_set rs,ws,xs;
382 int opt,longindx;
383 char *netw=NULL;
384 int daemonize=0;
385 struct redirtcp *rtcp=NULL;
386 struct redirx *rx=NULL;
387 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
389 prog=basename(argv[0]);
391 while ((opt=GETOPT_LONG(argc,argv,"s:n:p:g:m:L:X:x:dD",slirpvdeopts,&longindx)) > 0) {
392 switch (opt) {
393 case 's' : sockname=optarg;
394 break;
395 case 'D' : dhcpmgmt = 1;
396 break;
397 case 'd' : daemonize = 1;
398 break;
399 case 'n' : netw=optarg;
400 break;
401 case 'm' : sscanf(optarg,"%o",&(open_args.mode));
402 break;
403 case 'g' : open_args.group=strdup(optarg);
404 break;
405 case 'p': pidfile=strdup(optarg);
406 break;
407 case 'P' : open_args.port=atoi(optarg);
408 break;
409 case 'L': rtcp=parse_redir_tcp(rtcp,optarg);
410 break;
411 case 'X': rx=parse_redir_x(rx,optarg);
412 break;
413 case 'x': parse_redir_locx(optarg);
414 break;
415 default : usage(prog);
416 break;
419 atexit(cleanup);
420 if (daemonize) {
421 openlog(basename(prog), LOG_PID, 0);
422 logok=1;
423 syslog(LOG_INFO,"slirpvde started");
425 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
426 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
427 exit(1);
430 conn=vde_open(sockname,"slirpvde:",&open_args);
431 if (!conn)
433 printlog(LOG_ERR, "Could not connect to the VDE switch at '%s': %s",
434 sockname, strerror(errno));
435 exit(1);
438 strncat(pidfile_path, "/", sizeof(pidfile_path) - strlen(pidfile_path) -1);
439 if (daemonize && daemon(0, 0)) {
440 printlog(LOG_ERR,"daemon: %s",strerror(errno));
441 exit(1);
444 if(pidfile) save_pidfile();
446 lfd=stderr;
447 slirp_init(netw);
449 do_redir_tcp(rtcp);
450 do_redir_x(rx);
452 for(;;) {
453 int datafd,ctlfd;
454 FD_ZERO(&rs);
455 FD_ZERO(&ws);
456 FD_ZERO(&xs);
457 nfds= -1;
458 slirp_select_fill(&nfds,&rs,&ws,&xs);
459 datafd = vde_datafd(conn);
460 ctlfd = vde_ctlfd(conn);
462 if (datafd < 0 || ctlfd < 0)
464 printlog(LOG_ERR, "Wrong file descriptor(s) for the VDE plug: (%d, %d)",
465 datafd, ctlfd);
466 exit(1);
469 FD_SET(datafd,&rs);
470 FD_SET(ctlfd,&rs);
471 if (datafd>nfds) nfds=datafd;
472 if (ctlfd>nfds) nfds=ctlfd;
473 result=select(nfds+1,&rs,&ws,&xs,NULL);
474 //printf("SELECT %d %d\n",nfds,result);
475 if (FD_ISSET(datafd,&rs)) {
476 nx=vde_recv(conn,bufin,BUFSIZE,0);
477 //fprintf(stderr,"TX to slirp %d\n",nx);
478 result--;
479 slirp_input(bufin,nx);
480 //fprintf(stderr,"TX to slirp %d exit\n",nx);
482 if (result > 0) {
483 //fprintf(stderr,"slirp poll\n");
484 slirp_select_poll(&rs,&ws,&xs);
485 //fprintf(stderr,"slirp poll exit\n");
487 if (FD_ISSET(ctlfd,&rs)) {
488 if(read(ctlfd,bufin,BUFSIZE)==0)
489 exit(0);
492 return(0);