cvs_plug2tap (direct connection to the tap). bugfix in libvdeplug
[vde.git] / vde-2 / vde_plug2tap / vde_plug2tap.c
blob42c47f416afd92a2b4570bf5526ec2c8b2ddbf38
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 #endif
37 VDECONN *conn;
39 char *prog;
40 int logok;
41 static char *pidfile = NULL;
42 static char pidfile_path[PATH_MAX];
44 void printlog(int priority, const char *format, ...)
46 va_list arg;
48 va_start (arg, format);
50 if (logok)
51 vsyslog(priority,format,arg);
52 else {
53 fprintf(stderr,"%s: ",prog);
54 vfprintf(stderr,format,arg);
55 fprintf(stderr,"\n");
57 va_end (arg);
60 static void cleanup(void)
62 if((pidfile != NULL) && unlink(pidfile_path) < 0) {
63 printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
66 vde_close(conn);
69 static void sig_handler(int sig)
71 cleanup();
72 signal(sig, SIG_DFL);
73 kill(getpid(), sig);
76 static void setsighandlers()
78 /* setting signal handlers.
79 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
80 * ignores all the others signals which could cause termination. */
81 struct { int sig; const char *name; int ignore; } signals[] = {
82 { SIGHUP, "SIGHUP", 0 },
83 { SIGINT, "SIGINT", 0 },
84 { SIGPIPE, "SIGPIPE", 1 },
85 { SIGALRM, "SIGALRM", 1 },
86 { SIGTERM, "SIGTERM", 0 },
87 { SIGUSR1, "SIGUSR1", 1 },
88 { SIGUSR2, "SIGUSR2", 1 },
89 { SIGPROF, "SIGPROF", 1 },
90 { SIGVTALRM, "SIGVTALRM", 1 },
91 #ifdef VDE_LINUX
92 { SIGPOLL, "SIGPOLL", 1 },
93 { SIGSTKFLT, "SIGSTKFLT", 1 },
94 { SIGIO, "SIGIO", 1 },
95 { SIGPWR, "SIGPWR", 1 },
96 { SIGUNUSED, "SIGUNUSED", 1 },
97 #endif
98 #ifdef VDE_DARWIN
99 { SIGXCPU, "SIGXCPU", 1 },
100 { SIGXFSZ, "SIGXFSZ", 1 },
101 #endif
102 { 0, NULL, 0 }
105 int i;
106 for(i = 0; signals[i].sig != 0; i++)
107 if(signal(signals[i].sig,
108 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
109 perror("Setting handler");
112 struct pollfd pollv[]={{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP}};
114 static void usage(void) {
115 fprintf (stderr,"Usage: %s [-p portnum] [-g group] [-m mod] [-s sock] -daemon tap_name\n\n",prog);
116 exit(-1);
119 #ifdef VDE_LINUX
120 int open_tap(char *dev)
122 struct ifreq ifr;
123 int fd;
125 if((fd = open("/dev/net/tun", O_RDWR)) < 0){
126 printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
127 return(-1);
129 memset(&ifr, 0, sizeof(ifr));
130 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
131 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
132 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
133 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
134 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
135 close(fd);
136 return(-1);
138 return(fd);
140 #endif
142 #ifdef VDE_DARWIN
143 int open_tap(char *dev)
145 int fd;
146 int prefixlen = strlen(TAP_PREFIX);
147 char *path = NULL;
148 if (*dev == '/')
149 fd=open(dev, O_RDWR);
150 else
152 path = malloc(strlen(dev) + prefixlen + 1);
153 if (path != NULL)
155 snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
156 fd=open(path, O_RDWR);
157 free(path);
159 else
160 fd = -1;
163 if (fd < 0)
165 printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
166 return(-1);
168 return fd;
170 #endif
172 unsigned char bufin[BUFSIZE];
174 static void save_pidfile()
176 if(pidfile[0] != '/')
177 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
178 else
179 strcpy(pidfile_path, pidfile);
181 int fd = open(pidfile_path,
182 O_WRONLY | O_CREAT | O_EXCL,
183 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
184 FILE *f;
186 if(fd == -1) {
187 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
188 exit(1);
191 if((f = fdopen(fd, "w")) == NULL) {
192 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
193 exit(1);
196 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
197 printlog(LOG_ERR, "Error in writing pidfile");
198 exit(1);
201 fclose(f);
204 int main(int argc, char **argv)
206 static char *sockname=NULL;
207 static char *tapname=NULL;
208 int daemonize=0;
209 int result;
210 int tapfd;
211 register ssize_t nx;
212 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
213 int c;
214 prog=argv[0];
215 while (1) {
216 int option_index = 0;
218 static struct option long_options[] = {
219 {"sock", 1, 0, 's'},
220 {"port", 1, 0, 'p'},
221 {"help",0,0,'h'},
222 {"mod",1,0,'m'},
223 {"group",1,0,'g'},
224 {"daemon",0,0,'d'},
225 {"pidfile", 1, 0, 'P'},
226 {0, 0, 0, 0}
228 c = GETOPT_LONG (argc, argv, "hdPp:s:m:g:",
229 long_options, &option_index);
230 if (c == -1)
231 break;
233 switch (c) {
234 case 'p':
235 open_args.port=atoi(optarg);
236 if (open_args.port <= 0 || open_args.port > 255 )
237 usage(); //implies exit
238 break;
240 case 'h':
241 usage(); //implies exit
242 break;
244 case 's':
245 sockname=strdup(optarg);
246 break;
248 case 'm':
249 sscanf(optarg,"%o",&(open_args.mode));
250 break;
252 case 'g':
253 open_args.group=strdup(optarg);
254 break;
256 case 'd':
257 daemonize=1;
258 break;
260 case 'P':
261 pidfile=strdup(optarg);
262 break;
264 default:
265 usage(); //implies exit
269 if (daemonize) {
270 openlog(basename(prog), LOG_PID, 0);
271 logok=1;
272 syslog(LOG_INFO,"VDE_PLUG2TAP started");
274 /* saves current path in pidfile_path, because otherwise with daemonize() we
275 * forget it */
276 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
277 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
278 exit(1);
280 strcat(pidfile_path, "/");
281 if (daemonize && daemon(0, 1)) {
282 printlog(LOG_ERR,"daemon: %s",strerror(errno));
283 exit(1);
286 /* once here, we're sure we're the true process which will continue as a
287 * server: save PID file if needed */
288 if(pidfile) save_pidfile();
290 if (optind < argc)
291 tapname=argv[optind];
292 atexit(cleanup);
293 setsighandlers();
295 tapfd=open_tap(tapname);
296 if(tapfd<0)
297 exit(1);
298 conn=vde_open(sockname,"vde_plug:",&open_args);
299 if (conn == NULL)
300 exit(1);
302 pollv[0].fd=tapfd;
303 pollv[1].fd=vde_datafd(conn);
304 pollv[2].fd=vde_ctlfd(conn);
306 for(;;) {
307 result=poll(pollv,3,-1);
308 if ((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP ||
309 pollv[2].revents & POLLIN)
310 break;
311 if (pollv[0].revents & POLLIN) {
312 nx=read(tapfd,bufin,sizeof(bufin));
313 /* if POLLIN but not data it means that the stream has been
314 * closed at the other end */
315 //fprintf(stderr,"%s: RECV %d %x %x \n",prog,nx,bufin[0],bufin[1]);
316 if (nx<=0)
317 break;
318 vde_send(conn,bufin,nx,0);
320 if (pollv[1].revents & POLLIN) {
321 nx=vde_recv(conn,bufin,sizeof(bufin),0);
322 if (nx<=0)
323 break;
324 write(tapfd,bufin,nx);
325 //fprintf(stderr,"%s: SENT %d %x %x \n",prog,nx,bufin[0],bufin[1]);
329 return(0);