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

drv_tcp.c

   /****************************************************************
    Copyright (C) 1986-2000 by

    F6FBB - Jean-Paul ROUBELAT
    6, rue George Sand
    31120 - Roquettes - France
      jpr@f6fbb.org

    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-1307  USA

    Parts of code have been taken from many other softwares.
    Thanks for the help.
    ****************************************************************/


 /******************************************************
 *                                                     *
 *         FBB Driver for TCP/IP domain sockets       *
 *                                                     *
 *         F6FBB - 1996                                *
 *                                                     *
 ******************************************************/

#include <serv.h>
#include <fbb_drv.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#undef open
#undef read
#undef write
#undef close

#define AX25_CALLSID 10
#define READ_EVENT 1
#define WRITE_EVENT 2
#define EXCEPT_EVENT 4
#define QUEUE_EVENT 8

#define DISCONNECT  0
#define CPROGRESS   1
#define CONNECTED   2
#define WAITINGCALL 3
#define WAITINGPASS 4
#define READONLY    5
#define SENDCALL  6

#define DISC_EVENT  1
#define CONN_EVENT  2
#define RETR_EVENT  4
#define BUSY_EVENT  8
#define TIME_EVENT  16

typedef struct
{
      int ncan;
      int sock;
      int sock_ui;
      int port;
      int state;
      int paclen;
      int maxframe;
      int netrom;
      int event;
      int queue;
      int nego;
      int cesc;
      int lgial;
      int lpos;
      int lqueue;
      int nb_try;
      int nb_ret;
      int bs;
      int binary;
      int lgcall;
      long timeout;
      char ial[3];
      char call[80];
      indicat callsign;
      char *lbuf;
}
tcan_t;

typedef struct
{
      int sock_ui;
      int rem_port;
      int curcan;
      int nbcan;
      char rem_addr[80];
      tcan_t *tcan;
}
tport_t;

static tport_t tport[NBPORT];

/* static int last_can = 1; */

static int stop_cnx (int port);
static int tcp_getline (int port, int can, char *buffer);
static int tcp_snd_dt (int port, int, char *, int);
static int tcp_cmd (int, int, char *);
static int tcp_connect (int, char *, int);
static int tcp_stat (int, int, stat_ch *);
static int tcp_paclen (int port, int);
static int s_free (tcan_t *);
static int s_status (tcan_t *);
static int tcp_check_call (int port, int can, char *callsign, char *address);
static int tcp_check_pass (int port, int can, char *callsign);
static int tcp_trame (int port, int canal, char *data, int len);
static int snd_tcp_ui(int port, char *buffer, int len, Beacon *ptr);
static int rcv_tcp_ui(int port, char *buffer, int *len, ui_header * ui);

static void clear_can (int port, int canal);
static void read_only_alert (int port, int);

/*
 * Generic functions of the driver
 */

/* Check or change status of a port/channel */
int sta_tcp (int port, int canal, int cmd, void *ptr)
{
      char *scan;
      char commande;

      switch (cmd)
      {
      case TNCSTAT:
            return (tcp_stat (port, canal, (stat_ch *) ptr));
      case PACLEN:
            *((int *) ptr) = tcp_paclen (port, canal);
            return (1);
      case BSCMD:
            tport[port].tcan[canal].bs = *((int *) ptr);
            return (1);
      case SNDCMD:
            return (tcp_cmd (port, canal, (char *) ptr));
      case SETBUSY:
            return stop_cnx (port);
      case PORTCMD:
            scan = (char *)ptr;
            commande = toupper(*scan);
            ++scan;

            while (isspace(*scan))
                  ++scan;

            switch (commande)
            {
            case 'A' :
                  n_cpy(39, tport[port].rem_addr, scan);
                  break;
            case 'P' :
                  tport[port].rem_port = atoi(scan);
                  break;
            }
            return(1);
      }
      return (0);
}

/* Sends data */
int snd_tcp (int port, int canal, int cmd, char *buffer, int len, Beacon * ptr)
{
      int ret = 0;

      switch (cmd)
      {
      case COMMAND:
            break;

      case UNPROTO:
            if (p_port[port].typort == TYP_ETH)
            {
                  snd_tcp_ui(port, buffer, len, ptr);
                  return 1;
            }
            break;

      case DATA:
            ret = tcp_snd_dt (port, canal, buffer, len);
            break;
      }
      return (ret);
}

