vde_autolink: Add missing null entry in getopt_long array.
[vde.git] / vde-2 / src / vde_plug2tap.c
blobc769353901720399a7653398c06b54176544c137
1 /* Copyright 2006 Renzo Davoli
2 * from vde_plug Davoli Gardenghi
3 * Modified 2010 Renzo Davoli, vdestream added
4 * Licensed under the GPLv2
5 */
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <syslog.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <stdarg.h>
19 #include <syslog.h>
20 #include <libgen.h>
21 #define _GNU_SOURCE
22 #include <getopt.h>
23 #include <limits.h>
25 #include <config.h>
26 #include <vde.h>
27 #include <vdecommon.h>
28 #include <libvdeplug.h>
30 #define BUFSIZE 2048
32 #if defined VDE_LINUX || defined VDE_BIONIC
33 #include <net/if.h>
34 #include <linux/if_tun.h>
35 #endif
37 #ifdef VDE_FREEBSD
38 #include <sys/socket.h>
39 #include <net/if.h>
40 #include <net/if_tun.h>
41 #endif
43 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
44 # define TAP_PREFIX "/dev/"
45 # if defined HAVE_SYSLIMITS_H
46 # include <syslimits.h>
47 # elif defined HAVE_SYS_SYSLIMITS_H
48 # include <sys/syslimits.h>
49 # else
50 # error "No syslimits.h found"
51 # endif
52 #endif
54 VDECONN *conn;
55 VDESTREAM *vdestream;
57 char *prog;
58 int logok;
59 static char *pidfile = NULL;
60 static char pidfile_path[PATH_MAX];
62 void printlog(int priority, const char *format, ...)
64 va_list arg;
66 va_start (arg, format);
68 if (logok)
69 vsyslog(priority,format,arg);
70 else {
71 fprintf(stderr,"%s: ",prog);
72 vfprintf(stderr,format,arg);
73 fprintf(stderr,"\n");
75 va_end (arg);
78 static void cleanup(void)
80 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
81 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
84 if (vdestream != NULL)
85 vdestream_close(vdestream);
86 if (conn != NULL)
87 vde_close(conn);
90 static void sig_handler(int sig)
92 cleanup();
93 signal(sig, SIG_DFL);
94 if (sig == SIGTERM)
95 _exit(0);
96 else
97 kill(getpid(), sig);
100 static void setsighandlers()
102 /* setting signal handlers.
103 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
104 * ignores all the others signals which could cause termination. */
105 struct { int sig; const char *name; int ignore; } signals[] = {
106 { SIGHUP, "SIGHUP", 0 },
107 { SIGINT, "SIGINT", 0 },
108 { SIGPIPE, "SIGPIPE", 1 },
109 { SIGALRM, "SIGALRM", 1 },
110 { SIGTERM, "SIGTERM", 0 },
111 { SIGUSR1, "SIGUSR1", 1 },
112 { SIGUSR2, "SIGUSR2", 1 },
113 { SIGPROF, "SIGPROF", 1 },
114 { SIGVTALRM, "SIGVTALRM", 1 },
115 #if defined VDE_LINUX || defined VDE_BIONIC
116 { SIGPOLL, "SIGPOLL", 1 },
117 #ifdef SIGSTKFLT
118 { SIGSTKFLT, "SIGSTKFLT", 1 },
119 #endif
120 { SIGIO, "SIGIO", 1 },
121 { SIGPWR, "SIGPWR", 1 },
122 #ifdef SIGUNUSED
123 { SIGUNUSED, "SIGUNUSED", 1 },
124 #endif
125 #endif
126 #ifdef VDE_DARWIN
127 { SIGXCPU, "SIGXCPU", 1 },
128 { SIGXFSZ, "SIGXFSZ", 1 },
129 #endif
130 { 0, NULL, 0 }
133 int i;
134 for(i = 0; signals[i].sig != 0; i++)
135 if(signal(signals[i].sig,
136 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
137 perror("Setting handler");
140 static void usage(void) {
141 fprintf(stderr, "Usage: %s [OPTION]... tap_name\n\n", prog);
142 fprintf(stderr, " -p, --port=portnum Port number in the VDE switch\n"
143 " -g, --group=group Group for the socket\n"
144 " -m, --mode=mode Octal mode for the socket\n"
145 " -s, --sock=socket VDE switch control socket or dir\n"
146 " -d, --daemon Launch in background\n"
147 " -P, --pidfile=pidfile Create pidfile with our PID\n"
148 " -h, --help This help\n");
149 exit(-1);
152 #ifdef VDE_LINUX
153 int open_tap(char *dev)
155 struct ifreq ifr;
156 int fd;
158 if((fd = open("/dev/net/tun", O_RDWR)) < 0){
159 printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
160 return(-1);
162 memset(&ifr, 0, sizeof(ifr));
163 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
164 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
165 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
166 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
167 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
168 close(fd);
169 return(-1);
171 return(fd);
173 #endif
175 #ifdef VDE_BIONIC
176 int open_tap(char *dev)
178 struct ifreq ifr;
179 int fd;
181 if((fd = open("/dev/tun", O_RDWR)) < 0){
182 printlog(LOG_ERR,"Failed to open /dev/tun %s",strerror(errno));
183 return(-1);
185 memset(&ifr, 0, sizeof(ifr));
186 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
187 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
188 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
189 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
190 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
191 close(fd);
192 return(-1);
194 return(fd);
196 #endif
198 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
199 int open_tap(char *dev)
201 int fd;
202 int prefixlen = strlen(TAP_PREFIX);
203 char *path = NULL;
204 if (*dev == '/')
205 fd=open(dev, O_RDWR);
206 else
208 path = malloc(strlen(dev) + prefixlen + 1);
209 if (path != NULL)
211 snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
212 fd=open(path, O_RDWR);
213 free(path);
215 else
216 fd = -1;
219 if (fd < 0)
221 printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
222 return(-1);
224 return fd;
226 #endif
228 unsigned char bufin[BUFSIZE];
230 static void save_pidfile()
232 if(pidfile[0] != '/')
233 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path) - 1);
234 else
235 strncpy(pidfile_path, pidfile, PATH_MAX - 1);
237 int fd = open(pidfile_path,
238 O_WRONLY | O_CREAT | O_EXCL,
239 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
240 FILE *f;
242 if(fd == -1) {
243 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
244 exit(1);
247 if((f = fdopen(fd, "w")) == NULL) {
248 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
249 exit(1);
252 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
253 printlog(LOG_ERR, "Error in writing pidfile");
254 exit(1);
257 fclose(f);
260 static ssize_t vde_plug2tap_recv(void *opaque, void *buf, size_t count)
262 int *tapfdp=opaque;
263 return write(*tapfdp,buf,count);
266 int main(int argc, char **argv)
268 static char *sockname=NULL;
269 static char *tapname=NULL;
270 int daemonize=0;
271 int tapfd;
272 register ssize_t nx;
273 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
274 int c;
275 static struct pollfd pollv[]={{0,POLLIN|POLLHUP},
276 {0,POLLIN|POLLHUP},
277 {0,POLLIN|POLLHUP}};
278 int npollv;
280 prog=argv[0];
281 while (1) {
282 int option_index = 0;
284 static struct option long_options[] = {
285 {"sock", 1, 0, 's'},
286 {"port", 1, 0, 'p'},
287 {"help",0,0,'h'},
288 {"mod",1,0,'m'},
289 {"group",1,0,'g'},
290 {"daemon",0,0,'d'},
291 {"pidfile", 1, 0, 'P'},
292 {0, 0, 0, 0}
294 c = GETOPT_LONG (argc, argv, "hdP:p:s:m:g:",
295 long_options, &option_index);
296 if (c == -1)
297 break;
299 switch (c) {
300 case 'p':
301 open_args.port=atoi(optarg);
302 if (open_args.port <= 0)
303 usage(); //implies exit
304 break;
306 case 'h':
307 usage(); //implies exit
308 break;
310 case 's':
311 sockname=strdup(optarg);
312 break;
314 case 'm':
315 sscanf(optarg,"%o",(unsigned int *)&(open_args.mode));
316 break;
318 case 'g':
319 open_args.group=strdup(optarg);
320 break;
322 case 'd':
323 daemonize=1;
324 break;
326 case 'P':
327 pidfile=strdup(optarg);
328 break;
330 default:
331 usage(); //implies exit
335 if (daemonize) {
336 openlog(basename(prog), LOG_PID, 0);
337 logok=1;
338 syslog(LOG_INFO,"VDE_PLUG2TAP started");
340 /* saves current path in pidfile_path, because otherwise with daemonize() we
341 * forget it */
342 if(getcwd(pidfile_path, PATH_MAX-2) == NULL) {
343 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
344 exit(1);
346 strcat(pidfile_path, "/");
347 if (daemonize && daemon(0, 0)) {
348 printlog(LOG_ERR,"daemon: %s",strerror(errno));
349 exit(1);
352 /* once here, we're sure we're the true process which will continue as a
353 * server: save PID file if needed */
354 if(pidfile) save_pidfile();
356 if (optind < argc)
357 tapname=argv[optind];
358 else
359 usage(); // implies exit
361 atexit(cleanup);
362 setsighandlers();
364 tapfd=open_tap(tapname);
365 if(tapfd<0)
366 exit(1);
367 pollv[0].fd=tapfd;
369 if (sockname==NULL || strcmp(sockname,"-") != 0) {
370 conn=vde_open(sockname,"vde_plug2tap:",&open_args);
371 if (conn == NULL) {
372 printlog(LOG_ERR,"vde_open %s: %s",sockname?sockname:"DEF_SWITCH",strerror(errno));
373 exit(1);
375 pollv[1].fd=vde_datafd(conn);
376 pollv[2].fd=vde_ctlfd(conn);
377 npollv=3;
378 } else {
379 vdestream=vdestream_open(&tapfd,STDOUT_FILENO,vde_plug2tap_recv,NULL);
380 if (vdestream == NULL)
381 exit(1);
382 pollv[1].fd=STDIN_FILENO;
383 npollv=2;
386 for(;;) {
387 poll(pollv,3,-1);
388 if ((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP ||
389 (npollv > 2 && pollv[2].revents & POLLIN))
390 break;
391 if (pollv[0].revents & POLLIN) {
392 nx=read(tapfd,bufin,sizeof(bufin));
393 /* if POLLIN but not data it means that the stream has been
394 * closed at the other end */
395 //fprintf(stderr,"%s: RECV %d %x %x \n",prog,nx,bufin[0],bufin[1]);
396 if (nx<=0)
397 break;
398 if (conn != NULL)
399 vde_send(conn,bufin,nx,0);
400 else
401 vdestream_send(vdestream, bufin, nx);
403 if (pollv[1].revents & POLLIN) {
404 if (conn != NULL) {
405 nx=vde_recv(conn,bufin,sizeof(bufin),0);
406 if (nx<=0)
407 break;
408 write(tapfd,bufin,nx);
409 } else {
410 nx=read(STDIN_FILENO,bufin,sizeof(bufin));
411 if (nx<=0)
412 break;
413 vdestream_recv(vdestream,bufin,nx);
415 //fprintf(stderr,"%s: SENT %d %x %x \n",prog,nx,bufin[0],bufin[1]);
419 return(0);