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

protocol.c

/*****************************************************************************
Protocollo di comunicazione per ODBC
*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>

#include <define.h>
#include <dbug/dbug.h>
#include <socket.h>
#include <my_string.h>
#include <my_bstring.h>
#include <my_array.h>
#include <unistd.h>
#include "protocol.h"
#include "socket.h"

/******************************************************************************
int send_tcp_pkt (int sock, char *dati, int length, unsigned char cmd)
Invia un pacchetto sulla connessione sock con il protocollo ODBCD impostando il
flag di identificazione a cmd.
ATTENZIONE: I primi 6 bytes devono essere lasciati vuoti per il protocollo.

Valori ritornati:
                  OK  - Dati trasmessi
                  ERR - Impossibile trasmettere i dati
******************************************************************************/
int 
send_tcp_pkt (int sock, MY_BSTRING *bstr, uchar cmd)
{
  int ret;
  char *data;
  uint length;

  DBUG_ENTER ( "send_tcp_pkt" );

  data=bstring_ptr(bstr);
  length=bstring_length(bstr)-6;

  if ( length > 0 )
    {
      data[0]=CHR_STX;
      data[1]=(unsigned char)((length&0xff00)>>8);
      data[2]=(unsigned char)(length&0xff);
      data[3]=0x00;
      data[4]=0x00;
      data[5]=cmd;
      
      DBUG_PRINT ("net",("header { %X,%X,%X,%X,%X,%X }%X", data[0], data[1], data[2], data[3], data[4], data[5],length ) );
      
      DBUG_PRINT ("net",("data (%*.*s)", length, length, &data[6] ));
      ret=dbtcp_net_write ( sock, data, bstring_length(bstr) );
      if ( ret>0 )
      {
        DBUG_RETURN ( OK );
        return ( OK );
      }
    }

  DBUG_RETURN ( ERR );
  return ( ERR );
}

void dump ( char *data, int len )
{
  int idmy;

  for (idmy=0; idmy<len; idmy++ )
    printf ("%x,",data[idmy] );

  printf ( "\n" );
}

/*****************************************************************************
int receive_tcp_pkt ( int socket, uchar *cmd, MY_BSTRING *bstr )
 Riceve un pacchetto dal socket sock ( massima grandezza del pacchetto 4 K )
 Formato dei pacchetti
 |CHR_STX|dati|CHR_ETX| SYNC |
 Se deve trasmettere dei caratteri CHR_ETX li trasmette due volte
 alla fine viene aggiunto un carattere per non bloccare la comunicazione
*****************************************************************************/
int receive_tcp_pkt ( int socket, uchar *cmd, MY_BSTRING *bstr )
{
  uchar ucdmy;
  uchar buffer[5];
  int mylen;
  char *data;

  DBUG_ENTER ( "receive_tcp_pkt" );

  /* Aspetta il carattere di sincronismo dal remoto, attesa infinita */
  ucdmy=0;
  while ( ucdmy != CHR_STX )
    {
      errno=0;
      if ( ( dbtcp_net_read ( socket, &ucdmy, 1 ) < 0 ) || ( errno != 0 ) )
      {
        DBUG_PRINT( "net", ( "Error on sync %d\n", errno ));
        DBUG_RETURN ( ERR );
        return ( ERR );
      }
    }
  
  DBUG_PRINT ( "net", ( "Socket %d - Received STX", socket ) );

  /* Riceve l'header del messaggio senza STX */
  if ( dbtcp_net_read ( socket, buffer, 5 ) == 5 )
    {
      mylen = (buffer[0]<<8)+buffer[1];
      *cmd=(unsigned char)buffer[4];
      
      DBUG_PRINT ( "net", ( "Socket %d - ID = %d - Length = %d ", socket, *cmd, mylen ) );

      bstring_append ( bstr, NULL, mylen );
      data=bstring_ptr ( bstr );
      if ( mylen > 0 )
      {
        memset ( data, 0, mylen );
        if ( dbtcp_net_read ( socket, data, mylen ) == mylen )
          {
            bstring_length(bstr)=mylen;
            //printf ( "BUFFER '%*.*s'\n", mylen, mylen, *data );
            //dump ( *data, mylen );
            DBUG_RETURN ( OK );
            return ( OK );
          }
      }
      else
      {
        DBUG_RETURN ( OK );
        return ( OK );
      }
    }

  DBUG_RETURN ( ERR );
  return ( ERR );

}

