Logo Search packages:      
Sourcecode: vde2 version File versions  Download package

vde_plug2tap.c

/* Copyright 2006 Renzo Davoli 
 * from vde_plug Davoli Gardenghi
 */

#include <config.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <poll.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <syslog.h>
#include <libgen.h>
#include <libvdeplug/libvdeplug.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <vde.h>

#define BUFSIZE 2048

#ifdef VDE_LINUX
#include <net/if.h>
#include <linux/if_tun.h>
#endif

#ifdef VDE_DARWIN
#     define TAP_PREFIX "/dev/"
#     include <limits.h>
#     if defined HAVE_SYSLIMITS_H
#           include <syslimits.h>
#     elif defined HAVE_SYS_SYSLIMITS_H
#           include <sys/syslimits.h>
#     else
#           error "No syslimits.h found"
#     endif
#endif

VDECONN *conn;

char *prog;
int logok;
static char *pidfile = NULL;
static char pidfile_path[PATH_MAX];

void printlog(int priority, const char *format, ...)
{
      va_list arg;

      va_start (arg, format);

      if (logok)
            vsyslog(priority,format,arg);
      else {
            fprintf(stderr,"%s: ",prog);
            vfprintf(stderr,format,arg);
            fprintf(stderr,"\n");
      }
      va_end (arg);
}

static void cleanup(void)
{
      if((pidfile != NULL) && unlink(pidfile_path) < 0) {
            printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
      }

      vde_close(conn);
}

static void sig_handler(int sig)
{
      cleanup();
      signal(sig, SIG_DFL);
      kill(getpid(), sig);
}

static void setsighandlers()
{
      /* setting signal handlers.
       * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
       * ignores all the others signals which could cause termination. */
      struct { int sig; const char *name; int ignore; } signals[] = {
            { SIGHUP, "SIGHUP", 0 },
            { SIGINT, "SIGINT", 0 },
            { SIGPIPE, "SIGPIPE", 1 },
            { SIGALRM, "SIGALRM", 1 },
            { SIGTERM, "SIGTERM", 0 },
            { SIGUSR1, "SIGUSR1", 1 },
            { SIGUSR2, "SIGUSR2", 1 },
            { SIGPROF, "SIGPROF", 1 },
            { SIGVTALRM, "SIGVTALRM", 1 },
#ifdef VDE_LINUX
            { SIGPOLL, "SIGPOLL", 1 },
#ifdef SIGSTKFLT
            { SIGSTKFLT, "SIGSTKFLT", 1 },
#endif
            { SIGIO, "SIGIO", 1 },
            { SIGPWR, "SIGPWR", 1 },
#ifdef SIGUNUSED
            { SIGUNUSED, "SIGUNUSED", 1 },
#endif
#endif
#ifdef VDE_DARWIN
            { SIGXCPU, "SIGXCPU", 1 },
            { SIGXFSZ, "SIGXFSZ", 1 },
#endif
            { 0, NULL, 0 }
      };

      int i;
      for(i = 0; signals[i].sig != 0; i++)
            if(signal(signals[i].sig,
                              signals[i].ignore ? SIG_IGN : sig_handler) < 0)
                  perror("Setting handler");
}

struct pollfd pollv[]={{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP}};

static void usage(void) {
      fprintf(stderr, "Usage: %s [OPTION]... tap_name\n\n", prog);
      fprintf(stderr, "  -p, --port=portnum          Port number in the VDE switch\n"
                          "  -g, --group=group           Group for the socket\n"
                              "  -m, --mode=mode             Octal mode for the socket\n"
                              "  -s, --sock=socket           VDE switch control socket or dir\n"
                              "  -d, --daemon                Launch in background\n"
                              "  -P, --pidfile=pidfile       Create pidfile with our PID\n"
                              "  -h, --help                  This help\n");
      exit(-1);
}

