/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- ipc_set_active
- ipc_get_active
- ipc_send_receive
- ipc_close
- 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