/******************************************************************************
int sendreceive_tcp_pkt ( int sock, char **buffer, int *len, int *maxlen, int *cmd )

Invia un pacchetto e aspetta una risposta dal server, se il pacchetto di risposta e' troppo grande per essere contenuto nel buffer lo rialloca.
Valori ritornati:
                  OK  - Pacchetto inviato e ricevuta la risposta
              ERR - Errore
 *****************************************************************************/
int sendreceive_tcp_pkt ( int sock, uchar *cmd, MY_BSTRING *bstr )
{
  DBUG_ENTER ( "sendreceive_tcp_pkt" );

  if ( send_tcp_pkt ( sock, bstr, *cmd ) == OK )
    {
      if ( receive_tcp_pkt ( sock, cmd, bstr ) == OK )
      {
        DBUG_RETURN ( OK );
        return ( OK );
      }
    }

  DBUG_RETURN ( ERR );
  return ( ERR );
}

/******************************************************************************
dbftp_result *init_dbftp_result ( void )
 *****************************************************************************/
dbftp_result *init_dbftp_result ( void )
{
  dbftp_result *myresults;

  DBUG_ENTER ( "init_dbftp_result" );

  myresults=malloc(sizeof(dbftp_result));
  if ( myresults != NULL )
    {
      myresults->field=malloc(sizeof(struct MY_ARRAY));
      myresults->cols=malloc(sizeof(struct MY_ARRAY));
      myresults->net_buf=malloc(sizeof(MY_BSTRING));
      myresults->dsn=malloc(sizeof(MY_STRING));
      myresults->error=malloc(sizeof(MY_STRING));

      if ( ( myresults->field != NULL ) && ( myresults->cols != NULL ) )
      {
        myresults->sock=-1;
        myresults->num_fields=0;
        bstring_init ( myresults->net_buf, 128, 256, NULL, 0 );
        string_init ( myresults->dsn, 128, 256, NULL );
        string_init ( myresults->error, 128, 256, NULL );

        if ( Init_DArray ( myresults->field, sizeof( my_fields ), 10, 5 ) == OK )
        {
          if ( Init_DArray ( myresults->cols, sizeof( MY_STRING ), 15, 5 ) == OK )
          {
            DBUG_RETURN( myresults );
            return ( myresults );
          }
        }
      }
   
      if ( myresults->field != NULL )
      free ( myresults->field );

      if ( myresults->cols != NULL )
      free ( myresults->cols );

      if ( myresults->net_buf != NULL )
      free ( myresults->net_buf );

      if ( myresults->dsn != NULL )
      free ( myresults->dsn );

      if ( myresults->error != NULL )
      free ( myresults->error );

      free ( myresults );

    }
  
  DBUG_RETURN ( NULL );
  return ( NULL );
}

/******************************************************************************
int free_dbftp_result ( dbftp_result *myresults )
 *****************************************************************************/
int free_dbftp_result ( dbftp_result *myresults )
{
  int idmy;
  MY_STRING stringa;
  my_fields campi;

  DBUG_ENTER ( "free_dbftp_result" );

  if ( myresults->sock > 0 )
    {
      dbftp_close ( myresults );
    }

  /* Questa condizione vale solo per un caso bisogna cambiarla */
  if ( ( myresults->cols != NULL ) && ( myresults->num_fields > 0 ) )
    {
      /* --------------- Bisogna prima deallocare tutte le stringhe dei dati */
      for ( idmy=0; idmy<myresults->num_fields; idmy++ )
      {
        Get_DArray ( myresults->cols, (char *)&stringa, idmy );
        if ( string_ptr(&stringa) != NULL )
          string_free ( &stringa );
      }

      Delete_DArray ( myresults->cols );
      myresults->cols = NULL;

      /* ---------------Bisogna prima deallocare tutte le stringhe dei campi */
      for ( idmy=0; idmy<myresults->num_fields; idmy++ )
        {
          Get_DArray ( myresults->field, (char *)&campi, idmy );
        if ( string_ptr(&(campi.name)) != NULL )
          string_free ( &stringa );
        }
      Delete_DArray ( myresults->field );
      myresults->field = NULL;
    }

  string_free ( myresults->dsn );
  string_free ( myresults->error );
  bstring_free ( myresults->net_buf );

  DBUG_RETURN ( OK );
  return ( OK );
}

/******************************************************************************
void dbftp_set_error ( dbftp_result *myres, char *string, int len )
 *****************************************************************************/