/* receives data */
int rcv_tcp (int *port, int *canal, int *cmd, char *buffer, int *len, ui_header * ui)
{
#define LGBUF 252
      char buf[LGBUF + 2];
      int can;
      int valid;
      int res;
      int i;

      *cmd = INVCMD;

      valid = 0;

      /* Teste les UIs */
      if (rcv_tcp_ui(*port, buffer, len, ui))
      {
            *canal = 0;
            *cmd = UNPROTO;
            return 1;
      }
      
      /* Teste s'il y a une connection */
      tport[*port].tcan[0].sock = p_port[*port].fd;
      res = s_status (&tport[*port].tcan[0]);

      if (res & READ_EVENT)
      {
            /* static char *TelnetInit = "\377\375\001\377\375\042"; */
            /* static char *TelnetInit = "\377\376\001\377\375\042"; */

            static char *TelnetInit =
            "\377\374\001\000Telnet Initialisation string                                   ";

            int new;
            int addr_len;
            struct sockaddr_in sock_addr;
            addr_len = sizeof (sock_addr);

            new = accept (p_port[*port].fd, (struct sockaddr *) &sock_addr, &addr_len);

            /* Affecter le nouveau socket a un canal vide */
            for (i = 1; i <= tport[*port].nbcan; i++)
            {
                  if (tport[*port].tcan[i].state == DISCONNECT)
                  {
                        break;
                  }
            }

            if (i > tport[*port].nbcan)
            {
                  write (new, TelnetInit, strlen (TelnetInit));

                  /* Impossible d'affecter le canal -> deconnexion */
                  sprintf (buf, "\r\nSorry, no more channels available\r\n\r\n");
                  write (new, buf, strlen (buf));
                  close (new);
            }
            else
            {
                  int val = 0;
                  FILE *fptr;

                  tport[*port].tcan[i].state = WAITINGCALL;
                  tport[*port].tcan[i].sock = new;
                  tport[*port].tcan[i].paclen = (val == 0) ? 250 : val;
                  tport[*port].tcan[i].queue = s_free (&tport[*port].tcan[i]);
                  tport[*port].tcan[i].timeout = time (NULL) + 120L;

                  if (p_port[*port].typort == TYP_ETH)
                  {
                        sprintf (buf, "\r\n%s BBS data access\r\n\r\n", my_call);
                        write (new, buf, strlen (buf));
                  }
                  else
                  {
                        write (new, TelnetInit, strlen (TelnetInit));

                        if ((fptr = fopen (c_disque ("LANG\\TELNET.ENT"), "rt")) == NULL)
                        {
                              sprintf (buf, "\r\n%s BBS. TELNET Access\r\n\r\n", my_call);
                              write (new, buf, strlen (buf));
                        }
                        else
                        {
                              int nb;
                              char *ptr;

                              while (fgets (buf, LGBUF, fptr))
                              {
                                    nb = strlen (buf);
                                    if (nb)
                                    {
                                          buf[nb - 1] = '\r';
                                          buf[nb] = '\n';
                                          buf[nb + 1] = '\0';
                                    }
                                    ptr = var_txt (buf);
                                    write (new, ptr, strlen (ptr));
                              }
                              fclose (fptr);
                        }
                  }
                  sprintf (buf, "Callsign : ");
                  write (new, buf, strlen (buf));

                  val = p_port[*port].pk_t;

                  return (FALSE);
            }
      }

      for (i = 1 ; i <= tport[*port].nbcan ; i++)
      {
            /* Passe au canal suivant pour le polling */
            ++tport[*port].curcan;
            if (tport[*port].curcan > tport[*port].nbcan)
                  tport[*port].curcan = 1;

            can = tport[*port].curcan;

            if ((tport[*port].tcan[can].sock == -1) && (tport[*port].tcan[can].state != DISCONNECT))
            {
                  sprintf (buffer, "(%d) DISCONNECTED fm TCP", can);
                  tport[*port].tcan[can].state = DISCONNECT;
                  clear_can (*port, can);
                  *len = strlen (buffer);
                  *cmd = COMMAND;
                  *canal = can;
                  return (TRUE);
            }

            /* Canal de communication */
            res = s_status (&tport[*port].tcan[can]);

            if (res & TIME_EVENT)
            {
                  sprintf (buf, "Timeout, disconnected !\r\n");
                  write (tport[*port].tcan[can].sock, buf, strlen (buf));
                  close (tport[*port].tcan[can].sock);
                  clear_can (*port, can);
                  return (FALSE);
            }

            if (res & WRITE_EVENT)
            {
                  /* Can write to the socket... Unused */
            }

            if (res & EXCEPT_EVENT)
            {
                  if (tport[*port].tcan[can].event == CONN_EVENT)
                  {
                        /* Appel sortant connecte */

                        /* Le host distant a ete connecte.
                           sprintf(buffer, "*** Connected to %s-%d\r", 
                           tcan[can].callsign.call, tcan[can].callsign.num);
                           in_buf(voie, buffer, strlen(buffer)); */

                        /* if (tcan[can].lgcall)
                              write (tcan[can].sock, tcan[can].call, tcan[can].lgcall); */

                        /* Connexion a la BBS... */
                        sprintf (buffer, "(%d) CONNECTED to %s-%d",
                                     can, tport[*port].tcan[can].callsign.call, tport[*port].tcan[can].callsign.num);

                        if (p_port[*port].typort == TYP_ETH)
                              tport[*port].tcan[can].state = SENDCALL;
                        else
                              tport[*port].tcan[can].state = CONNECTED;

                        tport[*port].tcan[can].nb_try = 0;
                        tport[*port].tcan[can].timeout = 0L;
                        *len = strlen (buffer);
                        *cmd = COMMAND;
                        *canal = can;
                        return (TRUE);
                  }
            }

#define LGTCP 1100

            if ((res & QUEUE_EVENT) || (res & READ_EVENT))
            {
                  int nb = 0;
                  int i;

                  if (tport[*port].tcan[can].sock == -1)
                  {
                        printf ("read on invalid socket\n");
                        return (FALSE);
                  }

                  /* Alloue le buffer si necessaire */
                  if (tport[*port].tcan[can].lbuf == NULL)
                  {
                        tport[*port].tcan[can].lbuf = calloc (LGTCP, 1);
                        tport[*port].tcan[can].lpos = 0;
                        tport[*port].tcan[can].lqueue = 0;
                        tport[*port].tcan[can].nb_ret = 0;
                  }

                  if (res & READ_EVENT)
                  {
                        /* Reste de la place ds le buffer ? */
                        nb = ((LGTCP - tport[*port].tcan[can].lqueue) > 256) ? 256 : LGTCP - tport[*port].tcan[can].lqueue;
                        if (nb)
                        {
                              nb = read (tport[*port].tcan[can].sock, buffer, nb);
                              if ((nb == 0) || ((nb == -1) && (errno == ENOTCONN)))
                              {
                                    /* Deconnection */
                                    sprintf (buffer, "(%d) DISCONNECTED fm TCP", can);
                                    close (tport[*port].tcan[can].sock);
                                    clear_can (*port, can);
                                    *len = strlen (buffer);
                                    *cmd = COMMAND;
                                    *canal = can;
                                    return (TRUE);
                              }
                              else if (nb == -1)
                              {
                                    printf ("errno = %d\n", errno);
                                    perror ("read");
                                    return (FALSE);
                              }
                        }
                  }

                  {
                        int process;
                        int pos;
                        int lg;
                        char *ptr;
                        char *address;
                        int addr_len;
                        struct sockaddr_in sock_addr;

                        if (nb)
                        {
                              nb = tcp_trame (*port, can, buffer, nb);

                              if (nb == 0)
                                    return (FALSE);
                        }

                        pos = tport[*port].tcan[can].lpos + tport[*port].tcan[can].lqueue;
                        if (pos > LGTCP)
                              pos -= LGTCP;

                        for (i = 0; i < nb; i++)
                        {
                              if (tport[*port].tcan[can].lqueue > (LGTCP - 10))
                              {
                                    ++tport[*port].tcan[can].nb_ret;
                                    break;
                              }

                              tport[*port].tcan[can].lbuf[pos] = buffer[i];
                              if (++pos == LGTCP)
                                    pos = 0;

                              ++tport[*port].tcan[can].lqueue;

                              if (buffer[i] == '\r')
                              {
                                    ++tport[*port].tcan[can].nb_ret;
                              }
                        }

                        nb = tport[*port].tcan[can].lqueue;

                        tport[*port].tcan[can].timeout = time (NULL) + 120L;
                        process = (tport[*port].tcan[can].nb_ret > 0);

                        switch (tport[*port].tcan[can].state)
                        {
                        case SENDCALL:
                              lg = tcp_getline (*port, can, buffer);
                              if (lg == 0)
                                    return 0;

                              buffer[lg] = '\0';
                              if (strstr(buffer, "allsig"))
                              {
                                    write(tport[*port].tcan[can].sock, tport[*port].tcan[can].call, tport[*port].tcan[can].lgcall);
                                    tport[*port].tcan[can].state = CONNECTED;
                                    tport[*port].tcan[can].lgcall = 0;
                                    return (TRUE);
                              }
                              break;
                        case WAITINGCALL:
                              if (!process)
                                    return (FALSE);

                              if (!tcp_getline (*port, can, buffer))
                                    return 0;

                              sup_ln (strupr (buffer));

                              addr_len = sizeof (sock_addr);
                              if ((getpeername(tport[*port].tcan[can].sock, (struct sockaddr *)&sock_addr, &addr_len) == 0) && (sock_addr.sin_family == AF_INET))
                                    address = inet_ntoa(sock_addr.sin_addr);
                              else
                                    address = NULL;

                              switch (tcp_check_call (*port, can, buffer, address))
                              {
                              case 0:
                                    if (++tport[*port].tcan[can].nb_try > 3)
                                    {
                                          sprintf (buf, "Callsign error, disconnected !\r\n");
                                          write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                          close (tport[*port].tcan[can].sock);
                                          tport[*port].tcan[can].sock = -1;
                                    }
                                    else
                                    {
                                          char buf[80];

                                          buffer[20] = '\0';
                                          sprintf (buf, "Invalid callsign \"%s\" !\r\n", buffer);
                                          write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                          sprintf (buf, "Callsign : ");
                                          write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                    }
                                    break;
                              case 1:
                                    {
                                          info buf_info;
                                          FILE *fptr;
                                          unsigned coord;

                                          if ((coord = chercoord (tport[*port].tcan[can].callsign.call)) == 0xffff)
                                          {
                                                close (tport[*port].tcan[can].sock);
                                                tport[*port].tcan[can].sock = -1;
                                                break;
                                          }

                                          fptr = ouvre_nomenc ();
                                          fseek (fptr, (long) coord * sizeof (info), 0);
                                          fread ((char *) &buf_info, sizeof (info), 1, fptr);
                                          ferme (fptr, 11);

                                          if (!MOD (buf_info.flags))
                                          {
                                                read_only_alert (*port, can);
                                                tport[*port].tcan[can].state = READONLY;
                                          }
                                          else
                                          {
                                                sprintf (buf, "Password : ");
                                                write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                                tport[*port].tcan[can].state = WAITINGPASS;
                                                tport[*port].tcan[can].nb_try = 0;
                                          }
                                    }
                                    break;
                              case 2:
                                    if (++tport[*port].tcan[can].nb_try > 3)
                                    {
                                          sprintf (buf, "Callsign error, disconnected !\r\n");
                                          write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                          close (tport[*port].tcan[can].sock);
                                          tport[*port].tcan[can].sock = -1;
                                    }
                                    else
                                    {
                                          if (p_port[*port].moport & 0x40)
                                          {
                                                read_only_alert (*port, can);
                                                tport[*port].tcan[can].state = READONLY;
                                          }
                                          else
                                          {
                                                char buf[80];

                                                sprintf (buf, "Unregistered callsign \"%s\" !\r\n", buffer);
                                                write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                                sprintf (buf, "Callsign : ");
                                                write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                          }
                                    }
                                    break;
                              case 5:
                                    sprintf (buffer, "(%d) CONNECTED to %s-%d",
                                                 can, tport[*port].tcan[can].callsign.call,
                                                 tport[*port].tcan[can].callsign.num);
                                    tport[*port].tcan[can].state = CONNECTED;
                                    tport[*port].tcan[can].nb_try = 0;
                                    tport[*port].tcan[can].timeout = 0L;
                                    *len = strlen (buffer);
                                    *cmd = COMMAND;
                                    *canal = can;
                                    return (TRUE);
                              }
                              break;

                        case WAITINGPASS:
                              if (!process)
                                    return (FALSE);

                              if (!tcp_getline (*port, can, buffer))
                                    return 0;

                              sup_ln (buffer);
                              if (tcp_check_pass (*port, can, buffer))
                              {
                                    sprintf (buf, "\r\nLogon Ok. Type NP to change password.\r\n\r\n");
                                    write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                    sprintf (buffer, "(%d) CONNECTED to %s-%d",
                                                 can, tport[*port].tcan[can].callsign.call,
                                                 tport[*port].tcan[can].callsign.num);
                                    tport[*port].tcan[can].state = CONNECTED;
                                    tport[*port].tcan[can].nb_try = 0;
                                    tport[*port].tcan[can].timeout = 0L;
                                    *len = strlen (buffer);
                                    *cmd = COMMAND;
                                    *canal = can;
                                    return (TRUE);
                              }
                              else
                              {
                                    if (++tport[*port].tcan[can].nb_try > 3)
                                    {
                                          if (p_port[*port].moport & 0x40)
                                          {
                                                read_only_alert (*port, can);
                                                tport[*port].tcan[can].state = READONLY;
                                          }
                                          else
                                          {
                                                sprintf (buf, "Password error, disconnected !\r\n");
                                                write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                                close (tport[*port].tcan[can].sock);
                                                tport[*port].tcan[can].sock = -1;
                                          }
                                    }
                                    else
                                    {
                                          char buf[80];

                                          sprintf (buf, "Password error !\r\nPassword : ");
                                          write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                    }
                              }
                              return (FALSE);

                        case READONLY:
                              if (!process)
                                    return (FALSE);

                              if (!tcp_getline (*port, can, buffer))
                                    return 0;

                              if (toupper (*buffer) == 'Y')
                              {
                                    /* Read-Only mode accepted */
                                    sprintf (buf, "\r\nLogon Ok. You have a read-only access.\r\n\r\n");
                                    write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                    sprintf (buffer, "(%d) READONLY to %s-%d",
                                                 can, tport[*port].tcan[can].callsign.call,
                                                 tport[*port].tcan[can].callsign.num);
                                    tport[*port].tcan[can].state = CONNECTED;
                                    tport[*port].tcan[can].nb_try = 0;
                                    tport[*port].tcan[can].timeout = 0L;
                                    *len = strlen (buffer);
                                    *cmd = COMMAND;
                                    *canal = can;
                                    return (TRUE);
                              }
                              else
                              {
                                    sprintf (buf, "Callsign : ");
                                    write (tport[*port].tcan[can].sock, buf, strlen (buf));
                                    tport[*port].tcan[can].state = WAITINGCALL;
                              }
                              break;

                        default:
                              pos = tport[*port].tcan[can].lpos;
                              ptr = tport[*port].tcan[can].lbuf;
                              for (i = 0; i < tport[*port].tcan[can].lqueue; i++)
                              {
                                    buffer[i] = ptr[pos];
                                    if (++pos == LGTCP)
                                          pos = 0;
                              }
                              *len = tport[*port].tcan[can].lqueue;
                              *cmd = DATA;
                              *canal = can;
                              tport[*port].tcan[can].nb_ret = 0;
                              tport[*port].tcan[can].lpos = 0;
                              tport[*port].tcan[can].lqueue = 0;
                              tport[*port].tcan[can].timeout = 0L;
                              return (TRUE);
                        }
                  }
            }
      }
      return (FALSE);
}

