connect.c 8.54 KB
Newer Older
1 2 3 4 5
/*****************************************************************************
 * connect.c
 * Functions to communicate with the vlanbridge
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
6
 * $Id: connect.c,v 1.15 2001/10/26 23:16:10 marcari Exp $
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
 *
 * Authors: Brieuc Jeunhomme <bbp@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

#include <arpa/inet.h>                                            /* types.h */
#include <errno.h>                                                  /* EBUSY */
#include <sys/time.h>                                     /* struct time_val */
#include <unistd.h>                                          /* close, sleep */
#include <sys/socket.h>                                      /* bind, socket */
#include <pthread.h>                                   /* pthread_mutex_lock */
#include <stdio.h>                                                /* sprintf */

#include "../types.h"
#include "../logger.h"

#include "../config.h"                                            /* VERSION */
#include "../config/config.h"                     /* vs->cfg->vlanbridge ... */
#include "../vlanserver.h"                                             /* vs */
#include "../common.h"                                       /* for protocol */
#include "connect.h"

/****************************************************************************
 * CNX_cnx_lost
 ****************************************************************************
 * Tries to log on again on the VLANbridge when the connection has been lost
 ****************************************************************************/
static void CNX_cnx_lost()
{
  unsigned int retry_delay;
  unsigned int still_sleep;

  retry_delay=12;

  if(pthread_mutex_trylock(&(vs->cnx_lock))==EBUSY)
    return;

  if (vs->fdescr)
  {
    if (!close(vs->fdescr))
      vs->fdescr=0;
    else
      VS_log(LOGERROR, SERVER, "Unable to close socket for communication "
                               "with the VLANbridge.");
  }
  
  while (vs->runlevel<VS_STOP)
  {
    VS_log(LOGINFO, SERVER, "Reconnection to the VLB trial failed or "
           "connection lost, retrying in %u seconds.", retry_delay);
    /* this sleeps retry_delay seconds */
    for (still_sleep=retry_delay;still_sleep;still_sleep=sleep(still_sleep));

    if (!CNX_vlb_login(VERSION))
    {
      VS_log(LOGINFO, SERVER, "Connection to VLB is up again.");
      pthread_mutex_unlock(&(vs->cnx_lock));
      return;
    }

    if (vs->fdescr)
    {
      if (!close(vs->fdescr))
        vs->fdescr=0;
      else
        VS_log(LOGERROR, SERVER, "Unable to close socket for communication "
                                 "with the VLANbridge.");
    }

    retry_delay*=2;
  }
}

/****************************************************************************
 * CNX_vlb_set_vlan
 ****************************************************************************
 * Tells the VLANbridge that a machine has changed vlan
 * Returns VS_R_SEND in case of problems
 * (in which case CNX_cnx_lost will be called), 0 otherwise
 ****************************************************************************/
unsigned int CNX_vlb_set_vlan(unsigned int session_id,
                              char * MAC, char * IP, VS_VLAN VLANdest,
                              VS_VLAN VLANsrc)
{
  unsigned char message[VLAN_MSG_LEN];
  size_t j;
  int i;

  j=sprintf(message,"%u %u %s %s %u %u\n", VLAN_ROUTE_REQUEST, session_id, \
                       MAC, IP, (unsigned int)VLANdest, (unsigned int)VLANsrc);
  i=send(vs->fdescr, message, j, 0);
  if (i==j)
  {
    VS_log(LOGDEBUG, SERVER, "Request (%u) to change %s %s from VS_VLAN %u to"\
114
                     " %u successfully sent to VLANbridge",session_id, IP, MAC,\
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
                                (unsigned int)VLANsrc, (unsigned int)VLANdest);
    return 0;
  }
  else 
  {
    if (i==-1)
    {
      VS_log(LOGERROR, SERVER, "Unable to send the request (%u) to change %s "\
                 "%s from VS_VLAN %u to %u to the VLANbridge", session_id, IP,\
                           MAC, (unsigned int)VLANsrc, (unsigned int)VLANdest);
    }
    else
    {
      VS_log(LOGERROR, SERVER, "Unable to send the whole request (%u) to "\
                       "change %s %s from VS_VLAN %u to %u to the VLANbridge",\
                   session_id, IP, MAC, (unsigned)VLANsrc, (unsigned)VLANdest);
    }
    CNX_cnx_lost(vs);
    return VS_R_SEND;
  }
}

