/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Ident Daemon - Listener Functions
 * ----------------------------------------------------------------
 * Copyright (C) 1997-2007 Jonas Kvinge <jonas@night-light.net>
 * All rights reserved.
 *
 * 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Last modified by:
 * Jonas Kvinge (25.11.2007)
 *
 */

#define IDENT_LISTEN_C

#define NEED_SYS_TYPES_H 1		/* Extra types */
#define NEED_SYS_PARAM_H 1		/* Some systems need this */
#define NEED_LIMITS_H 0			/* Kernel limits */
#define NEED_STDARG_H 1			/* va_list, etc */
#define NEED_ERRNO_H 1			/* errno */
#define NEED_CTYPE_H 1			/* isdigit(), etc */
#define NEED_NETINET_IN_H 1		/* in_addr, sockaddr_in, etc */
#define NEED_ARPA_INET_H 1		/* inet_ntoa(), inet_aton(), etc */
#define NEED_STDIO_H 1			/* Standard C UNIX functions */
#define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
#define NEED_TIME_H 1			/* time(), etc */
#define NEED_SYSCTL_H 0			/* sysctl(), etc */
#define NEED_SYS_STAT_H 0		/* chmod(), mkdir(), etc */
#define NEED_SYS_UIO_H 0		/* iovec, etc */
#define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
#define NEED_SYS_IOCTL_H 1		/* ioctl(), etc */
#define NEED_SYS_FILIO_H 1		/* Solaris need this for ioctl(), etc */
#define NEED_UNISTD_H 1			/* Unix standard functions */
#define NEED_STRING_H 1			/* C string functions */
#define NEED_SIGNAL_H 0			/* Signal functions */
#define NEED_SYS_SOCKET_H 1		/* Socket functions */
#define NEED_NETDB_H 1			/* Network database functions */
#define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */
#define NEED_ARES 1			/* Functions needed for ares */
#define NEED_SSL 0			/* Needed for SSL support */

#include "includes.h"

#include "ident_listen.h"
#include "ident_conn.h"

/* VARIABLES - JONAS (03.07.2003) */

struct IdentListen_Struct *IdentListen_Head = NULL;
struct IdentListen_Struct *IdentListen_Tail = NULL;
unsigned long int G_Ident_Listens = 0;

#if ARES
  extern ares_channel Ares_Channel;
#endif

/* IDENT_LISTEN_ADD FUNCTION - JONAS (03.07.2003) */

struct IdentListen_Struct *ident_listen_add(const char *const HostPT, const unsigned long int Port) {

  struct IdentListen_Struct *IdentListenS = NULL;
  struct IdentListen_Struct *IdentListen_NEW = NULL;

  assert(HostPT != NULL);

  IdentListenS = ident_get(HostPT, Port);
  if (IdentListenS != NULL) {
    aerrno = AEEXISTS;
    return(IdentListenS);
  }

