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

posix-specific.c

/*
 * Copyright (C) 2006 BATMAN contributors:
 * Thomas Lopatic, Marek Lindner
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA
 *
 */



#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <net/if.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <syslog.h>
#include <paths.h>

#include "os.h"
#include "originator.h"
#include "batman.h"



static int8_t stop;



int8_t is_aborted() {

      return stop != 0;

}



void handler( int32_t sig ) {

      stop = 1;

}



int my_daemon() {

      int fd;

      switch( fork() ) {

            case -1:
                  return(-1);

            case 0:
                  break;

            default:
                  exit(EXIT_SUCCESS);

      }

      if ( setsid() == -1 )
            return(-1);

      /* Make certain we are not a session leader, or else we
      * might reacquire a controlling terminal */
      if ( fork() )
            exit(EXIT_SUCCESS);

      chdir("/");

      if ( ( fd = open(_PATH_DEVNULL, O_RDWR, 0) ) != -1 ) {

            dup2(fd, STDIN_FILENO);
            dup2(fd, STDOUT_FILENO);
            dup2(fd, STDERR_FILENO);

            if (fd > 2)
                  close(fd);

      }

      return(0);

}


void debug_output( int8_t debug_prio, char *format, ... ) {

      struct list_head *debug_pos;
      struct debug_level_info *debug_level_info;
      int8_t debug_prio_intern;
      va_list args;
      char tmp_string[500]; // TBD: must be checked for overflow when using with sprintf


      if ( debug_prio == 0 ) {

            if ( debug_level == 0 ) {

                  va_start( args, format );
                  vsyslog( LOG_ERR, format, args );
                  va_end( args );

            } else if ( ( debug_level == 3 ) || ( debug_level == 4 ) ) {

                  if ( debug_level == 4 )
                        printf( "[%10u] ", get_time() );

                  va_start( args, format );
                  vprintf( format, args );
                  va_end( args );

            }

            debug_prio_intern = 3;

      } else {

            debug_prio_intern = debug_prio - 1;

      }

      if ( debug_clients.clients_num[debug_prio_intern] > 0 ) {

            if ( pthread_mutex_trylock( (pthread_mutex_t *)debug_clients.mutex[debug_prio_intern] ) == 0 ) {

//                va_start( args, format );

                  list_for_each( debug_pos, (struct list_head *)debug_clients.fd_list[debug_prio_intern] ) {

                        debug_level_info = list_entry(debug_pos, struct debug_level_info, list);

                        if ( debug_prio_intern == 3 )
                              dprintf( debug_level_info->fd, "[%10u] ", get_time() );

                        if ( ( ( debug_level == 1 ) || ( debug_level == 2 ) ) && ( debug_level_info->fd == 1 ) && ( strncmp( format, "BOD", 3 ) == 0 ) ) {

                              system( "clear" );

                        } else {

                              if ( ( ( debug_level != 1 ) && ( debug_level != 2 ) ) || ( debug_level_info->fd != 1 ) || ( strncmp( format, "EOD", 3 ) != 0 ) ) {

                                    va_start( args, format );
                                    vsprintf( tmp_string, format, args );
// TODO: this causes lots of errors if enabled:
//                                  if( vdprintf( debug_level_info->fd, format, args ) < 0) {
//                                  if(
                                          dprintf( debug_level_info->fd, "%s", tmp_string );
//                                                                                  < 0) {
//                                        printf("error: could not write to fd !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! \n");
//                                  }

                                    va_end( args );

                              }

                        }

                  }

//                va_end( args );

                  if ( pthread_mutex_unlock( (pthread_mutex_t *)debug_clients.mutex[debug_prio_intern] ) < 0 )
                        debug_output( 0, "Error - could not unlock mutex (debug_output): %s \n", strerror( errno ) );

            } else {

                  debug_output( 0, "Warning - could not trylock mutex (debug_output): %s \n", strerror( EBUSY ) );

            }

      }

}



