syslimits.h fix for OSX
[vde.git] / vde-2 / vde_plug2tap / vde_plug2tap.c
blob1bd4ee2fbdab83adcdde7a9138c6708292c750e8
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 { SIGSTKFLT, "SIGSTKFLT", 1 },
102 { SIGIO, "SIGIO", 1 },
103 { SIGPWR, "SIGPWR", 1 },
104 { SIGUNUSED, "SIGUNUSED", 1 },
105 #endif
106 #ifdef VDE_DARWIN
107 { SIGXCPU, "SIGXCPU", 1 },
108 { SIGXFSZ, "SIGXFSZ", 1 },
109 #endif
110 { 0, NULL, 0 }
113 int i;
114 for(i = 0; signals[i].sig != 0; i++)
115 if(signal(signals[i].sig,
116 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
117 perror("Setting handler");
120 struct pollfd pollv[]={{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP}};
122 static void usage(void) {
123 fprintf(stderr, "Usage: %s [OPTION]... tap_name\n\n", prog);
124 fprintf(stderr, " -p, --port=portnum Port number in the VDE switch\n"
125 " -g, --group=group Group for the socket\n"
126 " -m, --mode=mode Octal mode for the socket\n"
127 " -s, --sock=socket VDE switch control socket or dir\n"
128 " -d, --daemon Launch in background\n"
129 " -P, --pidfile=pidfile Create pidfile with our PID\n"
130 " -h, --help This help\n");
131 exit(-1);
134 #ifdef VDE_LINUX
135 int open_tap(char *dev)
137 struct ifreq ifr;
138 int fd;
140 if((fd = open("/dev/net/tun", O_RDWR)) < 0){
141 printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
142 return(-1);
144 memset(&ifr, 0, sizeof(ifr));
145 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
146 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
147 /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
148 if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
149 printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
150 close(fd);
151 return(-1);
153 return(fd);
155 #endif
157 #ifdef VDE_DARWIN
158 int open_tap(char *dev)
160 int fd;
161 int prefixlen = strlen(TAP_PREFIX);
162 char *path = NULL;
163 if (*dev == '/')
164 fd=open(dev, O_RDWR);
165 else
167 path = malloc(strlen(dev) + prefixlen + 1);
168 if (path != NULL)
170 snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
171 fd=open(path, O_RDWR);
172 free(path);
174 else
175 fd = -1;
178 if (fd < 0)
180 printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
181 return(-1);
183 return fd;
185 #endif
187 unsigned char bufin[BUFSIZE];
189 static void save_pidfile()
191 if(pidfile[0] != '/')
192 strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
193 else
194 strcpy(pidfile_path, pidfile);
196 int fd = open(pidfile_path,
197 O_WRONLY | O_CREAT | O_EXCL,
198 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
199 FILE *f;
201 if(fd == -1) {
202 printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
203 exit(1);
206 if((f = fdopen(fd, "w")) == NULL) {
207 printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
208 exit(1);
211 if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
212 printlog(LOG_ERR, "Error in writing pidfile");
213 exit(1);
216 fclose(f);
219 int main(int argc, char **argv)
221 static char *sockname=NULL;
222 static char *tapname=NULL;
223 int daemonize=0;
224 int result;
225 int tapfd;
226 register ssize_t nx;
227 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
228 int c;
229 prog=argv[0];
230 while (1) {
231 int option_index = 0;
233 static struct option long_options[] = {
234 {"sock", 1, 0, 's'},
235 {"port", 1, 0, 'p'},
236 {"help",0,0,'h'},
237 {"mod",1,0,'m'},
238 {"group",1,0,'g'},
239 {"daemon",0,0,'d'},
240 {"pidfile", 1, 0, 'P'},
241 {0, 0, 0, 0}
243 c = GETOPT_LONG (argc, argv, "hdP:p:s:m:g:",
244 long_options, &option_index);
245 if (c == -1)
246 break;
248 switch (c) {
249 case 'p':
250 open_args.port=atoi(optarg);
251 if (open_args.port <= 0 || open_args.port > 255 )
252 usage(); //implies exit
253 break;
255 case 'h':
256 usage(); //implies exit
257 break;
259 case 's':
260 sockname=strdup(optarg);
261 break;
263 case 'm':
264 sscanf(optarg,"%o",&(open_args.mode));
265 break;
267 case 'g':
268 open_args.group=strdup(optarg);
269 break;
271 case 'd':
272 daemonize=1;
273 break;
275 case 'P':
276 pidfile=strdup(optarg);
277 break;
279 default:
280 usage(); //implies exit
284 if (daemonize) {
285 openlog(basename(prog), LOG_PID, 0);
286 logok=1;
287 syslog(LOG_INFO,"VDE_PLUG2TAP started");
289 /* saves current path in pidfile_path, because otherwise with daemonize() we
290 * forget it */
291 if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
292 printlog(LOG_ERR, "getcwd: %s", strerror(errno));
293 exit(1);
295 strcat(pidfile_path, "/");
296 if (daemonize && daemon(0, 1)) {
297 printlog(LOG_ERR,"daemon: %s",strerror(errno));
298 exit(1);
301 /* once here, we're sure we're the true process which will continue as a
302 * server: save PID file if needed */
303 if(pidfile) save_pidfile();
305 if (optind < argc)
306 tapname=argv[optind];
307 atexit(cleanup);
308 setsighandlers();
310 tapfd=open_tap(tapname);
311 if(tapfd<0)
312 exit(1);
313 conn=vde_open(sockname,"vde_plug:",&open_args);
314 if (conn == NULL)
315 exit(1);
317 pollv[0].fd=tapfd;
318 pollv[1].fd=vde_datafd(conn);
319 pollv[2].fd=vde_ctlfd(conn);
321 for(;;) {
322 result=poll(pollv,3,-1);
323 if ((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP ||
324 pollv[2].revents & POLLIN)
325 break;
326 if (pollv[0].revents & POLLIN) {
327 nx=read(tapfd,bufin,sizeof(bufin));
328 /* if POLLIN but not data it means that the stream has been
329 * closed at the other end */
330 //fprintf(stderr,"%s: RECV %d %x %x \n",prog,nx,bufin[0],bufin[1]);
331 if (nx<=0)
332 break;
333 vde_send(conn,bufin,nx,0);
335 if (pollv[1].revents & POLLIN) {
336 nx=vde_recv(conn,bufin,sizeof(bufin),0);
337 if (nx<=0)
338 break;
339 write(tapfd,bufin,nx);
340 //fprintf(stderr,"%s: SENT %d %x %x \n",prog,nx,bufin[0],bufin[1]);
344 return(0);