/**
 * @package de.atwillys.cc.swl
 * @license BSD (simplified)
 * @author Stefan Wilhelm (stfwi)
 *
 * @socket.hh
 * @ccflags
 * @ldflags -lpthread
 * @platform linux, bsd, windows
 * @standard >= c++98
 *
 * -----------------------------------------------------------------------------
 *
 * Template based socket handling, contains classes that you can extend to implement:
 *
 *  - TCP sockets:
 *      - class sw::sock::tcp_client    : Client class, connects to servers
 *      - class sw::sock::tcp_acceptor  : Server class dealing with the requests
 *      - template class sw::sock::tcp_server<acceptor_type>: Listening server
 *
 *  - UDP sockets:
 *      - class sw::sock::udp_socket    : UDP socket class
 *
 * All you actually have to to is to overload callback methods. The rest of the socket
 * handling is pretty much done in the base classes.
 *
 * REQUIRES header file "sw/thread.hh"
 *
 * -----------------------------------------------------------------------------
 * +++ BSD license header +++
 * Copyright (c) 2008-2014, Stefan Wilhelm (stfwi, <cerbero s@atwilly s.de>)
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met: (1) Redistributions
 * of source code must retain the above copyright notice, this list of conditions
 * and the following disclaimer. (2) Redistributions in binary form must reproduce
 * the above copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the distribution.
 * (3) Neither the name of atwillys.de nor the names of its contributors may be
 * used to endorse or promote products derived from this software without specific
 * prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
 * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 * -----------------------------------------------------------------------------
 */
#ifndef SW_SOCKET_HH
#define SW_SOCKET_HH

// <editor-fold desc="includes" defaultstate="collapsed">
#ifdef __MSC_VER
#ifndef OS_WIN
#define OS_WIN
#endif
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
typedef unsigned long sa_family_t;
#define swsck SOCKET
#define swsck_inv (INVALID_SOCKET)
#define swsck_err (SOCKET_ERROR)
#define swsck_eno ((long)(::WSAGetLastError()))
#define swsck_eintr (WSAEINTR)
#define swsck_nexist (WSAENOTSOCK)
#define swsck_timeout (WSAETIMEDOUT)
#define swsck_eagain (WSAEWOULDBLOCK)
#define swsck_default_timeout (1000)
typedef int socklen_t;
typedef unsigned long sa_family_t;
typedef USHORT in_port_t;
#define MSG_DONTWAIT 0
namespace sw { namespace detail {
template <typename wserr_t>
class winsock_init {
public:
  winsock_init() { err = ::WSAStartup(MAKEWORD(2, 2), &wsadata); }
  virtual ~winsock_init() { ::WSACleanup(); }
  typename wserr_t err;
  WSADATA wsadata;
  static winsock_init _wsinit;
};
//template <typename wserr_t> winsock_init<wserr_t>::_wsinit;
}}
namespace sw { namespace sock {
  typedef sw::detail::winsock_init<int> winsock_initializer;
}}
#else
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/poll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <cstdlib>
#define swsck int
#define swsck_inv (-1)
#define swsck_err (-1)
#define swsck_eno (errno)
#define swsck_eintr (EINTR)
#define swsck_nexist (ENOTSOCK)
#define swsck_timeout (ETIMEDOUT)
#define swsck_eagain (EWOULDBLOCK)
#define swsck_default_timeout (100)
#endif
#include "thread.hh"
#include <string>
#include <sstream>
#include <algorithm>
#include <exception>
#include <limits>
#include <vector>

#ifdef SOCK_DEBUG
#include <cstdio>
#include <stdarg.h>
template <typename char_t> static void sck_ctrace(const char_t* ptrn, ...)
{ va_list args; va_start(args, ptrn); vfprintf(stderr, ptrn, args);
  fprintf(stderr, "\n"); fflush(stderr); va_end(args); }
#else
template <typename char_t> static inline void sck_ctrace(const char_t*, ...) {;}
#endif
#undef ctrace
#define ctrace sck_ctrace
#undef ctracem
#define ctracem sck_ctrace
// </editor-fold>

// <editor-fold desc="basic_ip_address" defaultstate="collapsed">
/**
 * class basic_ip_address
 * Organizes basic operations with IP addresses, ports,
 * cast from and to inet_addr and string. Parses addresses with ports, e.g.
 * http://127.0.0.1, ftp://localhost, 192.168.0.1:23, google.de:80
 */
namespace sw { namespace detail {
template <typename char_type=char>
class basic_ip_address
{
public:

  typedef sockaddr_storage address_type;  // socket storage
  typedef socklen_t addresslen_type;      // socket data length
  typedef in_port_t port_type;            // inet port type
  typedef char_type char_t;               // string character type
  typedef std::string str_t;              // string type
  typedef typename str_t::size_type sz_t; // string size type

  /**
   * Socket family type abstraction, values correspond to AF_UNSPEC/AF_INET/AF_INET6
   */
  enum family_sel { family_any=AF_UNSPEC, family_ipv4=AF_INET, family_ipv6=AF_INET6 };

  /**
   * Socket type type abstraction, values correspond to SOCK_STREAM/SOCK_DGRAM.
   */
  enum type_sel   { type_any=0, type_tcp=SOCK_STREAM, type_udp=SOCK_DGRAM };

  /**
   * Intermediate storage data type for address lookups.
   */
  struct hostlookup_data_t {
    str_t saddr, shost; enum family_sel family; addresslen_type size; address_type adr;
  };
  /**
   * Intermediate list type for address lookups.
   */
  typedef std::vector<hostlookup_data_t> hostlookup_list_t;

public:

  /**
   * Standard constructor, initial invalid address
   **/
  inline basic_ip_address() : size_(0), mask_(0)
  { clear(); }

  /**
   * Constructor (copy constructor)
   **/
  inline basic_ip_address(const basic_ip_address & ip) : address_(ip.address_), size_(ip.size_),
          mask_(ip.mask_)
  { ; }

  /**
   * Constructor from local byte order address and port.
   * Note: Only IPV6 and IPV6 addresses are assigned, other address families have to be
   *       explicitly set using the methods address(const address_type&) and size(socklen_t).
   **/
  inline basic_ip_address(address_type adr, port_type port) : address_(adr), size_(0), mask_(0)
  {
    if(address_.ss_family == AF_INET6) size_ = sizeof(struct sockaddr_in6);
    if(address_.ss_family == AF_INET) size_ = sizeof(struct sockaddr_in);
    this->port(port);
  }

  /**
   * Constructor from dotted string, optional with port ( "127.0.0.1:21" or "127.0.0.1")
   * If no port is defined, the port is unchanged = 0
   **/
  basic_ip_address(const char *s)
  { str(s); }

  /**
   * Constructor from dotted string, optional with port ( "127.0.0.1:21" or "127.0.0.1")
   * If no port is defined, the port is unchanged = 0
   **/
  basic_ip_address(const str_t & s)
  { str(s); }

  /**
   * Constructor from ip v4 inet address type
   **/
  basic_ip_address(struct sockaddr_in sa)
  { operator =(sa); }

  /**
   * Constructor from ip v6 inet address type
   **/
  basic_ip_address(struct sockaddr_in6 sa)
  { operator =(sa); }

  /**
   * Destructor
   **/
  virtual ~basic_ip_address()
  { }

public:

  /**
   * Invalidates the address
   */
  inline void clear()
  { memset(&address_, 0, sizeof(address_type)); mask_=0; size_=0; }

  /**
   * Returns if the address is set
   */
  inline bool valid() const throw ()
  { return address_.ss_family != 0 && size_ != 0; }

  /**
   * Returns if the currently stored address is IP V4
   * @return bool
   */
  inline bool is_v4() const throw()
  { return address_.ss_family == AF_INET; }

  /**
   * Returns if the currently stored address is IP V6
   * @return bool
   */
  inline bool is_v6() const throw()
  { return address_.ss_family == AF_INET6; }

  /**
   * Returns the address (storage type)
   */
  inline const address_type & address() const throw ()
  { return address_; }

  /**
   * Clears the object and sets the address (storage type). You have to set the data size
   * yourself if the family is not AF_INET or AF_INET6, otherwise the object is !valid().
   **/
  void address(const address_type & adr) throw ()
  {
    clear();
    if(adr.ss_family == AF_INET) size_ = sizeof(sockaddr_in);
    else if(adr.ss_family == AF_INET6) size_ = sizeof(sockaddr_in6);
    address_ = adr;
  }

  /**
   * Rreturns the address family
   **/
  inline sa_family_t family() const throw ()
  { return address_.ss_family; }