  IdentListen_NEW = malloc(sizeof(struct IdentListen_Struct));
  if (IdentListen_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(IdentListen_NEW, 0, sizeof(struct IdentListen_Struct));

  IdentListen_NEW->Host = strdup(HostPT);
  if (IdentListen_NEW->Host == NULL) {
    free(IdentListen_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  IdentListen_NEW->PortH = Port;
  IdentListen_NEW->PortN = htons(Port);

  if (IdentListen_Head == NULL) {
    IdentListen_Head = IdentListen_NEW;
    IdentListen_Tail = IdentListen_NEW;
  }
  else {
    IdentListenS = IdentListen_Tail;
    IdentListenS->Next = IdentListen_NEW;
    IdentListen_NEW->Prev = IdentListenS;
    IdentListen_Tail = IdentListen_NEW;
  }

  G_Ident_Listens++;

  aerrno = AESUCCESS;
  return(IdentListen_NEW);

}

/* IDENT_LISTEN_REM FUNCTION - JONAS (03.07.2003) */

void ident_listen_rem(struct IdentListen_Struct *IdentListenS) {

  assert(IdentListenS != NULL);

  if (IdentListenS->Prev == NULL) { IdentListen_Head = IdentListenS->Next; }
  else { IdentListenS->Prev->Next = IdentListenS->Next; }

  if (IdentListenS->Next == NULL) { IdentListen_Tail = IdentListenS->Prev; }
  else { IdentListenS->Next->Prev = IdentListenS->Prev; }

  ident_listen_init(IdentListenS);

  free(IdentListenS->Host);
  free(IdentListenS);

  G_Ident_Listens--;

}

/* IDENT_LISTEN_INIT FUNCTION - JONAS (03.07.2003) */

void ident_listen_init(struct IdentListen_Struct *IdentListenS) {

  assert(IdentListenS != NULL);

  IdentListenS->Flags = 0;
  FREE(IdentListenS->HostIPS);
  memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr));
#if IPV6_SUPPORT
  memset(&IdentListenS->INAddr6, 0, sizeof(IdentListenS->INAddr6));
#endif
  IdentListenS->PortH = 0;
  IdentListenS->PortN = 0;
  IdentListenS->FD = FD_NONE;

}

/* IDENT_LISTEN_GET - JONAS (03.07.2003) */

struct IdentListen_Struct *ident_get(const char *const HostPT, const unsigned long int Port) {

  struct IdentListen_Struct *IdentListenS = NULL;

  assert(HostPT != NULL);

  for (IdentListenS = IdentListen_Head ; IdentListenS != NULL ; IdentListenS = IdentListenS->Next) {
    if ((strcasecmp(IdentListenS->Host, HostPT) == FALSE) && (IdentListenS->PortH == Port)) {
      aerrno = AESUCCESS;
      return(IdentListenS);
    }
  }
  aerrno = AENOMATCH;
  return(NULL);

}

/* IDENT_LISTEN_START - JONAS (03.07.2003) */

void ident_listen_start(struct IdentListen_Struct *IdentListenS) {

  signed long int Result = 0;
  signed long int BindResult = 0;

  struct sockaddr_in SockAddr = { 0 };
#if IPV6_SUPPORT
  struct sockaddr_in6 SockAddr6 = { 0 };
#endif

#if !ARES
  struct hostent *HostEnt = NULL;
#endif

  unsigned long int Flags = 0;

  assert(IdentListenS != NULL);

  IdentListenS->Time = NOW;
  IdentListenS->Tries++;

  if (!IdentListen_IsResolved(IdentListenS)) {

    if (IdentListenS->Host[0] == '*') {
#if IPV6_SUPPORT
      if (IdentListen_IsIPv6(IdentListenS)) {
        memset(&IdentListenS->INAddr6, 0, sizeof(IdentListenS->INAddr6));
        IdentListenS->INAddr6 = in6addr_any;
      }
      else {
#endif /* IPV6_SUPPORT */
        memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr));
        IdentListenS->INAddr.s_addr = INADDR_ANY;
#if IPV6_SUPPORT
      }
#endif /* IPV6_SUPPORT */
      IdentListen_SetResolved(IdentListenS);
    }
    else {
      memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr));
      Result = inet_aton(IdentListenS->Host, &IdentListenS->INAddr);
      if (Result <= 0) {
        IdentListen_SetResolving(IdentListenS);
#if ARES
#if IPV6_SUPPORT
        if (IdentListen_IsIPv6(IdentListenS)) {
          ares_gethostbyname(Ares_Channel, IdentListenS->Host, AF_INET6, (ares_host_callback) ident_listen_hosttoip, IdentListenS);
          return;
        }
        else {
#endif /* IPV6_SUPPORT */
          ares_gethostbyname(Ares_Channel, IdentListenS->Host, AF_INET, (ares_host_callback) ident_listen_hosttoip, IdentListenS);
#if IPV6_SUPPORT
        }
#endif /* IPV6_SUPPORT */
        return;
#else /* ARES */


#if IPV6_SUPPORT
        if (IdentListen_IsIPv6(IdentListenS)) { HostEnt = gethostbyname2(IdentListenS->Host, AF_INET6); }
        else { HostEnt = gethostbyname2(IdentListenS->Host, AF_INET); }
#else /* IPV6_SUPPORT */
        HostEnt = gethostbyname(IdentListenS->Host);
#endif /* IPV6_SUPPORT */
        ident_listen_hosttoip(IdentListenS, errno, HostEnt);
        if (!Listen_IsResolved(IdentListenS)) { return; }
#endif /* ARES */
      }
      else {
        IdentListen_SetResolved(IdentListenS);
        IdentListenS->HostIPS = strrealloc(IdentListenS->HostIPS, IdentListenS->Host);
        if (aerrno != AESUCCESS) { ident_listen_init(IdentListenS); return; }
      }
    }

  }

  /* CREATE SOCKET */

