/* 
  Copyright 2018-2023 Thorsten Alteholz <libcontra@alteholz.eu>

  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; version 2 of the License

  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 (see the file COPYING included with this
  distribution); if not, write to the Free Software Foundation, Inc.,
  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*!
*************************************************************************
*
* \file libcontra_gethostbyname.c
*
* \author Thorsten Alteholz <libcontra@alteholz.eu>
*
* \todo documentation
*
* \brief wrapper for gethostbyname()
*
* get structure of type hostent for the given host name
* man 2 gethhostbyname
* 
* \addtogroup libcontra
* The group of the library.
* @{
************************************************************************/

#include <libcontra.h>
#include <libcontra_log.h>
#include <netdb.h>

extern bool	libcontra_logGethostbyname; /*!< this is needed to control the output in the logging function */
extern bool	libcontra_isInitialized; /*!< this is needed to control the output in the logging function */

/*!
*************************************************************************
*
* \fn struct hostent *gethostbyname(const char *name)
*
* \author Thorsten Alteholz <libcontra@alteholz.eu>
*
* \brief wrapper around libc::gethostbyname()
*
* @param[in]  name  hostname to query
* 
* \return On success, return a hostent structure
*         On error, return NIL, errno is set
*
************************************************************************/
struct hostent *gethostbyname(const char *name)
{
  struct hostent * (*libc_gethostbyname)(const char *name);
  struct hostent *rcstruct;
  char addrStr[INET6_ADDRSTRLEN];

  if (libcontra_isInitialized==false) {
    libcontra_init();
  } 

  if (libcontra_logGethostbyname) {
    libcontra_log(LOGLEVEL_DEBUG, "D: gethostbyname start");
    libcontra_log(LOGLEVEL_INFO,  "I: gethostbyname looking for %s",name);
  }

  *(void **)(&libc_gethostbyname) = dlsym(RTLD_NEXT, "gethostbyname");
  if(dlerror()) {
    errno = EACCES;
    return NULL;
  }

  rcstruct = (*libc_gethostbyname)(name);
  
  if (libcontra_logGethostbyname) {
    char **aliases;
    struct in_addr **list;
    struct in6_addr **list6;
    int i;
    libcontra_log(LOGLEVEL_INFO, "I: gethostbyname h_name: %s", rcstruct->h_name);
    aliases=rcstruct->h_aliases;
    list=(struct in_addr **)rcstruct->h_addr_list;
    if (*aliases==NULL) libcontra_log(LOGLEVEL_INFO, "I: gethostbyname alias list empty");
    while (*aliases!=NULL) {
      libcontra_log(LOGLEVEL_INFO, "I: gethostbyname alias of %s is %s", rcstruct->h_name, *aliases);
      aliases++;
    }
    libcontra_log(LOGLEVEL_INFO, "I: gethostbyname h_addrtype: %i (%i/%i) h_length: %i", rcstruct->h_addrtype, AF_INET, AF_INET6, rcstruct->h_length);
    for(i = 0; list[i] != NULL; i++) {      
      switch (rcstruct->h_addrtype) {
        case AF_INET:
          inet_ntop(AF_INET, (const void *)list[i], addrStr, INET6_ADDRSTRLEN);
          break;
        case AF_INET6:
          inet_ntop(AF_INET6, (const void *)list6[i] , addrStr, INET6_ADDRSTRLEN);
          break;
        default:
          libcontra_log(LOGLEVEL_ERROR, "E: gethostbyaddr: unknown type: %i\n", rcstruct->h_addrtype);
          break;
      }
      libcontra_log(LOGLEVEL_INFO, "I: gethostbyaddr h_addr_list[%i] = v(%s) ", i, addrStr);      
    }
    libcontra_log(LOGLEVEL_DEBUG, "D: gethostbyname end");
  }

  return rcstruct;
}

/*! @} */