  /**
   * Sets the address family. Most assignment methods of this object set the family implicitly.
   * This function is required when defining addresses that are not AF_INET or AF_INET6.
   **/
  inline void family(sa_family_t family__) throw ()
  { address_.ss_family = family__; }

  /**
   * Returns the data size of the address structure dependent on the family set
   * (sockaddr_in or sockaddr_in6).
   * @return socklen_t
   */
  socklen_t size() const throw()
  { return size_; }

  /**
   * Sets the data size of the address structure (sockaddr_in, sockaddr_in6 ...).
   * Note: If you set it, it must be correct. Subsequent operations rely on it.
   * @return socklen_t
   */
  inline void size(socklen_t sz) throw()
  { size_ = sz; }

  /**
   * Returns the port (only for AF_INET or AF_INET6, otherwise 0) or 0 if not set yet.
   */
  port_type port() const throw ()
  {
    if(address_.ss_family == AF_INET) return ntohs(((sockaddr_in*)&address_)->sin_port);
    if(address_.ss_family == AF_INET6) return ntohs(((sockaddr_in6*)&address_)->sin6_port);
    return 0;
  }

  /**
   * Sets the port (only for AF_INET or AF_INET6). For other families you must set the
   * port directly in the corresponding sockaddr_### structure and assign the storage type
   * to this address.
   */
  bool port(port_type port__) throw ()
  {
    if(address_.ss_family == AF_INET)  {
      ((sockaddr_in*)&address_)->sin_port = htons(port__);
      return true;
    } else if(address_.ss_family == AF_INET6) {
      ((sockaddr_in6*)&address_)->sin6_port = htons(port__);
      return true;
    }
    return false;
  }

  /**
   * Set the subnet mask bit count, e.g. 24 for a /24 network.
   * Note: Has currently only informational purpose and has no effect in any methods.
   * @param unsigned char msk
   * @return bool
   */
  bool subnet_mask(unsigned char msk) throw()
  {
    mask_ = 0;
    if(address_.ss_family == AF_INET && msk > 32) return false;
    if(address_.ss_family == AF_INET6 && msk > 128) return false;
    mask_ = msk;
    return true;
  }

  /**
   * Returns the subnet mask bit count (e.g. 24 for a /24 network), which may be set explicitly
   * or parsed from string assignments.
   * Note: Has currently only informational purpose and has no effect in any methods.
   * @return unsigned char
   */
  inline unsigned char subnet_mask() const throw()
  { return mask_; }

  /**
   * String representation of the address (without port, service etc - only the plain address)
   * @return str_t
   */
  str_t str() const
  {
    char s[INET6_ADDRSTRLEN+2];
    s[sizeof(s)-1] = '\0';
    if(address_.ss_family == AF_INET6) {
      return !::inet_ntop(AF_INET6, &(((struct sockaddr_in6*)&address_)->sin6_addr), s, sizeof(s)) ? str_t() : s;
    } else if(address_.ss_family == AF_INET) {
      return !::inet_ntop(AF_INET, &(((struct sockaddr_in*)&address_)->sin_addr), s, sizeof(s)) ? str_t() : s;
    } else {
      return str_t();
    }
  }

  /**
   * Set resource path with ip, port and path from string.
   * Note: This method does not perform host lookups.
   * - 192.168.0.1    (v4 address)
   * - a::bcd0        (v6 address)
   * - 127.0.0.1:1234 (v4 address : port)
   * - [::1]:1234     (v6 address : port)
   * - [::1/64]:1234  (v6 address / mask : port)
   */
  bool str(str_t adr)
  {
    clear();
    if(adr.length() < 2) return false; // shortest: "::"
    str_t port, subn;
    sz_t p;
    if((p = adr.find('[')) != str_t::npos) { // [ v6 address </subn?> ] <:port?>
      sz_t p1 = adr.find(']');
      if(p != 0 || p1==str_t::npos || p1 < p) return false; // if [ is must be at the beginning
      if(p1 > 0 && (p1 < adr.length()-1)) {
        port = adr.substr(p1+1); // port may be empty or still contain ":"
      }
      adr.resize(p1);
      adr = adr.substr(p+1); // [ ] stripped, address may contain net mask
    } else if(adr.find(']') != str_t::npos) {
      return false; // ] without [
    }
    if((p = adr.find('/')) != str_t::npos) { // <v4/v6 address> </subn?> <:port?>
      if(p >= adr.length()-1) return false; // / is last character
      subn = adr.substr(p+1);
      sz_t p1 = subn.find(':');
      if(p1 != str_t::npos) {
        if(!port.empty()) return false; // [address/sub:port]:port not allowed
        if(p1==0 || p1 >= subn.length()-1) return false; // : is first or last char
        port = subn.substr(p1+1);
        subn.resize(p1);
      }
      adr.resize(p);  // <v4/v6 address>
    } else if((p=adr.find(':')) != str_t::npos) { // check if v4 with port
      if(adr.rfind(':') == p) { // only one ":" ->v4 is in the string (v6 has at least 2)
        if(!port.empty()) return false; // not possible
        if(p==0 || p >= subn.length()-1) return false; // : is first or last char
        port = adr.substr(p+1); // port may be empty or still contain :
        adr.resize(p);
      }
    }
    if(!port.empty() && port[0] == ':') { // Remove potential leading colon
      port = port.substr(1);
    }
    if(!port.empty() && (unsigned)std::count_if(port.begin(), port.end(), ::isdigit) < port.length()) {
      return false; // port contains non-digits
    } else if(subn.length() > 3) {
      return false; // even v6 subnet spec has only 3 digits
    } else  if(!subn.empty() && (unsigned)std::count_if(subn.begin(),subn.end(),::isdigit)<subn.length()) {
      return false; // subnet contains non-digits
    }
    // adr is now a plain v4, v6 or invalid address
    if(adr.find(':') != str_t::npos) {
      // assume v6
      struct sockaddr_in6 addr;
      memset(&addr, 0, sizeof(struct sockaddr_in6));
      addr.sin6_family = AF_INET6;
      addr.sin6_port = htons(0);
      if(::inet_pton(AF_INET6, adr.c_str(), &(addr.sin6_addr)) != 1) return false;
      size_ = sizeof(struct sockaddr_in6);
      address_.ss_family = AF_INET6;
      ((struct sockaddr_in6*)&address_)->sin6_addr = addr.sin6_addr;
      //((struct sockaddr_in6)&address_)->sin6_scope_id = ;
      //((struct sockaddr_in6)&address_)->sin6_flowinfo = ;
    } else {
      // assume v4
      struct sockaddr_in addr;
      memset(&addr, 0, sizeof(struct sockaddr_in));
      addr.sin_family = AF_INET;
      addr.sin_port = htons(0);
      if(::inet_pton(AF_INET, adr.c_str(), &(addr.sin_addr)) != 1) return false;
      size_ = sizeof(struct sockaddr_in);
      address_.ss_family = AF_INET;
      ((struct sockaddr_in*)&address_)->sin_addr = addr.sin_addr;
    }
    if(!subn.empty() && !subnet_mask((unsigned char)(::atol(subn.c_str()) & 0xff))) return false;
    if(!port.empty()) basic_ip_address::port((port_type)(::atol(port.c_str()))); // port check, only digits
    return true;
  }

public:

  /**
   * Copy assignment
   * @param const basic_ip_address & ip
   */
  inline void operator=(const basic_ip_address & ip) throw ()
  { address_ = ip.address_; size_ = ip.size_; mask_ = ip.mask_; }

  /**
   * IPV4 address copy assignment. Does not modify port or mask.
   * @param const sockaddr_in & adr
   */
  inline void operator=(const sockaddr_in & adr) throw ()
  { *((sockaddr_in*)&address_)=adr; address_.ss_family=AF_INET; size_=sizeof(struct sockaddr_in); }

  /**
   * IPV6 address copy assignment. Does not modify port or mask.
   * @param const sockaddr_in6 & adr
   */
  inline void operator=(const sockaddr_in6 & adr) throw ()
  { *((sockaddr_in6*)&address_)=adr; address_.ss_family=AF_INET6; size_=sizeof(struct sockaddr_in6);}

  /**
   * String assignment
   * @param const str_t & ip
   */
  inline void operator=(const str_t & ip)
  { str(ip); }

  /**
   * Sets new address from C string (optional with port). e.g. "127.0.0.1" or "127.0.0.1:21" are valid arguments
   * @param const char* ip
   **/
  inline void operator=(const char* ip)
  { str(ip); }