#if IPV6_SUPPORT
  if (IdentListen_IsIPv6(IdentListenS)) {
    Result = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
  }
  else {
#endif /* IPV6_SUPPORT */
    Result = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#if IPV6_SUPPORT
  }
#endif /* IPV6_SUPPORT */
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to create socket: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
    ident_listen_stop(IdentListenS);
    return;
  }
  IdentListenS->FD = Result;

  IdentListen_SetSocket(IdentListenS);

  /* SET SOCKET IN NON-BLOCKING MODE */

#if defined(NBLOCK_SYSV)
  Flags = 1;
  Result = ioctl(IdentListenS->FD, FIONBIO, &Flags);
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to set socket in non-blocking mode using ioctl(): [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
    ident_listen_stop(IdentListenS);
    return;
  }
#else
  Result = fcntl(IdentListenS->FD, F_GETFL, &Flags);
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to get socket flags using fcntl(): [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
    ident_listen_stop(IdentListenS);
    return;
  }
#if defined(NBLOCK_BSD)
    Flags |= O_NDELAY;
#elif defined(NBLOCK_POSIX)
    Flags |= O_NONBLOCK;
#else
    #warning "This system does not support non-blocking sockets?"
    Flags |= O_NONBLOCK;
#endif
  Result = fcntl(IdentListenS->FD, F_SETFL, Flags);
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to set socket in non-blocking mode using fcntl(): [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
    ident_listen_stop(IdentListenS);
    return;
  }
#endif


  if (IDENTLISTEN_SOCKKEEPALIVE == TRUE) {

    unsigned long int OPT = 1;

    Result = setsockopt(IdentListenS->FD, SOL_SOCKET, SO_KEEPALIVE, &OPT, sizeof(OPT));
    if (Result <= ERROR) {
      sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to set Keep Alive option for socket: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
      ident_listen_stop(IdentListenS);
      return;
    }

  }

  if (IDENTLISTEN_SOCKREUSEADDR == TRUE) {

    unsigned long int OPT = 1;

    Result = setsockopt(IdentListenS->FD, SOL_SOCKET, SO_REUSEADDR, &OPT, sizeof(OPT));
    if (Result <= ERROR) {
      sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to set Reuse Address option for socket: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
      ident_listen_stop(IdentListenS);
      return;
    }

  }

  /* BIND */

#if !WIN32
  if (IdentListenS->PortH < 1024) { sysseteuid(0); }
#endif

#if IPV6_SUPPORT
  if (IdentListen_IsIPv6(IdentListenS)) {
    memset(&SockAddr6, 0, sizeof(SockAddr6));
    SockAddr6.sin6_family = AF_INET6;
    SockAddr6.sin6_addr = IdentListenS->INAddr6;
    SockAddr6.sin6_port = IdentListenS->PortN;
    BindResult = bind(IdentListenS->FD, (struct sockaddr *) &SockAddr6, sizeof(SockAddr6));
  }
  else {
#endif /* IPV6_SUPPORT */
    memset(&SockAddr, 0, sizeof(SockAddr));
    SockAddr.sin_family = AF_INET;
    SockAddr.sin_addr = IdentListenS->INAddr;
    SockAddr.sin_port = IdentListenS->PortN;
    BindResult = bind(IdentListenS->FD, (struct sockaddr *) &SockAddr, sizeof(SockAddr));
#if IPV6_SUPPORT
  }
