/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Listen I/O 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 (15.11.2006)
 *
 */

#define LISTEN_IO_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 1			/* Needed for SSL support */

#include "includes.h"

#include "conf.h"

#include "listen.h"
#include "listen_io.h"
#include "client.h"
#include "client_connection.h"

/* VARIABLES - JONAS (06.10.2000) */

extern struct Conf_Struct ConfS;
extern struct Listen_Struct *Listen_Head;
extern struct Listen_Struct *Listen_Tail;
extern struct Client_Struct *Client_Head;
#if ARES
  extern ares_channel Ares_Channel;
#endif
#if SSL_SUPPORT
  extern SSL_CTX *IRCPROXY_SSL_SERVER_CTX;
  extern SSL_CTX *IRCPROXY_SSL_CLIENT_CTX;
#endif

/* LISTEN_START - JONAS (22.07.2001) */

void listen_start(struct Listen_Struct *ListenS) {

  signed long int Result = 0;
  struct sockaddr_in SockAddr = { 0 };
#if IPV6_SUPPORT
  struct sockaddr_in6 SockAddr6 = { 0 };
#endif
  unsigned long int Flags = 0;

  assert(ListenS != NULL);

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

  DEBUGPRINT(BITMASK_DEBUG_LISTEN, "*** DEBUG *** listen_start(%s)", ListenS->Host);

  if (!Listen_IsResolved(ListenS)) {

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

    if (ListenS->Host[0] == '*') {
#if IPV6_SUPPORT
      if (Listen_IsIPv6(ListenS)) {
        memset(&ListenS->INAddr6, 0, sizeof(ListenS->INAddr6));
        ListenS->INAddr6 = in6addr_any;
      }
      else {
#endif /* IPV6_SUPPORT */
        memset(&ListenS->INAddr, 0, sizeof(ListenS->INAddr));
        ListenS->INAddr.s_addr = INADDR_ANY;
#if IPV6_SUPPORT
      }
#endif /* IPV6_SUPPORT */
      ListenS->HostIPS = strrealloc(ListenS->HostIPS, "ALL");
      Listen_SetResolved(ListenS);
    }
    else {
#if IPV6_SUPPORT
      if (Listen_IsIPv6(ListenS)) {
        memset(&ListenS->INAddr6, 0, sizeof(ListenS->INAddr6));
        Result = inet_pton(AF_INET6, ListenS->Host, &ListenS->INAddr6);
      }
      else {
        memset(&ListenS->INAddr, 0, sizeof(ListenS->INAddr));
        Result = inet_pton(AF_INET, ListenS->Host, &ListenS->INAddr);
      }
#else /* IPV6_SUPPORT */
      memset(&ListenS->INAddr, 0, sizeof(ListenS->INAddr));
      Result = inet_aton(ListenS->Host, &ListenS->INAddr);
#endif /* IPV6_SUPPORT */
      if (Result <= 0) {
        Listen_SetResolving(ListenS);
#if ARES
#if IPV6_SUPPORT
        if (Listen_IsIPv6(ListenS)) {
          ares_gethostbyname(Ares_Channel, ListenS->Host, AF_INET6, (ares_host_callback) listen_hosttoip, ListenS);
        }
        else {
#endif /* IPV6_SUPPORT */
          ares_gethostbyname(Ares_Channel, ListenS->Host, AF_INET, (ares_host_callback) listen_hosttoip, ListenS);
#if IPV6_SUPPORT
        }
#endif /* IPV6_SUPPORT */
        return;
#else /* ARES */
#if IPV6_SUPPORT
        if (Listen_IsIPv6(ListenS)) { HostEnt = gethostbyname2(ListenS->Host, AF_INET6); }
        else { HostEnt = gethostbyname2(ListenS->Host, AF_INET); }
#else /* IPV6_SUPPORT */
        HostEnt = gethostbyname(ListenS->Host);
#endif /* IPV6_SUPPORT */
        listen_hosttoip(ListenS, errno, HostEnt);
        if (!Listen_IsResolved(ListenS)) { return; }
#endif /* ARES */
      }
      else {
        Listen_SetResolved(ListenS);
        ListenS->HostIPS = strrealloc(ListenS->HostIPS, ListenS->Host);
        if (aerrno != AESUCCESS) { listen_init(ListenS); return; }
      }
    }
  }

  /* CREATE SOCKET */

#if IPV6_SUPPORT
  if (Listen_IsIPv6(ListenS)) {
    Result = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
  }
  else {
#endif
    Result = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#if IPV6_SUPPORT
  }
#endif
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Listener %s(%s):%ld%s: Unable to create socket: [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
    listen_stop(ListenS);
    return;
  }
  ListenS->FD = Result;
  Listen_SetSocket(ListenS);

  /* SET SOCKET IN NON-BLOCKING MODE */

#if defined(NBLOCK_SYSV)
  Flags = 1;
  Result = ioctl(ListenS->FD, FIONBIO, &Flags);
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Listener %s(%s):%ld%s: Unable to set socket in non-blocking mode using ioctl(): [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
    listen_stop(ListenS);
    return;
  }
#else
  Result = fcntl(ListenS->FD, F_GETFL, &Flags);
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Listener %s(%s):%ld%s: Unable to get socket flags using fcntl(): [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
    listen_stop(ListenS);
    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(ListenS->FD, F_SETFL, Flags);
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Listener %s(%s):%ld%s: Unable to set socket in non-blocking mode using fcntl(): [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
    listen_stop(ListenS);
    return;
  }
#endif

  if (LISTEN_SOCKKEEPALIVE == TRUE) {

    unsigned long int OPT = 1;

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

  }

  if (LISTEN_SOCKREUSEADDR == TRUE) {

    unsigned long int OPT = 1;

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

  }

  /* BIND */

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

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

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

  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Listener %s(%s):%ld%s: Unable to bind socket to address: [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
    listen_stop(ListenS);
    return;
  }

  /* LISTEN */

  Result = listen(ListenS->FD, SOMAXCONN);
  if (Result <= ERROR) {
    sysprint(BITMASK_MAIN, "Listener %s(%s):%ld%s: Unable to listen on address: [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
    listen_stop(ListenS);
    return;
  }
  else {
    sysprint(BITMASK_MAIN, "Listening on %s(%s):%ld%s for incoming connections.", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""));
    Listen_SetListening(ListenS);
    return;
  }

}

/* LISTEN_HOSTTOIP FUNCTION - JONAS (01.03.2000) */

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

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

  assert(ListenS != NULL);

  if ((HostEnt == NULL) || (HostEnt->h_length < 1)) {
    sysprint(BITMASK_MAIN, "Listener %s:%ld%s: Unable to resolve host %s to IP-address: [%d] %s", ListenS->Host, ListenS->PortH, ListenS->Host, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), ErrNo, res_strerror(ErrNo));
    listen_init(ListenS);
    return;
  }