  /**
   * Type cast to sockaddr_in structure.
   * Note: If the address is not IPV4, these data is not valid. There is no conversion.
   * @return const struct sockaddr_in & ()
   **/
  operator const struct sockaddr_in & () const throw ()
  { return *((sockaddr_in*) &address_); };

  /**
   * Type cast to sockaddr_in6 structure
   * Note: If the address is not IPV6, these data is not valid. There is no conversion.
   * @return const struct sockaddr_in6 &
   **/
  operator const struct sockaddr_in6 & () const throw ()
  { return *((sockaddr_in6*) &address_); };

public:

  /**
   * Parse an address and additional data from a resource uri, e.g.
   *
   * - http://user@host:port/path,
   * - ftp://[::1]/path
   * - user@192.168.0.1
   *
   * First argument is your input string, second the address, the rest are the parsed output chunks.
   * Returns success.
   *
   * Note: This is a function intended to be used for ipv4/ipv6 clients.
   * Note: This function is not suitable to be used with subnet mask specifications (e.g. ab::c:d/64)
   *
   * @param str_t res_addr
   * @param basic_ip_address & ip
   * @param str_t & service
   * @param str_t & user
   * @param str_t & host
   * @param str_t & path
   * @param bool lookup_host=false
   * @param enum family_sel family=family_any
   * @param enum type_sel type=type_tcp
   * @return bool
   */
  static bool parse_resource_address(str_t res_addr, basic_ip_address & ip,
    str_t & service, str_t & user, str_t & host, str_t & path, bool lookup_host=false,
    enum family_sel family=family_any, enum type_sel type=type_tcp)
  {
    for(str_t::const_iterator it = res_addr.begin(); it != res_addr.end(); ++it) {
      if(!isprint(*it)) return false;
    }
    sz_t pss, ps;
    if(res_addr.empty()) return false;
    pss = res_addr.find("://"); ps = res_addr.find('/');
    if(pss != 0 && pss != str_t::npos && ps > pss) {
      service = res_addr.substr(0, pss);
      res_addr = res_addr.substr(pss+3);
    }
    if((ps = res_addr.find('/')) != str_t::npos) {
      if(ps == 0) return false; // only path or generally invalid, could cause an exception
      path = res_addr.substr(ps);
      res_addr.resize(res_addr.length() - path.length());
    }
    if((pss = res_addr.find('@')) != str_t::npos) {
      if(pss == 0) return false; // @ first char --> empty user
      user = res_addr.substr(0, pss);
      res_addr = res_addr.substr(pss+1);
    }
    str_t port;
    if(res_addr.find('[') != str_t::npos) {
      if((pss = res_addr.find("]:")) != str_t::npos) {
        if(pss >= res_addr.length()-2) return false;
        port = res_addr.substr(pss+2);
        res_addr.resize(pss+1); // including the ]
        if(std::count_if(port.begin(), port.end(), ::isdigit) < (int)port.length()) return false;
      }
    } else {
      if((pss = res_addr.find(":")) != str_t::npos) {
        if(pss >= res_addr.length()-1) return false;
        port = res_addr.substr(pss+1);
        res_addr.resize(pss);
        if(std::count_if(port.begin(), port.end(), ::isdigit) < (int)port.length()) return false;
      }
    }
    host = res_addr;
    ip.str(res_addr);
    if(!ip.valid() && lookup_host) {
      hostlookup_list_t lst = host_lookup(res_addr, service, family, type);
      for(typename hostlookup_list_t::const_iterator it=lst.begin(); it!=lst.end(); ++it) {
        if(it->family == family_ipv4) {
          ip = *((struct sockaddr_in*)&it->adr);
          break;
        } else if(it->family == family_ipv6) {
          ip = *((struct sockaddr_in6*)&it->adr);
          break;
        } else {
          continue; // Currently other families not handled
        }
      }
    }
    if(port.length() > 0) ip.port((port_type)(::atol(port.c_str())));
    if(ip.port() == 0 && !service.empty()) ip.port(port_by_service(service));
    return false;
  }

  /**
   * Performs a canonical name host lookup using ::getaddrinfo and returns a vector of the
   * resulting data.
   * @param host
   * @param service
   * @param family
   * @param type
   * @return hostlookup_list_t
   */
  static hostlookup_list_t host_lookup(str_t host, str_t service=str_t(),
          enum family_sel family=family_any, enum type_sel type=type_any)
  {
    hostlookup_list_t lst;
    if(host.empty()) return lst;
    struct addrinfo *ai=0, *aii=0, hints;
    char str_addr[INET6_ADDRSTRLEN+1];
    memset(str_addr, 0, sizeof(str_addr));
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = family;
    hints.ai_socktype = type;
    hints.ai_flags = AI_CANONNAME;
    if(::getaddrinfo(host.c_str(), (service.empty() ? NULL : service.c_str() ), &hints, &aii)
    || !aii) return lst;
    unsigned n_entries = 0;
    for(ai=aii; ai; ai=ai->ai_next) ++n_entries;
    if(n_entries > 0) {
      try {
        lst.reserve(n_entries);
        for(ai=aii; ai; ai=ai->ai_next) {
          str_addr[0] = 0;
          struct hostlookup_data_t data;
          if(!ai->ai_addrlen || ai->ai_addrlen > sizeof(address_type)) continue;
          if(ai->ai_family == AF_INET6) {
            if(ai->ai_addr->sa_family != AF_INET6 || ai->ai_addrlen != sizeof(struct sockaddr_in6)
            || !::inet_ntop(AF_INET6, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, str_addr,
               ai->ai_addrlen)) continue;
          } else if(ai->ai_family == AF_INET) {
            if(ai->ai_addr->sa_family != AF_INET || ai->ai_addrlen != sizeof(struct sockaddr_in)
            || !::inet_ntop(AF_INET, &((struct sockaddr_in*)ai->ai_addr)->sin_addr, str_addr,
               ai->ai_addrlen)) continue;
          } else {
            continue;
          }
          data.saddr = str_addr;
          data.family = (enum family_sel)ai->ai_family;
          data.size = ai->ai_addrlen;
          data.shost = ai->ai_canonname ? ai->ai_canonname : "";
          memcpy(&data.adr, ai->ai_addr, ai->ai_addrlen);
          lst.push_back(data);
        }
      } catch(const std::exception & e) {
        if(aii) freeaddrinfo(aii);
        throw e;
      } catch(...) {
        ctrace("basic_ip_address::host_lookup(): unexpected exception");
        lst.clear();
      }
    }
    if(aii) freeaddrinfo(aii);
    return lst;
  }

  /**
   * Returns a host name from a given address or an empty string if not found.
   * @param const basic_ip_address & ip
   * @return str_t
   */
  static str_t hostname_by_address(const basic_ip_address & ip)
  {
    struct hostent *sh = 0;
    if(ip.family() == AF_INET) {
      sh = ::gethostbyaddr(&((struct sockaddr_in const*)&ip.address())->sin_addr,
              sizeof(struct sockaddr_in), AF_INET);
    } else if(ip.family() == AF_INET6) {
      sh = ::gethostbyaddr(&((struct sockaddr_in6 const*)&ip.address())->sin6_addr,
              sizeof(struct sockaddr_in6), AF_INET6);
    }
    return (!sh || !sh->h_name) ? str_t() : str_t(sh->h_name);
  }

  /**
   * Returns a service name from a given port, such as "ftp", "https".
   * @return
   */
  static str_t service_by_port(port_type port__) throw ()
  {
    struct servent* sa = ::getservbyport(htons(port__), NULL);
    return (!sa || !sa->s_name) ? str_t() : str_t(sa->s_name);
  }

  /**
   * Returns the port number for a service specification, such as "ftp", "https".
   * @param const str_t & service
   * @return port_type
   */
  static port_type port_by_service(const str_t & service__) throw ()
  {
    struct servent* sa = ::getservbyname(service__.c_str(), NULL);
    return (!sa || !sa->s_name) ? 0 : ntohs(sa->s_port);
  }

  /**
   * Returns the own host name
   **/
  static str_t my_hostname()
  {
    char s[128]; s[sizeof(s)-1] = '\0';
    return (::gethostname(s, sizeof(s)-1) < 0) ? str_t() : str_t(s);
  }

private:

  address_type address_;
  addresslen_type size_;
  unsigned char mask_;
};
}}
// </editor-fold>

