sockets.c



Depending on the targer system you specified in the makefile, this file implements two functions:
  • open_tcp_connexion
  • Get_Sock_Adress
As you can see, we use conditional compilation depending on the target system (actually Windows or UNIX). Generic macros defined in "sockets.h" make the functions' declarations system independent.

open_tcp_connexion()

The function open_tcp_connexion() opens a TCP connection to a server.

argument description
tcp_host Host's name (or IP address) of the server's host.
tcp_port Port number od the server.
tcp_add This argument will receive the internet address os the server.
timeout Timeout in seconds. If the function can not connect to the server before the end of the timeout, then the function returns SCK_TIMEOUT_CONNECT.


Return value:
  • SCK_OK: Success.
  • SCK_CREATE_ERROR: Can not create socket. This means that the system call socket() failed.
  • SCK_CONNECT_ERROR: Can not connect to the server. This means that the system call connect() failed.
  • SCK_GET_IP_ERROR: Can not get the IP address associated with the host name. This means that the system call gethostbyname() failed.
  • SCK_TIMEOUT_CONNECT: Can not connect to the server before the end of the timeout.
  • SCK_SOCK_INIT_DLL_ERR: Can not initialize the winsock library (Windows only).
  • SCK_SOCK_INIT_DLL_CHECK_ERR: Wrong winsock library's version.
  • SCK_SET_NON_BLOCK_ERR: Can not set socket in non blocking mode.
  • SCK_SET_BLOCK_ERR: Can not set socket in blocking mode.

Get_Sock_Adress

This function returns the server's internet address.

argument description
Machine_serveur Server's IP address.
port_serveur Server's port.
TCP_address This argument receives the server's internet address.


Return value:
  • always SOCK_OK



/******************************************************************************/
/* sockets.c: Socket management for TCP connexion */
/* */
/* Author: Denis BEURIVE. */
/******************************************************************************/

#include <errno.h>
#include "sockets.h"
#include <stdio.h>




/*****************************************************************************/
/* open_tcp_connexion */
/* */
/* -> tcp_host: Distant host (could be a host name or an IP address). */
/* -> tcp_port: Port number of the service to contact. */
/* <- tcp_add: Pointer to a structure unsed to save the Internet address. */
/* You probably don't need it, but sometimes you mist have it. */
/* -> timeout: timeout in seconds. */
/* */
/* RET: SCK_CREATE_ERROR => Can not create the socket. */
/* SCK_CONNECT_ERROR => Can not establish the connexion to the */
/* host. */
/* SCK_GET_IP_ERROR => gethostbyname() failed. This means that */
/* the system can not convert the host name */
/* into an IP address. */
/*****************************************************************************/