void dbftp_set_error ( dbftp_result *myres, char *string, int len  )
{
  DBUG_ENTER ( "dbftp_set_error" );

  string_clear ( myres->error );
  string_append ( myres->error, string, 0 );

  DBUG_VOID_RETURN;
  return;
}

/******************************************************************************
int packet2data ( dbftp_result *myresults )
Converte una riga di risultati ricevuta da remoto nelle stringhe componenti.
Se i campi del risultato sono < del numero di campi definiti non imposta i campi non inviati ( hanno lo stesso valore del passo precedente ).
Valori ritornati:
                      OK  - Risultati convertiti correttamente
                  ERR - Errore
 *****************************************************************************/
int packet2data ( dbftp_result *myresults )
{
  MY_STRING stringa;
  ulong idx,count,datalen;
  uchar *data;

  DBUG_ENTER ( "packet2data" );
  
  idx=0;
  count=0;
  data=bstring_ptr( myresults->net_buf );

  while ( ( idx < bstring_length( myresults->net_buf ) ) && 
        ( count < myresults->num_fields ) )
    {
      
      datalen=(unsigned char)data[idx]*256+(unsigned char)data[idx+1];
      idx += 2;
      if ( (idx+datalen) > bstring_length(myresults->net_buf) )
      {
        /* Messaggio di errore pacchetto dati errato */
        DBUG_RETURN ( ERR );
        return ( ERR );
      }

      Get_DArray ( myresults->cols, (char *)&stringa, count );
      if ( string_ptr( &stringa ) == NULL )
      {
        /* Devo allocare la stringa nuova */
        string_init ( &stringa, 128, 256, NULL );
      }

      string_clear ( &stringa );
      if ( datalen > 0 )
      string_append ( &stringa, &data[idx], datalen );
      

      DBUG_PRINT ( "packet2data", ("COL %d: '%*.*s' (%d) STRING(%d,%s)", count, datalen, datalen, &data[idx], datalen, string_length(&stringa), string_ptr(&stringa) ) );
      
      Set_DArray ( myresults->cols, (char *)&stringa, count++ );
      idx += datalen;
    }

    /* Questo e' il conteggio dinamico dei campi, qui c'e' il numero di campi che sono stati ricevuti */
    //myresults->num_fields=count; 
  DBUG_RETURN ( OK );
  return ( OK );
}

/******************************************************************************
int packet2field ( dbftp_result *myresults )
Manca un controllo della lunghezza dei dati del campo prima di andare a leggerli, potrebbe provocare un SEGV.
 *****************************************************************************/
int packet2field ( dbftp_result *myresults )
{
  my_fields campo;
  ulong idx,count,datalen;
  uchar *data;

  DBUG_ENTER ( "packet2field" );

  idx=0;
  count=0;
  data=bstring_ptr ( myresults->net_buf );

  while ( idx < bstring_length( myresults->net_buf ) )
    {
      datalen=data[idx]*256+data[idx+1];
      idx += 2;

      Get_DArray ( myresults->field, (char *)&campo, count );
      if ( string_ptr( &(campo.name) ) == NULL )
        {
          /* Devo allocare la stringa nuova */
          string_init ( &(campo.name), 128, 256, NULL );
        }

      DBUG_PRINT ( "packet2field", ("COL %d: '%*.*s' (%d) idx %d", count, datalen, datalen, &data[idx], datalen, idx ) );

      string_clear ( &(campo.name) );
      if ( datalen > 0 )
      string_append ( &(campo.name), &data[idx], datalen );

      idx += datalen;

      campo.type=data[idx++];
      campo.length=data[idx]*256+data[idx+1];
      DBUG_PRINT ("packet2field", ("COL %d: length %d - type %c STRING(%d,%s)", count, campo.length, campo.type,string_length(&(campo.name)), string_ptr(&(campo.name)) ) );

      idx += 2;

      Set_DArray ( myresults->field, (char *)&campo, count++ );

    }

  myresults->num_fields=count;
  DBUG_RETURN ( OK );
  return ( OK );
}

/******************************************************************************
int dbftp_connect ( dbftp_result *myres, char *host, int port, char *dsn )
 *****************************************************************************/