// <editor-fold desc="basic_socket" defaultstate="collapsed">
/**
 * class basic_socket
 * Basic platform independent socket wrapper with small changes:
 * - On object construction, a socket (id/handle) is not directly opened.
 *   Use the create() method to open the socket.
 * - Method connected() returns if the socket is ok.
 * - recv() reads until (method argument) buffer is full, all data of socket
 *   buffer read or error.
 * - send() sends until all data sent or error.
 * - automatically close() on destruct (if not closed()
 * - sets socket in nonblocking mode in listen() and accept()
 * - methods return bool instead of socket error types (because socket handle/id
 *   is a instance variable). Errors are saved in a instance variable and can be
 *   read using error().
 * - Method wait() can be used to wait for data (FD_SET ...) with timeout.
 */
namespace sw { namespace detail {
template <typename Address_type=basic_ip_address<>, unsigned Timeout=100>
class basic_socket {
public:

  typedef Address_type ip_address_t;
  typedef std::string str_t;
  typedef char char_t;

public:

  /**
   * Standard constructor. Returns closed/uninitialized socket.
   **/
  basic_socket() throw () : id_(swsck_inv), errno_(0), timeout_(Timeout),
    checksent_(false), listens_(false)
  { ; }

  /**
   * Constrictor from socket identifier/handle in win32.
   **/
  basic_socket(swsck id) throw () : id_(id), errno_(0), timeout_(Timeout),
    checksent_(false), listens_(false)
  { ; }

  /**
   * Constrictor from ip address
   **/
  basic_socket(const ip_address_t & adr) throw () : id_(swsck_inv), ip_(adr),
  errno_(0), timeout_(Timeout), checksent_(false), listens_(false)
  { ; }

  /**
   * Constrictor from socket identifier/handle in win32 and ip address
   **/
  basic_socket(swsck id, const ip_address_t & adr) throw () : id_(id), ip_(adr),
  errno_(0), timeout_(Timeout), checksent_(false), listens_(false)
  { ; }

  /**
   * Constrictor basic_ip_address string definition
   **/
  basic_socket(const char* adr) throw () :
  id_(swsck_inv), ip_(adr), errno_(0), timeout_(Timeout),
  checksent_(false), listens_(false)
  { ; }

  /**
   * Destructor, closes the socket if it is not yet closed.
   **/
  virtual ~basic_socket()
  {
    ctracem("basic_socket::~basic_socket()");
    basic_socket::close();
  }

public:

  /**
   * Returns if the socket is closed
   * @return bool
   **/
  inline bool closed() const throw ()
  { return id_ == swsck_inv; }

  /**
   * Returns the socket id
   * @return swsck
   */
  inline swsck socket_id() const throw()
  { return id_; }

  /**
   * Returns the basic_ip_address
   * @return const ip_address_t &
   **/
  inline const ip_address_t & ip() const
  { return ip_; }

  /**
   * Sets the new basic_ip_address
   * @param const ip_address_t & adr
   **/
  inline void ip(const ip_address_t & adr)
  { ip_ = adr; }

  /**
   * Sets the new basic_ip_address
   * @param const char* adr
   **/
  inline void ip(const char* adr)
  { if(adr) ip_ = adr; }

  /**
   * Returns the current socket error.
   * @return long
   **/
  inline long error() const throw ()
  { return errno_; }

 /**
   * Sets the new socket error
   * The error instance variable is mutable, so the method can be const.
   * This is required because some const methods must set the error.
   * @param long newerror
   **/
  inline void error(long newerror)
  {
    ctracem("basic_socket::error(SET)");
    errno_ = newerror;
    if (newerror == -1) return;
    if (newerror == 0) { errtext_ = ""; return; }
    errtext_ = syserr_text(newerror);
  }

  /**
   * Returns a string representation of the error
   * @return const str_t &
   */
  inline const str_t & error_text() const
  { return errtext_; }

  /**
   * Set an error text
   * @param const char* text
   */
  inline void error_text(const char* text, bool overwrite=false)
  {
    if(!overwrite && !errtext_.empty()) return;
    errno_ = -1; errtext_ = text;
  }

  /**
   * Get actual timeout value in ms for wait method
   * @return unsigned
   **/
  inline unsigned timeout_ms() const throw ()
  { return timeout_; }

  /**
   * Set timeout value in ms for wait method
   * @param unsigned newtimeout
   **/
  inline void timeout_ms(unsigned newtimeout) throw ()
  { timeout_ = newtimeout; }

  /**
   * Get a socket option
   * @param int level
   * @param int optname
   */
  int option(int level, int optname)
  {
    int i=0;
    socklen_t size = sizeof(i);
    if (::getsockopt(id_, level, optname, (void*) &i, &size) == swsck_err) error(swsck_eno);
    ctracem("basic_socket::option(lvl=%d, opt=%d) = %d", level, optname, i);
    return i;
  }

  /**
   * Set a socket option
   * @param int level
   * @param int optname
   * @param int newval
   */
  void option(int level, int optname, int newval)
  {
    ctracem("basic_socket::option(lvl=%d, opt=%d, val=%d)", level, optname, newval);
    int i = newval;
    #ifndef OS_WIN
    analyze_error(::setsockopt(id_, level, optname, (void*) &i, (socklen_t) sizeof(i)));
    #else
    analyze_error(::setsockopt(id_, level, optname, (const char*) &i, (socklen_t) sizeof(i)));
    #endif
  }

  /**
   * Get socket send buffer size
   * @return int
   */
  inline int option_sendbuffer_size()
  { return option(SOL_SOCKET, SO_SNDBUF); }

  /**
   * Get socket receive buffer size
   * @return int
   */
  inline int option_recvbuffer_size()
  { return option(SOL_SOCKET, SO_RCVBUF); }

  /**
   * Returns if the socket is in error state. Automatically resets error.
   * @return bool
   */
  inline bool option_error()
  { if (option(SOL_SOCKET, SO_ERROR) != 0) { close(); return true; } return false; }

  /**
   * Set if the socket can send with delay
   * @param bool enabled
   */
  inline void nodelay(bool enabled)
  { option(IPPROTO_TCP, TCP_NODELAY, enabled ? 1 : 0); }

  /**
   * Get if the socket can send with delay
   * @return bool
   */
  inline bool nodelay()
  { return option(IPPROTO_TCP, TCP_NODELAY) != 0; }

  /**
   * Set if socket automatically sends keep alive packets
   * @param bool enabled
   */
  inline void keepalive(bool enabled)
  { option(SOL_SOCKET, SO_KEEPALIVE, enabled ? 1 : 0); }

  /**
   * Get if socket automatically sends keep alive packets
   * @return bool
   */
  inline bool keepalive()
  { return option(SOL_SOCKET, SO_KEEPALIVE) != 0; }

  /**
   * Set if socket can resuse the local address (important for servers)
   * @param bool enabled
   */
  inline void reuseaddress(bool enabled)
  { option(SOL_SOCKET, SO_REUSEADDR, enabled ? 1 : 0); }

  /**
   * Get if socket can resuse the local address (important for servers)
   * @return bool
   */
  inline bool reuseaddress()
  { return option(SOL_SOCKET, SO_REUSEADDR) != 0; }

  /**
   * Set nonblocking mode
   * @param bool enabled
   */
  void nonblocking(bool enabled)
  {
    #ifdef OS_WIN
    u_long d = enabled ? 1:0;
    ioctlsocket(id_, FIONBIO, &d);
    #elif defined(O_NONBLOCK)
    int o = ::fcntl(id_, F_GETFL, 0);
    if(o < 0) return;
    if(enabled) o |= O_NONBLOCK; else o &= (~O_NONBLOCK);
    ::fcntl(id_, F_SETFL, o);
    #elif defined(SO_NONBLOCK)
    long d = enabled ? 1:0;
    ::setsockopt(id_, SOL_SOCKET, SO_NONBLOCK, &d, sizeof(d));
    #endif
  }

  /**
   * Get nonblocking mode
   * @return bool
   */
  bool nonblocking()
  {
    #if defined(O_NONBLOCK)
    int o = ::fcntl(id_, F_GETFL, 0);
    return (o > 0) && (o & O_NONBLOCK) != 0;
    #elif defined(SO_NONBLOCK)
    long d;
    ::getsockopt(id_, SOL_SOCKET, SO_NONBLOCK, &d, sizeof(d));
    return d != 0;
    #endif
    return false;
  }