SOCK open_tcp_connexion (SOCK_IN *tcp_add, char *tcp_host, int tcp_port, int timeout)
{
  SOCK desc;
  int cr;
  struct hostent *name;
  char ip[16];

  #if OS == WINDOWS_OS
        u_long cmd_option;
        DWORD start;
        int last_error;
  #endif

  #if OS == UNIX_OS
  
        int err;
        
  #endif

  #if OS == WINDOWS_OS

        WORD wVersionRequested;
        WSADATA wsaData;

  #endif

  /***************************************************************************/
  /* For Windows only, initialize the "winsock" library. */
  /***************************************************************************/

  #if OS == WINDOWS_OS

        wVersionRequested = MAKEWORD(2, 0);
 
        if (WSAStartup(wVersionRequested, &wsaData) != 0)
        { return SCK_SOCK_INIT_DLL_ERR; }

        if ((LOBYTE( wsaData.wVersion ) != 2) ¦¦ (HIBYTE( wsaData.wVersion ) != 0) )
        {
                WSACleanup();
                return SCK_SOCK_INIT_DLL_CHECK_ERR;
        }

  #endif

  #ifdef DEBUG
  fprintf (stdout, "\nopen_tcp_connexion: begin\n");
  fprintf (stdout, "\nTCP host: %s\n", tcp_host);
  fflush (stdout);
  #endif

  name = gethostbyname (tcp_host);
  if (name == NULL)
  { return SCK_GET_IP_ERROR; }

  #ifdef DEBUG
  fprintf (stdout, "\nopen_tcp_connexion: gethostbyname() done\n");
  fflush (stdout);
  #endif

  sprintf (ip, "%d.%d.%d.%d", (unsigned char)(name->h_addr_list)[0][0],
                              (unsigned char)(name->h_addr_list)[0][1],
                              (unsigned char)(name->h_addr_list)[0][2],
                              (unsigned char)(name->h_addr_list)[0][3]);

  #ifdef DEBUG
  fprintf (stdout, "\nopen_tcp_connexion: get the IP, done\n");
  fflush (stdout);
  #endif

  desc = CREATE_SOCKET(AF_INET, SOCK_STREAM, 0);
  if (desc == SCK_ERROR_SOCKET) { return (SCK_CREATE_ERROR); };

  #ifdef DEBUG
  fprintf (stdout, "\nopen_tcp_connexion: open socket, done\n");
  fflush (stdout);
  #endif

  Get_Sock_Adress (ip, tcp_port, tcp_add);

  #ifdef DEBUG
  fprintf (stdout, "\nopen_tcp_connexion: Get_Sock_Adress(), done\n");
  fflush (stdout);
  #endif


  /***************************************************************************/
  /* Under Windows we use non blocking sockets to implement the "connect's */
  /* timeout". */
  /***************************************************************************/

  #if OS == WINDOWS_OS

  /***************************************************************************/
  /* Set sockect in non blocking mode */
  /***************************************************************************/

  cmd_option = 1;

  if (ioctlsocket (desc, FIONBIO, &cmd_option) == SOCKET_ERROR)
  { return SCK_SET_NON_BLOCK_ERR; }

  /***************************************************************************/
  /* Get start time */
  /***************************************************************************/

  cr = 1;
  start = GetTickCount();

  /***************************************************************************/
  /* Loop until we connect or until timeout */
  /***************************************************************************/

  while (cr != 0)
  {

  #endif




  /***************************************************************************/

  cr = CONNECT_TO_SERVER(desc, tcp_add, sizeof(struct sockaddr_in));

  /***************************************************************************/





  #if OS == WINDOWS_OS

        last_error = WSAGetLastError();
        if (cr == SCK_ERROR_CONNECT)
        {
                if (
                                (last_error != WSAEWOULDBLOCK)
                                &&
                                (last_error != WSAEALREADY)
                                &&
                                (last_error != WSAEISCONN)
                        )
                { return SCK_CONNECT_ERROR; }
                else
                {
                        if (last_error == WSAEISCONN)
                        {
                                /*****************************************************************/
                                /* We set back the socket in blocking mode now and we return the */
                                /* socket's descriptor. */
                                /*****************************************************************/

                                cmd_option = 0;
                                if (ioctlsocket (desc, FIONBIO, &cmd_option) == SOCKET_ERROR)
                                { return SCK_SET_BLOCK_ERR; }

                                return desc;
                        }
                }

                if ((GetTickCount() - start) > timeout*1000)
                { return SCK_TIMEOUT_CONNECT; }
        }
  }
  #endif

  /***************************************************************************/
  /* Under UNIX, the system call "connect()" may be interrupted by the sig- */
  /* -nal "SIGALRM". */
  /***************************************************************************/

  #if OS == UNIX_OS
  err = errno;
  
  if (cr == SCK_ERROR_CONNECT)
  {
    #if OS == UNIX_OS
        if (err == EINTR) { return SCK_TIMEOUT_CONNECT; }
        #endif
        return SCK_CONNECT_ERROR;
  }

  #endif

  return (desc);
};

/***************************************************************************/
/* Get_Sock_Adress */
/* */
/* Get the Internet address of a service from the following data: */
/* */
/* -> Machine_serveur : (in) Host IP address. */
/* -> port_serveur : (in) Port number. */
/* <- TCP_address : (out) service's address. */
/* */
/* RET: Always SCK_OK */
/***************************************************************************/

int Get_Sock_Adress (char *Machine_serveur, int port_serveur, SOCK_IN *TCP_address)
{
  #ifdef DEBUG
  fprintf (stdout, "\nGet_Sock_Adress: begin\n");
  fflush (stdout);
  #endif

  memset ((void*)TCP_address, 0, sizeof(struct sockaddr_in));
  TCP_address->sin_family = AF_INET;
  TCP_address->sin_port = htons((u_short)port_serveur);
  (TCP_address->sin_addr).s_addr = inet_addr(Machine_serveur);

  #ifdef DEBUG
  fprintf (stdout, "\nGet_Sock_Adress: end\n");
  fflush (stdout);
  #endif

  return (SCK_OK);
}