void *unix_listen( void *arg ) {

      struct unix_client *unix_client;
      struct debug_level_info *debug_level_info;
      struct list_head *unix_pos, *unix_pos_tmp, *debug_pos, *debug_pos_tmp;
      struct timeval tv;
      struct sockaddr_un sun_addr;
      int32_t status, max_sock, unix_opts;
      int8_t res;
      unsigned char buff[10];
      fd_set wait_sockets, tmp_wait_sockets;
      socklen_t sun_size = sizeof(struct sockaddr_un);


      INIT_LIST_HEAD(&unix_if.client_list);

      FD_ZERO(&wait_sockets);
      FD_SET(unix_if.unix_sock, &wait_sockets);

      max_sock = unix_if.unix_sock;

      while ( !is_aborted() ) {

            tv.tv_sec = 1;
            tv.tv_usec = 0;
            memcpy( &tmp_wait_sockets, &wait_sockets, sizeof(fd_set) );

            res = select( max_sock + 1, &tmp_wait_sockets, NULL, NULL, &tv );

            if ( res > 0 ) {

                  /* new client */
                  if ( FD_ISSET( unix_if.unix_sock, &tmp_wait_sockets ) ) {

                        unix_client = debugMalloc( sizeof(struct unix_client), 201 );
                        memset( unix_client, 0, sizeof(struct unix_client) );

                        if ( ( unix_client->sock = accept( unix_if.unix_sock, (struct sockaddr *)&sun_addr, &sun_size) ) == -1 ) {
                              debug_output( 0, "Error - can't accept unix client: %s \n", strerror(errno) );
                              continue;
                        }

                        INIT_LIST_HEAD( &unix_client->list );

                        FD_SET( unix_client->sock, &wait_sockets );
                        if ( unix_client->sock > max_sock )
                              max_sock = unix_client->sock;

                        list_add_tail( &unix_client->list, &unix_if.client_list );

                        debug_output( 3, "Unix socket: got connection \n" );

                  /* client sent data */
                  } else {

                        max_sock = unix_if.unix_sock;

                        list_for_each_safe(unix_pos, unix_pos_tmp, &unix_if.client_list) {

                              unix_client = list_entry(unix_pos, struct unix_client, list);

                              if ( FD_ISSET( unix_client->sock, &tmp_wait_sockets ) ) {

                                    status = read( unix_client->sock, buff, sizeof( buff ) );

                                    if ( status > 0 ) {

                                          if ( unix_client->sock > max_sock )
                                                max_sock = unix_client->sock;

                                          /* debug_output( 3, "gateway: client sent data via unix socket: %s\n", buff ); */

                                          if ( ( status > 2 ) && ( ( buff[2] == '1' ) || ( buff[2] == '2' ) || ( buff[2] == '3' ) || ( buff[2] == '4' ) ) ) {

                                                if ( unix_client->debug_level != 0 ) {

                                                      if ( pthread_mutex_lock( (pthread_mutex_t *)debug_clients.mutex[(int)unix_client->debug_level - '1'] ) != 0 )
                                                            debug_output( 0, "Error - could not lock mutex (unix_listen => 1): %s \n", strerror( errno ) );

                                                      list_for_each_safe( debug_pos, debug_pos_tmp, (struct list_head *)debug_clients.fd_list[(int)unix_client->debug_level - '1'] ) {

                                                            debug_level_info = list_entry(debug_pos, struct debug_level_info, list);

                                                            if ( debug_level_info->fd == unix_client->sock ) {

                                                                  list_del( debug_pos );
                                                                  debug_clients.clients_num[(int)unix_client->debug_level - '1']--;

                                                                  debugFree( debug_pos, 1201 );

                                                                  break;

                                                            }

                                                      }

                                                      if ( pthread_mutex_unlock( (pthread_mutex_t *)debug_clients.mutex[(int)unix_client->debug_level - '1'] ) != 0 )
                                                            debug_output( 0, "Error - could not unlock mutex (unix_listen => 1): %s \n", strerror( errno ) );

                                                }

                                                if ( unix_client->debug_level != buff[2] ) {

                                                      if ( pthread_mutex_lock( (pthread_mutex_t *)debug_clients.mutex[(int)buff[2] - '1'] ) != 0 )
                                                            debug_output( 0, "Error - could not lock mutex (unix_listen => 2): %s \n", strerror( errno ) );

                                                      debug_level_info = debugMalloc( sizeof(struct debug_level_info), 202 );
                                                      INIT_LIST_HEAD( &debug_level_info->list );
                                                      debug_level_info->fd = unix_client->sock;
                                                      list_add( &debug_level_info->list, (struct list_head *)debug_clients.fd_list[(int)buff[2] - '1'] );
                                                      debug_clients.clients_num[(int)buff[2] - '1']++;

                                                      unix_client->debug_level = (int)buff[2];

                                                      /* make unix socket non blocking */
                                                      unix_opts = fcntl( debug_level_info->fd, F_GETFL, 0 );
                                                      fcntl( debug_level_info->fd, F_SETFL, unix_opts | O_NONBLOCK );

                                                      if ( pthread_mutex_unlock( (pthread_mutex_t *)debug_clients.mutex[(int)buff[2] - '1'] ) != 0 )
                                                            debug_output( 0, "Error - could not unlock mutex (unix_listen => 2): %s \n", strerror( errno ) );

                                                } else {

                                                      unix_client->debug_level = 0;

                                                }



                                          }

                                    } else {

                                          if ( status < 0 )
                                                debug_output( 0, "Error - can't read unix message: %s \n", strerror(errno) );

                                          if ( unix_client->debug_level != 0 ) {

                                                if ( pthread_mutex_lock( (pthread_mutex_t *)debug_clients.mutex[(int)unix_client->debug_level - '1'] ) != 0 )
                                                      debug_output( 0, "Error - could not lock mutex (unix_listen => 3): %s \n", strerror( errno ) );

                                                list_for_each_safe( debug_pos, debug_pos_tmp, (struct list_head *)debug_clients.fd_list[(int)unix_client->debug_level - '1'] ) {

                                                      debug_level_info = list_entry(debug_pos, struct debug_level_info, list);

                                                      if ( debug_level_info->fd == unix_client->sock ) {

                                                            list_del( debug_pos );
                                                            debug_clients.clients_num[(int)unix_client->debug_level - '1']--;

                                                            debugFree( debug_pos, 1202 );

                                                            break;

                                                      }

                                                }

                                                if ( pthread_mutex_unlock( (pthread_mutex_t *)debug_clients.mutex[(int)unix_client->debug_level - '1'] ) != 0 )
                                                      debug_output( 0, "Error - could not unlock mutex (unix_listen => 3): %s \n", strerror( errno ) );

                                          }

                                          debug_output( 3, "Unix client closed connection ... \n" );

                                          FD_CLR(unix_client->sock, &wait_sockets);
                                          close( unix_client->sock );

                                          list_del( unix_pos );
                                          debugFree( unix_pos, 1203 );

                                    }

                              } else {

                                    if ( unix_client->sock > max_sock )
                                          max_sock = unix_client->sock;

                              }

                        }

                  }

            } else if ( ( res < 0 ) && ( errno != EINTR ) ) {

                  debug_output( 0, "Error - can't select: %s \n", strerror(errno) );
                  break;

            }

      }

      list_for_each_safe(unix_pos, unix_pos_tmp, &unix_if.client_list) {

            unix_client = list_entry(unix_pos, struct unix_client, list);

            if ( unix_client->debug_level != 0 ) {

                  list_for_each_safe( debug_pos, debug_pos_tmp, (struct list_head *)debug_clients.fd_list[(int)unix_client->debug_level - '1'] ) {

                        debug_level_info = list_entry(debug_pos, struct debug_level_info, list);

                        if ( debug_level_info->fd == unix_client->sock ) {

                              list_del( debug_pos );
                              debug_clients.clients_num[(int)unix_client->debug_level - '1']--;

                              debugFree( debug_pos, 1204 );

                              break;

                        }

                  }

            }

            list_del( unix_pos );
            debugFree( unix_pos, 1205 );

      }

      return NULL;

}