#endif /* IPV6_SUPPORT */

#if !WIN32
  if (IdentListenS->PortH < 1024) { sysseteuidnormal(); }
#endif

  if (BindResult <= ERROR) {
    sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to bind socket to address: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
    ident_listen_stop(IdentListenS);
    return;
  }

  /* IDENT */

  Result = listen(IdentListenS->FD, SOMAXCONN);
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to listen on address: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
    ident_listen_stop(IdentListenS);
    return;
  }
  else {
    DEBUGPRINT(BITMASK_DEBUG_IDENT, "Ident daemon %s(%s):%ld started.", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH);
    IdentListen_SetListening(IdentListenS);
    return;
  }

}

/* IDENT_LISTEN_HOSTTOIP FUNCTION - JONAS (03.07.2003) */

#if HAVE_CARES_CALLBACK_TIMEOUTS
void ident_listen_hosttoip(void *ArgPT, unsigned short int ErrNo, int Timeouts, struct hostent *HostEnt) {
#else
void ident_listen_hosttoip(void *ArgPT, unsigned short int ErrNo, struct hostent *HostEnt) {
#endif

  struct IdentListen_Struct *IdentListenS = ArgPT;
  const char *HostIPPT = NULL;
#if IPV6_SUPPORT
  char Host[INET6_ADDRSTRLEN+1] = "";
#endif

  assert(IdentListenS != NULL);

  if ((HostEnt == NULL) || (HostEnt->h_length < 1)) {
    sysprint(BITMASK_MAIN, "Ident daemon %s:%ld: Unable to resolve host %s to IP-address: [%d] %s", IdentListenS->Host, IdentListenS->PortH, IdentListenS->Host, ErrNo, res_strerror(ErrNo));
    ident_listen_init(IdentListenS);
    return;
  }

#if IPV6_SUPPORT
  if (IdentListen_IsIPv6(IdentListenS)) {
    memset(&IdentListenS->INAddr6, 0, sizeof(IdentListenS->INAddr6));
    memcpy(&IdentListenS->INAddr6, HostEnt->h_addr, HostEnt->h_length);
    HostIPPT = inet_ntop(AF_INET6, &IdentListenS->INAddr6, Host, INET6_ADDRSTRLEN);
    if (HostIPPT == NULL) {
      sysprint(BITMASK_MAIN, "Ident daemon %s:%ld: inet_ntop() failed: [%d] %s", IdentListenS->Host, IdentListenS->PortH, errno, strerror(errno));
      ident_listen_init(IdentListenS);
      return;
    }
  }
  else {
    memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr));
    memcpy(&IdentListenS->INAddr, HostEnt->h_addr, HostEnt->h_length);
    HostIPPT = inet_ntop(AF_INET, &IdentListenS->INAddr, Host, INET6_ADDRSTRLEN);
    if (HostIPPT == NULL) {
      sysprint(BITMASK_MAIN, "Ident daemon %s:%ld: inet_ntop() failed: [%d] %s", IdentListenS->Host, IdentListenS->PortH, errno, strerror(errno));
      ident_listen_init(IdentListenS);
      return;
    }
  }
#else /* IPV6_SUPPORT */
  memset(&IdentListenS->INAddr, 0, sizeof(IdentListenS->INAddr));
  memcpy(&IdentListenS->INAddr, HostEnt->h_addr, HostEnt->h_length);
  HostIPPT = inet_ntoa(IdentListenS->INAddr);
  if (HostIPPT == NULL) {
    sysprint(BITMASK_MAIN, "Ident daemon %s:%ld: inet_ntoa() failed: [%d] %s", IdentListenS->Host, IdentListenS->PortH, errno, strerror(errno));
    ident_listen_init(IdentListenS);
    return;
  }