  /**
   * Creates the socket, default TCP socket
   * @param int type=SOCK_STREAM
   * @param int family=0
   * @param int protocol=0
   * @return bool
   **/
  bool create(int type=SOCK_STREAM, int family=0, int protocol=0)
  {
    ctracem("basic_socket::create()");
    if(!family) {
      if(!ip_.valid()) {
        error_text("basic_socket::create(): Cannot create socket from invalid ip", true);
        return false;
      }
      family = ip_.family();
    }
    id_ = ::socket(family, type, protocol);
    if(id_ == swsck_inv) {
      analyze_error(swsck_err);
      error_text("basic_socket::create(): Failed to create socket");
      return false;
    }
    return true;
  }

  /**
   * TCP connect. If the method fails, the error can be fetched using the
   * error() method.
   * @return bool
   **/
  bool connect()
  {
    ctracem("basic_socket::connect()");
    if(!ip_.valid()) return false;
    typename ip_address_t::address_type adr = ip_.address();
    analyze_error(::connect(id_, (sockaddr*)(&adr), (socklen_t) ip_.size()));
    if (error()) { close(); return false; }
    nonblocking(false);
    return true;
  }

  /**
   * Binds a server socket to port/address. If the method fails, the error
   * can be fetched using the error() method.
   * @return bool
   **/
  bool bind()
  {
    ctracem("basic_socket::bind()");
    if(!ip_.valid()) return false;
    typename ip_address_t::address_type adr = ip_.address();
    analyze_error(::bind(id_, (sockaddr*)(&adr), (socklen_t) ip_.size()));
    if (error()) { close(); return false; }
    return true;
  }

  /**
   * Starts listening. Returns success. If the method fails, the
   * error can be fetched using the error() method.
   * Annotation: this method sets automatically the nonblocking mode
   * for the acceptor. This is not implemented in api ::listen.
   * @return bool
   **/
  bool listen(int max_listen_pending = 1)
  {
    ctracem("basic_socket::listen()");
    analyze_error(::listen(id_, max_listen_pending));
    if (error()) { close(); return false; }
    nonblocking(true);
    listens_ = true;
    return true;
  }

  /**
   * TCP accept. Returns the accepting socket. If the method fails, the
   * returned socket is invalid (method connected()==false).
   * Annotation: this method sets automatically the nonblocking mode
   * for the acceptor. This is not implemented in api ::accept.
   * @param basic_socket & acc
   * @return bool
   **/
  bool accept(basic_socket & acc)
  {
    ctracem("basic_socket::accept()");
    if(!acc.closed()) acc.close();
    acc.ip_.clear();
    ip_address_t tip;
    typename ip_address_t::address_type sa;
    typename ip_address_t::addresslen_type lsa = sizeof (sa);
    swsck id = ::accept(id_, (sockaddr*) (&sa), &lsa);
    if(id == swsck_inv || !sa.ss_family || !lsa) return false;
    acc.id_ = id;
    if(sa.ss_family == AF_INET) {
      acc.ip_ = *((sockaddr_in*)&sa);
    } else if(sa.ss_family == AF_INET6) {
      acc.ip_ = *((sockaddr_in6*)&sa);
    } else {
      acc.ip_.address(sa);
      acc.ip_.size(lsa);
    }
    nonblocking(false);
    return true;
  }

  /**
   * Closes a socket. Before the method checks if the socket is already closed.
   **/
  void close() throw ()
  {
    if(id_ == swsck_inv) return;
    ctracem("basic_socket::close()");
    swsck iid = id_;
    id_ = swsck_inv;
    #ifndef OS_WIN
    ::close(iid);
    #else
    shutdown(iid, SD_BOTH); closesocket(iid);
    #endif
  }

  /**
   * Waits until something has changed in the socket, either received new data,
   * send ready or error. Returns false if timeout, true if somthing changed.
   * @param bool *is_recv = NULL
   * @param bool *is_sent = NULL
   * @param int timeout_ms=100
   * @return bool
   **/
  bool wait(bool *is_recv = NULL, bool *is_sent = NULL, int timeout_ms=100)
  {
    if(closed() || ((!is_recv) && (!is_sent))) return false;
    if(is_recv) *is_recv = false;
    if(is_sent) *is_sent = false;
    if(!checksent_) is_sent=NULL;
    checksent_ = false;
    #ifndef OS_WIN
    struct pollfd fd;
    fd.fd = id_;
    fd.events = (is_recv ? POLLIN:0) | ((checksent_ && is_sent) ? POLLOUT:0);
    fd.revents = 0;
    checksent_ = false;
    if(!fd.events) return false;
    int r = ::poll(&fd, 1, timeout_ms);
    if(r<0) { analyze_error(r); return false; }
    if(!r || !fd.revents) return false;
    if(is_recv && (fd.revents & POLLIN)) *is_recv = true;
    if(is_sent && (fd.revents & POLLOUT)) *is_sent = true;
    #else
    struct timeval to;
    struct fd_set ifd, ofd;
    to.tv_sec = timeout_ms / 1000;
    to.tv_usec= timeout_ms % 1000;
    FD_ZERO(&ifd); FD_ZERO(&ofd);
    if(is_recv) FD_SET(id_, &ifd);
    if(is_sent) FD_SET(id_, &ofd);
    int r = ::select(id_+1, is_recv ? (&ifd):0, is_sent ? (&ofd):0, 0, &to);
    if(r<0) { analyze_error(r); return false; }
    if((!r) || (!FD_ISSET(id_, &ifd) && (!FD_ISSET(id_, &ofd)))) return false;
    if(is_recv && FD_ISSET(id_, &ifd)) *is_recv = true;
    if(is_sent && FD_ISSET(id_, &ofd)) *is_sent = true;
    #endif
    return true;
  }

  /**
   * TCP send string
   * @param const str_t & text
   * @return long
   */
  inline long send(const str_t & text)
  { if (text.empty()) return 0; return send(text.data(), text.length()); }

  /**
   * TCP send data, returns success and byref the number of data bytes
   * received in the data buffer. On fail the error can be fetched using
   * the error() method.
   * Annotation: this method trys to send all data until the buffer
   * is full or error. This is not implemented in api ::send.
   * @param const void* data
   * @oaram size_t datasize
   * @return long
   **/
  long send(const void* data, size_t datasize)
  {
    if(!data || !datasize) return 0;
    checksent_ = true;
    const char *p = (const char*) data;
    long l = (long) datasize;
    while (l > 0) {
      long r = ::send(id_, p, (unsigned)l, 0);
      if(r > 0)  {
        l -= r;
        p += r;
        continue;
      } else if((r = analyze_error(r)) != swsck_eagain) {
        return r;
      }
      break;
    }
    ctracem("basic_socket::send(const void* data, datasize=%d)", datasize);
    return (long)datasize-l;
  }

  /**
   * TCP receive data, returns success and byref the number of data bytes
   * received in the data buffer. On fail the error can be fetched using
   * the error() method.
   * Annotation: this method trys to receive all data until the buffer
   * is full, no more data available or error. This is not implemented
   * in api ::recv.
   * @param void* data
   * @param size_t datasize
   * @return long
   **/
  long recv(void* data, size_t datasize)
  {
    if(!data || ! datasize) {
      ctrace("basic_socket::recv(!data?, !datasize?, !nreceived?)!");
      close();
      return false;
    }
    long l = ::recv(id_, (char*) data, datasize, MSG_DONTWAIT);
    if(l > 0) return l; // we have data
    if(l == 0) { ctracem("basic_socket::recv() 0 bytes --> close"); close(); return 0; } // we don't have data, socket shall be closed
    analyze_error(l); // Closes the socket if needed
    if(error()) ctracem("basic_socket::recv() ERROR");
    return 0; // we don't have data
  }

  /**
   * Receive text data to string. More a testing convenience wrapper
   * with low performance. Prefer recv(void* data, ...).
   * @paran str_t & s
   * @return long
   */
  long recv(str_t & s)
  {
    unsigned n = 256;
    s.clear();
    char *buffer;
    try {
      buffer = new char[n]; // no throw convention
    } catch(...) {
      error_text("basic_socket::recv(str_t&) intermediate data memory allocation failed)", true);
      return -1;
    }
    if(buffer) {
      long nr = 0;
      if((nr = recv(buffer, n)) > 0) {
        s.reserve(s.length()+nr);
        for(long i=0; i<nr; ++i) s += buffer[i];
      }
      delete [] buffer;
    } else {
      error_text("basic_socket::recv(str_t&) failed (no buffer allocated)", true);
    }
    return (long) s.size();
  }

