loadlwipv6 inlined
[vde.git] / vde-2 / src / vde_plug2tap.c
blob75e6aee8d8f669dd819302313a6eab0f0feba0ca
1 /* Copyright 2006 Renzo Davoli
2 * from vde_plug Davoli Gardenghi
3 */
5 #include <stdio.h>
6 #include <fcntl.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <signal.h>
10 #include <syslog.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <sys/ioctl.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <stdarg.h>
17 #include <syslog.h>
18 #include <libgen.h>
19 #define _GNU_SOURCE
20 #include <getopt.h>
22 #include <config.h>
23 #include <vde.h>
24 #include <vdecommon.h>
25 #include <libvdeplug.h>
27 #define BUFSIZE 2048
29 #ifdef VDE_LINUX
30 #include <net/if.h>
31 #include <linux/if_tun.h>
32 #endif
34 #ifdef VDE_FREEBSD
35 #include <sys/socket.h>
36 #include <net/if.h>
37 #include <net/if_tun.h>
38 #endif
40 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
41 # define TAP_PREFIX "/dev/"
42 # include <limits.h>
43 # if defined HAVE_SYSLIMITS_H
44 # include <syslimits.h>
45 # elif defined HAVE_SYS_SYSLIMITS_H
46 # include <sys/syslimits.h>
47 # else
48 # error "No syslimits.h found"
49 # endif
50 #endif
52 VDECONN *conn;
54 char *prog;
55 int logok;
56 static char *pidfile = NULL;
57 static char pidfile_path[PATH_MAX];
59 void printlog(int priority, const char *format, ...)
61 va_list arg;
63 va_start (arg, format);
65 if (logok)
66 vsyslog(priority,format,arg);
67 else {
68 fprintf(stderr,"%s: ",prog);
69 vfprintf(stderr,format,arg);
70 fprintf(stderr,"\n");
72 va_end (arg);
75 static void cleanup(void)
77 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
78 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
81 vde_close(conn);
84 static void sig_handler(int sig)
86 cleanup();
87 signal(sig, SIG_DFL);
88 kill(getpid(), sig);
91 static void setsighandlers()
93 /* setting signal handlers.
94 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
95 * ignores all the others signals which could cause termination. */
96 struct { int sig; const char *name; int ignore; } signals[] = {
97 { SIGHUP, "SIGHUP", 0 },
98 { SIGINT, "SIGINT", 0 },
99 { SIGPIPE, "SIGPIPE", 1 },
100 { SIGALRM, "SIGALRM", 1 },
101 { SIGTERM, "SIGTERM", 0 },
102 { SIGUSR1, "SIGUSR1", 1 },
103 { SIGUSR2, "SIGUSR2", 1 },
104 { SIGPROF, "SIGPROF", 1 },
105 { SIGVTALRM, "SIGVTALRM", 1 },
106 #ifdef VDE_LINUX
107 { SIGPOLL, "SIGPOLL", 1 },
108 #ifdef SIGSTKFLT
109 { SIGSTKFLT, "SIGSTKFLT", 1 },
110 #endif
111 { SIGIO, "SIGIO", 1 },
112 { SIGPWR, "SIGPWR", 1 },
113 #ifdef SIGUNUSED
114 { SIGUNUSED, "SIGUNUSED", 1 },
115 #endif
116 #endif
117 #ifdef VDE_DARWIN
118 { SIGXCPU, "SIGXCPU", 1 },
119 { SIGXFSZ, "SIGXFSZ", 1 },
120 #endif
121 { 0, NULL, 0 }
124 int i;
125 for(i = 0; signals[i].sig != 0; i++)
126 if(signal(signals[i].sig,
127 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
128 perror("Setting handler");
131 struct pollfd pollv[]={{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP}};
133 static void usage(void) {
134 fprintf(stderr, "Usage: %s [OPTION]... tap_name\n\n", prog);
135 fprintf(stderr, " -p, --port=portnum Port number in the VDE switch\n"
136 " -g, --group=group Group for the socket\n"
137 " -m, --mode=mode Octal mode for the socket\n"
138 " -s, --sock=socket VDE switch control socket or dir\n"
139 " -d, --daemon Launch in background\n"
140 " -P, --pidfile=pidfile Create pidfile with our PID\n"
141 " -h, --help This help\n");
142 exit(-1);
145 #ifdef VDE_LINUX
146 int open_tap(char *dev)
148 struct ifreq ifr;
149 int fd;
151 if((fd = open("/dev/net/tun", O_RDWR)) < 0){
152 printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
153 return(-1);
155 memset(&ifr, 0, sizeof(ifr));
156 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
157 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
158 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
159 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
160 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
161 close(fd);
162 return(-1);
164 return(fd);
166 #endif
168 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
169 int open_tap(char *dev)
171 int fd;
172 int prefixlen = strlen(TAP_PREFIX);
173 char *path = NULL;
174 if (*dev == '/')
175 fd=open(dev, O_RDWR);
176 else
178 path = malloc(strlen(dev) + prefixlen + 1);
179 if (path != NULL)
181 snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
182 fd=open(path, O_RDWR);
183 free(path);
185 else
186 fd = -1;
189 if (fd < 0)
191 printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
192 return(-1);
194 return fd;
196 #endif
198 unsigned char bufin[BUFSIZE];
200 static void save_pidfile()
202 if(pidfile[0] != '/')
203 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
204 else
205 strcpy(pidfile_path, pidfile);
207 int fd = open(pidfile_path,
208 O_WRONLY | O_CREAT | O_EXCL,
209 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
210 FILE *f;
212 if(fd == -1) {
213 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
214 exit(1);
217 if((f = fdopen(fd, "w")) == NULL) {
218 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
219 exit(1);
222 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
223 printlog(LOG_ERR, "Error in writing pidfile");
224 exit(1);
227 fclose(f);
230 int main(int argc, char **argv)
232 static char *sockname=NULL;
233 static char *tapname=NULL;
234 int daemonize=0;
235 int result;
236 int tapfd;
237 register ssize_t nx;
238 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
239 int c;
240 prog=argv[0];
241 while (1) {
242 int option_index = 0;
244 static struct option long_options[] = {
245 {"sock", 1, 0, 's'},
246 {"port", 1, 0, 'p'},
247 {"help",0,0,'h'},
248 {"mod",1,0,'m'},
249 {"group",1,0,'g'},
250 {"daemon",0,0,'d'},
251 {"pidfile", 1, 0, 'P'},
252 {0, 0, 0, 0}
254 c = GETOPT_LONG (argc, argv, "hdP:p:s:m:g:",
255 long_options, &option_index);
256 if (c == -1)
257 break;
259 switch (c) {
260 case 'p':
261 open_args.port=atoi(optarg);
262 if (open_args.port <= 0 || open_args.port > 255 )
263 usage(); //implies exit
264 break;
266 case 'h':
267 usage(); //implies exit
268 break;
270 case 's':
271 sockname=strdup(optarg);
272 break;
274 case 'm':
275 sscanf(optarg,"%o",&(open_args.mode));
276 break;
278 case 'g':
279 open_args.group=strdup(optarg);
280 break;
282 case 'd':
283 daemonize=1;
284 break;
286 case 'P':
287 pidfile=strdup(optarg);
288 break;
290 default:
291 usage(); //implies exit
295 if (daemonize) {
296 openlog(basename(prog), LOG_PID, 0);
297 logok=1;
298 syslog(LOG_INFO,"VDE_PLUG2TAP started");
300 /* saves current path in pidfile_path, because otherwise with daemonize() we
301 * forget it */
302 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
303 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
304 exit(1);
306 strcat(pidfile_path, "/");
307 if (daemonize && daemon(0, 0)) {
308 printlog(LOG_ERR,"daemon: %s",strerror(errno));
309 exit(1);
312 /* once here, we're sure we're the true process which will continue as a
313 * server: save PID file if needed */
314 if(pidfile) save_pidfile();
316 if (optind < argc)
317 tapname=argv[optind];
318 else
319 usage(); // implies exit
321 atexit(cleanup);
322 setsighandlers();
324 tapfd=open_tap(tapname);
325 if(tapfd<0)
326 exit(1);
327 conn=vde_open(sockname,"vde_plug:",&open_args);
328 if (conn == NULL)
329 exit(1);
331 pollv[0].fd=tapfd;
332 pollv[1].fd=vde_datafd(conn);
333 pollv[2].fd=vde_ctlfd(conn);
335 for(;;) {
336 result=poll(pollv,3,-1);
337 if ((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP ||
338 pollv[2].revents & POLLIN)
339 break;
340 if (pollv[0].revents & POLLIN) {
341 nx=read(tapfd,bufin,sizeof(bufin));
342 /* if POLLIN but not data it means that the stream has been
343 * closed at the other end */
344 //fprintf(stderr,"%s: RECV %d %x %x \n",prog,nx,bufin[0],bufin[1]);
345 if (nx<=0)
346 break;
347 vde_send(conn,bufin,nx,0);
349 if (pollv[1].revents & POLLIN) {
350 nx=vde_recv(conn,bufin,sizeof(bufin),0);
351 if (nx<=0)
352 break;
353 write(tapfd,bufin,nx);
354 //fprintf(stderr,"%s: SENT %d %x %x \n",prog,nx,bufin[0],bufin[1]);
358 return(0);