## root/socloc/slocsrv.c

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

## DEFINITIONS

This source file includes following definitions.

1. sloc_custom_status
2. sloc_get_list
3. sloc_config_get_list
4. sloc_bcast_add
5. sloc_bcast_delete
6. sloc_bcast_config_add
7. sloc_bcast_config_delete
8. sloc_get_active_socloc
9. sloc_find_first_active
10. sloc_is_init
11. sloc_ll_status
12. sloc_sr_code
13. sloc_sr_char
14. sloc_client_connect

    /* A communications module for the socket locate service server.
       This module is used only by 'socloc' servers to talk to
       other 'socloc' servers. Applies to TCP socket IPC method only.
       Rick Smereka, Copyright (C) 2003.

       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 module was constructed to enable a 'socloc' server to communicate
       with other 'socloc' and socket servers without using the standard 'socloc'
       client API. It was found that having both client applications and
       'socloc' servers using the standard 'socloc' API ('sloc.c') was
       causing too many interactions. Since a specific 'socloc' server
       may talk to a number of other 'socloc' servers along with any
       number of socket servers, this API does not follow the model of
       other Future Lab socket API's. Instead of connecting to another
       server and leaving the socket open, this API performs a 'connect',
       send, receive and a disconnect once per request.

       Original Linux version. May/2003, Rick Smereka

       Ported to 32-bit Windows, Jun/2003, Rick Smereka */

    #include "stdhead.h"          // standard include
    #include "flsocket.h"         // standard socket defines
    #include "ipcomm.h"           // low level socket send/receive
    #include "slocsrv.h"          // this module
    #include "socloc.h"           // global socket locator defines
    #include "slconfig.h"         // socket locate config management
    #include "ip.h"               // IP library routines

    // global (to module) data

    #ifdef OS_WIN32
    SOCKET slclientSocket;        // client socket
    SOCKADDR_IN slsockClientAddr; // client address structure
    LPHOSTENT lpHostEnt;          // host info structure
    #endif

    #ifdef OS_UNIX
    int slclientSocket;
    struct sockaddr_in slsockClientAddr;
    struct hostent *lpHostEnt;
    #endif

    char sloc_hostname[128];      // host name of 'socloc' server
    int sloc_port = 0;            // port 'socloc' is using

    // private functions

    static int sloc_ll_status(void);
    static int sloc_sr_code(int, char *);
    static int sloc_sr_char(int, char *, char *);
    static int sloc_client_connect(void);

    int sloc_custom_status(char *hname, int port)
    {
       /* Query the status of any socket server on any port.
          Socket server must understand the status command
          code (see 'flsocket.h'). Function returns
          'SL_OK' if the server is responding, a 'socloc'
          code otherwise. */

       char mname[] = "sloc_custom_status";
       char thost[128];
       int ret, tport;

       log_file_date("%s:enter", mname);

       if (hname == (char *)NULL || !strlen(hname))
          {
          log_file_date("%s:null or empty[hname]", mname);
          return(SL_INVALID_PARAMETER);
          }

       if (port <= 0)
          {
          log_file_date("%s:out of range[port]", mname);
          return(SL_INVALID_PARAMETER);
          }

       /* save current host name and port */

       strcpy(thost, sloc_hostname);
       tport = sloc_port;

       /* load new values */

       strcpy(sloc_hostname, hname);
       sloc_port = port;

       /* call low level status */

       if ((ret = sloc_ll_status()) != SL_OK)
          {
          log_file_date("%s:bad rc[%d] from sloc_ll_status", mname, ret);
          strcpy(sloc_hostname, thost);
          sloc_port = tport;
          return(ret);
          }

       log_file_date("%s:normal exit[%d]", mname, ret);
       strcpy(sloc_hostname, thost);
       sloc_port = tport;
       return(ret);
    }

    int sloc_get_list(char *list_out)
    {
       /* Get the 'socloc' list. The delimited list is
          returned in 'list_out' which must already be allocated
          by the caller to sufficient size. Function returns
          'SL_OK' upon success, a 'socloc' code otherwise. */

       char mname[] = "sloc_get_list";
       int ret;

       log_file_date("%s:enter", mname);

       if (list_out == (char *)NULL)
          {
          log_file_date("%s:null[list_out]", mname);
          return(SL_INVALID_PARAMETER);
          }

       ret = sloc_sr_char(SL_SEND_GET_LIST, (char *)NULL, list_out);
       log_file_date("%s:normal exit[%d]", mname, ret);
       return(ret);
    }

    int sloc_config_get_list(char *list_out)
    {
       /* Get the 'socloc' config list. The delimited list is
          returned in 'list_out' which must already be allocated
          by the caller to sufficient size. Function returns
          'SL_OK' upon success, a 'socloc' code otherwise. */

       char mname[] = "sloc_config_get_list";
       int ret;

       log_file_date("%s:enter", mname);

       if (list_out == (char *)NULL)
          {
          log_file_date("%s:null[list_out]", mname);
          return(SL_INVALID_PARAMETER);
          }

       ret = sloc_sr_char(SL_SEND_CONFIG_GET_LIST, (char *)NULL, list_out);
       log_file_date("%s:normal exit[%d]", mname, ret);
       return(ret);
    }

    int sloc_bcast_add(char *sname, char *hname, int port, char *ip_ad)
    {
       /* Send an add command to each known 'socloc' server.
          This function should only be used by a 'socloc' server.
          Note that it is not considered an error if a 'socloc'
          server does not respond or responds with an error.
          Function returns a 'socloc' code. */

       char mname[] = "sloc_bcast_add";
       char thost[128], *aentry;
       int tport, nentries, i, ret;

       log_file_date("%s:enter", mname);

       if (sname == (char *)NULL || !strlen(sname))
          {
          log_file_date("%s:null or empty[sname]", mname);
          return(SL_INVALID_PARAMETER);
          }

       if (hname == (char *)NULL || !strlen(hname))
          {
          log_file_date("%s:null or empty[hname]", mname);
          return(SL_INVALID_PARAMETER);
          }

       if (port <= 0)
          {
          log_file_date("%s:out of range[port]", mname);
          return(SL_INVALID_PARAMETER);
          }

       /* save current server host name and port */

       strcpy(thost, sloc_hostname);
       tport = sloc_port;

       if ((ret = sl_config_get_nentries(&nentries)) != SL_OK)
          {
          log_file_date("%s:bad rc[%d] from sl_config_get_nentries", mname, ret);
          return(ret);
          }

       log_file_date("%s:number of config entries is %d", mname, nentries);

       if ((aentry = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[aentry]", mname);
          return(SL_MEMORY_FAIL);
          }

       if (ip_ad != (char *)NULL && strlen(ip_ad))
          sprintf(aentry, "0 '%s' '%s' %d %s", sname, hname, port, ip_ad);
       else
          sprintf(aentry, "0 '%s' '%s' %d", sname, hname, port);

       /* go through list of servers, sending an add command to each
          with the 'orig_flag' set to a server (0) */

       for(i = 1; i <= nentries; i++)
          {
          if ((ret = sl_config_get_nth(i, sloc_hostname, &sloc_port, (char *)NULL))
              == SL_OK)
             {
             ret = sloc_sr_code(SL_SEND_ADD, aentry);
             log_file_date("%s[%s,%d]rc=%d", mname, sloc_hostname, sloc_port, ret);
             }
          }

       /* put back current entry */

       strcpy(sloc_hostname, thost);
       sloc_port = tport;
       free(aentry);
       log_file_date("%s:normal exit[0]", mname);
       return(SL_OK);
    }

    int sloc_bcast_delete(int port)
    {
       /* Send a delete command to each known 'socloc' server.
          This function should only be used by a 'socloc' server.
          Note that it is not considered an error if a 'socloc'
          server does not respond or responds with an error.
          Function returns a 'socloc' code. */

       char mname[] = "sloc_bcast_delete";
       char thost[128], *aentry;
       int tport, nentries, i, ret;

       log_file_date("%s:enter,port=%d", mname, port);

       if (port <= 0)
          {
          log_file_date("%s:out of range[port]", mname);
          return(SL_INVALID_PARAMETER);
          }

       /* save current server host name and port */

       strcpy(thost, sloc_hostname);
       tport = sloc_port;

       if ((ret = sl_config_get_nentries(&nentries)) != SL_OK)
          {
          log_file_date("%s:bad rc[%d] from sl_config_get_nentries", mname, ret);
          return(ret);
          }

       log_file_date("%s:number of config entries is %d", mname, nentries);

       if ((aentry = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[aentry]", mname);
          return(SL_MEMORY_FAIL);
          }

       /* indicate a server send with the initial 'orig_flag' set to zero */

       sprintf(aentry, "0 %d", port);

       /* go through list of servers, sending a config add command to each */

       for(i = 1; i <= nentries; i++)
          {
          if ((ret = sl_config_get_nth(i, sloc_hostname, &sloc_port, (char *)NULL))
              == SL_OK)
             {
             ret = sloc_sr_code(SL_SEND_DELETE, aentry);
             log_file_date("%s[%s,%d]rc=%d", mname, sloc_hostname, sloc_port, ret);
             }
          }

       /* put back current entry */

       strcpy(sloc_hostname, thost);
       sloc_port = tport;
       free(aentry);
       log_file_date("%s:normal exit[0]", mname);
       return(SL_OK);
    }

    int sloc_bcast_config_add(char *hname, int port, char *ip_ad)
    {
       /* Send a config add command to each known 'socloc' server.
          This function should only be used by a 'socloc' server.
          Note that it is not considered an error if a 'socloc'
          server does not respond or responds with an error.
          Function returns a 'socloc' code. */

       char mname[] = "sloc_bcast_config_add";
       char thost[128], *aentry;
       int tport, nentries, i, ret;

       log_file_date("%s:enter", mname);

       if (hname == (char *)NULL || !strlen(hname))
          {
          log_file_date("%s:null or empty[hname]", mname);
          return(SL_INVALID_PARAMETER);
          }

       if (port <= 0)
          {
          log_file_date("%s:out of range[port]", mname);
          return(SL_INVALID_PARAMETER);
          }

       /* save current server host name and port */

       strcpy(thost, sloc_hostname);
       tport = sloc_port;

       if ((ret = sl_config_get_nentries(&nentries)) != SL_OK)
          {
          log_file_date("%s:bad rc[%d] from sl_config_get_nentries", mname, ret);
          return(ret);
          }

       log_file_date("%s:number of config entries is %d", mname, nentries);

       if ((aentry = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[aentry]", mname);
          return(SL_MEMORY_FAIL);
          }

       /* indicate a server send with the initial 'orig_flag' set to zero */

       if (ip_ad != (char *)NULL && strlen(ip_ad))
          sprintf(aentry, "0 '%s' %d %s", hname, port, ip_ad);
       else
          sprintf(aentry, "0 '%s' %d", hname, port);

       /* go through list of servers, sending a config add command to each */

       for(i = 1; i <= nentries; i++)
          {
          if ((ret = sl_config_get_nth(i, sloc_hostname, &sloc_port, (char *)NULL))
              == SL_OK)
             {
             ret = sloc_sr_code(SL_SEND_CONFIG_ADD, aentry);
             log_file_date("%s[%s,%d]rc=%d", mname, sloc_hostname, sloc_port, ret);
             }
          }

       /* put back current entry */

       strcpy(sloc_hostname, thost);
       sloc_port = tport;
       free(aentry);
       log_file_date("%s:normal exit[0]", mname);
       return(SL_OK);
    }

    int sloc_bcast_config_delete(int port)
    {
       /* Send a config delete command to each known 'socloc' server.
          This function should only be used by a 'socloc' server.
          Note that it is not considered an error if a 'socloc'
          server does not respond or responds with an error.
          Function returns a 'socloc' code. */

       char mname[] = "sloc_bcast_config_delete";
       char thost[128], *aentry;
       int tport, nentries, i, ret;

       log_file_date("%s:enter", mname);

       if (port <= 0)
          {
          log_file_date("%s:out of range[port]", mname);
          return(SL_INVALID_PARAMETER);
          }

       /* save current server host name and port */

       strcpy(thost, sloc_hostname);
       tport = sloc_port;

       if ((ret = sl_config_get_nentries(&nentries)) != SL_OK)
          {
          log_file_date("%s:bad rc[%d] from sl_config_get_nentries", mname, ret);
          return(ret);
          }

       log_file_date("%s:number of config entries is %d", mname, nentries);

       if ((aentry = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[aentry]", mname);
          return(SL_MEMORY_FAIL);
          }

       sprintf(aentry, "0 %d", port);

       /* go through list of servers, sending a config add command to each */

       for(i = 1; i <= nentries; i++)
          {
          if ((ret = sl_config_get_nth(i, sloc_hostname, &sloc_port, (char *)NULL))
              == SL_OK)
             {
             ret = sloc_sr_code(SL_SEND_CONFIG_DELETE, aentry);
             log_file_date("%s[%s,%d]rc=%d", mname, sloc_hostname, sloc_port, ret);
             }
          }

       /* put back current entry */

       strcpy(sloc_hostname, thost);
       sloc_port = tport;
       free(aentry);
       log_file_date("%s:normal exit[0]", mname);
       return(SL_OK);
    }

    void sloc_get_active_socloc(char *hname, int *port)
    {
       /* Get and return the active 'socloc' server host name
          and port number. 'hname' must be allocated by the
          caller to sufficient size. */

       char mname[] = "sloc_get_active_socloc";

       if (hname == (char *)NULL || port == (int *)NULL)
          {
          log_file_date("%s:null[hname or port]", mname);
          return;
          }

       hname[0] = EOS;
       *port = 0;

       if (!strlen(sloc_hostname) || sloc_port == 0)
          {
          log_file_date("%s:no active server", mname);
          return;
          }

       strcpy(hname, sloc_hostname);
       *port = sloc_port;
       log_file_date("%s:normal exit", mname);
    }

    int sloc_find_first_active(void)
    {
       /* Traverse through the list of socket locate servers and
          find the first one active. The active server host name
          and port number will be loaded into the globals
          'sloc_hostname' and 'sloc_port' upon success. Any entry
          in the list not found to be active will be deleted. Function
          returns 'SL_OK' upon success, a socket locate code
          otherwise. */

       char mname[] = "sloc_find_first_active";
       int nentries;
       int ret;

       log_file_date("%s:enter", mname);

       while(1)
          {
          if ((ret = sl_config_get_nentries(&nentries)) != SL_OK)
             {
             log_file_date("%s:bad rc[%d] from sl_config_get_nentries", mname, ret);
             return(ret);
             }

          log_file_date("%s:number of config entries is %d", mname, nentries);

          /* load host name and port number for this entry */

          if ((ret = sl_config_get_first(sloc_hostname, &sloc_port,
                                       (char *)NULL)) != SL_OK)
             {
             log_file_date("%s:bad rc[%d] from sl_config_get_first", mname, ret);
             return(ret);
             }

          log_file_date("%s:config entry:sloc_hostname=%s,sloc_port=%d",
                        mname, sloc_hostname, sloc_port);

          /* get status of server */

          if ((ret = sloc_ll_status()) == SL_OK)
             {
             log_file_date("%s:exit:server %s responding", mname, sloc_hostname);
             return(ret);
             }

          log_file_date("%s:server %s not responding", mname, sloc_hostname);

          /* if not responding delete entry */

          if ((ret = sl_config_delete(sloc_port)) != SL_OK)
             {
             log_file_date("%s:bad rc[%d] from sl_config_delete", mname, ret);
             return(ret);
             }
          }

       /* we should never get here but just in case */

       sloc_hostname[0] = EOS;
       sloc_port = 0;
       log_file_date("%s:unanticipated wacky exit,rc=%d", mname,
                     SL_NO_SUCH_SOCLOC);
       return(SL_NO_SUCH_SOCLOC);
    }

    int sloc_is_init(void)
    {
       /* Determine whether the 'socloc' API has been initialized.
          The API is considered initialized when there is an active
          host name in 'sloc_hostname' and a positive port number in
          'sloc_port'. Function returns 'SL_OK' if the API has been
          initialized, 'SL_NO_INIT' otherwise. */

       char mname[] = "sloc_is_init";
       int ret;

       log_file_date("%s:enter", mname);

       if (!sloc_port || sloc_hostname == (char *)NULL || !strlen(sloc_hostname))
          ret = SL_NO_INIT;
       else
          ret = SL_OK;

       log_file_date("%s:normal exit[%d]", mname, ret);
       return(ret);
    }

    /* private functions */

    static int sloc_ll_status(void)
    {
       /* Get the status from the current 'socloc' server.
          Function returns 'SL_OK' upon success, a 'socloc'
          code otherwise. */

       char mname[] = "sloc_ll_status";
       int ret;

       log_file_date("%s:enter:host=%s,port=%d", mname, sloc_hostname,
                     sloc_port);
       ret = sloc_sr_code(SL_SEND_STATUS, (char *)NULL);
       log_file_date("%s:normal exit[%d]", mname, ret);
       return(ret);
    }

    static int sloc_sr_code(int typ, char *parm)
    {
       /* Send and recveive a message to the 'socloc' server that returns
          only a return code. Its ok if 'parm' is NULL or empty.
          Function returns a 'socloc' code. */

       char mname[] = "sloc_sr_code", *mess;
       int len, full_len, ret;

       /* if init has not been called, exit error */

       if ((ret = sloc_is_init()) != SL_OK)
          {
          log_file_date("%s:no socloc server details", mname);
          return(ret);
          }

       // connect to defined server

       if ((ret = sloc_client_connect()) != SL_OK)
          {
          log_file_date("%s:bad rc[%d] from sloc_client_connect", mname, ret);
          return(ret);
          }

       // estimate length and alloc send/receive buffer

       len = (parm == (char *)NULL) ? 0 : strlen(parm);
       full_len = len + 5;

       if ((mess = (char *)malloc(full_len)) == (char *)NULL)
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:alloc fail[mess]", mname);
          return(SL_MEMORY_FAIL);
          }

       memset(mess, 0, full_len);

       // format send string

       if (parm == (char *)NULL || !len)
          sprintf(mess, "%d", typ);
       else
          sprintf(mess, "%d %s", typ, parm);

       // send message

       if (!ipc_send(slclientSocket, mess))
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:bad rc[FALSE] from ipc_send", mname);
          free(mess);
          return(SL_VC_ERROR);
          }

       memset(mess, 0, full_len);

       // receive return code

       if (!ipc_recv(slclientSocket, mess))
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:bad rc[FALSE] from ipc_recv", mname);
          free(mess);
          return(SL_VC_ERROR);
          }

       // make sure its a number

       if (!qatoi(mess, &ret))
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:bad rc[FALSE] from qatoi[wrd 1]", mname);
          free(mess);
          return(SL_INTERNAL_ERROR);
          }

       free(mess);

    #ifdef OS_WIN32
       (void)closesocket(slclientSocket);
    #else
       close(slclientSocket);
    #endif

       return(ret);
    }

    static int sloc_sr_char(int typ, char *parm, char *char_out)
    {
       /* Send and recveive a message to the 'socloc' server that returns a
          string as well as a return code. 'char_out' must already
          be allocated to sufficient size for the receiving string.
          Its ok if 'parm' is NULL or empty. Function returns a 'socloc' code. */

       char mname[] = "sloc_sr_char", *mess, tmp[50];
       int len, full_len, nwords, pos, ret;

       /* if init has not been called, exit error */

       if ((ret = sloc_is_init()) != SL_OK)
          {
          log_file_date("%s:no socloc server details", mname);
          return(ret);
          }

       char_out[0] = EOS;

       // connect to defined server

       if ((ret = sloc_client_connect()) != SL_OK)
          {
          log_file_date("%s:bad rc[%d] from sloc_client_connect", mname, ret);
          return(ret);
          }

       // estimate length and alloc send/receive buffer

       len = (parm == (char *)NULL) ? 0 : strlen(parm);
       full_len = len + 5;

       if ((mess = (char *)malloc(full_len)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[mess]", mname);
          return(SL_MEMORY_FAIL);
          }

       memset(mess, 0, full_len);

       // format send string

       if (parm == (char *)NULL || !len)
          sprintf(mess, "%d", typ);
       else
          sprintf(mess, "%d %s", typ, parm);

       // send message

       if (!ipc_send(slclientSocket, mess))
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:bad rc[FALSE] from ipc_send", mname);
          free(mess);
          return(SL_VC_ERROR);
          }

       free(mess);

       // re-allocate 'mess' for receive buffer (max size)

       if ((mess = (char *)malloc(SL_MAXCOMMAND)) == (char *)NULL)
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:alloc fail[mess]", mname);
          return(SL_MEMORY_FAIL);
          }

       memset(mess, 0, SL_MAXCOMMAND);

       // receive reply

       if (!ipc_recv(slclientSocket, mess))
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:bad rc[FALSE] from ipc_recv", mname);
          free(mess);
          return(SL_VC_ERROR);
          }

       // s/b two words in reply

       nwords = command_words(mess);

       // s/b reply code in word one

       if (!command_word(mess, tmp, 1))
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:bad rc[FALSE] from command_word[1]", mname);
          free(mess);
          return(SL_INTERNAL_ERROR);
          }

       // make sure its a number

       if (!qatoi(tmp, &ret))
          {
    #ifdef OS_WIN32
          (void)closesocket(slclientSocket);
    #else
          close(slclientSocket);
    #endif

          log_file_date("%s:bad rc[FALSE] from qatoi[wrd 1]", mname);
          free(mess);
          return(SL_INTERNAL_ERROR);
          }

       // if reply is 'ok', load 'char_out'

       if (ret == SL_OK)
          {
          if (nwords < 2)
             {
    #ifdef OS_WIN32
             (void)closesocket(slclientSocket);
    #else
             close(slclientSocket);
    #endif

             log_file_date("%s:expecting at least two words in reply", mname);
             free(mess);
             return(SL_INTERNAL_ERROR);
             }

          // 'char_value' is from the end of the first word

          if ((pos = command_indxword(mess, 2)) == -1)
             {
    #ifdef OS_WIN32
             (void)closesocket(slclientSocket);
    #else
             close(slclientSocket);
    #endif

             log_file_date("%s:bad rc[-1] from command_indxword[2]", mname);
             free(mess);
             return(SL_INTERNAL_ERROR);
             }

          /* if second command word starts with quote backup one */

          if (mess[pos - 1] == '\'' || mess[pos - 1] == '"')
             pos -= 1;

          len = strlen(mess) - pos;
          strncpy(char_out, &mess[pos], len);
          char_out[len] = EOS;
          }

       free(mess);

    #ifdef OS_WIN32
       (void)closesocket(slclientSocket);
    #else
       close(slclientSocket);
    #endif

       return(ret);
    }

    static int sloc_client_connect(void)
    {
       /* Connect to the 'socloc' server. An attempt to open the TCP
          socket is made. The host name 'sloc_hostname' and the
          TCP port 'sloc_port' are assumed to be already loaded
          Function returns 'SL_OK' if a successful connection was
          made, a 'socloc' code otherwise. Private function. */

       char mname[] = "sloc_client_connect";
       int ret;

       // make sure host name and port are loaded

       if ((ret = sloc_is_init()) != SL_OK)
          {
          log_file_date("%s:bad rc[%d] from sloc_is_init", mname, ret);
          return(ret);
          }

       // resolve server host name

       lpHostEnt = gethostbyname(sloc_hostname);

       if (!lpHostEnt)
          {
          log_file_date("%s:bad rc[0] from gethostbyname", mname);
          return(SL_VC_ERROR);
          }

       // create the socket

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

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

       if (slclientSocket == INVALID_SOCKET)
          {
          log_file_date("%s:bad rc[INVALID_SOCKET] from socket", mname);
          return(SL_VC_ERROR);
          }

       // load client address data

       memset(&slsockClientAddr, 0, sizeof(slsockClientAddr));
       slsockClientAddr.sin_family = AF_INET;
       slsockClientAddr.sin_port = htons(sloc_port);

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

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

       // connect to server

    #ifdef OS_WIN32
       if (connect(slclientSocket, (LPSOCKADDR)&slsockClientAddr,
                   sizeof(slsockClientAddr)))
    #endif

    #ifdef OS_UNIX
       if (connect(slclientSocket, (SA *)&slsockClientAddr,
                   sizeof(slsockClientAddr)) == SOCKET_ERROR)
    #endif
          {
          log_file_date("%s:bad rc[SOCKET_ERROR] from connect", mname);
          return(SL_VC_ERROR);
          }

       return(SL_OK);
    }

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