## root/socloc/slconfig.c

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

## DEFINITIONS

This source file includes following definitions.

1. sl_config_read
2. sl_config_get_first
3. sl_config_get_nentries
4. sl_config_get_nth
5. sl_config_find
6. sl_config_add
7. sl_config_port_exist
8. sl_config_host_exist
9. sl_config_delete
10. sl_config_delete_all
11. sl_config_get_list
12. sl_config_put_list
13. sl_config_write_file
14. sl_config_get_ils
15. sl_config_set_ils
16. sl_config_list
17. sl_config_debug

    /* Socket locate config settings handler. This module reads
       the settings in the socket locate config file.
       This config file is a normal ASCII file that
       contains a number of lines, each line describing a
       single socket locate server. Here is the format of the file:

          * comment line
          host_name port_number [ip_address]

       Each line of the config file may contain a comment by either
       placing an asterisk in column one or an asterisk after the
       server definition (there must be at least one space between the
       server definition and the asterisk). The line may also contain
       a 'socloc' server definition. If the 'host_name' contains spaces,
       the name must be enclosed by single or double quotes (must be
       balanced). Note that the IP address is optional. The list of
       socket locate servers will be searched in order that they
       appear in the configuration file.  Rick Smereka,
       Copyright (C) 2000-2004.

       This program is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation; either version 2 of the License, or
       (at your option) any later version.

       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.

       You should have received a copy of the GNU General Public License
       along with this program; if not, get a copy via the Internet at
       http://gnu.org/copyleft/gpl.html or write to the Free Software
       Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       MA 02111-1307 USA

       You can contact the author via email at rsmereka@future-lab.com

       Original version for CodeWarrior V4 under Windows 32bit.
       Feb/2000, Rick Smereka

       Added include of header 'ip.h' after moving the function 'isip'.
       Jul/2000, Rick Smereka

       Ported to Debian Linux. Nov/2002, Rick Smereka

       Changed all logging calls from 'log_file_date' to 'logman'.
       Mar/2004, Rick Smereka */

    #include "stdhead.h"
    #include "flsocket.h"
    #include "slconfig.h"
    #include "socloc.h"
    #include "ip.h"

    #define SL_NULL ((struct sl_config_entry *)NULL)

    /* global module data */

    struct sl_config_entry *sl_base = SL_NULL;

    int sl_config_read(char *fname)
    {
       /* Read and parse the socket locate config file 'fname'.
          Function returns a socket locate configuration code
          (defined in 'slconfig.h'). Upon successful completion,
          a link list of available socket locate servers will
          be built. */

       FILE *in;
       char mname[] = "sl_config_read";
       char *line, *host_name, *port_char, *ip;
       int lineno, nwords, port_num, ret;

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

       // reasonableness checks

       if (fname == (char *)NULL || !strlen(fname))
          {
          logman("%s:invalid parameter[fname]", mname);
          return(SL_INVALID_PARAMETER);
          }

            // attempt to open config file

       if ((in = fopen(fname, "r")) == (FILE *)NULL)
              {
              logman("%s:unable to open config file[%s]", mname, fname);
          return(SL_CONFIG_UNABLE_TO_OPEN);
          }

            // alloc line buffer

       if ((line = (char *)malloc(BUFSIZE)) == (char *)NULL)
              {
              logman("%s:alloc fail[line]", mname);
              fclose(in);
          return(SL_MEMORY_FAIL);
              }

            // get first record

            get_rec(in, line);
            lineno = 1;

            while(!feof(in))
               {
               /* if line begins with an asterisk in column one, ignore */

               if (line[0] == '*')
                  {
                  logman("%s:line %d is a comment", mname, lineno);
                  get_rec(in, line);
                  lineno++;
                  continue;
                  }

               // number of command words on line

               nwords = command_words(line);

               // must have at least two command words per record

               if (nwords < 2)
                  {
                  logman("%s:less than two parameters found on line %d",
                                mname, lineno);
                  free(line);
              fclose(in);
              return(SL_CONFIG_PARAMETER_MISSING);
                  }

          /* create host name string by dynamically copying and
             set length to zero */

          host_name = initstring(line);
          host_name[0] = EOS;

               // get first command word on line

          if (!command_word(line, host_name, 1))
                 {
                 logman("%s:error getting first word on line %d",
                               mname, lineno);
             free(host_name);
                 free(line);
                 fclose(in);
             return(SL_CONFIG_INTERNAL_PARSE_ERROR);
                 }

          /* get port number */

          port_char = initstring(line);
          port_char[0] = EOS;

          if (!command_word(line, port_char, 2))
             {
             logman("%s:error getting second word on line %d",
                               mname, lineno);
             free(port_char);
             free(host_name);
             free(line);
             fclose(in);
             return(SL_CONFIG_INTERNAL_PARSE_ERROR);
             }

          // must be a valid decimal number

          if (!qatoi(port_char, &port_num))
             {
             logman("%s:TCP/IP port not numeric on line %d",
                           mname, lineno);
             free(port_char);
             free(host_name);
             free(line);
             fclose(in);
             return(SL_CONFIG_PORT_NOT_NUMERIC);
             }

          free(port_char);
          ip = (char *)NULL;

          /* get IP address if present */

          if (nwords > 2)
             {
             ip = initstring(line);
             ip[0] = EOS;

             if (!command_word(line, ip, 3))
                {
                logman("%s:unexpected error getting IP on line %d",
                              mname, lineno);
                free(ip);
                free(host_name);
                free(line);
                fclose(in);
                return(SL_CONFIG_INTERNAL_PARSE_ERROR);
                }

             if (!isip(ip))
                {
                logman("%s:IP address is invalid on line %d",
                              mname, lineno);
                free(ip);
                free(host_name);
                free(line);
                fclose(in);
                return(SL_BAD_IP);
                }
             }

             /* add server to link list */

             if ((ret = sl_config_add(host_name, port_num, ip)) !=
                  SL_OK)
                {
                if (ip != (char *)NULL)
                   free(ip);

                free(host_name);
                free(line);
                fclose(in);
                logman("%s:error[%d] adding socloc server entry "
                              "on line %d", mname, ret, lineno);
                return(ret);
                }

          /* dealloc temp vars */

          if (ip != (char *)NULL)
             free(ip);

          free(host_name);

          // get next record

          get_rec(in, line);
          lineno++;
          }

       fclose(in);
       free(line);
       logman("%s:normal exit", mname);
       return(SL_OK);
    }

    int sl_config_get_first(char *hname, int *port_num, char *ip_ad)
    {
       /* Return the first socket locate server detail. Host name and
          ip address (if not NULL) must already be allocated by the
          caller to sufficient size. Note that the config entry for
          the currently running 'socloc' server (denoted by the
          'is_local_server' flag) is automatically excluded.
          Function returns 'SL_OK' upon success, a socket
          locate config code otherwise. */

       struct sl_config_entry *rov = sl_base;
       char mname[] = "sl_config_get_first";
       int ret, found = FALSE;

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

       if (rov == SL_NULL)
          {
          logman("%s:config list empty", mname);
          return(SL_NOT_FOUND);
          }

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

       while(rov != SL_NULL)
          {
          if (rov->is_local_server == FALSE)
             {
             strcpy(hname, rov->host_name);
             *port_num = rov->port_number;

             if (ip_ad != (char *)NULL)
                if (rov->ip_addr != (char *)NULL)
                   strcpy(ip_ad, rov->ip_addr);
                else
                   ip_ad[0] = EOS;

             found = TRUE;
             break;
             }

          rov = rov->next;
          }

       ret = found ? SL_OK : SL_NOT_FOUND;
       logman("%s:normal exit[%d]", mname, ret);
       return(ret);
    }

    int sl_config_get_nentries(int *nentries)
    {
       /* Get the number of entries in the link list.
          Note that the config entry for the currently
          running 'socloc' server (denoted by the
          'is_local_server' flag) is automatically excluded.
          Function returns 'SL_OK' with the number of entries
          loaded into 'nentries' upon success, a socket
          locate config error otherwise. */

       struct sl_config_entry *rov = sl_base;
       char mname[] = "sl_config_get_nentries";
       int cnt = 0;

       logman("%s:enter", mname);
       *nentries = 0;

       while(rov != SL_NULL)
          {
          if (!rov->is_local_server)
             cnt++;

          rov = rov->next;
          }

       if (!cnt)
          {
          logman("%s:config list empty", mname);
          return(SL_NOT_FOUND);
          }

       *nentries = cnt;
       logman("%s:normal exit", mname);
       return(SL_OK);
    }

    int sl_config_get_nth(int pos, char *hname, int *port_num, char *ip_ad)
    {
       /* Get a specific 'socloc' server entry. Function returns
          'SL_OK' upon success with the 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.
          Note that the config entry for the currently running 'socloc'
          server (denoted by the 'is_local_server' flag) is
          automatically excluded. Function returns
          a socket locate config error upon failure. */

       struct sl_config_entry *rov;
       char mname[] = "sl_config_get_nth";
       int i, nentries, ret;

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

       /* get total number of entries and validate */

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

       if (pos > nentries)
          {
          logman("%s:entry not found", mname);
          return(SL_NOT_FOUND);
          }

       for(rov = sl_base, i = 0; i <= pos; rov = rov->next)
          {
          if (!rov->is_local_server)
             i++;

          if (i == pos)
             {
             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;
             }
          }

       logman("%s:normal exit", mname);
       return(SL_OK);
    }

    int sl_config_find(char *hname, int *port_num, char *ip_ad)
    {
       /* Find a config entry by one or more details. At least one
          parameter must be given. Upon success, missing details
          will be loaded into parameters. Note that if this function
          is called from a 'socloc' server, that server will not be
          excluded from the find. Function returns 'SL_OK'
          upon success, a socket locate config code otherwise. */

       struct sl_config_entry *rov = sl_base;
       char mname[] = "sl_config_find";
       int ret, found = FALSE;
       int ishname, isport, isip;

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

       if (rov == SL_NULL)
          {
          logman("%s:config list empty", mname);
          return(SL_NOT_FOUND);
          }

       ishname = isport = isip = TRUE;

       if (hname == (char *)NULL || !strlen(hname))
          ishname = FALSE;

       if (port_num == (int *)NULL || *port_num <= 0)
          isport = FALSE;

       if (ip_ad == (char *)NULL || !strlen(ip_ad))
          isip = FALSE;

       if (!ishname && !isport && !isip)
          {
          logman("%s:no parameters", mname);
          return(SL_INVALID_PARAMETER);
          }

       logman("%s:ishname=%d,isport=%d,isip=%d", mname, ishname,
                     isport, isip);

       while(rov != SL_NULL)
          {
          if (!ishname)
             found = TRUE;
          else
             if (!strcmp(hname, rov->host_name))
                found = TRUE;
             else
                found = FALSE;

          if (found)
             if (!isport)
                found = TRUE;
             else
                if (*port_num == rov->port_number)
                   found = TRUE;
                else
                   found = FALSE;

          if (found)
             if (!isip)
                found = TRUE;
             else
                if (!strcmp(ip_ad, rov->ip_addr))
                   found = TRUE;
                else
                   found = FALSE;

          if (found)
             {
             if (!ishname && hname != (char *)NULL)
                strcpy(hname, rov->host_name);

             if (!isport && port_num != (int *)NULL)
                *port_num = rov->port_number;

             if (rov->ip_addr != (char *)NULL)
                if (!isip && ip_ad != (char *)NULL)
                   strcpy(ip_ad, rov->ip_addr);

             logman("%s:found match,hname=%s,port=%d", mname,
                           hname, *port_num);
             break;
             }

          rov = rov->next;
          }

       ret = found ? SL_OK : SL_NOT_FOUND;
       logman("%s:normal exit[%d]", mname, ret);
       return(ret);
    }

    int sl_config_add(char *hname, int port_num, char *ip_ad)
    {
       /* Add a socket locate server entry. Function returns
          'SL_OK' upon success, a socket locate config
          error code otherwise. */

       struct sl_config_entry *sl_entry;
       struct sl_config_entry *rov;
       char mname[] = "sl_config_add";
       int ret, len, size;

       logman("%s:enter", mname);
       size = sizeof(struct sl_config_entry);

       /* reasonableness checks */

       if (hname == (char *)NULL || !strlen(hname))
          {
          logman("%s:invalid parameter[hname]", mname);
          return(SL_INVALID_PARAMETER);
          }

       if (port_num <= 0)
          {
          logman("%s:port out of range", mname);
          return(SL_CONFIG_PORT_OUT_OF_RANGE);
          }

       /* check for duplicate port number */

       if ((ret = sl_config_port_exist(port_num)) != SL_OK)
          {
          logman("%s:bad rc[%d] from 'sl_config_port_exist'",
                        mname, ret);
          return(ret);
          }

       /* check for duplicate host name */

       if ((ret = sl_config_host_exist(hname)) != SL_OK)
          {
          logman("%s:bad rc[%d] from 'sl_config_host_exist'",
                        mname, ret);
          return(ret);
          }

       if ((sl_entry = (struct sl_config_entry *)malloc(size)) == SL_NULL)
          {
          logman("%s:alloc fail[sl_entry]", mname);
          return(SL_MEMORY_FAIL);
          }

       len = strlen(hname);

       if ((sl_entry->host_name = (char *)malloc(len + 1)) == (char *)NULL)
          {
          logman("%s:alloc fail[sl_entry->host_name]", mname);
          free(sl_entry);
          return(SL_MEMORY_FAIL);
          }

       strcpy(sl_entry->host_name, hname);
       sl_entry->port_number = port_num;

       if (ip_ad != (char *)NULL)
          {
          len = strlen(ip_ad);

          if ((sl_entry->ip_addr = (char *)malloc(len + 1)) == (char *)NULL)
             {
             logman("%s:alloc fail[sl_entry->ip_addr]", mname);
             free(sl_entry->host_name);
             free(sl_entry);
             return(SL_MEMORY_FAIL);
             }

          strcpy(sl_entry->ip_addr, ip_ad);
          }
       else
          sl_entry->ip_addr = (char *)NULL;

       sl_entry->next = SL_NULL;
       sl_entry->is_local_server = FALSE;

       /* set head of list if this is the first entry */

       if (sl_base == SL_NULL)
          {
          sl_base = sl_entry;
          logman("%s:normal exit at head of list", mname);
          return(SL_OK);
          }

       /* find last entry and hook into it */

       rov = sl_base;

       while(rov->next != SL_NULL)
          rov = rov->next;

       rov->next = sl_entry;
       logman("%s:normal exit", mname);
       return(SL_OK);
    }

    int sl_config_port_exist(int port_num)
    {
       /* Determine whether there already is a socket locate
          config entry with the specified port number.
          Function returns 'SL_OK' if the port
          does not already exist and 'SL_PORT_EXIST'
          if the port does already exist. */

       struct sl_config_entry *rov = sl_base;
       char mname[] = "sl_config_port_exist";
       int ret = SL_OK;

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

       while(rov != SL_NULL)
          {
          if (port_num == rov->port_number)
             {
             logman("%s:found port already defined", mname);
             ret = SL_PORT_EXIST;
             break;
             }

           rov = rov->next;
           }

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

    int sl_config_host_exist(char *hname)
    {
       /* Determine whether there already is a socket locate
          config entry with the specified host name.
          Function returns 'SL_OK' if the host
          does not already exist and 'SL_CONFIG_HOST_EXIST'
          if the host does already exist. */

       struct sl_config_entry *rov = sl_base;
       char mname[] = "sl_config_host_exist";
       int ret = SL_OK;

       logman("%s:enter,host=%s", mname, hname);

       while(rov != SL_NULL)
          {
          if (!strcmp(hname, rov->host_name))
             {
             logman("%s:found host already defined", mname);
             ret = SL_CONFIG_HOST_EXIST;
             break;
             }

           rov = rov->next;
           }

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

    int sl_config_delete(int port_num)
    {
       /* Delete a socket locate server entry. Since the TCP/IP
          port is unique, this is used as the entry key.
          Function returns 'SL_OK' upon success, a
          socket locate config error otherwise. */

       struct sl_config_entry *rov;
       struct sl_config_entry *prev;
       char mname[] = "sl_config_delete";

       logman("%s:enter,port=%d", mname, port_num);
       rov = prev = sl_base;

       while(rov != SL_NULL)
          {
          if (port_num == rov->port_number)
             break;
          else
             {
             prev = rov;
             rov = rov->next;
             }
          }

       /* if no match, error */

       if (rov == SL_NULL)
          {
          logman("%s:entry not found", mname);
          return(SL_NOT_FOUND);
          }

       /* if we are deleting the head entry, set new head */

       if (rov == sl_base)
          sl_base = rov->next;
       else
          prev->next = rov->next;

       free(rov->host_name);

       if (rov->ip_addr != (char *)NULL)
          free(rov->ip_addr);

       free(rov);
       logman("%s:normal exit", mname);
       return(SL_OK);
    }

    void sl_config_delete_all(void)
    {
       /* Delete all config entries. */

       struct sl_config_entry *rov = sl_base;
       struct sl_config_entry *tmp;
       char mname[] = "sl_config_delete_all";

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

       while(rov != SL_NULL)
          {
          free(rov->host_name);

          if (rov->ip_addr != (char *)NULL)
             free(rov->ip_addr);

          tmp = rov;
          rov = rov->next;
          free(tmp);
          }

       sl_base = SL_NULL;
       logman("%s:normal exit", mname);
    }

    int sl_config_get_list(char *list_out)
    {
       /* Get the 'socloc' config list. The list is built with
          each entry delimited by 'SL_LIST_DELIM'. Upon success,
          function returns the config list in 'list_out' which
          already must be allocated to sufficient size by the
          caller. Function returns 'SL_OK' upon success, a
          'socloc' code otherwise. */

       struct sl_config_entry *rov = sl_base;
       char mname[] = "sl_config_get_list";
       char *anentry;
       int i, len, out_pos = 0;

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

       if (rov == SL_NULL)
          {
          logman("%s:empty list", mname);
          return(SL_NOT_FOUND);
          }

       list_out[0] = EOS;

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

       while(rov != SL_NULL)
          {
          if (rov->ip_addr != (char *)NULL && strlen(rov->ip_addr))
             sprintf(anentry, "'%s' %d %s", rov->host_name, rov->port_number,
                     rov->ip_addr);
          else
             sprintf(anentry, "'%s' %d", rov->host_name, rov->port_number);

          /* load this entry into 'list_out' */

          len = strlen(anentry);

          for(i = 0; i < len; i++, out_pos++)
             list_out[out_pos] = anentry[i];

          if (rov->next != SL_NULL)
             list_out[out_pos++] = SL_LIST_DELIM;

          rov = rov->next;
          }

       list_out[out_pos] = EOS;
       free(anentry);
       logman("%s:normal exit", mname);
       return(SL_OK);
    }

    int sl_config_put_list(char *thelist)
    {
       /* Take the input 'socloc' config list ('thelist')
          and write/put it. A list entry is expected in the
          format:

             hname port[ ip_ad]

          Where 'hname' is the host name, port is the TCP/IP
          port number and the optional 'ip_ad' is the TCP/IP
          address. If the host name contains spaces, it
          must be quoted.

          Each entry is delimited by 'SL_LIST_DELIM'. */

       char mname[] = "sl_config_put_list";
       char *entry, *hname, *port_char, *ip_ad;
       int nentries, nwords, port, len, i, ret;

       if (thelist == (char *)NULL || !strlen(thelist))
          {
          logman("%s:invalid parameter[thelist]", mname);
          return(SL_INVALID_PARAMETER);
          }

       /* get number of delimited entries */

       nentries = ll_words(thelist, SL_LIST_DELIM);

       if (nentries < 1)
          {
          logman("%s:unexpected[nentries] from 'll_words'", mname);
          return(SL_INTERNAL_ERROR);
          }

       /* delete the existing list in memory */

       sl_config_delete_all();

       /* add each entry in the list */

       for(i = 1; i <= nentries; i++)
          {
          len = ll_wordlen(thelist, i, SL_LIST_DELIM);

          if (len < 1)
             {
             logman("%s:entry[%d]:unexpected[len] from 'll_wordlen'",
                           mname, i);
             return(SL_INTERNAL_ERROR);
             }

          if ((entry = (char *)malloc(len + 1)) == (char *)NULL)
             {
             logman("%s:entry[%d]:alloc fail[entry]", mname, i);
             return(SL_MEMORY_FAIL);
             }

          if (!ll_word(thelist, entry, i, SL_LIST_DELIM))
             {
             free(entry);
             logman("%s:entry[%d]:unexpected from 'll_word'", mname, i);
             return(SL_INTERNAL_ERROR);
             }

          /* must have at least 2 command words in each entry */

          if ((nwords = command_words(entry)) < 2)
             {
             free(entry);
             logman("%s:entry[%d] insufficient parameters", mname, i);
             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 ((hname = initstring(entry)) == (char *)NULL)
             {
             free(entry);
             logman("%s:entry[%d]:alloc fail[hname]", mname, i);
             return(SL_MEMORY_FAIL);
             }

          if ((port_char = initstring(entry)) == (char *)NULL)
             {
             free(entry);
             free(hname);
             logman("%s:entry[%d]:alloc fail[port_char]", mname, i);
             return(SL_MEMORY_FAIL);
             }

          if ((ip_ad = initstring(entry)) == (char *)NULL)
             {
             free(entry);
             free(hname);
             free(port_char);
             logman("%s:entry[%d]:alloc fail[ip_ad]", mname, i);
             return(SL_MEMORY_FAIL);
             }

          hname[0] = EOS;
          port_char[0] = EOS;
          ip_ad[0] = EOS;

          if (!command_word(entry, hname, 1))
             {
             free(entry);
             free(hname);
             free(port_char);
             free(ip_ad);
             logman("%s:entry[%d]:unexpected from 'command_word'[hname]",
                           mname, i);
             return(SL_INTERNAL_ERROR);
             }

          if (!command_word(entry, port_char, 2))
             {
             free(entry);
             free(hname);
             free(port_char);
             free(ip_ad);
             logman("%s:entry[%d]:unexpected from 'command_word'[port_char]",
                           mname, i);
             return(SL_INTERNAL_ERROR);
             }

          if (!qatoi(port_char, &port))
             {
             free(entry);
             free(hname);
             free(port_char);
             free(ip_ad);
             logman("%s:entry[%d]:non-numeric port", mname, i);
             return(SL_INVALID_PARAMETER);
             }

          free(port_char);

          if (nwords > 2)
             {
             if (!command_word(entry, ip_ad, 3))
                {
                free(entry);
                free(hname);
                free(ip_ad);
                logman("%s:entry[%d]:unexpected from 'command_word'[ip_ad]",
                              mname, i);
                return(SL_INTERNAL_ERROR);
                }

             if (!isip(ip_ad))
                {
                free(entry);
                free(hname);
                free(ip_ad);
                logman("%s:entry[%s]:invalid IP address", mname, i);
                return(SL_BAD_IP);
                }
             }

          /* finally, after all that, we are ready to add the entry */

          if ((ret = sl_config_add(hname, port, ip_ad)) != SL_OK)
             {
             free(entry);
             free(hname);
             free(ip_ad);
             logman("%s:entry[%d]:bad rc[%d] from 'sl_config_add'",
                           mname, i, ret);
             return(ret);
             }

          free(entry);
          free(hname);
          free(ip_ad);
          }

       logman("%s:normal exit", mname);
       return(SL_OK);
    }

    int sl_config_write_file(void)
    {
       /* Write the current config list to the config
          file. Function returns 'SL_OK' upon success,
          a 'socloc' code otherwise. */

       struct sl_config_entry *rov = sl_base;
       FILE *out;
       char mname[] = "sl_config_write_file";

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

       if (sl_base == SL_NULL)
          {
          logman("%s:list empty, nothing to write", mname);
          return(SL_NOT_FOUND);
          }

       if ((out = fopen(SL_CONFIG_FILE_NAME, "w")) == (FILE *)NULL)
          {
          logman("%s:unable to open file '%s' for writing",
                        mname, SL_CONFIG_FILE_NAME);
          return(SL_CONFIG_UNABLE_TO_OPEN);
          }

       fprintf(out, "* list written by 'sl_config_write_file'\n");

       while(rov != SL_NULL)
          {
          if (words(rov->host_name) > 1)
             fprintf(out, "'%s' %d", rov->host_name, rov->port_number);
          else
             fprintf(out, "%s %d", rov->host_name, rov->port_number);

          if (rov->ip_addr != (char *)NULL && strlen(rov->ip_addr))
             fprintf(out, " %s\n", rov->ip_addr);
          else
             fprintf(out, "\n");

          rov = rov->next;
          }

       fclose(out);
       logman("%s:normal exit", mname);
       return(SL_OK);
    }

    int sl_config_get_ils(int port_num, int *ils_flag)
    {
       /* Get and return the 'is_local_server' flag for
          a 'socloc' server based on its TCP/IP port
          number. Function returns the 'is_local_server'
          flag upon success, a 'socloc' code otherwise. */

       struct sl_config_entry *rov = sl_base;
       char mname[] = "sl_config_get_ils";
       int ret, found = FALSE;

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

       if (port_num <= 0)
          {
          logman("%s:illegal port number", mname);
          return(SL_INVALID_PARAMETER);
          }

       if (ils_flag == (int *)NULL)
          {
          logman("%s:invalid parameter[ils_flag]", mname);
          return(SL_INVALID_PARAMETER);
          }

       *ils_flag = FALSE;

       while(rov != SL_NULL)
          {
          if (port_num == rov->port_number)
             {
             *ils_flag = rov->is_local_server;
             found = TRUE;
             break;
             }

          rov = rov->next;
          }

       ret = found ? SL_OK : SL_NOT_FOUND;
       logman("%s:normal exit[%d]", mname, ret);
       return(ret);
    }

    int sl_config_set_ils(int port_num, int ils_flag)
    {
       /* Set the 'socloc' server on TCP/IP port 'port_num'
          'is_local_server' flag to 'ils_flag'. Function
          returns a 'socloc' code. */

       struct sl_config_entry *rov = sl_base;
       char mname[] = "sl_config_set_ils";
       int ret, found = FALSE;

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

       if (port_num <= 0)
          {
          logman("%s:invalid port number", mname);
          return(SL_INVALID_PARAMETER);
          }

       if (ils_flag < 0 || ils_flag > 1)
          {
          logman("%s:invalid parameter[ils_flag] must be 0 or 1", mname);
          return(SL_INVALID_PARAMETER);
          }

       while(rov != SL_NULL)
          {
          if (port_num == rov->port_number)
             {
             rov->is_local_server = ils_flag;
             found = TRUE;
             break;
             }

          rov = rov->next;
          }

       ret = found ? SL_OK : SL_NOT_FOUND;
       logman("%s:normal exit[%d]", mname, ret);
    }

    void sl_config_list(void)
    {
       /* List the contents of the link list. Used for screen output
          only. */

       char mname[] = "sl_config_list";
       struct sl_config_entry *rov = sl_base;
       int i = 1;

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

       if (is_log_active())
          {
          logman("%s:log is on, using 'sl_config_debug'", mname);
          sl_config_debug();
          return;
          }

       while(rov != SL_NULL)
          {
          if (strlen(rov->ip_addr))
             printf("socloc[%d]:host='%s',port=%d,ip=%s\n", i,
                    rov->host_name, rov->port_number, rov->ip_addr);
          else
             printf("socloc[%d]:host='%s',port=%d\n", i, rov->host_name,
                    rov->port_number, rov->ip_addr);

          rov = rov->next;
          i++;
          }

       if (i == 1)
          printf("list empty\n");
    }

    void sl_config_debug(void)
    {
       /* Print the contents of the link list. */

       char mname[] = "sl_config_debug";
       struct sl_config_entry *rov = sl_base;
       int i = 1;

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

       while(rov != SL_NULL)
          {
          logman("%s[%d]:host='%s',port=%d,ip='%s',ils=%d", mname,
                        i, rov->host_name, rov->port_number, rov->ip_addr,
                        rov->is_local_server);
          rov = rov->next;
          i++;
          }

       if (i == 1)
          logman("%s:list empty", mname);

       logman("%s:normal exit", mname);
    }

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