VDE 2.1.6, 2006-12-21
[vde.git] / vde-2 / vde_plug2tap / vde_plug2tap.c
blobd2fa1ed0d68dd3cc6b9198bcb2a3ad00b1ee464f
1 /* Copyright 2006 Renzo Davoli
2 * from vde_plug Davoli Gardenghi
3 */
5 #include <config.h>
6 #include <stdio.h>
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <signal.h>
11 #include <poll.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 #include <libvdeplug/libvdeplug.h>
22 #define _GNU_SOURCE
23 #include <getopt.h>
24 #include <vde.h>
26 #define BUFSIZE 2048
28 #ifdef VDE_LINUX
29 #include <net/if.h>
30 #include <linux/if_tun.h>
31 #endif
33 #ifdef VDE_DARWIN
34 # define TAP_PREFIX "/dev/"
35 # include <limits.h>
36 # if defined HAVE_SYSLIMITS_H
37 # include <syslimits.h>
38 # elif defined HAVE_SYS_SYSLIMITS_H
39 # include <sys/syslimits.h>
40 # else
41 # error "No syslimits.h found"
42 # endif
43 #endif
45 VDECONN *conn;
47 char *prog;
48 int logok;
49 static char *pidfile = NULL;
50 static char pidfile_path[PATH_MAX];
52 void printlog(int priority, const char *format, ...)
54 va_list arg;
56 va_start (arg, format);
58 if (logok)
59 vsyslog(priority,format,arg);
60 else {
61 fprintf(stderr,"%s: ",prog);
62 vfprintf(stderr,format,arg);
63 fprintf(stderr,"\n");
65 va_end (arg);
68 static void cleanup(void)
70 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
71 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
74 vde_close(conn);
77 static void sig_handler(int sig)
79 cleanup();
80 signal(sig, SIG_DFL);
81 kill(getpid(), sig);
84 static void setsighandlers()
86 /* setting signal handlers.
87 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
88 * ignores all the others signals which could cause termination. */
89 struct { int sig; const char *name; int ignore; } signals[] = {
90 { SIGHUP, "SIGHUP", 0 },
91 { SIGINT, "SIGINT", 0 },
92 { SIGPIPE, "SIGPIPE", 1 },
93 { SIGALRM, "SIGALRM", 1 },
94 { SIGTERM, "SIGTERM", 0 },
95 { SIGUSR1, "SIGUSR1", 1 },
96 { SIGUSR2, "SIGUSR2", 1 },
97 { SIGPROF, "SIGPROF", 1 },
98 { SIGVTALRM, "SIGVTALRM", 1 },
99 #ifdef VDE_LINUX
100 { SIGPOLL, "SIGPOLL", 1 },
101 #ifdef SIGSTKFLT
102 { SIGSTKFLT, "SIGSTKFLT", 1 },
103 #endif
104 { SIGIO, "SIGIO", 1 },
105 { SIGPWR, "SIGPWR", 1 },
106 #ifdef SIGUNUSED
107 { SIGUNUSED, "SIGUNUSED", 1 },
108 #endif
109 #endif
110 #ifdef VDE_DARWIN
111 { SIGXCPU, "SIGXCPU", 1 },
112 { SIGXFSZ, "SIGXFSZ", 1 },
113 #endif
114 { 0, NULL, 0 }
117 int i;
118 for(i = 0; signals[i].sig != 0; i++)
119 if(signal(signals[i].sig,
120 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
121 perror("Setting handler");
124 struct pollfd pollv[]={{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP}};
126 static void usage(void) {
127 fprintf(stderr, "Usage: %s [OPTION]... tap_name\n\n", prog);
128 fprintf(stderr, " -p, --port=portnum Port number in the VDE switch\n"
129 " -g, --group=group Group for the socket\n"
130 " -m, --mode=mode Octal mode for the socket\n"
131 " -s, --sock=socket VDE switch control socket or dir\n"
132 " -d, --daemon Launch in background\n"
133 " -P, --pidfile=pidfile Create pidfile with our PID\n"
134 " -h, --help This help\n");
135 exit(-1);
138 #ifdef VDE_LINUX
139 int open_tap(char *dev)
141 struct ifreq ifr;
142 int fd;
144 if((fd = open("/dev/net/tun", O_RDWR)) < 0){
145 printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
146 return(-1);
148 memset(&ifr, 0, sizeof(ifr));
149 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
150 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
151 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
152 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
153 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
154 close(fd);
155 return(-1);
157 return(fd);
159 #endif
161 #ifdef VDE_DARWIN
162 int open_tap(char *dev)
164 int fd;
165 int prefixlen = strlen(TAP_PREFIX);
166 char *path = NULL;
167 if (*dev == '/')
168 fd=open(dev, O_RDWR);
169 else
171 path = malloc(strlen(dev) + prefixlen + 1);
172 if (path != NULL)
174 snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
175 fd=open(path, O_RDWR);
176 free(path);
178 else
179 fd = -1;
182 if (fd < 0)
184 printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
185 return(-1);
187 return fd;
189 #endif
191 unsigned char bufin[BUFSIZE];
193 static void save_pidfile()
195 if(pidfile[0] != '/')
196 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
197 else
198 strcpy(pidfile_path, pidfile);
200 int fd = open(pidfile_path,
201 O_WRONLY | O_CREAT | O_EXCL,
202 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
203 FILE *f;
205 if(fd == -1) {
206 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
207 exit(1);
210 if((f = fdopen(fd, "w")) == NULL) {
211 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
212 exit(1);
215 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
216 printlog(LOG_ERR, "Error in writing pidfile");
217 exit(1);
220 fclose(f);
223 int main(int argc, char **argv)
225 static char *sockname=NULL;
226 static char *tapname=NULL;
227 int daemonize=0;
228 int result;
229 int tapfd;
230 register ssize_t nx;
231 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
232 int c;
233 prog=argv[0];
234 while (1) {
235 int option_index = 0;
237 static struct option long_options[] = {
238 {"sock", 1, 0, 's'},
239 {"port", 1, 0, 'p'},
240 {"help",0,0,'h'},
241 {"mod",1,0,'m'},
242 {"group",1,0,'g'},
243 {"daemon",0,0,'d'},
244 {"pidfile", 1, 0, 'P'},
245 {0, 0, 0, 0}
247 c = GETOPT_LONG (argc, argv, "hdP:p:s:m:g:",
248 long_options, &option_index);
249 if (c == -1)
250 break;
252 switch (c) {
253 case 'p':
254 open_args.port=atoi(optarg);
255 if (open_args.port <= 0 || open_args.port > 255 )
256 usage(); //implies exit
257 break;
259 case 'h':
260 usage(); //implies exit
261 break;
263 case 's':
264 sockname=strdup(optarg);
265 break;
267 case 'm':
268 sscanf(optarg,"%o",&(open_args.mode));
269 break;
271 case 'g':
272 open_args.group=strdup(optarg);
273 break;
275 case 'd':
276 daemonize=1;
277 break;
279 case 'P':
280 pidfile=strdup(optarg);
281 break;
283 default:
284 usage(); //implies exit
288 if (daemonize) {
289 openlog(basename(prog), LOG_PID, 0);
290 logok=1;
291 syslog(LOG_INFO,"VDE_PLUG2TAP started");
293 /* saves current path in pidfile_path, because otherwise with daemonize() we
294 * forget it */
295 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
296 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
297 exit(1);
299 strcat(pidfile_path, "/");
300 if (daemonize && daemon(0, 0)) {
301 printlog(LOG_ERR,"daemon: %s",strerror(errno));
302 exit(1);
305 /* once here, we're sure we're the true process which will continue as a
306 * server: save PID file if needed */
307 if(pidfile) save_pidfile();
309 if (optind < argc)
310 tapname=argv[optind];
311 atexit(cleanup);
312 setsighandlers();
314 tapfd=open_tap(tapname);
315 if(tapfd<0)
316 exit(1);
317 conn=vde_open(sockname,"vde_plug:",&open_args);
318 if (conn == NULL)
319 exit(1);
321 pollv[0].fd=tapfd;
322 pollv[1].fd=vde_datafd(conn);
323 pollv[2].fd=vde_ctlfd(conn);
325 for(;;) {
326 result=poll(pollv,3,-1);
327 if ((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP ||
328 pollv[2].revents & POLLIN)
329 break;
330 if (pollv[0].revents & POLLIN) {
331 nx=read(tapfd,bufin,sizeof(bufin));
332 /* if POLLIN but not data it means that the stream has been
333 * closed at the other end */
334 //fprintf(stderr,"%s: RECV %d %x %x \n",prog,nx,bufin[0],bufin[1]);
335 if (nx<=0)
336 break;
337 vde_send(conn,bufin,nx,0);
339 if (pollv[1].revents & POLLIN) {
340 nx=vde_recv(conn,bufin,sizeof(bufin),0);
341 if (nx<=0)
342 break;
343 write(tapfd,bufin,nx);
344 //fprintf(stderr,"%s: SENT %d %x %x \n",prog,nx,bufin[0],bufin[1]);
348 return(0);