Logo Search packages:      
Sourcecode: psqlodbc version File versions

socket.c

/*-------
 * Module:              socket.c
 *
 * Description:         This module contains functions for low level socket
 *                            operations (connecting/reading/writing to the backend)
 *
 * Classes:             SocketClass (Functions prefix: "SOCK_")
 *
 * API functions: none
 *
 * Comments:            See "notice.txt" for copyright and license information.
 *-------
 */

#include "socket.h"

#include "connection.h"

#ifndef WIN32
#include <stdlib.h>
#include <string.h>                       /* for memset */
#endif

extern GLOBAL_VALUES globals;

#ifndef BOOL
#define BOOL      int
#endif
#ifndef TRUE
#define TRUE      (BOOL)1
#endif
#ifndef FALSE
#define FALSE     (BOOL)0
#endif


void
SOCK_clear_error(SocketClass *self)
{
      self->errornumber = 0;
      self->errormsg = NULL;
}


SocketClass *
SOCK_Constructor(const ConnectionClass *conn)
{
      SocketClass *rv;

      rv = (SocketClass *) malloc(sizeof(SocketClass));

      if (rv != NULL)
      {
            rv->socket = (SOCKETFD) - 1;
            rv->buffer_filled_in = 0;
            rv->buffer_filled_out = 0;
            rv->buffer_read_in = 0;

            if (rv)
                  rv->buffer_size = conn->connInfo.drivers.socket_buffersize;
            else
                  rv->buffer_size = globals.socket_buffersize;
            rv->buffer_in = (unsigned char *) malloc(rv->buffer_size);
            if (!rv->buffer_in)
            {
                  free(rv);
                  return NULL;
            }

            rv->buffer_out = (unsigned char *) malloc(rv->buffer_size);
            if (!rv->buffer_out)
            {
                  free(rv->buffer_in);
                  free(rv);
                  return NULL;
            }
            rv->errormsg = NULL;
            rv->errornumber = 0;
            rv->reverse = FALSE;
      }
      return rv;
}


void
SOCK_Destructor(SocketClass *self)
{
      mylog("SOCK_Destructor\n");
      if (!self)
            return;
      if (self->socket != -1)
      {
            SOCK_put_char(self, 'X');
            SOCK_flush_output(self);
            closesocket(self->socket);
      }

      if (self->buffer_in)
            free(self->buffer_in);

      if (self->buffer_out)
            free(self->buffer_out);

      free(self);
}


char
SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
{
#if defined (POSIX_MULTITHREAD_SUPPORT)
    const int bufsz = 8192; 
    char buf[bufsz];
    int error = 0;
    struct hostent host;
    struct hostent* hp = &host;
#else
    struct hostent* hp;
#endif 
      unsigned long iaddr;

      if (self->socket != -1)
      {
            self->errornumber = SOCKET_ALREADY_CONNECTED;
            self->errormsg = "Socket is already connected";
            return 0;
      }

      memset((char *) &(self->sadr), 0, sizeof(self->sadr));

      /*
       * If it is a valid IP address, use it. Otherwise use hostname lookup.
       */
      iaddr = inet_addr(hostname);
      if (iaddr == INADDR_NONE)
      {
#if defined (POSIX_MULTITHREAD_SUPPORT) 
  #if defined (HAVE_GETIPNODEBYNAME) /* Free-BSD ? */
      hp = getipnodebyname(hostname, AF_INET, 0, &error); 
  #elif defined (PGS_REENTRANT_API_1) /* solaris, irix */
        hp = gethostbyname_r(hostname, hp, buf, bufsz, &error);
  #elif defined (PGS_REENTRANT_API_2) /* linux */
        int result = 0;
        result = gethostbyname_r(hostname, hp, buf, bufsz, &hp, &error);
        if (result)
          hp = 0;
  #else
        hp = gethostbyname(hostname);
  #endif
#else
        hp = gethostbyname(hostname);
#endif
            if (hp == NULL)
            {
                  self->errornumber = SOCKET_HOST_NOT_FOUND;
                  self->errormsg = "Could not resolve hostname.";
                  return 0;
            }
            memcpy(&(self->sadr.sin_addr), hp->h_addr, hp->h_length);
      }
      else
            memcpy(&(self->sadr.sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));

#if defined (HAVE_GETIPNODEBYNAME)
      freehostent(hp);
#endif /* HAVE_GETIPNODEBYNAME */
      self->sadr.sin_family = AF_INET;
      self->sadr.sin_port = htons(port);

      self->socket = socket(AF_INET, SOCK_STREAM, 0);
      if (self->socket == -1)
      {
            self->errornumber = SOCKET_COULD_NOT_CREATE_SOCKET;
            self->errormsg = "Could not create Socket.";
            return 0;
      }

      if (connect(self->socket, (struct sockaddr *) & (self->sadr),
                        sizeof(self->sadr)) < 0)
      {
            self->errornumber = SOCKET_COULD_NOT_CONNECT;
            self->errormsg = "Could not connect to remote socket.";
            closesocket(self->socket);
            self->socket = (SOCKETFD) - 1;
            return 0;
      }
      return 1;
}