/****************************************************************************
 * CNX_vlb_login
 ****************************************************************************
 * logs on on the VLANbridge
 * returns 0 if everything's ok
 ****************************************************************************/
unsigned int CNX_vlb_login(char * version)
{
  unsigned char message[VLAN_MSG_LEN];
  unsigned int i;
  unsigned int j;
  int k;
  fd_set set;
  struct timeval tout={VS_VLB_TIMEOUT, 0};

  vs->fdescr=0;

  VS_log(LOGINFO, SERVER, "Trying to login on VLANbridge");
  for (i=0;version[i];i++)
    if (version[i]=='.')
      break;
  if (version[i]=='.')
    j=sprintf(message, "%u %s %s %s\n", VLAN_LOGIN_REQUEST, version,\
              vs->cfg->vlanbridge_login, vs->cfg->vlanbridge_password);
  else
    j=sprintf(message, "%u %s.0 %s %s\n", VLAN_LOGIN_REQUEST, version,\
              vs->cfg->vlanbridge_login, vs->cfg->vlanbridge_password);

  k=socket(AF_INET, SOCK_STREAM, 0);
  if (k==-1)
  {
    VS_log(LOGERROR, SERVER, "Unable to open a stream socket to connect to "\
           "VLB");
    return VS_R_SOCKET;
  }
  vs->fdescr=k;
  VS_log(LOGDEBUG, SERVER, "Stream socket opened. File descriptor is %u", k);

  VS_log(LOGDEBUG, SERVER, "Trying to connect to VLANbridge");
  if(connect(k, (struct sockaddr *)&vs->vlb_params,\
                                                  sizeof(struct sockaddr))==-1)
  {
    VS_log(LOGERROR, SERVER, "Unable to connect to VLANbridge");
    if (close(k))
      VS_log(LOGERROR, SERVER, "Unable to close the socket for the VLB");
    return VS_R_CONNECT;
  }
184
  VS_log(LOGINFO, SERVER, "Successfully connected to VLANbridge");
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
  
  VS_log(LOGDEBUG, SERVER, "Sending string to VLANbridge: %s", message);
  i=send(k, message, j, 0);
  if (((int)i)==-1)
  {
    VS_log(LOGERROR, SERVER, "Unable to send anything to the VLB");
    if (close(k))
      VS_log(LOGERROR, SERVER, "Unable to close the socket for the VLB");
    return VS_R_SEND;
  }
  if (i!=j)
  {
    VS_log(LOGERROR, SERVER, "Unable to send the whole string to the VLB");
    if (close(k))
      VS_log(LOGERROR, SERVER, "Unable to close the socket for the VLB");
    return VS_R_SEND;
  }
  VS_log(LOGDEBUG, SERVER, " %u bytes sent",j);

  VS_log(LOGDEBUG, SERVER, "Waiting for VLANbridge answer");
  FD_ZERO(&set);
  FD_SET(k, &set);
  i=select(1+k, &set, NULL, NULL, &tout);
  if (((int)i)==-1)
  {
    VS_log(LOGERROR, SERVER, "Unable to select() VLANbridge's file "\
                                                                 "descriptor");
    if (close(k))
      VS_log(LOGERROR, SERVER, "Unable to close the socket for the VLB");
    return VS_R_SELECT;
  }
  if (!i)
  {
    VS_log(LOGERROR, SERVER, "tout(%us): VLB answer not arrived",
           VS_VLB_TIMEOUT);
    if (close(k))
      VS_log(LOGERROR, SERVER, "Unable to close the socket for the"\
                                                                " VLANbridge");
    return VS_R_TIMEOUT;
  }

  VS_log(LOGDEBUG, SERVER, "Answer has arrived, reading it");
  i=recv(k, message, VLAN_MSG_LEN*sizeof(char), 0);
  if (((int)i)==-1)
  {
    VS_log(LOGERROR, SERVER, "Unable to read the answer");
    if (close(k))
      VS_log(LOGERROR, SERVER, "Unable to close the socket for the"\
                                                                " VLANbridge");
    return VS_R_RECV;
  }
  message[i]=0;
  VS_log(LOGINFO, SERVER, "Answer from VLANbridge: %s", message);

  return 0;
}