void apply_init_args( int argc, char *argv[] ) {

      struct in_addr tmp_ip_holder;
      struct batman_if *batman_if;
      struct hna_node *hna_node;
      struct debug_level_info *debug_level_info;
      uint8_t found_args = 1, batch_mode = 0;
      uint16_t netmask;
      int8_t res;

      int32_t optchar, recv_buff_len, bytes_written;
      char str1[16], str2[16], *slash_ptr, *unix_buff, *buff_ptr, *cr_ptr;
      uint32_t vis_server = 0;


      memset( &tmp_ip_holder, 0, sizeof (struct in_addr) );
      stop = 0;


      while ( ( optchar = getopt ( argc, argv, "a:bcd:hHo:g:p:r:s:vV" ) ) != -1 ) {

            switch ( optchar ) {

                  case 'a':

                        if ( ( slash_ptr = strchr( optarg, '/' ) ) == NULL ) {

                              printf( "Invalid announced network (netmask is missing): %s\n", optarg );
                              exit(EXIT_FAILURE);

                        }

                        *slash_ptr = '\0';

                        if ( inet_pton(AF_INET, optarg, &tmp_ip_holder) < 1 ) {

                              *slash_ptr = '/';
                              printf( "Invalid announced network (IP is invalid): %s\n", optarg );
                              exit(EXIT_FAILURE);

                        }

                        errno = 0;
                        netmask = strtol(slash_ptr + 1, NULL , 10);

                        if ( ( errno == ERANGE ) || ( errno != 0 && netmask == 0 ) ) {
                              perror("strtol");
                              exit(EXIT_FAILURE);
                        }

                        if ( netmask < 1 || netmask > 32 ) {

                              *slash_ptr = '/';
                              printf( "Invalid announced network (netmask is invalid): %s\n", optarg );
                              exit(EXIT_FAILURE);

                        }

                        hna_node = debugMalloc( sizeof(struct hna_node), 203 );
                        memset( hna_node, 0, sizeof(struct hna_node) );
                        INIT_LIST_HEAD( &hna_node->list );

                        hna_node->addr = tmp_ip_holder.s_addr;
                        hna_node->netmask = netmask;

                        list_add_tail( &hna_node->list, &hna_list );

                        *slash_ptr = '/';
                        found_args += 2;
                        break;

                  case 'b':
                        batch_mode++;
                        break;

                  case 'c':
                        unix_client++;
                        break;

                  case 'd':

                        errno = 0;
                        debug_level = strtol (optarg, NULL , 10);

                        if ( ( errno == ERANGE ) || ( errno != 0 && debug_level == 0 ) ) {
                              perror("strtol");
                              exit(EXIT_FAILURE);
                        }

                        if ( debug_level > 4 ) {
                              printf( "Invalid debug level: %i\nDebug level has to be between 0 and 4.\n", debug_level );
                              exit(EXIT_FAILURE);
                        }

                        found_args += 2;
                        break;

                  case 'g':

                        errno = 0;
                        gateway_class = strtol(optarg, NULL , 10);

                        if ( ( errno == ERANGE ) || ( errno != 0 && gateway_class == 0 ) ) {
                              perror("strtol");
                              exit(EXIT_FAILURE);
                        }

                        if ( gateway_class > 11 ) {
                              printf( "Invalid gateway class specified: %i.\nThe class is a value between 0 and 11.\n", gateway_class );
                              exit(EXIT_FAILURE);
                        }

                        found_args += 2;
                        break;

                  case 'H':
                        verbose_usage();
                        exit(EXIT_SUCCESS);

                  case 'o':

                        errno = 0;
                        orginator_interval = strtol (optarg, NULL , 10);

                        if ( orginator_interval < 1 ) {

                              printf( "Invalid orginator interval specified: %i.\nThe Interval has to be greater than 0.\n", orginator_interval );
                              exit(EXIT_FAILURE);

                        }

                        found_args += 2;
                        break;

                  case 'p':

                        errno = 0;
                        if ( inet_pton(AF_INET, optarg, &tmp_ip_holder) < 1 ) {

                              printf( "Invalid preferred gateway IP specified: %s\n", optarg );
                              exit(EXIT_FAILURE);

                        }

                        pref_gateway = tmp_ip_holder.s_addr;

                        found_args += 2;
                        break;

                  case 'r':

                        errno = 0;
                        routing_class = strtol (optarg, NULL , 10);

                        if ( routing_class > 3 ) {

                              printf( "Invalid routing class specified: %i.\nThe class is a value between 0 and 3.\n", routing_class );
                              exit(EXIT_FAILURE);

                        }

                        found_args += 2;
                        break;

                  case 's':

                        errno = 0;
                        if ( inet_pton(AF_INET, optarg, &tmp_ip_holder) < 1 ) {

                              printf( "Invalid preferred visualation server IP specified: %s\n", optarg );
                              exit(EXIT_FAILURE);

                        }

                        vis_server = tmp_ip_holder.s_addr;


                        found_args += 2;
                        break;

                  case 'v':

                        printf( "B.A.T.M.A.N. %s%s (compability version %i)\n", SOURCE_VERSION, ( strncmp( REVISION_VERSION, "0", 1 ) != 0 ? REVISION_VERSION : "" ), COMPAT_VERSION );
                        exit(EXIT_SUCCESS);

                  case 'V':

                        print_animation();

                        printf( "\x1B[0;0HB.A.T.M.A.N. %s%s (compability version %i)\n", SOURCE_VERSION, ( strncmp( REVISION_VERSION, "0", 1 ) != 0 ? REVISION_VERSION : "" ), COMPAT_VERSION );
                        printf( "\x1B[9;0H \t May the bat guide your path ...\n\n\n" );

                        exit(EXIT_SUCCESS);

                  case 'h':
                  default:
                        usage();
                        exit(EXIT_SUCCESS);

            }

      }


      if ( ( gateway_class != 0 ) && ( routing_class != 0 ) ) {
            fprintf( stderr, "Error - routing class can't be set while gateway class is in use !\n" );
            usage();
            exit(EXIT_FAILURE);
      }

      if ( ( gateway_class != 0 ) && ( pref_gateway != 0 ) ) {
            fprintf( stderr, "Error - preferred gateway can't be set while gateway class is in use !\n" );
            usage();
            exit(EXIT_FAILURE);
      }

      if ( ( routing_class == 0 ) && ( pref_gateway != 0 ) ) {
            fprintf( stderr, "Error - preferred gateway can't be set without specifying routing class !\n" );
            usage();
            exit(EXIT_FAILURE);
      }

      if ( ( ( routing_class != 0 ) || ( gateway_class != 0 ) ) && ( !probe_tun() ) )
            exit(EXIT_FAILURE);

      if ( ! unix_client ) {

            if ( argc <= found_args ) {
                  fprintf( stderr, "Error - no interface specified\n" );
                  usage();
                  restore_defaults();
                  exit(EXIT_FAILURE);
            }

            signal( SIGINT, handler );
            signal( SIGTERM, handler );
            signal( SIGPIPE, SIG_IGN );
            signal( SIGSEGV, segmentation_fault );

            for ( res = 0; res < 4; res++ ) {

                  debug_clients.fd_list[res] = debugMalloc( sizeof(struct list_head), 204 );
                  INIT_LIST_HEAD( (struct list_head *)debug_clients.fd_list[res] );
                  debug_clients.mutex[res] = debugMalloc( sizeof(pthread_mutex_t), 209 );
                  pthread_mutex_init( (pthread_mutex_t *)debug_clients.mutex[res], NULL );

            }

            memset( &debug_clients.clients_num, 0, sizeof(debug_clients.clients_num) );

            /* daemonize */
            if ( debug_level == 0 ) {

                  if ( my_daemon() < 0 ) {

                        printf( "Error - can't fork to background: %s\n", strerror(errno) );
                        restore_defaults();
                        exit(EXIT_FAILURE);

                  }

                  openlog( "batmand", LOG_PID, LOG_DAEMON );

            } else {

                  printf( "B.A.T.M.A.N. %s%s (compability version %i)\n", SOURCE_VERSION, ( strncmp( REVISION_VERSION, "0", 1 ) != 0 ? REVISION_VERSION : "" ), COMPAT_VERSION );

                  debug_clients.clients_num[ debug_level - 1 ]++;
                  debug_level_info = debugMalloc( sizeof(struct debug_level_info), 205 );
                  INIT_LIST_HEAD( &debug_level_info->list );
                  debug_level_info->fd = 1;
                  list_add( &debug_level_info->list, (struct list_head *)debug_clients.fd_list[debug_level - 1] );

            }

            FD_ZERO( &receive_wait_set );

            while ( argc > found_args ) {

                  batman_if = debugMalloc( sizeof(struct batman_if), 206 );
                  memset( batman_if, 0, sizeof(struct batman_if) );
                  INIT_LIST_HEAD( &batman_if->list );
                  INIT_LIST_HEAD( &batman_if->client_list );

                  batman_if->dev = argv[found_args];
                  batman_if->if_num = found_ifs;

                  list_add_tail( &batman_if->list, &if_list );

                  init_interface ( batman_if );

                  if ( batman_if->udp_recv_sock > receive_max_sock )
                        receive_max_sock = batman_if->udp_recv_sock;

                  FD_SET( batman_if->udp_recv_sock, &receive_wait_set );

                  addr_to_string(batman_if->addr.sin_addr.s_addr, str1, sizeof (str1));
                  addr_to_string(batman_if->broad.sin_addr.s_addr, str2, sizeof (str2));

                  if ( debug_level > 0 )
                        printf( "Using interface %s with address %s and broadcast address %s\n", batman_if->dev, str1, str2 );

                  if ( gateway_class != 0 ) {

                    init_interface_gw( batman_if );

                  }

                  found_ifs++;
                  found_args++;

            }

            if(vis_server)
            {
                  memset(&vis_if.addr, 0, sizeof(vis_if.addr));
                  vis_if.addr.sin_family = AF_INET;
                  vis_if.addr.sin_port = htons(1968);
                  vis_if.addr.sin_addr.s_addr = vis_server;
                  vis_if.sock = socket( PF_INET, SOCK_DGRAM, 0 );
                  /*vis_if.sock = ((struct batman_if *)if_list.next)->udp_send_sock;*/
            } else {
                  memset(&vis_if, 0, sizeof(vis_if));
            }


            unlink( UNIX_PATH );
            unix_if.unix_sock = socket( AF_LOCAL, SOCK_STREAM, 0 );

            memset( &unix_if.addr, 0, sizeof(struct sockaddr_un) );
            unix_if.addr.sun_family = AF_LOCAL;
            strcpy( unix_if.addr.sun_path, UNIX_PATH );

            if ( bind ( unix_if.unix_sock, (struct sockaddr *)&unix_if.addr, sizeof (struct sockaddr_un) ) < 0 ) {
                  debug_output( 0, "Error - can't bind unix socket: %s \n", strerror(errno) );
                  restore_defaults();
                  exit(EXIT_FAILURE);
            }

            if ( listen( unix_if.unix_sock, 10 ) < 0 ) {
                  debug_output( 0, "Error - can't listen unix socket: %s \n", strerror(errno) );
                  restore_defaults();
                  exit(EXIT_FAILURE);
            }

            pthread_create( &unix_if.listen_thread_id, NULL, &unix_listen, NULL );


            if ( debug_level > 0 ) {

                  printf( "debug level: %i\n", debug_level );

                  if ( orginator_interval != 1000 )
                        printf( "orginator interval: %i\n", orginator_interval );

                  if ( gateway_class > 0 )
                        printf( "gateway class: %i\n", gateway_class );

                  if ( routing_class > 0 )
                        printf( "routing class: %i\n", routing_class );

                  if ( pref_gateway > 0 ) {
                        addr_to_string(pref_gateway, str1, sizeof (str1));
                        printf( "preferred gateway: %s\n", str1 );
                  }

                  if ( vis_server > 0 ) {
                        addr_to_string(vis_server, str1, sizeof (str1));
                        printf( "visualisation server: %s\n", str1 );
                  }

            }

      /* connect to running batmand via unix socket */
      } else {

            if ( ( debug_level == 1 ) || ( debug_level == 2 ) || ( debug_level == 3 ) || ( debug_level == 4 ) ) {

                  if ( ( ( debug_level == 3 ) || ( debug_level == 4 ) ) && ( batch_mode ) )
                        printf( "WARNING: Your chosen debug level (%i) does not support batch mode !\n", debug_level );

                  unix_if.unix_sock = socket(AF_LOCAL, SOCK_STREAM, 0);

                  memset( &unix_if.addr, 0, sizeof(struct sockaddr_un) );
                  unix_if.addr.sun_family = AF_LOCAL;
                  strcpy( unix_if.addr.sun_path, UNIX_PATH );

                  if ( connect ( unix_if.unix_sock, (struct sockaddr *)&unix_if.addr, sizeof(struct sockaddr_un) ) < 0 ) {

                        printf( "Error - can't connect to unix socket '%s': %s ! Is batmand running on this host ?\n", UNIX_PATH, strerror(errno) );
                        close( unix_if.unix_sock );
                        exit(EXIT_FAILURE);

                  }

                  unix_buff = debugMalloc( 1501, 5001 );
                  snprintf( unix_buff, 10, "d:%i", debug_level );

                  if ( write( unix_if.unix_sock, unix_buff, 10 ) < 0 ) {

                        printf( "Error - can't write to unix socket: %s\n", strerror(errno) );
                        close( unix_if.unix_sock );
                        debugFree( unix_buff, 5101 );
                        exit(EXIT_FAILURE);

                  }

                  while ( ( recv_buff_len = read( unix_if.unix_sock, unix_buff, 1500 ) ) > 0 ) {

                        unix_buff[recv_buff_len] = '\0';

                        buff_ptr = unix_buff;
                        bytes_written = 0;

                        while ( ( cr_ptr = strchr( buff_ptr, '\n' ) ) != NULL ) {

                              *cr_ptr = '\0';

                              if ( strncmp( buff_ptr, "EOD", 3 ) == 0 ) {

                                    if ( batch_mode ) {

                                          close( unix_if.unix_sock );
                                          debugFree( unix_buff, 5102 );
                                          exit(EXIT_SUCCESS);

                                    }

                              } else if ( strncmp( buff_ptr, "BOD", 3 ) == 0 ) {

                                    if ( !batch_mode )
                                          system( "clear" );

                              } else {

                                    printf( "%s \n", buff_ptr );

                              }

                              bytes_written += strlen( buff_ptr ) + 1;
                              buff_ptr = cr_ptr + 1;

                        }

                        if ( bytes_written != recv_buff_len )
                              printf( "%s", buff_ptr );

                  }

                  close( unix_if.unix_sock );
                  debugFree( unix_buff, 5103 );

                  if ( recv_buff_len < 0 ) {

                        printf( "Error - can't read from unix socket: %s\n", strerror(errno) );
                        exit(EXIT_FAILURE);

                  } else {

                        printf( "Connection terminated by remote host\n" );

                  }

            }

            exit(EXIT_SUCCESS);

      }

}



