/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- main
- d_initialize
- do_comm
- d_term
- d_status
- d_client_log_on
- d_client_log_off
- d_client_log_status
- d_server_log_on
- d_server_log_off
- d_server_log_status
- d_socloc_log_on
- d_socloc_log_off
- d_socloc_log_status
- d_connect
- d_socloc_get_list
- d_socloc_config_get_list
- d_socloc_get
- d_socloc_version
- d_version
- d_trans_num
- d_connect_num
- d_socloc_trans_num
- d_socloc_connect_num
- d_tcp_only
- d_sr_code
- d_sr_int
- d_sr_long
- d_sr_char
- d_sr
- is_connected
- d_failover
- d_code_string
- get_token
- d_header
- d_out
- term_app
/* dumsockc - A command line for the dumb server 'dumsocks'.
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
Original Windows 32bit version Feb/2000, Rick Smereka
Re-compiled after re-structuring the definition of the common
send and repy codes. Apr/2000, Rick Smereka
Re-compiled after adding the new 'clib' module 'ip.c'.
Jul/2000, Rick Smereka
Modified for use with both sockets and QNX message passing IPC.
Removed manual socket interface. Re-coded to use 'ipclient'
API. Ported to QNX V4.23a. Oct/2001, Rick Smereka
Ported to Debian Linux. Jan/2003, Rick Smereka
Modified for the updated 'socloc' API ('sloc.c').
May/2003, Rick Smereka
Added function 'term_app' to perform shutdown tasks.
Added support for the commands 'DMCOM_TRANS_NUM',
'DMCOM_CONNECT_NUM', 'DMCOM_SOCLOC_TRANS_NUM' and
'DMCOM_SOCLOC_CONNECT_NUM'. Jun/2003, Rick Smereka
Added includes 'appinit.h' and 'sliocode.h'.
Added define 'APNAME'. Changed all logging calls to use 'logman'.
Used 'appinit' to register and remove application name.
May/2004, Rick Smereka
Changed call in 'main' from 'gets' to 'get_rec' and changed
command line buffer size to 'BUFSIZE' (defined in 'fio.h').
Dec/2004, Rick Smereka
Re-compile after changing the 'socloc' API.
Jan/2005, 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"
#include "appinit.h"
#include "ipclient.h" /* IPC client routines */
#include "dumsocks.h" /* dumb socket server defines */
#ifdef IPC_TCP
#include "socloc.h" /* socket locate defines */
#include "sloc.h" /* 'socloc' client API */
#include "sconnect.h" /* parse connect string */
#include "sliocode.h" // 'socloc' error translation
#endif
#define VERSION "1.08.01-2006.02.23" /* version ID */
// #define DEBUG 1
/* default private log file definition */
#define DUM_LOG_FILE "dumsockc.log"
#define APNAME "dumsockc"
/* global data */
#ifdef OS_WIN32
WSADATA wsaData; /* struct used by 'WSAStartup()' */
#endif
#ifdef IPC_TCP
int serverport = 0; /* TCP port that server is using */
int socloc_port; /* TCP port that 'socloc' is using */
char serverhost[256]; /* 'dumsocks' server host name */
#else
int connected_flag = FALSE;
#endif
char d_log_file[256]; /* name of client log file */
int main(void);
int d_initialize(void);
void d_term(char *);
void d_status(void);
void d_client_log_on(char *);
void d_client_log_off(void);
void d_client_log_status(void);
void d_server_log_on(char *);
void d_server_log_off(void);
void d_server_log_status(void);
void d_connect(char *);
void d_version(void);
void d_connect_num(void);
void d_trans_num(void);
void d_socloc_trans_num(void);
void d_socloc_connect_num(void);
void d_code_string(int, char *);
int get_token(char *);
void d_header(char *);
void d_out(char *,...);
int d_sr_code(int, char *);
int d_sr_int(int, char *, int *);
int d_sr_long(int, char *, long *);
int d_sr_char(int, char *, char *);
int is_connected(void);
void term_app(void);
#ifdef IPC_TCP
void d_socloc_log_on(char *);
void d_socloc_log_off(void);
void d_socloc_log_status(void);
void d_socloc_get_list(void);
void d_socloc_config_get_list(void);
void d_socloc_get(void);
void d_socloc_version(void);
int d_sr(int, char *, char *);
void d_failover(int);
#else
int d_sr(int, char *, char *, int);
void d_tcp_only(void);
#endif
int main(void)
{
char *comm;
int done = FALSE;
/* allocate command line buffer */
if ((comm = malloc(BUFSIZE + 1)) == NULL)
{
printf("dumsockc:insufficient memory to run program\n");
return(0);
}
/* build logo string based on platform */
#ifndef OS_UNIX
/* non-Unix */
sprintf(comm, "dumsockc for %s Version %s", PLATFORM_STRING,
VERSION);
#else
/* Unix */
sprintf(comm, "dumsockc for %s Version %s", SUB_PLATFORM_STRING,
VERSION);
#endif
printf("%s\n", comm);
printf("By Rick Smereka, Copyright (c) 2000-2006\n");
// register application name with 'appinit'
if (!appinit_register_name(APNAME))
{
free(comm);
printf("%s:fatal error registering app name with appinit\n", APNAME);
return(0);
}
#ifdef DEBUG
if (logman_start(d_log_file, APNAME))
{
printf("error starting log file\n");
free(comm);
return(0);
}
#endif
/* initialize */
if (!d_initialize())
{
free(comm);
term_app();
return(0);
}
printf("dumsockc comes with ABSOLUTELY NO WARRANTY\n");
printf("This is free software, and you are welcome to redistribute it\n");
printf("under certain conditions; see 'gpl.txt' for information.\n");
/* interpret loop */
while(!done)
{
#ifdef IPC_TCP
printf("dumsockc/%s[%d]> ", serverhost, serverport);
#else
printf("dumsockc> ");
#endif
get_rec(stdin, comm);
if (!do_comm(comm))
done = TRUE;
}
free(comm);
term_app();
printf("exit dumsockc\n");
return(0);
}
int d_initialize(void)
{
/* Start socket communication, locate a 'socloc' server
and connect to a 'dumsocks' server. Function returns
'TRUE' if the initialization was successful, 'FALSE'
otherwise. */
char mname[] = "d_initialize";
char *thelist, mes[128];
int ret;
logman("%s:enter", mname);
/* startup WinSock (if Windoze) */
#ifdef OS_WIN32
if (WSAStartup(WINSOCK_VERSION, &wsaData))
{
d_out("%s:unable to start WinSock. "
"Program abort", mname);
return(FALSE);
}
#endif
/* attempt to connect to a 'socloc' server */
#ifdef IPC_TCP
if ((ret = sloc_initialize()) != SL_OK)
{
sl_code_string(ret, mes);
d_out("%s:bad rc[%s] from 'sloc_initialize'. "
"Program abort", mname, mes);
return(FALSE);
}
/* locate a 'dumsocks' server */
if ((ret = sloc_find(DM_SERVICE_NAME, serverhost, &serverport,
(char *)NULL)) != SL_OK)
{
sl_code_string(ret, mes);
d_out("%s:bad rc[%s] from 'sloc_find'. Program abort", mname, mes);
return(FALSE);
}
d_out("%s:found 'dumsocks' server on host '%s' port %d", mname,
serverhost, serverport);
/* get config list from 'socloc' server and update
the client list with it */
if ((thelist = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[thelist]", mname);
return(FALSE);
}
if ((ret = sloc_config_get_list(thelist)) != SL_OK)
{
free(thelist);
sl_code_string(ret, mes);
d_out("%s:bad rc[%s] from 'sloc_config_get_list'", mname, mes);
return(FALSE);
}
if ((ret = sl_config_put_list(thelist)) != SL_OK)
{
sl_code_string(ret, mes);
d_out("%s:bad rc[%s] from 'sl_config_put_list'",
mname, mes);
free(thelist);
return(FALSE);
}
/* load the port that the current 'socloc' server is
using */
sloc_get_active_socloc(thelist, &socloc_port);
free(thelist);
// connect to the 'dumsocks' server
if (!ipc_set_active(serverhost, serverport))
{
d_out("%s:bad rc[FALSE] from 'ipc_set_active'", mname);
return(FALSE);
}
#else
if (!ipc_set_active(DM_SERVICE_NAME))
{
d_out("%s:bad rc[FALSE] from 'ipc_set_active'", mname);
return(FALSE);
}
connected_flag = TRUE;
#endif
strcpy(d_log_file, DUM_LOG_FILE);
return(TRUE);
}
int do_comm(char *comm)
{
/* Dispatch a 'dumsockc' command. Function always returns
'TRUE' except when the 'off' command is detected. */
char mname[] = "do_comm";
char *keywrd; /* command keyword */
int token; /* keyword token */
int nwords; /* number of words */
int len; /* length of command */
logman("%s:enter", mname);
len = strlen(comm);
if (!len)
{
d_out("empty command");
return(TRUE);
}
/* allocate to max as this string is re-used for the return
status string */
if ((keywrd = malloc(DM_MAXCOMMAND + 1)) == NULL)
{
d_out("%s:alloc fail[keywrd]", mname);
return(TRUE);
}
if (!word(comm, keywrd, 1))
{
d_out("%s:error while retreving keyword, line skipped", mname);
free(keywrd);
return(TRUE);
}
nwords = words(comm);
if ((token = get_token(keywrd)) == DMCOM_NOT_FOUND)
{
d_out("%s:unknown keyword[%s]", mname, keywrd);
free(keywrd);
return(TRUE);
}
/* process command */
switch(token)
{
case DMCOM_TERM:
d_term(comm);
break;
case DMCOM_STATUS:
d_status();
break;
case DMCOM_CLIENT_LOG_ON:
d_client_log_on(comm);
break;
case DMCOM_CLIENT_LOG_OFF:
d_client_log_off();
break;
case DMCOM_CLIENT_LOG_STATUS:
d_client_log_status();
break;
case DMCOM_SERVER_LOG_ON:
d_server_log_on(comm);
break;
case DMCOM_SERVER_LOG_OFF:
d_server_log_off();
break;
case DMCOM_SERVER_LOG_STATUS:
d_server_log_status();
break;
case DMCOM_CONNECT:
d_connect(comm);
break;
case DMCOM_SOCLOC_GET_LIST:
#ifdef IPC_TCP
d_socloc_get_list();
#else
d_tcp_only();
#endif
break;
case DMCOM_SOCLOC_CONFIG_GET_LIST:
#ifdef IPC_TCP
d_socloc_config_get_list();
#else
d_tcp_only();
#endif
break;
case DMCOM_SOCLOC_GET:
#ifdef IPC_TCP
d_socloc_get();
#else
d_tcp_only();
#endif
break;
case DMCOM_SOCLOC_LOG_OFF:
#ifdef IPC_TCP
d_socloc_log_off();
#else
d_tcp_only();
#endif
break;
case DMCOM_SOCLOC_LOG_ON:
#ifdef IPC_TCP
d_socloc_log_on(comm);
#else
d_tcp_only();
#endif
break;
case DMCOM_SOCLOC_LOG_STATUS:
#ifdef IPC_TCP
d_socloc_log_status();
#else
d_tcp_only();
#endif
break;
case DMCOM_SOCLOC_VERSION:
#ifdef IPC_TCP
d_socloc_version();
#else
d_tcp_only();
#endif
break;
case DMCOM_VERSION:
d_version();
break;
case DMCOM_TRANS_NUM:
d_trans_num();
break;
case DMCOM_CONNECT_NUM:
d_connect_num();
break;
case DMCOM_SOCLOC_TRANS_NUM:
#ifdef IPC_TCP
d_socloc_trans_num();
#else
d_tcp_only();
#endif
break;
case DMCOM_SOCLOC_CONNECT_NUM:
#ifdef IPC_TCP
d_socloc_connect_num();
#else
d_tcp_only();
#endif
break;
case DMCOM_OFF:
free(keywrd);
return(FALSE);
break;
default:
d_out("%s:command not found", mname);
free(keywrd);
return(TRUE);
};
free(keywrd);
return(TRUE);
}
void d_term(char *comm)
{
/* Terminate a 'dumsocks' server. Syntax:
term passwd
Where 'passwd' is the termination password. */
char mname[] = "d_term";
char passwd[128], parm[128], reply[25];
int ret;
d_header(mname);
if (command_words(comm) < 2)
{
d_out("%s:no password,access denied", mname);
return;
}
if (!command_word(comm, passwd, 2))
{
d_out("%s:error getting password", mname);
return;
}
if (words(passwd) > 1)
sprintf(parm, "'%s'", passwd);
else
strcpy(parm, passwd);
ret = d_sr_code(DM_SEND_TERM, parm);
/* if shutdown was successful, failover to
next 'dumsocks' server */
if (ret == DM_OK)
{
d_out("%s:'dumsocks' server is down", mname);
#ifdef IPC_TCP
d_failover(FALSE);
#endif
}
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
else
{
d_code_string(ret, parm);
printf("%s\n", parm);
}
}
void d_status(void)
{
/* Get 'dumsocks' server status. Syntax:
status */
char mname[] = "d_status";
char mes[128];
int ret;
d_header(mname);
ret = d_sr_code(DM_SEND_STATUS, (char *)NULL);
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
else
{
d_code_string(ret, mes);
printf("%s\n", mes);
}
}
void d_client_log_on(char *comm)
{
/* Turn client logging on with optional log file name.
Syntax:
client.log.on[ log.fname]
Where 'log.fname' is the optional log file name. If no
log file name is given 'DUM_LOG_FILE' will be used.
It is an error if client logging is already on. */
char mname[] = "d_client_log_on";
d_header(mname);
if (logman_is_active())
{
d_out("%s:logging already on", mname);
return;
}
if (command_words(comm) > 1)
{
if (!command_word(comm, d_log_file, 2))
{
d_out("%s:error getting log file name", mname);
return;
}
}
else
strcpy(d_log_file, DUM_LOG_FILE);
if (logman_start(d_log_file, APNAME))
{
d_out("%s:error starting logging", mname);
return;
}
if (logman_is_active())
logman("%s:normal exit[0]", mname);
else
printf("ok\n");
}
void d_client_log_off(void)
{
/* Turn client logging off. Syntax:
client.log.off
It is an error if client logging is already off. */
char mname[] = "d_client_log_off";
d_header(mname);
if (!logman_is_active())
{
d_out("%s:log already off", mname);
return;
}
if (logman_is_active())
logman("%s:normal exit[0]", mname);
else
printf("ok\n");
logman_end();
}
void d_client_log_status(void)
{
/* Display status of client logging. Syntax:
client.log.status */
char mname[] = "d_client_log_status";
d_header(mname);
if (logman_is_active())
logman("%s:client log is on", mname);
else
printf("%s:client log is off\nok\n", mname);
}
void d_server_log_on(char *comm)
{
/* Tell server to turn its logging on. Syntax:
server.log.on[ log_fname]
If no 'log_fname' is given, the default sever log file
name will be used. It is an error if server logging is
already on. */
char mname[] = "d_server_log_on";
char tmp[256], slog[256];
int ret;
d_header(mname);
if (command_words(comm) > 1)
{
if (!command_word(comm, tmp, 2))
{
d_out("%s:error getting server log file name", mname);
return;
}
if (words(tmp) > 1)
sprintf(slog, "'%s'", tmp);
else
strcpy(slog, tmp);
ret = d_sr_code(DM_SEND_LOG_ON, slog);
}
else
ret = d_sr_code(DM_SEND_LOG_ON, (char *)NULL);
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
else
{
d_code_string(ret, tmp);
printf("%s\n", tmp);
}
}
void d_server_log_off(void)
{
/* Tell server to turn its logging off. Syntax:
server.log.off
It is an error if the server log is already off. */
char mname[] = "d_server_log_off";
char mes[128];
int ret;
d_header(mname);
ret = d_sr_code(DM_SEND_LOG_OFF, (char *)NULL);
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
else
{
d_code_string(ret, mes);
printf("%s\n", mes);
}
}
void d_server_log_status(void)
{
/* Get status of server logging. Syntax:
server.log.status */
char mname[] = "d_server_log_status";
char mes[128];
int ret;
d_header(mname);
ret = d_sr_char(DM_SEND_LOG_STATUS, (char *)NULL, mes);
if (ret == DM_OK)
d_out("%s:log status is '%s'", mname, mes);
d_code_string(ret, mes);
if (logman_is_active())
logman("%s:normal exit,rc[%d]", mname, ret);
else
{
d_code_string(ret, mes);
printf("%s\n", mes);
}
}
#ifdef IPC_TCP
void d_socloc_log_on(char *comm)
{
/* Tell 'socloc' server to turn its logging on. Syntax:
socloc.log.on[ log_fname]
If no 'log_fname' is given, the default sever log file
name will be used. It is an error if server logging is
already on. */
char mname[] = "d_socloc_log_on";
char tmp[256], slog[256];
int ret;
d_header(mname);
if (command_words(comm) > 1)
{
if (!command_word(comm, tmp, 2))
{
d_out("%s:error getting server log file name", mname);
return;
}
if (words(tmp) > 1)
sprintf(slog, "'%s'", tmp);
else
strcpy(slog, tmp);
ret = sloc_log_on(slog);
}
else
ret = sloc_log_on((char *)NULL);
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
else
{
sl_code_string(ret, tmp);
printf("%s\n", tmp);
}
}
#endif
#ifdef IPC_TCP
void d_socloc_log_off(void)
{
/* Tell 'socloc' server to turn its logging off. Syntax:
socloc.log.off
It is an error if the server log is already off. */
char mname[] = "d_socloc_log_off";
char mes[128];
int ret;
d_header(mname);
ret = sloc_log_off();
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
else
{
sl_code_string(ret, mes);
printf("%s\n", mes);
}
}
#endif
#ifdef IPC_TCP
void d_socloc_log_status(void)
{
/* Get status of 'socloc' server logging. Syntax:
socloc.log.status */
char mname[] = "d_socloc_log_status";
char mes[128];
int ret, lflag;
d_header(mname);
ret = sloc_log_status(&lflag, mes);
if (ret != SL_OK)
{
if (logman_is_active())
logman("%s:normal exit,rc[%d]", mname, ret);
else
{
sl_code_string(ret, mes);
printf("%s\n", mes);
}
return;
}
if (lflag)
d_out("%s:socloc server log is active,log is %s", mname, mes);
else
d_out("%s:socloc server log is inactive,log is %s", mname, mes);
if (logman_is_active())
logman("%s:normal exit,rc[0]", mname);
}
#endif
void d_connect(char *comm)
{
/* Connect to any 'dumsocks' server. TCP syntax is:
connect [host host_name][ port port_num][ ip ip_ad]
QNX message passing syntax is:
connect
All parameters except 'connect' keyword are optional (TCP oly). If no
server details are supplied, a re-connect will be attempted
to the first 'dumsocks' server. */
char mname[] = "d_connect";
char mes[128], *hname, *ip_ad;
int pos, ret, port, nwords;
d_header(mname);
#ifdef IPC_TCP
nwords = command_words(comm);
if (nwords < 2)
{
/* if only 'connect' keyword, re-lookup first 'dumsocks' server */
if ((ret = sloc_find(DM_SERVICE_NAME, serverhost, &serverport,
(char *)NULL)) != SL_OK)
{
d_out("%s:bad rc[%d] from 'sloc_find'", mname, ret);
return;
}
d_status();
return;
}
/* alloc details */
if ((hname = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[hname]", mname);
return;
}
if ((ip_ad = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[ip_ad]", mname);
free(hname);
return;
}
/* 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 the connect string */
if ((ret = sconnect_parse(&comm[pos], FALSE, (char *)NULL, hname,
&port, ip_ad)) != SP_OK)
{
sp_code_string(ret, mes);
d_out("%s:bad rc[%d,%s] from 'sconnect_parse'", mname, ret, mes);
free(hname);
free(ip_ad);
return;
}
/* locate the 'dumsocks' server based on supplied details */
if ((ret = sloc_ll_find(DM_SERVICE_NAME, hname, &port, ip_ad)) != SL_OK)
{
sl_code_string(ret, mes);
d_out("%s:bad rc[%d,%s] from 'sloc_ll_find'", mname, ret, mes);
free(hname);
free(ip_ad);
return;
}
strcpy(serverhost, hname);
serverport = port;
if (!ipc_set_active(serverhost, serverport))
{
d_out("%s:bad rc[FALSE] from 'ipc_set_active'", mname);
free(hname);
free(ip_ad);
return;
}
#else
if (!ipc_set_active(DM_SERVICE_NAME))
{
d_out("%s:bad rc[FALSE] from 'ipc_set_active'", mname);
return;
}
connected_flag = TRUE;
#endif
d_status();
#ifdef IPC_TCP
free(hname);
free(ip_ad);
#endif
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
}
#ifdef IPC_TCP
void d_socloc_get_list(void)
{
/* Get the list of available 'dumsocks' servers from 'socloc'.
Syntax:
socloc.get.list */
char mname[] = "d_socloc_get_list";
char *list_out, *entry, *hname, *port_char, *ip_ad;
int ret, nentries, i;
d_header(mname);
if ((list_out = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[list_out]", mname);
return;
}
ret = sloc_find_list(DM_SERVICE_NAME, list_out);
if (ret == DM_OK)
{
d_out("current 'dumsocks' servers");
nentries = ll_words(list_out, SL_LIST_DELIM);
if ((entry = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[entry]", mname);
free(list_out);
return;
}
if ((hname = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[hname]", mname);
free(list_out);
free(entry);
return;
}
if ((port_char = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[port_char]", mname);
free(list_out);
free(entry);
free(hname);
return;
}
if ((ip_ad = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[ip_ad]", mname);
free(list_out);
free(entry);
free(hname);
free(port_char);
return;
}
for(i = 1; i <= nentries; i++)
{
if (!ll_word(list_out, entry, i, SL_LIST_DELIM))
{
d_out("%s:error geting list entry[%d]", mname, i);
free(list_out);
free(entry);
free(hname);
free(port_char);
free(ip_ad);
return;
}
/* service name is first command word, we bypass this */
if (!command_word(entry, hname, 2))
{
d_out("%s:error getting host from entry[%d]", mname, i);
free(list_out);
free(entry);
free(hname);
free(port_char);
free(ip_ad);
return;
}
if (!command_word(entry, port_char, 3))
{
d_out("%s:error getting port from entry[%d]", mname, i);
free(list_out);
free(entry);
free(hname);
free(port_char);
free(ip_ad);
return;
}
if (command_words(entry) > 3)
{
if (!command_word(entry, ip_ad, 4))
{
d_out("%s:error getting ip from entry[%d]", mname, i);
free(list_out);
free(entry);
free(hname);
free(port_char);
free(ip_ad);
return;
}
}
else
ip_ad[0] = EOS;
if (strlen(ip_ad))
d_out("dumsocks[%d]:host=%s,port=%s,ip=%s", i, hname,
port_char, ip_ad);
else
d_out("dumsocks[%d]:host=%s,port=%s", i, hname, port_char);
}
free(entry);
free(hname);
free(port_char);
free(ip_ad);
}
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
else
{
sl_code_string(ret, list_out);
printf("%s\n", list_out);
}
free(list_out);
}
#endif
#ifdef IPC_TCP
void d_socloc_config_get_list(void)
{
/* Get the list of available 'socloc' servers.
Syntax:
socloc.config.get.list */
char mname[] = "d_socloc_config_get_list";
char *list_out, *entry, *hname, *port_char, *ip_ad;
int ret, nentries, i;
d_header(mname);
if ((list_out = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[list_out]", mname);
return;
}
ret = sloc_config_get_list(list_out);
if (ret == DM_OK)
{
d_out("current 'socloc' servers");
nentries = ll_words(list_out, SL_LIST_DELIM);
if ((entry = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[entry]", mname);
free(list_out);
return;
}
if ((hname = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[hname]", mname);
free(list_out);
free(entry);
return;
}
if ((port_char = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[port_char]", mname);
free(list_out);
free(entry);
free(hname);
return;
}
if ((ip_ad = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
d_out("%s:alloc fail[ip_ad]", mname);
free(list_out);
free(entry);
free(hname);
free(port_char);
return;
}
for(i = 1; i <= nentries; i++)
{
if (!ll_word(list_out, entry, i, SL_LIST_DELIM))
{
d_out("%s:error geting list entry[%d]", mname, i);
free(list_out);
free(entry);
free(hname);
free(port_char);
free(ip_ad);
return;
}
if (!command_word(entry, hname, 1))
{
d_out("%s:error getting host from entry[%d]", mname, i);
free(list_out);
free(entry);
free(hname);
free(port_char);
free(ip_ad);
return;
}
if (!command_word(entry, port_char, 2))
{
d_out("%s:error getting port from entry[%d]", mname, i);
free(list_out);
free(entry);
free(hname);
free(port_char);
free(ip_ad);
return;
}
if (command_words(entry) > 2)
{
if (!command_word(entry, ip_ad, 3))
{
d_out("%s:error getting ip from entry[%d]", mname, i);
free(list_out);
free(entry);
free(hname);
free(port_char);
free(ip_ad);
return;
}
}
else
ip_ad[0] = EOS;
if (strlen(ip_ad))
d_out("socloc[%d]:host=%s,port=%s,ip=%s", i, hname,
port_char, ip_ad);
else
d_out("socloc[%d]:host=%s,port=%s", i, hname, port_char);
}
free(entry);
free(hname);
free(port_char);
free(ip_ad);
}
if (logman_is_active())
logman("%s:normal exit rc[%d]", mname, ret);
else
{
sl_code_string(ret, list_out);
printf("%s\n", list_out);
}
free(list_out);
}
#endif
#ifdef IPC_TCP
void d_socloc_get(void)
{
/* Get and display the current 'socloc' server. Syntax:
socloc.get */
char mname[] = "d_socloc_get";
char hname[256];
int port;
d_header(mname);
hname[0] = EOS;
port = 0;
sloc_get_active_socloc(hname, &port);
if (strlen(hname))
d_out("connected to 'socloc' server '%s' on port %d", hname, port);
else
d_out("no current 'socloc' server");
logman("%s:normal exit", mname);
}
#endif
#ifdef IPC_TCP
void d_socloc_version(void)
{
/* Get the version ID of the current 'socloc' server.
Syntax:
socloc.version */
char mname[] = "d_socloc_version";
char versionid[128];
int ret;
d_header(mname);
ret = sloc_version(versionid);
if (ret == SL_OK)
d_out("'socloc' version ID is '%s'", versionid);
else
{
sl_code_string(ret, versionid);
d_out("%s", versionid);
}
logman("%s:normal exit,rc[%d]", mname, ret);
}
#endif
void d_version(void)
{
/* Get the 'dumsocks' server version ID. Syntax:
version */
char mname[] = "d_version";
char versionid[128];
int ret;
d_header(mname);
ret = d_sr_char(DM_SEND_VERSION, (char *)NULL, versionid);
if (ret == DM_OK)
d_out("'dumsocks' version ID is '%s'", versionid);
else
{
d_code_string(ret, versionid);
d_out("%s", versionid);
}
logman("%s:normal exit,rc[%d]", mname, ret);
}
void d_trans_num(void)
{
/* Get the 'dumsocks' server transaction count. Syntax:
trans.num */
char mname[] = "d_trans_num", mes[150];
long trans_num;
int ret;
d_header(mname);
ret = d_sr_long(DM_SEND_TRANS_NUM, (char *)NULL, &trans_num);
if (ret == DM_OK)
d_out("dumsocks transaction count is %ld", trans_num);
else
{
d_code_string(ret, mes);
d_out("%s", mes);
}
logman("%s:normal exit,rc[%d]", mname, ret);
}
void d_connect_num(void)
{
/* Get the 'dumsocks' server connection count. Syntax:
connect.num */
char mname[] = "d_connect_num", mes[150];
int ret, connect_num;
d_header(mname);
ret = d_sr_int(DM_SEND_CONNECT_NUM, (char *)NULL, &connect_num);
if (ret == DM_OK)
d_out("dumsocks connection count is %d", connect_num);
else
{
d_code_string(ret, mes);
d_out("%s", mes);
}
logman("%s:normal exit,rc[%d]", mname, ret);
}
#ifdef IPC_TCP
void d_socloc_trans_num(void)
{
/* Get the current transaction count from the 'socloc' server. Syntax:
socloc.trans.num */
char mname[] = "d_socloc_trans_num", mes[128];
long trans_num;
int ret;
d_header(mname);
ret = sloc_trans_num(&trans_num);
if (ret != SL_OK)
{
if (logman_is_active())
logman("%s:normal exit,rc[%d]", mname, ret);
else
{
sl_code_string(ret, mes);
d_out("%s", mes);
}
return;
}
d_out("%s:current socloc transaction count is %ld", mname, trans_num);
if (logman_is_active())
logman("%s:normal exit,rc[0]", mname);
}
void d_socloc_connect_num(void)
{
/* Get the current connection count from the 'socloc' server. Syntax:
socloc.connect.num */
char mname[] = "d_socloc_connect_num", mes[128];
int ret, connect_num;
d_header(mname);
ret = sloc_connect_num(&connect_num);
if (ret != SL_OK)
{
if (logman_is_active())
logman("%s:normal exit,rc[%d]", mname, ret);
else
{
sl_code_string(ret, mes);
d_out("%s", mes);
}
return;
}
d_out("%s:current socloc connection count is %d", mname, connect_num);
if (logman_is_active())
logman("%s:normal exit,rc[0]", mname);
}
#endif
#ifdef IPC_QNX
void d_tcp_only(void)
{
d_out("applies to TCP IPC method only");
}
#endif
int d_sr_code(int typ, char *parm)
{
/* Send a message to the server which will return just a code. */
char reply[50], mname[] = "d_sr_code";
int ret;
d_header(mname);
#ifdef IPC_TCP
ret = d_sr(typ, parm, reply);
#else
ret = d_sr(typ, parm, reply, 50);
#endif
if (ret == DM_OK)
if (!qatoi(reply, &ret))
return(DM_INTERNAL_ERROR);
d_code_string(ret, reply);
logman("%s:normal exit[%s]", mname, reply);
return(ret);
}
int d_sr_int(int typ, char *parm, int *ival)
{
/* Send a message to the server which will return an integer
value as well as the 'dumsocks' code. */
char reply[50], anint[50];
int ret;
#ifdef IPC_TCP
ret = d_sr(typ, parm, reply);
#else
ret = d_sr(typ, parm, reply, 50);
#endif
if (ret == DM_OK)
{
if (words(reply) < 2)
return(DM_INTERNAL_ERROR);
if (!word(reply, anint, 1))
return(DM_INTERNAL_ERROR);
if (!qatoi(anint, &ret))
return(DM_INTERNAL_ERROR);
if (!word(reply, anint, 2))
return(DM_INTERNAL_ERROR);
if (!qatoi(anint, ival))
return(DM_INTERNAL_ERROR);
}
return(ret);
}
int d_sr_long(int typ, char *parm, long *lval)
{
/* Send a message to the server which will return a long integer
value as well as the 'dumsocks' code. */
char reply[100], along[50];
int ret;
#ifdef IPC_TCP
ret = d_sr(typ, parm, reply);
#else
ret = d_sr(typ, parm, reply, 100);
#endif
if (ret == DM_OK)
{
if (words(reply) < 2)
return(DM_INTERNAL_ERROR);
if (!word(reply, along, 1))
return(DM_INTERNAL_ERROR);
if (!qatoi(along, &ret))
return(DM_INTERNAL_ERROR);
if (!word(reply, along, 2))
return(DM_INTERNAL_ERROR);
if (!qatol(along, lval))
return(DM_INTERNAL_ERROR);
}
return(ret);
}
int d_sr_char(int typ, char *parm, char *reply)
{
/* Send a message to the server which will return a string in
addition to the 'dumsocks' code. */
char *tmp, ival[25], mname[] = "d_sr_char";
int ret;
d_header(mname);
if ((tmp = (char *)malloc(DM_MAXCOMMAND)) == NULL)
{
logman("%s:alloc fail[tmp]", mname);
return(DM_MEMORY_FAIL);
}
#ifdef IPC_TCP
ret = d_sr(typ, parm, tmp);
#else
ret = d_sr(typ, parm, tmp, DM_MAXCOMMAND);
#endif
logman("%s:reply=%s,l=%d", mname, tmp, strlen(tmp));
if (ret == DM_OK)
{
if (command_words(tmp) < 2)
{
free(tmp);
return(DM_INTERNAL_ERROR);
}
if (!command_word(tmp, ival, 1))
{
free(tmp);
return(DM_INTERNAL_ERROR);
}
if (!qatoi(ival, &ret))
{
free(tmp);
return(DM_INTERNAL_ERROR);
}
if (!command_word(tmp, reply, 2))
{
free(tmp);
return(DM_INTERNAL_ERROR);
}
}
d_code_string(ret, tmp);
logman("%s:normal exit[%s]", mname, tmp);
free(tmp);
return(ret);
}
#ifdef IPC_TCP
int d_sr(int typ, char *parm, char *reply)
#else
int d_sr(int typ, char *parm, char *reply, int size_reply)
#endif
{
/* Send and receive a message to the server. Its ok if 'parm'
is NULL or empty. Upon success, server reply load loaded
into 'reply' which must be already allocated to
sufficient size. Function returns a 'dumsocks' code. */
char mname[] = "d_sr";
char *mess;
logman("%s:enter", mname);
/* make sure we are connected */
if (!is_connected())
{
logman("%s:not connected to any 'dumsocks' server", mname);
return(DM_NO_SERVER);
}
if ((mess = (char *)malloc(DM_MAXCOMMAND)) == (char *)NULL)
{
logman("%s:alloc fail[mess]", mname);
return(DM_MEMORY_FAIL);
}
memset(mess, 0, DM_MAXCOMMAND);
// format send string
if (parm == (char *)NULL || !strlen(parm))
sprintf(mess, "%d", typ);
else
sprintf(mess, "%d %s", typ, parm);
logman("%s:send buf=%s,l=%d", mname, mess, strlen(mess));
#ifdef IPC_TCP
if (!ipc_send_receive(mess, reply))
#else
if (!ipc_send_receive(mess, reply, size_reply))
#endif
{
logman("%s:error communicating with server", mname);
free(mess);
#ifdef IPC_TCP
d_failover(TRUE);
#else
connected_flag = FALSE;
#endif
return(DM_VC_ERROR);
}
free(mess);
logman("%s:normal exit,rc[ok],reply=%s,l=%d", mname,
reply, strlen(reply));
return(DM_OK);
}
int is_connected(void)
{
/* Determine whether a 'dumsocks' server is active.
Function returns 'TRUE' if a server is active,
'FALSE' otherwise. */
#ifdef IPC_TCP
if (serverport > 0)
return(TRUE);
#else
if (connected_flag)
return(TRUE);
#endif
return(FALSE);
}
#ifdef IPC_TCP
void d_failover(int dflag)
{
/* Failover to another 'dumsocks' server. The flag 'dflag'
indicates whether we should get 'socloc' to delete the
old entry. */
char mname[] = "d_failover";
char mes[138];
int ret;
d_header(mname);
if (dflag)
if ((ret = sloc_delete(serverport)) != SL_OK)
{
sl_code_string(ret, mes);
d_out("%s:bad rc[%s] from 'sloc_delete'", mname, mes);
}
if ((ret = sloc_find(DM_SERVICE_NAME, serverhost, &serverport,
(char *)NULL)) != SL_OK)
{
sl_code_string(ret, mes);
d_out("%s:bad rc[%s] from 'sloc_find'", mname, mes);
return;
}
if (!ipc_set_active(serverhost, serverport))
{
d_out("%s:bad rc[FALSE] from 'ipc_set_active'", mname);
return;
}
if (logman_is_active())
logman("%s:normal exit,failover ok,h=%s,p=%d", mname,
serverhost, serverport);
else
printf("failover to host '%s' on port %d successful\n",
serverhost, serverport);
}
#endif
void d_code_string(int ret, char *mes)
{
/* Translate a 'dumsocks' return code to English. 'mes' must
already be allocated to sufficient size. */
switch(ret)
{
case DM_OK:
strcpy(mes, "ok");
break;
case DM_ACCESS_DENIED:
strcpy(mes, "access denied");
break;
case DM_MEMORY_FAIL:
strcpy(mes, "memory allocation error");
break;
case DM_INVALID_FUNCTION:
strcpy(mes, "invalid function");
break;
case DM_INTERNAL_ERROR:
strcpy(mes, "internal server error");
break;
case DM_INVALID_PARAMETER:
strcpy(mes, "invalid parameter");
break;
case DM_VC_ERROR:
strcpy(mes, "socket communication error");
break;
case DM_LOG_ALREADY_OFF:
strcpy(mes, "log already off");
break;
case DM_LOG_ALREADY_ON:
strcpy(mes, "log already on");
break;
case DM_NO_SERVER:
strcpy(mes, "not connected to dumsocks server");
break;
case DM_NOT_FOUND:
strcpy(mes, "not found");
break;
case DM_LOG_ERROR:
strcpy(mes, "error writing to log file");
break;
case DM_NOT_IMPLEMENTED:
strcpy(mes, "not implemented");
break;
default:
strcpy(mes, "unknown code");
};
}
int get_token(char *keywrd)
{
/* Get keyword token. */
char mname[] = "get_token";
int i;
int token = DMCOM_NOT_FOUND;
/* static array of command words, notice the dummy zero position */
static char *coms[] = { " ", "TERM", "STATUS", "CLIENT.LOG.OFF",
"CLIENT.LOG.ON", "CLIENT.LOG.STATUS",
"SERVER.LOG.OFF", "SERVER.LOG.ON",
"SERVER.LOG.STATUS", "CONNECT",
"SOCLOC.GET.LIST", "SOCLOC.CONFIG.GET.LIST",
"SOCLOC.GET", "SOCLOC.LOG.OFF",
"SOCLOC.LOG.ON", "SOCLOC.LOG.STATUS",
"SOCLOC.VERSION", "VERSION", "TRANS.NUM",
"CONNECT.NUM", "SOCLOC.TRANS.NUM",
"SOCLOC.CONNECT.NUM" };
logman("%s:enter,keywrd='%s'", mname, keywrd);
/* check for 'OFF' keyword separately */
if (!stricmp(keywrd, "OFF"))
{
logman("%s:found 'OFF' keyword", mname);
return(DMCOM_OFF);
}
for(i = 1; i <= DMCOM_MAXCOM; i++)
if (!stricmp(keywrd, coms[i]))
{
token = i;
break;
}
logman("%s:normal exit,token=%d", mname, token);
return(token);
}
void d_header(char *mname)
{
/* Output the function enter header if logging. */
#ifdef IPC_TCP
if (strlen(serverhost) && serverport != 0)
logman("%s:enter,sh=%s,sp=%d", mname, serverhost, serverport);
else
logman("%s:enter,no connection", mname);
#else
logman("%s:enter", mname);
#endif
}
void d_out(char *fmt,...)
{
/* Output a message to the screen or use 'logman' to
log the message. Output method depends on personal (client)
logging status. Do not put a cr/lf at the end of the message.
This will be automatically written to the end of the message. */
char mes[MAXMES];
va_list argptr;
va_start(argptr, fmt);
vsprintf(mes, fmt, argptr);
if (logman_is_active())
logman_nf(mes);
else
printf("%s\n", mes);
}
void term_app(void)
{
// Shutdown all API's.
if (logman_is_active())
logman_end();
#ifdef IPC_TCP
ipc_close();
sloc_term_api();
#ifdef OS_WIN32
WSACleanup();
#endif
#endif
(void)appinit_remove_name();
}