#ifdef VDE_LINUX
int open_tap(char *dev)
{
      struct ifreq ifr;
      int fd;

      if((fd = open("/dev/net/tun", O_RDWR)) < 0){
            printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
            return(-1);
      }
      memset(&ifr, 0, sizeof(ifr));
      ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
      strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
      /*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
      if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
            printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
            close(fd);
            return(-1);
      }
      return(fd);
}
#endif

#ifdef VDE_DARWIN
int open_tap(char *dev)
{
      int fd;
      int prefixlen = strlen(TAP_PREFIX);
      char *path = NULL;
      if (*dev == '/')
            fd=open(dev, O_RDWR);
      else
      {
            path = malloc(strlen(dev) + prefixlen + 1);
            if (path != NULL)
            {
                  snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
                  fd=open(path, O_RDWR);
                  free(path);
            }
            else
                  fd = -1;
      }

      if (fd < 0)
      {
            printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
            return(-1);
      }
      return fd;
}
#endif

unsigned char bufin[BUFSIZE];

static void save_pidfile()
{
      if(pidfile[0] != '/')
            strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
      else
            strcpy(pidfile_path, pidfile);

      int fd = open(pidfile_path,
                  O_WRONLY | O_CREAT | O_EXCL,
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
      FILE *f;

      if(fd == -1) {
            printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
            exit(1);
      }

      if((f = fdopen(fd, "w")) == NULL) {
            printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
            exit(1);
      }

      if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
            printlog(LOG_ERR, "Error in writing pidfile");
            exit(1);
      }

      fclose(f);
}

int main(int argc, char **argv)
{
      static char *sockname=NULL;
      static char *tapname=NULL;
      int daemonize=0;
      int result;
      int tapfd;
      register ssize_t nx;
      struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
      int c;
      prog=argv[0];
      while (1) {
            int option_index = 0;

            static struct option long_options[] = {
                  {"sock", 1, 0, 's'},
                  {"port", 1, 0, 'p'},
                  {"help",0,0,'h'},
                  {"mod",1,0,'m'},
                  {"group",1,0,'g'},
                  {"daemon",0,0,'d'},
                  {"pidfile", 1, 0, 'P'},
                  {0, 0, 0, 0}
            };
            c = GETOPT_LONG (argc, argv, "hdP:p:s:m:g:",
                        long_options, &option_index);
            if (c == -1)
                  break;

            switch (c) {
                  case 'p':
                        open_args.port=atoi(optarg);
                        if (open_args.port <= 0 || open_args.port > 255 )
                              usage(); //implies exit
                        break;

                  case 'h':
                        usage(); //implies exit
                        break;

                  case 's':
                        sockname=strdup(optarg);
                        break;

                  case 'm':
                        sscanf(optarg,"%o",&(open_args.mode));
                        break;

                  case 'g':
                        open_args.group=strdup(optarg);
                        break;

                  case 'd':
                        daemonize=1;
                        break;

                  case 'P':
                        pidfile=strdup(optarg);
                        break;

                  default:
                        usage(); //implies exit
            }
      }

      if (daemonize) {
            openlog(basename(prog), LOG_PID, 0);
            logok=1;
            syslog(LOG_INFO,"VDE_PLUG2TAP started");
      }
      /* saves current path in pidfile_path, because otherwise with daemonize() we
       * forget it */
      if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
            printlog(LOG_ERR, "getcwd: %s", strerror(errno));
            exit(1);
      }
      strcat(pidfile_path, "/");
      if (daemonize && daemon(0, 0)) {
            printlog(LOG_ERR,"daemon: %s",strerror(errno));
            exit(1);
      }

      /* once here, we're sure we're the true process which will continue as a
       * server: save PID file if needed */
      if(pidfile) save_pidfile();

      if (optind < argc)
            tapname=argv[optind];
      else
            usage(); // implies exit
      
      atexit(cleanup);
      setsighandlers();

      tapfd=open_tap(tapname);
      if(tapfd<0)
            exit(1);
      conn=vde_open(sockname,"vde_plug:",&open_args);
      if (conn == NULL)
            exit(1);

      pollv[0].fd=tapfd;
      pollv[1].fd=vde_datafd(conn);
      pollv[2].fd=vde_ctlfd(conn);

      for(;;) {
            result=poll(pollv,3,-1);
            if ((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP ||
                        pollv[2].revents & POLLIN) 
                  break;
            if (pollv[0].revents & POLLIN) {
                  nx=read(tapfd,bufin,sizeof(bufin));
                  /* if POLLIN but not data it means that the stream has been
                   * closed at the other end */
                  //fprintf(stderr,"%s: RECV %d %x %x \n",prog,nx,bufin[0],bufin[1]);
                  if (nx<=0)
                        break;
                  vde_send(conn,bufin,nx,0);
            }
            if (pollv[1].revents & POLLIN) {
                  nx=vde_recv(conn,bufin,sizeof(bufin),0);
                  if (nx<=0)
                        break;
                  write(tapfd,bufin,nx);
                  //fprintf(stderr,"%s: SENT %d %x %x \n",prog,nx,bufin[0],bufin[1]);
            }

      }
      return(0);
}

Generated by  Doxygen 1.6.0   Back to index