#if IPV6_SUPPORT
  if (Listen_IsIPv6(ListenS)) {
    memset(&ListenS->INAddr6, 0, sizeof(ListenS->INAddr6));
    memcpy(&ListenS->INAddr6, HostEnt->h_addr, HostEnt->h_length);
    HostIPPT = inet_ntop(AF_INET6, &ListenS->INAddr6, Host, INET6_ADDRSTRLEN);
    if (HostIPPT == NULL) {
      sysprint(BITMASK_MAIN, "Listener %s:%ld%s: inet_ntop() failed: [%d] %s", ListenS->Host, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
      listen_init(ListenS);
      return;
    }
  }
  else {
    memset(&ListenS->INAddr, 0, sizeof(ListenS->INAddr));
    memcpy(&ListenS->INAddr, HostEnt->h_addr, HostEnt->h_length);
    HostIPPT = inet_ntop(AF_INET, &ListenS->INAddr, Host, INET_ADDRSTRLEN);
    if (HostIPPT == NULL) {
      sysprint(BITMASK_MAIN, "Listener %s:%ld%s: inet_ntop() failed: [%d] %s", ListenS->Host, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
      listen_init(ListenS);
      return;
    }
  }
#else /* IPV6_SUPPORT */
  memset(&ListenS->INAddr, 0, sizeof(ListenS->INAddr));
  memcpy(&ListenS->INAddr, HostEnt->h_addr, HostEnt->h_length);
  HostIPPT = inet_ntoa(ListenS->INAddr);
  if (HostIPPT == NULL) {
    sysprint(BITMASK_MAIN, "Listener %s:%ld%s: inet_ntoa() failed: [%d] %s", ListenS->Host, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
    listen_init(ListenS);
    return;
  }
#endif
  ListenS->HostIPS = strrealloc(ListenS->HostIPS, HostIPPT);
  if (ListenS->HostIPS == NULL) {
    listen_init(ListenS);
    return;
  }

  Listen_ClearResolving(ListenS);
  Listen_SetResolved(ListenS);

#if ARES
  listen_start(ListenS);
#endif

}

/* LISTEN_STOP - JONAS (05.10.2000) */

void listen_stop(struct Listen_Struct *ListenS) {

  assert(ListenS != NULL);

  if (Listen_IsResolving(ListenS)) {
#if HAVE_ARES_CANCELQUERY
    ares_cancelquery(Ares_Channel, ListenS);
#endif
    return;
  }

  if (Listen_IsListening(ListenS)) { sysprint(BITMASK_MAIN, "Listener %s(%s):%ld%s has stopped.", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : "")); }
  if (Listen_IsSocket(ListenS)) {
    close(ListenS->FD);
    ListenS->FD = FD_NONE;
  }

  listen_init(ListenS);

}

/* LISTEN_FDS - JONAS (22.07.2001) */

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

  struct Listen_Struct *ListenS = NULL;

  for (ListenS = Listen_Head ; ListenS != NULL ;) {
    if (Listen_IsRemove(ListenS)) {
      struct Listen_Struct *ListenS_DEL = NULL;
      if (Listen_IsResolving(ListenS)) { continue; }
      listen_stop(ListenS);
      ListenS_DEL = ListenS;
      ListenS = ListenS->Next;
      listen_rem(ListenS_DEL);
      continue;
    }
    if (Listen_IsListening(ListenS)) { FD_SET(ListenS->FD, ReadFDS); }
    else {
      if (!Listen_IsResolving(ListenS)) {
        time_t Duration = (NOW - ListenS->Time);
        if (Duration >= LISTEN_INTERVAL) {
#if SSL_SUPPORT
          if (ConfS.SSLSupport == TRUE) { listen_start(ListenS); }
          else if (!Listen_IsSSL(ListenS)) { listen_start(ListenS); }
#else
          if (!Listen_IsSSL(ListenS)) { listen_start(ListenS); }
#endif
        }
      }
    }
    ListenS = ListenS->Next;
  }

}