void
SOCK_get_n_char(SocketClass *self, char *buffer, int len)
{
      int               lf;

      if (!self)
            return;
      if (!buffer)
      {
            self->errornumber = SOCKET_NULLPOINTER_PARAMETER;
            self->errormsg = "get_n_char was called with NULL-Pointer";
            return;
      }

      for (lf = 0; lf < len; lf++)
            buffer[lf] = SOCK_get_next_byte(self);
}


void
SOCK_put_n_char(SocketClass *self, char *buffer, int len)
{
      int               lf;

      if (!self)
            return;
      if (!buffer)
      {
            self->errornumber = SOCKET_NULLPOINTER_PARAMETER;
            self->errormsg = "put_n_char was called with NULL-Pointer";
            return;
      }

      for (lf = 0; lf < len; lf++)
            SOCK_put_next_byte(self, (unsigned char) buffer[lf]);
}


/*
 *    bufsize must include room for the null terminator
 *    will read at most bufsize-1 characters + null.
 *    returns TRUE if truncation occurs.
 */
BOOL
SOCK_get_string(SocketClass *self, char *buffer, int bufsize)
{
      register int lf = 0;

      for (lf = 0; lf < bufsize - 1; lf++)
            if (!(buffer[lf] = SOCK_get_next_byte(self)))
                  return FALSE;

      buffer[bufsize - 1] = '\0';
      return TRUE;
}


void
SOCK_put_string(SocketClass *self, char *string)
{
      register int lf;
      int               len;

      len = strlen(string) + 1;

      for (lf = 0; lf < len; lf++)
            SOCK_put_next_byte(self, (unsigned char) string[lf]);
}


int
SOCK_get_int(SocketClass *self, short len)
{
      if (!self)
            return 0;
      switch (len)
      {
            case 2:
                  {
                        unsigned short buf;

                        SOCK_get_n_char(self, (char *) &buf, len);
                        if (self->reverse)
                              return buf;
                        else
                              return ntohs(buf);
                  }

            case 4:
                  {
                        unsigned int buf;

                        SOCK_get_n_char(self, (char *) &buf, len);
                        if (self->reverse)
                              return buf;
                        else
                              return ntohl(buf);
                  }

            default:
                  self->errornumber = SOCKET_GET_INT_WRONG_LENGTH;
                  self->errormsg = "Cannot read ints of that length";
                  return 0;
      }
}


void
SOCK_put_int(SocketClass *self, int value, short len)
{
      unsigned int rv;

      if (!self)
            return;
      switch (len)
      {
            case 2:
                  rv = self->reverse ? value : htons((unsigned short) value);
                  SOCK_put_n_char(self, (char *) &rv, 2);
                  return;

            case 4:
                  rv = self->reverse ? value : htonl((unsigned int) value);
                  SOCK_put_n_char(self, (char *) &rv, 4);
                  return;

            default:
                  self->errornumber = SOCKET_PUT_INT_WRONG_LENGTH;
                  self->errormsg = "Cannot write ints of that length";
                  return;
      }
}


void
SOCK_flush_output(SocketClass *self)
{
      int               written;

      if (!self)
            return;
      written = send(self->socket, (char *) self->buffer_out, self->buffer_filled_out, 0);
      if (written != self->buffer_filled_out)
      {
            self->errornumber = SOCKET_WRITE_ERROR;
            self->errormsg = "Could not flush socket buffer.";
      }
      self->buffer_filled_out = 0;
}


unsigned char
SOCK_get_next_byte(SocketClass *self)
{
      if (!self)
            return 0;
      if (self->buffer_read_in >= self->buffer_filled_in)
      {
            /*
             * there are no more bytes left in the buffer so reload the buffer
             */
            self->buffer_read_in = 0;
            self->buffer_filled_in = recv(self->socket, (char *) self->buffer_in, self->buffer_size, 0);

            mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, self->buffer_size);

            if (self->buffer_filled_in < 0)
            {
                  self->errornumber = SOCKET_READ_ERROR;
                  self->errormsg = "Error while reading from the socket.";
                  self->buffer_filled_in = 0;
                  return 0;
            }
            if (self->buffer_filled_in == 0)
            {
                  self->errornumber = SOCKET_CLOSED;
                  self->errormsg = "Socket has been closed.";
                  self->buffer_filled_in = 0;
                  return 0;
            }
      }
      return self->buffer_in[self->buffer_read_in++];
}


void
SOCK_put_next_byte(SocketClass *self, unsigned char next_byte)
{
      int               bytes_sent;

      if (!self)
            return;
      self->buffer_out[self->buffer_filled_out++] = next_byte;

      if (self->buffer_filled_out == self->buffer_size)
      {
            /* buffer is full, so write it out */
            bytes_sent = send(self->socket, (char *) self->buffer_out, self->buffer_size, 0);
            if (bytes_sent != self->buffer_size)
            {
                  self->errornumber = SOCKET_WRITE_ERROR;
                  self->errormsg = "Error while writing to the socket.";
            }
            self->buffer_filled_out = 0;
      }
}

Generated by  Doxygen 1.6.0   Back to index