  /**
   * UDP receive data, returns success and byref the senders basic_ip_address and the
   * number of data bytes received in the data buffer.
   * On fail the error can be fetched using the error() method.
   * @param void* data
   * @param size_t datasize
   * @param ip_address_t & ip
   * @return long
   **/
  long recvfrom(void* data, size_t datasize, ip_address_t & ip)
  {
    typename ip_address_t::address_type sa;
    typename ip_address_t::addresslen_type lsa = sizeof (sa);
    long r = ::recvfrom(id_, (char*) data, datasize, 0, (sockaddr*)&sa, &lsa);
    if(r == swsck_err && analyze_error(r)) return -1;
    if(sa.ss_family == AF_INET) {
      ip = *((sockaddr_in*)&sa);
    } else if(sa.ss_family == AF_INET6) {
      ip = *((sockaddr_in6*)&sa);
    } else {
      ip.address(sa); // fingers crossed that those data are right
      ip.size(lsa);
    }
    return r;
  }

  /**
   * UDP send data to a basic_ip_address. On fail the error can be fetched using the error() method.
   * @param const void* data
   * @param size_t datasize
   * @param const ip_address_t & ip
   * @return long
   **/
  long sendto(const void* data, size_t datasize, const ip_address_t & ip)
  {
    if(!ip.valid()) {
      error_text("basic_socket::sendto(): IP address is invalid", true);
      return -1;
    }
    typename ip_address_t::address_type sa = ip.address(); // ip.address() is const
    typename ip_address_t::addresslen_type lsa = ip.size();
    long r = ::sendto(id_, (const char*) data, datasize, 0, (struct sockaddr*) (&sa), lsa);
    if(r == swsck_err && analyze_error(r)) {
      ctrace("basic_socket::sendto(): Failed to send");
      return -1;
    }
    checksent_ = true;
    return r;
  }

protected:

  /**
   * Analyzes the socket error, if it is fatal closes the socket. Returns 0 on
   * EGAIN/EWOULDBLOCK, EINTR and ETIMEOUT.
   * @param long fn_return
   * @return long
   **/
  long analyze_error(long fn_return) const
  {
    if(fn_return == swsck_err) {
      long e = swsck_eno;
      switch (e) { // list of not fatal errors
        case swsck_eagain: break; // ctracem("basic_socket::analyze_error() WOULDBLOCK"); break;
        case swsck_eintr:  break; // ctracem("basic_socket::analyze_error() EINTR"); break;
        case swsck_timeout: break;// ctracem("basic_socket::analyze_error() TIMEOUT");  break;
        default:
          const_cast<long&>(errno_) = (long)e;
          const_cast<str_t&>(errtext_) = syserr_text(e);
		  if(id_ != swsck_inv) {
			#ifdef OS_WIN
			::shutdown(id_, SD_BOTH); ::closesocket(id_);
			#else
			::close(id_);
			#endif
			ctrace("basic_socket::analyze_error() '%s' (socket id=%d)", errtext_.c_str(), id_);
		  }
		  const_cast<swsck&>(id_) = swsck_inv;
      }
      return e;
    }
    return -1;
  }

  /**
   * Returns true if the socket is a listening server socket.
   * @return bool
   */
  inline bool listens()
  { return listens_; }

  /**
   * Get an error text form system
   * @param long err
   * @return str_t
   */
  static inline str_t syserr_text(long err)
  {
    #ifdef OS_WIN
    char buffer[64];
    if(FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
      NULL, (DWORD) err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      buffer, 63, NULL)) {
        buffer[63] = '\0';
        return str_t(buffer);
    }
    return str_t("unknown error");
    #else
    return ::strerror(err);
    #endif
  }

private:
  swsck id_;
  ip_address_t ip_;
  long errno_;
  str_t errtext_;
  unsigned long timeout_;
  bool checksent_;
  bool listens_;
  int max_listen_pending_;
};
}}
// </editor-fold>

// <editor-fold desc="basic_udp_socket" defaultstate="collapsed">
/**
 * Implements basic_socket and a self starting thread performing ::select()
 * and calling overloadable callbacks for connected, error, close, receive,
 * send.
 */
namespace sw { namespace detail {
template <typename Address_type=basic_ip_address<> >
class basic_udp_socket : protected basic_socket<Address_type>
{
public:

  typedef basic_socket<Address_type> socket_t;
  typedef typename socket_t::ip_address_t ip_address_t;
  typedef typename socket_t::str_t str_t;

public:

  basic_udp_socket() : socket_t()
  {}

  basic_udp_socket(const ip_address_t & adr) : socket_t(adr)
  {}

  basic_udp_socket(const char* adr) : socket_t(adr)
  {}

  virtual ~basic_udp_socket()
  { socket_t::close(); }

public:

  inline bool closed() const
  { return socket_t::closed(); }

  inline long error() const
  { return socket_t::error(); }

  /**
   * Returns a string representation of the error
   * @return const str_t &
   */
  inline const str_t & error_text() const
  { return socket_t::error_text(); }

  /**
   * Waits until something has changed in the socket, either received new data,
   * send ready or error. Returns false if timeout, true if somthing changed.
   * @param bool *is_recv = NULL
   * @param bool *is_sent = NULL
   * @param int timeout_ms=100
   **/
  inline bool wait(bool *is_recv = NULL, bool *is_sent = NULL, int timeout_ms=100)
  { return socket_t::wait(is_recv, is_sent, timeout_ms); }

public:

  /**
   * Create an unbound ("client") UDP socket.
   * @return bool
   */
  bool create()
  {
    if(!socket_t::closed()) {
      socket_t::error_text("basic_udp_socket::create(): Already created", true);
      return false;
	} else if(!socket_t::create(SOCK_DGRAM)) {
      socket_t::error_text("basic_udp_socket::create(): failed to create socket");
      return false;
    } else if(!thread::start()) {
      socket_t::error_text("basic_udp_socket::create(): failed to start thread");
    }
    return true;
  }

  /**
   * Create a bound socket to the specified ip address (text must include the port)
   * @param const char* ip
   * @return bool
   */
  inline bool bind(const char* ip)
  { return !ip ? false : basic_udp_socket::bind(ip_address_t(ip)); }

  /**
   * Create a bound socket to the specified ip address
   * @param const ip_address_t & ip
   * @return bool
   */
  bool bind(const ip_address_t & ip)
  {
    socket_t::ip(ip);
	if(!socket_t::closed()) {
      socket_t::error_text("basic_udp_socket::bind(): Socket already open", true);
	  return false;
	} else if(!ip.valid()) {
      socket_t::error_text("basic_udp_socket::bind(): IP address not valid", true);
    } else if(!ip.port()) {
      socket_t::error_text("basic_udp_socket::bind(): No port specified", true);
	  return false;
	} else if(!socket_t::create(SOCK_DGRAM)) {
      socket_t::error_text("basic_udp_socket::bind(): Could not create UDP socket");
      return false;
    } else if(!socket_t::bind()) {
      socket_t::error_text("basic_udp_socket::bind(): Could not bind socket");
      return false;
    }
    return true;
	}

  /**
   * Closes the socket
   */
  inline void close()
  { socket_t::close(); }

  /**
   * UDP receive data, returns success and byref the senders basic_ip_address and the
   * number of data bytes received in the data buffer.
   * On fail the error can be fetched using the error() method.
   * @param void* data
   * @param size_t datasize
   * @param ip_address_t & ip
   * @return long
   **/
  inline long recvfrom(void* data, size_t datasize, ip_address_t & ip)
  { return socket_t::recvfrom(data, datasize, ip); }

  /**
   * UDP send data to a basic_ip_address. On fail the error can be fetched using the error() method.
   * @param const void* data
   * @param size_t datasize
   * @param const ip_address_t & ip
   * @return long
   **/
  inline long sendto(const void* data, size_t datasize, const ip_address_t & ip)
  { return socket_t::sendto(data, datasize, ip); }

};
}}
namespace sw { namespace sock {
  typedef sw::detail::basic_udp_socket<> udp_socket;
}}
// </editor-fold>

// <editor-fold desc="basic_tcp_socket" defaultstate="collapsed">
/**
 * class basic_tcp_socket
 * Implements basic_socket and a self starting thread performing ::select()
 * and calling overloadable callbacks for connected, error, close, receive,
 * send and accept.
 */
namespace sw { namespace detail {
template <typename Address_type=basic_ip_address<> >
class basic_tcp_socket : protected basic_socket<Address_type>, protected basic_thread<>
{
public:

  typedef basic_socket<Address_type> socket_t;
  typedef basic_thread<> thread_t;
  typedef typename socket_t::ip_address_t ip_address_t;
  typedef typename socket_t::str_t str_t;

protected:

  // Methods to overload

  /**
   * First callback ever called in the tcp socket's thread. Called when a client is connected
   * to a server OR when a server listening thread just started.
   */
  virtual void on_connected() { ; }

