## root/clib/ipclient.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. ipc_set_active
2. ipc_get_active
3. ipc_send_receive
4. ipc_close
5. ipclient_connect

    /* High-level client IPC API for TCP sockets and QNX message passing.
       Rick Smereka, Copyright (C) 1998-2002.

       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, get a copy via the Internet at
       http://gnu.org/copyleft/gpl.html or write to the Free Software
       Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       MA 02111-1307 USA

       You can contact the author via email at rsmereka@future-lab.com

       Original version for CodeWarrior V4 under Windows 32bit.
       Dec/98, Rick Smereka

       Ported to HP-UX under GNU C 2.8.1.
       Jan/99, Rick Smereka

       Ported to Red Hat Linux 5.2, Jul/99, Rick Smereka

       Changed 'clientSocket' to 'clientsock' to avoid global
       naming conflicts and removed 'WSA' Winsock functions.
       Dec/99, Rick Smereka

       Found major structural bug with socket 'connect' in the
       'ipc_init' function. Moved socket initialization to
       static function 'ipclient_connect'. Added 'ipclient_hostname',
       'ipclient_port' and 'ipclient_init' global data. Removed
       'ipc_init', 'ipc_send_data' and 'ipc_recv_data' functions.
       Added functions 'ipc_set_active, 'ipc_get_active' and
       'ipc_send_receive'. May/2000, Rick Smereka

       Modified for use with TCP sockets and QNX message passing.
       Sep/2001, Rick Smereka

       Ported to Debian Linux. Nov/2002, Rick Smereka

       Changed socket version to use TCP 'connect' function only when
       'ipc_set_active' is called. The socket now remains open and is
       only closed when 'ipc_close' is called (which is done automatically
       upon subsequent call to 'ipc_set_active'). This API will properly
       talk only to server's that are using the new 'ipcsrv' (GPL
       package version 1.33 or higher). May/2003, Rick Smereka */

    #include "stdhead.h"
    #include "flsocket.h"

    #ifdef IPC_TCP
    #include "ipcomm.h"
    #endif

    #include "ipclient.h"

    #ifdef IPC_TCP

    // global (to module) socket data

    #ifdef OS_WIN32
    SOCKET clientsock;               // client socket
    SOCKADDR_IN sockClientAddr;      // client address structure
    LPHOSTENT lpHostEnt;             // host info structure
    #else
    int clientsock;
    struct sockaddr_in sockClientAddr;
    struct hostent *lpHostEnt;
    #endif

    int ipclient_port;               // server port number
    #else

    // global QNX message passing data

    pid_t ipclient_port = -1;        // QNX pid stored in port number
    #endif

    char ipclient_hostname[128];     // server host name
    int ipclient_init = FALSE;       // client interface flag

    /* private functions (sockets only) */

    #ifdef IPC_TCP
    static int ipclient_connect(void);
    #endif

    #ifdef IPC_TCP
    int ipc_set_active(char *host_name, int port_number)
    #else
    int ipc_set_active(char *host_name)
    #endif
    {
       /* Set the active server host name and port number (sockets) or
          the QNX server name. In the case of sockets, the host and
          port data is loaded into the module globals, in the case of
          QNX message passing, the data is loaded and the 'nameloc'
          service name is verified. Function returns 'TRUE' upon
          success, 'FALSE' otherwise. */

       if (host_name == (char *)NULL || !strlen(host_name))
          return(FALSE);

    #ifdef IPC_TCP
       if (port_number <= 0)
          return(FALSE);

       /* if already connected to a server, close it */

       if (ipclient_init)
          (void)ipc_close();

       /* load global data */

       strcpy(ipclient_hostname, host_name);
       ipclient_port = port_number;

       /* attempt to connect to currently defined server (TCP socket only) */

       if (!ipclient_connect())
          return(FALSE);
    #else
       /* QNX message passing code */

       if ((ipclient_port = qnx_name_locate(0, host_name, 0, NULL)) == -1)
          return(FALSE);

       strcpy(ipclient_hostname, host_name);
    #endif

       ipclient_init = TRUE;
       return(TRUE);
    }

    #ifdef IPC_TCP
    int ipc_get_active(char *host_name, int *port_number)
    #else
    int ipc_get_active(char *host_name)
    #endif
    {
       /* Obtain the current server host name and port number.
          Function returns 'TRUE' upon success with the server
          host name loaded into 'host_name' which must be already
          allocated to sufficient size, the server port number will
          be loaded into 'port_number'. Function returns 'FALSE'
          upon failure. */

       if (host_name == (char *)NULL)
          return(FALSE);

    #ifdef IPC_TCP
       if (port_number == (int *)NULL)
          return(FALSE);

       *port_number = 0;
    #endif

       host_name[0] = EOS;

       if (!ipclient_init)
          return(FALSE);

       strcpy(host_name, ipclient_hostname);

    #ifdef IPC_TCP
       *port_number = ipclient_port;
    #endif

       return(TRUE);
    }

    #ifdef IPC_TCP
    int ipc_send_receive(char *sbuf, char *rbuf)
    #else
    int ipc_send_receive(char *sbuf, char *rbuf, int size_rbuf)
    #endif
    {
       /* Send a command to the current server and
          wait for a reply. Function returns 'TRUE' upon
          success with the receive contents loaded into
          'rbuf' which must be already allocated to
          sufficient size by the caller. Function
          returns 'FALSE' upon failure. */

    #ifdef IPC_QNX
       int i, sent = FALSE;
    #endif

       if (!ipclient_init)
          return(FALSE);

       if (sbuf == (char *)NULL || !strlen(sbuf))
          return(FALSE);

       if (rbuf == (char *)NULL)
          return(FALSE);

    #ifdef IPC_QNX
       if (size_rbuf <= 0)
          return(FALSE);
    #endif

       rbuf[0] = EOS;

    #ifdef IPC_TCP

       /* we are connected, send the command string using
          the low level socket send function */

       if (ipc_send(clientsock, sbuf) == 0)
          {
          (void)ipc_close();
          return(FALSE);
          }

       /* receive reply */

       if (ipc_recv(clientsock, rbuf) == 0)
          {
          (void)ipc_close();
          return(FALSE);
          }
    #else
       /* QNX message passing version uses a retry loop
          and the 'Send' function also receives the reply */

       for(i = 0; i < IPC_SEND_RETRY; i++)
          if (!Send(ipclient_port, sbuf, rbuf, strlen(sbuf) + 1, size_rbuf))
             {
             sent = TRUE;
             break;
             }

       if (!sent)
          return(FALSE);
    #endif

       return(TRUE);
    }

    /* socket functions */

    #ifdef IPC_TCP
    int ipc_close(void)
    {
       /* Close the socket between client and server.
          Function returns 'TRUE' upon success, 'FALSE'
          otherwise. */

    #ifdef OS_WIN32
       if (closesocket(clientsock) == SOCKET_ERROR)
          return(FALSE);
    #endif

    #ifdef OS_UNIX
       close(clientsock);
    #endif

       ipclient_init = FALSE;
       return(TRUE);
    }

    /* private functions */

    static int ipclient_connect(void)
    {
       /* Use the previously loaded host name and port number to
          connect to the server. Function returns 'TRUE' if the
          connection was successful, 'FALSE' otherwise (TCP only). */

       // resolve server host name

       lpHostEnt = gethostbyname(ipclient_hostname);

       if (!lpHostEnt)
          return(FALSE);

       // create the socket

    #ifdef OS_WIN32
       clientsock = socket(PF_INET, SOCK_STREAM, DEFAULT_PROTOCOL);
    #endif

    #ifdef OS_UNIX
       clientsock = socket(AF_INET, SOCK_STREAM, DEFAULT_PROTOCOL);
    #endif

       if (clientsock == INVALID_SOCKET)
          return(FALSE);

       // load client address data

       memset(&sockClientAddr, 0, sizeof(sockClientAddr));
       sockClientAddr.sin_family = AF_INET;
       sockClientAddr.sin_port = htons(ipclient_port);

    #ifdef OS_WIN32
       sockClientAddr.sin_addr = *((LPIN_ADDR)*lpHostEnt->h_addr_list);
    #endif

    #ifdef OS_UNIX
       sockClientAddr.sin_addr.s_addr = ((struct in_addr *)(lpHostEnt->h_addr))->s_addr;
    #endif

       // connect to server

    #ifdef OS_WIN32
       if (connect(clientsock, (LPSOCKADDR)&sockClientAddr, sizeof(sockClientAddr)))
    #endif

    #ifdef OS_UNIX
       if (connect(clientsock, (SA *)&sockClientAddr, sizeof(sockClientAddr))
           == SOCKET_ERROR)
    #endif
          return(FALSE);

       return(TRUE);
    }
    #endif

/* [<][>][^][v][top][bottom][index][help] */