#endif
  IdentListenS->HostIPS = strrealloc(IdentListenS->HostIPS, HostIPPT);

  IdentListen_ClearResolving(IdentListenS);
  IdentListen_SetResolved(IdentListenS);

#if ARES
    ident_listen_start(IdentListenS);
#endif /* ARES */

}

/* IDENT_LISTEN_STOP - JONAS (03.07.2003) */

void ident_listen_stop(struct IdentListen_Struct *IdentListenS) {

  assert(IdentListenS != NULL);

  if (IdentListen_IsResolving(IdentListenS)) {
#if HAVE_ARES_CANCELQUERY
    ares_cancelquery(Ares_Channel, IdentListenS);
#endif
    return;
  }
  if (IdentListen_IsListening(IdentListenS)) { DEBUGPRINT(BITMASK_DEBUG_IDENT, "Ident daemon %s(%s):%ld stopped.", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH); }
  if (IdentListen_IsSocket(IdentListenS)) {
    close(IdentListenS->FD);
    IdentListenS->FD = FD_NONE;
  }
  ident_listen_init(IdentListenS);

}

/* IDENT_LISTEN_FDS - JONAS (03.07.2003) */

void ident_listen_fds(fd_set *ReadFDS, fd_set *WriteFDS, unsigned long int *FDS) {

  struct IdentListen_Struct *IdentListenS = NULL;

  for (IdentListenS = IdentListen_Head ; IdentListenS != NULL ;) {
    if (IdentListen_IsRemove(IdentListenS)) {
      struct IdentListen_Struct *IdentListenS_DEL = NULL;
      if (IdentListen_IsResolving(IdentListenS)) { continue; }
      ident_listen_stop(IdentListenS);
      IdentListenS_DEL = IdentListenS;
      IdentListenS = IdentListenS->Next;
      ident_listen_rem(IdentListenS_DEL);
      continue;
    }
    if (IdentListen_IsListening(IdentListenS)) { FD_SET(IdentListenS->FD, ReadFDS); }
    else {
      if (!IdentListen_IsResolving(IdentListenS)) {
        unsigned long int Duration = (NOW - IdentListenS->Time);
        if (Duration >= IDENTLISTEN_INTERVAL) { ident_listen_start(IdentListenS); }
      }
    }
    IdentListenS = IdentListenS->Next;
  }

}

/* IDENT_LISTEN_IO - JONAS (03.07.2003) */