  /**
   * Called when a client or acceptor has received data with payload.
   */
  virtual void on_receive()   { ; }

  /**
   * Called when a client or acceptor has sent data with payload.
   */
  virtual void on_sent()      { ; }

  /**
   * Called when a server listening socket received a new request.
   */
  virtual void on_accept()    { ; }

  /**
   * Called when a an error occurred.
   */
  virtual void on_error(long no, const char* text)  { (void)no; (void)text; }

  /**
   * Called immediately after a the socket thread loop is quit because the basic_socket
   * is closed.
   */

  virtual void on_close()     { ; }

  /**
   * Called frequently when the socket is open (either when data were received or sent, or wait()
   * exited with a select/poll timeout)
   */
  virtual void on_update()    { ; }

protected:

  /**
   * Constructors / destructor
   */
  basic_tcp_socket() : socket_t(), thread_t(), rx_(false), tx_(false)
  { ; }

  basic_tcp_socket(swsck id) : socket_t(id), thread_t(), rx_(false), tx_(false)
  { ; }

  basic_tcp_socket(const ip_address_t & adr) : socket_t(adr), thread_t(), rx_(false), tx_(false)
  { ; }

  basic_tcp_socket(swsck id, const ip_address_t & adr) : socket_t(id, adr), thread_t(),
    rx_(false), tx_(false)
  { ; }

  basic_tcp_socket(const char* adr) : socket_t(adr), thread_t(), rx_(false), tx_(false)
  { ; }

  virtual ~basic_tcp_socket()
  { ctracem("basic_tcp_socket::~basic_tcp_socket()"); socket_t::close(); }

public:

  /**
   * Returns the basic_ip_address
   * @return const ip_address_t &
   **/
  inline const ip_address_t & ip() const
  { return socket_t::ip(); }

  /**
   * Sets the new basic_ip_address
   * @param const ip_address_t & adr
   **/
  inline void ip(const ip_address_t & adr)
  { socket_t::ip(adr); }

  /**
   * Sets the new basic_ip_address
   * @param const char* adr
   **/
  inline void ip(const char* adr)
  { socket_t::ip(adr); }

  /**
   * Returns the current socket error.
   * @return long
   **/
  inline long error() const throw ()
  { return socket_t::error(); }

  /**
   * Returns a string representation of the error
   * @return const str_t &
   */
  inline const str_t & error_text() const
  { return socket_t::error_text(); }

protected:

 /**
   * Sets the new socket error
   * The error instance variable is mutable, so the method can be const.
   * This is required because some const methods must set the error.
   * @param long newerror
   **/
  inline void error(long newerror)
  { return socket_t::error(newerror); }

  /**
   * Set an error text
   * @param const char* text
   */
  inline void error_text(const char* text)
  { return socket_t::error_text(text); }

  /**
   * Connect (client) by host string
   * @param const char* iptext
   * @return bool
   */
  inline bool connect(const char* iptext)
  { return connect(ip_address_t(iptext)); }

  /**
   * Connect (client) by ip address
   * @param const ip_address_t & ip_addr
   * @return bool
   */
  bool connect(const ip_address_t & ip_addr)
  {
    if(!socket_t::closed()) {
      error_text("basic_tcp_socket::connect(): Already connected.");
      return false;
    }
    if(!ip_addr.valid()) {
      error_text("basic_tcp_socket::connect(): IP address no valid.");
      return false;
    }
    socket_t::ip(ip_addr);
    if(!socket_t::create())  {
      if(error_text().empty()) error_text("basic_tcp_socket::connect(): Failed to create socket.");
      return false;
    }
    if(!socket_t::connect()) {
      error_text("basic_tcp_socket::connect(): Failed to connect.");
      return false;
    }
    if(!thread_t::start()) {
      error_text("basic_tcp_socket::connect(): Failed to start thread.");
      socket_t::close();
      return false;
    }
    return true;
  }

  /**
   * Listen to an address/port (server)
   * @param const ip_address_t & ip_addr
   * @return bool
   */
  bool listen(const ip_address_t & ip_addr, bool reuse_address=true, bool no_delay=true,
          int max_pending=1)
  {
    if(!socket_t::closed()) {
      error_text("basic_tcp_socket::listen(): Already connected.");
      return false;
    }
    if(ip_addr.port() == 0) {
      error_text("basic_tcp_socket::listen(): Port not specified.");
      return false;
    }
    socket_t::ip(ip_addr);
    if(!socket_t::create()) {
      if(error_text().empty()) error_text("basic_tcp_socket::listen(): Failed to create socket.");
      return false;
    }
    socket_t::reuseaddress(reuse_address);
    socket_t::nodelay(no_delay);
    if(!socket_t::bind()) {
      error_text("basic_tcp_socket::listen(): Failed to bind socket.");
      return false;
    }
    if(!socket_t::listen(max_pending)) {
      error_text("basic_tcp_socket::listen(): Failed to start listening.");
      return false;
    }
    if(!thread_t::start()) {
      error_text("basic_tcp_socket::listen(): Failed to start thread.");
      socket_t::close();
      return false;
    }
    return true;
  }

  /**
   * Accept a request with an acceptor socket (server=
   * @param basic_tcp_socket & acc
   * @return bool
   */
  bool accept(basic_tcp_socket & acc)
  {
    if(!socket_t::accept(acc)) return false;
    if(!acc.start()) {
      acc.close();
      acc.stop();
      error_text("basic_tcp_socket::accept(): Failed to start acceptor thread.");
      return false;
    }
    return true;
  }

  /**
   * Close connection (server / client)
   */
  void close()
  {
    ctrace("basic_tcp_socket::close()");
    socket_t::close(); // That will break the thread loop
  }

  /**
   * Returns if the TCP socket is closed and the thread not running.
   */
  inline bool closed() const
  { return socket_t::closed() && !thread::running(); }

  /**
   * Start thread
   */
  inline bool start()
  { return thread::start(); }

  /**
   * Returns the id if the tcp_socket's thread
   * @return typename thread::id_type
   */
  inline typename thread::id_type thread_id() const throw()
  { return thread::thread_id(); }

private:

  /**
   * Thread callback. Exceptions are caught in the thread frame loop, which will proceed
   * with on_stop() {}
   */
  void on_start()
  { this->on_connected(); }

  /**
   * Thread callback. Exceptions are caught in the thread frame loop, which will proceed
   * with on_stop() {}
   */
  bool on_loop()
  {
    if(socket_t::wait(&rx_, &tx_)) {
      if(rx_) {
        if (socket_t::listens()) {
          this->on_accept();
        } else {
          this->on_receive();
        }
      }
      if(tx_ && !socket_t::listens()) {
        this->on_sent();
      }
    }
    if(!socket_t::closed()) {
      if(socket_t::error()) {
        socket_t::close();
        this->on_error(socket_t::error(), socket_t::error_text().c_str());
      }
      this->on_update();
    } else {
      this->on_close();
      return false;
    }
    return true;
  }

  /**
   * Thread callback after the loop was quit.
   */
  void on_stop()
  { socket_t::close(); } // Ensure the socket is closed as well to meet closed() requirements.

private:

  bool rx_; // wait() received flag
  bool tx_; // wait() sent flag
};
}}
// </editor-fold>

// <editor-fold desc="basic_tcp_client" defaultstate="collapsed">
/**
 * Base class for TCP clients.
 * NOTE:  See basic_tcp_socket for the method details. This class makes some
 *        features private that clients do not have (e.g. listen).
 **/
namespace sw { namespace detail {
template <typename Address_type=basic_ip_address<> >
class basic_tcp_client : public basic_tcp_socket<Address_type>
{
public:
  typedef basic_tcp_socket<Address_type> socket_t;
  typedef typename socket_t::ip_address_t ip_address_t;
  typedef typename socket_t::str_t str_t;
public:
  // Public forwards
  basic_tcp_client() : socket_t()   { }
  virtual ~basic_tcp_client()  { }
  inline void disconnect() { socket_t::close(); }
  inline bool connect(const char* ip)  { return socket_t::connect(ip); }
  inline bool connect(const ip_address_t & ip)  { return socket_t::connect(ip); }
  inline bool connected() { return !socket_t::closed(); }
  inline bool closed() { return socket_t::closed(); }
  inline long error() { return socket_t::error(); }
  inline str_t error_text() { return socket_t::error_text(); }
  inline long send(const void* data, size_t datasize) { return socket_t::send(data, datasize); }
  inline bool send(const str_t & text) { return socket_t::send(text) >=0; }
private:
  // Private blockers
  inline bool listen(const ip_address_t & ip_addr) { (void) ip_addr; return false; }
  inline bool listen() { return false; }
  inline bool accept(socket_t & acc) { (void) acc; return false; }
  inline bool create(int type = SOCK_STREAM) { (void) type; return false; }
  inline bool bind() { return false; }
  virtual void on_accept() { }
};
}}
// </editor-fold>

