/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- main
- parse_comline
- srv_initialize
- process_request
- do_comm
- s_log_off
- s_log_on
- s_log_status
- s_add
- s_delete
- s_config_add
- s_config_delete
- s_find
- s_config_find
- s_find_list
- s_get_list
- s_put_list
- s_config_get_list
- s_config_put_list
- s_terminate
- s_trans_num
- s_connect_num
- do_reply_int
- do_reply_long
- do_reply_code
- do_reply_char
- s_ll_put_list
- s_ll_get_first
- s_ll_get_nentries
- s_ll_get_nth
- s_ll_add
- s_ll_port_exist
- s_ll_delete
- s_ll_delete_all
- s_ll_debug
- s_config_debug
- term_app
/* socloc - A socket locate server. This TCP connection oriented
iterative socket server will register the name, port and IP
address of other socket servers. Client applications can then
easily find the host name, port and IP address of these socket
servers. Rick Smereka, Copyright (C) 2000-2006.
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 socket locate server maintains two singly linked lists. One
(called the config list) is the list of currently available
socket locate servers. The other is a list of currently
available socket servers. All additions and deletions (of
both lists) are populated to all known 'socloc' servers giving
automatic dynamic 'failover' protection.
You can have as many 'socloc' servers running as you like. The only
limitations are that each 'socloc' server must occupy a unique
TCP port and not more than one 'socloc' server can be running
on each host machine. You may also have as many socket servers
running as you desire. Each socket server is identified by a
'service name'. You may seach just by service name (in which
case, the first entry with the same service name will match).
You may also qualify the search with a host name, TCP port
or the IP address. Throughout 'socloc', the IP
address is completly optional. The only limitation is that each
socket server must be occupy a unique TCP port. You may
even have multiple socket servers with the same 'service
name' running on the same host machine.
Note that this socket server (unlike my other socket servers)
does not use the 'sys_log' system logging server. This
is due to the fact that it is assumed that this server is the
first one started and 'sys_log' will not be running. This server
logs all information into the private log file 'SL_LOG_FILE' by
default.
Original Windows 32bit version under CodeWarrior V4. Feb/2000,
Rick Smereka
Modified to have server log status query return the name of the
current log file if active. Mar/2000, Rick Smereka
Re-compiled after re-structuring the definition of the common
send and repy codes. Added '-l' command line option to specify
the output log file and '-q' quiet command line option to
supress console output. Program syntax now is:
socloc [-q] [-l log_file]
Apr/2000, Rick Smereka
Modified function 'srv_initialize' to obtain the local machine
IP address and pass this to 'sloc_bcast_config_add'. Changed
function 'do_comm' to send a reply code when encountering a
send code that is out of range. Jul/2000, Rick Smereka
Re-compiled based on new version of 'socloc' API.
Jul/2001, Rick Smereka
Fixed bug in 's_ll_put_list' which called 'log_file_date' with an
improper number of parameters. Feb/2002, Rick Smereka
Fixed bug in 's_find' that incorrectly calculated the length of the
reply string. Mar/2002, Rick Smereka
Coded to use the 'appinit' API. May/2002, Rick Smereka
Ported to Debian Linux. Jan/2003, Rick Smereka
Changed to in accordance with the modifications in 'ipcsrv.c'.
Changed the method that this server uses to talk to other
socloc and socket servers. This server now uses the
'slocsrv' API. May/2003, Rick Smereka
Added function 'term_app' to perform server shutdown.
Jun/2003, Rick Smereka
Code cleanup. Dec/2004, Rick Smereka
Re-compile after modifications to low level TCP socket communication
module (ipcomm.c). Feb/2006, Rick Smereka */
#include "stdhead.h"
#include "flsocket.h" /* generic socket definitions */
#include "socloc.h" /* socket locate defines */
#include "slconfig.h" /* socket locate config management */
#include "ipcsrv.h" /* TCP server routines */
#include "ip.h" /* IP library routines */
#include "slocsrv.h" /* client API for socloc server */
#include "sconnect.h" /* 'sconnect' parse functions */
#include "appinit.h" /* app init API */
#define VERSION "1.08.01-2006.02.23" /* version ID */
#define SL_TERM_PASSWD "rdsWin32" /* terminate server password */
#define SL_LOG_FILE "socloc.log" /* default log file name */
/* WinSock specific global data structure */
#ifdef OS_WIN32
WSADATA wsaData; /* struct used by 'WSAStartup()' */
#endif
/* global data */
int server_port = 0; /* TCP port that server is using */
int console_output = TRUE; /* echo messages to console? */
char s_log_file[128]; /* current log file */
struct sloc_entry /* link list of socket servers */
{
char *service_name; /* name of socket service */
char *host_name; /* machine host name */
int port_number; /* port that is being serviced */
char *ip_addr; /* IP address (might be null) */
struct sloc_entry *next; /* next link */
};
struct sloc_entry *sloc_base; /* root/base node pointer */
#define SLOC_NULL ((struct sloc_entry *)NULL)
/* function prototypes */
int main(int, char **);
int parse_comline(int, char **);
int srv_initialize(void);
int process_request(void);
int do_comm(int, char *);
void s_log_off(void);
void s_log_on(char *);
void s_log_status(void);
void s_add(char *);
void s_delete(char *);
void s_config_add(char *);
void s_config_delete(char *);
void s_find(char *);
void s_config_find(char *);
void s_find_list(char *);
void s_get_list(void);
void s_put_list(char *);
void s_config_get_list(void);
void s_config_put_list(char *);
int s_terminate(char *);
void s_trans_num(void);
void s_connect_num(void);
int do_reply_int(int, int);
int do_reply_long(int, long);
int do_reply_code(int);
int do_reply_char(int, char *char_value);
int s_ll_put_list(char *);
int s_ll_get_first(char *, char *, int *, char *);
int s_ll_get_nentries(int *);
int s_ll_get_nth(int, char *, char *, int *, char *);
int s_ll_add(char *, char *, int, char *);
int s_ll_port_exist(int);
int s_ll_delete(int);
void s_ll_delete_all(void);
void s_ll_debug(void);
void s_config_debug(void);
void term_app(void);
int main(int argc, char **argv)
{
char localHost[128];
int isterm;
/* indicate initialization in progress */
if (!appinit_start(SL_SERVICE_NAME))
{
printf("%s:error creating appinit lock file. Program abort\n",
SL_SERVICE_NAME);
return(0);
}
/* set default log file name */
strcpy(s_log_file, SL_LOG_FILE);
/* parse any command line parameters */
if (argc > 1)
if (!parse_comline(argc, argv))
{
(void)appinit_stop(SL_SERVICE_NAME);
return(0);
}
/* initialize private logging */
if (!log_start(s_log_file))
{
printf("%s:error initializing log file. Program abort\n",
SL_SERVICE_NAME);
(void)appinit_stop(SL_SERVICE_NAME);
return(0);
}
/* set logger console output flag */
log_console(console_output);
/* build logo string based on platform */
#ifndef OS_UNIX
/* non-Unix */
log_file_date("%s Socket Locate Server for %s Version %s",
SL_SERVICE_NAME, PLATFORM_STRING, VERSION);
#else
/* Unix */
log_file_date("%s Socket Locate Server for %s Version %s",
SL_SERVICE_NAME, SUB_PLATFORM_STRING,VERSION);
#endif
log_file_date("By Rick Smereka, Copyright (c) 2000-2006");
/* read IPC config file and validate other 'socloc' servers
(if any) */
if (!srv_initialize())
{
(void)appinit_stop(SL_SERVICE_NAME);
term_app();
return(4);
}
/* initialize the server on the TCP socket level, note that
the hostname 'localhost' is returned to us */
if (!ipc_init(localHost, server_port))
{
(void)appinit_stop(SL_SERVICE_NAME);
term_app();
return(6);
}
log_file_date("%s:server on \"%s\" servicing TCP port %d (decimal)",
SL_SERVICE_NAME, localHost, server_port);
log_file_date("%s:socket locate server started", SL_SERVICE_NAME);
log_file_date("%s comes with ABSOLUTELY NO WARRANTY", SL_SERVICE_NAME);
log_file_date("This is free software, and you are welcome to redistribute it");
log_file_date("under certain conditions; see \"gpl.txt\" for information.");
/* turn off log as this is used only for debugging */
//log_end();
/* indicate initialization complete */
(void)appinit_stop(SL_SERVICE_NAME);
// 'ipc_server_wait' is an infinite loop
ipc_server_wait();
term_app();
return(0);
}
int parse_comline(int c_count, char **c_parm)
{
/* Parse the command line for parameters. Function
returns 'TRUE' if no error was detected, 'FALSE'
otherwise. */
int parms = 1, done = FALSE;
while(!done)
{
if (c_parm[parms][0] == SWITCH_CHAR)
{
switch(toupper(c_parm[parms][1]))
{
case 'L':
if (strlen(c_parm[parms]) > 2)
printf("%s:extraneous input with log file switch, "
"ignoring\n", SL_SERVICE_NAME);
parms++;
if (parms >= c_count)
{
printf("%s:log file switch with no file name, "
"program abort\n", SL_SERVICE_NAME);
return(FALSE);
}
strcpy(s_log_file, c_parm[parms]);
parms++;
break;
case 'Q':
console_output = FALSE;
parms++;
break;
default:
printf("%s:unknown switch[%s], program abort\n",
SL_SERVICE_NAME, c_parm[parms]);
return(FALSE);
};
}
else
{
printf("%s:unknown parameter[%s], program abort\n",
SL_SERVICE_NAME, c_parm[parms]);
return(FALSE);
}
if (parms >= c_count)
done = TRUE;
}
return(TRUE);
}
int srv_initialize(void)
{
/* Initialize the server by reading the list of socket
locate servers and making sure there is an entry
for this server. Function returns 'TRUE' upon
success, 'FALSE' otherwise. */
char mname[] = "srv_initialize";
char localhost[128], mes[128], hname[128], ip_ad[50];
char *thelist;
int i, ret, nentries, port_num;
log_file_date("%s:enter", mname);
/* load list of socket locate servers */
if ((ret = sl_config_read(SL_CONFIG_FILE_NAME)) != SL_OK)
{
sl_code_string(ret, mes);
log_file_date("%s:error reading socket locate "
"server list,rc=%s. Program abort", mname, mes);
return(FALSE);
}
/* startup WinSock (if Windoze) */
#ifdef OS_WIN32
if (WSAStartup(WINSOCK_VERSION, &wsaData))
{
log_file_date("%s:unable to start WinSock, "
"program abort", mname);
return(FALSE);
}
#endif
/* get host name of this machine */
if (gethostname(localhost, 127))
{
log_file_date("%s:unable to resolve local "
"host name. Program abort", mname);
return(FALSE);
}
log_file_date("%s:host name is '%s'", mname, localhost);
/* get the number of socket locate servers from config file */
if ((ret = sl_config_get_nentries(&nentries)) != SL_OK)
{
sl_code_string(ret, mes);
log_file_date("%s:error getting number of "
"socket locate servers. Program "
"abort,rc=%s", mname, mes);
return(FALSE);
}
log_file_date("%s:number of config entries is %d", mname, nentries);
/* go through the list looking for a host name match */
for(i = 1; i <= nentries; i++)
{
if ((ret = sl_config_get_nth(i, hname, &port_num, ip_ad)) != SL_OK)
{
sl_code_string(ret, mes);
log_file_date("%s:error socket locate server "
"entry #%d. Program abort,rc=%s", mname, i, mes);
return(FALSE);
}
/* if the host name matches, load the port number used */
if (!strcmp(hname, localhost))
server_port = port_num;
}
/* if all socket locate servers were checked and no host
name match, error */
if (server_port == 0)
{
log_file_date("%s:no matching host name found in '%s'. "
"Program abort.", mname,
SL_CONFIG_FILE_NAME);
return(FALSE);
}
/* tell config API that this is the local server */
if ((ret = sl_config_set_ils(server_port, TRUE)) != SL_OK)
{
sl_code_string(ret, mes);
log_file_date("%s:bad rc from 'sl_config_set_ils',rc=%s",
mname, mes);
return(FALSE);
}
sloc_base = SLOC_NULL;
/* use 'socloc' client API to find first active 'socloc' server
its okay if there are no other 'socloc' servers present */
if ((ret = sloc_find_first_active()) != SL_OK)
{
sl_code_string(ret, mes);
log_file_date("%s:no other active 'socloc' servers,rc=%s",
mname, mes);
}
else
{
/* when other 'socloc' servers are present, don't trust their
'ipc' config files, send a config add command to each active
'socloc' server then update this server's 'ipc' config file
and list from the current active 'socloc' server, re-set
the 'is_local_server' flag for this server and finally,
get and load the current socket server list */
log_file_date("%s:found other active 'socloc' servers", mname);
/* get this machine IP address */
if (!ip_host2ip(localhost, ip_ad))
{
log_file_date("%s:unable to obtain this machine IP address",
mname);
return(FALSE);
}
(void)sloc_bcast_config_add(localhost, server_port, ip_ad);
/* commented out the update of the config file after noticing
some cases of the config file being updated from a
more incomplete version */
/* if ((ret = sloc_config_update()) != SL_OK)
{
sl_code_string(ret, mes);
log_file_date("%s:bad rc from 'sloc_config_update',rc=%s",
mname, mes);
return(FALSE);
} */
if ((thelist = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[thelist]", mname);
return(FALSE);
}
/* get the config list from the first active server */
if ((ret = sloc_config_get_list(thelist)) != SL_OK)
{
log_file_date("%s:bad rc[%d] from 'sloc_config_get_list'",
mname, ret);
free(thelist);
return(FALSE);
}
/* create a new list in memory */
if ((ret = sl_config_put_list(thelist)) != SL_OK)
{
log_file_date("%s:bad rc[%d] from 'sl_config_put_list'",
mname, ret);
free(thelist);
return(FALSE);
}
if ((ret = sl_config_set_ils(server_port, TRUE)) != SL_OK)
{
sl_code_string(ret, mes);
log_file_date("%s:bad rc from 'sl_config_set_ils',rc=%s",
mname, mes);
return(FALSE);
}
/* if list is empty, that's ok */
if ((ret = sloc_get_list(thelist)) != SL_OK)
if (ret == SL_NOT_FOUND)
log_file_date("%s:socket server list is empty", mname);
else
{
free(thelist);
sl_code_string(ret, mes);
log_file_date("%s:bad rc[%s] from 'sloc_get_list'", mname, mes);
return(FALSE);
}
if (ret == SL_OK)
if ((ret = s_ll_put_list(thelist)) != SL_OK)
{
free(thelist);
sl_code_string(ret, mes);
log_file_date("%s:bad rc[%s] from 's_ll_put_list'", mname, mes);
return(FALSE);
}
free(thelist);
}
sl_config_debug();
s_ll_debug();
log_file_date("%s:normal exit[TRUE]", mname);
return(TRUE);
}
int process_request(void)
{
/* Process a single request. Function returns 'FALSE' if
termination signal was not encountered, 'TRUE'
otherwise. */
char mname[] = "process_request";
char *messbuf, tmp[128];
int ret, nbytes, nwords, mestype;
log_file_date("%s:enter", mname);
if ((messbuf = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
(void)do_reply_code(SL_MEMORY_FAIL);
log_file_date("%s:alloc fail[messbuf]", mname);
return(FALSE);
}
memset(messbuf, 0, SL_MAXCOMMAND);
// get the message from the client
if ((nbytes = ipc_recv_data(messbuf)) == 0)
{
free(messbuf);
log_file_date("%s:connection closed by client", mname);
return(-1);
}
messbuf[nbytes] = EOS;
log_file_date("%s:recv %s,l=%d", mname, messbuf, strlen(messbuf));
nwords = command_words(messbuf);
// no command words, empty string
if (!nwords)
{
(void)do_reply_code(SL_INVALID_FUNCTION);
free(messbuf);
log_file_date("%s:empty command", mname);
return(FALSE);
}
// first command word must be a number
if (!command_word(messbuf, tmp, 1))
{
free(messbuf);
(void)do_reply_code(SL_INTERNAL_ERROR);
log_file_date("%s:error getting first command word", mname);
return(FALSE);
}
if (!qatoi(tmp, &mestype))
{
(void)do_reply_code(SL_INVALID_FUNCTION);
log_file_date("%s:command signature not a number", mname);
free(messbuf);
return(FALSE);
}
/* pass entire string including command number */
ret = do_comm(mestype, messbuf);
free(messbuf);
log_file_date("%s:normal exit,rc=%d", mname, ret);
return(ret);
}
int do_comm(int mestype, char *slm)
{
/* High level server command dispatcher.
Function returns 'TRUE' if a terminate
request was encountered, 'FALSE'
otherwise. */
char mname[] = "do_comm";
int ret;
log_file_date("%s:enter", mname);
ret = FALSE;
switch(mestype)
{
case SL_SEND_ADD:
s_add(slm);
break;
case SL_SEND_DELETE:
s_delete(slm);
break;
case SL_SEND_CONFIG_ADD:
s_config_add(slm);
break;
case SL_SEND_CONFIG_DELETE:
s_config_delete(slm);
break;
case SL_SEND_FIND:
s_find(slm);
break;
case SL_SEND_CONFIG_FIND:
s_config_find(slm);
break;
case SL_SEND_FIND_LIST:
s_find_list(slm);
break;
case SL_SEND_GET_LIST:
s_get_list();
break;
case SL_SEND_PUT_LIST:
s_put_list(slm);
break;
case SL_SEND_CONFIG_GET_LIST:
s_config_get_list();
break;
case SL_SEND_CONFIG_PUT_LIST:
s_config_put_list(slm);
break;
case SL_SEND_STATUS:
(void)do_reply_code(SL_OK);
break;
case SL_SEND_LOG_OFF:
s_log_off();
break;
case SL_SEND_LOG_ON:
s_log_on(slm);
break;
case SL_SEND_LOG_STATUS:
s_log_status();
break;
case SL_SEND_SERVICE_NAME:
(void)do_reply_char(SL_OK, SL_SERVICE_NAME);
break;
case SL_SEND_VERSION:
(void)do_reply_char(SL_OK, VERSION);
break;
case SL_SEND_DUMP_DEBUG:
s_ll_debug();
(void)do_reply_code(SL_OK);
break;
case SL_SEND_CONFIG_DUMP_DEBUG:
s_config_debug();
(void)do_reply_code(SL_OK);
break;
case SL_SEND_TRANS_NUM:
s_trans_num();
break;
case SL_SEND_CONNECT_NUM:
s_connect_num();
break;
case SL_SEND_TERM:
if (s_terminate(slm))
ret = TRUE;
break;
default:
log_file_date("%s:received unknown code=%d", mname, mestype);
(void)do_reply_code(SL_INVALID_FUNCTION);
break;
};
log_file_date("%s:exit[%d]", mname, ret);
return(ret);
}
void s_log_off(void)
{
/* Turn all loggging off. Of course, check for logging
already off. */
char mname[] = "s_log_off";
int ret;
log_file_date("%s:enter", mname);
if (!is_log_active())
ret = SL_LOG_ALREADY_OFF;
else
{
log_end();
ret = SL_OK;
}
(void)do_reply_code(ret);
log_file_date("%s:normal exit rc[%d]", mname, ret);
}
void s_log_on(char *comm)
{
/* Turn server logging on using either the supplied log file name
or the global log file name. Of course, check for logging
already on. */
char mname[] = "s_log_on";
int ret;
log_file_date("%s:enter", mname);
if (is_log_active())
ret = SL_LOG_ALREADY_ON;
else
{
if (command_words(comm) > 1)
if (!command_word(comm, s_log_file, 2))
{
log_file_date("%s:error getting log file name", mname);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!log_start(s_log_file))
{
(void)do_reply_code(SL_LOG_ERROR);
log_file_date("%s:error starting log", mname);
return;
}
ret = SL_OK;
}
(void)do_reply_code(ret);
log_file_date("%s:normal exit rc[%d]", mname, ret);
}
void s_log_status(void)
{
/* Get the current log status (on or off) along with the
current log file name. */
char mname[] = "s_log_status";
char reply[128];
log_file_date("%s:enter", mname);
if (is_log_active())
{
if (words(s_log_file) > 1)
sprintf(reply, "1 '%s'", s_log_file);
else
sprintf(reply, "1 %s", s_log_file);
(void)do_reply_char(SL_OK, reply);
}
else
{
if (words(s_log_file) > 1)
sprintf(reply, "0 '%s'", s_log_file);
else
sprintf(reply, "0 %s", s_log_file);
(void)do_reply_char(SL_OK, reply);
}
log_file_date("%s:normal exit rc[0],reply=%s", mname, reply);
}
void s_add(char *comm)
{
/* Add an entry to the list of available socket servers.
Syntax:
SL_SEND_ADD orig_flag service_name host_name port_number[ ip_addr]
Where 'orig_flag' indicates the origin (0=server,1=client).
If the origin is the client, a broadcast will be sent to
all other known 'socloc' servers. Line will be parsed with
'command_word' functions so any parameter with a space must
be quoted. */
char mname[] = "s_add";
char *sname, *hname, *port_char, *ip_ad;
char orig_flag_char[25], mess[150];
int orig_flag, port, len, ret, sockrc;
log_file_date("%s:enter", mname);
/* must be at least 5 command words */
if (command_words(comm) < 5)
{
log_file_date("%s:incorrect number of parameters", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* get 'orig_flag' */
if (!command_word(comm, orig_flag_char, 2))
{
log_file_date("%s:parse error[orig_flag_char]", mname);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!qatoi(orig_flag_char, &orig_flag))
{
log_file_date("%s:'orig_flag' not numeric", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
if (orig_flag != 0 && orig_flag != 1)
{
log_file_date("%s:'orig_flag' must be 0 or 1", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* get service name */
if ((len = command_wordlen(comm, 3)) <= 0)
{
log_file_date("%s:service name invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
if ((sname = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[sname]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
return;
}
if (!command_word(comm, sname, 3))
{
log_file_date("%s:parse error[sname]", mname);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
//log_file_date("%s:service name=%s", mname, sname);
/* get host name */
if ((len = command_wordlen(comm, 4)) <= 0)
{
log_file_date("%s:host name invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(sname);
return;
}
if ((hname = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[hname]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
free(sname);
return;
}
if (!command_word(comm, hname, 4))
{
log_file_date("%s:parse error[hname]", mname);
free(sname);
free(hname);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
//log_file_date("%s:host name=%s", mname, hname);
/* get port number */
if ((len = command_wordlen(comm, 5)) <= 0)
{
log_file_date("%s:port number invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(sname);
free(hname);
return;
}
if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[port_char]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
free(sname);
free(hname);
return;
}
if (!command_word(comm, port_char, 5))
{
log_file_date("%s:parse error[port_char]", mname);
free(sname);
free(hname);
free(port_char);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!qatoi(port_char, &port))
{
log_file_date("%s:port not numeric", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(sname);
free(hname);
free(port_char);
}
free(port_char);
/* get ip address (if present) */
if (command_words(comm) > 5)
{
if ((len = command_wordlen(comm, 6)) <= 0)
{
log_file_date("%s:ip address invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(sname);
free(hname);
return;
}
if ((ip_ad = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[ip_ad]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
free(sname);
free(hname);
return;
}
if (!command_word(comm, ip_ad, 6))
{
log_file_date("%s:parse error[ip_ad]", mname);
free(sname);
free(hname);
free(ip_ad);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!isip(ip_ad))
{
log_file_date("%s:invalid ip address", mname);
free(sname);
free(hname);
free(ip_ad);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
}
else
ip_ad = (char *)NULL;
ret = s_ll_add(sname, hname, port, ip_ad);
if ((sockrc = do_reply_code(ret)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'do_reply_code'", mname, sockrc);
/* if add was successful and the 'orig_flag' indicates
a client source, broadcast this addition to
all other 'socloc' servers */
if (ret == SL_OK && orig_flag)
if ((sockrc = sloc_bcast_add(sname, hname, port, ip_ad)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'sloc_bcast_add'", mname, sockrc);
if (ip_ad != (char *)NULL)
free(ip_ad);
free(sname);
free(hname);
s_ll_debug();
sl_code_string(ret, mess);
log_file_date("%s:normal exit[%s]", mname, mess);
}
void s_delete(char *comm)
{
/* Delete a socket server entry.
Syntax:
SL_SEND_DELETE orig_flag port_number
*/
char mname[] = "s_delete";
char *port_char;
char orig_flag_char[25], mess[150];
int orig_flag, port, len, ret, sockrc;
log_file_date("%s:enter", mname);
/* must be at least 3 command words */
if (command_words(comm) < 3)
{
log_file_date("%s:incorrect number of parameters", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* get 'orig_flag' */
if (!command_word(comm, orig_flag_char, 2))
{
log_file_date("%s:parse error[orig_flag_char]", mname);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!qatoi(orig_flag_char, &orig_flag))
{
log_file_date("%s:'orig_flag' not numeric", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
if (orig_flag != 0 && orig_flag != 1)
{
log_file_date("%s:'orig_flag' must be 0 or 1", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* get port number */
if ((len = command_wordlen(comm, 3)) <= 0)
{
log_file_date("%s:port number invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[port_char]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
return;
}
if (!command_word(comm, port_char, 3))
{
log_file_date("%s:parse error[port_char]", mname);
free(port_char);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!qatoi(port_char, &port))
{
log_file_date("%s:port not numeric", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(port_char);
}
free(port_char);
ret = s_ll_delete(port);
if ((sockrc = do_reply_code(ret)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'do_reply_code'", mname, sockrc);
/* if delete was successful and the 'orig_flag' indicates
a client source, broadcast this deletion to all
other 'socloc' servers */
if (ret == SL_OK && orig_flag)
if ((sockrc = sloc_bcast_delete(port)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'sloc_bcast_delete'", mname, sockrc);
s_ll_debug();
sl_code_string(ret, mess);
log_file_date("%s:normal exit,rc[%s]", mname, mess);
}
void s_config_add(char *comm)
{
/* Add an entry to the config list of available socloc servers.
Syntax:
SL_SEND_CONFIG_ADD orig_flag host_name port_number[ ip_addr]
Line will be parsed with 'command_word' functions so any
parameter with a space must be quoted. */
char mname[] = "s_config_add";
char *hname, *port_char, *ip_ad;
char mess[150], orig_flag_char[50];
int port, len, ret, orig_flag, sockrc;
log_file_date("%s:enter", mname);
/* must be at least 4 command words */
if (command_words(comm) < 4)
{
log_file_date("%s:incorrect number of parameters", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* get 'orig_flag' */
if (!command_word(comm, orig_flag_char, 2))
{
log_file_date("%s:parse error[orig_flag_char]", mname);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!qatoi(orig_flag_char, &orig_flag))
{
log_file_date("%s:'orig_flag' not numeric", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
if (orig_flag != 0 && orig_flag != 1)
{
log_file_date("%s:'orig_flag' must be 0 or 1", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* get host name */
if ((len = command_wordlen(comm, 3)) <= 0)
{
log_file_date("%s:host name invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
if ((hname = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[hname]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
return;
}
if (!command_word(comm, hname, 3))
{
log_file_date("%s:parse error[hname]", mname);
free(hname);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
//log_file_date("%s:host name=%s", mname, hname);
/* get port number */
if ((len = command_wordlen(comm, 4)) <= 0)
{
log_file_date("%s:port number invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(hname);
return;
}
if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[port_char]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
free(hname);
return;
}
if (!command_word(comm, port_char, 4))
{
log_file_date("%s:parse error[port_char]", mname);
free(hname);
free(port_char);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!qatoi(port_char, &port))
{
log_file_date("%s:port not numeric", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(hname);
free(port_char);
}
free(port_char);
/* get ip address (if present) */
if (command_words(comm) > 4)
{
if ((len = command_wordlen(comm, 5)) <= 0)
{
log_file_date("%s:ip address invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(hname);
return;
}
if ((ip_ad = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[ip_ad]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
free(hname);
return;
}
if (!command_word(comm, ip_ad, 5))
{
log_file_date("%s:parse error[ip_ad]", mname);
free(hname);
free(ip_ad);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!isip(ip_ad))
{
log_file_date("%s:invalid ip address", mname);
free(hname);
free(ip_ad);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
}
else
ip_ad = (char *)NULL;
/* since 'sl_config_add' only checks for duplicate 'socloc'
ports, we check for duplicate in socket server list */
if ((ret = s_ll_port_exist(port)) != SL_OK)
{
log_file_date("%s:bad ret from s_ll_port_exist,rc=%d",
mname, ret);
free(hname);
free(ip_ad);
(void)do_reply_code(ret);
return;
}
ret = sl_config_add(hname, port, ip_ad);
if ((sockrc = do_reply_code(ret)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'do_reply_code'", mname, sockrc);
if (ret == SL_OK && orig_flag)
if ((sockrc = sloc_bcast_config_add(hname, port, ip_ad)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'sloc_bcast_config_add'",
mname, sockrc);
free(hname);
if (ip_ad != (char *)NULL)
free(ip_ad);
sl_code_string(ret, mess);
log_file_date("%s:normal exit,rc=%s", mname, mess);
sl_config_debug();
}
void s_config_delete(char *comm)
{
/* Delete a config socket server entry.
Syntax:
SL_SEND_CONFIG_DELETE orig_flag port_number
*/
char mname[] = "s_config_delete";
char *port_char;
char mess[150], orig_flag_char[50];
int port, len, ret, orig_flag, sockrc;
log_file_date("%s:enter", mname);
/* must be at least 3 command words */
if (command_words(comm) < 3)
{
log_file_date("%s:incorrect number of parameters", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* get 'orig_flag' */
if (!command_word(comm, orig_flag_char, 2))
{
log_file_date("%s:parse error[orig_flag_char]", mname);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!qatoi(orig_flag_char, &orig_flag))
{
log_file_date("%s:'orig_flag' not numeric", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
if (orig_flag != 0 && orig_flag != 1)
{
log_file_date("%s:'orig_flag' must be 0 or 1", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* get port number */
if ((len = command_wordlen(comm, 3)) <= 0)
{
log_file_date("%s:port number invalid", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
if ((port_char = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[port_char]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
return;
}
if (!command_word(comm, port_char, 3))
{
log_file_date("%s:parse error[port_char]", mname);
free(port_char);
(void)do_reply_code(SL_INTERNAL_ERROR);
return;
}
if (!qatoi(port_char, &port))
{
log_file_date("%s:port not numeric", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
free(port_char);
}
free(port_char);
ret = sl_config_delete(port);
if ((sockrc = do_reply_code(ret)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'do_reply_code'", mname, sockrc);
if (ret == SL_OK && orig_flag)
if ((sockrc = sloc_bcast_config_delete(port)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'sloc_bcast_config_delete'",
mname, sockrc);
sl_code_string(ret, mess);
log_file_date("%s:normal exit,rc[%s]", mname, mess);
sl_config_debug();
}
void s_find(char *comm)
{
/* Find a socket server by one or more details. All parameters
are optional but at least one parameter must be supplied. Syntax:
SL_SEND_FIND [service sname][ host hname][ port port_num][ ip ip_ad]
Any parameter containing spaces must be quoted. The first server
matching the supplied parameters will be used.
Function replies with the following string upon success:
'service_name' 'host_name' port_number[ ip_addr]
Note that the string is space delimited. Since there is a
possibility of the host name having
spaces, this word will always be quoted. Function will check
the status of the matching server. If the server is not responding,
the entry will be deleted from this and all other 'socloc'
servers. */
char mname[] = "s_find";
char *reply, *sname, *hname, *ip_ad;
char mess[150];
int pos, nwords, port, len, ret, i, found = FALSE;
log_file_date("%s:enter", mname);
// s_ll_debug();
// s_config_debug();
nwords = command_words(comm);
/* must be at least 3 command words */
if (nwords < 3)
{
log_file_date("%s:incorrect number of parameters", mname);
(void)do_reply_char(SL_INVALID_PARAMETER, "nok");
return;
}
/* alloc details */
if ((sname = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[sname]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
if ((hname = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[hname]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
free(sname);
return;
}
if ((ip_ad = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[ip_ad]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
free(sname);
free(hname);
return;
}
/* set starting position in command string of parameters */
pos = command_indxword(comm, 2);
/* if the first char in the second word is a quote,
'command_indxword' will skip over this, we need to
backup one position */
if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
pos--;
/* loop looking for a match and checking the status of the
matching server, since the same vars are used from parse
and match, we re-parse every iteration (sloppy, I know) */
while(!found)
{
sname[0] = EOS;
hname[0] = EOS;
ip_ad[0] = EOS;
port = 0;
if ((ret = sconnect_parse(&comm[pos], TRUE, sname, hname,
&port, ip_ad)) != SP_OK)
{
sp_code_string(ret, mess);
log_file_date("%s:bad rc[%s] from 'sconnect_parse", mname, mess);
(void)do_reply_char(SL_INVALID_PARAMETER, mess);
free(sname);
free(hname);
free(ip_ad);
return;
}
if ((ret = s_ll_get_first(sname, hname, &port, ip_ad)) != SL_OK)
{
sl_code_string(ret, mess);
log_file_date("%s:s_ll_get_first failed,rc=%s", mname, mess);
(void)do_reply_char(ret, mess);
free(sname);
free(hname);
free(ip_ad);
return;
}
log_file_date("%s:found match,hname=%s,port=%d", mname, hname, port);
/* we have found a match, check the server status */
if ((ret = sloc_custom_status(hname, port)) != SL_OK)
{
sl_code_string(ret, mess);
log_file_date("%s:bad rc[%s] from 'sloc_custom_status'", mname,
mess);
/* status failed, delete the entry and broadcast
this delete to all 'socloc' servers */
if (s_ll_delete(port) == SL_OK)
if ((i = sloc_bcast_delete(port)) != SL_OK)
log_file_date("%s:bad rc[%d] from 'sloc_bcast_delete'",
mname, i);
}
else
found = TRUE;
}
len = strlen(sname) + strlen(hname) + strlen(ip_ad) + 25;
if ((reply = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[reply]", mname);
(void)do_reply_char(SL_INTERNAL_ERROR, "nok");
free(sname);
free(hname);
free(ip_ad);
return;
}
if (!strlen(ip_ad))
sprintf(reply, "'%s' '%s' %d", sname, hname, port);
else
sprintf(reply, "'%s' '%s' %d %s", sname, hname, port, ip_ad);
free(sname);
(void)do_reply_char(ret, reply);
free(hname);
free(ip_ad);
free(reply);
sl_code_string(ret, mess);
log_file_date("%s:normal exit,rc=%s", mname, mess);
}
void s_config_find(char *comm)
{
/* Find a 'socloc' server by one or more details. At least one
optional parameter must be present. Syntax:
SL_SEND_CONFIG_FIND[ host host_name][ port port_num][ ip ip_ad]
Any parameter containing spaces must be quoted.
Function replies with the following string upon success:
'host_name' port_number[ ip_addr]
Note that the string is space delimited. Since there is a
possibility of the host name having spaces, this word will
always be quoted. Since it is possible that the find will
match this 'socloc' server, the status of the matched server
is not checked. */
char mname[] = "s_config_find";
char *reply, *hname, *ip_ad;
char mess[150];
int pos, nwords, port, len, ret, found = FALSE;
log_file_date("%s:enter", mname);
nwords = command_words(comm);
/* must be at least 3 command words */
if (nwords < 3)
{
log_file_date("%s:incorrect number of parameters", mname);
(void)do_reply_char(SL_INVALID_PARAMETER, "nok");
return;
}
/* alloc details */
if ((hname = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[hname]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
if ((ip_ad = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[ip_ad]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
free(hname);
return;
}
/* set starting position in command string of parameters */
pos = command_indxword(comm, 2);
/* if the first char in the second word is a quote,
'command_indxword' will skip over this, we need to
backup one position */
if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
pos--;
hname[0] = EOS;
ip_ad[0] = EOS;
port = 0;
/* detect parameters */
if ((ret = sconnect_parse(&comm[pos], FALSE, (char *)NULL, hname,
&port, ip_ad)) != SP_OK)
{
sp_code_string(ret, mess);
log_file_date("%s:bad rc[%s] from 'sconnect_parse", mname, mess);
(void)do_reply_char(SL_INVALID_PARAMETER, mess);
free(hname);
free(ip_ad);
return;
}
if ((ret = sl_config_find(hname, &port, ip_ad)) != SL_OK)
{
sl_code_string(ret, mess);
log_file_date("%s:bad rc[%s] from 'sl_config_find'", mname, mess);
(void)do_reply_char(ret, mess);
free(hname);
free(ip_ad);
return;
}
log_file_date("%s:found match,hname=%s,port=%d", mname, hname, port);
len = strlen(hname) + strlen(ip_ad) + 10;
if ((reply = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[reply]", mname);
(void)do_reply_char(SL_INTERNAL_ERROR, "nok");
free(hname);
free(ip_ad);
return;
}
if (!strlen(ip_ad))
sprintf(reply, "'%s' %d", hname, port);
else
sprintf(reply, "'%s' %d %s", hname, port, ip_ad);
(void)do_reply_char(ret, reply);
free(hname);
free(ip_ad);
free(reply);
sl_code_string(ret, mess);
log_file_date("%s:normal exit,rc=%s", mname, mess);
}
void s_find_list(char *comm)
{
/* Find one or more socket servers by one or more details. Syntax:
SL_SEND_FIND_LIST[ service service_name][ host host_name]
[ port port_num][ ip ip_ad]
Any parameter containing spaces must be quoted. At least one
keyword and its value must be present. Function will locate and
build a list of all socket servers matching the details.
Function replies with a list of socket servers matching. Each
list entry consists of the following string:
'host_name' port_number[ ip_addr]
List entries are delimited by 'SL_LIST_DELIM'. Since there is a
possibility of the host name having
spaces, this word will always be quoted. */
struct sloc_entry *rov = sloc_base;
char mname[] = "s_find_list";
char *anentry, *reply, *sname, *hname, *ip_ad;
char mess[150];
int pos, nwords, port, len, ret, i, found;
int nentries = 0, out_pos = 0;
log_file_date("%s:enter", mname);
nwords = command_words(comm);
/* must be at least 3 command words (command code, keyword and value) */
if (nwords < 3)
{
log_file_date("%s:incorrect number of parameters", mname);
(void)do_reply_char(SL_INVALID_PARAMETER, "nok");
return;
}
/* make sure list is not empty */
if (rov == SLOC_NULL)
{
log_file_date("%s:locate server list empty", mname);
(void)do_reply_char(SL_NOT_FOUND, "nok");
return;
}
/* alloc details */
if ((sname = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[sname]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
if ((hname = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[hname]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
free(sname);
return;
}
if ((ip_ad = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[ip_ad]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
free(sname);
free(hname);
return;
}
sname[0] = EOS;
hname[0] = EOS;
ip_ad[0] = EOS;
/* get the position of the second command word */
pos = command_indxword(comm, 2);
/* if the first char in the second word is a quote,
'command_indxword' will skip over this, we need to
backup one position */
if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
pos--;
/* parse details */
if ((ret = sconnect_parse(&comm[pos], TRUE, sname, hname, &port,
ip_ad)) != SP_OK)
{
sp_code_string(ret, mess);
log_file_date("%s:bad rc[%s] from 'sconnect_parse", mname, mess);
free(sname);
free(hname);
free(ip_ad);
(void)do_reply_char(SL_INVALID_PARAMETER, mess);
return;
}
if ((reply = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc fail[reply]", mname);
(void)do_reply_char(SL_INTERNAL_ERROR, "nok");
free(sname);
free(hname);
free(ip_ad);
return;
}
if ((anentry = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc error[anentry]", mname);
free(sname);
free(hname);
free(ip_ad);
free(reply);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
reply[0] = EOS;
/* loop through list looking for matches */
while(rov != SLOC_NULL)
{
found = TRUE;
if (strlen(sname))
if (!strcmp(sname, rov->service_name))
found = TRUE;
else
found = FALSE;
if (found && strlen(hname))
if (!strcmp(hname, rov->host_name))
found = TRUE;
else
found = FALSE;
if (found && port > 0)
if (port == rov->port_number)
found = TRUE;
else
found = FALSE;
if (found && ip_ad != (char *)NULL && strlen(ip_ad))
if (rov->ip_addr == (char *)NULL)
found = FALSE;
else
if (!strlen(rov->ip_addr))
found = FALSE;
else
if (!strcmp(ip_ad, rov->ip_addr))
found = TRUE;
else
found = FALSE;
if (found)
{
nentries++;
if (rov->ip_addr != (char *)NULL && strlen(rov->ip_addr))
sprintf(anentry, "'%s' '%s' %d %s", rov->service_name,
rov->host_name, rov->port_number, rov->ip_addr);
else
sprintf(anentry, "'%s' '%s' %d", rov->service_name,
rov->host_name, rov->port_number);
if (nentries > 1)
reply[out_pos++] = SL_LIST_DELIM;
/* load this entry into 'reply' */
len = strlen(anentry);
for(i = 0; i < len; i++, out_pos++)
reply[out_pos] = anentry[i];
}
rov = rov->next;
}
if (!nentries)
{
log_file_date("%s:no match", mname);
(void)do_reply_char(SL_NOT_FOUND, "nok");
free(sname);
free(hname);
free(ip_ad);
free(reply);
free(anentry);
return;
}
free(sname);
free(hname);
free(ip_ad);
free(anentry);
(void)do_reply_char(ret, reply);
free(reply);
sl_code_string(ret, mess);
log_file_date("%s:normal exit,rc[%s]", mname, mess);
}
void s_get_list(void)
{
/* Get the 'socloc' list. The list is transmitted with
each entry delimited by 'SL_LIST_DELIM'. Syntax:
SL_SEND_GET_LIST */
char mname[] = "s_get_list";
char *reply, *anentry, *sname, *hname, ip_ad[25];
int ret, nentries, i, j, port, len, out_pos = 0;
log_file_date("%s:enter", mname);
if ((ret = s_ll_get_nentries(&nentries)) != SL_OK)
{
log_file_date("%s:bad rc from 's_ll_get_nentries',rc=%d",
mname, ret);
(void)do_reply_char(ret, "nok");
return;
}
if ((reply = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc error[reply]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
if ((anentry = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc error[anentry]", mname);
free(reply);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
if ((sname = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc error[sname]", mname);
free(reply);
free(anentry);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
if ((hname = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc error[hname]", mname);
free(reply);
free(anentry);
free(sname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
reply[0] = EOS;
for(i = 1; i <= nentries; i++)
{
if ((ret = s_ll_get_nth(i, sname, hname, &port, ip_ad)) != SL_OK)
{
log_file_date("%s:bad rc from 's_ll_get_nth',entry=%d,rc=%d",
mname, i, ret);
free(reply);
free(anentry);
free(sname);
free(hname);
(void)do_reply_char(ret, "nok");
return;
}
if (strlen(ip_ad))
sprintf(anentry, "'%s' '%s' %d %s", sname, hname, port, ip_ad);
else
sprintf(anentry, "'%s' '%s' %d", sname, hname, port);
/* load this entry into 'reply' */
len = strlen(anentry);
for(j = 0; j < len; j++, out_pos++)
reply[out_pos] = anentry[j];
if (i < nentries)
reply[out_pos++] = SL_LIST_DELIM;
}
reply[out_pos] = EOS;
free(anentry);
free(sname);
free(hname);
(void)do_reply_char(SL_OK, reply);
free(reply);
log_file_date("%s:normal exit,rc=SL_OK", mname);
}
void s_put_list(char *comm)
{
/* Take the received 'socloc' list and write/put it.
A list entry is expected in the format:
sname hname port[ ip_ad]
Where 'sname' is the service name, 'hname' is the
host name, port is the TCP port number and the
optional 'ip_ad' is the IP address. If the
service name or host name contains spaces, they
must be quoted.
Each entry is delimited by 'SL_LIST_DELIM'.
Syntax:
SL_SEND_PUT_LIST list */
char mname[] = "s_put_list";
char *thelist;
int pos, len, ret;
log_file_date("%s:enter", mname);
if (command_words(comm) < 2)
{
log_file_date("%s:no list", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* load just the list */
pos = command_indxword(comm, 2);
/* if the first word in the first entry is a quote,
'command_indxword' will skip over this, we need
to backup one position */
if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
pos--;
len = strlen(comm) - pos;
if ((thelist = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[thelist]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
return;
}
strcpy(thelist, &comm[pos]);
ret = s_ll_put_list(thelist);
free(thelist);
(void)do_reply_code(ret);
log_file_date("%s:normal exit reply[%d]", mname, ret);
}
void s_config_get_list(void)
{
/* Get the 'socloc' config list. The list is transmitted with
each entry delimited by 'SL_LIST_DELIM'. Syntax:
SL_SEND_GET_LIST */
char mname[] = "s_config_get_list";
char *reply;
int ret;
log_file_date("%s:enter", mname);
if ((reply = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
{
log_file_date("%s:alloc error[reply]", mname);
(void)do_reply_char(SL_MEMORY_FAIL, "nok");
return;
}
if ((ret = sl_config_get_list(reply)) != SL_OK)
(void)do_reply_char(ret, "nok");
else
(void)do_reply_char(ret, reply);
free(reply);
log_file_date("%s:normal exit,rc=%d", mname, ret);
}
void s_config_put_list(char *comm)
{
/* Put/write the 'socloc' config list. Syntax:
SL_SEND_CONFIG_PUT_LIST list
Where 'list' is one or more delimited entries (delimited
by 'SL_LIST_DELIM') with each being:
hname port[ ip_ad]
where 'hname' is the host name. If it contains spaces, it
must be quoted. 'Port' is the decimal TCP port number
and 'ip_ad' is the optional IP address. A reply code
(without any other value) is sent. */
char mname[] = "s_config_put_list";
char *thelist;
int pos, len, ret;
log_file_date("%s:enter", mname);
if (command_words(comm) < 2)
{
log_file_date("%s:no list", mname);
(void)do_reply_code(SL_INVALID_PARAMETER);
return;
}
/* load just the list */
pos = command_indxword(comm, 2);
/* if the first word in the first entry is a quote,
'command_indxword' will skip over this, we need
to backup one position */
if (comm[pos - 1] == '\"' || comm[pos - 1] == '\'')
pos--;
len = strlen(comm) - pos;
if ((thelist = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:alloc fail[thelist]", mname);
(void)do_reply_code(SL_MEMORY_FAIL);
return;
}
strcpy(thelist, &comm[pos]);
ret = sl_config_put_list(thelist);
free(thelist);
(void)do_reply_code(ret);
log_file_date("%s:normal exit,rc=%d", mname, ret);
}
int s_terminate(char *comm)
{
/* Terminate the server. Check the supplied password first.
Syntax:
SL_SEND_TERM password
Function returns 'TRUE' if correct password was supplied,
'FALSE' otherwise. */
char mname[] = "s_terminate";
char wrd[256];
int ret;
log_file_date("%s:enter", mname);
if (command_words(comm) < 2)
{
(void)do_reply_code(SL_INVALID_FUNCTION);
log_file_date("%s:no password", mname);
return(FALSE);
}
if (!command_word(comm, wrd, 2))
{
(void)do_reply_code(SL_INTERNAL_ERROR);
log_file_date("%s:error getting password", mname);
return(FALSE);
}
if (!strcmp(wrd, SL_TERM_PASSWD))
{
(void)do_reply_code(SL_OK);
return(TRUE);
}
log_file_date("%s:illegal terminate request", mname);
(void)do_reply_code(SL_ACCESS_DENIED);
return(FALSE);
}
void s_trans_num(void)
{
/* Get the current transaction count. Syntax:
SL_SEND_TRANS_NUM */
char mname[] = "s_trans_num";
long count;
log_file_date("%s:enter", mname);
count = ipc_trans_num();
(void)do_reply_long(SL_OK, count);
log_file_date("%s:normal exit,rc=0", mname);
}
void s_connect_num(void)
{
/* Get the current connection count. Syntax:
SL_SEND_CONNECT_NUM */
char mname[] = "s_connect_num";
int count;
log_file_date("%s:enter", mname);
count = ipc_connect_num();
(void)do_reply_int(SL_OK, count);
log_file_date("%s:normal exit,rc=0", mname);
}
/* IPC primatives */
int do_reply_int(int reply_code, int int_value)
{
/* Send a reply to a request which returns an int in addition
to the reply code. Function returns 'SL_OK' upon success,
an error code otherwise. */
char reply_char[50];
int anint = 0;
if (reply_code == SL_OK)
anint = int_value;
memset(reply_char, 0, 50);
sprintf(reply_char, "%d %d", reply_code, anint);
log_file_date("do_reply_int:reply=%s,l=%d", reply_char,
strlen(reply_char));
if (ipc_send_data(reply_char) == 0)
return(SL_VC_ERROR);
return(SL_OK);
}
int do_reply_long(int reply_code, long long_value)
{
/* Send a reply to a request which returns a long in addition
to the reply code. Function returns 'SL_OK' upon success,
an error code otherwise. */
char reply_char[50];
int along = 0L;
if (reply_code == SL_OK)
along = long_value;
memset(reply_char, 0, 50);
sprintf(reply_char, "%d %ld", reply_code, along);
log_file_date("do_reply_long:reply=%s,l=%d", reply_char, strlen(reply_char));
if (ipc_send_data(reply_char) == 0)
return(SL_VC_ERROR);
return(SL_OK);
}
int do_reply_code(int reply_code)
{
/* Send a reply to a request which returns the reply code. Function
returns 'SL_OK' upon success, an error code otherwise. */
char reply_char[50];
memset(reply_char, 0, 50);
sprintf(reply_char, "%d", reply_code);
log_file_date("do_reply_code:reply=%s,l=%d", reply_char,
strlen(reply_char));
if (ipc_send_data(reply_char) == 0)
return(SL_VC_ERROR);
return(SL_OK);
}
int do_reply_char(int reply_code, char *char_value)
{
/* Send a reply to a request that returns a string as well as
the reply code. Function returns 'SL_OK' upon success, an
error code otherwise. */
char *reply_char;
int len;
if (char_value == (char *)NULL)
return(SL_INVALID_FUNCTION);
len = strlen(char_value);
// alloc reply string, note that 'char_value' might be empty
if ((reply_char = (char *)malloc(len + 10)) == (char *)NULL)
return(SL_MEMORY_FAIL);
memset(reply_char, 0, len + 10);
sprintf(reply_char, "%d %s", reply_code, char_value);
log_file_date("do_reply_char:reply=%s,l=%d", reply_char, strlen(reply_char));
if (ipc_send_data(reply_char) == 0)
{
free(reply_char);
return(SL_VC_ERROR);
}
free(reply_char);
return(SL_OK);
}
/* low level functions */
int s_ll_put_list(char *comm)
{
/* Take the input 'socloc' list and write/put it.
A list entry is expected in the format:
sname hname port[ ip_ad]
Where 'sname' is the service name, 'hname' is the
host name, port is the TCP port number and the
optional 'ip_ad' is the IP address. If the
service name or host name contains spaces, they
must be quoted.
Each entry is delimited by 'SL_LIST_DELIM'. */
char mname[] = "s_ll_put_list";
char *entry, *sname, *hname, *port_char, *ip_ad;
int nentries, nwords, port, len, i, ret;
log_file_date("%s:enter", mname);
if (comm == (char *)NULL || !strlen(comm))
{
log_file_date("%s:[comm] null or empty", mname);
return(SL_INVALID_PARAMETER);
}
len = strlen(comm);
/* get number of delimited entries */
nentries = ll_words(comm, SL_LIST_DELIM);
log_file_date("%s:found %d entries in input list", mname, nentries);
if (nentries < 1)
{
log_file_date("%s:wacky value from 'll_words'", mname);
return(SL_INTERNAL_ERROR);
}
/* delete the existing list in memory */
s_ll_delete_all();
/* add each entry in the list */
for(i = 1; i <= nentries; i++)
{
len = ll_wordlen(comm, i, SL_LIST_DELIM);
log_file_date("%s:entry[%d]:len=%d", mname, i, len);
if (len < 1)
{
log_file_date("%s:entry[%d]:wacky value from 'll_wordlen", mname, i);
return(SL_INTERNAL_ERROR);
}
if ((entry = (char *)malloc(len + 1)) == (char *)NULL)
{
log_file_date("%s:entry[%d]:alloc fail[entry]", mname, i);
return(SL_MEMORY_FAIL);
}
if (!ll_word(comm, entry, i, SL_LIST_DELIM))
{
log_file_date("%s:entry[%d]:bad rc from 'll_word'", mname, i);
free(entry);
return(SL_INTERNAL_ERROR);
}
log_file_date("%s:entry[%d]=%s", mname, i, entry);
/* must have at least 3 command words in each entry */
if ((nwords = command_words(entry)) < 3)
{
log_file_date("%s:entry[%d]:wrong number of parms", mname, i);
free(entry);
return(SL_INVALID_PARAMETER);
}
/* since no single entry value can exceed the length of
the entry, we get sloppy and allocate to length
of entry */
if ((sname = initstring(entry)) == (char *)NULL)
{
log_file_date("%s:entry[%d]NULL from 'initstring'[sname]", mname, i);
free(entry);
return(SL_MEMORY_FAIL);
}
if ((hname = initstring(entry)) == (char *)NULL)
{
log_file_date("%s:entry[%d]:NULL from 'initstring'[hname]", mname, i);
free(entry);
free(sname);
return(SL_MEMORY_FAIL);
}
if ((port_char = initstring(entry)) == (char *)NULL)
{
log_file_date("%s:entry[%d]:NULL from 'initstring'[port_char]", mname, i);
free(entry);
free(sname);
free(hname);
return(SL_MEMORY_FAIL);
}
if ((ip_ad = initstring(entry)) == (char *)NULL)
{
log_file_date("%s:entry[%d]:NULL from 'initstring'[ip_ad]", mname, i);
free(entry);
free(sname);
free(hname);
free(port_char);
return(SL_MEMORY_FAIL);
}
sname[0] = EOS;
hname[0] = EOS;
port_char[0] = EOS;
ip_ad[0] = EOS;
if (!command_word(entry, sname, 1))
{
log_file_date("%s:entry[%d]:bad ret from 'command_word'[sname]",
mname, i);
free(entry);
free(sname);
free(hname);
free(port_char);
free(ip_ad);
return(SL_INTERNAL_ERROR);
}
log_file_date("%s:entry[%d]:service name=%s", mname, i, sname);
if (!command_word(entry, hname, 2))
{
log_file_date("%s:entry[%d]:bad ret from 'command_word'[hname]",
mname, i);
free(entry);
free(sname);
free(hname);
free(port_char);
free(ip_ad);
return(SL_INTERNAL_ERROR);
}
log_file_date("%s:entry[%d]:host name=%s", mname, i, hname);
if (!command_word(entry, port_char, 3))
{
log_file_date("%s:entry[%d]bad ret from 'command_word'[port_char]",
mname, i);
free(entry);
free(sname);
free(hname);
free(port_char);
free(ip_ad);
return(SL_INTERNAL_ERROR);
}
log_file_date("%s:entry[%d]:port_char=%s", mname, i, port_char);
if (!qatoi(port_char, &port))
{
log_file_date("%s:entry[%d]:port not numeric", mname, i);
free(entry);
free(sname);
free(hname);
free(port_char);
free(ip_ad);
return(SL_INVALID_PARAMETER);
}
free(port_char);
if (nwords > 3)
{
if (!command_word(entry, ip_ad, 4))
{
log_file_date("%s:entry[%d]:bad ret from 'command_word'[port_char]",
mname, i);
free(entry);
free(sname);
free(hname);
free(ip_ad);
return(SL_INTERNAL_ERROR);
}
if (!isip(ip_ad))
{
log_file_date("%s:entry[%d]:IP address invalid", mname, i);
free(entry);
free(sname);
free(hname);
free(ip_ad);
return(SL_INVALID_PARAMETER);
}
log_file_date("%s:entry[%d]:ip=%s", mname, i, ip_ad);
}
else
log_file_date("%s:entry[%d]:no ip present", mname, i);
/* finally, after all that, we are ready to add the entry */
if ((ret = s_ll_add(sname, hname, port, ip_ad)) != SL_OK)
{
log_file_date("%s:entry[%d]:bad rc[%d] from 's_ll_add'", mname,
i, ret);
free(entry);
free(sname);
free(hname);
free(ip_ad);
return(ret);
}
free(entry);
free(sname);
free(hname);
free(ip_ad);
}
log_file_date("%s:normal exit,rc[SL_OK]", mname);
return(SL_OK);
}
/* link list management functions */
int s_ll_get_first(char *sname, char *hname, int *port_num,
char *ip_ad)
{
/* Return the first matching socket server.At least one parameter
must be supplied. Function will locate first match based on
supplied parameters. 'ip_ad' is the only parameter that may
be NULL. Upon success, missing details will be loaded. Service
name, host name and IP address (if present) must be allocated
to sufficient size by the caller. Function returns 'SL_OK' upon
success, a socket locate code otherwise. */
struct sloc_entry *rov = sloc_base;
char mname[] = "s_ll_get_first";
int found;
log_file_date("%s:enter", mname);
if (sname == (char *)NULL || hname == (char *)NULL ||
port_num == (int *)NULL)
{
log_file_date("%s:null parm", mname);
return(SL_INVALID_PARAMETER);
}
if (!strlen(sname) && !strlen(hname) && *port_num <= 0 &&
(ip_ad == (char *)NULL || !strlen(ip_ad)))
{
log_file_date("%s:at least one parameter must be supplied", mname);
return(SL_INVALID_PARAMETER);
}
if (rov == SLOC_NULL)
{
log_file_date("%s:locate server list empty", mname);
return(SL_NOT_FOUND);
}
while(rov != SLOC_NULL)
{
found = TRUE;
if (strlen(sname))
if (!strcmp(sname, rov->service_name))
found = TRUE;
else
found = FALSE;
if (found && strlen(hname))
if (!strcmp(hname, rov->host_name))
found = TRUE;
else
found = FALSE;
if (found && *port_num > 0)
if (*port_num == rov->port_number)
found = TRUE;
else
found = FALSE;
if (found && ip_ad != (char *)NULL && strlen(ip_ad))
if (rov->ip_addr == (char *)NULL)
found = FALSE;
else
if (!strlen(rov->ip_addr))
found = FALSE;
else
if (!strcmp(ip_ad, rov->ip_addr))
found = TRUE;
else
found = FALSE;
if (found)
{
if (!strlen(sname))
strcpy(sname, rov->service_name);
if (!strlen(hname))
strcpy(hname, rov->host_name);
if (*port_num == 0)
*port_num = rov->port_number;
if (ip_ad != (char *)NULL && !strlen(ip_ad))
if (rov->ip_addr != (char *)NULL && strlen(rov->ip_addr))
strcpy(ip_ad, rov->ip_addr);
else
ip_ad[0] = EOS;
break;
}
else
rov = rov->next;
}
if (rov == SLOC_NULL)
{
log_file_date("%s:no match", mname);
return(SL_NOT_FOUND);
}
log_file_date("%s:found match", mname);
return(SL_OK);
}
int s_ll_get_nentries(int *nentries)
{
/* Get the number of entries in the link list. Function returns
'SL_OK' with the number of entries loaded into
'nentries' upon success, a socket locate error
otherwise. */
struct sloc_entry *rov = sloc_base;
char mname[] = "s_ll_get_nentries";
int cnt = 0;
log_file_date("%s:enter", mname);
*nentries = 0;
while(rov != SLOC_NULL)
{
cnt++;
rov = rov->next;
}
if (!cnt)
{
log_file_date("%s:locate server list empty", mname);
return(SL_NOT_FOUND);
}
*nentries = cnt;
log_file_date("%s:normal exit,nentries=%d", mname, cnt);
return(SL_OK);
}
int s_ll_get_nth(int pos, char *sname, char *hname, int *port_num,
char *ip_ad)
{
/* Get a specific socket server entry. Function returns
'SL_OK' upon success with the service name loaded into
'sname', host name loaded into 'hname',
the port number loaded into 'port_num' and the IP address loaded
into 'ip_ad'. These character variables must previously be
allocated to sufficient size by the caller. Function returns
a socket locate config error upon failure. */
struct sloc_entry *rov;
char mname[] = "s_ll_get_nth";
int i, nentries, ret;
log_file_date("%s:enter", mname);
/* get total number of entries and validate */
if ((ret = s_ll_get_nentries(&nentries)) != SL_OK)
{
log_file_date("%s:bad ret from s_ll_get_nentries,rc=%d",
mname, ret);
return(ret);
}
if (pos > nentries)
{
log_file_date("%s:request out of range", mname);
return(SL_NOT_FOUND);
}
for(rov = sloc_base, i = 1; i <= pos; rov = rov->next, i++)
if (i == pos)
{
strcpy(sname, rov->service_name);
strcpy(hname, rov->host_name);
*port_num = rov->port_number;
/* if the ip address parameter is null, do not attempt
to load the ip address even if there is one */
if (ip_ad == (char *)NULL)
break;
if (rov->ip_addr != (char *)NULL)
strcpy(ip_ad, rov->ip_addr);
else
/* if no ip address is present in the entry and the
ip address parameter is not null, zero out the
ip address parameter */
ip_ad[0] = EOS;
break;
}
log_file_date("%s:normal exit", mname);
return(SL_OK);
}
int s_ll_add(char *sname, char *hname, int port_num, char *ip_ad)
{
/* Add a socket server entry. Function returns
'SL_OK' upon success, a socket locate error code otherwise. */
struct sloc_entry *sloc;
struct sloc_entry *rov;
char mname[] = "s_ll_add";
int ret, len, size;
log_file_date("%s:enter", mname);
size = sizeof(struct sloc_entry);
/* reasonableness checks */
if (sname == (char *)NULL || !strlen(sname))
{
log_file_date("%s:null or empty service name", mname);
return(SL_INVALID_PARAMETER);
}
if (hname == (char *)NULL || !strlen(hname))
{
log_file_date("%s:null or empty host name", mname);
return(SL_INVALID_PARAMETER);
}
if (port_num <= 0)
{
log_file_date("%s:port out of range", mname);
return(SL_INVALID_PARAMETER);
}
/* check for duplicate port number */
if ((ret = s_ll_port_exist(port_num)) != SL_OK)
{
log_file_date("%s:bad ret from s_ll_port_exist,rc=%d",
mname, ret);
return(ret);
}
if ((sloc = (struct sloc_entry *)malloc(size)) == SLOC_NULL)
{
log_file_date("%s:alloc fail[sloc]", mname);
return(SL_MEMORY_FAIL);
}
len = strlen(sname);
if ((sloc->service_name = (char *)malloc(len + 1)) == (char *)NULL)
{
free(sloc);
log_file_date("%s:alloc fail[sloc->service_name]", mname);
return(SL_MEMORY_FAIL);
}
strcpy(sloc->service_name, sname);
len = strlen(hname);
if ((sloc->host_name = (char *)malloc(len + 1)) == (char *)NULL)
{
free(sloc->service_name);
free(sloc);
log_file_date("%s:alloc fail[sloc->host_name]", mname);
return(SL_MEMORY_FAIL);
}
strcpy(sloc->host_name, hname);
sloc->port_number = port_num;
if (ip_ad != (char *)NULL)
{
len = strlen(ip_ad);
if ((sloc->ip_addr = (char *)malloc(len + 1)) == (char *)NULL)
{
free(sloc->service_name);
free(sloc->host_name);
free(sloc);
log_file_date("%s:alloc fail[sloc->ip_addr]", mname);
return(SL_MEMORY_FAIL);
}
strcpy(sloc->ip_addr, ip_ad);
}
else
sloc->ip_addr = (char *)NULL;
sloc->next = SLOC_NULL;
/* set head of list if this is the first entry */
if (sloc_base == SLOC_NULL)
{
sloc_base = sloc;
log_file_date("%s:normal exit with head of list", mname);
return(SL_OK);
}
/* find last entry and hook into it */
rov = sloc_base;
while(rov->next != SLOC_NULL)
rov = rov->next;
rov->next = sloc;
log_file_date("%s:normal exit", mname);
return(SL_OK);
}
int s_ll_port_exist(int port_num)
{
/* Determine whether there already is a socket server or
'socloc' server using the specified port number. Check
port used by socket servers and 'socloc' servers.
Function returns 'SL_OK' if the port does not already
exist and 'SL_PORT_EXIST' if the port does already
exist/in use. */
struct sloc_entry *rov = sloc_base;
char mname[] = "s_ll_port_exist";
int ret = SL_OK;
log_file_date("%s:enter", mname);
while(rov != SLOC_NULL)
{
if (port_num == rov->port_number)
{
ret = SL_PORT_EXIST;
log_file_date("%s:port already in use by socket server", mname);
break;
}
rov = rov->next;
}
if (ret == SL_OK)
if ((ret = sl_config_port_exist(port_num)) != SL_OK)
log_file_date("%s:port already in use by 'socloc'", mname);
log_file_date("%s:normal exit,rc=%d", mname, ret);
return(ret);
}
int s_ll_delete(int port_num)
{
/* Delete a socket server entry. Since the TCP
port is unique, this is used as the entry key.
Function returns 'SL_OK' upon success, a
socket locate config error otherwise. */
struct sloc_entry *rov;
struct sloc_entry *prev;
char mname[] = "s_ll_delete";
log_file_date("%s:enter,port=%d", mname, port_num);
rov = prev = sloc_base;
while(rov != SLOC_NULL)
{
if (port_num == rov->port_number)
break;
else
{
prev = rov;
rov = rov->next;
}
}
/* if no match, error */
if (rov == SLOC_NULL)
{
log_file_date("%s:exit,no match", mname);
return(SL_NOT_FOUND);
}
/* if we are deleting the head entry, set new head */
if (rov == sloc_base)
sloc_base = rov->next;
else
prev->next = rov->next;
free(rov->service_name);
free(rov->host_name);
if (rov->ip_addr != (char *)NULL)
free(rov->ip_addr);
free(rov);
s_ll_debug();
log_file_date("%s:normal exit,rc[0]", mname);
return(SL_OK);
}
void s_ll_delete_all(void)
{
/* Delete all entries. */
struct sloc_entry *rov = sloc_base;
struct sloc_entry *tmp;
char mname[] = "s_ll_delete_all";
log_file_date("%s:enter", mname);
while(rov != SLOC_NULL)
{
free(rov->service_name);
free(rov->host_name);
if (rov->ip_addr != (char *)NULL)
free(rov->ip_addr);
tmp = rov;
rov = rov->next;
free(tmp);
}
log_file_date("%s:normal exit", mname);
sloc_base = SLOC_NULL;
}
void s_ll_debug(void)
{
/* Print the contents of the link list. Log file is
forced active. */
struct sloc_entry *rov = sloc_base;
char mname[] = "s_ll_debug";
int i = 1, islog;
if ((islog = is_log_active()) == FALSE)
log_start(s_log_file);
log_file_date("%s:enter", mname);
while(rov != SLOC_NULL)
{
log_file_date("%s[%d]:sname='%s',host='%s',port=%d,ip='%s'",
mname, i, rov->service_name, rov->host_name,
rov->port_number, rov->ip_addr);
rov = rov->next;
i++;
}
if (i == 1)
log_file_date("%s:list empty", mname);
log_file_date("%s:normal exit", mname);
if (!islog)
log_end();
}
void s_config_debug(void)
{
/* Print the contents of the config link list. Log file is
forced active. */
int islog;
if ((islog = is_log_active()) == FALSE)
log_start(s_log_file);
sl_config_debug();
if (!islog)
log_end();
}
void term_app(void)
{
// Shutdown anything left open.
(void)sloc_bcast_config_delete(server_port);
s_ll_delete_all();
#ifdef OS_WIN32
WSACleanup();
#endif
log_file_date("term_app:server down");
if (is_log_active())
log_end();
}