/* Open port */
int opn_tcp (int port, int nb)
{
      int i;
      int val;
      int len;
      int ok = TRUE;
      int tcp_port;
      char s[80];
      struct sockaddr_in sock_addr;
      char *ptr;

      tport[port].sock_ui = -1;
      
      sock_addr.sin_family = AF_INET;
      sock_addr.sin_addr.s_addr = 0;

      /* Test if portname is hex number */
      ptr = p_com[(int) p_port[port].ccom].name;

      if (strcmp (ptr, "0") == 0)
      {
            tcp_port = p_com[(int) p_port[port].ccom].port;
      }
      else if (strspn (ptr, "0123456789abcdefABCDEF") != strlen (ptr))
      {
            /* It may be tcp address. Port number is in port */
            if (inet_aton (ptr, &sock_addr.sin_addr))
                  tcp_port = p_com[(int) p_port[port].ccom].port;
            else
                  tcp_port = p_com[(int) p_port[port].ccom].cbase;
      }
      else
      {
            /* for up compatibility */
            tcp_port = p_com[(int) p_port[port].ccom].cbase;
      }

      sock_addr.sin_port = htons (tcp_port);

      sprintf (s, "Init PORT %d COM%d-%d",
                   port, p_port[port].ccom, p_port[port].ccanal);
      InitText (s);

      /*
      old_can = last_can;
      last_can += nb;

      if (last_can > TCP_MAXCAN)
            last_can = TCP_MAXCAN;
      
      for (i = old_can; i < last_can; i++)
      {
            clear_can (i);
      }
      */
      
      tport[port].tcan = (tcan_t *)calloc(nb+1, sizeof(tcan_t));
      if (tport[port].tcan == NULL)
            return 0;
            
      tport[port].curcan = 1;
      tport[port].nbcan = nb;
      for (i = 0 ; i <= nb ; i++)
            clear_can(port, i);

      /* Socket reception d'appels */
      if (p_port[port].fd == 0)
      {

            sprintf (s, "Open PORT %d COM%d-%d",
                         port, p_port[port].ccom, p_port[port].ccanal);
            InitText (s);
            sleep (1);

            if ((p_port[port].fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
            {
                  perror ("socket_r");
                  return (0);
            }

            val = 1;
            len = sizeof (val);
            if (setsockopt (p_port[port].fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, len) == -1)
            {
                  perror ("opn_tcp : setsockopt SO_REUSEADDR");
            }

            if (bind (p_port[port].fd, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) != 0)
            {
                  perror ("opn_tcp : bind");
                  close (p_port[port].fd);
                  p_port[port].fd = -1;
                  return (0);
            }

            if (listen (p_port[port].fd, SOMAXCONN) == -1)
            {
                  perror ("listen");
                  close (p_port[port].fd);
                  p_port[port].fd = -1;
                  return (0);
            }

            memset (&tport[port].tcan[0], 0, sizeof (tcan_t));

      }

      /* Socket reception UIs */
      if (p_port[port].typort == TYP_ETH)
      {
            if ((tport[port].sock_ui = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
            {
                  perror ("socket_ui");
                  return (0);
            }

            if (bind (tport[port].sock_ui, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) != 0)
            {
                  perror ("opn_tcp : bind");
                  close (tport[port].sock_ui);
                  tport[port].sock_ui = -1;
                  return (0);
            }

      }
      
      sprintf (s, "Prog PORT %d COM%d-%d",
                   port, p_port[port].ccom, p_port[port].ccanal);
      InitText (s);

      return (ok);
}

/* Close port */
int cls_tcp (int port)
{
      int i;

      for (i = 1; i <= tport[port].nbcan; i++)
      {
            if (tport[port].tcan[i].sock != -1)
            {
                  close (tport[port].tcan[i].sock);
            }
            tport[port].tcan[i].state = DISCONNECT;
      }

      if ((p_port[port].typort == TYP_SCK) && (p_port[port].fd))
      {
            close (p_port[port].fd);
            p_port[port].fd = 0;
      }

      if (tport[port].sock_ui != -1)
      {
            close (tport[port].sock_ui);
            tport[port].sock_ui = -1;
      }
      
      free(tport[port].tcan);
      
      return (1);
}


/* 

 * Static functions
 *
 */

#define LF  0x0a
#define CR  0x0d
#define SE      0xf0
#define NOP     0xf1
#define DM      0xf2
#define BRK     0xf3
#define IP      0xf4
#define AO      0xf5
#define AYT     0xf6
#define EC      0xf7
#define EL      0xf8
#define GA      0xf9
#define SB      0xfa
#define WILL      0xfb
#define WONT      0xfc
#define DO  0xfd
#define DONT      0xfe
#define IAC     0xff

/* Telnet options */
#define TN_TRANSMIT_BINARY    0
#define TN_ECHO               1
#define TN_SUPPRESS_GA        3
#define TN_STATUS       5
#define TN_TIMING_MARK        6

/* Linemode options */
#define TN_LINEMODE           34
#define TN_LINEMODE_MODE      1
#define TN_LINEMODE_MODE_EDIT 1

static int stop_cnx (int port)
{
      close(p_port[port].fd);
      p_port[port].fd = 0;
      return 1;
}

static int tcp_trame (int port, int canal, char *data, int len)
{
      int i;
      int carac;
      int olg = 0;

      char *optr = data;

      int pial = tport[port].tcan[canal].lgial;

      if (tport[port].tcan[canal].binary)
      {
            return (len);
      }

      for (i = 0; i < len; i++)
      {
            carac = data[i] & 0xff;

            switch (pial)
            {
            case 0:
                  if (carac == IAC)
                        tport[port].tcan[canal].ial[pial++] = carac;
                  else
                  {
                        if (tport[port].tcan[canal].nego == 0)
                        {
                              optr[olg++] = carac;
                              if ((carac == CR) && (tport[port].tcan[canal].bs))
                                    pial = 10;
                        }
                        else
                        {
                              printf ("%02x ", carac);
                        }
                  }
                  break;
            case 1:
                  if (carac == IAC)
                  {
                        optr[olg++] = carac;
                        pial = 0;
                  }
                  else if (tport[port].tcan[canal].nego)
                  {
                        printf ("%02x...\n", carac);
                  }
                  else
                  {
                        switch (carac)
                        {

                        case WILL:
                              printf ("WILL ");
                              break;
                        case WONT:
                              printf ("WONT ");
                              break;
                        case DO:
                              printf ("DO ");
                              break;
                        case DONT:
                              printf ("DONT ");
                              break;

                        case SB:
                              printf ("SUBN ");
                              tport[port].tcan[canal].nego = 1;
                              pial = 0;
                              break;
                        case GA:
                              printf ("GA\n");
                              pial = 0;
                              break;
                        case EL:
                              printf ("EL\n");
                              pial = 0;
                              break;
                        case EC:
                              printf ("EC\n");
                              pial = 0;
                              break;
                        case AYT:
                              printf ("AYT\n");
                              pial = 0;
                              break;
                        case AO:
                              printf ("AO\n");
                              pial = 0;
                              break;
                        case IP:
                              printf ("IP\n");
                              pial = 0;
                              break;
                        case BRK:
                              printf ("BRK\n");
                              pial = 0;
                              break;
                        case DM:
                              printf ("DM\n");
                              pial = 0;
                              break;
                        case NOP:
                              printf ("NOP\n");
                              pial = 0;
                              break;
                        case SE:
                              printf ("SE\n");
                              /* l = 0; */
                              tport[port].tcan[canal].nego = 0;
                              pial = 0;
                              break;
                        default:
                              printf ("%02x...\n", carac);
                              break;
                        }
                        if (pial)
                              tport[port].tcan[canal].ial[pial++] = carac;
                  }
                  break;
            case 2:
                  {
                        char buf[80];

                        printf ("%02x...\n", carac);
                        switch (tport[port].tcan[canal].ial[1])
                        {
                        case WILL:
                              if (carac == TN_LINEMODE)
                              {
                                    /* write(tport[port].tcan[canal].sock, buffer, strlen(buffer)); */
                              }
                              printf (" -> DONT %02x\n", carac);
                              sprintf (buf, "%c%c%c", IAC, DONT, carac);
                              write (tport[port].tcan[canal].sock, buf, strlen (buf));
                              break;
                        case DO:
                              if (carac != TN_ECHO)
                              {
                                    printf (" -> WONT %02x\n", carac);
                                    sprintf (buf, "%c%c%c", IAC, WONT, carac);
                                    write (tport[port].tcan[canal].sock, buf, strlen (buf));
                              }
                              break;
                        case WONT:
                        case DONT:
                              break;

                        case SB:
                              break;
                        }
                        pial = 0;
                  }
                  break;
            case 10:
                  {
                        /* Teste le CRLF -> CR */
                        if (carac != LF)
                              optr[olg++] = carac;
                        pial = 0;
                  }
                  break;
            }
      }

      tport[port].tcan[canal].lgial = pial;

      return (olg);
}

static int tcp_check_call (int port, int can, char *callsign, char *address)
{
      int res = 0;
      
      if (*callsign == '.')
      {
            tport[port].tcan[can].binary = 1;
            ++callsign;
      }

      tport[port].tcan[can].callsign.num = extind (callsign, tport[port].tcan[can].callsign.call);
      if (find (tport[port].tcan[can].callsign.call))
      {
            if (chercoord (tport[port].tcan[can].callsign.call) != 0xffff)
                  res = 1;
            else
                  res = 2;
      }

      // Adresse autorisee sans password ?
      if (address)
      {
            FILE *fptr;
            char str[256];
            char ip[80];
            char pass[256];

            fptr = fopen(c_disque("passwd.sys"), "rt");
            if (fptr)
            {
                  while (fgets(str, sizeof(str), fptr))
                  {
                        if ((*str == '\0') || (*str == '#'))
                              continue;
                        *ip = *pass = '\0';
                        sscanf(str, "%s %s", ip, pass);
                        if (strcmp("+", ip) == 0)
                        {
                              res = 5;
                              break;
                        }
                        if (strcmp(address, ip) == 0)
                        {
                              if (strcmp("+", pass) == 0)
                                    res = 5;
                              else
                                    res = 2;
                              break;
                        }
                  }
                  fclose(fptr);
            }
      }

      return (res);
}

static int tcp_check_pass (int port, int can, char *passwd)
{
      unsigned record;

      record = chercoord (tport[port].tcan[can].callsign.call);

      if (record != 0xffff)
      {
            FILE *fptr;
            info frec;

            fptr = ouvre_nomenc ();
            fseek (fptr, ((long) record * sizeof (info)), 0);
            fread (&frec, sizeof (info), 1, fptr);
            ferme (fptr, 92);

            if (strcasecmp (passwd, frec.pass) == 0)
            {
                  return (TRUE);
            }
      }

      return (FALSE);
}

static int tcp_snd_dt (int port, int canal, char *buffer, int len)
{
      int i;
      int nb;
      int lg;
      char *ptr;

      char buf[600];

      if (tport[port].tcan[canal].sock == -1)
            return (FALSE);

      for (ptr = buf, nb = 0, i = 0; i < len; i++)
      {

            *ptr++ = buffer[i];
            ++nb;
            if (!tport[port].tcan[canal].binary)
            {
                  if ((buffer[i] == '\r') && (tport[port].tcan[canal].bs))
                  {
                        *ptr++ = '\n';
                        ++nb;
                  }
                  else if (buffer[i] == IAC)
                  {
                        *ptr++ = IAC;
                        ++nb;
                  }
            }
      }

      lg = write (tport[port].tcan[canal].sock, buf, nb);
      if (lg == -1)
      {
            printf ("Error %d on socket %d\n", errno, tport[port].tcan[canal].sock);
            perror ("write on socket");
      }
      else if (lg < nb)
      {
            printf ("Cannot write %d bytes on socket %d\n", nb - lg, tport[port].tcan[canal].sock);
      }
      return (TRUE);
}

static int tcp_cmd (int port, int canal, char *cmd)
{
      switch (*cmd++)
      {
      case 'I':
            /* source callsign */
            while (isspace (*cmd))
                  ++cmd;
            tport[port].tcan[canal].callsign.num = extind (cmd, tport[port].tcan[canal].callsign.call);
            break;
      case 'D':
            /* Deconnection */
            if (tport[port].tcan[canal].sock != -1)
            {
                  close (tport[port].tcan[canal].sock);
                  tport[port].tcan[canal].sock = -1;
            }
            break;
      case 'C':
            tcp_connect (port, cmd, canal);
            break;
      default:
            return (0);
      }
      return (1);
}

static int tcp_connect (int port, char *commande, int can)
{
      int fd;
      int ioc;
      int tcp_port;
      char tcp_add[80];
      char indic[80];

      struct sockaddr_in sock_addr;
      struct hostent *host;
            
      /* Connection */
      while (isspace (*commande))
            ++commande;

      tport[port].tcan[can].paclen = p_port[port].pk_t;
      tport[port].tcan[can].maxframe = p_port[port].frame;
      tport[port].tcan[can].port = port;

      if (tport[port].tcan[can].state != DISCONNECT)
            return (0);

      tcp_add[0] = '\0';
      tcp_port = 23;

      commande[79] = '\0';
      
      if (p_port[port].typort == TYP_ETH)
      {
            char *ptr;

            strcpy(tcp_add, tport[port].rem_addr);
            tcp_port = tport[port].rem_port;
            
            sprintf(tport[port].tcan[can].call, ".%s-%d^", tport[port].tcan[can].callsign.call, tport[port].tcan[can].callsign.num);

            /* Remote call */
            ptr = strtok(commande, " ,\t");
            if (!ptr)
                  return(0);

            strcat(tport[port].tcan[can].call, strupr(ptr));

            /* Digis */
            ptr = strtok(NULL, " ,\t");
            if (ptr)
                  strcat(tport[port].tcan[can].call, " via");

            while (ptr)
            {
                  if ((stricmp(ptr, "via") != 0) && (stricmp(ptr, "v") != 0))
                  {
                        strcat(tport[port].tcan[can].call, " ");
                        strcat(tport[port].tcan[can].call, strupr(ptr));
                  }
                  ptr = strtok(NULL, " ,\t");
            }

            strcat(tport[port].tcan[can].call, "\r");
            tport[port].tcan[can].lgcall = strlen(tport[port].tcan[can].call);

            tport[port].tcan[can].binary = 1;
            /* Canal->phase = SENDCALL; */
      }
      else
      {
            sscanf (commande, "%s %s %i", indic, tcp_add, &tcp_port);

            tport[port].tcan[can].callsign.num = extind (indic, tport[port].tcan[can].callsign.call);
            tport[port].tcan[can].lgcall = 0;

            if (!find (tport[port].tcan[can].callsign.call))
            {
                  fprintf (stderr, "connect : invalid callsign %s\n", indic);
                  return (0);
            }

            if (tcp_add[0] == '\0')
            {
                  fprintf (stderr, "connect : tcp address missing\n");
                  return (0);
            }
            
      }
      
      if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
      {
            perror ("socket_ax");
            clear_can (port, can);
            return (0);
      }

      sock_addr.sin_family = AF_INET;
      sock_addr.sin_port = htons (tcp_port);

      host = gethostbyname(tcp_add);
      if (host)
            sock_addr.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
      else
            sock_addr.sin_addr.s_addr = inet_addr (tcp_add);

      ioc = 1;
      ioctl (fd, FIONBIO, &ioc);
      if (connect (fd, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) == -1)
      {
            if (errno != EINPROGRESS)
            {
                  printf ("\n");
                  perror ("connect");
                  clear_can (port, can);
                  close (fd);
                  return (0);
            }
      }

      printf ("*** Connect in progress %s canal %d\n", commande, can);

      tport[port].tcan[can].sock = fd;
      tport[port].tcan[can].state = CPROGRESS;
      tport[port].tcan[can].queue = s_free (&tport[port].tcan[can]);

      return (TRUE);
}

static int tcp_stat (int port, int canal, stat_ch * ptr)
{
      int val;

      if ((canal == 0) || (tport[port].tcan[canal].sock == -1))
            return (0);

      ptr->mem = 100;

      val = s_free (&tport[port].tcan[canal]);

      if (tport[port].tcan[canal].state != CONNECTED)
            ptr->ack = 0;
      else
      {
            ptr->ack = (tport[port].tcan[canal].queue - val) / tport[port].tcan[canal].paclen;
            if ((tport[port].tcan[canal].queue - val) && (ptr->ack == 0))
                  ptr->ack = 1;
      }

      return (1);
}

static int s_status (tcan_t * can)
{
      int nb;
      int res = 0;
      fd_set tcp_read;
      fd_set tcp_write;
      fd_set tcp_excep;
      struct timeval to;

      if (can->sock == -1)
            return (0);

      if ((can->timeout) && (can->timeout < time (NULL)))
      {
            res |= TIME_EVENT;
            can->timeout = 0L;
            return (res);
      }

      if (can->lqueue)
      {
            res |= QUEUE_EVENT;
      }

      to.tv_sec = to.tv_usec = 0;
      can->event = 0;

      FD_ZERO (&tcp_read);
      FD_ZERO (&tcp_write);
      FD_ZERO (&tcp_excep);

      FD_SET (can->sock, &tcp_read);
      FD_SET (can->sock, &tcp_write);
      FD_SET (can->sock, &tcp_excep);

      nb = select (can->sock + 1, &tcp_read, &tcp_write, &tcp_excep, &to);
      if (nb == -1)
      {
            perror ("select");
            return (res);
      }
      else if (nb == 0)
      {
            return (res);
      }
      else
      {
            if (FD_ISSET (can->sock, &tcp_read))
            {
                  res |= READ_EVENT;
            }
            if (FD_ISSET (can->sock, &tcp_write))
            {
                  if (can->state == CPROGRESS)
                  {
                        if (p_port[port].typort == TYP_ETH)
                              can->state = SENDCALL;
                        else
                              can->state = CONNECTED;
                        write (can->sock, &res, 0);
                        res |= EXCEPT_EVENT;
                        can->event = CONN_EVENT;
                  }
                  else
                        res |= WRITE_EVENT;
            }
            if (FD_ISSET (can->sock, &tcp_excep))
            {
                  res |= EXCEPT_EVENT;
            }
      }
      return (res);
}

static int tcp_paclen (int port, int canal)
{
      if (tport[port].tcan[canal].sock == -1)
            return (0);

      return (tport[port].tcan[canal].paclen);
}

static int s_free (tcan_t * can)
{
      int queue_free;

      if (ioctl (can->sock, TIOCOUTQ, &queue_free) == -1)
      {
            perror ("ioctl : TIOCOUTQ");
            return (0);
      }
      return (queue_free);
}

static void clear_can (int port, int canal)
{
      if (tport[port].tcan[canal].lbuf)
            free (tport[port].tcan[canal].lbuf);
      memset (&tport[port].tcan[canal], 0, sizeof (tcan_t));
      tport[port].tcan[canal].sock = -1;
      tport[port].tcan[canal].bs = 1;
      tport[port].tcan[canal].binary = 0;
      tport[port].tcan[canal].state = DISCONNECT;
}

#define READ_ONLY "\r\nLogin in read-only mode.\r\nYou may leave a message to SYSOP.\r\n\r\nGo on anyway (Y/N) ? "

static void read_only_alert (int port, int can)
{
      char buf[256];

      sprintf (buf, READ_ONLY);
      write (tport[port].tcan[can].sock, buf, strlen (buf));
}

/* Copie une ligne dans le buffer */
static int tcp_getline (int port, int can, char *buffer)
{
      int i = 0;
      int c;
      int pos;
      char *ptr;

      pos = tport[port].tcan[can].lpos;
      ptr = tport[port].tcan[can].lbuf;

      while (tport[port].tcan[can].lqueue)
      {
            c = ptr[pos];
            if (++pos == LGTCP)
                  pos = 0;

            --tport[port].tcan[can].lqueue;

            if ((c == '\n') && (tport[port].tcan[can].bs))
                  continue;

            buffer[i++] = c;

            if (c == '\r')
            {
                  --tport[port].tcan[can].nb_ret;
                  break;
            }
      }

      buffer[i] = '\0';

      tport[port].tcan[can].lpos = pos;

      return (i);
}

static int snd_tcp_ui(int port, char *buffer, int len, Beacon *ptr)
{
      int i;
      int lg;
      char buf[1024];
      char call[10];
      char desti[120];
      int sock_ui;
      struct sockaddr_in sock_addr;

      sock_addr.sin_family      = AF_INET;
      sock_addr.sin_addr.s_addr = INADDR_ANY;
      sock_addr.sin_port        = 0;

      sock_ui = socket(AF_INET, SOCK_DGRAM, 0);
      if (sock_ui < 0)
      {
            perror ("socket_ui");
            return (0);
      }
      
      if (bind (sock_ui, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) != 0)
      {
            perror ("snd_tcp_ui : bind");
            close (sock_ui);
            return (0);
      }

      sprintf(desti, "%s-%d", ptr->desti.call, ptr->desti.num);
      for (i = 0; i < ptr->nb_digi; i++)
      {
            strcat(desti, " ");
            sprintf(call, "%s-%d", ptr->digi[i].call, ptr->digi[i].num);
            strcat(desti, call);
      }

      sprintf(buf, "%d^%s-%d^%s^UI^F0^%d^", port, mycall, myssid, desti, len);
      lg = strlen(buf);

      memcpy(buf+lg, buffer, len);

      sock_addr.sin_family = AF_INET;
      sock_addr.sin_addr.s_addr = inet_addr(tport[port].rem_addr);
      sock_addr.sin_port = htons(tport[port].rem_port);
      lg = sendto(sock_ui, buf, lg+len, 0, (const struct sockaddr *)&sock_addr, sizeof (sock_addr));
      
      close(sock_ui);

      if (lg < 0)
      {
            perror ("snd_tcp_ui:sendto");
            return (0);
      }

      return(1);
}

static int rcv_tcp_ui(int port, char *buffer, int *len, ui_header * ui)
{
      int nb;
      int lg;
      fd_set tcp_read;
      struct timeval to;
      struct sockaddr_in sock_addr;
      int addr_len = sizeof (sock_addr);
      char buf[1024];
      char *ptr;
      char *p;

      if (tport[port].sock_ui == -1)
            return (0);

      to.tv_sec = to.tv_usec = 0;

      FD_ZERO (&tcp_read);

      FD_SET (tport[port].sock_ui, &tcp_read);

      nb = select (tport[port].sock_ui + 1, &tcp_read, NULL, NULL, &to);
      if (nb == -1)
      {
            perror ("select_ui");
            return (0);
      }
      else if (nb == 0)
      {
            return (0);
      }
      
      nb = recvfrom(tport[port].sock_ui, buf, sizeof(buf), 0, (struct sockaddr *) &sock_addr, &addr_len);
      
      ptr = buf;
      
      /* remote port ignored */
      lg = 0;
      p = ptr;
      while (*ptr != '^')
      {
            ++ptr;
            ++lg;
            --nb;
      }
      ++ptr;
      --nb;
      ui->port = port;

      /* from */
      lg = 0;
      p = ptr;
      while (*ptr != '^')
      {
            ++ptr;
            ++lg;
            --nb;
      }
      n_cpy(lg, ui->from, p);
      ++ptr;
      --nb;

      /* to */
      lg = 0;
      p = ptr;
      while (*ptr != '^')
      {
            if (*ptr == ' ')
            {
                  /* Digis ... */
                  break;
            }
            ++ptr;
            ++lg;
            --nb;
      }
      n_cpy(lg, ui->to, p);

      ui->via[0] = '\0';
      if (*ptr == ' ')
      {
            /* Digis ... */
            ++ptr;
            --nb;

            lg = 0;
            p = ptr;
            while (*ptr != '^')
            {
                  ++ptr;
                  ++lg;
                  --nb;
            }
            n_cpy(lg, ui->via, p);
            strcat(ui->via, " ");
      }

      ++ptr;
      --nb;

      /* ctrl */
      lg = 0;
      p = ptr;
      while (*ptr != '^')
      {
            ++ptr;
            ++lg;
            --nb;
      }
      n_cpy(lg, ui->ctl, p);
      ui->ui = (strncmp("UI", p, 2) == 0);
      ++ptr;
      --nb;

      /* pid */
      lg = 0;
      p = ptr;
      while (*ptr != '^')
      {
            ++ptr;
            ++lg;
            --nb;
      }
      sscanf(p, "%x", &ui->pid);
      ++ptr;
      --nb;

      /* len */
      lg = 0;
      p = ptr;
      while (*ptr != '^')
      {
            ++ptr;
            ++lg;
            --nb;
      }
      
      lg = atoi(p);
      ++ptr;
      --nb;

      sprintf (ui->txt, " (%d)", lg);

      if (lg != nb)
            return 0;

      if (lg > 0)
            memcpy(buffer, ptr, lg);

      *len = lg;
      return lg;
}

Generated by  Doxygen 1.6.0   Back to index