// <editor-fold desc="basic_tcp_acceptor" defaultstate="collapsed">
/**
 * Server class forward
 */
namespace sw { namespace sock {
  template <typename acceptor_type> class tcp_server;
}}

/**
 * Base class for TCP server<> acceptors.
 * NOTE:  See basic_tcp_socket for the method details. This class only makes
 *        features private that acceptors do not have (e.g. listen and connect).

 **/
namespace sw { namespace detail {
template <typename Address_type=basic_ip_address<> >
class basic_tcp_acceptor : public basic_tcp_socket<Address_type>
{
  template <typename acceptor_type> friend class sw::sock::tcp_server;
public:
  typedef basic_tcp_socket<Address_type> socket_t;
  typedef typename socket_t::ip_address_t ip_address_t;
  basic_tcp_acceptor() : socket_t() { }
  virtual ~basic_tcp_acceptor() { }
private:
  // Private overrides to prevent wrong usage / mistyping
  bool connect(const ip_address_t & ip_addr) { (void) ip_addr; return false; }
  bool connect() { return false; }
  bool listen(const ip_address_t & ip_addr) { (void) ip_addr; return false; }
  bool listen() { return false; }
  bool accept(socket_t & acc) { (void) acc; return false; }
  bool create(int type = SOCK_STREAM) { (void) type; return false; }
  bool bind() { return false; }
  void on_accept() { }
};
}}
// </editor-fold>

// <editor-fold desc="tcp_server" defaultstate="collapsed">
/**
 * Server class with auto accept with sock::acceptor derived acceptors.
 */
namespace sw { namespace sock {
template <typename acceptor_type>
class tcp_server : public sw::detail::basic_tcp_socket<>
{
public:

  typedef acceptor_type acceptor_t;
  typedef std::deque<acceptor_t*> container_type;
  typedef typename std::deque<acceptor_t*>::iterator acceptor_iterator;
  typedef sw::detail::basic_tcp_socket<> socket_t;
  typedef typename socket_t::ip_address_t ip_address_t;

protected:

  /**
   * Methods to overload to use the server:
   */
  virtual void on_started()   { ; }
  virtual void on_stopped()   { ; }
  virtual bool on_request(acceptor_t&)  { return true; }

protected:

  tcp_server() : max_clients_(16), max_listen_pending_(64), TcpNoDelay(true), TcpReuseAddress(true)
  { ctracem("tcp_server::tcp_server()"); }

  virtual ~tcp_server()
  { ctracem("tcp_server::~tcp_server()"); tcp_server::stop(); }

public:

  /**
   * Start the server
   * @return bool
   */
  inline bool start()
  { return socket_t::listen(socket_t::ip(), TcpReuseAddress, TcpNoDelay, max_listen_pending_); }

  /**
   * Returns the maximum number of concurrent clients
   * @return unsigned
   */
  inline unsigned max_clients() const throw()
  { return max_clients_; }

  /**
   * Sets the maximum number of concurrent clients
   */
  inline void max_clients(unsigned n) throw()
  { max_clients_ = n; }

  /**
   * Returns the maximum number of pending connections (backlog) of a listening socket.
   * @return int
   */
  inline int max_clients_pending() const
  { return max_listen_pending_; }

  /**
   * Sets the maximum number of pending connections (backlog) of a listening socket.
   * @param int n
   */
  inline void max_clients_pending(int n)
  { max_listen_pending_ = n > 2 ? n : 2; }

  /**
   * Stop the server
   */
  void stop()
  {
    if(socket_t::closed()) return;
    ctracem("tcp_server::stop()");
    max_clients_ = 0;
    socket_t::close();
    if(thread::current_thread() != thread_id()) {
      ctracem("tcp_server::stop(): Not my thread, wait until done");
      while(!socket_t::closed()) thread::usleep(1000);
    }
    // See details in on_close()
  }

  /**
   * Returns true if the server is listening
   * @return bool
   */
  inline bool running() const
  { return !socket_t::closed(); }

  /**
   * Returns the number of currently connected clients
   * @return unsigned
   */
  inline unsigned num_connected() const throw()
  { return (unsigned) acceptors_.size(); }        // stfwi: double check thread safety requirements.

  /**
   * Removes closed acceptors form the list. Can be only called either from the server thread
   * or when the server thread is stopped.
   * @return unsigned
   */
  unsigned clear_closed()
  {
    unsigned n_cleared = 0;
    acceptor_iterator it = acceptors_.begin();
    while (it != acceptors_.end()) {
      if((*it)->closed()) {
        acceptor_t *p_acc = *it;
        it = acceptors_.erase(it);
        delete p_acc;
        ++n_cleared;
      } else {
        ++it;
      }
    }
    return n_cleared;
  }

private:

  /**
   * Listener initialisation
   */
  void on_connected()
  {
    ctracem("tcp_server::on_connected()");
    this->on_started();
  }

  /**
   * Accept callback. Creates and assigns an acceptor invokes on_request().
   */
  void on_accept()
  {
    ctracem("tcp_server::on_accept()");
    if(socket_t::closed()) return; // don't accept new connections when gracefully closing
    if(acceptors_.size() >= max_clients_ && !clear_closed()) {
      thread_t::usleep(1000);
      return;
    }
    acceptor_t *p_acc = 0;
    try { p_acc = new acceptor_type(); } catch(...) { p_acc = 0; }
    if(!p_acc) {
      ctrace("tcp_server::on_accept(): Failed create new acceptor_t object");
      return;
    }
    acceptor_t &acc = *p_acc;
    if(socket_t::accept(acc)) {
      bool accepted = false;
      try {
        accepted = this->on_request(acc);
      } catch (const std::exception & e) {
        socket_t::error_text(e.what());
      } catch (...) {
        socket_t::error_text("exception in server.on_request()");
      }
      if(!accepted) {
        acc.close();
      } else {
        acc.nodelay(true); // Normally the acceptors should inherit this, but to ensure ...
        acceptors_.push_back(p_acc);
      }
    }
  }

  /**
   * Close event (thread)
   */
  void on_close()
  {
    ctracem("tcp_server::on_close()");
    for (acceptor_iterator it = acceptors_.begin(); it != acceptors_.end(); ++it) {
      try {
        ctracem("tcp_server::on_close(): close socket %d", (*it)->socket_id());
        (*it)->close();
      } catch (const std::exception & e) {
        socket_t::error_text(e.what());
      } catch (...) {
        socket_t::error_text("exception in server.on_close()");
      }
    }
    ctracem("tcp_server::on_close(): clear_closed()");
    while(!acceptors_.empty()) {
      if(!clear_closed()) thread::usleep(1000);
    }
    ctracem("tcp_server::on_close(): acceptors_.clear()");
    acceptors_.clear();
    this->on_stopped();
  }

private:
  // Masking
  void on_receive() { }
  void on_sent()  { }
  bool connect(const ip_address_t&)  { return false; }
  bool connect() { return false; }
  bool listen(const ip_address_t&) { return false; }
  bool listen() { return false; }
  bool create(int type = SOCK_STREAM) { (void) type; return false; }
  bool bind() { return false; }
  bool accept() { return false; }

private:
  container_type acceptors_;
  unsigned max_clients_;
  int max_listen_pending_;
  bool TcpNoDelay;
  bool TcpReuseAddress;
};
}}
// </editor-fold>

// <editor-fold desc="specialisations" defaultstate="collapsed">
namespace sw { namespace sock {
  typedef sw::detail::basic_ip_address<> ip_address;
  typedef sw::detail::basic_socket<> socket;
  typedef sw::detail::basic_tcp_socket<> tcp_socket;
  typedef sw::detail::basic_tcp_client<> tcp_client;
  typedef sw::detail::basic_tcp_acceptor<> tcp_acceptor;
}}
// </editor-fold>

// <editor-fold desc="undefs" defaultstate="collapsed">
#undef swsck
#undef swsck_inv
#undef swsck_err
#undef swsck_eno
#undef swsck_eintr
#undef swsck_nexist
#undef swsck_timeout
#undef swsck_eagain
#undef swsck_default_timeout
#undef ctracem
#undef ctrace
// </editor-fold>
#endif