/* LISTEN_IO - JONAS (06.10.2000) */

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

  struct Listen_Struct *ListenS = NULL;

  for (ListenS = Listen_Head ; ListenS != NULL ; ListenS = ListenS->Next) {

    unsigned short int Count = 0;

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

    if (!Listen_IsListening(ListenS)) { continue; }
    if (!FD_ISSET(ListenS->FD, ReadFDS)) { continue; }
    *FDS = *FDS - 1;
    assert(*FDS >= 0);

    for (Count = 0 ;; ++Count) {

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

#if SSL_SUPPORT
      SSL *ClientSSL = NULL;
#endif

#if IPV6_SUPPORT
      if (Listen_IsIPv6(ListenS)) {
        Result = accept(ListenS->FD, (struct sockaddr *) &SockAddr6, &SockAddrLen6);
      }
      else {
#endif /* IPV6_SUPPORT */
        Result = accept(ListenS->FD, (struct sockaddr *) &SockAddr, &SockAddrLen);
#if IPV6_SUPPORT
      }
#endif /* IPV6_SUPPORT */

      if (Result <= ERROR) {
        if (Count == 0) { sysprint(BITMASK_MAIN, "Unable to accept incoming connection on address \"%s(%s):%ld\": [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, errno, strerror(errno)); }
        return;
      }

      FD = Result;

#if SSL_SUPPORT
      if ((Listen_IsSSL(ListenS)) && (IRCPROXY_SSL_SERVER_CTX == NULL)) { /* This is fatal and should never happen under normal circumstances */
        sysprint(BITMASK_MAIN, "Closing socket to incoming connection on address \"%s(%s):%ld\": Missing SSL_CTX object.", ListenS->Host, ListenS->HostIPS, ListenS->PortH);
        close(FD);
        continue;
      }
#endif

#if IPV6_SUPPORT
      if (Listen_IsIPv6(ListenS)) {
        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 */

      PortH = ntohs(PortN);

#if IPV6_SUPPORT
      if (Listen_IsIPv6(ListenS)) {
        HostIPPT = inet_ntop(AF_INET6, &INAddr6, Host, INET6_ADDRSTRLEN);
        if (HostIPPT == NULL) {
          close(FD);
          sysprint(BITMASK_MAIN, "Failed inet_ntop() for incoming client connection on \"%s(%s):%ld%s\": [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
          continue;
        }
      }
      else {
        HostIPPT = inet_ntop(AF_INET, &INAddr, Host, INET6_ADDRSTRLEN);
        if (HostIPPT == NULL) {
          close(FD);
          sysprint(BITMASK_MAIN, "Failed inet_ntop() for incoming client connection on \"%s(%s):%ld%s\": [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
          continue;
        }
      }
#else
      HostIPPT = inet_ntoa(INAddr);
      if (HostIPPT == NULL) {
        close(FD);
        sysprint(BITMASK_MAIN, "Failed inet_ntoa() for incoming client connection on \"%s(%s):%ld%s\": [%d] %s", ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
        continue;
      }
#endif
      sysprint(BITMASK_MAIN, "Incoming client connection from \"%s:%ld\" on \"%s(%s):%ld%s\".", HostIPPT, PortH, ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""));

  /* SET SOCKET IN NON-BLOCKING MODE */

#if defined(NBLOCK_SYSV)
      Flags = 1;
      Result = ioctl(FD, FIONBIO, &Flags);
      if (Result <= ERROR) {
        sysprint(BITMASK_MAIN, "Unable to set socket in non-blocking mode using ioctl() for incoming client \"%s:%ld\" on \"%s(%s):%ld%s\".: [%d] %s", HostIPPT, PortH, ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
        close(FD);
        continue;
      }
#else
      Result = fcntl(FD, F_GETFL, &Flags);
      if (Result <= ERROR) {
        sysprint(BITMASK_MAIN, "Unable to get socket flags using fcntl() for incoming client \"%s:%ld\" on \"%s(%s):%ld%s\".: [%d] %s", HostIPPT, PortH, ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
        close(FD);
        continue;
      }
#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(FD, F_SETFL, Flags);
    if (Result <= ERROR) {
       sysprint(BITMASK_MAIN, "Unable to set socket in non-blocking mode using fcntl() for incoming client \"%s:%ld\" on \"%s(%s):%ld%s\".: [%d] %s", HostIPPT, PortH, ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
        close(FD);
        continue;
    }
#endif

#if SSL_SUPPORT
      if (Listen_IsSSL(ListenS)) {
        assert(IRCPROXY_SSL_SERVER_CTX != NULL);
        ClientSSL = SSL_new(IRCPROXY_SSL_SERVER_CTX);
        if (ClientSSL == NULL) {
          close(FD);
          sysprint(BITMASK_MAIN, "Failed to create a new SSL structure for incoming client connection from \"%s:%ld\" on \"%s(%s):%ld%s\".: [%d] %s.", HostIPPT, PortH, ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), errno, strerror(errno));
          continue;
        }
        Result = SSL_set_fd(ClientSSL, FD);
        if (Result <= 0) {
          signed long int sslerrno = SSL_get_error(ClientSSL, Result);
          close(FD);
          SSL_free(ClientSSL);
          sysprint(BITMASK_MAIN, "Failed to connect the SSL object with file descriptor for incoming client connection from \"%s:%ld\" on \"%s(%s):%ld%s\".: [%ld] %s.", HostIPPT, PortH, ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""), sslerrno, ERR_error_string(sslerrno, NULL));
          continue;
        }
        SSL_set_accept_state(ClientSSL);
      }
#endif /* SSL_SUPPORT */

      ClientS = client_add(ListenS, HostIPPT);
      if (ClientS == NULL) {
        close(FD);
#if SSL_SUPPORT
        SSL_free(ClientSSL);
#endif
        sysprint(BITMASK_MAIN, "Failed to allocate client structure for incoming client connection from \"%s:%ld\" on \"%s(%s):%ld%s\".", HostIPPT, PortH, ListenS->Host, ListenS->HostIPS, ListenS->PortH, (Listen_IsSSL(ListenS) ? "(SSL)" : ""));
        continue;
      }

      ClientS->FD = FD;
      ClientS->HostIPS = strrealloc(ClientS->HostIPS, HostIPPT);
      ClientS->PortH = PortH;
      ClientS->PortN = PortN;

#if IPV6_SUPPORT
      if (Listen_IsIPv6(ListenS)) {
        memset(&ClientS->INAddr6, 0, sizeof(ClientS->INAddr6));
        ClientS->INAddr6 = INAddr6;
        Client_SetIPv6(ClientS);
      }
      else {
#endif
        memset(&ClientS->INAddr, 0, sizeof(ClientS->INAddr));
        ClientS->INAddr = INAddr;
#if IPV6_SUPPORT
      }
#endif

#if SSL_SUPPORT
      if (Listen_IsSSL(ListenS)) {
        Client_SetSSL(ClientS);
        ClientS->SSL_H = ClientSSL;
      }
#endif

      client_resolve(ClientS);

    }
  }

}

/* LISTEN_CLOSEALL FUNCTION - JONAS (09.06.2001) */

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

  struct Listen_Struct *ListenS = NULL;
  struct Listen_Struct *ListenS_DEL = NULL;
  unsigned short int Count = 0;

  for (ListenS = Listen_Head ; ListenS != NULL ;) {
    if (Listen_IsResolving(ListenS)) {
#if HAVE_ARES_CANCELQUERY
      ares_cancelquery(Ares_Channel, ListenS);
#endif
      ++Count;
      Listen_SetRemove(ListenS);
      continue;
    }
    listen_stop(ListenS);
    ListenS_DEL = ListenS;
    ListenS = ListenS->Next;
    listen_rem(ListenS_DEL);
  }

  return(Count);

}

 


syntax highlighted by Code2HTML, v. 0.9.1