/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- sloc_initialize
- sloc_end
- sloc_log_off
- sloc_log_on
- sloc_log_status
- sloc_add
- sloc_config_add
- sloc_config_delete
- sloc_status
- sloc_service_name
- sloc_version
- sloc_delete
- sloc_find
- sloc_config_find
- sloc_find_list
- sloc_ll_find
- sloc_ll_find_list
- sloc_get_list
- sloc_put_list
- sloc_config_update
- sloc_config_get_list
- sloc_config_put_list
- sloc_dump_debug
- sloc_config_dump_debug
- sloc_terminate
- sloc_get_active_socloc
- sloc_set_active_socloc
- sloc_is_init
- sloc_trans_num
- sloc_connect_num
- sloc_term_api
- sloc_connect
- sloc_sr_code
- sloc_lsr_code
- sloc_sr_char
- sloc_lsr_char
- sloc_sr_int
- sloc_lsr_int
- sloc_sr_long
- sloc_lsr_long
- sloc_failover
- sloc_reload_config_list
- sloc_client_connect
- sloc_ll_client_connect
/* A high level client api module for the socket locate service.
Applies to TCP socket IPC method only.
Rick Smereka, Copyright (C) 2000-2005.
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
This API is used by both 'socloc' server and client applications.
Original Windows 32bit version under CodeWarrior V4. Feb/2000,
Rick Smereka
Changed function 'sloc_log_status' to accept the returned log
file name in addition to the code. Mar/2000, Rick Smereka
Corrected 'sloc_client_connect' to obtain the first config
entry using the function 'sl_config_get_first'. Modified function
'sloc_failover' to save the current 'spos' count before entering
the 'sloc_config_delete' loop. Jun/2000, Rick Smereka
Added include of header 'ip.h' after moving the function 'isip'.
Jul/2000, Rick Smereka
Changed name of module global 'sockClientAddr' to
'slsockClientAddr' to avoid duplicate module global names.
Jul/2001, Rick Smereka
Ported to Debian Linux. Nov/2002, Rick Smereka
Corrected bug in TCP socket connect to the server. The TCP
socket 'connect' function was being called for each request
sent to the server. This caused the socket descriptor pool
to become exhausted under some Unix's when a large number
of transactions were being processed. This behavior has been
changed to connect to the server only upon initialization or
previous send/receive socket error. This means that the socket
stays connected even when not in use. It is up to the
developer to call 'sloc_end' when the socket is no longer
required.
The 'socloc' server no longer uses this API. A new API called
'slocsrv.c' has been created specifically for the server.
This API will properly talk only to socloc server's that are using
the new 'ipcsrv' (GPL package version 1.33 or higher).
Added functions 'sloc_trans_num', 'sloc_connect_num' and
'sloc_term_api'. May/2003, Rick Smereka
Changed all logging calls from 'log_file_date' to 'logman'.
Mar/2004, Rick Smereka
Fixed bug in 'sloc_ll_find' that caused the system logger
not to record the server reply in the log file. Reply needed
double quotes around it. Removed this change as this fix
did not help. Jan/2005, Rick Smereka */
#include "stdhead.h" // standard include
#include "flsocket.h" // standard socket defines
#include "ipcomm.h" // low level socket send/receive
#include "sloc.h" // defines for this module
#include "socloc.h" // global socket locator defines
#include "slconfig.h" // socket locate config management
#include "sconnect.h" // connect string parse/build API
#include "ip.h" // IP library routines
// global (to module) data
#ifdef OS_WIN32
SOCKET slclientSocket; // client socket
SOCKADDR_IN slsockClientAddr; // client address structure
LPHOSTENT lpHostEnt; // host info structure
#endif
#ifdef OS_UNIX
int slclientSocket;
struct sockaddr_in slsockClientAddr;
struct hostent *lpHostEnt;
#endif
char sloc_hostname[128]; // host name of 'socloc' server
int sloc_port = 0; // port 'socloc' is using
// private functions
static int sloc_connect(char *, int);
static int sloc_sr_code(int, char *);
static int sloc_lsr_code(int, char *);
static int sloc_sr_char(int, char *, char *);
static int sloc_lsr_char(int, char *, char *);
static int sloc_sr_int(int, char *, int *);
static int sloc_lsr_int(int, char *, int *);
static int sloc_sr_long(int, char *, long *);
static int sloc_lsr_long(int, char *, long *);
static int sloc_failover(void);
static int sloc_reload_config_list(void);
static int sloc_client_connect(void);
static int sloc_ll_client_connect(void);
int sloc_initialize(void)
{
/* Initialize the client for communication with the
socket locate server. An attempt to get the server status
is made. Nodeid (host name), port number and optionally the
IP address are expected in the configuration file
'SL_CONFIG_FILE_NAME'. The format of this file is discussed
in 'slconfig.c'. Function returns 'SL_OK' if a successful
connection was made, a socket locate code otherwise. */
char mname[] = "sloc_initialize";
char hname[SL_MAXCOMMAND];
int ret, port;
logman("%s:enter", mname);
if ((ret = sl_config_read(SL_CONFIG_FILE_NAME)) != SL_OK)
{
logman("%s:bad rc from 'sl_config_read',rc[%d]", mname, ret);
return(ret);
}
// establish a connection to the first responding 'socloc' server
if ((ret = sloc_client_connect()) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_client_connect", mname, ret);
return(ret);
}
if ((ret = sloc_status()) != SL_OK)
{
logman("%s:bad rc from 'status',rc[%d]", mname, ret);
return(ret);
}
logman("%s:normal exit,server responding is '%s' on "
"port %d", mname, sloc_hostname, sloc_port);
return(SL_OK);
}
void sloc_end(void)
{
/* Stop communication with a 'socloc' server. The client socket
is closed and the 'socloc' server global details are wiped. */
char mname[] = "sloc_end";
logman("%s:enter", mname);
// if there are no 'socloc' server details, assume no connection
if (sloc_is_init() != SL_OK)
return;
#ifdef OS_WIN32
(void)closesocket(slclientSocket);
#else
close(slclientSocket);
#endif
sloc_port = 0;
sloc_hostname[0] = EOS;
logman("%s:normal exit", mname);
}
int sloc_log_off(void)
{
/* Turn 'socloc' server logging off.
Function returns 'SL_OK' upon success, an error code
otherwise. */
char mname[] = "sloc_log_off";
int ret;
logman("%s:enter,host=%s,port=%d", mname, sloc_hostname,
sloc_port);
ret = sloc_sr_code(SL_SEND_LOG_OFF, (char *)NULL);
logman("%s:normal exit,rc[%d]", mname, ret);
return(ret);
}
int sloc_log_on(char *lname)
{
/* Turn 'socloc; server logging on. Log file name 'lname'
is optional. Function returns 'SL_OK'
upon success, a 'socloc' code otherwise. */
char mname[] = "sloc_log_on";
int ret;
logman("%s:enter", mname);
ret = sloc_sr_code(SL_SEND_LOG_ON, lname);
logman("%s:normal exit,rc[%d]", mname, ret);
return(ret);
}
int sloc_log_status(int *lflag, char *lfname)
{
/* Get staus of 'socloc' server logging. Function returns
the log status (0=off,1=on) in 'lflag' and the current
log file name in 'lfname' upon success. Function returns a 'socloc'
code. */
char mname[] = "sloc_log_status";
char reply[128], flag_char[25];
int ret, flag;
logman("%s:enter,host=%s,port=%d", mname, sloc_hostname,
sloc_port);
if (lflag == (int *)NULL)
{
logman("%s:null[lflag]", mname);
return(SL_INVALID_PARAMETER);
}
if (lfname == (char *)NULL)
{
logman("%s:null[lfname]", mname);
return(SL_INVALID_PARAMETER);
}
lfname[0] = EOS;
*lflag = 0;
if ((ret = sloc_sr_char(SL_SEND_LOG_STATUS, (char *)NULL, reply))
!= SL_OK)
{
logman("%s:bad rc[%d] from sloc_sr_char", mname, ret);
return(ret);
}
if (!command_word(reply, flag_char, 1))
{
logman("%s:error getting flag_char", mname);
return(SL_INTERNAL_ERROR);
}
if (!qatoi(flag_char, &flag))
{
logman("%s:status flag is non-numeric", mname);
return(SL_INTERNAL_ERROR);
}
if (flag != 0 && flag != 1)
{
logman("%s:status flag has incorrect value", mname);
return(SL_INTERNAL_ERROR);
}
*lflag = flag;
if (!command_word(reply, lfname, 2))
{
logman("%s:error getting lfname", mname);
return(SL_INTERNAL_ERROR);
}
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_add(char *sname, char *hname, int port, char *ip_ad)
{
/* Add a socket server entry to 'socloc'. The IP address ('ip_ad')
may be null but if it is not null, it must be a valid
IP address. Function returns 'SL_OK' upon success,
a 'socloc' code otherwise. */
char mname[] = "sloc_add";
char *parm, *tsname, *thname;
int len, ret;
logman("%s:enter", mname);
if (sname == (char *)NULL || !strlen(sname))
{
logman("%s:null or empty[sname]", mname);
return(SL_INVALID_PARAMETER);
}
if (hname == (char *)NULL || !strlen(hname))
{
logman("%s:null or empty[hname]", mname);
return(SL_INVALID_PARAMETER);
}
if (port <= 0)
{
logman("%s:out of range[port]", mname);
return(SL_INVALID_PARAMETER);
}
/* make sure IP address (if present) is valid */
if (ip_ad != (char *)NULL)
if (!isip(ip_ad))
{
logman("%s:invalid ip address", mname);
return(SL_BAD_IP);
}
/* calc total length of parameter
length of service name + host name + port + ip_ad + 5 */
len = strlen(sname) + strlen(hname) + 30;
if ((parm = (char *)malloc(len)) == (char *)NULL)
{
logman("%s:alloc fail[parm]", mname);
return(SL_MEMORY_FAIL);
}
/* load each string into tmp strings, expanding
string with quotes if spaces are present */
if ((tsname = (char *)malloc(len)) == (char *)NULL)
{
logman("%s:alloc fail[tsname]", mname);
free(parm);
return(SL_MEMORY_FAIL);
}
if (words(sname) > 1)
sprintf(tsname, "'%s'", sname);
else
strcpy(tsname, sname);
if ((thname = (char *)malloc(len)) == (char *)NULL)
{
logman("%s:alloc fail[thname]", mname);
free(parm);
free(tsname);
return(SL_MEMORY_FAIL);
}
if (words(hname) > 1)
sprintf(thname, "'%s'", hname);
else
strcpy(thname, hname);
/* build final parameter string, we send a one as the
first parameter to indicate the originating client */
if (ip_ad != (char *)NULL)
sprintf(parm, "1 %s %s %d %s", tsname, thname, port, ip_ad);
else
sprintf(parm, "1 %s %s %d", tsname, thname, port);
free(tsname);
free(thname);
logman("%s:parm=%s", mname, parm);
ret = sloc_sr_code(SL_SEND_ADD, parm);
logman("%s:normal exit[%d]", mname, ret);
free(parm);
return(ret);
}
int sloc_config_add(char *hname, int port, char *ip_ad)
{
/* Add a config entry to 'socloc'. The IP address ('ip_ad')
may be null. Function returns 'SL_OK' upon success,
a 'socloc' code otherwise. */
char mname[] = "sloc_config_add";
char *parm, *thname;
int len, ret;
logman("%s:enter", mname);
if (hname == (char *)NULL || !strlen(hname))
{
logman("%s:null or empty[hname]", mname);
return(SL_INVALID_PARAMETER);
}
if (port <= 0)
{
logman("%s:out of range[port]", mname);
return(SL_INVALID_PARAMETER);
}
/* make sure IP address (if present) is valid */
if (ip_ad != (char *)NULL)
if (!isip(ip_ad))
{
logman("%s:invalid ip address", mname);
return(SL_BAD_IP);
}
/* calc total length of parameter
length of host name + port + ip_ad + 5 */
len = strlen(hname) + 30;
if ((parm = (char *)malloc(len)) == (char *)NULL)
{
logman("%s:alloc fail[parm]", mname);
return(SL_MEMORY_FAIL);
}
/* load host name into tmp strings, expanding
string with quotes if spaces are present */
if ((thname = (char *)malloc(len)) == (char *)NULL)
{
logman("%s:alloc fail[thname]", mname);
free(parm);
return(SL_MEMORY_FAIL);
}
if (words(hname) > 1)
sprintf(thname, "'%s'", hname);
else
strcpy(thname, hname);
/* build final parameter string, we send a one as the
first parameter to indicate the originating client */
if (ip_ad != (char *)NULL)
sprintf(parm, "1 %s %d %s", thname, port, ip_ad);
else
sprintf(parm, "1 %s %d", thname, port);
free(thname);
ret = sloc_sr_code(SL_SEND_CONFIG_ADD, parm);
logman("%s:exit[%d]:parm=%s", mname, ret, parm);
free(parm);
return(ret);
}
int sloc_config_delete(int port)
{
/* Delete a config 'socloc' entry. Function returns 'SL_OK'
upon success, a 'socloc' code otherwise. */
char mname[] = "sloc_config_delete";
char parm[25];
int ret;
logman("%s:enter", mname);
if (port <= 0)
{
logman("%s:out of range[port]", mname);
return(SL_INVALID_PARAMETER);
}
sprintf(parm,"1 %d", port);
ret = sloc_sr_code(SL_SEND_CONFIG_DELETE, parm);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_status(void)
{
/* Get 'socloc' server status.
Function returns 'SL_OK' upon success, an error code
otherwise. */
char mname[] = "sloc_status";
int ret;
logman("%s:enter,host=%s,port=%d", mname, sloc_hostname,
sloc_port);
ret = sloc_sr_code(SL_SEND_STATUS, (char *)NULL);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_service_name(char *sname)
{
/* Get the service name of a 'socloc' server.
Upon success, the service name will be loaded into
'sname' which must already be allocated to sufficient
size. Function returns a 'socloc' code. */
char mname[] = "sloc_service_name";
int ret;
logman("%s:enter", mname);
if (sname == (char *)NULL)
{
logman("%s:null[sname]", mname);
return(SL_INVALID_PARAMETER);
}
if ((ret = sloc_sr_char(SL_SEND_SERVICE_NAME, (char *)NULL, sname))
!= SL_OK)
{
logman("%s:rc[%d] from sloc_sr_char", mname, ret);
return(ret);
}
return(SL_OK);
}
int sloc_version(char *version)
{
/* Get the version of a 'socloc' server.
Upon success, the version string will be loaded into
'version' which must already be allocated to sufficient
size. Function returns a 'socloc' code. */
char mname[] = "sloc_version";
int ret;
logman("%s:enter", mname);
if (version == (char *)NULL)
{
logman("%s:null[version]", mname);
return(SL_INVALID_PARAMETER);
}
if ((ret = sloc_sr_char(SL_SEND_VERSION, (char *)NULL, version))
!= SL_OK)
{
logman("%s:rc[%d] from sloc_sr_char", mname, ret);
return(ret);
}
return(SL_OK);
}
int sloc_delete(int port)
{
/* Delete a socket server entry. Function returns 'SL_OK'
upon success, a 'socloc' code otherwise. */
char mname[] = "sloc_delete";
char parm[25];
int ret;
logman("%s:enter,port=%d", mname, port);
if (port <= 0)
{
logman("%s:out of range[port]", mname);
return(SL_INVALID_PARAMETER);
}
/* indicate a client send with 'orig_flag' set to one */
sprintf(parm,"1 %d", port);
ret = sloc_sr_code(SL_SEND_DELETE, parm);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_find(char *sname, char *hname, int *port, char *ip_ad)
{
/* Find a 'socloc' entry. Only the service name is used.
The IP address ('ip_ad') may be null. Upon success, details
are loaded into 'hname', 'port' and optionally 'ip_ad'.
Function returns a 'socloc' code. */
char mname[] = "sloc_find";
int ret;
logman("%s:enter", mname);
if (sname == (char *)NULL || !strlen(sname))
{
logman("%s:null or empty[sname]", mname);
return(SL_INVALID_PARAMETER);
}
if (hname == (char *)NULL)
{
logman("%s:null[hname]", mname);
return(SL_INVALID_PARAMETER);
}
if (port == (int *)NULL)
{
logman("%s:null[port]", mname);
return(SL_INVALID_PARAMETER);
}
hname[0] = EOS;
*port = 0;
if (ip_ad != (char *)NULL)
ip_ad[0] = EOS;
ret = sloc_ll_find(sname, hname, port, ip_ad);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_config_find(char *hname, int *port, char *ip_ad)
{
/* Find a 'socloc' config entry by one or more details.
At least one detail must be present.Upon success,
missing details are loaded into 'hname', 'port'
and optionally 'ip_ad'. Function returns a 'socloc' code. */
char mname[] = "sloc_config_find";
char *buildstr, *reply, mes[128];
int ret, ishname, isport, isip;
logman("%s:enter", mname);
ishname = isport = isip = TRUE;
if (hname == (char *)NULL || !strlen(hname))
ishname = FALSE;
if (port == (int *)NULL || *port <= 0)
isport = FALSE;
if (ip_ad == (char *)NULL || !strlen(ip_ad))
isip = FALSE;
if (!ishname && !isport && !isip)
{
logman("%s:no parameters", mname);
return(SL_INVALID_PARAMETER);
}
/* use 'sconnect_build' to form the connect string */
if ((buildstr = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[buildstr]", mname);
return(SL_MEMORY_FAIL);
}
if ((ret = sconnect_build((char *)NULL, hname, port, ip_ad, buildstr))
!= SP_OK)
{
free(buildstr);
sp_code_string(ret, mes);
logman("%s:bad rc[%s] from sconnect_build", mname, mes);
return(SL_INVALID_PARAMETER);
}
if ((reply = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[reply]", mname);
free(buildstr);
return(SL_MEMORY_FAIL);
}
logman("%s:parm=%s,l=%d", mname, buildstr, strlen(buildstr));
ret = sloc_sr_char(SL_SEND_CONFIG_FIND, buildstr, reply);
free(buildstr);
if (ret != SL_OK)
{
logman("%s:exit bad rc[%d]", mname, ret);
free(reply);
return(ret);
}
logman("%s:server reply=%s,l=%d", mname, reply, strlen(reply));
/* take apart the return string and load only the missing pieces */
if (command_words(reply) < 2)
{
logman("%s:incorrect number of words returned", mname);
free(reply);
return(SL_INTERNAL_ERROR);
}
if ((buildstr = (char *)malloc(strlen(reply) + 1)) == (char *)NULL)
{
logman("%s:alloc fail[buildstr]", mname);
free(reply);
return(SL_MEMORY_FAIL);
}
if (!ishname && hname != (char *)NULL)
if (!command_word(reply, hname, 1))
{
logman("%s:error getting host name", mname);
free(reply);
free(buildstr);
return(SL_INTERNAL_ERROR);
}
if (!isport && port != (int *)NULL)
{
if (!command_word(reply, buildstr, 2))
{
logman("%s:error getting port char", mname);
free(reply);
free(buildstr);
return(SL_INTERNAL_ERROR);
}
if (!qatoi(buildstr, port))
{
logman("%s:server returned port that is not a number", mname);
free(reply);
free(buildstr);
return(SL_INTERNAL_ERROR);
}
}
if (command_words(reply) > 2)
if (!isip && ip_ad != (char *)NULL)
if (!command_word(reply, ip_ad, 3))
{
logman("%s:error getting ip address", mname);
free(reply);
free(buildstr);
return(SL_INTERNAL_ERROR);
}
free(reply);
free(buildstr);
logman("%s:normal exit[0]", mname);
return(SL_OK);
}
int sloc_find_list(char *sname, char *list_out)
{
/* Find one or more 'socloc' entries by service name. All entries
matching the service name will be loaded into 'list_out'.
The list is delimited by 'SL_LIST_DELIM'. Function returns
a 'socloc' code. */
char mname[] = "sloc_find_list";
int ret;
logman("%s:enter", mname);
if (sname == (char *)NULL || !strlen(sname))
{
logman("%s:null or empty[sname]", mname);
return(SL_INVALID_PARAMETER);
}
if (list_out == (char *)NULL)
{
logman("%s:null[list_out]", mname);
return(SL_INVALID_PARAMETER);
}
ret = sloc_ll_find_list(sname, (char *)NULL, (int *)NULL, (char *)NULL,
list_out);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_ll_find(char *sname, char *hname, int *port, char *ip_ad)
{
/* Find a 'socloc' entry. All parameters are optional. At least
one parameter must be specified. The lookup will use all
supplied parameters to perform the lookup. If you just want
to find by service name, do not call this function, use
'sloc_find' instead. Upon success, the missing items will
be loaded. Function returns 'SL_OK' upon success, a
'socloc' code otherwise. */
char mname[] = "sloc_ll_find";
char *buildstr, *parm, *wrd, mes[128];
int ret;
logman("%s:enter", mname);
if (sname == (char *)NULL)
{
logman("%s:null[sname]", mname);
return(SL_INVALID_PARAMETER);
}
if (hname == (char *)NULL)
{
logman("%s:null[hname]", mname);
return(SL_INVALID_PARAMETER);
}
if (port == (int *)NULL)
{
logman("%s:null[port]", mname);
return(SL_INVALID_PARAMETER);
}
if (!strlen(sname) && !strlen(hname) && *port <= 0 &&
(ip_ad == (char *)NULL || !strlen(ip_ad)))
{
logman("%s:at least one parameter must be supplied", mname);
return(SL_INVALID_PARAMETER);
}
/* use 'sconnect_build' to form the connect string */
if ((buildstr = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[buildstr]", mname);
return(SL_MEMORY_FAIL);
}
if ((ret = sconnect_build(sname, hname, port, ip_ad, buildstr))
!= SP_OK)
{
free(buildstr);
sp_code_string(ret, mes);
logman("%s:bad rc[%s] from sconnect_build", mname, mes);
return(SL_INVALID_PARAMETER);
}
if ((wrd = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[wrd]", mname);
free(buildstr);
return(SL_MEMORY_FAIL);
}
logman("%s:buildstr=%s,l=%d", mname, buildstr, strlen(buildstr));
ret = sloc_sr_char(SL_SEND_FIND, buildstr, wrd);
free(buildstr);
if (ret != SL_OK)
{
logman("%s:exit bad rc[%d]", mname, ret);
free(wrd);
return(ret);
}
logman("%s:server reply=%s,l=%d", mname, wrd, strlen(wrd));
/* take apart the return string and load only the missing pieces */
if (command_words(wrd) < 2)
{
logman("%s:incorrect number of words returned", mname);
logman("%s:wrd=%s,l=%d", mname, wrd, strlen(wrd));
free(wrd);
return(SL_INTERNAL_ERROR);
}
if ((parm = (char *)malloc(strlen(wrd) + 1)) == (char *)NULL)
{
logman("%s:alloc fail[parm]", mname);
free(wrd);
return(SL_MEMORY_FAIL);
}
if (!strlen(sname))
if (!command_word(wrd, sname, 1))
{
logman("%s:error getting service name", mname);
free(wrd);
free(parm);
return(SL_INTERNAL_ERROR);
}
if (!strlen(hname))
if (!command_word(wrd, hname, 2))
{
logman("%s:error getting host name", mname);
free(wrd);
free(parm);
return(SL_INTERNAL_ERROR);
}
if (*port == 0)
{
if (!command_word(wrd, parm, 3))
{
logman("%s:error getting port char", mname);
free(wrd);
free(parm);
return(SL_INTERNAL_ERROR);
}
if (!qatoi(parm, port))
{
logman("%s:server returned port that is not a number", mname);
free(wrd);
free(parm);
return(SL_INTERNAL_ERROR);
}
}
if (command_words(wrd) > 3)
if (ip_ad != (char *)NULL && !strlen(ip_ad))
if (!command_word(wrd, ip_ad, 4))
{
logman("%s:error getting ip address", mname);
free(wrd);
free(parm);
return(SL_INTERNAL_ERROR);
}
free(wrd);
free(parm);
logman("%s:normal exit[0]", mname);
return(SL_OK);
}
int sloc_ll_find_list(char *sname, char *hname, int *port, char *ip_ad,
char *list_out)
{
/* Find one or more 'socloc' entries. All parameters are optional
except 'list_out' which is the output list. The output list is
delimited by 'SL_LIST_DELIM' The lookup will use all supplied
parameters to perform the lookup. If you just want to find a list
of socket servers by service name, do not call this function,
use 'sloc_find_list' instead. Function returns
'SL_OK' upon success, a 'socloc' code otherwise. */
char mname[] = "sloc_ll_find_list";
char *parm, mes[128];
int ret;
logman("%s:enter", mname);
if (sname == (char *)NULL && hname == (char *)NULL && port == (int *)NULL
&& ip_ad == (char *)NULL)
{
logman("%s:all null parameters", mname);
return(SL_INVALID_PARAMETER);
}
if (list_out == (char *)NULL)
{
logman("%s:null[list_out]", mname);
return(SL_INVALID_PARAMETER);
}
/* use 'sconnect_build' to form the connect string */
if ((parm = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[parm]", mname);
return(SL_MEMORY_FAIL);
}
if ((ret = sconnect_build(sname, hname, port, ip_ad, parm))
!= SP_OK)
{
free(parm);
sp_code_string(ret, mes);
logman("%s:bad rc[%s] from sconnect_build", mname, mes);
return(SL_INVALID_PARAMETER);
}
logman("%s:parm=%s,l=%d", mname, parm, strlen(parm));
ret = sloc_sr_char(SL_SEND_FIND_LIST, parm, list_out);
logman("%s:reply list_out=%s,%d", mname, list_out,
strlen(list_out));
free(parm);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_get_list(char *list_out)
{
/* Get the 'socloc' list. The delimited list is
returned in 'list_out' which must already be allocated
by the caller to sufficient size. Function returns
'SL_OK' upon success, a 'socloc' code otherwise. */
char mname[] = "sloc_get_list";
int ret;
logman("%s:enter", mname);
if (list_out == (char *)NULL)
{
logman("%s:null[list_out]", mname);
return(SL_INVALID_PARAMETER);
}
ret = sloc_sr_char(SL_SEND_GET_LIST, (char *)NULL, list_out);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_put_list(char *list_in)
{
/* Put/write a 'socloc' list to a server. The delimited
list (delimited by 'SL_LIST_DELIM') is expected in
'list_in'. Function returns 'SL_OK' upon success,
a 'socloc' code otherwise. */
char mname[] = "sloc_put_list";
int ret;
logman("%s:enter", mname);
if (list_in == (char *)NULL || !strlen(list_in))
{
logman("%s:null or empty[list_in]", mname);
return(SL_INVALID_PARAMETER);
}
ret = sloc_sr_code(SL_SEND_PUT_LIST, list_in);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_config_update(void)
{
/* Get the current config list from the first active
'socloc' server and use this list to update the
config list in memory and write a new config file.
Function returns 'SL_OK' upon success, a 'socloc'
code otherwise. */
char mname[]= "sloc_config_update";
char *thelist;
int ret;
logman("%s:enter", mname);
if ((thelist = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[thelist]", mname);
return(SL_MEMORY_FAIL);
}
/* get the config list from the first active server */
if ((ret = sloc_config_get_list(thelist)) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_config_get_list", mname, ret);
free(thelist);
return(ret);
}
/* create a new list in memory */
if ((ret = sl_config_put_list(thelist)) != SL_OK)
{
logman("%s:bad rc[%d] from sl_config_put_list", mname, ret);
free(thelist);
return(ret);
}
free(thelist);
/* write this new list to the config file */
if ((ret = sl_config_write_file()) != SL_OK)
{
logman("%s:bad rc[%d] from sl_config_write_file", mname, ret);
return(ret);
}
logman("%s:normal exit[%d]", mname, ret);
return(SL_OK);
}
int sloc_config_get_list(char *list_out)
{
/* Get the 'socloc' config list. The delimited list is
returned in 'list_out' which must already be allocated
by the caller to sufficient size. Function returns
'SL_OK' upon success, a 'socloc' code otherwise. */
char mname[] = "sloc_config_get_list";
int ret;
logman("%s:enter", mname);
if (list_out == (char *)NULL)
{
logman("%s:null[list_out]", mname);
return(SL_INVALID_PARAMETER);
}
ret = sloc_sr_char(SL_SEND_CONFIG_GET_LIST, (char *)NULL, list_out);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_config_put_list(char *list_in)
{
/* Put/write a 'socloc' config list to a server. The delimited
list (delimited by 'SL_LIST_DELIM') is expected in
'list_in'. Function returns 'SL_OK' upon success,
a 'socloc' code otherwise. */
char mname[] = "sloc_config_put_list";
int ret;
logman("%s:enter", mname);
if (list_in == (char *)NULL || !strlen(list_in))
{
logman("%s:null[list_in]", mname);
return(SL_INVALID_PARAMETER);
}
ret = sloc_sr_code(SL_SEND_CONFIG_PUT_LIST, list_in);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_dump_debug(void)
{
/* Command server to display and log debug information.
Function returns 'SL_OK' upon success, an error code
otherwise. */
char mname[] = "sloc_dump_debug";
int ret;
logman("%s:enter,host=%s,port=%d", mname, sloc_hostname,
sloc_port);
ret = sloc_sr_code(SL_SEND_DUMP_DEBUG, (char *)NULL);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_config_dump_debug(void)
{
/* Command server to display and log config debug information.
Function returns 'SL_OK' upon success, an error code
otherwise. */
char mname[] = "sloc_config_dump_debug";
int ret;
logman("%s:enter,host=%s,port=%d", mname, sloc_hostname,
sloc_port);
ret = sloc_sr_code(SL_SEND_CONFIG_DUMP_DEBUG, (char *)NULL);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_terminate(char *passwd)
{
/* Terminate a 'socloc' server. Function returns 'SL_OK'
upon success, a 'socloc' code otherwise. */
char mname[] = "sloc_terminate";
int ret;
logman("%s:enter", mname);
if (passwd == (char *)NULL || !strlen(passwd))
{
logman("%s:null or empty[passwd]", mname);
return(SL_INVALID_PARAMETER);
}
ret = sloc_sr_code(SL_SEND_TERM, passwd);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
void sloc_get_active_socloc(char *hname, int *port)
{
/* Get and return the active 'socloc' server host name
and port number. 'hname' must be allocated by the
caller to sufficient size. */
char mname[] = "sloc_get_active_socloc";
if (hname == (char *)NULL || port == (int *)NULL)
{
logman("%s:exit:null[hname or port]", mname);
return;
}
hname[0] = EOS;
*port = 0;
if (!strlen(sloc_hostname) || sloc_port == 0)
{
logman("%s:no current socloc server", mname);
return;
}
strcpy(hname, sloc_hostname);
*port = sloc_port;
logman("%s:normal exit", mname);
}
int sloc_set_active_socloc(char *hname, int port)
{
/* Set the current active 'socloc' server. Connection is
tested and service name is verified. Function returns
a 'socloc' code. */
char mname[] = "sloc_set_active_socloc";
int ret;
logman("%s:enter", mname);
if (hname == (char *)NULL || !strlen(hname))
{
logman("%s:null or empty[hname]", mname);
return(SL_INVALID_PARAMETER);
}
if (port <= 0)
{
logman("%s:out of range[port]", mname);
return(SL_INVALID_PARAMETER);
}
if ((ret = sloc_connect(hname, port)) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_connect", mname, ret);
return(ret);
}
logman("%s:normal exit[0]", mname);
return(SL_OK);
}
int sloc_is_init(void)
{
/* Determine whether the 'socloc' API has been initialized.
The API is considered initialized when there is an active
host name in 'sloc_hostname' and a positive port number in
'sloc_port'. Function returns 'SL_OK' if the API has been
initialized, 'SL_NO_INIT' otherwise. */
char mname[] = "sloc_is_init";
int ret;
logman("%s:enter", mname);
if (!sloc_port || sloc_hostname == (char *)NULL || !strlen(sloc_hostname))
ret = SL_NO_INIT;
else
ret = SL_OK;
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_trans_num(long *transout)
{
/* Get the 'socloc' server transaction count.
Function returns 'SL_OK' upon success, a 'socloc'
code otherwise. */
char mname[] = "sloc_trans_num";
int ret;
logman("%s:enter", mname);
if (transout == (long *)NULL)
{
logman("%s:null[transout]", mname);
return(SL_INVALID_PARAMETER);
}
ret = sloc_sr_long(SL_SEND_TRANS_NUM, (char *)NULL, transout);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
int sloc_connect_num(int *connectout)
{
/* Get the 'socloc' server client connection count.
Function returns 'SL_OK' upon success, a 'socloc'
code otherwise. */
char mname[] = "sloc_connect_num";
int ret;
logman("%s:enter", mname);
if (connectout == (int *)NULL)
{
logman("%s:null[connectout]", mname);
return(SL_INVALID_PARAMETER);
}
ret = sloc_sr_int(SL_SEND_CONNECT_NUM, (char *)NULL, connectout);
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
void sloc_term_api(void)
{
/* Shutdown the API. Close the socket in use, wipe the globals
indicating the server host name and port and delete the
local 'socloc' config link list. */
char mname[] = "sloc_term_api";
logman("%s:enter", mname);
sloc_end();
sl_config_delete_all();
logman("%s:normal exit", mname);
}
/* private functions */
static int sloc_connect(char *hname, int port)
{
/* Attempt to connect to any 'socloc' server. Host name is
expected in 'hname' and TCP/IP port number is expected
in 'port'. Upon connection, the service name will be
verified. Upon success, the 'socloc' API
host name and port number will be set. Function returns a
'socloc' code. */
char mname[] = "sloc_connect";
char thname[128], sname[128];
int tport, ret;
logman("%s:enter", mname);
if (hname == (char *)NULL || !strlen(hname))
{
logman("%s:null or empty[hname]", mname);
return(SL_INVALID_PARAMETER);
}
if (port <= 0)
{
logman("%s:out of range[port]", mname);
return(SL_INVALID_PARAMETER);
}
/* save current connection values and terminate any existing connection */
strcpy(thname, sloc_hostname);
tport = sloc_port;
sloc_end();
/* load new values */
strcpy(sloc_hostname, hname);
sloc_port = port;
// attempt a connection
if ((ret = sloc_ll_client_connect()) != SL_OK)
{
// put host name and port back and re-connect to original server
sloc_end();
strcpy(sloc_hostname, thname);
sloc_port = tport;
(void)sloc_ll_client_connect();
logman("%s:bad rc[%d] from sloc_ll_client_connect", mname, ret);
return(ret);
}
// get and verify the service name
if ((ret = sloc_sr_char(SL_SEND_SERVICE_NAME, (char *)NULL, sname))
!= SL_OK)
{
sloc_end();
strcpy(sloc_hostname, thname);
sloc_port = tport;
(void)sloc_ll_client_connect();
logman("%s:bad rc[%d] from sloc_sr_char", mname, ret);
return(ret);
}
/* verify that this is a 'socloc' server */
if (strcmp(sname, SL_SERVICE_NAME))
{
sloc_end();
strcpy(sloc_hostname, thname);
sloc_port = tport;
(void)sloc_ll_client_connect();
logman("%s:not a socloc server", mname);
return(SL_NOT_A_SOCLOC_SERVER);
}
logman("%s:normal exit[0]", mname);
return(SL_OK);
}
static int sloc_sr_code(int typ, char *parm)
{
/* Send and receive a message to the 'socloc' server that
returns only a code. Function will failover to another
'socloc' server (if one available) upon a socket
communication error. Function returns a 'socloc' code. */
char mname[] = "sloc_sr_code";
int ret, done = FALSE;
// make sure there is an active connection
if ((ret = sloc_is_init()) != SL_OK)
{
logman("%s:no active connection", mname);
return(ret);
}
/* loop while there is a socket error and other 'socloc'
servers are available */
while(!done)
{
/* attempt to send command and receive reply */
ret = sloc_lsr_code(typ, parm);
logman("%s:sloc_lsr_code rc[%d]", mname, ret);
/* if a socket communication error, failover */
if (ret == SL_VC_ERROR)
{
logman("%s:server not responding,will failover", mname);
/* if failover failed, exit */
if ((ret = sloc_failover()) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_failover", mname, ret);
done = TRUE;
}
}
else
done = TRUE;
}
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
static int sloc_lsr_code(int typ, char *parm)
{
/* Send and recveive a message to the 'socloc' server that returns
only a return code. Its ok if 'parm' is NULL or empty.
Function returns a 'socloc' code. */
char mname[] = "sloc_sr_code", *mess;
int len, full_len, ret;
/* if init has not been called, exit error */
if ((ret = sloc_is_init()) != SL_OK)
{
logman("%s:no socloc server details", mname);
return(ret);
}
// estimate length and alloc send/receive buffer
len = (parm == (char *)NULL) ? 0 : strlen(parm);
full_len = len + 5;
if ((mess = (char *)malloc(full_len)) == (char *)NULL)
{
logman("%s:alloc fail[mess]", mname);
return(SL_MEMORY_FAIL);
}
memset(mess, 0, full_len);
// format send string
if (parm == (char *)NULL || !len)
sprintf(mess, "%d", typ);
else
sprintf(mess, "%d %s", typ, parm);
// send message
if (!ipc_send(slclientSocket, mess))
{
logman("%s:bad rc[FALSE] from ipc_send", mname);
free(mess);
return(SL_VC_ERROR);
}
memset(mess, 0, full_len);
// receive return code
if (!ipc_recv(slclientSocket, mess))
{
logman("%s:bad rc[FALSE] from ipc_recv", mname);
free(mess);
return(SL_VC_ERROR);
}
// make sure its a number
if (!qatoi(mess, &ret))
{
logman("%s:bad rc[FALSE] from qatoi[wrd 1]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
free(mess);
return(ret);
}
static int sloc_sr_char(int typ, char *parm, char *char_out)
{
/* Send and receive a message to the 'socloc' server that
returns a char string in addition to the reply code.
Function will failover to another
'socloc' server (if one available) upon a socket
communication error. Function returns a 'socloc' code. */
char mname[] = "sloc_sr_char";
int ret, done = FALSE;
// make sure there is an active connection
if ((ret = sloc_is_init()) != SL_OK)
{
logman("%s:no active connection", mname);
return(ret);
}
/* loop while there is a socket error and other 'socloc'
servers are available */
while(!done)
{
/* attempt to send command and receive reply */
ret = sloc_lsr_char(typ, parm, char_out);
logman("%s:sloc_lsr_char rc[%d]", mname, ret);
/* if a socket communication error, failover */
if (ret == SL_VC_ERROR)
{
logman("%s:server not responding,will failover", mname);
/* if failover failed, exit */
if ((ret = sloc_failover()) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_failover", mname, ret);
done = TRUE;
}
}
else
done = TRUE;
}
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
static int sloc_lsr_char(int typ, char *parm, char *char_out)
{
/* Send and recveive a message to the 'socloc' server that returns a
string as well as a return code. 'char_out' must already
be allocated to sufficient size for the receiving string.
Its ok if 'parm' is NULL or empty. Function returns a 'socloc' code. */
char mname[] = "sloc_sr_char", *mess, tmp[50];
int len, full_len, nwords, pos, ret;
/* if init has not been called, exit error */
if ((ret = sloc_is_init()) != SL_OK)
{
logman("%s:no socloc server details", mname);
return(ret);
}
char_out[0] = EOS;
// estimate length and alloc send/receive buffer
len = (parm == (char *)NULL) ? 0 : strlen(parm);
full_len = len + 5;
if ((mess = (char *)malloc(full_len)) == (char *)NULL)
{
logman("%s:alloc fail[mess]", mname);
return(SL_MEMORY_FAIL);
}
memset(mess, 0, full_len);
// format send string
if (parm == (char *)NULL || !len)
sprintf(mess, "%d", typ);
else
sprintf(mess, "%d %s", typ, parm);
// send message
if (!ipc_send(slclientSocket, mess))
{
logman("%s:bad rc[FALSE] from ipc_send", mname);
free(mess);
return(SL_VC_ERROR);
}
free(mess);
// re-allocate 'mess' for receive buffer (max size)
if ((mess = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[mess]", mname);
return(SL_MEMORY_FAIL);
}
memset(mess, 0, SL_MAXCOMMAND);
// receive reply
if (!ipc_recv(slclientSocket, mess))
{
logman("%s:bad rc[FALSE] from ipc_recv", mname);
free(mess);
return(SL_VC_ERROR);
}
// s/b two words in reply
nwords = command_words(mess);
// s/b reply code in word one
if (!command_word(mess, tmp, 1))
{
logman("%s:bad rc[FALSE] from command_word[1]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
// make sure its a number
if (!qatoi(tmp, &ret))
{
logman("%s:bad rc[FALSE] from qatoi[wrd 1]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
// if reply is 'ok', load 'char_out'
if (ret == SL_OK)
{
if (nwords < 2)
{
logman("%s:expecting at least two words in reply", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
// 'char_value' is from the end of the first word
if ((pos = command_indxword(mess, 2)) == -1)
{
logman("%s:bad rc[-1] from command_indxword[2]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
/* if second command word starts with quote backup one */
if (mess[pos - 1] == '\'' || mess[pos - 1] == '"')
pos -= 1;
len = strlen(mess) - pos;
strncpy(char_out, &mess[pos], len);
char_out[len] = EOS;
}
free(mess);
return(ret);
}
static int sloc_sr_int(int typ, char *parm, int *intout)
{
/* Send and receive a message to the 'socloc' server that
returns an integer in addition to the reply code.
Function will failover to another
'socloc' server (if one available) upon a socket
communication error. Function returns a 'socloc' code. */
char mname[] = "sloc_sr_int";
int ret, done = FALSE;
// make sure there is an active connection
if ((ret = sloc_is_init()) != SL_OK)
{
logman("%s:no active connection", mname);
return(ret);
}
/* loop while there is a socket error and other 'socloc'
servers are available */
while(!done)
{
/* attempt to send command and receive reply */
ret = sloc_lsr_int(typ, parm, intout);
logman("%s:sloc_lsr_int rc[%d]", mname, ret);
/* if a socket communication error, failover */
if (ret == SL_VC_ERROR)
{
logman("%s:server not responding,will failover", mname);
/* if failover failed, exit */
if ((ret = sloc_failover()) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_failover", mname, ret);
done = TRUE;
}
}
else
done = TRUE;
}
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
static int sloc_lsr_int(int typ, char *parm, int *intout)
{
/* Send and recveive a message to the 'socloc' server that returns an
integer as well as a return code. Its ok if 'parm' is NULL or empty.
Function returns a 'socloc' code. */
char mname[] = "sloc_lsr_int", *mess, tmp[50];
int len, full_len, nwords, pos, ret;
/* if init has not been called, exit error */
if ((ret = sloc_is_init()) != SL_OK)
{
logman("%s:no socloc server details", mname);
return(ret);
}
*intout = 0;
// estimate length and alloc send/receive buffer
len = (parm == (char *)NULL) ? 0 : strlen(parm);
full_len = len + 5;
if ((mess = (char *)malloc(full_len)) == (char *)NULL)
{
logman("%s:alloc fail[mess]", mname);
return(SL_MEMORY_FAIL);
}
memset(mess, 0, full_len);
// format send string
if (parm == (char *)NULL || !len)
sprintf(mess, "%d", typ);
else
sprintf(mess, "%d %s", typ, parm);
// send message
if (!ipc_send(slclientSocket, mess))
{
logman("%s:bad rc[FALSE] from ipc_send", mname);
free(mess);
return(SL_VC_ERROR);
}
free(mess);
// re-allocate 'mess' for receive buffer (max size)
if ((mess = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[mess]", mname);
return(SL_MEMORY_FAIL);
}
memset(mess, 0, SL_MAXCOMMAND);
// receive reply
if (!ipc_recv(slclientSocket, mess))
{
logman("%s:bad rc[FALSE] from ipc_recv", mname);
free(mess);
return(SL_VC_ERROR);
}
// s/b two words in reply
nwords = words(mess);
// s/b reply code in word one
if (!word(mess, tmp, 1))
{
logman("%s:bad rc[FALSE] from word[1]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
// make sure its a number
if (!qatoi(tmp, &ret))
{
logman("%s:bad rc[FALSE] from qatoi[wrd 1]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
// if reply is 'ok', load 'intout'
if (ret == SL_OK)
{
if (nwords < 2)
{
logman("%s:expecting at least two words in reply", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
if (!word(mess, tmp, 2))
{
logman("%s:bad rc[FALSE] from word[2]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
if (!qatoi(tmp, intout))
{
logman("%s:bad rc[FALSE] from qatoi[wrd 2]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
}
free(mess);
return(ret);
}
static int sloc_sr_long(int typ, char *parm, long *longout)
{
/* Send and receive a message to the 'socloc' server that
returns a long integer in addition to the reply code.
Function will failover to another
'socloc' server (if one available) upon a socket
communication error. Function returns a 'socloc' code. */
char mname[] = "sloc_sr_long";
int ret, done = FALSE;
// make sure there is an active connection
if ((ret = sloc_is_init()) != SL_OK)
{
logman("%s:no active connection", mname);
return(ret);
}
/* loop while there is a socket error and other 'socloc'
servers are available */
while(!done)
{
/* attempt to send command and receive reply */
ret = sloc_lsr_long(typ, parm, longout);
logman("%s:sloc_lsr_long rc[%d]", mname, ret);
/* if a socket communication error, failover */
if (ret == SL_VC_ERROR)
{
logman("%s:server not responding,will failover", mname);
/* if failover failed, exit */
if ((ret = sloc_failover()) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_failover", mname, ret);
done = TRUE;
}
}
else
done = TRUE;
}
logman("%s:normal exit[%d]", mname, ret);
return(ret);
}
static int sloc_lsr_long(int typ, char *parm, long *longout)
{
/* Send and recveive a message to the 'socloc' server that returns a
long integer as well as a return code. Its ok if 'parm' is NULL or empty.
Function returns a 'socloc' code. */
char mname[] = "sloc_lsr_long", *mess, tmp[50];
int len, full_len, nwords, pos, ret;
/* if init has not been called, exit error */
if ((ret = sloc_is_init()) != SL_OK)
{
logman("%s:no socloc server details", mname);
return(ret);
}
*longout = 0L;
// estimate length and alloc send/receive buffer
len = (parm == (char *)NULL) ? 0 : strlen(parm);
full_len = len + 5;
if ((mess = (char *)malloc(full_len)) == (char *)NULL)
{
logman("%s:alloc fail[mess]", mname);
return(SL_MEMORY_FAIL);
}
memset(mess, 0, full_len);
// format send string
if (parm == (char *)NULL || !len)
sprintf(mess, "%d", typ);
else
sprintf(mess, "%d %s", typ, parm);
// send message
if (!ipc_send(slclientSocket, mess))
{
logman("%s:bad rc[FALSE] from ipc_send", mname);
free(mess);
return(SL_VC_ERROR);
}
free(mess);
// re-allocate 'mess' for receive buffer (max size)
if ((mess = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[mess]", mname);
return(SL_MEMORY_FAIL);
}
memset(mess, 0, SL_MAXCOMMAND);
// receive reply
if (!ipc_recv(slclientSocket, mess))
{
logman("%s:bad rc[FALSE] from ipc_recv", mname);
free(mess);
return(SL_VC_ERROR);
}
// s/b two words in reply
nwords = words(mess);
// s/b reply code in word one
if (!word(mess, tmp, 1))
{
logman("%s:bad rc[FALSE] from word[1]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
// make sure its a number
if (!qatoi(tmp, &ret))
{
logman("%s:bad rc[FALSE] from qatoi[wrd 1]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
// if reply is 'ok', load 'longout'
if (ret == SL_OK)
{
if (nwords < 2)
{
logman("%s:expecting at least two words in reply", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
if (!word(mess, tmp, 2))
{
logman("%s:bad rc[FALSE] from word[2]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
if (!qatol(tmp, longout))
{
logman("%s:bad rc[FALSE] from qatol[wrd 2]", mname);
free(mess);
return(SL_INTERNAL_ERROR);
}
}
free(mess);
return(ret);
}
static int sloc_failover(void)
{
/* Failover to another 'socloc' server (if one is available).
Function returns a 'socloc' code. */
char mname[] = "sloc_failover";
int ret;
logman("%s:enter:port=%d", mname, sloc_port);
// delete the current entry from the local config link list
if ((ret = sl_config_delete(sloc_port)) != SL_OK)
{
logman("%s:bad rc[%d] from sl_config_delete", mname, ret);
return(ret);
}
// attempt to connect to the first available 'socloc' server
if ((ret = sloc_client_connect()) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_client_connect", mname, ret);
return(ret);
}
logman("%s:normal exit[0]:port=%d", mname, sloc_port);
return(SL_OK);
}
static int sloc_reload_config_list(void)
{
/* Get a fresh copy of the socloc config list
from the current 'socloc' server and place into
memory. Function returns a 'socloc' code. */
char mname[] = "sloc_reload_config_list";
char *thelist;
int ret;
logman("%s:enter", mname);
if ((thelist = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[thelist]", mname);
return(SL_MEMORY_FAIL);
}
// get the config list from the current 'socloc' server
if ((ret = sloc_config_get_list(thelist)) != SL_OK)
{
logman("%s:bad rc[%d] from sloc_config_get_list", mname, ret);
free(thelist);
return(ret);
}
// create a new list in memory
if ((ret = sl_config_put_list(thelist)) != SL_OK)
{
logman("%s:bad rc[%d] from sl_config_put_list", mname, ret);
free(thelist);
return(ret);
}
free(thelist);
logman("%s:normal exit[0]", mname);
return(SL_OK);
}
static int sloc_client_connect(void)
{
/* Attempt to connect to a 'socloc' server. The host name
and port number should have already been initialized by
calling 'sloc_initialize'. If the initialization routine
has not been called, it is an error. If the current 'socloc'
server has been found to be not responding, another
'socloc' server will attempt to be found. Function
returns 'SL_OK' if a connection was made to any
'socloc' server, a 'socloc' code otherwise. */
char mname[] = "sloc_client_connect";
int ret;
logman("%s:enter,sloc_hostname=%s,sloc_port=%d", mname,
sloc_hostname, sloc_port);
// if there is an active connection, close it
if ((ret = sloc_is_init()) == SL_OK)
{
logman("%s:active connection found,closing it", mname, ret);
sloc_end();
}
/* loop which attempts to connect to currently listed
'socloc' server, if this fails, get next active and
try */
while(1)
{
// get top entry in config link list
if ((ret = sl_config_get_first(sloc_hostname, &sloc_port,
(char *)NULL)) != SL_OK)
{
logman("%s:bad rc[%d] from sl_config_get_first", mname, ret);
return(ret);
}
// open the socket and attempt a connection
if ((ret = sloc_ll_client_connect()) == SL_OK)
{
/* if connection was successful, get a new copy
of the config link list from the server and
place it into memory */
(void)sloc_reload_config_list();
logman("%s:exit[0],connected to server %s", mname,
sloc_hostname);
return(ret);
}
logman("%s:server %s not responding,rc=%d", mname,
sloc_hostname, ret);
// delete the current entry
if ((ret = sl_config_delete(sloc_port)) != SL_OK)
{
logman("%s:bad rc[%d] from sl_config_delete", mname, ret);
return(ret);
}
/* wipe out current host name and port */
sloc_hostname[0] = EOS;
sloc_port = 0;
}
/* we should never get here, but just in case */
logman("%s:unanticipated wacky exit SL_NO_SUCH_SOCLOC", mname);
return(SL_NO_SUCH_SOCLOC);
}
static int sloc_ll_client_connect(void)
{
/* Connect to the 'socloc' server. An attempt to open the TCP
socket is made. The host name 'sloc_hostname' and the
TCP port 'sloc_port' are assumed to be already loaded
via 'sloc_initialize'. Function returns 'SL_OK' if a
successful connection was made, a 'socloc' code otherwise.
Private function. */
int ret;
// make sure host name and port are loaded
if ((ret = sloc_is_init()) != SL_OK)
return(ret);
// resolve server host name
lpHostEnt = gethostbyname(sloc_hostname);
if (!lpHostEnt)
return(SL_VC_ERROR);
// create the socket
#ifdef OS_WIN32
slclientSocket = socket(PF_INET, SOCK_STREAM, DEFAULT_PROTOCOL);
#endif
#ifdef OS_UNIX
slclientSocket = socket(AF_INET, SOCK_STREAM, DEFAULT_PROTOCOL);
#endif
if (slclientSocket == INVALID_SOCKET)
return(SL_VC_ERROR);
// load client address data
memset(&slsockClientAddr, 0, sizeof(slsockClientAddr));
slsockClientAddr.sin_family = AF_INET;
slsockClientAddr.sin_port = htons(sloc_port);
#ifdef OS_WIN32
slsockClientAddr.sin_addr = *((LPIN_ADDR)*lpHostEnt->h_addr_list);
#endif
#ifdef OS_UNIX
slsockClientAddr.sin_addr.s_addr = ((struct in_addr *)(lpHostEnt->h_addr))->s_addr;
#endif
// connect to server
#ifdef OS_WIN32
if (connect(slclientSocket, (LPSOCKADDR)&slsockClientAddr,
sizeof(slsockClientAddr)))
#endif
#ifdef OS_UNIX
if (connect(slclientSocket, (SA *)&slsockClientAddr,
sizeof(slsockClientAddr)) == SOCKET_ERROR)
#endif
return(SL_VC_ERROR);
return(SL_OK);
}