int dbftp_connect ( dbftp_result *myres, char *host, int port, char *dsn )
{
  uchar cmd=CLN_CMD_CONNECT;
  char buf[256];

  DBUG_ENTER ( "dbftp_connect" );

  if ( socket_open_client ( &myres->sock, host, port, buf, 255 ) == OK )
    {
      if ( ( bstring_clear ( myres->net_buf ) != OK ) ||
         ( bstring_append ( myres->net_buf, "123456", 6 ) != OK ) ||
         ( bstring_append ( myres->net_buf, dsn, 0 ) != OK ) )
      {
        dbftp_set_error ( myres, "Memory allocation error", 0 );
      }
      else
      {
        if ( sendreceive_tcp_pkt ( myres->sock, &cmd, myres->net_buf ) != OK )
          {
            dbftp_set_error ( myres, "Network error", 0 );
          }
        else
          {
            if ( cmd == SRV_CMD_SUCCESS )
            {
              DBUG_RETURN ( OK );
              return ( OK );
            }
            else
            {
              dbftp_set_error ( myres, bstring_ptr( myres->net_buf ), bstring_length( myres->net_buf ) );
            }
          }
      }
    }
  else
    {
      dbftp_set_error ( myres, buf, strlen(buf) );
    }
  
  DBUG_RETURN ( ERR );
  return ( ERR );
}

/******************************************************************************
int dbftp_sql ( dbftp_result *myres, char *query )
Invia una query al remoto e aspetta l'accettazione.
Valori ritornati:
                   OK  - Query inviata e accettata
               ERR - Errore
 *****************************************************************************/
int dbftp_sql ( dbftp_result *myres, char *query )
{
  uchar cmd=CLN_CMD_SQL;
  int is_select=0,idx;

  DBUG_ENTER ( "dbftp_sql" );

  /* Controlla se la query e' del tipo: <SPAZI>SELECT<ALTRO> */
  idx=0;
  while ( query[idx] != 0x00 )
    {
      if ( isspace( (int)query[idx] ) )
      idx++;
      else
      {
        if ( strncasecmp ( &query[idx], "SELECT", 6 ) == 0 )
          {
            is_select=1;
          }
        break;
      }
    }

  if ( ( bstring_clear ( myres->net_buf ) != OK ) ||
       ( bstring_append ( myres->net_buf, "123456", 6 ) != OK ) ||
       ( bstring_append ( myres->net_buf, query, strlen( query ) ) != OK ) )
    {
      dbftp_set_error ( myres, "Memory allocation error", 0 );
    }
  else
    {
      //dump ( bstring_ptr( myres->net_buf ), bstring_length( myres->net_buf ) );

      if ( sendreceive_tcp_pkt ( myres->sock, &cmd, myres->net_buf ) != OK )
      {
        dbftp_set_error ( myres, "Network error", 0 );
      }
      else
      {
        if ( ( cmd == SRV_CMD_SUCCESS ) || ( cmd == SRV_CMD_NO_DATA ) )
          {
            if ( is_select == 1 )
            {
              DBUG_RETURN ( dbftp_fetch_fields( myres ) );
              return ( dbftp_fetch_fields( myres ) );
            }
            else
            {
              DBUG_RETURN ( OK );
              return ( OK );
            }
          }
        else
          {
            dbftp_set_error ( myres, bstring_ptr(myres->net_buf), bstring_length(myres->net_buf) );
          }
      }
    }

  DBUG_RETURN ( ERR );
  return ( ERR );
}

/******************************************************************************
int dbftp_fetch_row ( dbftp_result *myres )
Preleva una riga di risultati dalla connessione corrente.
Valori ritornati:
                   OK  - Riga prelevata
               ERR - Errore
 *****************************************************************************/
int dbftp_fetch_row ( dbftp_result *myres )
{
  uchar cmd=CLN_CMD_FETCH;

  DBUG_ENTER ( "dbftp_fetch_row" );

  if ( ( bstring_clear ( myres->net_buf ) != OK ) ||
       ( bstring_append ( myres->net_buf, "123456q", 7 ) != OK ) )
    {
      dbftp_set_error ( myres, "Memory allocation error", 0 );

      DBUG_RETURN ( ERR );
      return ( ERR );
    }

  if ( sendreceive_tcp_pkt ( myres->sock, &cmd, myres->net_buf ) != OK )
    {
      dbftp_set_error ( myres, "Network error", 0 );

      DBUG_RETURN ( ERR );
      return ( ERR );
    }
  else
    {
      if ( cmd == SRV_FETCH_EOF )
      {
        /* Flag di fine risultati */
        DBUG_RETURN ( FETCH_EOF );
        return ( FETCH_EOF );
      }

      if ( cmd == SRV_FETCH_RESULT )
      {
        if ( packet2data ( myres ) == OK )
          {
            DBUG_RETURN ( FETCH_OK );
            return ( FETCH_OK );
          }
      }

      dbftp_set_error ( myres, bstring_ptr(myres->net_buf), bstring_length(myres->net_buf) );

    }

  DBUG_RETURN ( FETCH_ERROR ); 
  return ( FETCH_ERROR );
}