void ident_listen_io(fd_set *ReadFDS, fd_set *WriteFDS, unsigned long int *FDS) {

  struct IdentListen_Struct *IdentListenS = NULL;
  struct IdentConn_Struct *IdentConnS = NULL;
  signed long int Result = 0;
  unsigned long int FD = 0;
  struct in_addr INAddr;
  struct sockaddr_in SockAddr = { 0 };
  accept_addrlen_type SockAddrLen = sizeof(SockAddr);
#if IPV6_SUPPORT
  struct in6_addr INAddr6;
  struct sockaddr_in6 SockAddr6 = { 0 };
  accept_addrlen_type SockAddrLen6 = sizeof(SockAddr6);
#endif
  char Host[INET6_ADDRSTRLEN+1] = "";
  const char *HostIPPT = NULL;
  unsigned long int PortH;
  unsigned long int PortN;
  unsigned short int Count = 0;

  for (IdentListenS = IdentListen_Head ; IdentListenS != NULL ; IdentListenS = IdentListenS->Next) {

    assert(*FDS >= 0);
    if (*FDS <= 0) { return; }

    if (!IdentListen_IsListening(IdentListenS)) { continue; }

    if (!FD_ISSET(IdentListenS->FD, ReadFDS)) { continue; }
    *FDS = *FDS - 1;

    for (Count = 0 ;; ++Count) {
#if IPV6_SUPPORT
      if (IdentListen_IsIPv6(IdentListenS)) {
        Result = accept(IdentListenS->FD, (struct sockaddr *) &SockAddr6, &SockAddrLen6);
      }
      else {
#endif /* IPV6_SUPPORT */
       Result = accept(IdentListenS->FD, (struct sockaddr *) &SockAddr, &SockAddrLen);
#if IPV6_SUPPORT
      }
#endif /* IPV6_SUPPORT */
      if (Result <= ERROR) {
        if (Count == 0) { sysprint(BITMASK_MAIN, "Ident daemon %s(%s):%ld: Unable to accept new incoming connection: [%d] %s", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno)); }
        break;
      }
      FD = Result;

#if IPV6_SUPPORT
      if (IdentListen_IsIPv6(IdentListenS)) {
        memset(&INAddr6, 0, sizeof(INAddr6));
        INAddr6 = SockAddr6.sin6_addr;
        PortN = SockAddr6.sin6_port;
      }
      else {
#endif /* IPV6_SUPPORT */
        memset(&INAddr, 0, sizeof(INAddr));
        INAddr = SockAddr.sin_addr;
        PortN = SockAddr.sin_port;
#if IPV6_SUPPORT
      }
#endif /* IPV6_SUPPORT */


#if IPV6_SUPPORT
      if (IdentListen_IsIPv6(IdentListenS)) {
        HostIPPT = inet_ntop(AF_INET6, &INAddr6, Host, INET6_ADDRSTRLEN);
        if (HostIPPT == NULL) {
          close(FD);
          sysprint(BITMASK_ERROR, "Ident daemon %s(%s):%ld: Failed inet_ntop() for incoming client: %d [%s].", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
          continue;
        }
      }
      else {
        HostIPPT = inet_ntop(AF_INET, &INAddr, Host, INET6_ADDRSTRLEN);
        if (HostIPPT == NULL) {
          close(FD);
          sysprint(BITMASK_ERROR, "Ident daemon %s(%s):%ld: Failed inet_ntop() for incoming client: %d [%s].", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
          continue;
        }
      }
#else
      HostIPPT = inet_ntoa(INAddr);
      if (HostIPPT == NULL) {
        close(FD);
        sysprint(BITMASK_ERROR, "Ident daemon %s(%s):%ld: Failed inet_ntoa() for incoming client: %d [%s].", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, errno, strerror(errno));
        continue;
      }
#endif

      IdentConnS = ident_conn_add(HostIPPT, FD);
      if (IdentConnS == NULL) {
        close(FD);
        continue;
      }
      IdentConnS->PortH = PortH;
      IdentConnS->PortN = PortN;

#if IPV6_SUPPORT
      if (IdentListen_IsIPv6(IdentListenS)) {
        IdentConnS->INAddr6 = INAddr6;
      }
      else {
#endif
        IdentConnS->INAddr = INAddr;
#if IPV6_SUPPORT
      }
#endif

      DEBUGPRINT(BITMASK_DEBUG_IDENT, "Ident daemon %s(%s):%ld: Successfully accepted new incoming connection from \"%s\".", IdentListenS->Host, IdentListenS->HostIPS, IdentListenS->PortH, HostIPPT);

    }
  }
}

/* IDENT_LISTEN_CLOSEALL FUNCTION - JONAS (03.07.2003) */

unsigned short int ident_listen_closeall(const char *const MessagePT, ...) {

  struct IdentListen_Struct *IdentListenS = NULL;
  struct IdentListen_Struct *IdentListenS_DEL = NULL;
  unsigned short int Count = 0;

  for (IdentListenS = IdentListen_Head ; IdentListenS != NULL ;) {
    if (IdentListen_IsResolving(IdentListenS)) {
#if HAVE_ARES_CANCELQUERY
      ares_cancelquery(Ares_Channel, IdentListenS);
#endif
      ++Count;
      IdentListen_SetRemove(IdentListenS);
      continue;
    }
    ident_listen_stop(IdentListenS);
    IdentListenS_DEL = IdentListenS;
    IdentListenS = IdentListenS->Next;
    ident_listen_rem(IdentListenS_DEL);
  }

  return(Count);

}



syntax highlighted by Code2HTML, v. 0.9.1