void init_interface ( struct batman_if *batman_if ) {

      struct ifreq int_req;
      int16_t on = 1;


      if ( strlen( batman_if->dev ) > IFNAMSIZ - 1 ) {
            debug_output( 0, "Error - interface name too long: %s \n", batman_if->dev );
            restore_defaults();
            exit(EXIT_FAILURE);
      }

      batman_if->udp_send_sock = socket( PF_INET, SOCK_DGRAM, 0 );
      if (batman_if->udp_send_sock < 0) {
            debug_output( 0, "Error - can't create send socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);
      }

      batman_if->udp_recv_sock = socket( PF_INET, SOCK_DGRAM, 0 );
      if ( batman_if->udp_recv_sock < 0 ) {

            debug_output( 0, "Error - can't create receive socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);

      }

      memset( &int_req, 0, sizeof (struct ifreq) );
      strncpy( int_req.ifr_name, batman_if->dev, IFNAMSIZ - 1 );

      if ( ioctl( batman_if->udp_recv_sock, SIOCGIFADDR, &int_req ) < 0 ) {

            debug_output( 0, "Error - can't get IP address of interface %s \n", batman_if->dev );
            restore_defaults();
            exit(EXIT_FAILURE);

      }

      batman_if->addr.sin_family = AF_INET;
      batman_if->addr.sin_port = htons(PORT);
      batman_if->addr.sin_addr.s_addr = ((struct sockaddr_in *)&int_req.ifr_addr)->sin_addr.s_addr;

      if ( ioctl( batman_if->udp_recv_sock, SIOCGIFBRDADDR, &int_req ) < 0 ) {

            debug_output( 0, "Error - can't get broadcast IP address of interface %s \n", batman_if->dev );
            restore_defaults();
            exit(EXIT_FAILURE);

      }

      batman_if->broad.sin_family = AF_INET;
      batman_if->broad.sin_port = htons(PORT);
      batman_if->broad.sin_addr.s_addr = ((struct sockaddr_in *)&int_req.ifr_broadaddr)->sin_addr.s_addr;

      if ( batman_if->broad.sin_addr.s_addr == 0 ) {

            debug_output( 0, "Error - invalid broadcast address detected (0.0.0.0): %s \n", batman_if->dev );
            restore_defaults();
            exit(EXIT_FAILURE);

      }

      if ( setsockopt( batman_if->udp_send_sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (int) ) < 0 ) {

            debug_output( 0, "Error - can't enable broadcasts: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);

      }

      if ( bind_to_iface( batman_if->udp_send_sock, batman_if->dev ) < 0 ) {

            restore_defaults();
            exit(EXIT_FAILURE);

      }

      if ( bind( batman_if->udp_send_sock, (struct sockaddr *)&batman_if->addr, sizeof (struct sockaddr_in) ) < 0 ) {

            debug_output( 0, "Error - can't bind send socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);

      }

      if ( bind_to_iface( batman_if->udp_recv_sock, batman_if->dev ) < 0 ) {

            restore_defaults();
            exit(EXIT_FAILURE);

      }

      if ( bind( batman_if->udp_recv_sock, (struct sockaddr *)&batman_if->broad, sizeof (struct sockaddr_in) ) < 0 ) {

            debug_output( 0, "Error - can't bind receive socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);

      }

}




void init_interface_gw ( struct batman_if *batman_if )
{
      short on = 1;

      batman_if->addr.sin_port = htons(PORT + 1);
      batman_if->tcp_gw_sock = socket(PF_INET, SOCK_STREAM, 0);

      if ( batman_if->tcp_gw_sock < 0 ) {
            debug_output( 0, "Error - can't create socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);
      }

      if ( setsockopt( batman_if->tcp_gw_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int) ) < 0 ) {
            debug_output( 0, "Error - can't enable reuse of address: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);
      }

      if ( bind( batman_if->tcp_gw_sock, (struct sockaddr*)&batman_if->addr, sizeof(struct sockaddr_in) ) < 0 ) {
            debug_output( 0, "Error - can't bind socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);
      }

      if ( listen( batman_if->tcp_gw_sock, 10 ) < 0 ) {
            debug_output( 0, "Error - can't listen socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);
      }

      batman_if->tunnel_sock = socket(PF_INET, SOCK_DGRAM, 0);
      if ( batman_if->tunnel_sock < 0 ) {
            debug_output( 0, "Error - can't create tunnel socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);
      }

      if ( bind( batman_if->tunnel_sock, (struct sockaddr *)&batman_if->addr, sizeof (struct sockaddr_in) ) < 0 ) {
            debug_output( 0, "Error - can't bind tunnel socket: %s \n", strerror(errno) );
            restore_defaults();
            exit(EXIT_FAILURE);
      }

      batman_if->addr.sin_port = htons(PORT);

      pthread_create( &batman_if->listen_thread_id, NULL, &gw_listen, batman_if );

}



void *client_to_gw_tun( void *arg ) {

      struct curr_gw_data *curr_gw_data = (struct curr_gw_data *)arg;
      struct sockaddr_in gw_addr, my_addr, sender_addr;
      struct timeval tv;
      int32_t res, max_sock, status, buff_len, curr_gateway_tcp_sock, curr_gateway_tun_sock, curr_gateway_tun_fd, server_keep_alive_timeout;
      uint32_t addr_len;
      char curr_gateway_tun_if[IFNAMSIZ], keep_alive_string[] = "ping\0";
      unsigned char buff[1500];
      fd_set wait_sockets, tmp_wait_sockets;


      addr_len = sizeof (struct sockaddr_in);

      memset( &gw_addr, 0, sizeof(struct sockaddr_in) );
      memset( &my_addr, 0, sizeof(struct sockaddr_in) );

      gw_addr.sin_family = AF_INET;
      gw_addr.sin_port = htons(PORT + 1);
      gw_addr.sin_addr.s_addr = curr_gw_data->orig;

      my_addr.sin_family = AF_INET;
      my_addr.sin_port = htons(PORT + 1);
      my_addr.sin_addr.s_addr = curr_gw_data->batman_if->addr.sin_addr.s_addr;


      /* connect to server (ask permission) */
      if ( ( curr_gateway_tcp_sock = socket(PF_INET, SOCK_STREAM, 0) ) < 0 ) {

            debug_output( 0, "Error - can't create tcp socket: %s \n", strerror(errno) );
            curr_gateway = NULL;
            debugFree( arg, 1206 );
            return NULL;

      }

      if ( pthread_mutex_lock( &curr_gw_mutex ) == 0 ) {

            if ( connect ( curr_gateway_tcp_sock, (struct sockaddr *)&gw_addr, sizeof(struct sockaddr) ) < 0 ) {

                  debug_output( 0, "Error - can't connect to gateway: %s \n", strerror(errno) );
                  close( curr_gateway_tcp_sock );

                  curr_gw_data->gw_node->last_failure = get_time();
                  curr_gw_data->gw_node->unavail_factor++;

                  curr_gateway = NULL;
                  debugFree( arg, 1207 );

                  if ( pthread_mutex_unlock( &curr_gw_mutex ) != 0 )
                        debug_output( 0, "Error - could not unlock mutex (client_to_gw_tun => 1): %s \n", strerror( errno ) );

                  return NULL;

            }

            if ( pthread_mutex_unlock( &curr_gw_mutex ) != 0 )
                  debug_output( 0, "Error - could not unlock mutex (client_to_gw_tun => 2): %s \n", strerror( errno ) );

      } else {

            debug_output( 0, "Error - could not lock mutex (client_to_gw_tun => 1): %s \n", strerror( errno ) );
            close( curr_gateway_tcp_sock );

            curr_gateway = NULL;
            debugFree( arg, 1208 );
            return NULL;

      }

      server_keep_alive_timeout = get_time();


      /* connect to server (establish udp tunnel) */
      if ( ( curr_gateway_tun_sock = socket(PF_INET, SOCK_DGRAM, 0) ) < 0 ) {

            debug_output( 0, "Error - can't create udp socket: %s \n", strerror(errno) );
            close( curr_gateway_tcp_sock );
            curr_gateway = NULL;
            debugFree( arg, 1209 );
            return NULL;

      }

      if ( bind( curr_gateway_tun_sock, (struct sockaddr *)&my_addr, sizeof (struct sockaddr_in) ) < 0) {

            debug_output( 0, "Error - can't bind tunnel socket: %s \n", strerror(errno) );
            close( curr_gateway_tcp_sock );
            close( curr_gateway_tun_sock );
            curr_gateway = NULL;
            debugFree( arg, 1210 );
            return NULL;

      }


      if ( add_dev_tun( curr_gw_data->batman_if, curr_gw_data->batman_if->addr.sin_addr.s_addr, curr_gateway_tun_if, sizeof(curr_gateway_tun_if), &curr_gateway_tun_fd ) > 0 ) {

            add_del_route( 0, 0, 0, 0, curr_gateway_tun_if, curr_gw_data->batman_if->udp_send_sock );

      } else {

            close( curr_gateway_tcp_sock );
            close( curr_gateway_tun_sock );
            curr_gateway = NULL;
            debugFree( arg, 1211 );
            return NULL;

      }


      FD_ZERO(&wait_sockets);
      FD_SET(curr_gateway_tcp_sock, &wait_sockets);
      FD_SET(curr_gateway_tun_sock, &wait_sockets);
      FD_SET(curr_gateway_tun_fd, &wait_sockets);

      max_sock = curr_gateway_tcp_sock;
      if ( curr_gateway_tun_sock > max_sock )
            max_sock = curr_gateway_tun_sock;
      if ( curr_gateway_tun_fd > max_sock )
            max_sock = curr_gateway_tun_fd;

      while ( ( !is_aborted() ) && ( curr_gateway != NULL ) && ( ! curr_gw_data->gw_node->deleted ) ) {


            if ( server_keep_alive_timeout + 30000 < get_time() ) {

                  server_keep_alive_timeout = get_time();

                  if ( pthread_mutex_lock( &curr_gw_mutex ) == 0 ) {

                        if ( write( curr_gateway_tcp_sock, keep_alive_string, sizeof( keep_alive_string ) ) < 0 ) {

                              debug_output( 3, "server_keepalive failed: %s \n", strerror(errno) );

                              curr_gw_data->gw_node->last_failure = get_time();
                              curr_gw_data->gw_node->unavail_factor++;

                              if ( pthread_mutex_unlock( &curr_gw_mutex ) != 0 )
                                    debug_output( 0, "Error - could not unlock mutex (client_to_gw_tun => 3): %s \n", strerror( errno ) );

                              break;

                        }

                        if ( pthread_mutex_unlock( &curr_gw_mutex ) != 0 )
                              debug_output( 0, "Error - could not unlock mutex (client_to_gw_tun => 4): %s \n", strerror( errno ) );

                  } else {

                        debug_output( 0, "Error - could not lock mutex (client_to_gw_tun => 2): %s \n", strerror( errno ) );

                        break;

                  }

            }


            tv.tv_sec = 0;
            tv.tv_usec = 250;

            tmp_wait_sockets = wait_sockets;

            res = select(max_sock + 1, &tmp_wait_sockets, NULL, NULL, &tv);

            if ( res > 0 ) {

                  /* tcp message from server */
                  if ( FD_ISSET( curr_gateway_tcp_sock, &tmp_wait_sockets ) ) {

                        status = read( curr_gateway_tcp_sock, buff, sizeof( buff ) );

                        if ( status > 0 ) {

                              debug_output( 3, "server message ? \n" );

                        } else if ( status < 0 ) {

                              debug_output( 3, "Cannot read message from gateway: %s \n", strerror(errno) );

                              break;

                        } else if (status == 0) {

                              debug_output( 3, "Gateway closed connection - timeout ? \n" );

                              curr_gw_data->gw_node->last_failure = get_time();
                              curr_gw_data->gw_node->unavail_factor++;

                              break;

                        }

                  /* udp message (tunnel data) */
                  } else if ( FD_ISSET( curr_gateway_tun_sock, &tmp_wait_sockets ) ) {

                        if ( ( buff_len = recvfrom( curr_gateway_tun_sock, buff, sizeof( buff ), 0, (struct sockaddr *)&sender_addr, &addr_len ) ) < 0 ) {

                              debug_output( 0, "Error - can't receive packet: %s \n", strerror(errno) );

                        } else {

                              if ( write( curr_gateway_tun_fd, buff, buff_len ) < 0 ) {

                                    debug_output( 0, "Error - can't write packet: %s \n", strerror(errno) );

                              }

                        }

                  } else if ( FD_ISSET( curr_gateway_tun_fd, &tmp_wait_sockets ) ) {

                        if ( ( buff_len = read( curr_gateway_tun_fd, buff, sizeof( buff ) ) ) < 0 ) {

                              debug_output( 0, "Error - couldn't read data: %s \n", strerror(errno) );

                        } else {

                              if ( sendto(curr_gateway_tun_sock, buff, buff_len, 0, (struct sockaddr *)&gw_addr, sizeof (struct sockaddr_in) ) < 0 ) {
                                    debug_output( 0, "Error - can't send to gateway: %s \n", strerror(errno) );
                              }

                        }

                  }

            } else if ( ( res < 0 ) && (errno != EINTR) ) {

                  debug_output( 0, "Error - can't select: %s \n", strerror(errno) );
                  break;

            }

      }

      /* cleanup */
      add_del_route( 0, 0, 0, 1, curr_gateway_tun_if, curr_gw_data->batman_if->udp_send_sock );

      close( curr_gateway_tcp_sock );
      close( curr_gateway_tun_sock );

      del_dev_tun( curr_gateway_tun_fd );

      curr_gateway = NULL;
      debugFree( arg, 1212 );

      return NULL;

}


void del_default_route() {

      curr_gateway = NULL;

      if ( curr_gateway_thread_id != 0 )
            pthread_join( curr_gateway_thread_id, NULL );

}



int8_t add_default_route() {

      struct curr_gw_data *curr_gw_data;


      curr_gw_data = debugMalloc( sizeof(struct curr_gw_data), 207 );
      curr_gw_data->orig = curr_gateway->orig_node->orig;
      curr_gw_data->gw_node = curr_gateway;
      curr_gw_data->batman_if = curr_gateway->orig_node->batman_if;


      if ( pthread_create( &curr_gateway_thread_id, NULL, &client_to_gw_tun, curr_gw_data ) != 0 ) {

            debug_output( 0, "Error - couldn't spawn thread: %s \n", strerror(errno) );
            debugFree( curr_gw_data, 1213 );
            curr_gateway = NULL;

      }

      return 1;

}



void restore_defaults() {

      struct list_head *if_pos, *if_pos_tmp;
      struct batman_if *batman_if;


      stop = 1;

      list_for_each_safe( if_pos, if_pos_tmp, &if_list ) {

            batman_if = list_entry( if_pos, struct batman_if, list );

            if ( batman_if->listen_thread_id != 0 ) {

                  pthread_join( batman_if->listen_thread_id, NULL );
                  close( batman_if->tcp_gw_sock );

            }

            close( batman_if->udp_recv_sock );
            close( batman_if->udp_send_sock );

            list_del( if_pos );
            debugFree( if_pos, 1214 );

      }

      if ( ( routing_class != 0 ) && ( curr_gateway != NULL ) )
            del_default_route();

      if ( vis_if.sock )
            close( vis_if.sock );

      if ( unix_if.unix_sock )
            close( unix_if.unix_sock );

      if ( unix_if.listen_thread_id != 0 )
            pthread_join( unix_if.listen_thread_id, NULL );

      if ( debug_level == 0 )
            closelog();

}



int8_t receive_packet( unsigned char *packet_buff, int32_t packet_buff_len, int16_t *hna_buff_len, uint32_t *neigh, uint32_t timeout, struct batman_if **if_incoming ) {

      struct sockaddr_in addr;
      struct timeval tv;
      struct list_head *if_pos;
      struct batman_if *batman_if;
      uint32_t addr_len;
      int8_t res;
      fd_set tmp_wait_set;


      addr_len = sizeof(struct sockaddr_in);
      memcpy( &tmp_wait_set, &receive_wait_set, sizeof(fd_set) );

      while (1) {

            tv.tv_sec = timeout / 1000;
            tv.tv_usec = ( timeout % 1000 ) * 1000;

            res = select( receive_max_sock + 1, &tmp_wait_set, NULL, NULL, &tv );

            if ( res >= 0 )
                  break;

            if ( errno != EINTR ) {

                  debug_output( 0, "Error - can't select: %s \n", strerror(errno) );
                  return -1;

            }

      }

      if ( res == 0 )
            return 0;

      list_for_each( if_pos, &if_list ) {

            batman_if = list_entry( if_pos, struct batman_if, list );

            if ( FD_ISSET( batman_if->udp_recv_sock, &tmp_wait_set ) ) {

                  if ( ( *hna_buff_len = recvfrom( batman_if->udp_recv_sock, packet_buff, packet_buff_len - 1, 0, (struct sockaddr *)&addr, &addr_len ) ) < 0 ) {

                        debug_output( 0, "Error - can't receive packet: %s \n", strerror(errno) );
                        return -1;

                  }

                  if ( *hna_buff_len < sizeof(struct packet) )
                        return 0;

                  ((struct packet *)packet_buff)->seqno = ntohs( ((struct packet *)packet_buff)->seqno ); /* network to host order for our 16bit seqno.*/

                  (*if_incoming) = batman_if;
                  break;

            }

      }

      *neigh = addr.sin_addr.s_addr;

      return 1;

}



int8_t send_packet( unsigned char *packet_buff, int32_t packet_buff_len, struct sockaddr_in *broad, int32_t send_sock ) {

      if ( sendto( send_sock, packet_buff, packet_buff_len, 0, (struct sockaddr *)broad, sizeof(struct sockaddr_in) ) < 0 ) {

            if ( errno == 1 ) {

                  debug_output( 0, "Error - can't send packet: %s.\nDoes your firewall allow outgoing packets on port %i ?\n", strerror(errno), ntohs( broad->sin_port ) );

            } else {

                  debug_output( 0, "Error - can't send packet: %s. \n", strerror(errno) );

            }

            return -1;

      }

      return 0;

}



void *gw_listen( void *arg ) {

      struct batman_if *batman_if = (struct batman_if *)arg;
      struct gw_client *gw_client;
      struct list_head *client_pos, *client_pos_tmp;
      struct timeval tv;
      struct sockaddr_in addr;
      struct in_addr tmp_ip_holder;
      socklen_t sin_size = sizeof(struct sockaddr_in);
      char gw_addr[16], str2[16], tun_dev[IFNAMSIZ], tun_ip[] = "104.255.255.254\0";
      int32_t res, status, max_sock_min, max_sock, buff_len, tun_fd;
      uint32_t addr_len, client_timeout;
      unsigned char buff[1500];
      fd_set wait_sockets, tmp_wait_sockets;


      addr_to_string(batman_if->addr.sin_addr.s_addr, gw_addr, sizeof (gw_addr));
      addr_len = sizeof (struct sockaddr_in);
      client_timeout = get_time();

      if ( inet_pton(AF_INET, tun_ip, &tmp_ip_holder) < 1 ) {

            debug_output( 0, "Error - invalid tunnel IP specified: %s \n", tun_ip );
            exit(EXIT_FAILURE);

      }

      if ( add_dev_tun( batman_if, tmp_ip_holder.s_addr, tun_dev, sizeof(tun_dev), &tun_fd ) < 0 ) {
            return NULL;
      }


      FD_ZERO(&wait_sockets);
      FD_SET(batman_if->tcp_gw_sock, &wait_sockets);
      FD_SET(batman_if->tunnel_sock, &wait_sockets);
      FD_SET(tun_fd, &wait_sockets);

      max_sock_min = batman_if->tcp_gw_sock;
      if ( batman_if->tunnel_sock > max_sock_min )
            max_sock_min = batman_if->tunnel_sock;
      if ( tun_fd > max_sock_min )
            max_sock_min = tun_fd;

      max_sock = max_sock_min;

      while (!is_aborted()) {

            tv.tv_sec = 1;
            tv.tv_usec = 0;
            tmp_wait_sockets = wait_sockets;

            res = select(max_sock + 1, &tmp_wait_sockets, NULL, NULL, &tv);

            if (res > 0) {

                  /* new client */
                  if ( FD_ISSET( batman_if->tcp_gw_sock, &tmp_wait_sockets ) ) {

                        gw_client = debugMalloc( sizeof(struct gw_client), 208 );
                        memset( gw_client, 0, sizeof(struct gw_client) );

                        if ( ( gw_client->sock = accept(batman_if->tcp_gw_sock, (struct sockaddr *)&gw_client->addr, &sin_size) ) == -1 ) {
                              debug_output( 0, "Error - can't accept client packet: %s \n", strerror(errno) );
                              continue;
                        }

                        INIT_LIST_HEAD(&gw_client->list);
                        gw_client->batman_if = batman_if;
                        gw_client->last_keep_alive = get_time();

                        FD_SET(gw_client->sock, &wait_sockets);
                        if ( gw_client->sock > max_sock )
                              max_sock = gw_client->sock;

                        list_add_tail(&gw_client->list, &batman_if->client_list);

                        addr_to_string(gw_client->addr.sin_addr.s_addr, str2, sizeof (str2));
                        debug_output( 3, "gateway: %s (%s) got connection from %s (internet via %s) \n", gw_addr, batman_if->dev, str2, tun_dev );

                  /* tunnel activity */
                  } else if ( FD_ISSET( batman_if->tunnel_sock, &tmp_wait_sockets ) ) {

                        if ( ( buff_len = recvfrom( batman_if->tunnel_sock, buff, sizeof( buff ), 0, (struct sockaddr *)&addr, &addr_len ) ) < 0 ) {

                              debug_output( 0, "Error - can't receive packet: %s \n", strerror(errno) );

                        } else {

                              if ( write( tun_fd, buff, buff_len ) < 0 ) {

                                    debug_output( 0, "Error - can't write packet: %s \n", strerror(errno) );

                              }

                        }

                  /* /dev/tunX activity */
                  } else if ( FD_ISSET( tun_fd, &tmp_wait_sockets ) ) {

                        /* not needed - kernel knows client adress and routes traffic directly */

                        debug_output( 0, "Warning - data coming through tun device: %s \n", tun_dev );

                        /*if ( ( buff_len = read( tun_fd, buff, sizeof( buff ) ) ) < 0 ) {

                              fprintf(stderr, "Could not read data from %s: %s\n", tun_dev, strerror(errno));

                        } else {

                              if ( sendto(curr_gateway_tun_sock, buff, buff_len, 0, (struct sockaddr *)&gw_addr, sizeof (struct sockaddr_in) ) < 0 ) {
                                    fprintf(stderr, "Cannot send to client: %s\n", strerror(errno));
                              }

                        }*/

                  /* client sent keep alive */
                  } else {

                        max_sock = max_sock_min;

                        list_for_each_safe(client_pos, client_pos_tmp, &batman_if->client_list) {

                              gw_client = list_entry(client_pos, struct gw_client, list);

                              if ( FD_ISSET( gw_client->sock, &tmp_wait_sockets ) ) {

                                    addr_to_string(gw_client->addr.sin_addr.s_addr, str2, sizeof (str2));

                                    status = read( gw_client->sock, buff, sizeof( buff ) );

                                    if ( status > 0 ) {

                                          gw_client->last_keep_alive = get_time();

                                          if ( gw_client->sock > max_sock )
                                                max_sock = gw_client->sock;

                                          debug_output( 3, "gateway: client %s sent keep alive on interface %s \n", str2, batman_if->dev );

                                    } else {

                                          if ( status < 0 ) {

                                                debug_output( 0, "Error - can't read message: %s \n", strerror(errno) );

                                          } else {

                                                debug_output( 3, "Client %s closed connection ... \n", str2 );

                                          }

                                          FD_CLR(gw_client->sock, &wait_sockets);
                                          close( gw_client->sock );

                                          list_del( client_pos );
                                          debugFree( client_pos, 1215 );

                                    }

                              } else {

                                    if ( gw_client->sock > max_sock )
                                          max_sock = gw_client->sock;

                              }

                        }

                  }

            } else if ( ( res < 0 ) && (errno != EINTR) ) {

                  debug_output( 0, "Error - can't select: %s \n", strerror(errno) );
                  break;

            }


            /* close unresponsive client connections */
            if ( ( client_timeout + 59000 ) < get_time() ) {

                  client_timeout = get_time();

                  max_sock = max_sock_min;

                  list_for_each_safe(client_pos, client_pos_tmp, &batman_if->client_list) {

                        gw_client = list_entry(client_pos, struct gw_client, list);

                        if ( ( gw_client->last_keep_alive + 120000 ) < client_timeout ) {

                              FD_CLR(gw_client->sock, &wait_sockets);
                              close( gw_client->sock );

                              addr_to_string(gw_client->addr.sin_addr.s_addr, str2, sizeof (str2));
                              debug_output( 3, "gateway: client %s timeout on interface %s \n", str2, batman_if->dev );

                              list_del( client_pos );
                              debugFree( client_pos, 1216 );

                        } else {

                              if ( gw_client->sock > max_sock )
                                    max_sock = gw_client->sock;

                        }

                  }

            }

      }

      /* delete tun devices on exit */
      del_dev_tun( tun_fd );

      list_for_each_safe(client_pos, client_pos_tmp, &batman_if->client_list) {

            gw_client = list_entry(client_pos, struct gw_client, list);

            list_del( client_pos );
            debugFree( client_pos, 1217 );

      }

      return NULL;

}



void restore_and_exit( uint8_t is_sigsegv ) {

      struct list_head *if_pos;
      struct batman_if *batman_if;
      struct orig_node *orig_node;
      struct hash_it_t *hashit = NULL;


      if ( !unix_client ) {

            /* remove tun interface first */
            stop = 1;

            list_for_each( if_pos, &if_list ) {

                  batman_if = list_entry( if_pos, struct batman_if, list );

                  if ( batman_if->listen_thread_id != 0 ) {

                        pthread_join( batman_if->listen_thread_id, NULL );
                        close( batman_if->tcp_gw_sock );
                        batman_if->listen_thread_id = 0;

                  }

            }

            if ( ( routing_class != 0 ) && ( curr_gateway != NULL ) )
                  del_default_route();

            if ( !is_sigsegv ) {

                  purge_orig( get_time() + ( 5 * PURGE_TIMEOUT ) + orginator_interval );

            } else {

                  while ( NULL != ( hashit = hash_iterate( orig_hash, hashit ) ) ) {

                        orig_node = hashit->bucket->data;

                        update_routes( orig_node, NULL, NULL, 0 );

                  }

            }

            restore_defaults();

      }

      if ( !is_sigsegv )
            exit(EXIT_FAILURE);

}



void segmentation_fault( int32_t sig ) {

      signal( SIGSEGV, SIG_DFL );

      debug_output( 0, "Error - SIGSEGV received, trying to clean up ... \n" );

      restore_and_exit(1);

      raise( SIGSEGV );

}



void cleanup() {

      int8_t i;
      struct debug_level_info *debug_level_info;
      struct list_head *debug_pos, *debug_pos_tmp;


      for ( i = 0; i < 4; i++ ) {

            if ( debug_clients.clients_num[i] > 0 ) {

                  list_for_each_safe( debug_pos, debug_pos_tmp, (struct list_head *)debug_clients.fd_list[i] ) {

                        debug_level_info = list_entry(debug_pos, struct debug_level_info, list);

                        list_del( debug_pos );
                        debugFree( debug_pos, 1218 );

                  }

            }

            debugFree( debug_clients.fd_list[i], 1219 );
            debugFree( debug_clients.mutex[i], 1220 );

      }

}


Generated by  Doxygen 1.6.0   Back to index