/******************************************************************************
int dbftp_fetch_fields ( dbftp_result *myres )
*****************************************************************************/
int dbftp_fetch_fields ( dbftp_result *myres )
{
  uchar cmd=CLN_CMD_FETCH_F;

  DBUG_ENTER ( "dbftp_fetch_fields" );

  if ( ( bstring_clear ( myres->net_buf ) != OK ) ||
       ( bstring_append ( myres->net_buf, "123456q", 7 ) != OK ) )
    {
      dbftp_set_error ( myres, "Memory allocation error", 0 );

      DBUG_RETURN ( ERR );
      return ( ERR );
    }

  if ( sendreceive_tcp_pkt ( myres->sock, &cmd, myres->net_buf ) != OK )
    {
      dbftp_set_error ( myres, "Network error", 0 );
    }
  else
    {
      if ( cmd == SRV_FETCH_FIELDS )
        {
        if ( packet2field ( myres ) == OK )
          {
            DBUG_RETURN ( OK );
            return ( OK );
          }
        else
          {
            dbftp_set_error ( myres, "Unknown field format", 0 );
          }
        }
      else
        {
        dbftp_set_error ( myres, bstring_ptr(myres->net_buf), bstring_length(myres->net_buf) );
      }
    }
  DBUG_RETURN ( ERR );
  return ( ERR );
}

/******************************************************************************
char *dbftp_field_name ( dbftp_result *myres, int field )
 *****************************************************************************/
char *dbftp_field_name ( dbftp_result *myres, int field )
{
  my_fields campo;
  DBUG_ENTER ("dbftp_field_name");
  
  Get_DArray ( myres->field, (char *)&campo, field );
  if ( string_ptr(&campo.name) != NULL )
    {
      DBUG_RETURN ( string_ptr(&campo.name) );
      return ( string_ptr(&campo.name) );
    }
  DBUG_RETURN ( NULL );
  return ( NULL );
}

/******************************************************************************
int dbftp_field_len ( dbftp_result *myres, int field )
 *****************************************************************************/
int dbftp_field_len ( dbftp_result *myres, int field )
{
  my_fields campo;
  DBUG_ENTER ("dbftp_field_len");

  Get_DArray ( myres->field, (char *)&campo, field );
  if ( string_ptr(&campo.name) != NULL )
    {
      DBUG_RETURN ( campo.length );
      return ( campo.length );
    }
  DBUG_RETURN ( -1 );
  return ( -1 );
}

/******************************************************************************
int dbftp_field_type ( dbftp_result *myres, int field )
 *****************************************************************************/
int dbftp_field_type ( dbftp_result *myres, int field )
{
  my_fields campo;
  DBUG_ENTER ("dbftp_field_type");

  Get_DArray ( myres->field, (char *)&campo, field );
  if ( string_ptr(&campo.name) != NULL )
    {
      DBUG_RETURN ( campo.type );
      return ( campo.type );
    }
  DBUG_RETURN ( -1 );
  return ( -1 );
}

/******************************************************************************
char *dbftp_fetch_value ( dbftp_result *myres, int col )
 *****************************************************************************/
char *dbftp_fetch_value ( dbftp_result *myres, int col )
{
  MY_STRING stringa;

  DBUG_ENTER ("dbftp_fetch_value" );

  Get_DArray ( myres->cols, (char *)&stringa, col );
  if ( string_ptr( &stringa ) != NULL )
    {
      DBUG_RETURN ( string_ptr( &stringa ) );
      return ( string_ptr( &stringa ) );
    }

  DBUG_RETURN ( NULL );
  return ( NULL );
}

/******************************************************************************
int dbftp_close ( dbftp_result *myres )
Chiude la connessione con il remoto.
 *****************************************************************************/
int dbftp_close ( dbftp_result *myres )
{
  DBUG_ENTER ( "dbftp_close" );

  socket_close ( myres->sock );
  myres->sock = -1;

  DBUG_RETURN ( ERR );
  return ( ERR );
}











Generated by  Doxygen 1.6.0   Back to index