aboutsummaryrefslogtreecommitdiff
path: root/dep/sockets
diff options
context:
space:
mode:
Diffstat (limited to 'dep/sockets')
-rw-r--r--dep/sockets/Base64.cpp262
-rw-r--r--dep/sockets/CMakeLists.txt21
-rw-r--r--dep/sockets/Exception.cpp45
-rw-r--r--dep/sockets/Ipv4Address.cpp192
-rw-r--r--dep/sockets/Ipv6Address.cpp247
-rw-r--r--dep/sockets/Lock.cpp52
-rw-r--r--dep/sockets/Makefile136
-rw-r--r--dep/sockets/Mutex.cpp77
-rw-r--r--dep/sockets/Parse.cpp318
-rw-r--r--dep/sockets/ResolvServer.cpp92
-rw-r--r--dep/sockets/ResolvSocket.cpp426
-rw-r--r--dep/sockets/Socket.cpp1726
-rw-r--r--dep/sockets/SocketHandler.cpp1377
-rw-r--r--dep/sockets/StdoutLog.cpp98
-rw-r--r--dep/sockets/StreamSocket.cpp145
-rw-r--r--dep/sockets/TcpSocket.cpp1681
-rw-r--r--dep/sockets/Thread.cpp154
-rw-r--r--dep/sockets/UdpSocket.cpp810
-rw-r--r--dep/sockets/Utility.cpp960
-rw-r--r--dep/sockets/include/Base64.h77
-rw-r--r--dep/sockets/include/Exception.h55
-rw-r--r--dep/sockets/include/File.h82
-rw-r--r--dep/sockets/include/IFile.h71
-rw-r--r--dep/sockets/include/ISocketHandler.h231
-rw-r--r--dep/sockets/include/Ipv4Address.h95
-rw-r--r--dep/sockets/include/Ipv6Address.h105
-rw-r--r--dep/sockets/include/ListenSocket.h418
-rw-r--r--dep/sockets/include/Lock.h58
-rw-r--r--dep/sockets/include/Mutex.h68
-rw-r--r--dep/sockets/include/Parse.h100
-rw-r--r--dep/sockets/include/ResolvServer.h72
-rw-r--r--dep/sockets/include/ResolvSocket.h105
-rw-r--r--dep/sockets/include/SctpSocket.h108
-rw-r--r--dep/sockets/include/Socket.h735
-rw-r--r--dep/sockets/include/SocketAddress.h93
-rw-r--r--dep/sockets/include/SocketHandler.h265
-rw-r--r--dep/sockets/include/StdLog.h73
-rw-r--r--dep/sockets/include/StdoutLog.h55
-rw-r--r--dep/sockets/include/StreamSocket.h124
-rw-r--r--dep/sockets/include/TcpSocket.h356
-rw-r--r--dep/sockets/include/Thread.h100
-rw-r--r--dep/sockets/include/UdpSocket.h215
-rw-r--r--dep/sockets/include/Utility.h186
-rw-r--r--dep/sockets/include/socket_include.h290
-rw-r--r--dep/sockets/include/sockets-config.h90
-rw-r--r--dep/sockets/network_kist.txt20
-rw-r--r--dep/sockets/socket_include.cpp89
47 files changed, 13155 insertions, 0 deletions
diff --git a/dep/sockets/Base64.cpp b/dep/sockets/Base64.cpp
new file mode 100644
index 00000000000..f7f12f5edff
--- /dev/null
+++ b/dep/sockets/Base64.cpp
@@ -0,0 +1,262 @@
+/** \file Base64.cpp
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "Base64.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+const char *Base64::bstr =
+ "ABCDEFGHIJKLMNOPQ"
+ "RSTUVWXYZabcdefgh"
+ "ijklmnopqrstuvwxy"
+ "z0123456789+/";
+
+const char Base64::rstr[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
+ 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0};
+
+Base64::Base64()
+{
+}
+
+void Base64::encode(FILE *fil, std::string& output, bool add_crlf)
+{
+ size_t remain;
+ size_t i = 0;
+ size_t o = 0;
+ char input[4];
+
+ output = "";
+ remain = fread(input,1,3,fil);
+ while (remain > 0)
+ {
+ if (add_crlf && o && o % 76 == 0)
+ output += "\n";
+ switch (remain)
+ {
+ case 1:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) ];
+ output += "==";
+ break;
+ case 2:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
+ output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
+ output += "=";
+ break;
+ default:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
+ output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
+ output += bstr[ (input[i + 2] & 0x3f) ];
+ }
+ o += 4;
+ //
+ remain = fread(input,1,3,fil);
+ }
+}
+
+void Base64::encode(const std::string& str_in, std::string& str_out, bool add_crlf)
+{
+ encode(str_in.c_str(), str_in.size(), str_out, add_crlf);
+}
+
+void Base64::encode(const char* input,size_t l,std::string& output, bool add_crlf)
+{
+ size_t i = 0;
+ size_t o = 0;
+
+ output = "";
+ while (i < l)
+ {
+ size_t remain = l - i;
+ if (add_crlf && o && o % 76 == 0)
+ output += "\n";
+ switch (remain)
+ {
+ case 1:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) ];
+ output += "==";
+ break;
+ case 2:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
+ output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
+ output += "=";
+ break;
+ default:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
+ output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
+ output += bstr[ (input[i + 2] & 0x3f) ];
+ }
+ o += 4;
+ i += 3;
+ }
+}
+
+void Base64::encode(const unsigned char* input,size_t l,std::string& output,bool add_crlf)
+{
+ size_t i = 0;
+ size_t o = 0;
+
+ output = "";
+ while (i < l)
+ {
+ size_t remain = l - i;
+ if (add_crlf && o && o % 76 == 0)
+ output += "\n";
+ switch (remain)
+ {
+ case 1:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) ];
+ output += "==";
+ break;
+ case 2:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
+ output += bstr[ ((input[i + 1] << 2) & 0x3c) ];
+ output += "=";
+ break;
+ default:
+ output += bstr[ ((input[i] >> 2) & 0x3f) ];
+ output += bstr[ ((input[i] << 4) & 0x30) + ((input[i + 1] >> 4) & 0x0f) ];
+ output += bstr[ ((input[i + 1] << 2) & 0x3c) + ((input[i + 2] >> 6) & 0x03) ];
+ output += bstr[ (input[i + 2] & 0x3f) ];
+ }
+ o += 4;
+ i += 3;
+ }
+}
+
+void Base64::decode(const std::string& input,std::string& output)
+{
+ size_t i = 0;
+ size_t l = input.size();
+
+ output = "";
+ while (i < l)
+ {
+ while (i < l && (input[i] == 13 || input[i] == 10))
+ i++;
+ if (i < l)
+ {
+ char b1 = (char)((rstr[(int)input[i]] << 2 & 0xfc) +
+ (rstr[(int)input[i + 1]] >> 4 & 0x03));
+ output += b1;
+ if (input[i + 2] != '=')
+ {
+ char b2 = (char)((rstr[(int)input[i + 1]] << 4 & 0xf0) +
+ (rstr[(int)input[i + 2]] >> 2 & 0x0f));
+ output += b2;
+ }
+ if (input[i + 3] != '=')
+ {
+ char b3 = (char)((rstr[(int)input[i + 2]] << 6 & 0xc0) +
+ rstr[(int)input[i + 3]]);
+ output += b3;
+ }
+ i += 4;
+ }
+ }
+}
+
+void Base64::decode(const std::string& input, unsigned char *output, size_t& sz)
+{
+ size_t i = 0;
+ size_t l = input.size();
+ size_t j = 0;
+
+ while (i < l)
+ {
+ while (i < l && (input[i] == 13 || input[i] == 10))
+ i++;
+ if (i < l)
+ {
+ unsigned char b1 = (unsigned char)((rstr[(int)input[i]] << 2 & 0xfc) +
+ (rstr[(int)input[i + 1]] >> 4 & 0x03));
+ if (output)
+ {
+ output[j] = b1;
+ }
+ j++;
+ if (input[i + 2] != '=')
+ {
+ unsigned char b2 = (unsigned char)((rstr[(int)input[i + 1]] << 4 & 0xf0) +
+ (rstr[(int)input[i + 2]] >> 2 & 0x0f));
+ if (output)
+ {
+ output[j] = b2;
+ }
+ j++;
+ }
+ if (input[i + 3] != '=')
+ {
+ unsigned char b3 = (unsigned char)((rstr[(int)input[i + 2]] << 6 & 0xc0) +
+ rstr[(int)input[i + 3]]);
+ if (output)
+ {
+ output[j] = b3;
+ }
+ j++;
+ }
+ i += 4;
+ }
+ }
+ sz = j;
+}
+
+size_t Base64::decode_length(const std::string& str64)
+{
+ if (str64.empty() || str64.size() % 4)
+ return 0;
+ size_t l = 3 * (str64.size() / 4 - 1) + 1;
+ if (str64[str64.size() - 2] != '=')
+ l++;
+ if (str64[str64.size() - 1] != '=')
+ l++;
+ return l;
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/CMakeLists.txt b/dep/sockets/CMakeLists.txt
new file mode 100644
index 00000000000..a1756773c08
--- /dev/null
+++ b/dep/sockets/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+file(GLOB sources *.cpp)
+
+set(trinitysockets_STAT_SRCS
+ ${sources}
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+)
+
+add_library(trinitysockets STATIC ${trinitysockets_STAT_SRCS})
diff --git a/dep/sockets/Exception.cpp b/dep/sockets/Exception.cpp
new file mode 100644
index 00000000000..4d79aeef813
--- /dev/null
+++ b/dep/sockets/Exception.cpp
@@ -0,0 +1,45 @@
+/**
+ ** \file Exception.cpp
+ ** \date 2007-09-28
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+#include "Exception.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+Exception::Exception(const std::string& description) : m_description(description)
+{
+}
+
+const std::string Exception::ToString() const
+{
+ return m_description;
+}
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+
+
diff --git a/dep/sockets/Ipv4Address.cpp b/dep/sockets/Ipv4Address.cpp
new file mode 100644
index 00000000000..03935038951
--- /dev/null
+++ b/dep/sockets/Ipv4Address.cpp
@@ -0,0 +1,192 @@
+/**
+ ** \file Ipv4Address.cpp
+ ** \date 2006-09-21
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "Ipv4Address.h"
+#include "Utility.h"
+#include "Parse.h"
+#ifndef _WIN32
+#include <netdb.h>
+#endif
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+Ipv4Address::Ipv4Address(port_t port) : m_valid(true)
+{
+ memset(&m_addr, 0, sizeof(m_addr));
+ m_addr.sin_family = AF_INET;
+ m_addr.sin_port = htons( port );
+}
+
+Ipv4Address::Ipv4Address(ipaddr_t a,port_t port) : m_valid(true)
+{
+ memset(&m_addr, 0, sizeof(m_addr));
+ m_addr.sin_family = AF_INET;
+ m_addr.sin_port = htons( port );
+ memcpy(&m_addr.sin_addr, &a, sizeof(struct in_addr));
+}
+
+Ipv4Address::Ipv4Address(struct in_addr& a,port_t port) : m_valid(true)
+{
+ memset(&m_addr, 0, sizeof(m_addr));
+ m_addr.sin_family = AF_INET;
+ m_addr.sin_port = htons( port );
+ m_addr.sin_addr = a;
+}
+
+Ipv4Address::Ipv4Address(const std::string& host,port_t port) : m_valid(false)
+{
+ memset(&m_addr, 0, sizeof(m_addr));
+ m_addr.sin_family = AF_INET;
+ m_addr.sin_port = htons( port );
+ {
+ ipaddr_t a;
+ if (Utility::u2ip(host, a))
+ {
+ memcpy(&m_addr.sin_addr, &a, sizeof(struct in_addr));
+ m_valid = true;
+ }
+ }
+}
+
+Ipv4Address::Ipv4Address(struct sockaddr_in& sa)
+{
+ m_addr = sa;
+ m_valid = sa.sin_family == AF_INET;
+}
+
+Ipv4Address::~Ipv4Address()
+{
+}
+
+Ipv4Address::operator struct sockaddr *()
+{
+ return (struct sockaddr *)&m_addr;
+}
+
+Ipv4Address::operator socklen_t()
+{
+ return sizeof(struct sockaddr_in);
+}
+
+void Ipv4Address::SetPort(port_t port)
+{
+ m_addr.sin_port = htons( port );
+}
+
+port_t Ipv4Address::GetPort()
+{
+ return ntohs( m_addr.sin_port );
+}
+
+bool Ipv4Address::Resolve(const std::string& hostname,struct in_addr& a)
+{
+ struct sockaddr_in sa;
+ memset(&a, 0, sizeof(a));
+ if (Utility::isipv4(hostname))
+ {
+ if (!Utility::u2ip(hostname, sa, AI_NUMERICHOST))
+ return false;
+ a = sa.sin_addr;
+ return true;
+ }
+ if (!Utility::u2ip(hostname, sa))
+ return false;
+ a = sa.sin_addr;
+ return true;
+}
+
+bool Ipv4Address::Reverse(struct in_addr& a,std::string& name)
+{
+ struct sockaddr_in sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_addr = a;
+ return Utility::reverse((struct sockaddr *)&sa, sizeof(sa), name);
+}
+
+std::string Ipv4Address::Convert(bool include_port)
+{
+ if (include_port)
+ return Convert(m_addr.sin_addr) + ":" + Utility::l2string(GetPort());
+ return Convert(m_addr.sin_addr);
+}
+
+std::string Ipv4Address::Convert(struct in_addr& a)
+{
+ struct sockaddr_in sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_addr = a;
+ std::string name;
+ Utility::reverse((struct sockaddr *)&sa, sizeof(sa), name, NI_NUMERICHOST);
+ return name;
+}
+
+void Ipv4Address::SetAddress(struct sockaddr *sa)
+{
+ memcpy(&m_addr, sa, sizeof(struct sockaddr_in));
+}
+
+int Ipv4Address::GetFamily()
+{
+ return m_addr.sin_family;
+}
+
+bool Ipv4Address::IsValid()
+{
+ return m_valid;
+}
+
+bool Ipv4Address::operator==(SocketAddress& a)
+{
+ if (a.GetFamily() != GetFamily())
+ return false;
+ if ((socklen_t)a != sizeof(m_addr))
+ return false;
+ struct sockaddr *sa = a;
+ struct sockaddr_in *p = (struct sockaddr_in *)sa;
+ if (p -> sin_port != m_addr.sin_port)
+ return false;
+ if (memcmp(&p -> sin_addr, &m_addr.sin_addr, 4))
+ return false;
+ return true;
+}
+
+std::auto_ptr<SocketAddress> Ipv4Address::GetCopy()
+{
+ return std::auto_ptr<SocketAddress>(new Ipv4Address(m_addr));
+}
+
+std::string Ipv4Address::Reverse()
+{
+ std::string tmp;
+ Reverse(m_addr.sin_addr, tmp);
+ return tmp;
+}
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+
+
diff --git a/dep/sockets/Ipv6Address.cpp b/dep/sockets/Ipv6Address.cpp
new file mode 100644
index 00000000000..3208b5098fa
--- /dev/null
+++ b/dep/sockets/Ipv6Address.cpp
@@ -0,0 +1,247 @@
+/**
+ ** \file Ipv6Address.cpp
+ ** \date 2006-09-21
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "Ipv6Address.h"
+#ifdef ENABLE_IPV6
+
+#include "Utility.h"
+#include "Parse.h"
+#ifndef _WIN32
+#include <netdb.h>
+#endif
+#ifdef IPPROTO_IPV6
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+Ipv6Address::Ipv6Address(port_t port) : m_valid(true)
+{
+ memset(&m_addr, 0, sizeof(m_addr));
+ m_addr.sin6_family = AF_INET6;
+ m_addr.sin6_port = htons( port );
+}
+
+Ipv6Address::Ipv6Address(struct in6_addr& a,port_t port) : m_valid(true)
+{
+ memset(&m_addr, 0, sizeof(m_addr));
+ m_addr.sin6_family = AF_INET6;
+ m_addr.sin6_port = htons( port );
+ m_addr.sin6_addr = a;
+}
+
+Ipv6Address::Ipv6Address(const std::string& host,port_t port) : m_valid(false)
+{
+ memset(&m_addr, 0, sizeof(m_addr));
+ m_addr.sin6_family = AF_INET6;
+ m_addr.sin6_port = htons( port );
+ {
+ struct in6_addr a;
+ if (Utility::u2ip(host, a))
+ {
+ m_addr.sin6_addr = a;
+ m_valid = true;
+ }
+ }
+}
+
+Ipv6Address::Ipv6Address(struct sockaddr_in6& sa)
+{
+ m_addr = sa;
+ m_valid = sa.sin6_family == AF_INET6;
+}
+
+Ipv6Address::~Ipv6Address()
+{
+}
+
+Ipv6Address::operator struct sockaddr *()
+{
+ return (struct sockaddr *)&m_addr;
+}
+
+Ipv6Address::operator socklen_t()
+{
+ return sizeof(struct sockaddr_in6);
+}
+
+void Ipv6Address::SetPort(port_t port)
+{
+ m_addr.sin6_port = htons( port );
+}
+
+port_t Ipv6Address::GetPort()
+{
+ return ntohs( m_addr.sin6_port );
+}
+
+bool Ipv6Address::Resolve(const std::string& hostname,struct in6_addr& a)
+{
+ struct sockaddr_in6 sa;
+ memset(&a, 0, sizeof(a));
+ if (Utility::isipv6(hostname))
+ {
+ if (!Utility::u2ip(hostname, sa, AI_NUMERICHOST))
+ return false;
+ a = sa.sin6_addr;
+ return true;
+ }
+ if (!Utility::u2ip(hostname, sa))
+ return false;
+ a = sa.sin6_addr;
+ return true;
+}
+
+bool Ipv6Address::Reverse(struct in6_addr& a,std::string& name)
+{
+ struct sockaddr_in6 sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sin6_family = AF_INET6;
+ sa.sin6_addr = a;
+ return Utility::reverse((struct sockaddr *)&sa, sizeof(sa), name);
+}
+
+std::string Ipv6Address::Convert(bool include_port)
+{
+ if (include_port)
+ return Convert(m_addr.sin6_addr) + ":" + Utility::l2string(GetPort());
+ return Convert(m_addr.sin6_addr);
+}
+
+std::string Ipv6Address::Convert(struct in6_addr& a,bool mixed)
+{
+ char slask[100]; // l2ip temporary
+ *slask = 0;
+ unsigned int prev = 0;
+ bool skipped = false;
+ bool ok_to_skip = true;
+ if (mixed)
+ {
+ unsigned short x;
+ unsigned short addr16[8];
+ memcpy(addr16, &a, sizeof(addr16));
+ for (size_t i = 0; i < 6; i++)
+ {
+ x = ntohs(addr16[i]);
+ if (*slask && (x || !ok_to_skip || prev))
+ strcat(slask,":");
+ if (x || !ok_to_skip)
+ {
+ sprintf(slask + strlen(slask),"%x", x);
+ if (x && skipped)
+ ok_to_skip = false;
+ }
+ else
+ {
+ skipped = true;
+ }
+ prev = x;
+ }
+ x = ntohs(addr16[6]);
+ sprintf(slask + strlen(slask),":%u.%u",x / 256,x & 255);
+ x = ntohs(addr16[7]);
+ sprintf(slask + strlen(slask),".%u.%u",x / 256,x & 255);
+ }
+ else
+ {
+ struct sockaddr_in6 sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sin6_family = AF_INET6;
+ sa.sin6_addr = a;
+ std::string name;
+ Utility::reverse((struct sockaddr *)&sa, sizeof(sa), name, NI_NUMERICHOST);
+ return name;
+ }
+ return slask;
+}
+
+void Ipv6Address::SetAddress(struct sockaddr *sa)
+{
+ memcpy(&m_addr, sa, sizeof(struct sockaddr_in6));
+}
+
+int Ipv6Address::GetFamily()
+{
+ return m_addr.sin6_family;
+}
+
+void Ipv6Address::SetFlowinfo(uint32_t x)
+{
+ m_addr.sin6_flowinfo = x;
+}
+
+uint32_t Ipv6Address::GetFlowinfo()
+{
+ return m_addr.sin6_flowinfo;
+}
+
+#ifndef _WIN32
+void Ipv6Address::SetScopeId(uint32_t x)
+{
+ m_addr.sin6_scope_id = x;
+}
+
+uint32_t Ipv6Address::GetScopeId()
+{
+ return m_addr.sin6_scope_id;
+}
+#endif
+
+bool Ipv6Address::IsValid()
+{
+ return m_valid;
+}
+
+bool Ipv6Address::operator==(SocketAddress& a)
+{
+ if (a.GetFamily() != GetFamily())
+ return false;
+ if ((socklen_t)a != sizeof(m_addr))
+ return false;
+ struct sockaddr *sa = a;
+ struct sockaddr_in6 *p = (struct sockaddr_in6 *)sa;
+ if (p -> sin6_port != m_addr.sin6_port)
+ return false;
+ if (memcmp(&p -> sin6_addr, &m_addr.sin6_addr, sizeof(struct in6_addr)))
+ return false;
+ return true;
+}
+
+std::auto_ptr<SocketAddress> Ipv6Address::GetCopy()
+{
+ return std::auto_ptr<SocketAddress>(new Ipv6Address(m_addr));
+}
+
+std::string Ipv6Address::Reverse()
+{
+ std::string tmp;
+ Reverse(m_addr.sin6_addr, tmp);
+ return tmp;
+}
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+#endif // IPPROTO_IPV6
+#endif // ENABLE_IPV6
+
+
diff --git a/dep/sockets/Lock.cpp b/dep/sockets/Lock.cpp
new file mode 100644
index 00000000000..b75664cfbdc
--- /dev/null
+++ b/dep/sockets/Lock.cpp
@@ -0,0 +1,52 @@
+/** \file Lock.cpp
+ ** \date 2005-08-22
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2005,2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "Mutex.h"
+#include "Lock.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+Lock::Lock(Mutex& m) : m_mutex(m)
+{
+ m_mutex.Lock();
+}
+
+Lock::~Lock()
+{
+ m_mutex.Unlock();
+}
+
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/Makefile b/dep/sockets/Makefile
new file mode 100644
index 00000000000..88b6199788c
--- /dev/null
+++ b/dep/sockets/Makefile
@@ -0,0 +1,136 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 2.6
+
+# Default target executed when no arguments are given to make.
+default_target: all
+.PHONY : default_target
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canoncical targets will work.
+.SUFFIXES:
+
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+# Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+# A target that is always out of date.
+cmake_force:
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /usr/bin/cmake
+
+# The command to remove a file.
+RM = /usr/bin/cmake -E remove -f
+
+# The program to use to edit the cache.
+CMAKE_EDIT_COMMAND = /usr/bin/ccmake
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/trinity/dev/trinitycore/dep/sockets
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/trinity/dev/trinitycore/dep/sockets
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target edit_cache
+edit_cache:
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..."
+ /usr/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+.PHONY : edit_cache/fast
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+ @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+ /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+.PHONY : rebuild_cache/fast
+
+# The main all target
+all: cmake_check_build_system
+ $(CMAKE_COMMAND) -E cmake_progress_start /home/trinity/dev/trinitycore/dep/sockets/CMakeFiles /home/trinity/dev/trinitycore/dep/sockets/CMakeFiles/progress.make
+ $(MAKE) -f CMakeFiles/Makefile2 all
+ $(CMAKE_COMMAND) -E cmake_progress_start /home/trinity/dev/trinitycore/dep/sockets/CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+ $(MAKE) -f CMakeFiles/Makefile2 clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+ $(MAKE) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+ $(MAKE) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+ $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
+.PHONY : depend
+
+#=============================================================================
+# Target rules for targets named trinitysockets
+
+# Build rule for target.
+trinitysockets: cmake_check_build_system
+ $(MAKE) -f CMakeFiles/Makefile2 trinitysockets
+.PHONY : trinitysockets
+
+# fast build rule for target.
+trinitysockets/fast:
+ $(MAKE) -f CMakeFiles/trinitysockets.dir/build.make CMakeFiles/trinitysockets.dir/build
+.PHONY : trinitysockets/fast
+
+# Help Target
+help:
+ @echo "The following are some of the valid targets for this Makefile:"
+ @echo "... all (the default if no target is provided)"
+ @echo "... clean"
+ @echo "... depend"
+ @echo "... edit_cache"
+ @echo "... rebuild_cache"
+ @echo "... trinitysockets"
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+ $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
+.PHONY : cmake_check_build_system
+
diff --git a/dep/sockets/Mutex.cpp b/dep/sockets/Mutex.cpp
new file mode 100644
index 00000000000..681e85cee5b
--- /dev/null
+++ b/dep/sockets/Mutex.cpp
@@ -0,0 +1,77 @@
+/** \file Mutex.cpp
+ ** \date 2004-10-30
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "Mutex.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+Mutex::Mutex()
+{
+#ifdef _WIN32
+ m_mutex = ::CreateMutex(NULL, FALSE, NULL);
+#else
+ pthread_mutex_init(&m_mutex, NULL);
+#endif
+}
+
+Mutex::~Mutex()
+{
+#ifdef _WIN32
+ ::CloseHandle(m_mutex);
+#else
+ pthread_mutex_destroy(&m_mutex);
+#endif
+}
+
+void Mutex::Lock()
+{
+#ifdef _WIN32
+ /*DWORD d =*/ WaitForSingleObject(m_mutex, INFINITE);
+ /// \todo check 'd' for result
+#else
+ pthread_mutex_lock(&m_mutex);
+#endif
+}
+
+void Mutex::Unlock()
+{
+#ifdef _WIN32
+ ::ReleaseMutex(m_mutex);
+#else
+ pthread_mutex_unlock(&m_mutex);
+#endif
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/Parse.cpp b/dep/sockets/Parse.cpp
new file mode 100644
index 00000000000..2967859f23d
--- /dev/null
+++ b/dep/sockets/Parse.cpp
@@ -0,0 +1,318 @@
+/** \file Parse.cpp - parse a string
+ **
+ ** Written: 1999-Feb-10 grymse@alhem.net
+ **/
+
+/*
+Copyright (C) 1999-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "Parse.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/* implementation of class Parse */
+
+Parse::Parse()
+:pa_the_str("")
+,pa_splits("")
+,pa_ord("")
+,pa_the_ptr(0)
+,pa_breakchar(0)
+,pa_enable(0)
+,pa_disable(0)
+,pa_nospace(0)
+,pa_quote(false)
+{
+}
+
+Parse::Parse(const std::string&s)
+:pa_the_str(s)
+,pa_splits("")
+,pa_ord("")
+,pa_the_ptr(0)
+,pa_breakchar(0)
+,pa_enable(0)
+,pa_disable(0)
+,pa_nospace(0)
+,pa_quote(false)
+{
+}
+
+Parse::Parse(const std::string&s,const std::string&sp)
+:pa_the_str(s)
+,pa_splits(sp)
+,pa_ord("")
+,pa_the_ptr(0)
+,pa_breakchar(0)
+,pa_enable(0)
+,pa_disable(0)
+,pa_nospace(0)
+,pa_quote(false)
+{
+}
+
+Parse::Parse(const std::string&s,const std::string&sp,short /*nospace*/)
+:pa_the_str(s)
+,pa_splits(sp)
+,pa_ord("")
+,pa_the_ptr(0)
+,pa_breakchar(0)
+,pa_enable(0)
+,pa_disable(0)
+,pa_nospace(1)
+,pa_quote(false)
+{
+}
+
+Parse::~Parse()
+{
+}
+
+#define C ((pa_the_ptr<pa_the_str.size()) ? pa_the_str[pa_the_ptr] : 0)
+
+short Parse::issplit(const char c)
+{
+ for (size_t i = 0; i < pa_splits.size(); i++)
+ if (pa_splits[i] == c)
+ return 1;
+ return 0;
+}
+
+void Parse::getsplit()
+{
+ size_t x;
+
+ if (C == '=')
+ {
+ x = pa_the_ptr++;
+ } else
+ {
+ while (C && (issplit(C)))
+ pa_the_ptr++;
+ x = pa_the_ptr;
+ while (C && !issplit(C) && C != '=')
+ pa_the_ptr++;
+ }
+ if (x == pa_the_ptr && C == '=')
+ pa_the_ptr++;
+ pa_ord = (x < pa_the_str.size()) ? pa_the_str.substr(x,pa_the_ptr - x) : "";
+}
+
+std::string Parse::getword()
+{
+ size_t x;
+ int disabled = 0;
+ int quote = 0;
+ int rem = 0;
+
+ if (pa_nospace)
+ {
+ while (C && issplit(C))
+ pa_the_ptr++;
+ x = pa_the_ptr;
+ while (C && !issplit(C) && (C != pa_breakchar || !pa_breakchar || disabled))
+ {
+ if (pa_breakchar && C == pa_disable)
+ disabled = 1;
+ if (pa_breakchar && C == pa_enable)
+ disabled = 0;
+ if (pa_quote && C == '"')
+ quote = 1;
+ pa_the_ptr++;
+ while (quote && C && C != '"')
+ {
+ pa_the_ptr++;
+ }
+ if (pa_quote && C == '"')
+ {
+ pa_the_ptr++;
+ }
+ quote = 0;
+ }
+ } else
+ {
+ if (C == pa_breakchar && pa_breakchar)
+ {
+ x = pa_the_ptr++;
+ rem = 1;
+ } else
+ {
+ while (C && (C == ' ' || C == 9 || C == 13 || C == 10 || issplit(C)))
+ pa_the_ptr++;
+ x = pa_the_ptr;
+ while (C && C != ' ' && C != 9 && C != 13 && C != 10 && !issplit(C) &&
+ (C != pa_breakchar || !pa_breakchar || disabled))
+ {
+ if (pa_breakchar && C == pa_disable)
+ disabled = 1;
+ if (pa_breakchar && C == pa_enable)
+ disabled = 0;
+ if (pa_quote && C == '"')
+ {
+ quote = 1;
+ pa_the_ptr++;
+ while (quote && C && C != '"')
+ {
+ pa_the_ptr++;
+ }
+ if (pa_quote && C == '"')
+ {
+ pa_the_ptr++;
+ }
+ }
+ else
+ pa_the_ptr++;
+ quote = 0;
+ }
+ pa_the_ptr++;
+ rem = 1;
+ }
+ if (x == pa_the_ptr && C == pa_breakchar && pa_breakchar)
+ pa_the_ptr++;
+ }
+ if (x < pa_the_str.size())
+ {
+ pa_ord = pa_the_str.substr(x,pa_the_ptr - x - rem);
+ }
+ else
+ {
+ pa_ord = "";
+ }
+ return pa_ord;
+}
+
+void Parse::getword(std::string&s)
+{
+ s = Parse::getword();
+}
+
+void Parse::getsplit(std::string&s)
+{
+ Parse::getsplit();
+ s = pa_ord;
+}
+
+void Parse::getword(std::string&s,std::string&fill,int l)
+{
+ Parse::getword();
+ s = "";
+ while (s.size() + pa_ord.size() < (size_t)l)
+ s += fill;
+ s += pa_ord;
+}
+
+std::string Parse::getrest()
+{
+ std::string s;
+ while (C && (C == ' ' || C == 9 || issplit(C)))
+ pa_the_ptr++;
+ s = (pa_the_ptr < pa_the_str.size()) ? pa_the_str.substr(pa_the_ptr) : "";
+ return s;
+}
+
+void Parse::getrest(std::string&s)
+{
+ while (C && (C == ' ' || C == 9 || issplit(C)))
+ pa_the_ptr++;
+ s = (pa_the_ptr < pa_the_str.size()) ? pa_the_str.substr(pa_the_ptr) : "";
+}
+
+long Parse::getvalue()
+{
+ Parse::getword();
+ return atol(pa_ord.c_str());
+}
+
+void Parse::setbreak(const char c)
+{
+ pa_breakchar = c;
+}
+
+int Parse::getwordlen()
+{
+ size_t x,y = pa_the_ptr,len;
+
+ if (C == pa_breakchar && pa_breakchar)
+ {
+ x = pa_the_ptr++;
+ } else
+ {
+ while (C && (C == ' ' || C == 9 || C == 13 || C == 10 || issplit(C)))
+ pa_the_ptr++;
+ x = pa_the_ptr;
+ while (C && C != ' ' && C != 9 && C != 13 && C != 10 && !issplit(C) && (C != pa_breakchar || !pa_breakchar))
+ pa_the_ptr++;
+ }
+ if (x == pa_the_ptr && C == pa_breakchar && pa_breakchar)
+ pa_the_ptr++;
+ len = pa_the_ptr - x;
+ pa_the_ptr = y;
+ return (int)len;
+}
+
+int Parse::getrestlen()
+{
+ size_t y = pa_the_ptr;
+ size_t len;
+
+ while (C && (C == ' ' || C == 9 || issplit(C)))
+ pa_the_ptr++;
+ len = strlen(pa_the_str.c_str() + pa_the_ptr);
+ pa_the_ptr = y;
+ return (int)len;
+}
+
+void Parse::getline()
+{
+ size_t x;
+
+ x = pa_the_ptr;
+ while (C && C != 13 && C != 10)
+ pa_the_ptr++;
+ pa_ord = (x < pa_the_str.size()) ? pa_the_str.substr(x,pa_the_ptr - x) : "";
+ if (C == 13)
+ pa_the_ptr++;
+ if (C == 10)
+ pa_the_ptr++;
+}
+
+void Parse::getline(std::string&s)
+{
+ getline();
+ s = pa_ord;
+}
+
+/* end of implementation of class Parse */
+/***************************************************/
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/ResolvServer.cpp b/dep/sockets/ResolvServer.cpp
new file mode 100644
index 00000000000..3c8a7de6bc0
--- /dev/null
+++ b/dep/sockets/ResolvServer.cpp
@@ -0,0 +1,92 @@
+/** \file ResolvServer.cpp
+ ** \date 2005-03-24
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+#include "ResolvServer.h"
+#ifdef ENABLE_RESOLVER
+#include "StdoutLog.h"
+#include "ListenSocket.h"
+#include "ResolvSocket.h"
+#include "SocketHandler.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+ResolvServer::ResolvServer(port_t port)
+:Thread()
+,m_quit(false)
+,m_port(port)
+,m_ready(false)
+{
+}
+
+ResolvServer::~ResolvServer()
+{
+}
+
+void ResolvServer::Run()
+{
+// StdoutLog log;
+ SocketHandler h;
+ ListenSocket<ResolvSocket> l(h);
+
+ if (l.Bind("127.0.0.1", m_port))
+ {
+ return;
+ }
+ h.Add(&l);
+
+ m_ready = true;
+ while (!m_quit && IsRunning() )
+ {
+ h.Select(0, 500000);
+ }
+ SetRunning(false);
+}
+
+void ResolvServer::Quit()
+{
+ m_quit = true;
+}
+
+bool ResolvServer::Ready()
+{
+ return m_ready;
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // ENABLE_RESOLVER
+
+
diff --git a/dep/sockets/ResolvSocket.cpp b/dep/sockets/ResolvSocket.cpp
new file mode 100644
index 00000000000..636de276426
--- /dev/null
+++ b/dep/sockets/ResolvSocket.cpp
@@ -0,0 +1,426 @@
+/** \file ResolvSocket.cpp
+ ** \date 2005-03-24
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifdef _WIN32
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#pragma warning(disable:4503)
+#endif
+#else
+#include <netdb.h>
+#endif
+#include "ResolvSocket.h"
+#ifdef ENABLE_RESOLVER
+#include "Utility.h"
+#include "Parse.h"
+#include "ISocketHandler.h"
+#include "Lock.h"
+#include "Mutex.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+//#ifdef _DEBUG
+//#define DEB(x) x
+//#else
+#define DEB(x)
+//#endif
+
+// static
+ResolvSocket::cache_t ResolvSocket::m_cache;
+ResolvSocket::timeout_t ResolvSocket::m_cache_to;
+Mutex ResolvSocket::m_cache_mutex;
+
+ResolvSocket::ResolvSocket(ISocketHandler& h)
+:TcpSocket(h)
+,m_bServer(false)
+,m_parent(NULL)
+#ifdef ENABLE_IPV6
+,m_resolve_ipv6(false)
+#endif
+,m_cached(false)
+{
+ SetLineProtocol();
+}
+
+ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, const std::string& host, port_t port, bool ipv6)
+:TcpSocket(h)
+,m_bServer(false)
+,m_parent(parent)
+,m_resolv_host(host)
+,m_resolv_port(port)
+#ifdef ENABLE_IPV6
+,m_resolve_ipv6(ipv6)
+#endif
+,m_cached(false)
+{
+ SetLineProtocol();
+}
+
+ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, ipaddr_t a)
+:TcpSocket(h)
+,m_bServer(false)
+,m_parent(parent)
+,m_resolv_port(0)
+,m_resolv_address(a)
+#ifdef ENABLE_IPV6
+,m_resolve_ipv6(false)
+#endif
+,m_cached(false)
+{
+ SetLineProtocol();
+}
+
+#ifdef ENABLE_IPV6
+ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, in6_addr& a)
+:TcpSocket(h)
+,m_bServer(false)
+,m_parent(parent)
+,m_resolv_port(0)
+,m_resolve_ipv6(true)
+,m_resolv_address6(a)
+,m_cached(false)
+{
+ SetLineProtocol();
+}
+#endif
+
+ResolvSocket::~ResolvSocket()
+{
+}
+
+void ResolvSocket::OnLine(const std::string& line)
+{
+ Parse pa(line, ":");
+ if (m_bServer)
+ {
+ m_query = pa.getword();
+ m_data = pa.getrest();
+DEB( fprintf(stderr, " *** ResolvSocket server; query=%s, data=%s\n", m_query.c_str(), m_data.c_str());)
+ // %! check cache
+ {
+ Lock lock(m_cache_mutex);
+ if (m_cache[m_query].find(m_data) != m_cache[m_query].end())
+ {
+ if (time(NULL) - m_cache_to[m_query][m_data] < 3600) // ttl
+ {
+ std::string result = m_cache[m_query][m_data];
+DEB(fprintf(stderr, " *** Returning cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), result.c_str());)
+ Send("Cached\n");
+ if (!result.size()) /* failed */
+ {
+ Send("Failed\n\n");
+ SetCloseAndDelete();
+ return;
+ }
+ else
+ if (m_query == "gethostbyname")
+ {
+ Send("A: " + result + "\n\n");
+ SetCloseAndDelete();
+ return;
+ }
+ else
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (m_query == "gethostbyname2")
+ {
+ Send("AAAA: " + result + "\n\n");
+ SetCloseAndDelete();
+ return;
+ }
+ else
+#endif
+#endif
+ if (m_query == "gethostbyaddr")
+ {
+ Send("Name: " + result + "\n\n");
+ SetCloseAndDelete();
+ return;
+ }
+ }
+ }
+ }
+ if (!Detach()) // detach failed?
+ {
+ SetCloseAndDelete();
+ }
+ return;
+ }
+ std::string key = pa.getword();
+ std::string value = pa.getrest();
+DEB( fprintf(stderr, " *** ResolvSocket response; %s: %s\n", key.c_str(), value.c_str());)
+
+ if (key == "Cached")
+ {
+ m_cached = true;
+ }
+ else
+ if (key == "Failed" && m_parent)
+ {
+DEB( fprintf(stderr, " ************ Resolve failed\n");)
+ if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
+ {
+ m_parent -> OnResolveFailed(m_resolv_id);
+ }
+ // update cache
+ if (!m_cached)
+ {
+ Lock lock(m_cache_mutex);
+DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
+ m_cache[m_query][m_data] = value;
+ m_cache_to[m_query][m_data] = time(NULL);
+ }
+ m_parent = NULL;
+ }
+ else
+ if (key == "Name" && !m_resolv_host.size() && m_parent)
+ {
+ if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
+ {
+ m_parent -> OnReverseResolved(m_resolv_id, value);
+ }
+ // update cache
+ if (!m_cached)
+ {
+ Lock lock(m_cache_mutex);
+DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
+ m_cache[m_query][m_data] = value;
+ m_cache_to[m_query][m_data] = time(NULL);
+ }
+ m_parent = NULL;
+ }
+ else
+ if (key == "A" && m_parent)
+ {
+ if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
+ {
+ ipaddr_t l;
+ Utility::u2ip(value, l); // ip2ipaddr_t
+ m_parent -> OnResolved(m_resolv_id, l, m_resolv_port);
+ }
+ // update cache
+ if (!m_cached)
+ {
+ Lock lock(m_cache_mutex);
+DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
+ m_cache[m_query][m_data] = value;
+ m_cache_to[m_query][m_data] = time(NULL);
+ }
+ m_parent = NULL; // always use first ip in case there are several
+ }
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ else
+ if (key == "AAAA" && m_parent)
+ {
+ if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
+ {
+ in6_addr a;
+ Utility::u2ip(value, a);
+ m_parent -> OnResolved(m_resolv_id, a, m_resolv_port);
+ }
+ // update cache
+ if (!m_cached)
+ {
+ Lock lock(m_cache_mutex);
+DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
+ m_cache[m_query][m_data] = value;
+ m_cache_to[m_query][m_data] = time(NULL);
+ }
+ m_parent = NULL;
+ }
+#endif
+#endif
+}
+
+void ResolvSocket::OnDetached()
+{
+DEB( fprintf(stderr, " *** ResolvSocket::OnDetached(); query=%s, data=%s\n", m_query.c_str(), m_data.c_str());)
+ if (m_query == "gethostbyname")
+ {
+ struct sockaddr_in sa;
+ if (Utility::u2ip(m_data, sa))
+ {
+ std::string ip;
+ Utility::l2ip(sa.sin_addr, ip);
+ Send("A: " + ip + "\n");
+ }
+ else
+ {
+ Send("Failed\n");
+ }
+ Send("\n");
+ }
+ else
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (m_query == "gethostbyname2")
+ {
+ struct sockaddr_in6 sa;
+ if (Utility::u2ip(m_data, sa))
+ {
+ std::string ip;
+ Utility::l2ip(sa.sin6_addr, ip);
+ Send("AAAA: " + ip + "\n");
+ }
+ else
+ {
+ Send("Failed\n");
+ }
+ Send("\n");
+ }
+ else
+#endif
+#endif
+ if (m_query == "gethostbyaddr")
+ {
+ if (Utility::isipv4( m_data ))
+ {
+ struct sockaddr_in sa;
+ if (!Utility::u2ip(m_data, sa, AI_NUMERICHOST))
+ {
+ Send("Failed: convert to sockaddr_in failed\n");
+ }
+ else
+ {
+ std::string name;
+ if (!Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), name))
+ {
+ Send("Failed: ipv4 reverse lookup of " + m_data + "\n");
+ }
+ else
+ {
+ Send("Name: " + name + "\n");
+ }
+ }
+ }
+ else
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (Utility::isipv6( m_data ))
+ {
+ struct sockaddr_in6 sa;
+ if (!Utility::u2ip(m_data, sa, AI_NUMERICHOST))
+ {
+ Send("Failed: convert to sockaddr_in6 failed\n");
+ }
+ else
+ {
+ std::string name;
+ if (!Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), name))
+ {
+ Send("Failed: ipv6 reverse lookup of " + m_data + "\n");
+ }
+ else
+ {
+ Send("Name: " + name + "\n");
+ }
+ }
+ }
+ else
+#endif
+#endif
+ {
+ Send("Failed: malformed address\n");
+ }
+ Send("\n");
+ }
+ else
+ {
+ std::string msg = "Unknown query type: " + m_query;
+ Handler().LogError(this, "OnDetached", 0, msg);
+ Send("Unknown\n\n");
+ }
+ SetCloseAndDelete();
+}
+
+void ResolvSocket::OnConnect()
+{
+ if (!m_resolv_host.empty())
+ {
+#ifdef ENABLE_IPV6
+ std::string msg = (m_resolve_ipv6 ? "gethostbyname2 " : "gethostbyname ") + m_resolv_host + "\n";
+ m_query = m_resolve_ipv6 ? "gethostbyname2" : "gethostbyname";
+#else
+ std::string msg = "gethostbyname " + m_resolv_host + "\n";
+ m_query = "gethostbyname";
+#endif
+ m_data = m_resolv_host;
+ Send( msg );
+ return;
+ }
+#ifdef ENABLE_IPV6
+ if (m_resolve_ipv6)
+ {
+ std::string tmp;
+ Utility::l2ip(m_resolv_address6, tmp);
+ m_query = "gethostbyaddr";
+ m_data = tmp;
+ std::string msg = "gethostbyaddr " + tmp + "\n";
+ Send( msg );
+ }
+#endif
+ std::string tmp;
+ Utility::l2ip(m_resolv_address, tmp);
+ m_query = "gethostbyaddr";
+ m_data = tmp;
+ std::string msg = "gethostbyaddr " + tmp + "\n";
+ Send( msg );
+}
+
+void ResolvSocket::OnDelete()
+{
+ if (m_parent)
+ {
+ if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
+ {
+ m_parent -> OnResolveFailed(m_resolv_id);
+ }
+ // update cache
+ if (!m_cached)
+ {
+ Lock lock(m_cache_mutex);
+ std::string value;
+DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
+ m_cache[m_query][m_data] = value;
+ m_cache_to[m_query][m_data] = time(NULL);
+ }
+ m_parent = NULL;
+ }
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // ENABLE_RESOLVER
+
+
diff --git a/dep/sockets/Socket.cpp b/dep/sockets/Socket.cpp
new file mode 100644
index 00000000000..f53cd27621e
--- /dev/null
+++ b/dep/sockets/Socket.cpp
@@ -0,0 +1,1726 @@
+/** \file Socket.cpp
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "Socket.h"
+#ifdef _WIN32
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+#include <stdlib.h>
+#else
+#include <errno.h>
+#include <netdb.h>
+#endif
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "ISocketHandler.h"
+#include "Utility.h"
+
+#include "SocketAddress.h"
+#include "SocketHandler.h"
+#ifdef ENABLE_EXCEPTIONS
+#include "Exception.h"
+#endif
+#include "Ipv4Address.h"
+
+//#ifdef _DEBUG
+//#define DEB(x) x; fflush(stderr);
+//#else
+#define DEB(x)
+//#endif
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+// statics
+#ifdef _WIN32
+WSAInitializer Socket::m_winsock_init;
+#endif
+
+Socket::Socket(ISocketHandler& h)
+//:m_flags(0)
+:m_handler(h)
+,m_socket( INVALID_SOCKET )
+,m_bDel(false)
+,m_bClose(false)
+,m_tCreate(time(NULL))
+,m_parent(NULL)
+,m_b_disable_read(false)
+,m_connected(false)
+,m_b_erased_by_handler(false)
+,m_tClose(0)
+,m_client_remote_address(NULL)
+,m_remote_address(NULL)
+,m_traffic_monitor(NULL)
+,m_bLost(false)
+#ifdef HAVE_OPENSSL
+,m_b_enable_ssl(false)
+,m_b_ssl(false)
+,m_b_ssl_server(false)
+#endif
+#ifdef ENABLE_IPV6
+,m_ipv6(false)
+#endif
+#ifdef ENABLE_POOL
+,m_socket_type(0)
+,m_bClient(false)
+,m_bRetain(false)
+#endif
+#ifdef ENABLE_SOCKS4
+,m_bSocks4(false)
+,m_socks4_host(h.GetSocks4Host())
+,m_socks4_port(h.GetSocks4Port())
+,m_socks4_userid(h.GetSocks4Userid())
+#endif
+#ifdef ENABLE_DETACH
+,m_detach(false)
+,m_detached(false)
+,m_pThread(NULL)
+,m_slave_handler(NULL)
+#endif
+{
+}
+
+Socket::~Socket()
+{
+ Handler().Remove(this);
+ if (m_socket != INVALID_SOCKET
+#ifdef ENABLE_POOL
+ && !m_bRetain
+#endif
+ )
+ {
+ Close();
+ }
+}
+
+void Socket::Init()
+{
+}
+
+void Socket::OnRead()
+{
+}
+
+void Socket::OnWrite()
+{
+}
+
+void Socket::OnException()
+{
+ // %! exception doesn't always mean something bad happened, this code should be reworked
+ // errno valid here?
+ int err = SoError();
+ Handler().LogError(this, "exception on select", err, StrError(err), LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+}
+
+void Socket::OnDelete()
+{
+}
+
+void Socket::OnConnect()
+{
+}
+
+void Socket::OnAccept()
+{
+}
+
+int Socket::Close()
+{
+ if (m_socket == INVALID_SOCKET) // this could happen
+ {
+ Handler().LogError(this, "Socket::Close", 0, "file descriptor invalid", LOG_LEVEL_WARNING);
+ return 0;
+ }
+ int n;
+ if ((n = closesocket(m_socket)) == -1)
+ {
+ // failed...
+ Handler().LogError(this, "close", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+ Handler().Set(m_socket, false, false, false); // remove from fd_set's
+ Handler().AddList(m_socket, LIST_CALLONCONNECT, false);
+#ifdef ENABLE_DETACH
+ Handler().AddList(m_socket, LIST_DETACH, false);
+#endif
+ Handler().AddList(m_socket, LIST_TIMEOUT, false);
+ Handler().AddList(m_socket, LIST_RETRY, false);
+ Handler().AddList(m_socket, LIST_CLOSE, false);
+ m_socket = INVALID_SOCKET;
+ return n;
+}
+
+SOCKET Socket::CreateSocket(int af,int type, const std::string& protocol)
+{
+ struct protoent *p = NULL;
+ SOCKET s;
+
+#ifdef ENABLE_POOL
+ m_socket_type = type;
+ m_socket_protocol = protocol;
+#endif
+ if (!protocol.empty())
+ {
+ p = getprotobyname( protocol.c_str() );
+ if (!p)
+ {
+ Handler().LogError(this, "getprotobyname", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+#ifdef ENABLE_EXCEPTIONS
+ throw Exception(std::string("getprotobyname() failed: ") + StrError(Errno));
+#endif
+ return INVALID_SOCKET;
+ }
+ }
+ int protno = p ? p -> p_proto : 0;
+
+ s = socket(af, type, protno);
+ if (s == INVALID_SOCKET)
+ {
+ Handler().LogError(this, "socket", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+#ifdef ENABLE_EXCEPTIONS
+ throw Exception(std::string("socket() failed: ") + StrError(Errno));
+#endif
+ return INVALID_SOCKET;
+ }
+ Attach(s);
+ OnOptions(af, type, protno, s);
+ Attach(INVALID_SOCKET);
+ return s;
+}
+
+void Socket::Attach(SOCKET s)
+{
+ m_socket = s;
+}
+
+SOCKET Socket::GetSocket()
+{
+ return m_socket;
+}
+
+void Socket::SetDeleteByHandler(bool x)
+{
+ m_bDel = x;
+}
+
+bool Socket::DeleteByHandler()
+{
+ return m_bDel;
+}
+
+void Socket::SetCloseAndDelete(bool x)
+{
+ if (x != m_bClose)
+ {
+ Handler().AddList(m_socket, LIST_CLOSE, x);
+ m_bClose = x;
+ if (x)
+ {
+ m_tClose = time(NULL);
+ }
+ }
+}
+
+bool Socket::CloseAndDelete()
+{
+ return m_bClose;
+}
+
+void Socket::SetRemoteAddress(SocketAddress& ad) //struct sockaddr* sa, socklen_t l)
+{
+ m_remote_address = ad.GetCopy();
+}
+
+std::auto_ptr<SocketAddress> Socket::GetRemoteSocketAddress()
+{
+ return m_remote_address -> GetCopy();
+}
+
+ISocketHandler& Socket::Handler() const
+{
+#ifdef ENABLE_DETACH
+ if (IsDetached())
+ return *m_slave_handler;
+#endif
+ return m_handler;
+}
+
+ISocketHandler& Socket::MasterHandler() const
+{
+ return m_handler;
+}
+
+ipaddr_t Socket::GetRemoteIP4()
+{
+ ipaddr_t l = 0;
+#ifdef ENABLE_IPV6
+ if (m_ipv6)
+ {
+ Handler().LogError(this, "GetRemoteIP4", 0, "get ipv4 address for ipv6 socket", LOG_LEVEL_WARNING);
+ }
+#endif
+ if (m_remote_address.get() != NULL)
+ {
+ struct sockaddr *p = *m_remote_address;
+ struct sockaddr_in *sa = (struct sockaddr_in *)p;
+ memcpy(&l, &sa -> sin_addr, sizeof(struct in_addr));
+ }
+ return l;
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+struct in6_addr Socket::GetRemoteIP6()
+{
+ if (!m_ipv6)
+ {
+ Handler().LogError(this, "GetRemoteIP6", 0, "get ipv6 address for ipv4 socket", LOG_LEVEL_WARNING);
+ }
+ struct sockaddr_in6 fail;
+ if (m_remote_address.get() != NULL)
+ {
+ struct sockaddr *p = *m_remote_address;
+ memcpy(&fail, p, sizeof(struct sockaddr_in6));
+ }
+ else
+ {
+ memset(&fail, 0, sizeof(struct sockaddr_in6));
+ }
+ return fail.sin6_addr;
+}
+#endif
+#endif
+
+port_t Socket::GetRemotePort()
+{
+ if (!m_remote_address.get())
+ {
+ return 0;
+ }
+ return m_remote_address -> GetPort();
+}
+
+std::string Socket::GetRemoteAddress()
+{
+ if (!m_remote_address.get())
+ {
+ return "";
+ }
+ return m_remote_address -> Convert(false);
+}
+
+std::string Socket::GetRemoteHostname()
+{
+ if (!m_remote_address.get())
+ {
+ return "";
+ }
+ return m_remote_address -> Reverse();
+}
+
+bool Socket::SetNonblocking(bool bNb)
+{
+#ifdef _WIN32
+ unsigned long l = bNb ? 1 : 0;
+ int n = ioctlsocket(m_socket, FIONBIO, &l);
+ if (n != 0)
+ {
+ Handler().LogError(this, "ioctlsocket(FIONBIO)", Errno, "");
+ return false;
+ }
+ return true;
+#else
+ if (bNb)
+ {
+ if (fcntl(m_socket, F_SETFL, O_NONBLOCK) == -1)
+ {
+ Handler().LogError(this, "fcntl(F_SETFL, O_NONBLOCK)", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ return false;
+ }
+ }
+ else
+ {
+ if (fcntl(m_socket, F_SETFL, 0) == -1)
+ {
+ Handler().LogError(this, "fcntl(F_SETFL, 0)", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ return false;
+ }
+ }
+ return true;
+#endif
+}
+
+bool Socket::SetNonblocking(bool bNb, SOCKET s)
+{
+#ifdef _WIN32
+ unsigned long l = bNb ? 1 : 0;
+ int n = ioctlsocket(s, FIONBIO, &l);
+ if (n != 0)
+ {
+ Handler().LogError(this, "ioctlsocket(FIONBIO)", Errno, "");
+ return false;
+ }
+ return true;
+#else
+ if (bNb)
+ {
+ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
+ {
+ Handler().LogError(this, "fcntl(F_SETFL, O_NONBLOCK)", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ return false;
+ }
+ }
+ else
+ {
+ if (fcntl(s, F_SETFL, 0) == -1)
+ {
+ Handler().LogError(this, "fcntl(F_SETFL, 0)", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ return false;
+ }
+ }
+ return true;
+#endif
+}
+
+void Socket::Set(bool bRead, bool bWrite, bool bException)
+{
+ Handler().Set(m_socket, bRead, bWrite, bException);
+}
+
+bool Socket::Ready()
+{
+ if (m_socket != INVALID_SOCKET && !CloseAndDelete())
+ return true;
+ return false;
+}
+
+void Socket::OnLine(const std::string& )
+{
+}
+
+void Socket::OnConnectFailed()
+{
+}
+
+Socket *Socket::GetParent()
+{
+ return m_parent;
+}
+
+void Socket::SetParent(Socket *x)
+{
+ m_parent = x;
+}
+
+port_t Socket::GetPort()
+{
+ Handler().LogError(this, "GetPort", 0, "GetPort only implemented for ListenSocket", LOG_LEVEL_WARNING);
+ return 0;
+}
+
+bool Socket::OnConnectRetry()
+{
+ return true;
+}
+
+#ifdef ENABLE_RECONNECT
+void Socket::OnReconnect()
+{
+}
+#endif
+
+time_t Socket::Uptime()
+{
+ return time(NULL) - m_tCreate;
+}
+
+#ifdef ENABLE_IPV6
+void Socket::SetIpv6(bool x)
+{
+ m_ipv6 = x;
+}
+
+bool Socket::IsIpv6()
+{
+ return m_ipv6;
+}
+#endif
+
+void Socket::DisableRead(bool x)
+{
+ m_b_disable_read = x;
+}
+
+bool Socket::IsDisableRead()
+{
+ return m_b_disable_read;
+}
+
+void Socket::SendBuf(const char *,size_t,int)
+{
+}
+
+void Socket::Send(const std::string&,int)
+{
+}
+
+void Socket::SetConnected(bool x)
+{
+ m_connected = x;
+}
+
+bool Socket::IsConnected()
+{
+ return m_connected;
+}
+
+void Socket::OnDisconnect()
+{
+}
+
+void Socket::SetLost()
+{
+ m_bLost = true;
+}
+
+bool Socket::Lost()
+{
+ return m_bLost;
+}
+
+void Socket::SetErasedByHandler(bool x)
+{
+ m_b_erased_by_handler = x;
+}
+
+bool Socket::ErasedByHandler()
+{
+ return m_b_erased_by_handler;
+}
+
+time_t Socket::TimeSinceClose()
+{
+ return time(NULL) - m_tClose;
+}
+
+void Socket::SetClientRemoteAddress(SocketAddress& ad)
+{
+ if (!ad.IsValid())
+ {
+ Handler().LogError(this, "SetClientRemoteAddress", 0, "remote address not valid", LOG_LEVEL_ERROR);
+ }
+ m_client_remote_address = ad.GetCopy();
+}
+
+std::auto_ptr<SocketAddress> Socket::GetClientRemoteAddress()
+{
+ if (!m_client_remote_address.get())
+ {
+ Handler().LogError(this, "GetClientRemoteAddress", 0, "remote address not yet set", LOG_LEVEL_ERROR);
+ }
+ return m_client_remote_address -> GetCopy();
+}
+
+uint64_t Socket::GetBytesSent(bool)
+{
+ return 0;
+}
+
+uint64_t Socket::GetBytesReceived(bool)
+{
+ return 0;
+}
+
+#ifdef HAVE_OPENSSL
+void Socket::OnSSLConnect()
+{
+}
+
+void Socket::OnSSLAccept()
+{
+}
+
+bool Socket::SSLNegotiate()
+{
+ return false;
+}
+
+bool Socket::IsSSL()
+{
+ return m_b_enable_ssl;
+}
+
+void Socket::EnableSSL(bool x)
+{
+ m_b_enable_ssl = x;
+}
+
+bool Socket::IsSSLNegotiate()
+{
+ return m_b_ssl;
+}
+
+void Socket::SetSSLNegotiate(bool x)
+{
+ m_b_ssl = x;
+}
+
+bool Socket::IsSSLServer()
+{
+ return m_b_ssl_server;
+}
+
+void Socket::SetSSLServer(bool x)
+{
+ m_b_ssl_server = x;
+}
+
+void Socket::OnSSLConnectFailed()
+{
+}
+
+void Socket::OnSSLAcceptFailed()
+{
+}
+#endif // HAVE_OPENSSL
+
+#ifdef ENABLE_POOL
+void Socket::CopyConnection(Socket *sock)
+{
+ Attach( sock -> GetSocket() );
+#ifdef ENABLE_IPV6
+ SetIpv6( sock -> IsIpv6() );
+#endif
+ SetSocketType( sock -> GetSocketType() );
+ SetSocketProtocol( sock -> GetSocketProtocol() );
+
+ SetClientRemoteAddress( *sock -> GetClientRemoteAddress() );
+ SetRemoteAddress( *sock -> GetRemoteSocketAddress() );
+}
+
+void Socket::SetIsClient()
+{
+ m_bClient = true;
+}
+
+void Socket::SetSocketType(int x)
+{
+ m_socket_type = x;
+}
+
+int Socket::GetSocketType()
+{
+ return m_socket_type;
+}
+
+void Socket::SetSocketProtocol(const std::string& x)
+{
+ m_socket_protocol = x;
+}
+
+const std::string& Socket::GetSocketProtocol()
+{
+ return m_socket_protocol;
+}
+
+void Socket::SetRetain()
+{
+ if (m_bClient) m_bRetain = true;
+}
+
+bool Socket::Retain()
+{
+ return m_bRetain;
+}
+
+#endif // ENABLE_POOL
+
+#ifdef ENABLE_SOCKS4
+void Socket::OnSocks4Connect()
+{
+ Handler().LogError(this, "OnSocks4Connect", 0, "Use with TcpSocket only");
+}
+
+void Socket::OnSocks4ConnectFailed()
+{
+ Handler().LogError(this, "OnSocks4ConnectFailed", 0, "Use with TcpSocket only");
+}
+
+bool Socket::OnSocks4Read()
+{
+ Handler().LogError(this, "OnSocks4Read", 0, "Use with TcpSocket only");
+ return true;
+}
+
+void Socket::SetSocks4Host(const std::string& host)
+{
+ Utility::u2ip(host, m_socks4_host);
+}
+
+bool Socket::Socks4()
+{
+ return m_bSocks4;
+}
+
+void Socket::SetSocks4(bool x)
+{
+ m_bSocks4 = x;
+}
+
+void Socket::SetSocks4Host(ipaddr_t a)
+{
+ m_socks4_host = a;
+}
+
+void Socket::SetSocks4Port(port_t p)
+{
+ m_socks4_port = p;
+}
+
+void Socket::SetSocks4Userid(const std::string& x)
+{
+ m_socks4_userid = x;
+}
+
+ipaddr_t Socket::GetSocks4Host()
+{
+ return m_socks4_host;
+}
+
+port_t Socket::GetSocks4Port()
+{
+ return m_socks4_port;
+}
+
+const std::string& Socket::GetSocks4Userid()
+{
+ return m_socks4_userid;
+}
+#endif // ENABLE_SOCKS4
+
+#ifdef ENABLE_DETACH
+bool Socket::Detach()
+{
+ if (!DeleteByHandler())
+ return false;
+ if (m_pThread)
+ return false;
+ if (m_detached)
+ return false;
+ SetDetach();
+ return true;
+}
+
+void Socket::DetachSocket()
+{
+ SetDetached();
+ m_pThread = new SocketThread(this);
+ m_pThread -> SetRelease(true);
+}
+
+void Socket::OnDetached()
+{
+}
+
+void Socket::SetDetach(bool x)
+{
+ Handler().AddList(m_socket, LIST_DETACH, x);
+ m_detach = x;
+}
+
+bool Socket::IsDetach()
+{
+ return m_detach;
+}
+
+void Socket::SetDetached(bool x)
+{
+ m_detached = x;
+}
+
+const bool Socket::IsDetached() const
+{
+ return m_detached;
+}
+
+void Socket::SetSlaveHandler(ISocketHandler *p)
+{
+ m_slave_handler = p;
+}
+
+Socket::SocketThread::SocketThread(Socket *p)
+:Thread(false)
+,m_socket(p)
+{
+ // Creator will release
+}
+
+Socket::SocketThread::~SocketThread()
+{
+ if (IsRunning())
+ {
+ SetRelease(true);
+ SetRunning(false);
+#ifdef _WIN32
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ }
+}
+
+void Socket::SocketThread::Run()
+{
+ SocketHandler h;
+ h.SetSlave();
+ h.Add(m_socket);
+ m_socket -> SetSlaveHandler(&h);
+ m_socket -> OnDetached();
+ while (h.GetCount() && IsRunning())
+ {
+ h.Select(0, 500000);
+ }
+ // m_socket now deleted oops
+ // yeah oops m_socket delete its socket thread, that means this
+ // so Socket will no longer delete its socket thread, instead we do this:
+ SetDeleteOnExit();
+}
+#endif // ENABLE_DETACH
+
+#ifdef ENABLE_RESOLVER
+int Socket::Resolve(const std::string& host,port_t port)
+{
+ return Handler().Resolve(this, host, port);
+}
+
+#ifdef ENABLE_IPV6
+int Socket::Resolve6(const std::string& host,port_t port)
+{
+ return Handler().Resolve6(this, host, port);
+}
+#endif
+
+int Socket::Resolve(ipaddr_t a)
+{
+ return Handler().Resolve(this, a);
+}
+
+#ifdef ENABLE_IPV6
+int Socket::Resolve(in6_addr& a)
+{
+ return Handler().Resolve(this, a);
+}
+#endif
+
+void Socket::OnResolved(int,ipaddr_t,port_t)
+{
+}
+
+#ifdef ENABLE_IPV6
+void Socket::OnResolved(int,in6_addr&,port_t)
+{
+}
+#endif
+
+void Socket::OnReverseResolved(int,const std::string&)
+{
+}
+
+void Socket::OnResolveFailed(int)
+{
+}
+#endif // ENABLE_RESOLVER
+
+/* IP options */
+
+bool Socket::SetIpOptions(const void *p, socklen_t len)
+{
+#ifdef IP_OPTIONS
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_OPTIONS, (char *)p, len) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_OPTIONS)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_OPTIONS", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+#ifdef IP_PKTINFO
+bool Socket::SetIpPktinfo(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_PKTINFO, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_PKTINFO)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef IP_RECVTOS
+bool Socket::SetIpRecvTOS(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_RECVTOS, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_RECVTOS)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef IP_RECVTTL
+bool Socket::SetIpRecvTTL(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_RECVTTL, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_RECVTTL)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef IP_RECVOPTS
+bool Socket::SetIpRecvopts(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_RECVOPTS, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_RECVOPTS)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef IP_RETOPTS
+bool Socket::SetIpRetopts(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_RETOPTS, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_RETOPTS)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+bool Socket::SetIpTOS(unsigned char tos)
+{
+#ifdef IP_TOS
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(tos)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_TOS)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_TOS", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+unsigned char Socket::IpTOS()
+{
+ unsigned char tos = 0;
+#ifdef IP_TOS
+ socklen_t len = sizeof(tos);
+ if (getsockopt(GetSocket(), IPPROTO_IP, IP_TOS, (char *)&tos, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(IPPROTO_IP, IP_TOS)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_TOS", LOG_LEVEL_INFO);
+#endif
+ return tos;
+}
+
+bool Socket::SetIpTTL(int ttl)
+{
+#ifdef IP_TTL
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_TTL)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_TTL", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+int Socket::IpTTL()
+{
+ int ttl = 0;
+#ifdef IP_TTL
+ socklen_t len = sizeof(ttl);
+ if (getsockopt(GetSocket(), IPPROTO_IP, IP_TTL, (char *)&ttl, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(IPPROTO_IP, IP_TTL)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_TTL", LOG_LEVEL_INFO);
+#endif
+ return ttl;
+}
+
+bool Socket::SetIpHdrincl(bool x)
+{
+#ifdef IP_HDRINCL
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_HDRINCL)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_HDRINCL", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+#ifdef IP_RECVERR
+bool Socket::SetIpRecverr(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_RECVERR, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_RECVERR)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef IP_MTU_DISCOVER
+bool Socket::SetIpMtudiscover(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_MTU_DISCOVER, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_MTU_DISCOVER)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef IP_MTU
+int Socket::IpMtu()
+{
+ int mtu = 0;
+ socklen_t len = sizeof(mtu);
+ if (getsockopt(GetSocket(), IPPROTO_IP, IP_MTU, (char *)&mtu, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(IPPROTO_IP, IP_MTU)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+ return mtu;
+}
+#endif
+
+#ifdef IP_ROUTER_ALERT
+bool Socket::SetIpRouterAlert(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_ROUTER_ALERT, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_ROUTER_ALERT)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+bool Socket::SetIpMulticastTTL(int ttl)
+{
+#ifdef IP_MULTICAST_TTL
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_MULTICAST_TTL)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_MULTICAST_TTL", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+int Socket::IpMulticastTTL()
+{
+ int ttl = 0;
+#ifdef IP_MULTICAST_TTL
+ socklen_t len = sizeof(ttl);
+ if (getsockopt(GetSocket(), IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(IPPROTO_IP, IP_MULTICAST_TTL)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_MULTICAST_TTL", LOG_LEVEL_INFO);
+#endif
+ return ttl;
+}
+
+bool Socket::SetMulticastLoop(bool x)
+{
+#ifdef IP_MULTICAST_LOOP
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_MULTICAST_LOOP)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_MULTICAST_LOOP", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+#ifdef LINUX
+bool Socket::IpAddMembership(struct ip_mreqn& ref)
+{
+#ifdef IP_ADD_MEMBERSHIP
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&ref, sizeof(struct ip_mreqn)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_ADD_MEMBERSHIP", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+#endif
+
+bool Socket::IpAddMembership(struct ip_mreq& ref)
+{
+#ifdef IP_ADD_MEMBERSHIP
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&ref, sizeof(struct ip_mreq)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_ADD_MEMBERSHIP", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+#ifdef LINUX
+bool Socket::IpDropMembership(struct ip_mreqn& ref)
+{
+#ifdef IP_DROP_MEMBERSHIP
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&ref, sizeof(struct ip_mreqn)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_DROP_MEMBERSHIP)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_DROP_MEMBERSHIP", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+#endif
+
+bool Socket::IpDropMembership(struct ip_mreq& ref)
+{
+#ifdef IP_DROP_MEMBERSHIP
+ if (setsockopt(GetSocket(), IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&ref, sizeof(struct ip_mreq)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_IP, IP_DROP_MEMBERSHIP)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "ip option not available", 0, "IP_DROP_MEMBERSHIP", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+/* SOCKET options */
+
+bool Socket::SetSoReuseaddr(bool x)
+{
+#ifdef SO_REUSEADDR
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_REUSEADDR)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_REUSEADDR", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+bool Socket::SetSoKeepalive(bool x)
+{
+#ifdef SO_KEEPALIVE
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_KEEPALIVE)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_KEEPALIVE", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+#ifdef SO_NOSIGPIPE
+bool Socket::SetSoNosigpipe(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_NOSIGPIPE, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+bool Socket::SoAcceptconn()
+{
+ int value = 0;
+#ifdef SO_ACCEPTCONN
+ socklen_t len = sizeof(value);
+ if (getsockopt(GetSocket(), SOL_SOCKET, SO_ACCEPTCONN, (char *)&value, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(SOL_SOCKET, SO_ACCEPTCONN)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_ACCEPTCONN", LOG_LEVEL_INFO);
+#endif
+ return value ? true : false;
+}
+
+#ifdef SO_BSDCOMPAT
+bool Socket::SetSoBsdcompat(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_BSDCOMPAT, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_BSDCOMPAT)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef SO_BINDTODEVICE
+bool Socket::SetSoBindtodevice(const std::string& intf)
+{
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_BINDTODEVICE, (char *)intf.c_str(), intf.size()) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_BINDTODEVICE)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+bool Socket::SetSoBroadcast(bool x)
+{
+#ifdef SO_BROADCAST
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_BROADCAST)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_BROADCAST", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+bool Socket::SetSoDebug(bool x)
+{
+#ifdef SO_DEBUG
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_DEBUG, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_DEBUG)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_DEBUG", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+int Socket::SoError()
+{
+ int value = 0;
+#ifdef SO_ERROR
+ socklen_t len = sizeof(value);
+ if (getsockopt(GetSocket(), SOL_SOCKET, SO_ERROR, (char *)&value, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(SOL_SOCKET, SO_ERROR)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_ERROR", LOG_LEVEL_INFO);
+#endif
+ return value;
+}
+
+bool Socket::SetSoDontroute(bool x)
+{
+#ifdef SO_DONTROUTE
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_DONTROUTE, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_DONTROUTE)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_DONTROUTE", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+bool Socket::SetSoLinger(int onoff, int linger)
+{
+#ifdef SO_LINGER
+ struct linger stl;
+ stl.l_onoff = onoff;
+ stl.l_linger = linger;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_LINGER, (char *)&stl, sizeof(stl)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_LINGER)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_LINGER", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+bool Socket::SetSoOobinline(bool x)
+{
+#ifdef SO_OOBINLINE
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_OOBINLINE, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_OOBINLINE)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_OOBINLINE", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+#ifdef SO_PASSCRED
+bool Socket::SetSoPasscred(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_PASSCRED, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_PASSCRED)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef SO_PEERCRED
+bool Socket::SoPeercred(struct ucred& ucr)
+{
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_PEERCRED, (char *)&ucr, sizeof(ucr)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_PEERCRED)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef SO_PRIORITY
+bool Socket::SetSoPriority(int x)
+{
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_PRIORITY, (char *)&x, sizeof(x)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_PRIORITY)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+bool Socket::SetSoRcvlowat(int x)
+{
+#ifdef SO_RCVLOWAT
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_RCVLOWAT, (char *)&x, sizeof(x)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_RCVLOWAT)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_RCVLOWAT", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+bool Socket::SetSoSndlowat(int x)
+{
+#ifdef SO_SNDLOWAT
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_SNDLOWAT, (char *)&x, sizeof(x)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_SNDLOWAT)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_SNDLOWAT", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+bool Socket::SetSoRcvtimeo(struct timeval& tv)
+{
+#ifdef SO_RCVTIMEO
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_RCVTIMEO)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_RCVTIMEO", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+bool Socket::SetSoSndtimeo(struct timeval& tv)
+{
+#ifdef SO_SNDTIMEO
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_SNDTIMEO)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_SNDTIMEO", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+bool Socket::SetSoRcvbuf(int x)
+{
+#ifdef SO_RCVBUF
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_RCVBUF, (char *)&x, sizeof(x)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_RCVBUF)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_RCVBUF", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+int Socket::SoRcvbuf()
+{
+ int value = 0;
+#ifdef SO_RCVBUF
+ socklen_t len = sizeof(value);
+ if (getsockopt(GetSocket(), SOL_SOCKET, SO_RCVBUF, (char *)&value, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(SOL_SOCKET, SO_RCVBUF)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_RCVBUF", LOG_LEVEL_INFO);
+#endif
+ return value;
+}
+
+#ifdef SO_RCVBUFFORCE
+bool Socket::SetSoRcvbufforce(int x)
+{
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_RCVBUFFORCE, (char *)&x, sizeof(x)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_RCVBUFFORCE)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+bool Socket::SetSoSndbuf(int x)
+{
+#ifdef SO_SNDBUF
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_SNDBUF, (char *)&x, sizeof(x)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_SNDBUF)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_SNDBUF", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+int Socket::SoSndbuf()
+{
+ int value = 0;
+#ifdef SO_SNDBUF
+ socklen_t len = sizeof(value);
+ if (getsockopt(GetSocket(), SOL_SOCKET, SO_SNDBUF, (char *)&value, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(SOL_SOCKET, SO_SNDBUF)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_SNDBUF", LOG_LEVEL_INFO);
+#endif
+ return value;
+}
+
+#ifdef SO_SNDBUFFORCE
+bool Socket::SetSoSndbufforce(int x)
+{
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_SNDBUFFORCE, (char *)&x, sizeof(x)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_SNDBUFFORCE)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+#ifdef SO_TIMESTAMP
+bool Socket::SetSoTimestamp(bool x)
+{
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_TIMESTAMP, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(SOL_SOCKET, SO_TIMESTAMP)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+}
+#endif
+
+int Socket::SoType()
+{
+ int value = 0;
+#ifdef SO_TYPE
+ socklen_t len = sizeof(value);
+ if (getsockopt(GetSocket(), SOL_SOCKET, SO_TYPE, (char *)&value, &len) == -1)
+ {
+ Handler().LogError(this, "getsockopt(SOL_SOCKET, SO_TYPE)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ }
+#else
+ Handler().LogError(this, "socket option not available", 0, "SO_TYPE", LOG_LEVEL_INFO);
+#endif
+ return value;
+}
+
+#ifdef ENABLE_TRIGGERS
+void Socket::Subscribe(int id)
+{
+ Handler().Subscribe(id, this);
+}
+
+void Socket::Unsubscribe(int id)
+{
+ Handler().Unsubscribe(id, this);
+}
+
+void Socket::OnTrigger(int, const TriggerData&)
+{
+}
+
+void Socket::OnCancelled(int)
+{
+}
+#endif
+
+void Socket::SetTimeout(time_t secs)
+{
+ if (!secs)
+ {
+ Handler().AddList(m_socket, LIST_TIMEOUT, false);
+ return;
+ }
+ Handler().AddList(m_socket, LIST_TIMEOUT, true);
+ m_timeout_start = time(NULL);
+ m_timeout_limit = secs;
+}
+
+void Socket::OnTimeout()
+{
+}
+
+void Socket::OnConnectTimeout()
+{
+}
+
+bool Socket::Timeout(time_t tnow)
+{
+ if (tnow - m_timeout_start > m_timeout_limit)
+ return true;
+ return false;
+}
+
+/** Returns local port number for bound socket file descriptor. */
+port_t Socket::GetSockPort()
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ struct sockaddr_in6 sa;
+ socklen_t sockaddr_length = sizeof(struct sockaddr_in6);
+ if (getsockname(GetSocket(), (struct sockaddr *)&sa, (socklen_t*)&sockaddr_length) == -1)
+ memset(&sa, 0, sizeof(sa));
+ return ntohs(sa.sin6_port);
+ }
+#endif
+#endif
+ struct sockaddr_in sa;
+ socklen_t sockaddr_length = sizeof(struct sockaddr_in);
+ if (getsockname(GetSocket(), (struct sockaddr *)&sa, (socklen_t*)&sockaddr_length) == -1)
+ memset(&sa, 0, sizeof(sa));
+ return ntohs(sa.sin_port);
+}
+
+/** Returns local ipv4 address for bound socket file descriptor. */
+ipaddr_t Socket::GetSockIP4()
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ return 0;
+ }
+#endif
+#endif
+ struct sockaddr_in sa;
+ socklen_t sockaddr_length = sizeof(struct sockaddr_in);
+ if (getsockname(GetSocket(), (struct sockaddr *)&sa, (socklen_t*)&sockaddr_length) == -1)
+ memset(&sa, 0, sizeof(sa));
+ ipaddr_t a;
+ memcpy(&a, &sa.sin_addr, 4);
+ return a;
+}
+
+/** Returns local ipv4 address as text for bound socket file descriptor. */
+std::string Socket::GetSockAddress()
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ return "";
+ }
+#endif
+#endif
+ struct sockaddr_in sa;
+ socklen_t sockaddr_length = sizeof(struct sockaddr_in);
+ if (getsockname(GetSocket(), (struct sockaddr *)&sa, (socklen_t*)&sockaddr_length) == -1)
+ memset(&sa, 0, sizeof(sa));
+ Ipv4Address addr( sa );
+ return addr.Convert();
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+/** Returns local ipv6 address for bound socket file descriptor. */
+struct in6_addr Socket::GetSockIP6()
+{
+ if (IsIpv6())
+ {
+ struct sockaddr_in6 sa;
+ socklen_t sockaddr_length = sizeof(struct sockaddr_in6);
+ if (getsockname(GetSocket(), (struct sockaddr *)&sa, (socklen_t*)&sockaddr_length) == -1)
+ memset(&sa, 0, sizeof(sa));
+ return sa.sin6_addr;
+ }
+ struct in6_addr a;
+ memset(&a, 0, sizeof(a));
+ return a;
+}
+
+/** Returns local ipv6 address as text for bound socket file descriptor. */
+std::string Socket::GetSockAddress6()
+{
+ if (IsIpv6())
+ {
+ struct sockaddr_in6 sa;
+ socklen_t sockaddr_length = sizeof(struct sockaddr_in6);
+ if (getsockname(GetSocket(), (struct sockaddr *)&sa, (socklen_t*)&sockaddr_length) == -1)
+ memset(&sa, 0, sizeof(sa));
+ Ipv6Address addr( sa );
+ return addr.Convert();
+ }
+ return "";
+}
+#endif
+#endif
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/SocketHandler.cpp b/dep/sockets/SocketHandler.cpp
new file mode 100644
index 00000000000..acf71fb2efa
--- /dev/null
+++ b/dep/sockets/SocketHandler.cpp
@@ -0,0 +1,1377 @@
+/** \file SocketHandler.cpp
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifdef _WIN32
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <cstdio>
+
+#include "SocketHandler.h"
+#include "UdpSocket.h"
+#include "ResolvSocket.h"
+#include "ResolvServer.h"
+#include "TcpSocket.h"
+#include "Mutex.h"
+#include "Utility.h"
+#include "SocketAddress.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+//#ifdef _DEBUG
+//#define DEB(x) x; fflush(stderr);
+//#else
+#define DEB(x)
+//#endif
+
+SocketHandler::SocketHandler(StdLog *p)
+:m_stdlog(p)
+,m_mutex(m_mutex)
+,m_b_use_mutex(false)
+,m_maxsock(0)
+,m_preverror(-1)
+,m_errcnt(0)
+,m_tlast(0)
+#ifdef ENABLE_SOCKS4
+,m_socks4_host(0)
+,m_socks4_port(0)
+,m_bTryDirect(false)
+#endif
+#ifdef ENABLE_RESOLVER
+,m_resolv_id(0)
+,m_resolver(NULL)
+#endif
+#ifdef ENABLE_POOL
+,m_b_enable_pool(false)
+#endif
+#ifdef ENABLE_TRIGGERS
+,m_next_trigger_id(0)
+#endif
+#ifdef ENABLE_DETACH
+,m_slave(false)
+#endif
+{
+ FD_ZERO(&m_rfds);
+ FD_ZERO(&m_wfds);
+ FD_ZERO(&m_efds);
+}
+
+SocketHandler::SocketHandler(Mutex& mutex,StdLog *p)
+:m_stdlog(p)
+,m_mutex(mutex)
+,m_b_use_mutex(true)
+,m_maxsock(0)
+,m_preverror(-1)
+,m_errcnt(0)
+,m_tlast(0)
+#ifdef ENABLE_SOCKS4
+,m_socks4_host(0)
+,m_socks4_port(0)
+,m_bTryDirect(false)
+#endif
+#ifdef ENABLE_RESOLVER
+,m_resolv_id(0)
+,m_resolver(NULL)
+#endif
+#ifdef ENABLE_POOL
+,m_b_enable_pool(false)
+#endif
+#ifdef ENABLE_TRIGGERS
+,m_next_trigger_id(0)
+#endif
+#ifdef ENABLE_DETACH
+,m_slave(false)
+#endif
+{
+ m_mutex.Lock();
+ FD_ZERO(&m_rfds);
+ FD_ZERO(&m_wfds);
+ FD_ZERO(&m_efds);
+}
+
+SocketHandler::~SocketHandler()
+{
+#ifdef ENABLE_RESOLVER
+ if (m_resolver)
+ {
+ m_resolver -> Quit();
+ }
+#endif
+ {
+ while (m_sockets.size())
+ {
+DEB( fprintf(stderr, "Emptying sockets list in SocketHandler destructor, %d instances\n", (int)m_sockets.size());)
+ socket_m::iterator it = m_sockets.begin();
+ Socket *p = it -> second;
+ if (p)
+ {
+DEB( fprintf(stderr, " fd %d\n", p -> GetSocket());)
+ p -> Close();
+DEB( fprintf(stderr, " fd closed %d\n", p -> GetSocket());)
+// p -> OnDelete(); // hey, I turn this back on. what's the worst that could happen??!!
+ // MinionSocket breaks, calling MinderHandler methods in OnDelete -
+ // MinderHandler is already gone when that happens...
+
+ // only delete socket when controlled
+ // ie master sockethandler can delete non-detached sockets
+ // and a slave sockethandler can only delete a detach socket
+ if (p -> DeleteByHandler()
+#ifdef ENABLE_DETACH
+ && !(m_slave ^ p -> IsDetached())
+#endif
+ )
+ {
+ p -> SetErasedByHandler();
+ delete p;
+ }
+ m_sockets.erase(it);
+ }
+ else
+ {
+ m_sockets.erase(it);
+ }
+DEB( fprintf(stderr, "next\n");)
+ }
+DEB( fprintf(stderr, "/Emptying sockets list in SocketHandler destructor, %d instances\n", (int)m_sockets.size());)
+ }
+#ifdef ENABLE_RESOLVER
+ if (m_resolver)
+ {
+ delete m_resolver;
+ }
+#endif
+ if (m_b_use_mutex)
+ {
+ m_mutex.Unlock();
+ }
+}
+
+Mutex& SocketHandler::GetMutex() const
+{
+ return m_mutex;
+}
+
+#ifdef ENABLE_DETACH
+void SocketHandler::SetSlave(bool x)
+{
+ m_slave = x;
+}
+
+bool SocketHandler::IsSlave()
+{
+ return m_slave;
+}
+#endif
+
+void SocketHandler::RegStdLog(StdLog *log)
+{
+ m_stdlog = log;
+}
+
+void SocketHandler::LogError(Socket *p,const std::string& user_text,int err,const std::string& sys_err,loglevel_t t)
+{
+ if (m_stdlog)
+ {
+ m_stdlog -> error(this, p, user_text, err, sys_err, t);
+ }
+}
+
+void SocketHandler::Add(Socket *p)
+{
+ if (p -> GetSocket() == INVALID_SOCKET)
+ {
+ LogError(p, "Add", -1, "Invalid socket", LOG_LEVEL_WARNING);
+ if (p -> CloseAndDelete())
+ {
+ m_delete.push_back(p);
+ }
+ return;
+ }
+ if (m_add.find(p -> GetSocket()) != m_add.end())
+ {
+ LogError(p, "Add", (int)p -> GetSocket(), "Attempt to add socket already in add queue", LOG_LEVEL_FATAL);
+ m_delete.push_back(p);
+ return;
+ }
+ m_add[p -> GetSocket()] = p;
+}
+
+void SocketHandler::Get(SOCKET s,bool& r,bool& w,bool& e)
+{
+ if (s >= 0)
+ {
+ r = FD_ISSET(s, &m_rfds) ? true : false;
+ w = FD_ISSET(s, &m_wfds) ? true : false;
+ e = FD_ISSET(s, &m_efds) ? true : false;
+ }
+}
+
+void SocketHandler::Set(SOCKET s,bool bRead,bool bWrite,bool bException)
+{
+DEB( fprintf(stderr, "Set(%d, %s, %s, %s)\n", s, bRead ? "true" : "false", bWrite ? "true" : "false", bException ? "true" : "false");)
+ if (s >= 0)
+ {
+ if (bRead)
+ {
+ if (!FD_ISSET(s, &m_rfds))
+ {
+ FD_SET(s, &m_rfds);
+ }
+ }
+ else
+ {
+ FD_CLR(s, &m_rfds);
+ }
+ if (bWrite)
+ {
+ if (!FD_ISSET(s, &m_wfds))
+ {
+ FD_SET(s, &m_wfds);
+ }
+ }
+ else
+ {
+ FD_CLR(s, &m_wfds);
+ }
+ if (bException)
+ {
+ if (!FD_ISSET(s, &m_efds))
+ {
+ FD_SET(s, &m_efds);
+ }
+ }
+ else
+ {
+ FD_CLR(s, &m_efds);
+ }
+ }
+}
+
+int SocketHandler::Select(long sec,long usec)
+{
+ struct timeval tv;
+ tv.tv_sec = sec;
+ tv.tv_usec = usec;
+ return Select(&tv);
+}
+
+int SocketHandler::Select()
+{
+ if (!m_fds_callonconnect.empty() ||
+#ifdef ENABLE_DETACH
+ (!m_slave && !m_fds_detach.empty()) ||
+#endif
+ !m_fds_timeout.empty() ||
+ !m_fds_retry.empty() ||
+ !m_fds_close.empty() ||
+ !m_fds_erase.empty())
+ {
+ return Select(0, 200000);
+ }
+ return Select(NULL);
+}
+
+int SocketHandler::Select(struct timeval *tsel)
+{
+ size_t ignore = 0;
+ while (m_add.size() > ignore)
+ {
+ if (m_sockets.size() >= FD_SETSIZE)
+ {
+ LogError(NULL, "Select", (int)m_sockets.size(), "FD_SETSIZE reached", LOG_LEVEL_WARNING);
+ break;
+ }
+ socket_m::iterator it = m_add.begin();
+ SOCKET s = it -> first;
+ Socket *p = it -> second;
+DEB( fprintf(stderr, "Trying to add fd %d, m_add.size() %d, ignore %d\n", (int)s, (int)m_add.size(), (int)ignore);)
+ //
+ if (m_sockets.find(p -> GetSocket()) != m_sockets.end())
+ {
+ LogError(p, "Add", (int)p -> GetSocket(), "Attempt to add socket already in controlled queue", LOG_LEVEL_FATAL);
+ // %! it's a dup, don't add to delete queue, just ignore it
+ m_delete.push_back(p);
+ m_add.erase(it);
+// ignore++;
+ continue;
+ }
+ if (!p -> CloseAndDelete())
+ {
+ StreamSocket *scp = dynamic_cast<StreamSocket *>(p);
+ if (scp && scp -> Connecting()) // 'Open' called before adding socket
+ {
+ Set(s,false,true);
+ }
+ else
+ {
+ TcpSocket *tcp = dynamic_cast<TcpSocket *>(p);
+ bool bWrite = tcp ? tcp -> GetOutputLength() != 0 : false;
+ if (p -> IsDisableRead())
+ {
+ Set(s, false, bWrite);
+ }
+ else
+ {
+ Set(s, true, bWrite);
+ }
+ }
+ m_maxsock = (s > m_maxsock) ? s : m_maxsock;
+ }
+ else
+ {
+ LogError(p, "Add", (int)p -> GetSocket(), "Trying to add socket with SetCloseAndDelete() true", LOG_LEVEL_WARNING);
+ }
+ // only add to m_fds (process fd_set events) if
+ // slave handler and detached/detaching socket
+ // master handler and non-detached socket
+#ifdef ENABLE_DETACH
+ if (!(m_slave ^ p -> IsDetach()))
+#endif
+ {
+ m_fds.push_back(s);
+ }
+ m_sockets[s] = p;
+ //
+ m_add.erase(it);
+ }
+#ifdef MACOSX
+ fd_set rfds;
+ fd_set wfds;
+ fd_set efds;
+ FD_COPY(&m_rfds, &rfds);
+ FD_COPY(&m_wfds, &wfds);
+ FD_COPY(&m_efds, &efds);
+#else
+ fd_set rfds = m_rfds;
+ fd_set wfds = m_wfds;
+ fd_set efds = m_efds;
+#endif
+ int n;
+ if (m_b_use_mutex)
+ {
+ m_mutex.Unlock();
+ n = select( (int)(m_maxsock + 1),&rfds,&wfds,&efds,tsel);
+ m_mutex.Lock();
+ }
+ else
+ {
+ n = select( (int)(m_maxsock + 1),&rfds,&wfds,&efds,tsel);
+ }
+ if (n == -1)
+ {
+ /*
+ EBADF An invalid file descriptor was given in one of the sets.
+ EINTR A non blocked signal was caught.
+ EINVAL n is negative. Or struct timeval contains bad time values (<0).
+ ENOMEM select was unable to allocate memory for internal tables.
+ */
+ if (Errno != m_preverror || m_errcnt++ % 10000 == 0)
+ {
+ LogError(NULL, "select", Errno, StrError(Errno));
+DEB( fprintf(stderr, "m_maxsock: %d\n", m_maxsock);
+ fprintf(stderr, "%s\n", Errno == EINVAL ? "EINVAL" :
+ Errno == EINTR ? "EINTR" :
+ Errno == EBADF ? "EBADF" :
+ Errno == ENOMEM ? "ENOMEM" : "<another>");
+ // test bad fd
+ for (SOCKET i = 0; i <= m_maxsock; i++)
+ {
+ bool t = false;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+ if (FD_ISSET(i, &m_rfds))
+ {
+ FD_SET(i, &rfds);
+ t = true;
+ }
+ if (FD_ISSET(i, &m_wfds))
+ {
+ FD_SET(i, &wfds);
+ t = true;
+ }
+ if (FD_ISSET(i, &m_efds))
+ {
+ FD_SET(i, &efds);
+ t = true;
+ }
+ if (t && m_sockets.find(i) == m_sockets.end())
+ {
+ fprintf(stderr, "Bad fd in fd_set: %d\n", i);
+ }
+ }
+) // DEB
+ m_preverror = Errno;
+ }
+ /// \todo rebuild fd_set's from active sockets list (m_sockets) here
+ }
+ else
+ if (!n)
+ {
+ m_preverror = -1;
+ }
+ else
+ if (n > 0)
+ {
+ for (socket_v::iterator it2 = m_fds.begin(); it2 != m_fds.end() && n; it2++)
+ {
+ SOCKET i = *it2;
+ if (FD_ISSET(i, &rfds))
+ {
+ socket_m::iterator itmp = m_sockets.find(i);
+ if (itmp != m_sockets.end()) // found
+ {
+ Socket *p = itmp -> second;
+ // new SSL negotiate method
+#ifdef HAVE_OPENSSL
+ if (p -> IsSSLNegotiate())
+ {
+ p -> SSLNegotiate();
+ }
+ else
+#endif
+ {
+ p -> OnRead();
+ }
+ }
+ else
+ {
+ LogError(NULL, "GetSocket/handler/1", (int)i, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
+ }
+ n--;
+ }
+ if (FD_ISSET(i, &wfds))
+ {
+ socket_m::iterator itmp = m_sockets.find(i);
+ if (itmp != m_sockets.end()) // found
+ {
+ Socket *p = itmp -> second;
+ // new SSL negotiate method
+#ifdef HAVE_OPENSSL
+ if (p -> IsSSLNegotiate())
+ {
+ p -> SSLNegotiate();
+ }
+ else
+#endif
+ {
+ p -> OnWrite();
+ }
+ }
+ else
+ {
+ LogError(NULL, "GetSocket/handler/2", (int)i, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
+ }
+ n--;
+ }
+ if (FD_ISSET(i, &efds))
+ {
+ socket_m::iterator itmp = m_sockets.find(i);
+ if (itmp != m_sockets.end()) // found
+ {
+ Socket *p = itmp -> second;
+ p -> OnException();
+ }
+ else
+ {
+ LogError(NULL, "GetSocket/handler/3", (int)i, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
+ }
+ n--;
+ }
+ } // m_fds loop
+ m_preverror = -1;
+ } // if (n > 0)
+
+ // check CallOnConnect - EVENT
+ if (!m_fds_callonconnect.empty())
+ {
+ socket_v tmp = m_fds_callonconnect;
+ for (socket_v::iterator it = tmp.begin(); it != tmp.end(); it++)
+ {
+ Socket *p = NULL;
+ {
+ socket_m::iterator itmp = m_sockets.find(*it);
+ if (itmp != m_sockets.end()) // found
+ {
+ p = itmp -> second;
+ }
+ else
+ {
+ LogError(NULL, "GetSocket/handler/4", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
+ }
+ }
+ if (p)
+ {
+// if (p -> CallOnConnect() && p -> Ready() )
+ {
+ p -> SetConnected(); // moved here from inside if (tcp) check below
+#ifdef HAVE_OPENSSL
+ if (p -> IsSSL()) // SSL Enabled socket
+ p -> OnSSLConnect();
+ else
+#endif
+#ifdef ENABLE_SOCKS4
+ if (p -> Socks4())
+ p -> OnSocks4Connect();
+ else
+#endif
+ {
+ TcpSocket *tcp = dynamic_cast<TcpSocket *>(p);
+ if (tcp)
+ {
+ if (tcp -> GetOutputLength())
+ {
+ p -> OnWrite();
+ }
+ }
+#ifdef ENABLE_RECONNECT
+ if (tcp && tcp -> IsReconnect())
+ p -> OnReconnect();
+ else
+#endif
+ {
+// LogError(p, "Calling OnConnect", 0, "Because CallOnConnect", LOG_LEVEL_INFO);
+ p -> OnConnect();
+ }
+ }
+// p -> SetCallOnConnect( false );
+ AddList(p -> GetSocket(), LIST_CALLONCONNECT, false);
+ }
+ }
+ }
+ }
+#ifdef ENABLE_DETACH
+ // check detach of socket if master handler - EVENT
+ if (!m_slave && !m_fds_detach.empty())
+ {
+ // %! why not using tmp list here??!?
+ for (socket_v::iterator it = m_fds_detach.begin(); it != m_fds_detach.end(); it++)
+ {
+ Socket *p = NULL;
+ {
+ socket_m::iterator itmp = m_sockets.find(*it);
+ if (itmp != m_sockets.end()) // found
+ {
+ p = itmp -> second;
+ }
+ else
+ {
+ LogError(NULL, "GetSocket/handler/5", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
+ }
+ }
+ if (p)
+ {
+// if (p -> IsDetach())
+ {
+ Set(p -> GetSocket(), false, false, false);
+ // After DetachSocket(), all calls to Handler() will return a reference
+ // to the new slave SocketHandler running in the new thread.
+ p -> DetachSocket();
+ // Adding the file descriptor to m_fds_erase will now also remove the
+ // socket from the detach queue - tnx knightmad
+ m_fds_erase.push_back(p -> GetSocket());
+ }
+ }
+ }
+ }
+#endif
+ // check Connecting - connection timeout - conditional event
+ if (m_fds_timeout.size())
+ {
+ time_t tnow = time(NULL);
+ if (tnow != m_tlast)
+ {
+ socket_v tmp = m_fds_timeout;
+DEB( fprintf(stderr, "Checking %d socket(s) for timeout\n", tmp.size());)
+ for (socket_v::iterator it = tmp.begin(); it != tmp.end(); it++)
+ {
+ Socket *p = NULL;
+ {
+ socket_m::iterator itmp = m_sockets.find(*it);
+ if (itmp != m_sockets.end()) // found
+ {
+ p = itmp -> second;
+ }
+ else
+ {
+ itmp = m_add.find(*it);
+ if (itmp != m_add.end())
+ {
+ p = itmp -> second;
+ }
+ else
+ {
+ LogError(NULL, "GetSocket/handler/6", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
+ }
+ }
+ }
+ if (p)
+ {
+ if (p -> Timeout(tnow))
+ {
+ StreamSocket *scp = dynamic_cast<StreamSocket *>(p);
+ if (scp && scp -> Connecting())
+ p -> OnConnectTimeout();
+ else
+ p -> OnTimeout();
+ p -> SetTimeout(0);
+ }
+ }
+ }
+ m_tlast = tnow;
+ } // tnow != tlast
+ }
+ // check retry client connect - EVENT
+ if (!m_fds_retry.empty())
+ {
+ socket_v tmp = m_fds_retry;
+ for (socket_v::iterator it = tmp.begin(); it != tmp.end(); it++)
+ {
+ Socket *p = NULL;
+ {
+ socket_m::iterator itmp = m_sockets.find(*it);
+ if (itmp != m_sockets.end()) // found
+ {
+ p = itmp -> second;
+ }
+ else
+ {
+ LogError(NULL, "GetSocket/handler/7", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
+ }
+ }
+ if (p)
+ {
+// if (p -> RetryClientConnect())
+ {
+ TcpSocket *tcp = dynamic_cast<TcpSocket *>(p);
+ SOCKET nn = *it; //(*it3).first;
+ tcp -> SetRetryClientConnect(false);
+DEB( fprintf(stderr, "Close() before retry client connect\n");)
+ p -> Close(); // removes from m_fds_retry
+ std::auto_ptr<SocketAddress> ad = p -> GetClientRemoteAddress();
+ if (ad.get())
+ {
+ tcp -> Open(*ad);
+ }
+ else
+ {
+ LogError(p, "RetryClientConnect", 0, "no address", LOG_LEVEL_ERROR);
+ }
+ Add(p);
+ m_fds_erase.push_back(nn);
+ }
+ }
+ }
+ }
+ // check close and delete - conditional event
+ if (!m_fds_close.empty())
+ {
+ socket_v tmp = m_fds_close;
+DEB( fprintf(stderr, "m_fds_close.size() == %d\n", (int)m_fds_close.size());)
+ for (socket_v::iterator it = tmp.begin(); it != tmp.end(); it++)
+ {
+ Socket *p = NULL;
+ {
+ socket_m::iterator itmp = m_sockets.find(*it);
+ if (itmp != m_sockets.end()) // found
+ {
+ p = itmp -> second;
+ }
+ else
+ {
+ itmp = m_add.find(*it);
+ if (itmp != m_add.end())
+ {
+ p = itmp -> second;
+ }
+ else
+ {
+ LogError(NULL, "GetSocket/handler/8", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
+ }
+ }
+ }
+ if (p)
+ {
+// if (p -> CloseAndDelete() )
+ {
+ TcpSocket *tcp = dynamic_cast<TcpSocket *>(p);
+ // new graceful tcp - flush and close timeout 5s
+ if (tcp && p -> IsConnected() && tcp -> GetFlushBeforeClose() &&
+#ifdef HAVE_OPENSSL
+ !tcp -> IsSSL() &&
+#endif
+ p -> TimeSinceClose() < 5)
+ {
+DEB( fprintf(stderr, " close(1)\n");)
+ if (tcp -> GetOutputLength())
+ {
+ LogError(p, "Closing", (int)tcp -> GetOutputLength(), "Sending all data before closing", LOG_LEVEL_INFO);
+ }
+ else // shutdown write when output buffer is empty
+ if (!(tcp -> GetShutdown() & SHUT_WR))
+ {
+ SOCKET nn = *it;
+ if (nn != INVALID_SOCKET && shutdown(nn, SHUT_WR) == -1)
+ {
+ LogError(p, "graceful shutdown", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+ tcp -> SetShutdown(SHUT_WR);
+ }
+ }
+ else
+#ifdef ENABLE_RECONNECT
+ if (tcp && p -> IsConnected() && tcp -> Reconnect())
+ {
+ SOCKET nn = *it; //(*it3).first;
+DEB( fprintf(stderr, " close(2) fd %d\n", nn);)
+ p -> SetCloseAndDelete(false);
+ tcp -> SetIsReconnect();
+ p -> SetConnected(false);
+DEB( fprintf(stderr, "Close() before reconnect\n");)
+ p -> Close(); // dispose of old file descriptor (Open creates a new)
+ p -> OnDisconnect();
+ std::auto_ptr<SocketAddress> ad = p -> GetClientRemoteAddress();
+ if (ad.get())
+ {
+ tcp -> Open(*ad);
+ }
+ else
+ {
+ LogError(p, "Reconnect", 0, "no address", LOG_LEVEL_ERROR);
+ }
+ tcp -> ResetConnectionRetries();
+ Add(p);
+ m_fds_erase.push_back(nn);
+ }
+ else
+#endif
+ {
+ SOCKET nn = *it; //(*it3).first;
+DEB( fprintf(stderr, " close(3) fd %d GetSocket() %d\n", nn, p -> GetSocket());)
+ if (tcp && p -> IsConnected() && tcp -> GetOutputLength())
+ {
+ LogError(p, "Closing", (int)tcp -> GetOutputLength(), "Closing socket while data still left to send", LOG_LEVEL_WARNING);
+ }
+#ifdef ENABLE_POOL
+ if (p -> Retain() && !p -> Lost())
+ {
+ PoolSocket *p2 = new PoolSocket(*this, p);
+ p2 -> SetDeleteByHandler();
+ Add(p2);
+ //
+ p -> SetCloseAndDelete(false); // added - remove from m_fds_close
+ }
+ else
+#endif // ENABLE_POOL
+ {
+ Set(p -> GetSocket(),false,false,false);
+DEB( fprintf(stderr, "Close() before OnDelete\n");)
+ p -> Close();
+ }
+ p -> OnDelete();
+ if (p -> DeleteByHandler())
+ {
+ p -> SetErasedByHandler();
+ }
+ m_fds_erase.push_back(nn);
+ }
+ }
+ }
+ }
+ }
+
+ // check erased sockets
+ bool check_max_fd = false;
+ while (!m_fds_erase.empty())
+ {
+ socket_v::iterator it = m_fds_erase.begin();
+ SOCKET nn = *it;
+#ifdef ENABLE_DETACH
+ {
+ for (socket_v::iterator it = m_fds_detach.begin(); it != m_fds_detach.end(); it++)
+ {
+ if (*it == nn)
+ {
+ m_fds_detach.erase(it);
+ break;
+ }
+ }
+ }
+#endif
+ {
+ for (socket_v::iterator it = m_fds.begin(); it != m_fds.end(); it++)
+ {
+ if (*it == nn)
+ {
+ m_fds.erase(it);
+ break;
+ }
+ }
+ }
+ {
+ socket_m::iterator it = m_sockets.find(nn);
+ if (it != m_sockets.end())
+ {
+ Socket *p = it -> second;
+ /* Sometimes a SocketThread class can finish its run before the master
+ sockethandler gets here. In that case, the SocketThread has set the
+ 'ErasedByHandler' flag on the socket which will make us end up with a
+ double delete on the socket instance.
+ The fix is to make sure that the master sockethandler only can delete
+ non-detached sockets, and a slave sockethandler only can delete
+ detach sockets. */
+ if (p -> ErasedByHandler()
+#ifdef ENABLE_DETACH
+ && !(m_slave ^ p -> IsDetached())
+#endif
+ )
+ {
+#ifdef ENABLE_TRIGGERS
+ bool again = false;
+ do
+ {
+ again = false;
+ for (std::map<int, Socket *>::iterator it = m_trigger_src.begin(); it != m_trigger_src.end(); it++)
+ {
+ int id = it -> first;
+ Socket *src = it -> second;
+ if (src == p)
+ {
+ for (std::map<Socket *, bool>::iterator it = m_trigger_dst[id].begin(); it != m_trigger_dst[id].end(); it++)
+ {
+ Socket *dst = it -> first;
+ if (Valid(dst))
+ {
+ dst -> OnCancelled(id);
+ }
+ }
+ m_trigger_src.erase(m_trigger_src.find(id));
+ m_trigger_dst.erase(m_trigger_dst.find(id));
+ again = true;
+ break;
+ }
+ }
+ } while (again);
+#endif
+ delete p;
+ }
+ m_sockets.erase(it);
+ }
+ }
+ m_fds_erase.erase(it);
+ check_max_fd = true;
+ }
+ // calculate max file descriptor for select() call
+ if (check_max_fd)
+ {
+ m_maxsock = 0;
+ for (socket_v::iterator it = m_fds.begin(); it != m_fds.end(); it++)
+ {
+ SOCKET s = *it;
+ m_maxsock = s > m_maxsock ? s : m_maxsock;
+ }
+ }
+ // remove Add's that fizzed
+ while (!m_delete.empty())
+ {
+ std::list<Socket *>::iterator it = m_delete.begin();
+ Socket *p = *it;
+ p -> OnDelete();
+ m_delete.erase(it);
+ if (p -> DeleteByHandler()
+#ifdef ENABLE_DETACH
+ && !(m_slave ^ p -> IsDetached())
+#endif
+ )
+ {
+ p -> SetErasedByHandler();
+#ifdef ENABLE_TRIGGERS
+ bool again = false;
+ do
+ {
+ again = false;
+ for (std::map<int, Socket *>::iterator it = m_trigger_src.begin(); it != m_trigger_src.end(); it++)
+ {
+ int id = it -> first;
+ Socket *src = it -> second;
+ if (src == p)
+ {
+ for (std::map<Socket *, bool>::iterator it = m_trigger_dst[id].begin(); it != m_trigger_dst[id].end(); it++)
+ {
+ Socket *dst = it -> first;
+ if (Valid(dst))
+ {
+ dst -> OnCancelled(id);
+ }
+ }
+ m_trigger_src.erase(m_trigger_src.find(id));
+ m_trigger_dst.erase(m_trigger_dst.find(id));
+ again = true;
+ break;
+ }
+ }
+ } while (again);
+#endif
+ delete p;
+ }
+ }
+ return n;
+}
+
+#ifdef ENABLE_RESOLVER
+bool SocketHandler::Resolving(Socket *p0)
+{
+ std::map<Socket *, bool>::iterator it = m_resolve_q.find(p0);
+ return it != m_resolve_q.end();
+}
+#endif
+
+bool SocketHandler::Valid(Socket *p0)
+{
+ for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
+ {
+ Socket *p = it -> second;
+ if (p0 == p)
+ return true;
+ }
+ return false;
+}
+
+bool SocketHandler::OkToAccept(Socket *)
+{
+ return true;
+}
+
+size_t SocketHandler::GetCount()
+{
+/*
+printf(" m_sockets : %d\n", m_sockets.size());
+printf(" m_add : %d\n", m_add.size());
+printf(" m_delete : %d\n", m_delete.size());
+*/
+ return m_sockets.size() + m_add.size() + m_delete.size();
+}
+
+#ifdef ENABLE_SOCKS4
+void SocketHandler::SetSocks4Host(ipaddr_t a)
+{
+ m_socks4_host = a;
+}
+
+void SocketHandler::SetSocks4Host(const std::string& host)
+{
+ Utility::u2ip(host, m_socks4_host);
+}
+
+void SocketHandler::SetSocks4Port(port_t port)
+{
+ m_socks4_port = port;
+}
+
+void SocketHandler::SetSocks4Userid(const std::string& id)
+{
+ m_socks4_userid = id;
+}
+#endif
+
+#ifdef ENABLE_RESOLVER
+int SocketHandler::Resolve(Socket *p,const std::string& host,port_t port)
+{
+ // check cache
+ ResolvSocket *resolv = new ResolvSocket(*this, p, host, port);
+ resolv -> SetId(++m_resolv_id);
+ resolv -> SetDeleteByHandler();
+ ipaddr_t local;
+ Utility::u2ip("127.0.0.1", local);
+ if (!resolv -> Open(local, m_resolver_port))
+ {
+ LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL);
+ }
+ Add(resolv);
+ m_resolve_q[p] = true;
+DEB( fprintf(stderr, " *** Resolve '%s:%d' id#%d m_resolve_q size: %d p: %p\n", host.c_str(), port, resolv -> GetId(), m_resolve_q.size(), p);)
+ return resolv -> GetId();
+}
+
+#ifdef ENABLE_IPV6
+int SocketHandler::Resolve6(Socket *p,const std::string& host,port_t port)
+{
+ // check cache
+ ResolvSocket *resolv = new ResolvSocket(*this, p, host, port, true);
+ resolv -> SetId(++m_resolv_id);
+ resolv -> SetDeleteByHandler();
+ ipaddr_t local;
+ Utility::u2ip("127.0.0.1", local);
+ if (!resolv -> Open(local, m_resolver_port))
+ {
+ LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL);
+ }
+ Add(resolv);
+ m_resolve_q[p] = true;
+ return resolv -> GetId();
+}
+#endif
+
+int SocketHandler::Resolve(Socket *p,ipaddr_t a)
+{
+ // check cache
+ ResolvSocket *resolv = new ResolvSocket(*this, p, a);
+ resolv -> SetId(++m_resolv_id);
+ resolv -> SetDeleteByHandler();
+ ipaddr_t local;
+ Utility::u2ip("127.0.0.1", local);
+ if (!resolv -> Open(local, m_resolver_port))
+ {
+ LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL);
+ }
+ Add(resolv);
+ m_resolve_q[p] = true;
+ return resolv -> GetId();
+}
+
+#ifdef ENABLE_IPV6
+int SocketHandler::Resolve(Socket *p,in6_addr& a)
+{
+ // check cache
+ ResolvSocket *resolv = new ResolvSocket(*this, p, a);
+ resolv -> SetId(++m_resolv_id);
+ resolv -> SetDeleteByHandler();
+ ipaddr_t local;
+ Utility::u2ip("127.0.0.1", local);
+ if (!resolv -> Open(local, m_resolver_port))
+ {
+ LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL);
+ }
+ Add(resolv);
+ m_resolve_q[p] = true;
+ return resolv -> GetId();
+}
+#endif
+
+void SocketHandler::EnableResolver(port_t port)
+{
+ if (!m_resolver)
+ {
+ m_resolver_port = port;
+ m_resolver = new ResolvServer(port);
+ }
+}
+
+bool SocketHandler::ResolverReady()
+{
+ return m_resolver ? m_resolver -> Ready() : false;
+}
+#endif // ENABLE_RESOLVER
+
+#ifdef ENABLE_SOCKS4
+void SocketHandler::SetSocks4TryDirect(bool x)
+{
+ m_bTryDirect = x;
+}
+
+ipaddr_t SocketHandler::GetSocks4Host()
+{
+ return m_socks4_host;
+}
+
+port_t SocketHandler::GetSocks4Port()
+{
+ return m_socks4_port;
+}
+
+const std::string& SocketHandler::GetSocks4Userid()
+{
+ return m_socks4_userid;
+}
+
+bool SocketHandler::Socks4TryDirect()
+{
+ return m_bTryDirect;
+}
+#endif
+
+#ifdef ENABLE_RESOLVER
+bool SocketHandler::ResolverEnabled()
+{
+ return m_resolver ? true : false;
+}
+
+port_t SocketHandler::GetResolverPort()
+{
+ return m_resolver_port;
+}
+#endif // ENABLE_RESOLVER
+
+#ifdef ENABLE_POOL
+ISocketHandler::PoolSocket *SocketHandler::FindConnection(int type,const std::string& protocol,SocketAddress& ad)
+{
+ for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end() && !m_sockets.empty(); it++)
+ {
+ PoolSocket *pools = dynamic_cast<PoolSocket *>(it -> second);
+ if (pools)
+ {
+ if (pools -> GetSocketType() == type &&
+ pools -> GetSocketProtocol() == protocol &&
+// %! pools -> GetClientRemoteAddress() &&
+ *pools -> GetClientRemoteAddress() == ad)
+ {
+ m_sockets.erase(it);
+ pools -> SetRetain(); // avoid Close in Socket destructor
+ return pools; // Caller is responsible that this socket is deleted
+ }
+ }
+ }
+ return NULL;
+}
+
+void SocketHandler::EnablePool(bool x)
+{
+ m_b_enable_pool = x;
+}
+
+bool SocketHandler::PoolEnabled()
+{
+ return m_b_enable_pool;
+}
+#endif
+
+void SocketHandler::Remove(Socket *p)
+{
+#ifdef ENABLE_RESOLVER
+ std::map<Socket *, bool>::iterator it4 = m_resolve_q.find(p);
+ if (it4 != m_resolve_q.end())
+ m_resolve_q.erase(it4);
+#endif
+ if (p -> ErasedByHandler())
+ {
+ return;
+ }
+ for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
+ {
+ if (it -> second == p)
+ {
+ LogError(p, "Remove", -1, "Socket destructor called while still in use", LOG_LEVEL_WARNING);
+ m_sockets.erase(it);
+ return;
+ }
+ }
+ for (socket_m::iterator it2 = m_add.begin(); it2 != m_add.end(); it2++)
+ {
+ if ((*it2).second == p)
+ {
+ LogError(p, "Remove", -2, "Socket destructor called while still in use", LOG_LEVEL_WARNING);
+ m_add.erase(it2);
+ return;
+ }
+ }
+ for (std::list<Socket *>::iterator it3 = m_delete.begin(); it3 != m_delete.end(); it3++)
+ {
+ if (*it3 == p)
+ {
+ LogError(p, "Remove", -3, "Socket destructor called while still in use", LOG_LEVEL_WARNING);
+ m_delete.erase(it3);
+ return;
+ }
+ }
+}
+
+void SocketHandler::CheckSanity()
+{
+ CheckList(m_fds, "active sockets"); // active sockets
+ CheckList(m_fds_erase, "sockets to be erased"); // should always be empty anyway
+ CheckList(m_fds_callonconnect, "checklist CallOnConnect");
+#ifdef ENABLE_DETACH
+ CheckList(m_fds_detach, "checklist Detach");
+#endif
+ CheckList(m_fds_timeout, "checklist Timeout");
+ CheckList(m_fds_retry, "checklist retry client connect");
+ CheckList(m_fds_close, "checklist close and delete");
+}
+
+void SocketHandler::CheckList(socket_v& ref,const std::string& listname)
+{
+ for (socket_v::iterator it = ref.begin(); it != ref.end(); it++)
+ {
+ SOCKET s = *it;
+ if (m_sockets.find(s) != m_sockets.end())
+ continue;
+ if (m_add.find(s) != m_add.end())
+ continue;
+ bool found = false;
+ for (std::list<Socket *>::iterator it = m_delete.begin(); it != m_delete.end(); it++)
+ {
+ Socket *p = *it;
+ if (p -> GetSocket() == s)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ fprintf(stderr, "CheckList failed for \"%s\": fd %d\n", listname.c_str(), s);
+ }
+ }
+}
+
+void SocketHandler::AddList(SOCKET s,list_t which_one,bool add)
+{
+ if (s == INVALID_SOCKET)
+ {
+DEB( fprintf(stderr, "AddList: invalid_socket\n");)
+ return;
+ }
+ socket_v& ref =
+ (which_one == LIST_CALLONCONNECT) ? m_fds_callonconnect :
+#ifdef ENABLE_DETACH
+ (which_one == LIST_DETACH) ? m_fds_detach :
+#endif
+ (which_one == LIST_TIMEOUT) ? m_fds_timeout :
+ (which_one == LIST_RETRY) ? m_fds_retry :
+ (which_one == LIST_CLOSE) ? m_fds_close : m_fds_close;
+ if (add)
+ {
+#ifdef ENABLE_DETACH
+DEB( fprintf(stderr, "AddList; %5d: %s: %s\n", s, (which_one == LIST_CALLONCONNECT) ? "CallOnConnect" :
+ (which_one == LIST_DETACH) ? "Detach" :
+ (which_one == LIST_TIMEOUT) ? "Timeout" :
+ (which_one == LIST_RETRY) ? "Retry" :
+ (which_one == LIST_CLOSE) ? "Close" : "<undef>",
+ add ? "Add" : "Remove");)
+#else
+DEB( fprintf(stderr, "AddList; %5d: %s: %s\n", s, (which_one == LIST_CALLONCONNECT) ? "CallOnConnect" :
+ (which_one == LIST_TIMEOUT) ? "Timeout" :
+ (which_one == LIST_RETRY) ? "Retry" :
+ (which_one == LIST_CLOSE) ? "Close" : "<undef>",
+ add ? "Add" : "Remove");)
+#endif
+ }
+ if (add)
+ {
+ for (socket_v::iterator it = ref.begin(); it != ref.end(); it++)
+ {
+ if (*it == s) // already there
+ {
+ return;
+ }
+ }
+ ref.push_back(s);
+ return;
+ }
+ // remove
+ for (socket_v::iterator it = ref.begin(); it != ref.end(); it++)
+ {
+ if (*it == s)
+ {
+ ref.erase(it);
+ break;
+ }
+ }
+//DEB( fprintf(stderr, "/AddList\n");)
+}
+
+#ifdef ENABLE_TRIGGERS
+int SocketHandler::TriggerID(Socket *src)
+{
+ int id = m_next_trigger_id++;
+ m_trigger_src[id] = src;
+ return id;
+}
+
+bool SocketHandler::Subscribe(int id, Socket *dst)
+{
+ if (m_trigger_src.find(id) != m_trigger_src.end())
+ {
+ std::map<Socket *, bool>::iterator it = m_trigger_dst[id].find(dst);
+ if (it != m_trigger_dst[id].end())
+ {
+ m_trigger_dst[id][dst] = true;
+ return true;
+ }
+ LogError(dst, "Subscribe", id, "Already subscribed", LOG_LEVEL_INFO);
+ return false;
+ }
+ LogError(dst, "Subscribe", id, "Trigger id not found", LOG_LEVEL_INFO);
+ return false;
+}
+
+bool SocketHandler::Unsubscribe(int id, Socket *dst)
+{
+ if (m_trigger_src.find(id) != m_trigger_src.end())
+ {
+ std::map<Socket *, bool>::iterator it = m_trigger_dst[id].find(dst);
+ if (it != m_trigger_dst[id].end())
+ {
+ m_trigger_dst[id].erase(it);
+ return true;
+ }
+ LogError(dst, "Unsubscribe", id, "Not subscribed", LOG_LEVEL_INFO);
+ return false;
+ }
+ LogError(dst, "Unsubscribe", id, "Trigger id not found", LOG_LEVEL_INFO);
+ return false;
+}
+
+void SocketHandler::Trigger(int id, Socket::TriggerData& data, bool erase)
+{
+ if (m_trigger_src.find(id) != m_trigger_src.end())
+ {
+ data.SetSource( m_trigger_src[id] );
+ for (std::map<Socket *, bool>::iterator it = m_trigger_dst[id].begin(); it != m_trigger_dst[id].end(); it++)
+ {
+ Socket *dst = it -> first;
+ if (Valid(dst))
+ {
+ dst -> OnTrigger(id, data);
+ }
+ }
+ if (erase)
+ {
+ m_trigger_src.erase(m_trigger_src.find(id));
+ m_trigger_dst.erase(m_trigger_dst.find(id));
+ }
+ }
+ else
+ {
+ LogError(NULL, "Trigger", id, "Trigger id not found", LOG_LEVEL_INFO);
+ }
+}
+#endif // ENABLE_TRIGGERS
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/StdoutLog.cpp b/dep/sockets/StdoutLog.cpp
new file mode 100644
index 00000000000..e745a6d3358
--- /dev/null
+++ b/dep/sockets/StdoutLog.cpp
@@ -0,0 +1,98 @@
+/** \file StdoutLog.cpp
+ ** \date 2004-06-01
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include <stdio.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+
+#include <cstdio>
+
+#include "ISocketHandler.h"
+#include "Socket.h"
+#include "StdoutLog.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+
+void StdoutLog::error(ISocketHandler *,Socket *sock,const std::string& call,int err,const std::string& sys_err,loglevel_t lvl)
+{
+ time_t t = time(NULL);
+ struct tm tp;
+#ifdef _WIN32
+ memcpy(&tp, localtime(&t), sizeof(tp));
+#else
+ localtime_r(&t, &tp);
+#endif
+ std::string level;
+
+ switch (lvl)
+ {
+ case LOG_LEVEL_WARNING:
+ level = "Warning";
+ break;
+ case LOG_LEVEL_ERROR:
+ level = "Error";
+ break;
+ case LOG_LEVEL_FATAL:
+ level = "Fatal";
+ break;
+ case LOG_LEVEL_INFO:
+ level = "Info";
+ break;
+ }
+ if (sock)
+ {
+ printf("%d-%02d-%02d %02d:%02d:%02d :: fd %d :: %s: %d %s (%s)\n",
+ tp.tm_year + 1900,
+ tp.tm_mon + 1,
+ tp.tm_mday,
+ tp.tm_hour,tp.tm_min,tp.tm_sec,
+ sock -> GetSocket(),
+ call.c_str(),err,sys_err.c_str(),level.c_str());
+ }
+ else
+ {
+ printf("%d-%02d-%02d %02d:%02d:%02d :: %s: %d %s (%s)\n",
+ tp.tm_year + 1900,
+ tp.tm_mon + 1,
+ tp.tm_mday,
+ tp.tm_hour,tp.tm_min,tp.tm_sec,
+ call.c_str(),err,sys_err.c_str(),level.c_str());
+ }
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/StreamSocket.cpp b/dep/sockets/StreamSocket.cpp
new file mode 100644
index 00000000000..009abadad8f
--- /dev/null
+++ b/dep/sockets/StreamSocket.cpp
@@ -0,0 +1,145 @@
+#include "StreamSocket.h"
+#include "ISocketHandler.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+StreamSocket::StreamSocket(ISocketHandler& h) : Socket(h)
+,m_bConnecting(false)
+,m_connect_timeout(5)
+,m_flush_before_close(true)
+,m_connection_retry(0)
+,m_retries(0)
+,m_call_on_connect(false)
+,m_b_retry_connect(false)
+,m_line_protocol(false)
+,m_shutdown(0)
+{
+}
+
+StreamSocket::~StreamSocket()
+{
+}
+
+void StreamSocket::SetConnecting(bool x)
+{
+ if (x != m_bConnecting)
+ {
+ m_bConnecting = x;
+ if (x)
+ {
+ SetTimeout( GetConnectTimeout() );
+ }
+ else
+ {
+ SetTimeout( 0 );
+ }
+ }
+}
+
+bool StreamSocket::Connecting()
+{
+ return m_bConnecting;
+}
+
+bool StreamSocket::Ready()
+{
+ if (GetSocket() != INVALID_SOCKET && !Connecting() && !CloseAndDelete())
+ return true;
+ return false;
+}
+
+void StreamSocket::SetConnectTimeout(int x)
+{
+ m_connect_timeout = x;
+}
+
+int StreamSocket::GetConnectTimeout()
+{
+ return m_connect_timeout;
+}
+
+void StreamSocket::SetFlushBeforeClose(bool x)
+{
+ m_flush_before_close = x;
+}
+
+bool StreamSocket::GetFlushBeforeClose()
+{
+ return m_flush_before_close;
+}
+
+int StreamSocket::GetConnectionRetry()
+{
+ return m_connection_retry;
+}
+
+void StreamSocket::SetConnectionRetry(int x)
+{
+ m_connection_retry = x;
+}
+
+int StreamSocket::GetConnectionRetries()
+{
+ return m_retries;
+}
+
+void StreamSocket::IncreaseConnectionRetries()
+{
+ m_retries++;
+}
+
+void StreamSocket::ResetConnectionRetries()
+{
+ m_retries = 0;
+}
+
+void StreamSocket::SetCallOnConnect(bool x)
+{
+ Handler().AddList(GetSocket(), LIST_CALLONCONNECT, x);
+ m_call_on_connect = x;
+}
+
+bool StreamSocket::CallOnConnect()
+{
+ return m_call_on_connect;
+}
+
+void StreamSocket::SetRetryClientConnect(bool x)
+{
+ Handler().AddList(GetSocket(), LIST_RETRY, x);
+ m_b_retry_connect = x;
+}
+
+bool StreamSocket::RetryClientConnect()
+{
+ return m_b_retry_connect;
+}
+
+void StreamSocket::SetLineProtocol(bool x)
+{
+ m_line_protocol = x;
+}
+
+bool StreamSocket::LineProtocol()
+{
+ return m_line_protocol;
+}
+
+void StreamSocket::SetShutdown(int x)
+{
+ m_shutdown = x;
+}
+
+int StreamSocket::GetShutdown()
+{
+ return m_shutdown;
+}
+
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+
+
diff --git a/dep/sockets/TcpSocket.cpp b/dep/sockets/TcpSocket.cpp
new file mode 100644
index 00000000000..5f067b53124
--- /dev/null
+++ b/dep/sockets/TcpSocket.cpp
@@ -0,0 +1,1681 @@
+/** \file TcpSocket.cpp
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifdef _WIN32
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+#include <stdlib.h>
+#else
+#include <errno.h>
+#endif
+#include "ISocketHandler.h"
+#include <fcntl.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#ifdef HAVE_OPENSSL
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#endif
+#include <map>
+#include <cstdio>
+
+#include "TcpSocket.h"
+#include "Utility.h"
+#include "Ipv4Address.h"
+#include "Ipv6Address.h"
+#include "Mutex.h"
+#include "IFile.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+//#ifdef _DEBUG
+//#define DEB(x) x
+//#else
+#define DEB(x)
+//#endif
+
+// statics
+#ifdef HAVE_OPENSSL
+SSLInitializer TcpSocket::m_ssl_init;
+#endif
+
+// thanks, q
+#ifdef _MSC_VER
+#pragma warning(disable:4355)
+#endif
+TcpSocket::TcpSocket(ISocketHandler& h) : StreamSocket(h)
+,ibuf(TCP_BUFSIZE_READ)
+,m_b_input_buffer_disabled(false)
+,m_bytes_sent(0)
+,m_bytes_received(0)
+,m_skip_c(false)
+#ifdef SOCKETS_DYNAMIC_TEMP
+,m_buf(new char[TCP_BUFSIZE_READ + 1])
+#endif
+,m_obuf_top(NULL)
+,m_transfer_limit(0)
+,m_output_length(0)
+#ifdef HAVE_OPENSSL
+,m_ssl_ctx(NULL)
+,m_ssl(NULL)
+,m_sbio(NULL)
+#endif
+#ifdef ENABLE_SOCKS4
+,m_socks4_state(0)
+#endif
+#ifdef ENABLE_RESOLVER
+,m_resolver_id(0)
+#endif
+#ifdef ENABLE_RECONNECT
+,m_b_reconnect(false)
+,m_b_is_reconnect(false)
+#endif
+{
+}
+#ifdef _MSC_VER
+#pragma warning(default:4355)
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(disable:4355)
+#endif
+TcpSocket::TcpSocket(ISocketHandler& h,size_t isize,size_t osize) : StreamSocket(h)
+,ibuf(isize)
+,m_b_input_buffer_disabled(false)
+,m_bytes_sent(0)
+,m_bytes_received(0)
+,m_skip_c(false)
+#ifdef SOCKETS_DYNAMIC_TEMP
+,m_buf(new char[TCP_BUFSIZE_READ + 1])
+#endif
+,m_obuf_top(NULL)
+,m_transfer_limit(0)
+,m_output_length(0)
+#ifdef HAVE_OPENSSL
+,m_ssl_ctx(NULL)
+,m_ssl(NULL)
+,m_sbio(NULL)
+#endif
+#ifdef ENABLE_SOCKS4
+,m_socks4_state(0)
+#endif
+#ifdef ENABLE_RESOLVER
+,m_resolver_id(0)
+#endif
+#ifdef ENABLE_RECONNECT
+,m_b_reconnect(false)
+,m_b_is_reconnect(false)
+#endif
+{
+}
+#ifdef _MSC_VER
+#pragma warning(default:4355)
+#endif
+
+TcpSocket::~TcpSocket()
+{
+#ifdef SOCKETS_DYNAMIC_TEMP
+ delete[] m_buf;
+#endif
+ // %! empty m_obuf
+ while (m_obuf.size())
+ {
+ output_l::iterator it = m_obuf.begin();
+ OUTPUT *p = *it;
+ delete p;
+ m_obuf.erase(it);
+ }
+#ifdef HAVE_OPENSSL
+ if (m_ssl)
+ {
+ SSL_free(m_ssl);
+ }
+#endif
+}
+
+bool TcpSocket::Open(ipaddr_t ip,port_t port,bool skip_socks)
+{
+ Ipv4Address ad(ip, port);
+ Ipv4Address local;
+ return Open(ad, local, skip_socks);
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+bool TcpSocket::Open(in6_addr ip,port_t port,bool skip_socks)
+{
+ Ipv6Address ad(ip, port);
+ return Open(ad, skip_socks);
+}
+#endif
+#endif
+
+bool TcpSocket::Open(SocketAddress& ad,bool skip_socks)
+{
+ Ipv4Address bind_ad("0.0.0.0", 0);
+ return Open(ad, bind_ad, skip_socks);
+}
+
+bool TcpSocket::Open(SocketAddress& ad,SocketAddress& bind_ad,bool skip_socks)
+{
+ if (!ad.IsValid())
+ {
+ Handler().LogError(this, "Open", 0, "Invalid SocketAddress", LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ return false;
+ }
+ if (Handler().GetCount() >= FD_SETSIZE)
+ {
+ Handler().LogError(this, "Open", 0, "no space left in fd_set", LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ return false;
+ }
+ SetConnecting(false);
+#ifdef ENABLE_SOCKS4
+ SetSocks4(false);
+#endif
+ // check for pooling
+#ifdef ENABLE_POOL
+ if (Handler().PoolEnabled())
+ {
+ ISocketHandler::PoolSocket *pools = Handler().FindConnection(SOCK_STREAM, "tcp", ad);
+ if (pools)
+ {
+ CopyConnection( pools );
+ delete pools;
+
+ SetIsClient();
+ SetCallOnConnect(); // ISocketHandler must call OnConnect
+ Handler().LogError(this, "SetCallOnConnect", 0, "Found pooled connection", LOG_LEVEL_INFO);
+ return true;
+ }
+ }
+#endif
+ // if not, create new connection
+ SOCKET s = CreateSocket(ad.GetFamily(), SOCK_STREAM, "tcp");
+ if (s == INVALID_SOCKET)
+ {
+ return false;
+ }
+ // socket must be nonblocking for async connect
+ if (!SetNonblocking(true, s))
+ {
+ SetCloseAndDelete();
+ closesocket(s);
+ return false;
+ }
+#ifdef ENABLE_POOL
+ SetIsClient(); // client because we connect
+#endif
+ SetClientRemoteAddress(ad);
+ int n = 0;
+ if (bind_ad.GetPort() != 0)
+ {
+ bind(s, bind_ad, bind_ad);
+ }
+#ifdef ENABLE_SOCKS4
+ if (!skip_socks && GetSocks4Host() && GetSocks4Port())
+ {
+ Ipv4Address sa(GetSocks4Host(), GetSocks4Port());
+ {
+ std::string sockshost;
+ Utility::l2ip(GetSocks4Host(), sockshost);
+ Handler().LogError(this, "Open", 0, "Connecting to socks4 server @ " + sockshost + ":" +
+ Utility::l2string(GetSocks4Port()), LOG_LEVEL_INFO);
+ }
+ SetSocks4();
+ n = connect(s, sa, sa);
+ SetRemoteAddress(sa);
+ }
+ else
+#endif
+ {
+ n = connect(s, ad, ad);
+ SetRemoteAddress(ad);
+ }
+ if (n == -1)
+ {
+ // check error code that means a connect is in progress
+#ifdef _WIN32
+ if (Errno == WSAEWOULDBLOCK)
+#else
+ if (Errno == EINPROGRESS)
+#endif
+ {
+ Attach(s);
+ SetConnecting( true ); // this flag will control fd_set's
+ }
+ else
+#ifdef ENABLE_SOCKS4
+ if (Socks4() && Handler().Socks4TryDirect() ) // retry
+ {
+ closesocket(s);
+ return Open(ad, true);
+ }
+ else
+#endif
+#ifdef ENABLE_RECONNECT
+ if (Reconnect())
+ {
+ Handler().LogError(this, "connect: failed, reconnect pending", Errno, StrError(Errno), LOG_LEVEL_INFO);
+ Attach(s);
+ SetConnecting( true ); // this flag will control fd_set's
+ }
+ else
+#endif
+ {
+ Handler().LogError(this, "connect: failed", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ closesocket(s);
+ return false;
+ }
+ }
+ else
+ {
+ Attach(s);
+ SetCallOnConnect(); // ISocketHandler must call OnConnect
+ }
+
+ // 'true' means connected or connecting(not yet connected)
+ // 'false' means something failed
+ return true; //!Connecting();
+}
+
+bool TcpSocket::Open(const std::string &host,port_t port)
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+#ifdef ENABLE_RESOLVER
+ if (!Handler().ResolverEnabled() || Utility::isipv6(host) )
+ {
+#endif
+ in6_addr a;
+ if (!Utility::u2ip(host, a))
+ {
+ SetCloseAndDelete();
+ return false;
+ }
+ Ipv6Address ad(a, port);
+ Ipv6Address local;
+ return Open(ad, local);
+#ifdef ENABLE_RESOLVER
+ }
+ m_resolver_id = Resolve6(host, port);
+ return true;
+#endif
+ }
+#endif
+#endif
+#ifdef ENABLE_RESOLVER
+ if (!Handler().ResolverEnabled() || Utility::isipv4(host) )
+ {
+#endif
+ ipaddr_t l;
+ if (!Utility::u2ip(host,l))
+ {
+ SetCloseAndDelete();
+ return false;
+ }
+ Ipv4Address ad(l, port);
+ Ipv4Address local;
+ return Open(ad, local);
+#ifdef ENABLE_RESOLVER
+ }
+ // resolve using async resolver thread
+ m_resolver_id = Resolve(host, port);
+ return true;
+#endif
+}
+
+#ifdef ENABLE_RESOLVER
+void TcpSocket::OnResolved(int id,ipaddr_t a,port_t port)
+{
+DEB( fprintf(stderr, "TcpSocket::OnResolved id %d addr %x port %d\n", id, a, port);)
+ if (id == m_resolver_id)
+ {
+ if (a && port)
+ {
+ Ipv4Address ad(a, port);
+ Ipv4Address local;
+ if (Open(ad, local))
+ {
+ if (!Handler().Valid(this))
+ {
+ Handler().Add(this);
+ }
+ }
+ }
+ else
+ {
+ Handler().LogError(this, "OnResolved", 0, "Resolver failed", LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ }
+ }
+ else
+ {
+ Handler().LogError(this, "OnResolved", id, "Resolver returned wrong job id", LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ }
+}
+
+#ifdef ENABLE_IPV6
+void TcpSocket::OnResolved(int id,in6_addr& a,port_t port)
+{
+ if (id == m_resolver_id)
+ {
+ Ipv6Address ad(a, port);
+ if (ad.IsValid())
+ {
+ Ipv6Address local;
+ if (Open(ad, local))
+ {
+ if (!Handler().Valid(this))
+ {
+ Handler().Add(this);
+ }
+ }
+ }
+ }
+ else
+ {
+ Handler().LogError(this, "OnResolved", id, "Resolver returned wrong job id", LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ }
+}
+#endif
+#endif
+
+void TcpSocket::OnRead()
+{
+ int n = 0;
+#ifdef SOCKETS_DYNAMIC_TEMP
+ char *buf = m_buf;
+#else
+ char buf[TCP_BUFSIZE_READ];
+#endif
+#ifdef HAVE_OPENSSL
+ if (IsSSL())
+ {
+ if (!Ready())
+ return;
+ n = SSL_read(m_ssl, buf, TCP_BUFSIZE_READ);
+ if (n == -1)
+ {
+ n = SSL_get_error(m_ssl, n);
+ switch (n)
+ {
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+DEB( fprintf(stderr, "SSL_read() returns zero - closing socket\n");)
+ OnDisconnect();
+ SetCloseAndDelete(true);
+ SetFlushBeforeClose(false);
+ SetLost();
+ break;
+ default:
+DEB( fprintf(stderr, "SSL read problem, errcode = %d\n",n);)
+ OnDisconnect();
+ SetCloseAndDelete(true);
+ SetFlushBeforeClose(false);
+ SetLost();
+ }
+ return;
+ }
+ else
+ if (!n)
+ {
+ OnDisconnect();
+ SetCloseAndDelete(true);
+ SetFlushBeforeClose(false);
+ SetLost();
+ SetShutdown(SHUT_WR);
+ return;
+ }
+ else
+ if (n > 0 && n <= TCP_BUFSIZE_READ)
+ {
+ m_bytes_received += n;
+ if (GetTrafficMonitor())
+ {
+ GetTrafficMonitor() -> fwrite(buf, 1, n);
+ }
+ if (!m_b_input_buffer_disabled && !ibuf.Write(buf,n))
+ {
+ Handler().LogError(this, "OnRead(ssl)", 0, "ibuf overflow", LOG_LEVEL_WARNING);
+ }
+ }
+ else
+ {
+ Handler().LogError(this, "OnRead(ssl)", n, "abnormal value from SSL_read", LOG_LEVEL_ERROR);
+ }
+ }
+ else
+#endif // HAVE_OPENSSL
+ {
+ n = recv(GetSocket(), buf, TCP_BUFSIZE_READ, MSG_NOSIGNAL);
+ if (n == -1)
+ {
+ Handler().LogError(this, "read", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ OnDisconnect();
+ SetCloseAndDelete(true);
+ SetFlushBeforeClose(false);
+ SetLost();
+ return;
+ }
+ else
+ if (!n)
+ {
+ OnDisconnect();
+ SetCloseAndDelete(true);
+ SetFlushBeforeClose(false);
+ SetLost();
+ SetShutdown(SHUT_WR);
+ return;
+ }
+ else
+ if (n > 0 && n <= TCP_BUFSIZE_READ)
+ {
+ m_bytes_received += n;
+ if (GetTrafficMonitor())
+ {
+ GetTrafficMonitor() -> fwrite(buf, 1, n);
+ }
+ if (!m_b_input_buffer_disabled && !ibuf.Write(buf,n))
+ {
+ Handler().LogError(this, "OnRead", 0, "ibuf overflow", LOG_LEVEL_WARNING);
+ }
+ }
+ else
+ {
+ Handler().LogError(this, "OnRead", n, "abnormal value from recv", LOG_LEVEL_ERROR);
+ }
+ }
+ //
+ OnRead( buf, n );
+}
+
+void TcpSocket::OnRead( char *buf, size_t n )
+{
+ // unbuffered
+ if (n > 0 && n <= TCP_BUFSIZE_READ)
+ {
+ if (LineProtocol())
+ {
+ buf[n] = 0;
+ size_t i = 0;
+ if (m_skip_c && (buf[i] == 13 || buf[i] == 10) && buf[i] != m_c)
+ {
+ m_skip_c = false;
+ i++;
+ }
+ size_t x = i;
+ for (; i < n && LineProtocol(); i++)
+ {
+ while ((buf[i] == 13 || buf[i] == 10) && LineProtocol())
+ {
+ char c = buf[i];
+ buf[i] = 0;
+ if (buf[x])
+ {
+ m_line += (buf + x);
+ }
+ OnLine( m_line );
+ i++;
+ m_skip_c = true;
+ m_c = c;
+ if (i < n && (buf[i] == 13 || buf[i] == 10) && buf[i] != c)
+ {
+ m_skip_c = false;
+ i++;
+ }
+ x = i;
+ m_line = "";
+ }
+ if (!LineProtocol())
+ {
+ break;
+ }
+ }
+ if (!LineProtocol())
+ {
+ if (i < n)
+ {
+ OnRawData(buf + i, n - i);
+ }
+ }
+ else
+ if (buf[x])
+ {
+ m_line += (buf + x);
+ }
+ }
+ else
+ {
+ OnRawData(buf, n);
+ }
+ }
+ if (m_b_input_buffer_disabled)
+ {
+ return;
+ }
+ // further processing: socks4
+#ifdef ENABLE_SOCKS4
+ if (Socks4())
+ {
+ bool need_more = false;
+ while (GetInputLength() && !need_more && !CloseAndDelete())
+ {
+ need_more = OnSocks4Read();
+ }
+ }
+#endif
+}
+
+void TcpSocket::OnWriteComplete()
+{
+}
+
+void TcpSocket::OnWrite()
+{
+ if (Connecting())
+ {
+ int err = SoError();
+
+ // don't reset connecting flag on error here, we want the OnConnectFailed timeout later on
+ if (!err) // ok
+ {
+ Set(!IsDisableRead(), false);
+ SetConnecting(false);
+ SetCallOnConnect();
+ return;
+ }
+ Handler().LogError(this, "tcp: connect failed", err, StrError(err), LOG_LEVEL_FATAL);
+ Set(false, false); // no more monitoring because connection failed
+
+ // failed
+#ifdef ENABLE_SOCKS4
+ if (Socks4())
+ {
+ // %! leave 'Connecting' flag set?
+ OnSocks4ConnectFailed();
+ return;
+ }
+#endif
+ if (GetConnectionRetry() == -1 ||
+ (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
+ {
+ // even though the connection failed at once, only retry after
+ // the connection timeout.
+ // should we even try to connect again, when CheckConnect returns
+ // false it's because of a connection error - not a timeout...
+ return;
+ }
+ SetConnecting(false);
+ SetCloseAndDelete( true );
+ /// \todo state reason why connect failed
+ OnConnectFailed();
+ return;
+ }
+ // try send next block in buffer
+ // if full block is sent, repeat
+ // if all blocks are sent, reset m_wfds
+
+ bool repeat = false;
+ size_t sz = m_transfer_limit ? GetOutputLength() : 0;
+ do
+ {
+ output_l::iterator it = m_obuf.begin();
+ OUTPUT *p = *it;
+ repeat = false;
+ int n = TryWrite(p -> Buf(), p -> Len());
+ if (n > 0)
+ {
+ size_t left = p -> Remove(n);
+ m_output_length -= n;
+ if (!left)
+ {
+ delete p;
+ m_obuf.erase(it);
+ if (!m_obuf.size())
+ {
+ m_obuf_top = NULL;
+ OnWriteComplete();
+ }
+ else
+ {
+ repeat = true;
+ }
+ }
+ }
+ } while (repeat);
+
+ if (m_transfer_limit && sz > m_transfer_limit && GetOutputLength() < m_transfer_limit)
+ {
+ OnTransferLimit();
+ }
+
+ // check output buffer set, set/reset m_wfds accordingly
+ {
+ bool br;
+ bool bw;
+ bool bx;
+ Handler().Get(GetSocket(), br, bw, bx);
+ if (m_obuf.size())
+ Set(br, true);
+ else
+ Set(br, false);
+ }
+}
+
+int TcpSocket::TryWrite(const char *buf, size_t len)
+{
+ int n = 0;
+#ifdef HAVE_OPENSSL
+ if (IsSSL())
+ {
+ n = SSL_write(m_ssl, buf, (int)len);
+ if (n == -1)
+ {
+ int errnr = SSL_get_error(m_ssl, n);
+ if ( errnr != SSL_ERROR_WANT_READ && errnr != SSL_ERROR_WANT_WRITE )
+ {
+ OnDisconnect();
+ SetCloseAndDelete(true);
+ SetFlushBeforeClose(false);
+ SetLost();
+ const char *errbuf = ERR_error_string(errnr, NULL);
+ Handler().LogError(this, "OnWrite/SSL_write", errnr, errbuf, LOG_LEVEL_FATAL);
+ }
+ return 0;
+ }
+ else
+ if (!n)
+ {
+ OnDisconnect();
+ SetCloseAndDelete(true);
+ SetFlushBeforeClose(false);
+ SetLost();
+DEB( int errnr = SSL_get_error(m_ssl, n);
+ const char *errbuf = ERR_error_string(errnr, NULL);
+ fprintf(stderr, "SSL_write() returns 0: %d : %s\n",errnr, errbuf);)
+ }
+ }
+ else
+#endif // HAVE_OPENSSL
+ {
+ n = send(GetSocket(), buf, (int)len, MSG_NOSIGNAL);
+ if (n == -1)
+ {
+ // normal error codes:
+ // WSAEWOULDBLOCK
+ // EAGAIN or EWOULDBLOCK
+#ifdef _WIN32
+ if (Errno != WSAEWOULDBLOCK)
+#else
+ if (Errno != EWOULDBLOCK)
+#endif
+ {
+ Handler().LogError(this, "send", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ OnDisconnect();
+ SetCloseAndDelete(true);
+ SetFlushBeforeClose(false);
+ SetLost();
+ }
+ return 0;
+ }
+ }
+ if (n > 0)
+ {
+ m_bytes_sent += n;
+ if (GetTrafficMonitor())
+ {
+ GetTrafficMonitor() -> fwrite(buf, 1, n);
+ }
+ }
+ return n;
+}
+
+void TcpSocket::Buffer(const char *buf, size_t len)
+{
+ size_t ptr = 0;
+ m_output_length += len;
+ while (ptr < len)
+ {
+ // buf/len => pbuf/sz
+ size_t space = 0;
+ if (m_obuf_top && (space = m_obuf_top -> Space()) > 0)
+ {
+ const char *pbuf = buf + ptr;
+ size_t sz = len - ptr;
+ if (space >= sz)
+ {
+ m_obuf_top -> Add(pbuf, sz);
+ ptr += sz;
+ }
+ else
+ {
+ m_obuf_top -> Add(pbuf, space);
+ ptr += space;
+ }
+ }
+ else
+ {
+ m_obuf_top = new OUTPUT;
+ m_obuf.push_back( m_obuf_top );
+ }
+ }
+}
+
+void TcpSocket::Send(const std::string &str,int i)
+{
+ SendBuf(str.c_str(),str.size(),i);
+}
+
+void TcpSocket::SendBuf(const char *buf,size_t len,int)
+{
+ if (!Ready() && !Connecting())
+ {
+ Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-ready socket" ); // warning
+ if (GetSocket() == INVALID_SOCKET)
+ Handler().LogError(this, "SendBuf", 0, " * GetSocket() == INVALID_SOCKET", LOG_LEVEL_INFO);
+ if (Connecting())
+ Handler().LogError(this, "SendBuf", 0, " * Connecting()", LOG_LEVEL_INFO);
+ if (CloseAndDelete())
+ Handler().LogError(this, "SendBuf", 0, " * CloseAndDelete()", LOG_LEVEL_INFO);
+ return;
+ }
+ if (!IsConnected())
+ {
+ Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-connected socket, will be sent on connect" ); // warning
+ Buffer(buf, len);
+ return;
+ }
+ if (m_obuf_top)
+ {
+ Buffer(buf, len);
+ return;
+ }
+ int n = TryWrite(buf, len);
+ if (n >= 0 && n < (int)len)
+ {
+ Buffer(buf + n, len - n);
+ }
+ // if ( data in buffer || !IsConnected )
+ // {
+ // add to buffer
+ // }
+ // else
+ // try_send
+ // if any data is unsent, buffer it and set m_wfds
+
+ // check output buffer set, set/reset m_wfds accordingly
+ {
+ bool br;
+ bool bw;
+ bool bx;
+ Handler().Get(GetSocket(), br, bw, bx);
+ if (m_obuf.size())
+ Set(br, true);
+ else
+ Set(br, false);
+ }
+}
+
+void TcpSocket::OnLine(const std::string& )
+{
+}
+
+#ifdef _MSC_VER
+#pragma warning(disable:4355)
+#endif
+TcpSocket::TcpSocket(const TcpSocket& s)
+:StreamSocket(s)
+,ibuf(0)
+{
+}
+#ifdef _MSC_VER
+#pragma warning(default:4355)
+#endif
+
+#ifdef ENABLE_SOCKS4
+void TcpSocket::OnSocks4Connect()
+{
+ char request[1000];
+ memset(request, 0, sizeof(request));
+ request[0] = 4; // socks v4
+ request[1] = 1; // command code: CONNECT
+ {
+ std::auto_ptr<SocketAddress> ad = GetClientRemoteAddress();
+ if (ad.get())
+ {
+ struct sockaddr *p0 = (struct sockaddr *)*ad;
+ struct sockaddr_in *p = (struct sockaddr_in *)p0;
+ if (p -> sin_family == AF_INET)
+ {
+ memcpy(request + 2, &p -> sin_port, 2); // nwbo is ok here
+ memcpy(request + 4, &p -> sin_addr, sizeof(struct in_addr));
+ }
+ else
+ {
+ /// \todo warn
+ }
+ }
+ else
+ {
+ /// \todo warn
+ }
+ }
+ strcpy(request + 8, GetSocks4Userid().c_str());
+ size_t length = GetSocks4Userid().size() + 8 + 1;
+ SendBuf(request, length);
+ m_socks4_state = 0;
+}
+
+void TcpSocket::OnSocks4ConnectFailed()
+{
+ Handler().LogError(this,"OnSocks4ConnectFailed",0,"connection to socks4 server failed, trying direct connection",LOG_LEVEL_WARNING);
+ if (!Handler().Socks4TryDirect())
+ {
+ SetConnecting(false);
+ SetCloseAndDelete();
+ OnConnectFailed(); // just in case
+ }
+ else
+ {
+ SetRetryClientConnect();
+ }
+}
+
+bool TcpSocket::OnSocks4Read()
+{
+ switch (m_socks4_state)
+ {
+ case 0:
+ ibuf.Read(&m_socks4_vn, 1);
+ m_socks4_state = 1;
+ break;
+ case 1:
+ ibuf.Read(&m_socks4_cd, 1);
+ m_socks4_state = 2;
+ break;
+ case 2:
+ if (GetInputLength() > 1)
+ {
+ ibuf.Read( (char *)&m_socks4_dstport, 2);
+ m_socks4_state = 3;
+ }
+ else
+ {
+ return true;
+ }
+ break;
+ case 3:
+ if (GetInputLength() > 3)
+ {
+ ibuf.Read( (char *)&m_socks4_dstip, 4);
+ SetSocks4(false);
+
+ switch (m_socks4_cd)
+ {
+ case 90:
+ OnConnect();
+ Handler().LogError(this, "OnSocks4Read", 0, "Connection established", LOG_LEVEL_INFO);
+ break;
+ case 91:
+ case 92:
+ case 93:
+ Handler().LogError(this,"OnSocks4Read",m_socks4_cd,"socks4 server reports connect failed",LOG_LEVEL_FATAL);
+ SetConnecting(false);
+ SetCloseAndDelete();
+ OnConnectFailed();
+ break;
+ default:
+ Handler().LogError(this,"OnSocks4Read",m_socks4_cd,"socks4 server unrecognized response",LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ break;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+#endif
+
+void TcpSocket::Sendf(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char slask[5000]; // vsprintf / vsnprintf temporary
+#ifdef _WIN32
+ vsprintf(slask, format, ap);
+#else
+ vsnprintf(slask, 5000, format, ap);
+#endif
+ va_end(ap);
+ Send( slask );
+}
+
+#ifdef HAVE_OPENSSL
+void TcpSocket::OnSSLConnect()
+{
+ SetNonblocking(true);
+ {
+ if (m_ssl_ctx)
+ {
+DEB( fprintf(stderr, "SSL Context already initialized - closing socket\n");)
+ SetCloseAndDelete(true);
+ return;
+ }
+ InitSSLClient();
+ }
+ if (m_ssl_ctx)
+ {
+ /* Connect the SSL socket */
+ m_ssl = SSL_new(m_ssl_ctx);
+ if (!m_ssl)
+ {
+DEB( fprintf(stderr, " m_ssl is NULL\n");)
+ SetCloseAndDelete(true);
+ return;
+ }
+ SSL_set_mode(m_ssl, SSL_MODE_AUTO_RETRY);
+ m_sbio = BIO_new_socket((int)GetSocket(), BIO_NOCLOSE);
+ if (!m_sbio)
+ {
+DEB( fprintf(stderr, " m_sbio is NULL\n");)
+ SetCloseAndDelete(true);
+ return;
+ }
+ SSL_set_bio(m_ssl, m_sbio, m_sbio);
+ if (!SSLNegotiate())
+ {
+ SetSSLNegotiate();
+ }
+ }
+ else
+ {
+ SetCloseAndDelete();
+ }
+}
+
+void TcpSocket::OnSSLAccept()
+{
+ SetNonblocking(true);
+ {
+ if (m_ssl_ctx)
+ {
+DEB( fprintf(stderr, "SSL Context already initialized - closing socket\n");)
+ SetCloseAndDelete(true);
+ return;
+ }
+ InitSSLServer();
+ SetSSLServer();
+ }
+ if (m_ssl_ctx)
+ {
+ m_ssl = SSL_new(m_ssl_ctx);
+ if (!m_ssl)
+ {
+DEB( fprintf(stderr, " m_ssl is NULL\n");)
+ SetCloseAndDelete(true);
+ return;
+ }
+ SSL_set_mode(m_ssl, SSL_MODE_AUTO_RETRY);
+ m_sbio = BIO_new_socket((int)GetSocket(), BIO_NOCLOSE);
+ if (!m_sbio)
+ {
+DEB( fprintf(stderr, " m_sbio is NULL\n");)
+ SetCloseAndDelete(true);
+ return;
+ }
+ SSL_set_bio(m_ssl, m_sbio, m_sbio);
+// if (!SSLNegotiate())
+ {
+ SetSSLNegotiate();
+ }
+ }
+}
+
+bool TcpSocket::SSLNegotiate()
+{
+ if (!IsSSLServer()) // client
+ {
+ int r = SSL_connect(m_ssl);
+ if (r > 0)
+ {
+ SetSSLNegotiate(false);
+ /// \todo: resurrect certificate check... client
+// CheckCertificateChain( "");//ServerHOST);
+ SetNonblocking(false);
+ //
+ {
+ SetConnected();
+ if (GetOutputLength())
+ {
+ OnWrite();
+ }
+ }
+#ifdef ENABLE_RECONNECT
+ if (IsReconnect())
+ OnReconnect();
+ else
+#endif
+ {
+ OnConnect();
+ }
+ Handler().LogError(this, "SSLNegotiate/SSL_connect", 0, "Connection established", LOG_LEVEL_INFO);
+ return true;
+ }
+ else
+ if (!r)
+ {
+ Handler().LogError(this, "SSLNegotiate/SSL_connect", 0, "Connection failed", LOG_LEVEL_INFO);
+ SetSSLNegotiate(false);
+ SetCloseAndDelete();
+ OnSSLConnectFailed();
+ }
+ else
+ {
+ r = SSL_get_error(m_ssl, r);
+ if (r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE)
+ {
+ Handler().LogError(this, "SSLNegotiate/SSL_connect", -1, "Connection failed", LOG_LEVEL_INFO);
+DEB( fprintf(stderr, "SSL_connect() failed - closing socket, return code: %d\n",r);)
+ SetSSLNegotiate(false);
+ SetCloseAndDelete(true);
+ OnSSLConnectFailed();
+ }
+ }
+ }
+ else // server
+ {
+ int r = SSL_accept(m_ssl);
+ if (r > 0)
+ {
+ SetSSLNegotiate(false);
+ /// \todo: resurrect certificate check... server
+// CheckCertificateChain( "");//ClientHOST);
+ SetNonblocking(false);
+ //
+ {
+ SetConnected();
+ if (GetOutputLength())
+ {
+ OnWrite();
+ }
+ }
+ OnAccept();
+ Handler().LogError(this, "SSLNegotiate/SSL_accept", 0, "Connection established", LOG_LEVEL_INFO);
+ return true;
+ }
+ else
+ if (!r)
+ {
+ Handler().LogError(this, "SSLNegotiate/SSL_accept", 0, "Connection failed", LOG_LEVEL_INFO);
+ SetSSLNegotiate(false);
+ SetCloseAndDelete();
+ OnSSLAcceptFailed();
+ }
+ else
+ {
+ r = SSL_get_error(m_ssl, r);
+ if (r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE)
+ {
+ Handler().LogError(this, "SSLNegotiate/SSL_accept", -1, "Connection failed", LOG_LEVEL_INFO);
+DEB( fprintf(stderr, "SSL_accept() failed - closing socket, return code: %d\n",r);)
+ SetSSLNegotiate(false);
+ SetCloseAndDelete(true);
+ OnSSLAcceptFailed();
+ }
+ }
+ }
+ return false;
+}
+
+void TcpSocket::InitSSLClient()
+{
+ InitializeContext("", SSLv23_method());
+}
+
+void TcpSocket::InitSSLServer()
+{
+ Handler().LogError(this, "InitSSLServer", 0, "You MUST implement your own InitSSLServer method", LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+}
+
+void TcpSocket::InitializeContext(const std::string& context, SSL_METHOD *meth_in)
+{
+ /* Create our context*/
+ static std::map<std::string, SSL_CTX *> client_contexts;
+ if (client_contexts.find(context) == client_contexts.end())
+ {
+ SSL_METHOD *meth = meth_in ? meth_in : SSLv3_method();
+ m_ssl_ctx = client_contexts[context] = SSL_CTX_new(meth);
+ SSL_CTX_set_mode(m_ssl_ctx, SSL_MODE_AUTO_RETRY);
+ }
+ else
+ {
+ m_ssl_ctx = client_contexts[context];
+ }
+}
+
+void TcpSocket::InitializeContext(const std::string& context,const std::string& keyfile,const std::string& password,SSL_METHOD *meth_in)
+{
+ /* Create our context*/
+ static std::map<std::string, SSL_CTX *> server_contexts;
+ if (server_contexts.find(context) == server_contexts.end())
+ {
+ SSL_METHOD *meth = meth_in ? meth_in : SSLv3_method();
+ m_ssl_ctx = server_contexts[context] = SSL_CTX_new(meth);
+ SSL_CTX_set_mode(m_ssl_ctx, SSL_MODE_AUTO_RETRY);
+ // session id
+ if (!context.empty())
+ SSL_CTX_set_session_id_context(m_ssl_ctx, (const unsigned char *)context.c_str(), (unsigned int)context.size());
+ else
+ SSL_CTX_set_session_id_context(m_ssl_ctx, (const unsigned char *)"--empty--", 9);
+ }
+ else
+ {
+ m_ssl_ctx = server_contexts[context];
+ }
+
+ /* Load our keys and certificates*/
+ if (!(SSL_CTX_use_certificate_file(m_ssl_ctx, keyfile.c_str(), SSL_FILETYPE_PEM)))
+ {
+ Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read certificate file " + keyfile, LOG_LEVEL_FATAL);
+ }
+
+ m_password = password;
+ SSL_CTX_set_default_passwd_cb(m_ssl_ctx, SSL_password_cb);
+ SSL_CTX_set_default_passwd_cb_userdata(m_ssl_ctx, this);
+ if (!(SSL_CTX_use_PrivateKey_file(m_ssl_ctx, keyfile.c_str(), SSL_FILETYPE_PEM)))
+ {
+ Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read private key file " + keyfile, LOG_LEVEL_FATAL);
+ }
+}
+
+void TcpSocket::InitializeContext(const std::string& context,const std::string& certfile,const std::string& keyfile,const std::string& password,SSL_METHOD *meth_in)
+{
+ /* Create our context*/
+ static std::map<std::string, SSL_CTX *> server_contexts;
+ if (server_contexts.find(context) == server_contexts.end())
+ {
+ SSL_METHOD *meth = meth_in ? meth_in : SSLv3_method();
+ m_ssl_ctx = server_contexts[context] = SSL_CTX_new(meth);
+ SSL_CTX_set_mode(m_ssl_ctx, SSL_MODE_AUTO_RETRY);
+ // session id
+ if (context.size())
+ SSL_CTX_set_session_id_context(m_ssl_ctx, (const unsigned char *)context.c_str(), (unsigned int)context.size());
+ else
+ SSL_CTX_set_session_id_context(m_ssl_ctx, (const unsigned char *)"--empty--", 9);
+ }
+ else
+ {
+ m_ssl_ctx = server_contexts[context];
+ }
+
+ /* Load our keys and certificates*/
+ if (!(SSL_CTX_use_certificate_file(m_ssl_ctx, certfile.c_str(), SSL_FILETYPE_PEM)))
+ {
+ Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read certificate file " + keyfile, LOG_LEVEL_FATAL);
+ }
+
+ m_password = password;
+ SSL_CTX_set_default_passwd_cb(m_ssl_ctx, SSL_password_cb);
+ SSL_CTX_set_default_passwd_cb_userdata(m_ssl_ctx, this);
+ if (!(SSL_CTX_use_PrivateKey_file(m_ssl_ctx, keyfile.c_str(), SSL_FILETYPE_PEM)))
+ {
+ Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read private key file " + keyfile, LOG_LEVEL_FATAL);
+ }
+}
+
+int TcpSocket::SSL_password_cb(char *buf,int num,int rwflag,void *userdata)
+{
+ Socket *p0 = static_cast<Socket *>(userdata);
+ TcpSocket *p = dynamic_cast<TcpSocket *>(p0);
+ std::string pw = p ? p -> GetPassword() : "";
+ if ( (size_t)num < pw.size() + 1)
+ {
+ return 0;
+ }
+ strcpy(buf,pw.c_str());
+ return (int)pw.size();
+}
+#endif // HAVE_OPENSSL
+
+int TcpSocket::Close()
+{
+ if (GetSocket() == INVALID_SOCKET) // this could happen
+ {
+ Handler().LogError(this, "Socket::Close", 0, "file descriptor invalid", LOG_LEVEL_WARNING);
+ return 0;
+ }
+ int n;
+ SetNonblocking(true);
+ if (!Lost() && IsConnected() && !(GetShutdown() & SHUT_WR))
+ {
+ if (shutdown(GetSocket(), SHUT_WR) == -1)
+ {
+ // failed...
+ Handler().LogError(this, "shutdown", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+ }
+ //
+ char tmp[1000];
+ if (!Lost() && (n = recv(GetSocket(),tmp,1000,0)) >= 0)
+ {
+ if (n)
+ {
+ Handler().LogError(this, "read() after shutdown", n, "bytes read", LOG_LEVEL_WARNING);
+ }
+ }
+#ifdef HAVE_OPENSSL
+ if (IsSSL() && m_ssl)
+ SSL_shutdown(m_ssl);
+ if (m_ssl)
+ {
+ SSL_free(m_ssl);
+ m_ssl = NULL;
+ }
+#endif
+ return Socket::Close();
+}
+
+#ifdef HAVE_OPENSSL
+SSL_CTX *TcpSocket::GetSslContext()
+{
+ if (!m_ssl_ctx)
+ Handler().LogError(this, "GetSslContext", 0, "SSL Context is NULL; check InitSSLServer/InitSSLClient", LOG_LEVEL_WARNING);
+ return m_ssl_ctx;
+}
+
+SSL *TcpSocket::GetSsl()
+{
+ if (!m_ssl)
+ Handler().LogError(this, "GetSsl", 0, "SSL is NULL; check InitSSLServer/InitSSLClient", LOG_LEVEL_WARNING);
+ return m_ssl;
+}
+#endif
+
+#ifdef ENABLE_RECONNECT
+void TcpSocket::SetReconnect(bool x)
+{
+ m_b_reconnect = x;
+}
+#endif
+
+void TcpSocket::OnRawData(const char *buf_in,size_t len)
+{
+}
+
+size_t TcpSocket::GetInputLength()
+{
+ return ibuf.GetLength();
+}
+
+size_t TcpSocket::GetOutputLength()
+{
+ return m_output_length;
+}
+
+uint64_t TcpSocket::GetBytesReceived(bool clear)
+{
+ uint64_t z = m_bytes_received;
+ if (clear)
+ m_bytes_received = 0;
+ return z;
+}
+
+uint64_t TcpSocket::GetBytesSent(bool clear)
+{
+ uint64_t z = m_bytes_sent;
+ if (clear)
+ m_bytes_sent = 0;
+ return z;
+}
+
+#ifdef ENABLE_RECONNECT
+bool TcpSocket::Reconnect()
+{
+ return m_b_reconnect;
+}
+
+void TcpSocket::SetIsReconnect(bool x)
+{
+ m_b_is_reconnect = x;
+}
+
+bool TcpSocket::IsReconnect()
+{
+ return m_b_is_reconnect;
+}
+#endif
+
+#ifdef HAVE_OPENSSL
+const std::string& TcpSocket::GetPassword()
+{
+ return m_password;
+}
+#endif
+
+void TcpSocket::DisableInputBuffer(bool x)
+{
+ m_b_input_buffer_disabled = x;
+}
+
+void TcpSocket::OnOptions(int family,int type,int protocol,SOCKET s)
+{
+DEB( fprintf(stderr, "Socket::OnOptions()\n");)
+#ifdef SO_NOSIGPIPE
+ SetSoNosigpipe(true);
+#endif
+ SetSoReuseaddr(true);
+ SetSoKeepalive(true);
+}
+
+void TcpSocket::SetLineProtocol(bool x)
+{
+ StreamSocket::SetLineProtocol(x);
+ DisableInputBuffer(x);
+}
+
+bool TcpSocket::SetTcpNodelay(bool x)
+{
+#ifdef TCP_NODELAY
+ int optval = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(optval)) == -1)
+ {
+ Handler().LogError(this, "setsockopt(IPPROTO_TCP, TCP_NODELAY)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ return false;
+ }
+ return true;
+#else
+ Handler().LogError(this, "socket option not available", 0, "TCP_NODELAY", LOG_LEVEL_INFO);
+ return false;
+#endif
+}
+
+TcpSocket::CircularBuffer::CircularBuffer(size_t size)
+:buf(new char[2 * size])
+,m_max(size)
+,m_q(0)
+,m_b(0)
+,m_t(0)
+,m_count(0)
+{
+}
+
+TcpSocket::CircularBuffer::~CircularBuffer()
+{
+ delete[] buf;
+}
+
+bool TcpSocket::CircularBuffer::Write(const char *s,size_t l)
+{
+ if (m_q + l > m_max)
+ {
+ return false; // overflow
+ }
+ m_count += (unsigned long)l;
+ if (m_t + l > m_max) // block crosses circular border
+ {
+ size_t l1 = m_max - m_t; // size left until circular border crossing
+ // always copy full block to buffer(buf) + top pointer(m_t)
+ // because we have doubled the buffer size for performance reasons
+ memcpy(buf + m_t, s, l);
+ memcpy(buf, s + l1, l - l1);
+ m_t = l - l1;
+ m_q += l;
+ }
+ else
+ {
+ memcpy(buf + m_t, s, l);
+ memcpy(buf + m_max + m_t, s, l);
+ m_t += l;
+ if (m_t >= m_max)
+ m_t -= m_max;
+ m_q += l;
+ }
+ return true;
+}
+
+bool TcpSocket::CircularBuffer::Read(char *s,size_t l)
+{
+ if (l > m_q)
+ {
+ return false; // not enough chars
+ }
+ if (m_b + l > m_max) // block crosses circular border
+ {
+ size_t l1 = m_max - m_b;
+ if (s)
+ {
+ memcpy(s, buf + m_b, l1);
+ memcpy(s + l1, buf, l - l1);
+ }
+ m_b = l - l1;
+ m_q -= l;
+ }
+ else
+ {
+ if (s)
+ {
+ memcpy(s, buf + m_b, l);
+ }
+ m_b += l;
+ if (m_b >= m_max)
+ m_b -= m_max;
+ m_q -= l;
+ }
+ if (!m_q)
+ {
+ m_b = m_t = 0;
+ }
+ return true;
+}
+
+bool TcpSocket::CircularBuffer::SoftRead(char *s, size_t l)
+{
+ if (l > m_q)
+ {
+ return false;
+ }
+ if (m_b + l > m_max) // block crosses circular border
+ {
+ size_t l1 = m_max - m_b;
+ if (s)
+ {
+ memcpy(s, buf + m_b, l1);
+ memcpy(s + l1, buf, l - l1);
+ }
+ }
+ else
+ {
+ if (s)
+ {
+ memcpy(s, buf + m_b, l);
+ }
+ }
+ return true;
+}
+
+bool TcpSocket::CircularBuffer::Remove(size_t l)
+{
+ return Read(NULL, l);
+}
+
+size_t TcpSocket::CircularBuffer::GetLength()
+{
+ return m_q;
+}
+
+const char *TcpSocket::CircularBuffer::GetStart()
+{
+ return buf + m_b;
+}
+
+size_t TcpSocket::CircularBuffer::GetL()
+{
+ return (m_b + m_q > m_max) ? m_max - m_b : m_q;
+}
+
+size_t TcpSocket::CircularBuffer::Space()
+{
+ return m_max - m_q;
+}
+
+unsigned long TcpSocket::CircularBuffer::ByteCounter(bool clear)
+{
+ if (clear)
+ {
+ unsigned long x = m_count;
+ m_count = 0;
+ return x;
+ }
+ return m_count;
+}
+
+std::string TcpSocket::CircularBuffer::ReadString(size_t l)
+{
+ char *sz = new char[l + 1];
+ if (!Read(sz, l)) // failed, debug printout in Read() method
+ {
+ delete[] sz;
+ return "";
+ }
+ sz[l] = 0;
+ std::string tmp = sz;
+ delete[] sz;
+ return tmp;
+}
+
+void TcpSocket::OnConnectTimeout()
+{
+ Handler().LogError(this, "connect", -1, "connect timeout", LOG_LEVEL_FATAL);
+#ifdef ENABLE_SOCKS4
+ if (Socks4())
+ {
+ OnSocks4ConnectFailed();
+ // retry direct connection
+ }
+ else
+#endif
+ if (GetConnectionRetry() == -1 ||
+ (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
+ {
+ IncreaseConnectionRetries();
+ // ask socket via OnConnectRetry callback if we should continue trying
+ if (OnConnectRetry())
+ {
+ SetRetryClientConnect();
+ }
+ else
+ {
+ SetCloseAndDelete( true );
+ /// \todo state reason why connect failed
+ OnConnectFailed();
+ }
+ }
+ else
+ {
+ SetCloseAndDelete(true);
+ /// \todo state reason why connect failed
+ OnConnectFailed();
+ }
+ //
+ SetConnecting(false);
+}
+
+#ifdef _WIN32
+void TcpSocket::OnException()
+{
+ if (Connecting())
+ {
+#ifdef ENABLE_SOCKS4
+ if (Socks4())
+ OnSocks4ConnectFailed();
+ else
+#endif
+ if (GetConnectionRetry() == -1 ||
+ (GetConnectionRetry() &&
+ GetConnectionRetries() < GetConnectionRetry() ))
+ {
+ // even though the connection failed at once, only retry after
+ // the connection timeout
+ // should we even try to connect again, when CheckConnect returns
+ // false it's because of a connection error - not a timeout...
+ }
+ else
+ {
+ SetConnecting(false); // tnx snibbe
+ SetCloseAndDelete();
+ OnConnectFailed();
+ }
+ return;
+ }
+ // %! exception doesn't always mean something bad happened, this code should be reworked
+ // errno valid here?
+ int err = SoError();
+ Handler().LogError(this, "exception on select", err, StrError(err), LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+}
+#endif // _WIN32
+
+int TcpSocket::Protocol()
+{
+ return IPPROTO_TCP;
+}
+
+void TcpSocket::SetTransferLimit(size_t sz)
+{
+ m_transfer_limit = sz;
+}
+
+void TcpSocket::OnTransferLimit()
+{
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/Thread.cpp b/dep/sockets/Thread.cpp
new file mode 100644
index 00000000000..773e9f214fa
--- /dev/null
+++ b/dep/sockets/Thread.cpp
@@ -0,0 +1,154 @@
+/** \file Thread.cpp
+ ** \date 2004-10-30
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include <stdio.h>
+#ifdef _WIN32
+#include <process.h>
+#include "socket_include.h"
+#else
+#include <unistd.h>
+#endif
+
+#include "Thread.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+Thread::Thread(bool release)
+:m_thread(0)
+,m_running(true)
+,m_release(false)
+,m_b_delete_on_exit(false)
+,m_b_destructor(false)
+{
+#ifdef _WIN32
+// m_thread = ::CreateThread(NULL, 0, StartThread, this, 0, &m_dwThreadId);
+ m_thread = (HANDLE)_beginthreadex(NULL, 0, &StartThread, this, 0, &m_dwThreadId);
+#else
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
+ if (pthread_create(&m_thread,&attr, StartThread,this) == -1)
+ {
+ perror("Thread: create failed");
+ SetRunning(false);
+ }
+// pthread_attr_destroy(&attr);
+#endif
+ m_release = release;
+}
+
+Thread::~Thread()
+{
+ m_b_destructor = true;
+ if (m_running)
+ {
+ SetRelease(true);
+ SetRunning(false);
+#ifdef _WIN32
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ }
+#ifdef _WIN32
+ if (m_thread)
+ ::CloseHandle(m_thread);
+#endif
+}
+
+threadfunc_t STDPREFIX Thread::StartThread(threadparam_t zz)
+{
+ Thread *p = (Thread *)zz;
+
+ while (p -> m_running && !p -> m_release)
+ {
+#ifdef _WIN32
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ }
+ if (p -> m_running)
+ {
+ p -> Run();
+ }
+ p -> SetRunning(false); // if return
+ if (p -> DeleteOnExit() && !p -> IsDestructor())
+ {
+ delete p;
+ }
+#ifdef _WIN32
+ _endthreadex(0);
+#endif
+ return (threadfunc_t)NULL;
+}
+
+bool Thread::IsRunning()
+{
+ return m_running;
+}
+
+void Thread::SetRunning(bool x)
+{
+ m_running = x;
+}
+
+bool Thread::IsReleased()
+{
+ return m_release;
+}
+
+void Thread::SetRelease(bool x)
+{
+ m_release = x;
+}
+
+bool Thread::DeleteOnExit()
+{
+ return m_b_delete_on_exit;
+}
+
+void Thread::SetDeleteOnExit(bool x)
+{
+ m_b_delete_on_exit = x;
+}
+
+bool Thread::IsDestructor()
+{
+ return m_b_destructor;
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/UdpSocket.cpp b/dep/sockets/UdpSocket.cpp
new file mode 100644
index 00000000000..a3d393c00e2
--- /dev/null
+++ b/dep/sockets/UdpSocket.cpp
@@ -0,0 +1,810 @@
+/** \file UdpSocket.cpp
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifdef _WIN32
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#endif
+#include <stdlib.h>
+#else
+#include <errno.h>
+#endif
+
+#include "ISocketHandler.h"
+#include "UdpSocket.h"
+#include "Utility.h"
+#include "Ipv4Address.h"
+#include "Ipv6Address.h"
+#ifdef ENABLE_EXCEPTIONS
+#include "Exception.h"
+#endif
+// include this to see strange sights
+//#include <linux/in6.h>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+UdpSocket::UdpSocket(ISocketHandler& h, int ibufsz, bool ipv6, int retries) : Socket(h)
+, m_ibuf(new char[ibufsz])
+, m_ibufsz(ibufsz)
+, m_bind_ok(false)
+, m_port(0)
+, m_last_size_written(-1)
+, m_retries(retries)
+, m_b_read_ts(false)
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ SetIpv6(ipv6);
+#endif
+#endif
+}
+
+UdpSocket::~UdpSocket()
+{
+ Close();
+ delete[] m_ibuf;
+}
+
+int UdpSocket::Bind(port_t &port, int range)
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ Ipv6Address ad(port);
+ return Bind(ad, range);
+ }
+#endif
+#endif
+ Ipv4Address ad(port);
+ return Bind(ad, range);
+}
+
+int UdpSocket::Bind(const std::string& intf, port_t &port, int range)
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ Ipv6Address ad(intf, port);
+ if (ad.IsValid())
+ {
+ return Bind(ad, range);
+ }
+ SetCloseAndDelete();
+ return -1;
+ }
+#endif
+#endif
+ Ipv4Address ad(intf, port);
+ if (ad.IsValid())
+ {
+ return Bind(ad, range);
+ }
+ SetCloseAndDelete();
+ return -1;
+}
+
+int UdpSocket::Bind(ipaddr_t a, port_t &port, int range)
+{
+ Ipv4Address ad(a, port);
+ return Bind(ad, range);
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+int UdpSocket::Bind(in6_addr a, port_t &port, int range)
+{
+ Ipv6Address ad(a, port);
+ return Bind(ad, range);
+}
+#endif
+#endif
+
+int UdpSocket::Bind(SocketAddress& ad, int range)
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
+ }
+ if (GetSocket() != INVALID_SOCKET)
+ {
+ SetNonblocking(true);
+ int n = bind(GetSocket(), ad, ad);
+ int tries = range;
+ while (n == -1 && tries--)
+ {
+ ad.SetPort(ad.GetPort() + 1);
+ n = bind(GetSocket(), ad, ad);
+ }
+ if (n == -1)
+ {
+ Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+#ifdef ENABLE_EXCEPTIONS
+ throw Exception("bind() failed for UdpSocket, port:range: " + Utility::l2string(ad.GetPort()) + ":" + Utility::l2string(range));
+#endif
+ return -1;
+ }
+ m_bind_ok = true;
+ m_port = ad.GetPort();
+ return 0;
+ }
+ return -1;
+}
+
+/** if you wish to use Send, first Open a connection */
+bool UdpSocket::Open(ipaddr_t l, port_t port)
+{
+ Ipv4Address ad(l, port);
+ return Open(ad);
+}
+
+bool UdpSocket::Open(const std::string& host, port_t port)
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ Ipv6Address ad(host, port);
+ if (ad.IsValid())
+ {
+ return Open(ad);
+ }
+ return false;
+ }
+#endif
+#endif
+ Ipv4Address ad(host, port);
+ if (ad.IsValid())
+ {
+ return Open(ad);
+ }
+ return false;
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+bool UdpSocket::Open(struct in6_addr& a, port_t port)
+{
+ Ipv6Address ad(a, port);
+ return Open(ad);
+}
+#endif
+#endif
+
+bool UdpSocket::Open(SocketAddress& ad)
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
+ }
+ if (GetSocket() != INVALID_SOCKET)
+ {
+ SetNonblocking(true);
+ if (connect(GetSocket(), ad, ad) == -1)
+ {
+ Handler().LogError(this, "connect", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ return false;
+ }
+ SetConnected();
+ return true;
+ }
+ return false;
+}
+
+void UdpSocket::CreateConnection()
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ SOCKET s = CreateSocket(AF_INET6, SOCK_DGRAM, "udp");
+ if (s == INVALID_SOCKET)
+ {
+ return;
+ }
+ SetNonblocking(true, s);
+ Attach(s);
+ }
+ return;
+ }
+#endif
+#endif
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ SOCKET s = CreateSocket(AF_INET, SOCK_DGRAM, "udp");
+ if (s == INVALID_SOCKET)
+ {
+ return;
+ }
+ SetNonblocking(true, s);
+ Attach(s);
+ }
+}
+
+/** send to specified address */
+void UdpSocket::SendToBuf(const std::string& h, port_t p, const char *data, int len, int flags)
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ Ipv6Address ad(h, p);
+ if (ad.IsValid())
+ {
+ SendToBuf(ad, data, len, flags);
+ }
+ return;
+ }
+#endif
+#endif
+ Ipv4Address ad(h, p);
+ if (ad.IsValid())
+ {
+ SendToBuf(ad, data, len, flags);
+ }
+}
+
+/** send to specified address */
+void UdpSocket::SendToBuf(ipaddr_t a, port_t p, const char *data, int len, int flags)
+{
+ Ipv4Address ad(a, p);
+ SendToBuf(ad, data, len, flags);
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+void UdpSocket::SendToBuf(in6_addr a, port_t p, const char *data, int len, int flags)
+{
+ Ipv6Address ad(a, p);
+ SendToBuf(ad, data, len, flags);
+}
+#endif
+#endif
+
+void UdpSocket::SendToBuf(SocketAddress& ad, const char *data, int len, int flags)
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
+ }
+ if (GetSocket() != INVALID_SOCKET)
+ {
+ SetNonblocking(true);
+ if ((m_last_size_written = sendto(GetSocket(), data, len, flags, ad, ad)) == -1)
+ {
+ Handler().LogError(this, "sendto", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+ }
+}
+
+void UdpSocket::SendTo(const std::string& a, port_t p, const std::string& str, int flags)
+{
+ SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
+}
+
+void UdpSocket::SendTo(ipaddr_t a, port_t p, const std::string& str, int flags)
+{
+ SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+void UdpSocket::SendTo(in6_addr a, port_t p, const std::string& str, int flags)
+{
+ SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
+}
+#endif
+#endif
+
+void UdpSocket::SendTo(SocketAddress& ad, const std::string& str, int flags)
+{
+ SendToBuf(ad, str.c_str(), (int)str.size(), flags);
+}
+
+/** send to connected address */
+void UdpSocket::SendBuf(const char *data, size_t len, int flags)
+{
+ if (!IsConnected())
+ {
+ Handler().LogError(this, "SendBuf", 0, "not connected", LOG_LEVEL_ERROR);
+ return;
+ }
+ if ((m_last_size_written = send(GetSocket(), data, (int)len, flags)) == -1)
+ {
+ Handler().LogError(this, "send", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+}
+
+void UdpSocket::Send(const std::string& str, int flags)
+{
+ SendBuf(str.c_str(), (int)str.size(), flags);
+}
+
+#if defined(LINUX) || defined(MACOSX)
+int UdpSocket::ReadTS(char *ioBuf, int inBufSize, struct sockaddr *from, socklen_t fromlen, struct timeval *ts)
+{
+ struct msghdr msg;
+ struct iovec vec[1];
+ union {
+ struct cmsghdr cm;
+#ifdef MACOSX
+#ifdef __DARWIN_UNIX03
+#define ALIGNBYTES __DARWIN_ALIGNBYTES
+#endif
+#define myALIGN(p) (((unsigned int)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+#define myCMSG_SPACE(l) (myALIGN(sizeof(struct cmsghdr)) + myALIGN(l))
+ char data[ myCMSG_SPACE(sizeof(struct timeval)) ];
+#else
+ char data[ CMSG_SPACE(sizeof(struct timeval)) ];
+#endif
+ } cmsg_un;
+ struct cmsghdr *cmsg;
+ struct timeval *tv;
+
+ vec[0].iov_base = ioBuf;
+ vec[0].iov_len = inBufSize;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(from, 0, fromlen);
+ memset(ioBuf, 0, inBufSize);
+ memset(&cmsg_un, 0, sizeof(cmsg_un));
+
+ msg.msg_name = (caddr_t)from;
+ msg.msg_namelen = fromlen;
+ msg.msg_iov = vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsg_un.data;
+ msg.msg_controllen = sizeof(cmsg_un.data);
+ msg.msg_flags = 0;
+
+ // Original version - for reference only
+ //int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
+
+ int n = recvmsg(GetSocket(), &msg, MSG_DONTWAIT);
+
+ // now ioBuf will contain the data, as if we used recvfrom
+
+ // Now get the time
+ if(n != -1 && msg.msg_controllen >= sizeof(struct cmsghdr) && !(msg.msg_flags & MSG_CTRUNC))
+ {
+ tv = 0;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP)
+ {
+ tv = (struct timeval *)CMSG_DATA(cmsg);
+ }
+ }
+ if (tv)
+ {
+ memcpy(ts, tv, sizeof(struct timeval));
+ }
+ }
+ // The address is in network order, but that's OK right now
+ return n;
+}
+#endif
+
+void UdpSocket::OnRead()
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ struct sockaddr_in6 sa;
+ socklen_t sa_len = sizeof(sa);
+ if (m_b_read_ts)
+ {
+ struct timeval ts;
+ Utility::GetTime(&ts);
+#if !defined(LINUX) && !defined(MACOSX)
+ int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
+#else
+ int n = ReadTS(m_ibuf, m_ibufsz, (struct sockaddr *)&sa, sa_len, &ts);
+#endif
+ if (n > 0)
+ {
+ this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len, &ts);
+ }
+ else
+ if (n == -1)
+ {
+#ifdef _WIN32
+ if (Errno != WSAEWOULDBLOCK)
+#else
+ if (Errno != EWOULDBLOCK)
+#endif
+ Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+ return;
+ }
+ int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
+ int q = m_retries; // receive max 10 at one cycle
+ while (n > 0)
+ {
+ if (sa_len != sizeof(sa))
+ {
+ Handler().LogError(this, "recvfrom", 0, "unexpected address struct size", LOG_LEVEL_WARNING);
+ }
+ this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len);
+ if (!q--)
+ break;
+ //
+ n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
+ }
+ if (n == -1)
+ {
+#ifdef _WIN32
+ if (Errno != WSAEWOULDBLOCK)
+#else
+ if (Errno != EWOULDBLOCK)
+#endif
+ Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+ return;
+ }
+#endif
+#endif
+ struct sockaddr_in sa;
+ socklen_t sa_len = sizeof(sa);
+ if (m_b_read_ts)
+ {
+ struct timeval ts;
+ Utility::GetTime(&ts);
+#if !defined(LINUX) && !defined(MACOSX)
+ int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
+#else
+ int n = ReadTS(m_ibuf, m_ibufsz, (struct sockaddr *)&sa, sa_len, &ts);
+#endif
+ if (n > 0)
+ {
+ this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len, &ts);
+ }
+ else
+ if (n == -1)
+ {
+#ifdef _WIN32
+ if (Errno != WSAEWOULDBLOCK)
+#else
+ if (Errno != EWOULDBLOCK)
+#endif
+ Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+ return;
+ }
+ int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
+ int q = m_retries;
+ while (n > 0)
+ {
+ if (sa_len != sizeof(sa))
+ {
+ Handler().LogError(this, "recvfrom", 0, "unexpected address struct size", LOG_LEVEL_WARNING);
+ }
+ this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len);
+ if (!q--)
+ break;
+ //
+ n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
+ }
+ if (n == -1)
+ {
+#ifdef _WIN32
+ if (Errno != WSAEWOULDBLOCK)
+#else
+ if (Errno != EWOULDBLOCK)
+#endif
+ Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ }
+}
+
+void UdpSocket::SetBroadcast(bool b)
+{
+ int one = 1;
+ int zero = 0;
+
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+ if (b)
+ {
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof(one)) == -1)
+ {
+ Handler().LogError(this, "SetBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ }
+ else
+ {
+ if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *) &zero, sizeof(zero)) == -1)
+ {
+ Handler().LogError(this, "SetBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ }
+}
+
+bool UdpSocket::IsBroadcast()
+{
+ int is_broadcast = 0;
+ socklen_t size;
+
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+ if (getsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *)&is_broadcast, &size) == -1)
+ {
+ Handler().LogError(this, "IsBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ return is_broadcast != 0;
+}
+
+void UdpSocket::SetMulticastTTL(int ttl)
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+ if (setsockopt(GetSocket(), SOL_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(int)) == -1)
+ {
+ Handler().LogError(this, "SetMulticastTTL", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+}
+
+int UdpSocket::GetMulticastTTL()
+{
+ int ttl = 0;
+ socklen_t size = sizeof(int);
+
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+ if (getsockopt(GetSocket(), SOL_IP, IP_MULTICAST_TTL, (char *)&ttl, &size) == -1)
+ {
+ Handler().LogError(this, "GetMulticastTTL", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ return ttl;
+}
+
+void UdpSocket::SetMulticastLoop(bool x)
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ int val = x ? 1 : 0;
+ if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&val, sizeof(int)) == -1)
+ {
+ Handler().LogError(this, "SetMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ return;
+ }
+#endif
+#endif
+ int val = x ? 1 : 0;
+ if (setsockopt(GetSocket(), SOL_IP, IP_MULTICAST_LOOP, (char *)&val, sizeof(int)) == -1)
+ {
+ Handler().LogError(this, "SetMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+}
+
+bool UdpSocket::IsMulticastLoop()
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ int is_loop = 0;
+ socklen_t size = sizeof(int);
+ if (getsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&is_loop, &size) == -1)
+ {
+ Handler().LogError(this, "IsMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ return is_loop ? true : false;
+ }
+#endif
+#endif
+ int is_loop = 0;
+ socklen_t size = sizeof(int);
+ if (getsockopt(GetSocket(), SOL_IP, IP_MULTICAST_LOOP, (char *)&is_loop, &size) == -1)
+ {
+ Handler().LogError(this, "IsMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ return is_loop ? true : false;
+}
+
+void UdpSocket::AddMulticastMembership(const std::string& group, const std::string& local_if, int if_index)
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ struct ipv6_mreq x;
+ struct in6_addr addr;
+ if (Utility::u2ip( group, addr ))
+ {
+ x.ipv6mr_multiaddr = addr;
+ x.ipv6mr_interface = if_index;
+ if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&x, sizeof(struct ipv6_mreq)) == -1)
+ {
+ Handler().LogError(this, "AddMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ }
+ return;
+ }
+#endif
+#endif
+ struct ip_mreq x; // ip_mreqn
+ ipaddr_t addr;
+ if (Utility::u2ip( group, addr ))
+ {
+ memcpy(&x.imr_multiaddr.s_addr, &addr, sizeof(addr));
+ Utility::u2ip( local_if, addr);
+ memcpy(&x.imr_interface.s_addr, &addr, sizeof(addr));
+// x.imr_ifindex = if_index;
+ if (setsockopt(GetSocket(), SOL_IP, IP_ADD_MEMBERSHIP, (char *)&x, sizeof(struct ip_mreq)) == -1)
+ {
+ Handler().LogError(this, "AddMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ }
+}
+
+void UdpSocket::DropMulticastMembership(const std::string& group, const std::string& local_if, int if_index)
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ struct ipv6_mreq x;
+ struct in6_addr addr;
+ if (Utility::u2ip( group, addr ))
+ {
+ x.ipv6mr_multiaddr = addr;
+ x.ipv6mr_interface = if_index;
+ if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *)&x, sizeof(struct ipv6_mreq)) == -1)
+ {
+ Handler().LogError(this, "DropMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ }
+ return;
+ }
+#endif
+#endif
+ struct ip_mreq x; // ip_mreqn
+ ipaddr_t addr;
+ if (Utility::u2ip( group, addr ))
+ {
+ memcpy(&x.imr_multiaddr.s_addr, &addr, sizeof(addr));
+ Utility::u2ip( local_if, addr);
+ memcpy(&x.imr_interface.s_addr, &addr, sizeof(addr));
+// x.imr_ifindex = if_index;
+ if (setsockopt(GetSocket(), SOL_IP, IP_DROP_MEMBERSHIP, (char *)&x, sizeof(struct ip_mreq)) == -1)
+ {
+ Handler().LogError(this, "DropMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ }
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+void UdpSocket::SetMulticastHops(int hops)
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+ if (!IsIpv6())
+ {
+ Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR);
+ return;
+ }
+ if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hops, sizeof(int)) == -1)
+ {
+ Handler().LogError(this, "SetMulticastHops", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+}
+
+int UdpSocket::GetMulticastHops()
+{
+ if (GetSocket() == INVALID_SOCKET)
+ {
+ CreateConnection();
+ }
+ if (!IsIpv6())
+ {
+ Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR);
+ return -1;
+ }
+ int hops = 0;
+ socklen_t size = sizeof(int);
+ if (getsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hops, &size) == -1)
+ {
+ Handler().LogError(this, "GetMulticastHops", Errno, StrError(Errno), LOG_LEVEL_WARNING);
+ }
+ return hops;
+}
+#endif // IPPROTO_IPV6
+#endif
+
+bool UdpSocket::IsBound()
+{
+ return m_bind_ok;
+}
+
+void UdpSocket::OnRawData(const char *buf, size_t len, struct sockaddr *sa, socklen_t sa_len)
+{
+}
+
+void UdpSocket::OnRawData(const char *buf, size_t len, struct sockaddr *sa, socklen_t sa_len, struct timeval *ts)
+{
+}
+
+port_t UdpSocket::GetPort()
+{
+ return m_port;
+}
+
+int UdpSocket::GetLastSizeWritten()
+{
+ return m_last_size_written;
+}
+
+void UdpSocket::SetTimestamp(bool x)
+{
+ m_b_read_ts = x;
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/Utility.cpp b/dep/sockets/Utility.cpp
new file mode 100644
index 00000000000..7c093fc0832
--- /dev/null
+++ b/dep/sockets/Utility.cpp
@@ -0,0 +1,960 @@
+/** \file Utility.cpp
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "Utility.h"
+#include "Parse.h"
+#include "Ipv4Address.h"
+#include "Ipv6Address.h"
+#include "Base64.h"
+#include <vector>
+#ifdef _WIN32
+#include <time.h>
+#else
+#include <netdb.h>
+#include <pthread.h>
+#endif
+#include <map>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+// defines for the random number generator
+#define TWIST_IA 397
+#define TWIST_IB (TWIST_LEN - TWIST_IA)
+#define UMASK 0x80000000
+#define LMASK 0x7FFFFFFF
+#define MATRIX_A 0x9908B0DF
+#define TWIST(b,i,j) ((b)[i] & UMASK) | ((b)[j] & LMASK)
+#define MAGIC_TWIST(s) (((s) & 1) * MATRIX_A)
+
+// statics
+std::string Utility::m_host;
+bool Utility::m_local_resolved = false;
+ipaddr_t Utility::m_ip = 0;
+std::string Utility::m_addr;
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+struct in6_addr Utility::m_local_ip6;
+std::string Utility::m_local_addr6;
+#endif
+#endif
+
+std::string Utility::base64(const std::string& str_in)
+{
+ std::string str;
+ Base64 m_b;
+ m_b.encode(str_in, str, false); // , false == do not add cr/lf
+ return str;
+}
+
+std::string Utility::base64d(const std::string& str_in)
+{
+ std::string str;
+ Base64 m_b;
+ m_b.decode(str_in, str);
+ return str;
+}
+
+std::string Utility::l2string(long l)
+{
+ std::string str;
+ char tmp[100];
+ sprintf(tmp,"%ld",l);
+ str = tmp;
+ return str;
+}
+
+std::string Utility::bigint2string(uint64_t l)
+{
+ std::string str;
+ uint64_t tmp = l;
+ while (tmp)
+ {
+ uint64_t a = tmp % 10;
+ str = (char)(a + 48) + str;
+ tmp /= 10;
+ }
+ if (str.empty())
+ {
+ str = "0";
+ }
+ return str;
+}
+
+uint64_t Utility::atoi64(const std::string& str)
+{
+ uint64_t l = 0;
+ for (size_t i = 0; i < str.size(); i++)
+ {
+ l = l * 10 + str[i] - 48;
+ }
+ return l;
+}
+
+unsigned int Utility::hex2unsigned(const std::string& str)
+{
+ unsigned int r = 0;
+ for (size_t i = 0; i < str.size(); i++)
+ {
+ r = r * 16 + str[i] - 48 - ((str[i] >= 'A') ? 7 : 0) - ((str[i] >= 'a') ? 32 : 0);
+ }
+ return r;
+}
+
+/*
+* Encode string per RFC1738 URL encoding rules
+* tnx rstaveley
+*/
+std::string Utility::rfc1738_encode(const std::string& src)
+{
+static char hex[] = "0123456789ABCDEF";
+ std::string dst;
+ for (size_t i = 0; i < src.size(); i++)
+ {
+ if (isalnum(src[i]))
+ {
+ dst += src[i];
+ }
+ else
+ if (src[i] == ' ')
+ {
+ dst += '+';
+ }
+ else
+ {
+ unsigned char c = static_cast<unsigned char>(src[i]);
+ dst += '%';
+ dst += hex[c / 16];
+ dst += hex[c % 16];
+ }
+ }
+ return dst;
+} // rfc1738_encode
+
+/*
+* Decode string per RFC1738 URL encoding rules
+* tnx rstaveley
+*/
+std::string Utility::rfc1738_decode(const std::string& src)
+{
+ std::string dst;
+ for (size_t i = 0; i < src.size(); i++)
+ {
+ if (src[i] == '%' && isxdigit(src[i + 1]) && isxdigit(src[i + 2]))
+ {
+ char c1 = src[++i];
+ char c2 = src[++i];
+ c1 = c1 - 48 - ((c1 >= 'A') ? 7 : 0) - ((c1 >= 'a') ? 32 : 0);
+ c2 = c2 - 48 - ((c2 >= 'A') ? 7 : 0) - ((c2 >= 'a') ? 32 : 0);
+ dst += (char)(c1 * 16 + c2);
+ }
+ else
+ if (src[i] == '+')
+ {
+ dst += ' ';
+ }
+ else
+ {
+ dst += src[i];
+ }
+ }
+ return dst;
+} // rfc1738_decode
+
+bool Utility::isipv4(const std::string& str)
+{
+ int dots = 0;
+ // %! ignore :port?
+ for (size_t i = 0; i < str.size(); i++)
+ {
+ if (str[i] == '.')
+ dots++;
+ else
+ if (!isdigit(str[i]))
+ return false;
+ }
+ if (dots != 3)
+ return false;
+ return true;
+}
+
+bool Utility::isipv6(const std::string& str)
+{
+ size_t qc = 0;
+ size_t qd = 0;
+ for (size_t i = 0; i < str.size(); i++)
+ {
+ qc += (str[i] == ':') ? 1 : 0;
+ qd += (str[i] == '.') ? 1 : 0;
+ }
+ if (qc > 7)
+ {
+ return false;
+ }
+ if (qd && qd != 3)
+ {
+ return false;
+ }
+ Parse pa(str,":.");
+ std::string tmp = pa.getword();
+ while (!tmp.empty())
+ {
+ if (tmp.size() > 4)
+ {
+ return false;
+ }
+ for (size_t i = 0; i < tmp.size(); i++)
+ {
+ if (tmp[i] < '0' || (tmp[i] > '9' && tmp[i] < 'A') ||
+ (tmp[i] > 'F' && tmp[i] < 'a') || tmp[i] > 'f')
+ {
+ return false;
+ }
+ }
+ //
+ tmp = pa.getword();
+ }
+ return true;
+}
+
+bool Utility::u2ip(const std::string& str, ipaddr_t& l)
+{
+ struct sockaddr_in sa;
+ bool r = Utility::u2ip(str, sa);
+ memcpy(&l, &sa.sin_addr, sizeof(l));
+ return r;
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+bool Utility::u2ip(const std::string& str, struct in6_addr& l)
+{
+ struct sockaddr_in6 sa;
+ bool r = Utility::u2ip(str, sa);
+ l = sa.sin6_addr;
+ return r;
+}
+#endif
+#endif
+
+void Utility::l2ip(const ipaddr_t ip, std::string& str)
+{
+ struct sockaddr_in sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sin_family = AF_INET;
+ memcpy(&sa.sin_addr, &ip, sizeof(sa.sin_addr));
+ Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), str, NI_NUMERICHOST);
+}
+
+void Utility::l2ip(const in_addr& ip, std::string& str)
+{
+ struct sockaddr_in sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_addr = ip;
+ Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), str, NI_NUMERICHOST);
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+void Utility::l2ip(const struct in6_addr& ip, std::string& str,bool mixed)
+{
+ char slask[100]; // l2ip temporary
+ *slask = 0;
+ unsigned int prev = 0;
+ bool skipped = false;
+ bool ok_to_skip = true;
+ if (mixed)
+ {
+ unsigned short x;
+ unsigned short addr16[8];
+ memcpy(addr16, &ip, sizeof(addr16));
+ for (size_t i = 0; i < 6; i++)
+ {
+ x = ntohs(addr16[i]);
+ if (*slask && (x || !ok_to_skip || prev))
+ strcat(slask,":");
+ if (x || !ok_to_skip)
+ {
+ sprintf(slask + strlen(slask),"%x", x);
+ if (x && skipped)
+ ok_to_skip = false;
+ }
+ else
+ {
+ skipped = true;
+ }
+ prev = x;
+ }
+ x = ntohs(addr16[6]);
+ sprintf(slask + strlen(slask),":%u.%u",x / 256,x & 255);
+ x = ntohs(addr16[7]);
+ sprintf(slask + strlen(slask),".%u.%u",x / 256,x & 255);
+ }
+ else
+ {
+ struct sockaddr_in6 sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sin6_family = AF_INET6;
+ sa.sin6_addr = ip;
+ Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), str, NI_NUMERICHOST);
+ return;
+ }
+ str = slask;
+}
+
+int Utility::in6_addr_compare(in6_addr a,in6_addr b)
+{
+ for (size_t i = 0; i < 16; i++)
+ {
+ if (a.s6_addr[i] < b.s6_addr[i])
+ return -1;
+ if (a.s6_addr[i] > b.s6_addr[i])
+ return 1;
+ }
+ return 0;
+}
+#endif
+#endif
+
+void Utility::ResolveLocal()
+{
+ char h[256];
+
+ // get local hostname and translate into ip-address
+ *h = 0;
+ gethostname(h,255);
+ {
+ if (Utility::u2ip(h, m_ip))
+ {
+ Utility::l2ip(m_ip, m_addr);
+ }
+ }
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ memset(&m_local_ip6, 0, sizeof(m_local_ip6));
+ {
+ if (Utility::u2ip(h, m_local_ip6))
+ {
+ Utility::l2ip(m_local_ip6, m_local_addr6);
+ }
+ }
+#endif
+#endif
+ m_host = h;
+ m_local_resolved = true;
+}
+
+const std::string& Utility::GetLocalHostname()
+{
+ if (!m_local_resolved)
+ {
+ ResolveLocal();
+ }
+ return m_host;
+}
+
+ipaddr_t Utility::GetLocalIP()
+{
+ if (!m_local_resolved)
+ {
+ ResolveLocal();
+ }
+ return m_ip;
+}
+
+const std::string& Utility::GetLocalAddress()
+{
+ if (!m_local_resolved)
+ {
+ ResolveLocal();
+ }
+ return m_addr;
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+const struct in6_addr& Utility::GetLocalIP6()
+{
+ if (!m_local_resolved)
+ {
+ ResolveLocal();
+ }
+ return m_local_ip6;
+}
+
+const std::string& Utility::GetLocalAddress6()
+{
+ if (!m_local_resolved)
+ {
+ ResolveLocal();
+ }
+ return m_local_addr6;
+}
+#endif
+#endif
+
+void Utility::SetEnv(const std::string& var,const std::string& value)
+{
+#if (defined(SOLARIS8) || defined(SOLARIS))
+ {
+ static std::map<std::string, char *> vmap;
+ if (vmap.find(var) != vmap.end())
+ {
+ delete[] vmap[var];
+ }
+ vmap[var] = new char[var.size() + 1 + value.size() + 1];
+ sprintf(vmap[var], "%s=%s", var.c_str(), value.c_str());
+ putenv( vmap[var] );
+ }
+#elif defined _WIN32
+ {
+ std::string slask = var + "=" + value;
+ _putenv( (char *)slask.c_str());
+ }
+#else
+ setenv(var.c_str(), value.c_str(), 1);
+#endif
+}
+
+std::string Utility::Sa2String(struct sockaddr *sa)
+{
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (sa -> sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+ std::string tmp;
+ Utility::l2ip(sa6 -> sin6_addr, tmp);
+ return tmp + ":" + Utility::l2string(ntohs(sa6 -> sin6_port));
+ }
+#endif
+#endif
+ if (sa -> sa_family == AF_INET)
+ {
+ struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
+ ipaddr_t a;
+ memcpy(&a, &sa4 -> sin_addr, 4);
+ std::string tmp;
+ Utility::l2ip(a, tmp);
+ return tmp + ":" + Utility::l2string(ntohs(sa4 -> sin_port));
+ }
+ return "";
+}
+
+void Utility::GetTime(struct timeval *p)
+{
+#ifdef _WIN32
+ FILETIME ft; // Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
+ GetSystemTimeAsFileTime(&ft);
+ uint64_t tt;
+ memcpy(&tt, &ft, sizeof(tt));
+ tt /= 10; // make it usecs
+ p->tv_sec = (long)tt / 1000000;
+ p->tv_usec = (long)tt % 1000000;
+#else
+ gettimeofday(p, NULL);
+#endif
+}
+
+std::auto_ptr<SocketAddress> Utility::CreateAddress(struct sockaddr *sa,socklen_t sa_len)
+{
+ switch (sa -> sa_family)
+ {
+ case AF_INET:
+ if (sa_len == sizeof(struct sockaddr_in))
+ {
+ struct sockaddr_in *p = (struct sockaddr_in *)sa;
+ return std::auto_ptr<SocketAddress>(new Ipv4Address(*p));
+ }
+ break;
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ case AF_INET6:
+ if (sa_len == sizeof(struct sockaddr_in6))
+ {
+ struct sockaddr_in6 *p = (struct sockaddr_in6 *)sa;
+ return std::auto_ptr<SocketAddress>(new Ipv6Address(*p));
+ }
+ break;
+#endif
+#endif
+ }
+ return std::auto_ptr<SocketAddress>(NULL);
+}
+
+bool Utility::u2ip(const std::string& host, struct sockaddr_in& sa, int ai_flags)
+{
+ memset(&sa, 0, sizeof(sa));
+ sa.sin_family = AF_INET;
+#ifdef NO_GETADDRINFO
+ if ((ai_flags & AI_NUMERICHOST) != 0 || isipv4(host))
+ {
+ Parse pa((char *)host.c_str(), ".");
+ union {
+ struct {
+ unsigned char b1;
+ unsigned char b2;
+ unsigned char b3;
+ unsigned char b4;
+ } a;
+ ipaddr_t l;
+ } u;
+ u.a.b1 = static_cast<unsigned char>(pa.getvalue());
+ u.a.b2 = static_cast<unsigned char>(pa.getvalue());
+ u.a.b3 = static_cast<unsigned char>(pa.getvalue());
+ u.a.b4 = static_cast<unsigned char>(pa.getvalue());
+ memcpy(&sa.sin_addr, &u.l, sizeof(sa.sin_addr));
+ return true;
+ }
+#ifndef LINUX
+ struct hostent *he = gethostbyname( host.c_str() );
+ if (!he)
+ {
+ return false;
+ }
+ memcpy(&sa.sin_addr, he -> h_addr, sizeof(sa.sin_addr));
+#else
+ struct hostent he;
+ struct hostent *result = NULL;
+ int myerrno = 0;
+ char buf[2000];
+ int n = gethostbyname_r(host.c_str(), &he, buf, sizeof(buf), &result, &myerrno);
+ if (n || !result)
+ {
+ return false;
+ }
+ if (he.h_addr_list && he.h_addr_list[0])
+ memcpy(&sa.sin_addr, he.h_addr, 4);
+ else
+ return false;
+#endif
+ return true;
+#else
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ // AI_NUMERICHOST
+ // AI_CANONNAME
+ // AI_PASSIVE - server
+ // AI_ADDRCONFIG
+ // AI_V4MAPPED
+ // AI_ALL
+ // AI_NUMERICSERV
+ hints.ai_flags = ai_flags;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = 0;
+ hints.ai_protocol = 0;
+ struct addrinfo *res;
+ if (Utility::isipv4(host))
+ hints.ai_flags |= AI_NUMERICHOST;
+ int n = getaddrinfo(host.c_str(), NULL, &hints, &res);
+ if (!n)
+ {
+ std::vector<struct addrinfo *> vec;
+ struct addrinfo *ai = res;
+ while (ai)
+ {
+ if (ai -> ai_addrlen == sizeof(sa))
+ vec.push_back( ai );
+ ai = ai -> ai_next;
+ }
+ if (vec.empty())
+ return false;
+ ai = vec[Utility::Rnd() % vec.size()];
+ {
+ memcpy(&sa, ai -> ai_addr, ai -> ai_addrlen);
+ }
+ freeaddrinfo(res);
+ return true;
+ }
+ std::string error = "Error: ";
+#ifndef __CYGWIN__
+ error += gai_strerror(n);
+#endif
+ return false;
+#endif // NO_GETADDRINFO
+}
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+bool Utility::u2ip(const std::string& host, struct sockaddr_in6& sa, int ai_flags)
+{
+ memset(&sa, 0, sizeof(sa));
+ sa.sin6_family = AF_INET6;
+#ifdef NO_GETADDRINFO
+ if ((ai_flags & AI_NUMERICHOST) != 0 || isipv6(host))
+ {
+ std::list<std::string> vec;
+ size_t x = 0;
+ for (size_t i = 0; i <= host.size(); i++)
+ {
+ if (i == host.size() || host[i] == ':')
+ {
+ std::string s = host.substr(x, i - x);
+ //
+ if (strstr(s.c_str(),".")) // x.x.x.x
+ {
+ Parse pa(s,".");
+ char slask[100]; // u2ip temporary hex2string conversion
+ unsigned long b0 = static_cast<unsigned long>(pa.getvalue());
+ unsigned long b1 = static_cast<unsigned long>(pa.getvalue());
+ unsigned long b2 = static_cast<unsigned long>(pa.getvalue());
+ unsigned long b3 = static_cast<unsigned long>(pa.getvalue());
+ sprintf(slask,"%lx",b0 * 256 + b1);
+ vec.push_back(slask);
+ sprintf(slask,"%lx",b2 * 256 + b3);
+ vec.push_back(slask);
+ }
+ else
+ {
+ vec.push_back(s);
+ }
+ //
+ x = i + 1;
+ }
+ }
+ size_t sz = vec.size(); // number of byte pairs
+ size_t i = 0; // index in in6_addr.in6_u.u6_addr16[] ( 0 .. 7 )
+ unsigned short addr16[8];
+ for (std::list<std::string>::iterator it = vec.begin(); it != vec.end(); it++)
+ {
+ std::string bytepair = *it;
+ if (!bytepair.empty())
+ {
+ addr16[i++] = htons(Utility::hex2unsigned(bytepair));
+ }
+ else
+ {
+ addr16[i++] = 0;
+ while (sz++ < 8)
+ {
+ addr16[i++] = 0;
+ }
+ }
+ }
+ memcpy(&sa.sin6_addr, addr16, sizeof(addr16));
+ return true;
+ }
+#ifdef SOLARIS
+ int errnum = 0;
+ struct hostent *he = getipnodebyname( host.c_str(), AF_INET6, 0, &errnum );
+#else
+ struct hostent *he = gethostbyname2( host.c_str(), AF_INET6 );
+#endif
+ if (!he)
+ {
+ return false;
+ }
+ memcpy(&sa.sin6_addr,he -> h_addr_list[0],he -> h_length);
+#ifdef SOLARIS
+ free(he);
+#endif
+ return true;
+#else
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = ai_flags;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = 0;
+ hints.ai_protocol = 0;
+ struct addrinfo *res;
+ if (Utility::isipv6(host))
+ hints.ai_flags |= AI_NUMERICHOST;
+ int n = getaddrinfo(host.c_str(), NULL, &hints, &res);
+ if (!n)
+ {
+ std::vector<struct addrinfo *> vec;
+ struct addrinfo *ai = res;
+ while (ai)
+ {
+ if (ai -> ai_addrlen == sizeof(sa))
+ vec.push_back( ai );
+ ai = ai -> ai_next;
+ }
+ if (vec.empty())
+ return false;
+ ai = vec[Utility::Rnd() % vec.size()];
+ {
+ memcpy(&sa, ai -> ai_addr, ai -> ai_addrlen);
+ }
+ freeaddrinfo(res);
+ return true;
+ }
+ std::string error = "Error: ";
+#ifndef __CYGWIN__
+ error += gai_strerror(n);
+#endif
+ return false;
+#endif // NO_GETADDRINFO
+}
+#endif // IPPROTO_IPV6
+#endif // ENABLE_IPV6
+
+bool Utility::reverse(struct sockaddr *sa, socklen_t sa_len, std::string& hostname, int flags)
+{
+ std::string service;
+ return Utility::reverse(sa, sa_len, hostname, service, flags);
+}
+
+bool Utility::reverse(struct sockaddr *sa, socklen_t sa_len, std::string& hostname, std::string& service, int flags)
+{
+ hostname = "";
+ service = "";
+#ifdef NO_GETADDRINFO
+ switch (sa -> sa_family)
+ {
+ case AF_INET:
+ if (flags & NI_NUMERICHOST)
+ {
+ union {
+ struct {
+ unsigned char b1;
+ unsigned char b2;
+ unsigned char b3;
+ unsigned char b4;
+ } a;
+ ipaddr_t l;
+ } u;
+ struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
+ memcpy(&u.l, &sa_in -> sin_addr, sizeof(u.l));
+ char tmp[100];
+ sprintf(tmp, "%u.%u.%u.%u", u.a.b1, u.a.b2, u.a.b3, u.a.b4);
+ hostname = tmp;
+ return true;
+ }
+ else
+ {
+ struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
+ struct hostent *h = gethostbyaddr( (const char *)&sa_in -> sin_addr, sizeof(sa_in -> sin_addr), AF_INET);
+ if (h)
+ {
+ hostname = h -> h_name;
+ return true;
+ }
+ }
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ if (flags & NI_NUMERICHOST)
+ {
+ char slask[100]; // l2ip temporary
+ *slask = 0;
+ unsigned int prev = 0;
+ bool skipped = false;
+ bool ok_to_skip = true;
+ {
+ unsigned short addr16[8];
+ struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
+ memcpy(addr16, &sa_in6 -> sin6_addr, sizeof(addr16));
+ for (size_t i = 0; i < 8; i++)
+ {
+ unsigned short x = ntohs(addr16[i]);
+ if (*slask && (x || !ok_to_skip || prev))
+ strcat(slask,":");
+ if (x || !ok_to_skip)
+ {
+ sprintf(slask + strlen(slask),"%x", x);
+ if (x && skipped)
+ ok_to_skip = false;
+ }
+ else
+ {
+ skipped = true;
+ }
+ prev = x;
+ }
+ }
+ if (!*slask)
+ strcpy(slask, "::");
+ hostname = slask;
+ return true;
+ }
+ else
+ {
+ // %! TODO: ipv6 reverse lookup
+ struct sockaddr_in6 *sa_in = (struct sockaddr_in6 *)sa;
+ struct hostent *h = gethostbyaddr( (const char *)&sa_in -> sin6_addr, sizeof(sa_in -> sin6_addr), AF_INET6);
+ if (h)
+ {
+ hostname = h -> h_name;
+ return true;
+ }
+ }
+ break;
+#endif
+ }
+ return false;
+#else
+ char host[NI_MAXHOST];
+ char serv[NI_MAXSERV];
+ // NI_NOFQDN
+ // NI_NUMERICHOST
+ // NI_NAMEREQD
+ // NI_NUMERICSERV
+ // NI_DGRAM
+ int n = getnameinfo(sa, sa_len, host, sizeof(host), serv, sizeof(serv), flags);
+ if (n)
+ {
+ // EAI_AGAIN
+ // EAI_BADFLAGS
+ // EAI_FAIL
+ // EAI_FAMILY
+ // EAI_MEMORY
+ // EAI_NONAME
+ // EAI_OVERFLOW
+ // EAI_SYSTEM
+ return false;
+ }
+ hostname = host;
+ service = serv;
+ return true;
+#endif // NO_GETADDRINFO
+}
+
+bool Utility::u2service(const std::string& name, int& service, int ai_flags)
+{
+#ifdef NO_GETADDRINFO
+ // %!
+ return false;
+#else
+ struct addrinfo hints;
+ service = 0;
+ memset(&hints, 0, sizeof(hints));
+ // AI_NUMERICHOST
+ // AI_CANONNAME
+ // AI_PASSIVE - server
+ // AI_ADDRCONFIG
+ // AI_V4MAPPED
+ // AI_ALL
+ // AI_NUMERICSERV
+ hints.ai_flags = ai_flags;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = 0;
+ hints.ai_protocol = 0;
+ struct addrinfo *res;
+ int n = getaddrinfo(NULL, name.c_str(), &hints, &res);
+ if (!n)
+ {
+ service = res -> ai_protocol;
+ freeaddrinfo(res);
+ return true;
+ }
+ return false;
+#endif // NO_GETADDRINFO
+}
+
+unsigned long Utility::ThreadID()
+{
+#ifdef _WIN32
+ return GetCurrentThreadId();
+#else
+ return (unsigned long)pthread_self();
+#endif
+}
+
+std::string Utility::ToLower(const std::string& str)
+{
+ std::string r;
+ for (size_t i = 0; i < str.size(); i++)
+ {
+ if (str[i] >= 'A' && str[i] <= 'Z')
+ r += str[i] | 32;
+ else
+ r += str[i];
+ }
+ return r;
+}
+
+std::string Utility::ToUpper(const std::string& str)
+{
+ std::string r;
+ for (size_t i = 0; i < str.size(); i++)
+ {
+ if (str[i] >= 'a' && str[i] <= 'z')
+ r += (char)(str[i] - 32);
+ else
+ r += str[i];
+ }
+ return r;
+}
+
+std::string Utility::ToString(double d)
+{
+ char tmp[100];
+ sprintf(tmp, "%f", d);
+ return tmp;
+}
+
+unsigned long Utility::Rnd()
+{
+static Utility::Rng generator( (unsigned long)time(NULL) );
+ return generator.Get();
+}
+
+Utility::Rng::Rng(unsigned long seed) : m_value( 0 )
+{
+ m_tmp[0]= seed & 0xffffffffUL;
+ for (int i = 1; i < TWIST_LEN; i++)
+ {
+ m_tmp[i] = (1812433253UL * (m_tmp[i - 1] ^ (m_tmp[i - 1] >> 30)) + i);
+ }
+}
+
+unsigned long Utility::Rng::Get()
+{
+ unsigned long val = m_tmp[m_value];
+ ++m_value;
+ if (m_value == TWIST_LEN)
+ {
+ for (int i = 0; i < TWIST_IB; ++i)
+ {
+ unsigned long s = TWIST(m_tmp, i, i + 1);
+ m_tmp[i] = m_tmp[i + TWIST_IA] ^ (s >> 1) ^ MAGIC_TWIST(s);
+ }
+ {
+ for (int i = 0; i < TWIST_LEN - 1; ++i)
+ {
+ unsigned long s = TWIST(m_tmp, i, i + 1);
+ m_tmp[i] = m_tmp[i - TWIST_IB] ^ (s >> 1) ^ MAGIC_TWIST(s);
+ }
+ }
+ unsigned long s = TWIST(m_tmp, TWIST_LEN - 1, 0);
+ m_tmp[TWIST_LEN - 1] = m_tmp[TWIST_IA - 1] ^ (s >> 1) ^ MAGIC_TWIST(s);
+
+ m_value = 0;
+ }
+ return val;
+}
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+
diff --git a/dep/sockets/include/Base64.h b/dep/sockets/include/Base64.h
new file mode 100644
index 00000000000..d4323aaa019
--- /dev/null
+++ b/dep/sockets/include/Base64.h
@@ -0,0 +1,77 @@
+/** \file Base64.h
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_Base64_H
+#define _SOCKETS_Base64_H
+
+#include "sockets-config.h"
+#ifdef _MSC_VER
+#pragma warning(disable:4514)
+#endif
+
+#include <stdio.h>
+#include <string>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** \defgroup util Utilities */
+
+/** Base64 encode/decode.
+ \ingroup util */
+class Base64
+{
+public:
+ Base64();
+
+ void encode(FILE *, std::string& , bool add_crlf = true);
+ void encode(const std::string&, std::string& , bool add_crlf = true);
+ void encode(const char *, size_t, std::string& , bool add_crlf = true);
+ void encode(const unsigned char *, size_t, std::string& , bool add_crlf = true);
+
+ void decode(const std::string&, std::string& );
+ void decode(const std::string&, unsigned char *, size_t&);
+
+ size_t decode_length(const std::string& );
+
+private:
+ Base64(const Base64& ) {}
+ Base64& operator=(const Base64& ) { return *this; }
+static const char *bstr;
+static const char rstr[128];
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_Base64_H
+
+
diff --git a/dep/sockets/include/Exception.h b/dep/sockets/include/Exception.h
new file mode 100644
index 00000000000..bb881b2d74f
--- /dev/null
+++ b/dep/sockets/include/Exception.h
@@ -0,0 +1,55 @@
+/**
+ ** \file Exception.h
+ ** \date 2007-09-28
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _Sockets_Exception_H
+#define _Sockets_Exception_H
+
+#include <string>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+class Exception
+{
+public:
+ Exception(const std::string& description);
+ virtual ~Exception() {}
+
+ virtual const std::string ToString() const;
+
+ Exception(const Exception& ) {} // copy constructor
+
+ Exception& operator=(const Exception& ) { return *this; } // assignment operator
+
+private:
+ std::string m_description;
+
+};
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+
+#endif // _Sockets_Exception_H
+
+
diff --git a/dep/sockets/include/File.h b/dep/sockets/include/File.h
new file mode 100644
index 00000000000..ed322efa2d8
--- /dev/null
+++ b/dep/sockets/include/File.h
@@ -0,0 +1,82 @@
+/** \file File.h
+ ** \date 2005-04-25
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_File_H
+#define _SOCKETS_File_H
+
+#include "sockets-config.h"
+#include "IFile.h"
+#include <stdio.h>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** IFile implementation of a disk file.
+ \ingroup file */
+class File : public IFile
+{
+public:
+ File();
+ ~File();
+
+ bool fopen(const std::string&, const std::string&);
+ void fclose();
+
+ size_t fread(char *, size_t, size_t) const;
+ size_t fwrite(const char *, size_t, size_t);
+
+ char *fgets(char *, int) const;
+ void fprintf(const char *format, ...);
+
+ off_t size() const;
+ bool eof() const;
+
+ void reset_read() const;
+ void reset_write();
+
+private:
+ File(const File& ) {} // copy constructor
+ File& operator=(const File& ) { return *this; } // assignment operator
+
+ std::string m_path;
+ std::string m_mode;
+ FILE *m_fil;
+ mutable long m_rptr;
+ long m_wptr;
+};
+
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_File_H
+
+
diff --git a/dep/sockets/include/IFile.h b/dep/sockets/include/IFile.h
new file mode 100644
index 00000000000..657c8a4b1d9
--- /dev/null
+++ b/dep/sockets/include/IFile.h
@@ -0,0 +1,71 @@
+/** \file IFile.h
+ ** \date 2005-04-25
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_IFile_H
+#define _SOCKETS_IFile_H
+
+#include "sockets-config.h"
+#include <string>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** \defgroup file File handling */
+/** Pure virtual file I/O interface.
+ \ingroup file */
+class IFile
+{
+public:
+ virtual ~IFile() {}
+
+ virtual bool fopen(const std::string&, const std::string&) = 0;
+ virtual void fclose() = 0;
+
+ virtual size_t fread(char *, size_t, size_t) const = 0;
+ virtual size_t fwrite(const char *, size_t, size_t) = 0;
+
+ virtual char *fgets(char *, int) const = 0;
+ virtual void fprintf(const char *format, ...) = 0;
+
+ virtual off_t size() const = 0;
+ virtual bool eof() const = 0;
+
+ virtual void reset_read() const = 0;
+ virtual void reset_write() = 0;
+
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_IFile_H
+
+
diff --git a/dep/sockets/include/ISocketHandler.h b/dep/sockets/include/ISocketHandler.h
new file mode 100644
index 00000000000..940783c104b
--- /dev/null
+++ b/dep/sockets/include/ISocketHandler.h
@@ -0,0 +1,231 @@
+/** \file ISocketHandler.h
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_ISocketHandler_H
+#define _SOCKETS_ISocketHandler_H
+#include "sockets-config.h"
+
+#include <list>
+
+#include "socket_include.h"
+#include "Socket.h"
+#include "StdLog.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+typedef enum {
+ LIST_CALLONCONNECT = 0,
+#ifdef ENABLE_DETACH
+ LIST_DETACH,
+#endif
+ LIST_TIMEOUT,
+ LIST_RETRY,
+ LIST_CLOSE
+} list_t;
+
+class SocketAddress;
+class Mutex;
+
+/** Socket container class, event generator.
+ \ingroup basic */
+class ISocketHandler
+{
+ friend class Socket;
+
+public:
+ /** Connection pool class for internal use by the ISocketHandler.
+ \ingroup internal */
+#ifdef ENABLE_POOL
+ class PoolSocket : public Socket
+ {
+ public:
+ PoolSocket(ISocketHandler& h,Socket *src) : Socket(h) {
+ CopyConnection( src );
+ SetIsClient();
+ }
+
+ void OnRead() {
+ Handler().LogError(this, "OnRead", 0, "data on hibernating socket", LOG_LEVEL_FATAL);
+ SetCloseAndDelete();
+ }
+ void OnOptions(int,int,int,SOCKET) {}
+
+ };
+#endif
+
+public:
+ virtual ~ISocketHandler() {}
+
+ /** Get mutex reference for threadsafe operations. */
+ virtual Mutex& GetMutex() const = 0;
+
+ /** Register StdLog object for error callback.
+ \param log Pointer to log class */
+ virtual void RegStdLog(StdLog *log) = 0;
+
+ /** Log error to log class for print out / storage. */
+ virtual void LogError(Socket *p,const std::string& user_text,int err,const std::string& sys_err,loglevel_t t = LOG_LEVEL_WARNING) = 0;
+
+ // -------------------------------------------------------------------------
+ // Socket stuff
+ // -------------------------------------------------------------------------
+ /** Add socket instance to socket map. Removal is always automatic. */
+ virtual void Add(Socket *) = 0;
+private:
+ /** Remove socket from socket map, used by Socket class. */
+ virtual void Remove(Socket *) = 0;
+public:
+ /** Get status of read/write/exception file descriptor set for a socket. */
+ virtual void Get(SOCKET s,bool& r,bool& w,bool& e) = 0;
+ /** Set read/write/exception file descriptor sets (fd_set). */
+ virtual void Set(SOCKET s,bool bRead,bool bWrite,bool bException = true) = 0;
+
+ /** Wait for events, generate callbacks. */
+ virtual int Select(long sec,long usec) = 0;
+ /** This method will not return until an event has been detected. */
+ virtual int Select() = 0;
+ /** Wait for events, generate callbacks. */
+ virtual int Select(struct timeval *tsel) = 0;
+
+ /** Check that a socket really is handled by this socket handler. */
+ virtual bool Valid(Socket *) = 0;
+ /** Return number of sockets handled by this handler. */
+ virtual size_t GetCount() = 0;
+
+ /** Override and return false to deny all incoming connections.
+ \param p ListenSocket class pointer (use GetPort to identify which one) */
+ virtual bool OkToAccept(Socket *p) = 0;
+
+ /** Called by Socket when a socket changes state. */
+ virtual void AddList(SOCKET s,list_t which_one,bool add) = 0;
+
+ // -------------------------------------------------------------------------
+ // Connection pool
+ // -------------------------------------------------------------------------
+#ifdef ENABLE_POOL
+ /** Find available open connection (used by connection pool). */
+ virtual ISocketHandler::PoolSocket *FindConnection(int type,const std::string& protocol,SocketAddress&) = 0;
+ /** Enable connection pool (by default disabled). */
+ virtual void EnablePool(bool = true) = 0;
+ /** Check pool status.
+ \return true if connection pool is enabled */
+ virtual bool PoolEnabled() = 0;
+#endif // ENABLE_POOL
+
+ // -------------------------------------------------------------------------
+ // Socks4
+ // -------------------------------------------------------------------------
+#ifdef ENABLE_SOCKS4
+ /** Set socks4 server ip that all new tcp sockets should use. */
+ virtual void SetSocks4Host(ipaddr_t) = 0;
+ /** Set socks4 server hostname that all new tcp sockets should use. */
+ virtual void SetSocks4Host(const std::string& ) = 0;
+ /** Set socks4 server port number that all new tcp sockets should use. */
+ virtual void SetSocks4Port(port_t) = 0;
+ /** Set optional socks4 userid. */
+ virtual void SetSocks4Userid(const std::string& ) = 0;
+ /** If connection to socks4 server fails, immediately try direct connection to final host. */
+ virtual void SetSocks4TryDirect(bool = true) = 0;
+ /** Get socks4 server ip.
+ \return socks4 server ip */
+ virtual ipaddr_t GetSocks4Host() = 0;
+ /** Get socks4 port number.
+ \return socks4 port number */
+ virtual port_t GetSocks4Port() = 0;
+ /** Get socks4 userid (optional).
+ \return socks4 userid */
+ virtual const std::string& GetSocks4Userid() = 0;
+ /** Check status of socks4 try direct flag.
+ \return true if direct connection should be tried if connection to socks4 server fails */
+ virtual bool Socks4TryDirect() = 0;
+#endif // ENABLE_SOCKS4
+
+ // -------------------------------------------------------------------------
+ // DNS resolve server
+ // -------------------------------------------------------------------------
+#ifdef ENABLE_RESOLVER
+ /** Enable asynchronous DNS.
+ \param port Listen port of asynchronous dns server */
+ virtual void EnableResolver(port_t = 16667) = 0;
+ /** Check resolver status.
+ \return true if resolver is enabled */
+ virtual bool ResolverEnabled() = 0;
+ /** Queue a dns request.
+ \param host Hostname to be resolved
+ \param port Port number will be echoed in Socket::OnResolved callback */
+ virtual int Resolve(Socket *,const std::string& host,port_t port) = 0;
+#ifdef ENABLE_IPV6
+ virtual int Resolve6(Socket *,const std::string& host,port_t port) = 0;
+#endif
+ /** Do a reverse dns lookup. */
+ virtual int Resolve(Socket *,ipaddr_t a) = 0;
+#ifdef ENABLE_IPV6
+ virtual int Resolve(Socket *,in6_addr& a) = 0;
+#endif
+ /** Get listen port of asynchronous dns server. */
+ virtual port_t GetResolverPort() = 0;
+ /** Resolver thread ready for queries. */
+ virtual bool ResolverReady() = 0;
+ /** Returns true if socket waiting for a resolve event. */
+ virtual bool Resolving(Socket *) = 0;
+#endif // ENABLE_RESOLVER
+
+#ifdef ENABLE_TRIGGERS
+ /** Fetch unique trigger id. */
+ virtual int TriggerID(Socket *src) = 0;
+ /** Subscribe socket to trigger id. */
+ virtual bool Subscribe(int id, Socket *dst) = 0;
+ /** Unsubscribe socket from trigger id. */
+ virtual bool Unsubscribe(int id, Socket *dst) = 0;
+ /** Execute OnTrigger for subscribed sockets.
+ \param id Trigger ID
+ \param data Data passed from source to destination
+ \param erase Empty trigger id source and destination maps if 'true',
+ Leave them in place if 'false' - if a trigger should be called many times */
+ virtual void Trigger(int id, Socket::TriggerData& data, bool erase = true) = 0;
+#endif // ENABLE_TRIGGERS
+
+#ifdef ENABLE_DETACH
+ /** Indicates that the handler runs under SocketThread. */
+ virtual void SetSlave(bool x = true) = 0;
+ /** Indicates that the handler runs under SocketThread. */
+ virtual bool IsSlave() = 0;
+#endif // ENABLE_DETACH
+
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_ISocketHandler_H
+
+
diff --git a/dep/sockets/include/Ipv4Address.h b/dep/sockets/include/Ipv4Address.h
new file mode 100644
index 00000000000..71d925254e9
--- /dev/null
+++ b/dep/sockets/include/Ipv4Address.h
@@ -0,0 +1,95 @@
+/**
+ ** \file Ipv4Address.h
+ ** \date 2006-09-21
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_Ipv4Address_H
+#define _SOCKETS_Ipv4Address_H
+
+#include "sockets-config.h"
+#include "SocketAddress.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/* Ipv4 address implementation.
+ \ingroup basic */
+class Ipv4Address : public SocketAddress
+{
+public:
+ /** Create empty Ipv4 address structure.
+ \param port Port number */
+ Ipv4Address(port_t port = 0);
+ /** Create Ipv4 address structure.
+ \param a Socket address in network byte order (as returned by Utility::u2ip)
+ \param port Port number in host byte order */
+ Ipv4Address(ipaddr_t a,port_t port);
+ /** Create Ipv4 address structure.
+ \param a Socket address in network byte order
+ \param port Port number in host byte order */
+ Ipv4Address(struct in_addr& a,port_t port);
+ /** Create Ipv4 address structure.
+ \param host Hostname to be resolved
+ \param port Port number in host byte order */
+ Ipv4Address(const std::string& host,port_t port);
+ Ipv4Address(struct sockaddr_in&);
+ ~Ipv4Address();
+
+ // SocketAddress implementation
+
+ operator struct sockaddr *();
+ operator socklen_t();
+ bool operator==(SocketAddress&);
+
+ void SetPort(port_t port);
+ port_t GetPort();
+
+ void SetAddress(struct sockaddr *sa);
+ int GetFamily();
+
+ bool IsValid();
+ std::auto_ptr<SocketAddress> GetCopy();
+
+ /** Convert address struct to text. */
+ std::string Convert(bool include_port = false);
+ std::string Reverse();
+
+ /** Resolve hostname. */
+static bool Resolve(const std::string& hostname,struct in_addr& a);
+ /** Reverse resolve (IP to hostname). */
+static bool Reverse(struct in_addr& a,std::string& name);
+ /** Convert address struct to text. */
+static std::string Convert(struct in_addr& a);
+
+private:
+ Ipv4Address(const Ipv4Address& ) {} // copy constructor
+ Ipv4Address& operator=(const Ipv4Address& ) { return *this; } // assignment operator
+ struct sockaddr_in m_addr;
+ bool m_valid;
+};
+
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+#endif // _SOCKETS_Ipv4Address_H
+
+
diff --git a/dep/sockets/include/Ipv6Address.h b/dep/sockets/include/Ipv6Address.h
new file mode 100644
index 00000000000..20c68d8c92d
--- /dev/null
+++ b/dep/sockets/include/Ipv6Address.h
@@ -0,0 +1,105 @@
+/**
+ ** \file Ipv6Address.h
+ ** \date 2006-09-21
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_Ipv6Address_H
+#define _SOCKETS_Ipv6Address_H
+#include "sockets-config.h"
+#ifdef ENABLE_IPV6
+
+#include "SocketAddress.h"
+#ifdef IPPROTO_IPV6
+#if defined( _WIN32) && !defined(__CYGWIN__)
+typedef unsigned __int32 uint32_t;
+#endif
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** Ipv6 address implementation.
+ \ingroup basic */
+class Ipv6Address : public SocketAddress
+{
+public:
+ /** Create empty Ipv6 address structure.
+ \param port Port number */
+ Ipv6Address(port_t port = 0);
+ /** Create Ipv6 address structure.
+ \param a Socket address in network byte order
+ \param port Port number in host byte order */
+ Ipv6Address(struct in6_addr& a,port_t port);
+ /** Create Ipv6 address structure.
+ \param host Hostname to be resolved
+ \param port Port number in host byte order */
+ Ipv6Address(const std::string& host,port_t port);
+ Ipv6Address(struct sockaddr_in6&);
+ ~Ipv6Address();
+
+ // SocketAddress implementation
+
+ operator struct sockaddr *();
+ operator socklen_t();
+ bool operator==(SocketAddress&);
+
+ void SetPort(port_t port);
+ port_t GetPort();
+
+ void SetAddress(struct sockaddr *sa);
+ int GetFamily();
+
+ bool IsValid();
+ std::auto_ptr<SocketAddress> GetCopy();
+
+ /** Convert address struct to text. */
+ std::string Convert(bool include_port = false);
+ std::string Reverse();
+
+ /** Resolve hostname. */
+static bool Resolve(const std::string& hostname,struct in6_addr& a);
+ /** Reverse resolve (IP to hostname). */
+static bool Reverse(struct in6_addr& a,std::string& name);
+ /** Convert address struct to text. */
+static std::string Convert(struct in6_addr& a,bool mixed = false);
+
+ void SetFlowinfo(uint32_t);
+ uint32_t GetFlowinfo();
+#ifndef _WIN32
+ void SetScopeId(uint32_t);
+ uint32_t GetScopeId();
+#endif
+
+private:
+ Ipv6Address(const Ipv6Address& ) {} // copy constructor
+ Ipv6Address& operator=(const Ipv6Address& ) { return *this; } // assignment operator
+ struct sockaddr_in6 m_addr;
+ bool m_valid;
+};
+
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+#endif // IPPROTO_IPV6
+#endif // ENABLE_IPV6
+#endif // _SOCKETS_Ipv6Address_H
+
+
diff --git a/dep/sockets/include/ListenSocket.h b/dep/sockets/include/ListenSocket.h
new file mode 100644
index 00000000000..8934a809d0e
--- /dev/null
+++ b/dep/sockets/include/ListenSocket.h
@@ -0,0 +1,418 @@
+/** \file ListenSocket.h
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_ListenSocket_H
+#define _SOCKETS_ListenSocket_H
+#include "sockets-config.h"
+
+#ifdef _WIN32
+#include <stdlib.h>
+#else
+#include <errno.h>
+#endif
+
+#include "ISocketHandler.h"
+#include "Socket.h"
+#include "Utility.h"
+#include "SctpSocket.h"
+#include "Ipv4Address.h"
+#include "Ipv6Address.h"
+#ifdef ENABLE_EXCEPTIONS
+#include "Exception.h"
+#endif
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** Binds incoming port number to new Socket class X.
+ \ingroup basic */
+template <class X>
+class ListenSocket : public Socket
+{
+public:
+ /** Constructor.
+ \param h ISocketHandler reference
+ \param use_creator Optional use of creator (default true) */
+ ListenSocket(ISocketHandler& h,bool use_creator = true) : Socket(h), m_depth(0), m_creator(NULL)
+ ,m_bHasCreate(false)
+ {
+ if (use_creator)
+ {
+ m_creator = new X(h);
+ Socket *tmp = m_creator -> Create();
+ if (tmp && dynamic_cast<X *>(tmp))
+ {
+ m_bHasCreate = true;
+ }
+ if (tmp)
+ {
+ delete tmp;
+ }
+ }
+ }
+ ~ListenSocket() {
+ if (m_creator)
+ {
+ delete m_creator;
+ }
+ }
+
+ /** Close file descriptor. */
+ int Close() {
+ if (GetSocket() != INVALID_SOCKET)
+ {
+ closesocket(GetSocket());
+ }
+ return 0;
+ }
+
+ /** Bind and listen to any interface.
+ \param port Port (0 is random)
+ \param depth Listen queue depth */
+ int Bind(port_t port,int depth = 20) {
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ Ipv6Address ad(port);
+ return Bind(ad, depth);
+ }
+ else
+#endif
+#endif
+ {
+ Ipv4Address ad(port);
+ return Bind(ad, depth);
+ }
+ }
+
+ int Bind(SocketAddress& ad,int depth) {
+#ifdef USE_SCTP
+ if (dynamic_cast<SctpSocket *>(m_creator))
+ {
+ return Bind(ad, "sctp", depth);
+ }
+#endif
+ return Bind(ad, "tcp", depth);
+ }
+
+ /** Bind and listen to any interface, with optional protocol.
+ \param port Port (0 is random)
+ \param protocol Network protocol
+ \param depth Listen queue depth */
+ int Bind(port_t port,const std::string& protocol,int depth = 20) {
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ Ipv6Address ad(port);
+ return Bind(ad, protocol, depth);
+ }
+ else
+#endif
+#endif
+ {
+ Ipv4Address ad(port);
+ return Bind(ad, protocol, depth);
+ }
+ }
+
+ /** Bind and listen to specific interface.
+ \param intf Interface hostname
+ \param port Port (0 is random)
+ \param depth Listen queue depth */
+ int Bind(const std::string& intf,port_t port,int depth = 20) {
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ Ipv6Address ad(intf, port);
+ if (ad.IsValid())
+ {
+ return Bind(ad, depth);
+ }
+ Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
+ return -1;
+ }
+ else
+#endif
+#endif
+ {
+ Ipv4Address ad(intf, port);
+ if (ad.IsValid())
+ {
+ return Bind(ad, depth);
+ }
+ Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
+ return -1;
+ }
+ }
+
+ /** Bind and listen to specific interface.
+ \param intf Interface hostname
+ \param port Port (0 is random)
+ \param protocol Network protocol
+ \param depth Listen queue depth */
+ int Bind(const std::string& intf,port_t port,const std::string& protocol,int depth = 20) {
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (IsIpv6())
+ {
+ Ipv6Address ad(intf, port);
+ if (ad.IsValid())
+ {
+ return Bind(ad, protocol, depth);
+ }
+ Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
+ return -1;
+ }
+ else
+#endif
+#endif
+ {
+ Ipv4Address ad(intf, port);
+ if (ad.IsValid())
+ {
+ return Bind(ad, protocol, depth);
+ }
+ Handler().LogError(this, "Bind", 0, "name resolution of interface name failed", LOG_LEVEL_FATAL);
+ return -1;
+ }
+ }
+
+ /** Bind and listen to ipv4 interface.
+ \param a Ipv4 interface address
+ \param port Port (0 is random)
+ \param depth Listen queue depth */
+ int Bind(ipaddr_t a,port_t port,int depth = 20) {
+ Ipv4Address ad(a, port);
+#ifdef USE_SCTP
+ if (dynamic_cast<SctpSocket *>(m_creator))
+ {
+ return Bind(ad, "sctp", depth);
+ }
+#endif
+ return Bind(ad, "tcp", depth);
+ }
+ /** Bind and listen to ipv4 interface.
+ \param a Ipv4 interface address
+ \param port Port (0 is random)
+ \param protocol Network protocol
+ \param depth Listen queue depth */
+ int Bind(ipaddr_t a,port_t port,const std::string& protocol,int depth) {
+ Ipv4Address ad(a, port);
+ return Bind(ad, protocol, depth);
+ }
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Bind and listen to ipv6 interface.
+ \param a Ipv6 interface address
+ \param port Port (0 is random)
+ \param depth Listen queue depth */
+ int Bind(in6_addr a,port_t port,int depth = 20) {
+ Ipv6Address ad(a, port);
+#ifdef USE_SCTP
+ if (dynamic_cast<SctpSocket *>(m_creator))
+ {
+ return Bind(ad, "sctp", depth);
+ }
+#endif
+ return Bind(ad, "tcp", depth);
+ }
+ /** Bind and listen to ipv6 interface.
+ \param a Ipv6 interface address
+ \param port Port (0 is random)
+ \param protocol Network protocol
+ \param depth Listen queue depth */
+ int Bind(in6_addr a,port_t port,const std::string& protocol,int depth) {
+ Ipv6Address ad(a, port);
+ return Bind(ad, protocol, depth);
+ }
+#endif
+#endif
+
+ /** Bind and listen to network interface.
+ \param ad Interface address
+ \param protocol Network protocol
+ \param depth Listen queue depth */
+ int Bind(SocketAddress& ad,const std::string& protocol,int depth) {
+ SOCKET s;
+ if ( (s = CreateSocket(ad.GetFamily(), SOCK_STREAM, protocol)) == INVALID_SOCKET)
+ {
+ return -1;
+ }
+ if (bind(s, ad, ad) == -1)
+ {
+ Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ closesocket(s);
+#ifdef ENABLE_EXCEPTIONS
+ throw Exception("bind() failed for port " + Utility::l2string(ad.GetPort()) + ": " + StrError(Errno));
+#endif
+ return -1;
+ }
+ if (listen(s, depth) == -1)
+ {
+ Handler().LogError(this, "listen", Errno, StrError(Errno), LOG_LEVEL_FATAL);
+ closesocket(s);
+#ifdef ENABLE_EXCEPTIONS
+ throw Exception("listen() failed for port " + Utility::l2string(ad.GetPort()) + ": " + StrError(Errno));
+#endif
+ return -1;
+ }
+ m_depth = depth;
+ Attach(s);
+ return 0;
+ }
+
+ /** Return assigned port number. */
+ port_t GetPort()
+ {
+ return GetSockPort();
+ }
+
+ /** Return listen queue depth. */
+ int GetDepth()
+ {
+ return m_depth;
+ }
+
+ /** OnRead on a ListenSocket receives an incoming connection. */
+ void OnRead()
+ {
+ struct sockaddr sa;
+ socklen_t sa_len = sizeof(struct sockaddr);
+ SOCKET a_s = accept(GetSocket(), &sa, &sa_len);
+
+ if (a_s == INVALID_SOCKET)
+ {
+ Handler().LogError(this, "accept", Errno, StrError(Errno), LOG_LEVEL_ERROR);
+ return;
+ }
+ if (!Handler().OkToAccept(this))
+ {
+ Handler().LogError(this, "accept", -1, "Not OK to accept", LOG_LEVEL_WARNING);
+ closesocket(a_s);
+ return;
+ }
+ if (Handler().GetCount() >= FD_SETSIZE)
+ {
+ Handler().LogError(this, "accept", (int)Handler().GetCount(), "ISocketHandler fd_set limit reached", LOG_LEVEL_FATAL);
+ closesocket(a_s);
+ return;
+ }
+ Socket *tmp = m_bHasCreate ? m_creator -> Create() : new X(Handler());
+#ifdef ENABLE_IPV6
+ tmp -> SetIpv6( IsIpv6() );
+#endif
+ tmp -> SetParent(this);
+ tmp -> Attach(a_s);
+ tmp -> SetNonblocking(true);
+ {
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ if (sa_len == sizeof(struct sockaddr_in6))
+ {
+ struct sockaddr_in6 *p = (struct sockaddr_in6 *)&sa;
+ if (p -> sin6_family == AF_INET6)
+ {
+ Ipv6Address ad(p -> sin6_addr,ntohs(p -> sin6_port));
+ ad.SetFlowinfo(p -> sin6_flowinfo);
+#ifndef _WIN32
+ ad.SetScopeId(p -> sin6_scope_id);
+#endif
+ tmp -> SetRemoteAddress(ad);
+ }
+ }
+#endif
+#endif
+ if (sa_len == sizeof(struct sockaddr_in))
+ {
+ struct sockaddr_in *p = (struct sockaddr_in *)&sa;
+ if (p -> sin_family == AF_INET)
+ {
+ Ipv4Address ad(p -> sin_addr,ntohs(p -> sin_port));
+ tmp -> SetRemoteAddress(ad);
+ }
+ }
+ }
+ tmp -> SetConnected(true);
+ tmp -> Init();
+ tmp -> SetDeleteByHandler(true);
+ Handler().Add(tmp);
+#ifdef HAVE_OPENSSL
+ if (tmp -> IsSSL()) // SSL Enabled socket
+ {
+ // %! OnSSLAccept calls SSLNegotiate that can finish in this one call.
+ // %! If that happens and negotiation fails, the 'tmp' instance is
+ // %! still added to the list of active sockets in the sockethandler.
+ // %! See bugfix for this in SocketHandler::Select - don't Set rwx
+ // %! flags if CloseAndDelete() flag is true.
+ // %! An even better fugbix (see TcpSocket::OnSSLAccept) now avoids
+ // %! the Add problem altogether, so ignore the above.
+ // %! (OnSSLAccept does no longer call SSLNegotiate().)
+ tmp -> OnSSLAccept();
+ }
+ else
+#endif
+ {
+ tmp -> OnAccept();
+ }
+ }
+
+ /** Please don't use this method.
+ "accept()" is handled automatically in the OnRead() method. */
+ virtual SOCKET Accept(SOCKET socket, struct sockaddr *saptr, socklen_t *lenptr)
+ {
+ return accept(socket, saptr, lenptr);
+ }
+
+ bool HasCreator() { return m_bHasCreate; }
+
+ void OnOptions(int,int,int,SOCKET) {
+ SetSoReuseaddr(true);
+ }
+
+protected:
+ ListenSocket(const ListenSocket& s) : Socket(s) {}
+private:
+ ListenSocket& operator=(const ListenSocket& ) { return *this; }
+ int m_depth;
+ X *m_creator;
+ bool m_bHasCreate;
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_ListenSocket_H
+
+
diff --git a/dep/sockets/include/Lock.h b/dep/sockets/include/Lock.h
new file mode 100644
index 00000000000..f3bb9273920
--- /dev/null
+++ b/dep/sockets/include/Lock.h
@@ -0,0 +1,58 @@
+/** \file Lock.h
+ ** \date 2005-08-22
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2005,2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_Lock_H
+#define _SOCKETS_Lock_H
+
+#include "sockets-config.h"
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+class Mutex;
+
+/** Mutex encapsulation class.
+ \ingroup threading */
+class Lock
+{
+public:
+ Lock(Mutex&);
+ ~Lock();
+
+private:
+ Mutex& m_mutex;
+};
+
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+#endif // _SOCKETS_Lock_H
+
+
diff --git a/dep/sockets/include/Mutex.h b/dep/sockets/include/Mutex.h
new file mode 100644
index 00000000000..e42a57c3262
--- /dev/null
+++ b/dep/sockets/include/Mutex.h
@@ -0,0 +1,68 @@
+/** \file Mutex.h
+ ** \date 2004-10-30
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_Mutex_H
+#define _SOCKETS_Mutex_H
+
+#include "sockets-config.h"
+#ifndef _WIN32
+#include <pthread.h>
+#else
+#include <windows.h>
+#endif
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** Mutex container class, used by Lock.
+ \ingroup threading */
+class Mutex
+{
+ friend class Lock;
+public:
+ Mutex();
+ ~Mutex();
+
+ void Lock();
+ void Unlock();
+private:
+#ifdef _WIN32
+ HANDLE m_mutex;
+#else
+ pthread_mutex_t m_mutex;
+#endif
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+#endif // _SOCKETS_Mutex_H
+
+
diff --git a/dep/sockets/include/Parse.h b/dep/sockets/include/Parse.h
new file mode 100644
index 00000000000..52bd9327e28
--- /dev/null
+++ b/dep/sockets/include/Parse.h
@@ -0,0 +1,100 @@
+/** \file Parse.h - parse a string
+ **
+ ** Written: 1999-Feb-10 grymse@alhem.net
+ **/
+
+/*
+Copyright (C) 1999-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _SOCKETS_Parse_H
+#define _SOCKETS_Parse_H
+
+#include "sockets-config.h"
+#ifdef _MSC_VER
+#pragma warning(disable:4514)
+#endif
+
+#include <string>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/***************************************************/
+/* interface of class Parse */
+
+/** Splits a string whatever way you want.
+ \ingroup util */
+class Parse
+{
+public:
+ Parse();
+ Parse(const std::string&);
+ Parse(const std::string&,const std::string&);
+ Parse(const std::string&,const std::string&,short);
+ ~Parse();
+ short issplit(const char);
+ void getsplit();
+ void getsplit(std::string&);
+ std::string getword();
+ void getword(std::string&);
+ void getword(std::string&,std::string&,int);
+ std::string getrest();
+ void getrest(std::string&);
+ long getvalue();
+ void setbreak(const char);
+ int getwordlen();
+ int getrestlen();
+ void enablebreak(const char c) {
+ pa_enable = c;
+ }
+ void disablebreak(const char c) {
+ pa_disable = c;
+ }
+ void getline();
+ void getline(std::string&);
+ size_t getptr() { return pa_the_ptr; }
+ void EnableQuote(bool b) { pa_quote = b; }
+
+private:
+ std::string pa_the_str;
+ std::string pa_splits;
+ std::string pa_ord;
+ size_t pa_the_ptr;
+ char pa_breakchar;
+ char pa_enable;
+ char pa_disable;
+ short pa_nospace;
+ bool pa_quote;
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_Parse_H
+
+
diff --git a/dep/sockets/include/ResolvServer.h b/dep/sockets/include/ResolvServer.h
new file mode 100644
index 00000000000..409c9b7a619
--- /dev/null
+++ b/dep/sockets/include/ResolvServer.h
@@ -0,0 +1,72 @@
+/** \file ResolvServer.h
+ ** \date 2005-03-24
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_ResolvServer_H
+#define _SOCKETS_ResolvServer_H
+#include "sockets-config.h"
+#ifdef ENABLE_RESOLVER
+#include "socket_include.h"
+#include "Thread.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** \defgroup async Asynchronous DNS */
+/** Async DNS resolver thread.
+ \ingroup async */
+class ResolvServer : public Thread
+{
+public:
+ ResolvServer(port_t);
+ ~ResolvServer();
+
+ void Run();
+ void Quit();
+
+ bool Ready();
+
+private:
+ ResolvServer(const ResolvServer& ) {} // copy constructor
+ ResolvServer& operator=(const ResolvServer& ) { return *this; } // assignment operator
+
+ bool m_quit;
+ port_t m_port;
+ bool m_ready;
+};
+
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // ENABLE_RESOLVER
+#endif // _SOCKETS_ResolvServer_H
+
+
diff --git a/dep/sockets/include/ResolvSocket.h b/dep/sockets/include/ResolvSocket.h
new file mode 100644
index 00000000000..60743736e08
--- /dev/null
+++ b/dep/sockets/include/ResolvSocket.h
@@ -0,0 +1,105 @@
+/** \file ResolvSocket.h
+ ** \date 2005-03-24
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_ResolvSocket_H
+#define _SOCKETS_ResolvSocket_H
+#include "sockets-config.h"
+#ifdef ENABLE_RESOLVER
+#include "TcpSocket.h"
+#include <map>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+class Mutex;
+
+/** Async DNS resolver socket.
+ \ingroup async */
+class ResolvSocket : public TcpSocket
+{
+ typedef std::map<std::string, /* type */
+ std::map<std::string, std::string> > cache_t; /* host, result */
+ typedef std::map<std::string, /* type */
+ std::map<std::string, time_t> > timeout_t; /* host, time */
+
+public:
+ ResolvSocket(ISocketHandler&);
+ ResolvSocket(ISocketHandler&, Socket *parent, const std::string& host, port_t port, bool ipv6 = false);
+ ResolvSocket(ISocketHandler&, Socket *parent, ipaddr_t);
+#ifdef ENABLE_IPV6
+ ResolvSocket(ISocketHandler&, Socket *parent, in6_addr&);
+#endif
+ ~ResolvSocket();
+
+ void OnAccept() { m_bServer = true; }
+ void OnLine(const std::string& line);
+ void OnDetached();
+ void OnDelete();
+
+ void SetId(int x) { m_resolv_id = x; }
+ int GetId() { return m_resolv_id; }
+
+ void OnConnect();
+
+#ifdef ENABLE_IPV6
+ void SetResolveIpv6(bool x = true) { m_resolve_ipv6 = x; }
+#endif
+
+private:
+ ResolvSocket(const ResolvSocket& s) : TcpSocket(s) {} // copy constructor
+ ResolvSocket& operator=(const ResolvSocket& ) { return *this; } // assignment operator
+
+ std::string m_query;
+ std::string m_data;
+ bool m_bServer;
+ Socket *m_parent;
+ int m_resolv_id;
+ std::string m_resolv_host;
+ port_t m_resolv_port;
+ ipaddr_t m_resolv_address;
+#ifdef ENABLE_IPV6
+ bool m_resolve_ipv6;
+ in6_addr m_resolv_address6;
+#endif
+ static cache_t m_cache;
+ static timeout_t m_cache_to;
+ static Mutex m_cache_mutex;
+ bool m_cached;
+};
+
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // ENABLE_RESOLVER
+#endif // _SOCKETS_ResolvSocket_H
+
+
diff --git a/dep/sockets/include/SctpSocket.h b/dep/sockets/include/SctpSocket.h
new file mode 100644
index 00000000000..ed507fb1880
--- /dev/null
+++ b/dep/sockets/include/SctpSocket.h
@@ -0,0 +1,108 @@
+/**
+ ** \file SctpSocket.h
+ ** \date 2006-09-04
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_SctpSocket_H
+#define _SOCKETS_SctpSocket_H
+#include "sockets-config.h"
+
+#include "StreamSocket.h"
+#ifdef USE_SCTP
+#include <netinet/sctp.h>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+#define SCTP_BUFSIZE_READ 16400
+
+class SocketAddress;
+
+class SctpSocket : public StreamSocket
+{
+public:
+ /** SctpSocket constructor.
+ \param h Owner
+ \param type SCTP_STREAM or SCTP_SEQPACKET */
+ SctpSocket(ISocketHandler& h,int type);
+ ~SctpSocket();
+
+ /** bind() */
+ int Bind(const std::string&,port_t);
+ int Bind(SocketAddress&);
+ /** sctp_bindx() */
+ int AddAddress(const std::string&,port_t);
+ int AddAddress(SocketAddress&);
+ /** sctp_bindx() */
+ int RemoveAddress(const std::string&,port_t);
+ int RemoveAddress(SocketAddress&);
+
+ /** connect() */
+ int Open(const std::string&,port_t);
+ int Open(SocketAddress&);
+
+ /** Connect timeout callback. */
+ void OnConnectTimeout();
+#ifdef _WIN32
+ /** Connection failed reported as exception on win32 */
+ void OnException();
+#endif
+
+#ifndef SOLARIS
+ /** sctp_connectx() */
+ int AddConnection(const std::string&,port_t);
+ int AddConnection(SocketAddress&);
+#endif
+
+ /** Get peer addresses of an association. */
+ int getpaddrs(sctp_assoc_t id,std::list<std::string>&);
+ /** Get all bound addresses of an association. */
+ int getladdrs(sctp_assoc_t id,std::list<std::string>&);
+
+ /** sctp_peeloff */
+ int PeelOff(sctp_assoc_t id);
+
+ /** recvmsg callback */
+ virtual void OnReceiveMessage(const char *buf,size_t sz,struct sockaddr *sa,socklen_t sa_len,struct sctp_sndrcvinfo *sinfo,int msg_flags) = 0;
+
+ void OnOptions(int,int,int,SOCKET) {}
+
+ virtual int Protocol();
+
+protected:
+ SctpSocket(const SctpSocket& s) : StreamSocket(s) {}
+ void OnRead();
+ void OnWrite();
+
+private:
+ SctpSocket& operator=(const SctpSocket& s) { return *this; }
+ int m_type; ///< SCTP_STREAM or SCTP_SEQPACKET
+ char *m_buf; ///< Temporary receive buffer
+};
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE
+#endif
+
+#endif // USE_SCTP
+#endif // _SOCKETS_SctpSocket_H
+
+
diff --git a/dep/sockets/include/Socket.h b/dep/sockets/include/Socket.h
new file mode 100644
index 00000000000..23a806b5ea1
--- /dev/null
+++ b/dep/sockets/include/Socket.h
@@ -0,0 +1,735 @@
+/** \file Socket.h
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This software is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_Socket_H
+#define _SOCKETS_Socket_H
+#include "sockets-config.h"
+
+#include <string>
+#include <vector>
+#include <list>
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#endif
+
+#include "socket_include.h"
+#include <time.h>
+#include "SocketAddress.h"
+#include "Thread.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+class ISocketHandler;
+class SocketAddress;
+class IFile;
+
+/** \defgroup basic Basic sockets */
+/** Socket base class.
+ \ingroup basic */
+class Socket
+{
+ friend class ISocketHandler;
+#ifdef ENABLE_DETACH
+ /** Detached socket run thread.
+ \ingroup internal */
+ class SocketThread : public Thread
+ {
+ public:
+ SocketThread(Socket *p);
+ ~SocketThread();
+
+ void Run();
+
+ private:
+ Socket *GetSocket() const { return m_socket; }
+ SocketThread(const SocketThread& s) : m_socket(s.GetSocket()) {}
+ SocketThread& operator=(const SocketThread& ) { return *this; }
+ Socket *m_socket;
+ };
+#endif // ENABLE_DETACH
+
+#ifdef ENABLE_TRIGGERS
+public:
+ /** Data pass class from source to destination. */
+ class TriggerData
+ {
+ public:
+ TriggerData() : m_src(NULL) {}
+ virtual ~TriggerData() {}
+
+ Socket *GetSource() const { return m_src; }
+ void SetSource(Socket *x) { m_src = x; }
+
+ private:
+ Socket *m_src;
+ };
+#endif // ENABLE_TRIGGERS
+
+ /** Socket mode flags. */
+/*
+ enum {
+ // Socket
+ SOCK_DEL = 0x01, ///< Delete by handler flag
+ SOCK_CLOSE = 0x02, ///< Close and delete flag
+ SOCK_DISABLE_READ = 0x04, ///< Disable checking for read events
+ SOCK_CONNECTED = 0x08, ///< Socket is connected (tcp/udp)
+
+ SOCK_ERASED_BY_HANDLER = 0x10, ///< Set by handler before delete
+ // HAVE_OPENSSL
+ SOCK_ENABLE_SSL = 0x20, ///< Enable SSL for this TcpSocket
+ SOCK_SSL = 0x40, ///< ssl negotiation mode (TcpSocket)
+ SOCK_SSL_SERVER = 0x80, ///< True if this is an incoming ssl TcpSocket connection
+
+ // ENABLE_IPV6
+ SOCK_IPV6 = 0x0100, ///< This is an ipv6 socket if this one is true
+ // ENABLE_POOL
+ SOCK_CLIENT = 0x0200, ///< only client connections are pooled
+ SOCK_RETAIN = 0x0400, ///< keep connection on close
+ SOCK_LOST = 0x0800, ///< connection lost
+
+ // ENABLE_SOCKS4
+ SOCK_SOCKS4 = 0x1000, ///< socks4 negotiation mode (TcpSocket)
+ // ENABLE_DETACH
+ SOCK_DETACH = 0x2000, ///< Socket ordered to detach flag
+ SOCK_DETACHED = 0x4000, ///< Socket has been detached
+ // StreamSocket
+ STREAMSOCK_CONNECTING = 0x8000, ///< Flag indicating connection in progress
+
+ STREAMSOCK_FLUSH_BEFORE_CLOSE = 0x010000L, ///< Send all data before closing (default true)
+ STREAMSOCK_CALL_ON_CONNECT = 0x020000L, ///< OnConnect will be called next ISocketHandler cycle if true
+ STREAMSOCK_RETRY_CONNECT = 0x040000L, ///< Try another connection attempt next ISocketHandler cycle
+ STREAMSOCK_LINE_PROTOCOL = 0x080000L, ///< Line protocol mode flag
+
+ };
+*/
+
+public:
+ /** "Default" constructor */
+ Socket(ISocketHandler&);
+
+ virtual ~Socket();
+
+ /** Socket class instantiation method. Used when a "non-standard" constructor
+ * needs to be used for the socket class. Note: the socket class still needs
+ * the "default" constructor with one ISocketHandler& as input parameter.
+ */
+ virtual Socket *Create() { return NULL; }
+
+ /** Returns reference to sockethandler that owns the socket.
+ If the socket is detached, this is a reference to the slave sockethandler.
+ */
+ ISocketHandler& Handler() const;
+
+ /** Returns reference to sockethandler that owns the socket.
+ This one always returns the reference to the original sockethandler,
+ even if the socket is detached.
+ */
+ ISocketHandler& MasterHandler() const;
+
+ /** Called by ListenSocket after accept but before socket is added to handler.
+ * CTcpSocket uses this to create its ICrypt member variable.
+ * The ICrypt member variable is created by a virtual method, therefore
+ * it can't be called directly from the CTcpSocket constructor.
+ * Also used to determine if incoming HTTP connection is normal (port 80)
+ * or ssl (port 443).
+ */
+ virtual void Init();
+
+ /** Create a socket file descriptor.
+ \param af Address family AF_INET / AF_INET6 / ...
+ \param type SOCK_STREAM / SOCK_DGRAM / ...
+ \param protocol "tcp" / "udp" / ... */
+ SOCKET CreateSocket(int af,int type,const std::string& protocol = "");
+
+ /** Assign this socket a file descriptor created
+ by a call to socket() or otherwise. */
+ void Attach(SOCKET s);
+
+ /** Return file descriptor assigned to this socket. */
+ SOCKET GetSocket();
+
+ /** Close connection immediately - internal use.
+ \sa SetCloseAndDelete */
+ virtual int Close();
+
+ /** Add file descriptor to sockethandler fd_set's. */
+ void Set(bool bRead,bool bWrite,bool bException = true);
+
+ /** Returns true when socket file descriptor is valid
+ and socket is not about to be closed. */
+ virtual bool Ready();
+
+ /** Returns pointer to ListenSocket that created this instance
+ * on an incoming connection. */
+ Socket *GetParent();
+
+ /** Used by ListenSocket to set parent pointer of newly created
+ * socket instance. */
+ void SetParent(Socket *);
+
+ /** Get listening port from ListenSocket<>. */
+ virtual port_t GetPort();
+
+ /** Set socket non-block operation. */
+ bool SetNonblocking(bool);
+
+ /** Set socket non-block operation. */
+ bool SetNonblocking(bool, SOCKET);
+
+ /** Total lifetime of instance. */
+ time_t Uptime();
+
+ /** Set address/port of last connect() call. */
+ void SetClientRemoteAddress(SocketAddress&);
+
+ /** Get address/port of last connect() call. */
+ std::auto_ptr<SocketAddress> GetClientRemoteAddress();
+
+ /** Common interface for SendBuf used by Tcp and Udp sockets. */
+ virtual void SendBuf(const char *,size_t,int = 0);
+
+ /** Common interface for Send used by Tcp and Udp sockets. */
+ virtual void Send(const std::string&,int = 0);
+
+ /** Outgoing traffic counter. */
+ virtual uint64_t GetBytesSent(bool clear = false);
+
+ /** Incoming traffic counter. */
+ virtual uint64_t GetBytesReceived(bool clear = false);
+
+ // LIST_TIMEOUT
+
+ /** Enable timeout control. 0=disable timeout check. */
+ void SetTimeout(time_t secs);
+
+ /** Check timeout. \return true if time limit reached */
+ bool Timeout(time_t tnow);
+
+ /** Used by ListenSocket. ipv4 and ipv6 */
+ void SetRemoteAddress(SocketAddress&);
+
+ /** \name Event callbacks */
+ //@{
+
+ /** Called when there is something to be read from the file descriptor. */
+ virtual void OnRead();
+ /** Called when there is room for another write on the file descriptor. */
+ virtual void OnWrite();
+ /** Called on socket exception. */
+ virtual void OnException();
+ /** Called before a socket class is deleted by the ISocketHandler. */
+ virtual void OnDelete();
+ /** Called when a connection has completed. */
+ virtual void OnConnect();
+ /** Called when an incoming connection has been completed. */
+ virtual void OnAccept();
+ /** Called when a complete line has been read and the socket is in
+ * line protocol mode. */
+ virtual void OnLine(const std::string& );
+ /** Called on connect timeout (5s). */
+ virtual void OnConnectFailed();
+ /** Called when a client socket is created, to set socket options.
+ \param family AF_INET, AF_INET6, etc
+ \param type SOCK_STREAM, SOCK_DGRAM, etc
+ \param protocol Protocol number (tcp, udp, sctp, etc)
+ \param s Socket file descriptor
+ */
+ virtual void OnOptions(int family,int type,int protocol,SOCKET s) = 0;
+ /** Connection retry callback - return false to abort connection attempts */
+ virtual bool OnConnectRetry();
+#ifdef ENABLE_RECONNECT
+ /** a reconnect has been made */
+ virtual void OnReconnect();
+#endif
+ /** TcpSocket: When a disconnect has been detected (recv/SSL_read returns 0 bytes). */
+ virtual void OnDisconnect();
+ /** Timeout callback. */
+ virtual void OnTimeout();
+ /** Connection timeout. */
+ virtual void OnConnectTimeout();
+ //@}
+
+ /** \name Socket mode flags, set/reset */
+ //@{
+ /** Set delete by handler true when you want the sockethandler to
+ delete the socket instance after use. */
+ void SetDeleteByHandler(bool = true);
+ /** Check delete by handler flag.
+ \return true if this instance should be deleted by the sockethandler */
+ bool DeleteByHandler();
+
+ // LIST_CLOSE - conditional event queue
+
+ /** Set close and delete to terminate the connection. */
+ void SetCloseAndDelete(bool = true);
+ /** Check close and delete flag.
+ \return true if this socket should be closed and the instance removed */
+ bool CloseAndDelete();
+
+ /** Return number of seconds since socket was ordered to close. \sa SetCloseAndDelete */
+ time_t TimeSinceClose();
+
+ /** Ignore read events for an output only socket. */
+ void DisableRead(bool x = true);
+ /** Check ignore read events flag.
+ \return true if read events should be ignored */
+ bool IsDisableRead();
+
+ /** Set connected status. */
+ void SetConnected(bool = true);
+ /** Check connected status.
+ \return true if connected */
+ bool IsConnected();
+
+ /** Connection lost - error while reading/writing from a socket - TcpSocket only. */
+ void SetLost();
+ /** Check connection lost status flag, used by TcpSocket only.
+ \return true if there was an error while r/w causing the socket to close */
+ bool Lost();
+
+ /** Set flag indicating the socket is being actively deleted by the sockethandler. */
+ void SetErasedByHandler(bool x = true);
+ /** Get value of flag indicating socket is deleted by sockethandler. */
+ bool ErasedByHandler();
+
+ //@}
+
+ /** \name Information about remote connection */
+ //@{
+ /** Returns address of remote end. */
+ std::auto_ptr<SocketAddress> GetRemoteSocketAddress();
+ /** Returns address of remote end: ipv4. */
+ ipaddr_t GetRemoteIP4();
+#ifdef ENABLE_IPV6
+ /** Returns address of remote end: ipv6. */
+#ifdef IPPROTO_IPV6
+ struct in6_addr GetRemoteIP6();
+#endif
+#endif
+ /** Returns remote port number: ipv4 and ipv6. */
+ port_t GetRemotePort();
+ /** Returns remote ip as string? ipv4 and ipv6. */
+ std::string GetRemoteAddress();
+ /** ipv4 and ipv6(not implemented) */
+ std::string GetRemoteHostname();
+ //@}
+
+ /** Returns local port number for bound socket file descriptor. */
+ port_t GetSockPort();
+ /** Returns local ipv4 address for bound socket file descriptor. */
+ ipaddr_t GetSockIP4();
+ /** Returns local ipv4 address as text for bound socket file descriptor. */
+ std::string GetSockAddress();
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Returns local ipv6 address for bound socket file descriptor. */
+ struct in6_addr GetSockIP6();
+ /** Returns local ipv6 address as text for bound socket file descriptor. */
+ std::string GetSockAddress6();
+#endif
+#endif
+ // --------------------------------------------------------------------------
+ /** @name IP options
+ When an ip or socket option is available on all of the operating systems
+ I'm testing on (linux 2.4.x, _win32, macosx, solaris9 intel) they are not
+ checked with an #ifdef below.
+ This might cause a compile error on other operating systems. */
+ // --------------------------------------------------------------------------
+
+ // IP options
+ //@{
+
+ bool SetIpOptions(const void *p, socklen_t len);
+ bool SetIpTOS(unsigned char tos);
+ unsigned char IpTOS();
+ bool SetIpTTL(int ttl);
+ int IpTTL();
+ bool SetIpHdrincl(bool x = true);
+ bool SetIpMulticastTTL(int);
+ int IpMulticastTTL();
+ bool SetMulticastLoop(bool x = true);
+ bool IpAddMembership(struct ip_mreq&);
+ bool IpDropMembership(struct ip_mreq&);
+
+#ifdef IP_PKTINFO
+ bool SetIpPktinfo(bool x = true);
+#endif
+#ifdef IP_RECVTOS
+ bool SetIpRecvTOS(bool x = true);
+#endif
+#ifdef IP_RECVTTL
+ bool SetIpRecvTTL(bool x = true);
+#endif
+#ifdef IP_RECVOPTS
+ bool SetIpRecvopts(bool x = true);
+#endif
+#ifdef IP_RETOPTS
+ bool SetIpRetopts(bool x = true);
+#endif
+#ifdef IP_RECVERR
+ bool SetIpRecverr(bool x = true);
+#endif
+#ifdef IP_MTU_DISCOVER
+ bool SetIpMtudiscover(bool x = true);
+#endif
+#ifdef IP_MTU
+ int IpMtu();
+#endif
+#ifdef IP_ROUTER_ALERT
+ bool SetIpRouterAlert(bool x = true);
+#endif
+#ifdef LINUX
+ bool IpAddMembership(struct ip_mreqn&);
+#endif
+#ifdef LINUX
+ bool IpDropMembership(struct ip_mreqn&);
+#endif
+ //@}
+
+ // SOCKET options
+ /** @name Socket Options */
+ //@{
+
+ bool SoAcceptconn();
+ bool SetSoBroadcast(bool x = true);
+ bool SetSoDebug(bool x = true);
+ int SoError();
+ bool SetSoDontroute(bool x = true);
+ bool SetSoLinger(int onoff, int linger);
+ bool SetSoOobinline(bool x = true);
+ bool SetSoRcvlowat(int);
+ bool SetSoSndlowat(int);
+ bool SetSoRcvtimeo(struct timeval&);
+ bool SetSoSndtimeo(struct timeval&);
+ bool SetSoRcvbuf(int);
+ int SoRcvbuf();
+ bool SetSoSndbuf(int);
+ int SoSndbuf();
+ int SoType();
+ bool SetSoReuseaddr(bool x = true);
+ bool SetSoKeepalive(bool x = true);
+
+#ifdef SO_BSDCOMPAT
+ bool SetSoBsdcompat(bool x = true);
+#endif
+#ifdef SO_BINDTODEVICE
+ bool SetSoBindtodevice(const std::string& intf);
+#endif
+#ifdef SO_PASSCRED
+ bool SetSoPasscred(bool x = true);
+#endif
+#ifdef SO_PEERCRED
+ bool SoPeercred(struct ucred& );
+#endif
+#ifdef SO_PRIORITY
+ bool SetSoPriority(int);
+#endif
+#ifdef SO_RCVBUFFORCE
+ bool SetSoRcvbufforce(int);
+#endif
+#ifdef SO_SNDBUFFORCE
+ bool SetSoSndbufforce(int);
+#endif
+#ifdef SO_TIMESTAMP
+ bool SetSoTimestamp(bool x = true);
+#endif
+#ifdef SO_NOSIGPIPE
+ bool SetSoNosigpipe(bool x = true);
+#endif
+ //@}
+
+ // TCP options in TcpSocket.h/TcpSocket.cpp
+
+#ifdef HAVE_OPENSSL
+ /** @name SSL Support */
+ //@{
+ /** SSL client/server support - internal use. \sa TcpSocket */
+ virtual void OnSSLConnect();
+ /** SSL client/server support - internal use. \sa TcpSocket */
+ virtual void OnSSLAccept();
+ /** SSL negotiation failed for client connect. */
+ virtual void OnSSLConnectFailed();
+ /** SSL negotiation failed for server accept. */
+ virtual void OnSSLAcceptFailed();
+ /** new SSL support */
+ virtual bool SSLNegotiate();
+ /** Check if SSL is Enabled for this TcpSocket.
+ \return true if this is a TcpSocket with SSL enabled */
+ bool IsSSL();
+ /** Enable SSL operation for a TcpSocket. */
+ void EnableSSL(bool x = true);
+ /** Still negotiating ssl connection.
+ \return true if ssl negotiating is still in progress */
+ bool IsSSLNegotiate();
+ /** Set flag indicating ssl handshaking still in progress. */
+ void SetSSLNegotiate(bool x = true);
+ /** OnAccept called with SSL Enabled.
+ \return true if this is a TcpSocket with an incoming SSL connection */
+ bool IsSSLServer();
+ /** Set flag indicating that this is a TcpSocket with incoming SSL connection. */
+ void SetSSLServer(bool x = true);
+ /** SSL; Get pointer to ssl context structure. */
+ virtual SSL_CTX *GetSslContext() { return NULL; }
+ /** SSL; Get pointer to ssl structure. */
+ virtual SSL *GetSsl() { return NULL; }
+ //@}
+#endif // HAVE_OPENSSL
+
+#ifdef ENABLE_IPV6
+ /** Enable ipv6 for this socket. */
+ void SetIpv6(bool x = true);
+ /** Check ipv6 socket.
+ \return true if this is an ipv6 socket */
+ bool IsIpv6();
+#endif
+
+#ifdef ENABLE_POOL
+ /** @name Connection Pool */
+ //@{
+ /** Client = connecting TcpSocket. */
+ void SetIsClient();
+ /** Socket type from socket() call. */
+ void SetSocketType(int x);
+ /** Socket type from socket() call. */
+ int GetSocketType();
+ /** Protocol type from socket() call. */
+ void SetSocketProtocol(const std::string& x);
+ /** Protocol type from socket() call. */
+ const std::string& GetSocketProtocol();
+ /** Instruct a client socket to stay open in the connection pool after use.
+ If you have connected to a server using tcp, you can call SetRetain
+ to leave the connection open after your socket instance has been deleted.
+ The next connection you make to the same server will reuse the already
+ opened connection, if it is still available.
+ */
+ void SetRetain();
+ /** Check retain flag.
+ \return true if the socket should be moved to connection pool after use */
+ bool Retain();
+ /** Copy connection parameters from sock. */
+ void CopyConnection(Socket *sock);
+ //@}
+#endif // ENABLE_POOL
+
+#ifdef ENABLE_SOCKS4
+ /** \name Socks4 support */
+ //@{
+ /** Socks4 client support internal use. \sa TcpSocket */
+ virtual void OnSocks4Connect();
+ /** Socks4 client support internal use. \sa TcpSocket */
+ virtual void OnSocks4ConnectFailed();
+ /** Socks4 client support internal use. \sa TcpSocket */
+ virtual bool OnSocks4Read();
+ /** Called when the last write caused the tcp output buffer to
+ * become empty. */
+ /** socket still in socks4 negotiation mode */
+ bool Socks4();
+ /** Set flag indicating Socks4 handshaking in progress */
+ void SetSocks4(bool x = true);
+
+ /** Set socks4 server host address to use */
+ void SetSocks4Host(ipaddr_t a);
+ /** Set socks4 server hostname to use. */
+ void SetSocks4Host(const std::string& );
+ /** Socks4 server port to use. */
+ void SetSocks4Port(port_t p);
+ /** Provide a socks4 userid if required by the socks4 server. */
+ void SetSocks4Userid(const std::string& x);
+ /** Get the ip address of socks4 server to use.
+ \return socks4 server host address */
+ ipaddr_t GetSocks4Host();
+ /** Get the socks4 server port to use.
+ \return socks4 server port */
+ port_t GetSocks4Port();
+ /** Get socks4 userid.
+ \return Socks4 userid */
+ const std::string& GetSocks4Userid();
+ //@}
+#endif // ENABLE_SOCKS4
+
+#ifdef ENABLE_RESOLVER
+ /** \name Asynchronous Resolver */
+ //@{
+ /** Request an asynchronous dns resolution.
+ \param host hostname to be resolved
+ \param port port number passed along for the ride
+ \return Resolve ID */
+ int Resolve(const std::string& host,port_t port = 0);
+#ifdef ENABLE_IPV6
+ int Resolve6(const std::string& host, port_t port = 0);
+#endif
+ /** Callback returning a resolved address.
+ \param id Resolve ID from Resolve call
+ \param a resolved ip address
+ \param port port number passed to Resolve */
+ virtual void OnResolved(int id,ipaddr_t a,port_t port);
+#ifdef ENABLE_IPV6
+ virtual void OnResolved(int id,in6_addr& a,port_t port);
+#endif
+ /** Request asynchronous reverse dns lookup.
+ \param a in_addr to be translated */
+ int Resolve(ipaddr_t a);
+#ifdef ENABLE_IPV6
+ int Resolve(in6_addr& a);
+#endif
+ /** Callback returning reverse resolve results.
+ \param id Resolve ID
+ \param name Resolved hostname */
+ virtual void OnReverseResolved(int id,const std::string& name);
+ /** Callback indicating failed dns lookup.
+ \param id Resolve ID */
+ virtual void OnResolveFailed(int id);
+ //@}
+#endif // ENABLE_RESOLVER
+
+#ifdef ENABLE_DETACH
+ /** \name Thread Support */
+ //@{
+ /** Callback fires when a new socket thread has started and this
+ socket is ready for operation again.
+ \sa ResolvSocket */
+ virtual void OnDetached();
+
+ // LIST_DETACH
+
+ /** Internal use. */
+ void SetDetach(bool x = true);
+ /** Check detach flag.
+ \return true if the socket should detach to its own thread */
+ bool IsDetach();
+
+ /** Internal use. */
+ void SetDetached(bool x = true);
+ /** Check detached flag.
+ \return true if the socket runs in its own thread. */
+ const bool IsDetached() const;
+ /** Order this socket to start its own thread and call OnDetached
+ when ready for operation. */
+ bool Detach();
+ /** Store the slave sockethandler pointer. */
+ void SetSlaveHandler(ISocketHandler *);
+ /** Create new thread for this socket to run detached in. */
+ void DetachSocket();
+ //@}
+#endif // ENABLE_DETACH
+
+ /** Write traffic to an IFile. Socket will not delete this object. */
+ void SetTrafficMonitor(IFile *p) { m_traffic_monitor = p; }
+
+#ifdef ENABLE_TRIGGERS
+ /** \name Triggers */
+ //@{
+ /** Subscribe to trigger id. */
+ void Subscribe(int id);
+ /** Unsubscribe from trigger id. */
+ void Unsubscribe(int id);
+ /** Trigger callback, with data passed from source to destination. */
+ virtual void OnTrigger(int id, const TriggerData& data);
+ /** Trigger cancelled because source has been deleted (as in delete). */
+ virtual void OnCancelled(int id);
+ //@}
+#endif
+
+protected:
+ /** default constructor not available */
+ Socket() : m_handler(m_handler) {}
+ /** copy constructor not available */
+ Socket(const Socket& s) : m_handler(s.m_handler) {}
+
+ /** assignment operator not available. */
+ Socket& operator=(const Socket& ) { return *this; }
+
+ /** All traffic will be written to this IFile, if set. */
+ IFile *GetTrafficMonitor() { return m_traffic_monitor; }
+
+// unsigned long m_flags; ///< boolean flags, replacing old 'bool' members
+
+private:
+ ISocketHandler& m_handler; ///< Reference of ISocketHandler in control of this socket
+ SOCKET m_socket; ///< File descriptor
+ bool m_bDel; ///< Delete by handler flag
+ bool m_bClose; ///< Close and delete flag
+ time_t m_tCreate; ///< Time in seconds when this socket was created
+ Socket *m_parent; ///< Pointer to ListenSocket class, valid for incoming sockets
+ bool m_b_disable_read; ///< Disable checking for read events
+ bool m_connected; ///< Socket is connected (tcp/udp)
+ bool m_b_erased_by_handler; ///< Set by handler before delete
+ time_t m_tClose; ///< Time in seconds when ordered to close
+ std::auto_ptr<SocketAddress> m_client_remote_address; ///< Address of last connect()
+ std::auto_ptr<SocketAddress> m_remote_address; ///< Remote end address
+ IFile *m_traffic_monitor;
+ time_t m_timeout_start; ///< Set by SetTimeout
+ time_t m_timeout_limit; ///< Defined by SetTimeout
+ bool m_bLost; ///< connection lost
+
+#ifdef _WIN32
+static WSAInitializer m_winsock_init; ///< Winsock initialization singleton class
+#endif
+
+#ifdef HAVE_OPENSSL
+ bool m_b_enable_ssl; ///< Enable SSL for this TcpSocket
+ bool m_b_ssl; ///< ssl negotiation mode (TcpSocket)
+ bool m_b_ssl_server; ///< True if this is an incoming ssl TcpSocket connection
+#endif
+
+#ifdef ENABLE_IPV6
+ bool m_ipv6; ///< This is an ipv6 socket if this one is true
+#endif
+
+#ifdef ENABLE_POOL
+ int m_socket_type; ///< Type of socket, from socket() call
+ std::string m_socket_protocol; ///< Protocol, from socket() call
+ bool m_bClient; ///< only client connections are pooled
+ bool m_bRetain; ///< keep connection on close
+#endif
+
+#ifdef ENABLE_SOCKS4
+ bool m_bSocks4; ///< socks4 negotiation mode (TcpSocket)
+ ipaddr_t m_socks4_host; ///< socks4 server address
+ port_t m_socks4_port; ///< socks4 server port number
+ std::string m_socks4_userid; ///< socks4 server usedid
+#endif
+
+#ifdef ENABLE_DETACH
+ bool m_detach; ///< Socket ordered to detach flag
+ bool m_detached; ///< Socket has been detached
+ SocketThread *m_pThread; ///< Detach socket thread class pointer
+ ISocketHandler *m_slave_handler; ///< Actual sockethandler while detached
+#endif
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_Socket_H
+
+
diff --git a/dep/sockets/include/SocketAddress.h b/dep/sockets/include/SocketAddress.h
new file mode 100644
index 00000000000..abdbbfd2cf6
--- /dev/null
+++ b/dep/sockets/include/SocketAddress.h
@@ -0,0 +1,93 @@
+/**
+ ** \file SocketAddress.h
+ ** \date 2006-09-21
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_SocketAddress_H
+#define _SOCKETS_SocketAddress_H
+
+#include "sockets-config.h"
+#include <string>
+#include <memory>
+#include "socket_include.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/**
+ This class and its subclasses is intended to be used as replacement
+ for the internal data type 'ipaddr_t' and various implementations of
+ IPv6 addressing found throughout the library.
+ 'ipaddr_t' is an IPv4 address in network byte order.
+ 'port_t' is the portnumber in host byte order.
+ 'struct in6_addr' is an IPv6 address.
+ 'struct in_addr' is an IPv4 address.
+ \ingroup basic
+*/
+class SocketAddress
+{
+public:
+ virtual ~SocketAddress() {}
+
+ /** Get a pointer to the address struct. */
+ virtual operator struct sockaddr *() = 0;
+
+ /** Get length of address struct. */
+ virtual operator socklen_t() = 0;
+
+ /** Compare two addresses. */
+ virtual bool operator==(SocketAddress&) = 0;
+
+ /** Set port number.
+ \param port Port number in host byte order */
+ virtual void SetPort(port_t port) = 0;
+
+ /** Get port number.
+ \return Port number in host byte order. */
+ virtual port_t GetPort() = 0;
+
+ /** Set socket address.
+ \param sa Pointer to either 'struct sockaddr_in' or 'struct sockaddr_in6'. */
+ virtual void SetAddress(struct sockaddr *sa) = 0;
+
+ /** Convert address to text. */
+ virtual std::string Convert(bool include_port) = 0;
+
+ /** Reverse lookup of address. */
+ virtual std::string Reverse() = 0;
+
+ /** Get address family. */
+ virtual int GetFamily() = 0;
+
+ /** Address structure is valid. */
+ virtual bool IsValid() = 0;
+
+ /** Get a copy of this SocketAddress object. */
+ virtual std::auto_ptr<SocketAddress> GetCopy() = 0;
+};
+
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+#endif // _SOCKETS_SocketAddress_H
+
+
diff --git a/dep/sockets/include/SocketHandler.h b/dep/sockets/include/SocketHandler.h
new file mode 100644
index 00000000000..5598ec4249b
--- /dev/null
+++ b/dep/sockets/include/SocketHandler.h
@@ -0,0 +1,265 @@
+/** \file SocketHandler.h
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_SocketHandler_H
+#define _SOCKETS_SocketHandler_H
+
+#include "sockets-config.h"
+#include <map>
+#include <list>
+
+#include "socket_include.h"
+#include "ISocketHandler.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+class Socket;
+#ifdef ENABLE_RESOLVER
+class ResolvServer;
+#endif
+class Mutex;
+
+/** Socket container class, event generator.
+ \ingroup basic */
+class SocketHandler : public ISocketHandler
+{
+protected:
+ /** Map type for holding file descriptors/socket object pointers. */
+ typedef std::map<SOCKET,Socket *> socket_m;
+
+public:
+ /** SocketHandler constructor.
+ \param log Optional log class pointer */
+ SocketHandler(StdLog *log = NULL);
+
+ /** SocketHandler threadsafe constructor.
+ \param mutex Externally declared mutex variable
+ \param log Optional log class pointer */
+ SocketHandler(Mutex& mutex,StdLog *log = NULL);
+
+ ~SocketHandler();
+
+ /** Get mutex reference for threadsafe operations. */
+ Mutex& GetMutex() const;
+
+ /** Register StdLog object for error callback.
+ \param log Pointer to log class */
+ void RegStdLog(StdLog *log);
+
+ /** Log error to log class for print out / storage. */
+ void LogError(Socket *p,const std::string& user_text,int err,const std::string& sys_err,loglevel_t t = LOG_LEVEL_WARNING);
+
+ /** Add socket instance to socket map. Removal is always automatic. */
+ void Add(Socket *);
+
+ /** Get status of read/write/exception file descriptor set for a socket. */
+ void Get(SOCKET s,bool& r,bool& w,bool& e);
+
+ /** Set read/write/exception file descriptor sets (fd_set). */
+ void Set(SOCKET s,bool bRead,bool bWrite,bool bException = true);
+
+ /** Wait for events, generate callbacks. */
+ int Select(long sec,long usec);
+
+ /** This method will not return until an event has been detected. */
+ int Select();
+
+ /** Wait for events, generate callbacks. */
+ int Select(struct timeval *tsel);
+
+ /** Check that a socket really is handled by this socket handler. */
+ bool Valid(Socket *);
+
+ /** Return number of sockets handled by this handler. */
+ size_t GetCount();
+
+ /** Override and return false to deny all incoming connections.
+ \param p ListenSocket class pointer (use GetPort to identify which one) */
+ bool OkToAccept(Socket *p);
+
+ /** Called by Socket when a socket changes state. */
+ void AddList(SOCKET s,list_t which_one,bool add);
+
+ // Connection pool
+#ifdef ENABLE_POOL
+ /** Find available open connection (used by connection pool). */
+ ISocketHandler::PoolSocket *FindConnection(int type,const std::string& protocol,SocketAddress&);
+ /** Enable connection pool (by default disabled). */
+ void EnablePool(bool x = true);
+ /** Check pool status.
+ \return true if connection pool is enabled */
+ bool PoolEnabled();
+#endif // ENABLE_POOL
+
+ // Socks4
+#ifdef ENABLE_SOCKS4
+ /** Set socks4 server ip that all new tcp sockets should use. */
+ void SetSocks4Host(ipaddr_t);
+ /** Set socks4 server hostname that all new tcp sockets should use. */
+ void SetSocks4Host(const std::string& );
+ /** Set socks4 server port number that all new tcp sockets should use. */
+ void SetSocks4Port(port_t);
+ /** Set optional socks4 userid. */
+ void SetSocks4Userid(const std::string& );
+ /** If connection to socks4 server fails, immediately try direct connection to final host. */
+ void SetSocks4TryDirect(bool x = true);
+ /** Get socks4 server ip.
+ \return socks4 server ip */
+ ipaddr_t GetSocks4Host();
+ /** Get socks4 port number.
+ \return socks4 port number */
+ port_t GetSocks4Port();
+ /** Get socks4 userid (optional).
+ \return socks4 userid */
+ const std::string& GetSocks4Userid();
+ /** Check status of socks4 try direct flag.
+ \return true if direct connection should be tried if connection to socks4 server fails */
+ bool Socks4TryDirect();
+#endif // ENABLE_SOCKS4
+
+ // DNS resolve server
+#ifdef ENABLE_RESOLVER
+ /** Enable asynchronous DNS.
+ \param port Listen port of asynchronous dns server */
+ void EnableResolver(port_t port = 16667);
+ /** Check resolver status.
+ \return true if resolver is enabled */
+ bool ResolverEnabled();
+ /** Queue a dns request.
+ \param host Hostname to be resolved
+ \param port Port number will be echoed in Socket::OnResolved callback */
+ int Resolve(Socket *,const std::string& host,port_t port);
+#ifdef ENABLE_IPV6
+ int Resolve6(Socket *,const std::string& host,port_t port);
+#endif
+ /** Do a reverse dns lookup. */
+ int Resolve(Socket *,ipaddr_t a);
+#ifdef ENABLE_IPV6
+ int Resolve(Socket *,in6_addr& a);
+#endif
+ /** Get listen port of asynchronous dns server. */
+ port_t GetResolverPort();
+ /** Resolver thread ready for queries. */
+ bool ResolverReady();
+ /** Returns true if the socket is waiting for a resolve event. */
+ bool Resolving(Socket *);
+#endif // ENABLE_RESOLVER
+
+#ifdef ENABLE_TRIGGERS
+ /** Fetch unique trigger id. */
+ int TriggerID(Socket *src);
+ /** Subscribe socket to trigger id. */
+ bool Subscribe(int id, Socket *dst);
+ /** Unsubscribe socket from trigger id. */
+ bool Unsubscribe(int id, Socket *dst);
+ /** Execute OnTrigger for subscribed sockets.
+ \param id Trigger ID
+ \param data Data passed from source to destination
+ \param erase Empty trigger id source and destination maps if 'true',
+ Leave them in place if 'false' - if a trigger should be called many times */
+ void Trigger(int id, Socket::TriggerData& data, bool erase = true);
+#endif // ENABLE_TRIGGERS
+
+#ifdef ENABLE_DETACH
+ /** Indicates that the handler runs under SocketThread. */
+ void SetSlave(bool x = true);
+ /** Indicates that the handler runs under SocketThread. */
+ bool IsSlave();
+#endif
+
+ /** Sanity check of those accursed lists. */
+ void CheckSanity();
+
+protected:
+ socket_m m_sockets; ///< Active sockets map
+ socket_m m_add; ///< Sockets to be added to sockets map
+ std::list<Socket *> m_delete; ///< Sockets to be deleted (failed when Add)
+
+protected:
+ StdLog *m_stdlog; ///< Registered log class, or NULL
+ Mutex& m_mutex; ///< Thread safety mutex
+ bool m_b_use_mutex; ///< Mutex correctly initialized
+
+private:
+ void CheckList(socket_v&,const std::string&); ///< Used by CheckSanity
+ /** Remove socket from socket map, used by Socket class. */
+ void Remove(Socket *);
+ SOCKET m_maxsock; ///< Highest file descriptor + 1 in active sockets list
+ fd_set m_rfds; ///< file descriptor set monitored for read events
+ fd_set m_wfds; ///< file descriptor set monitored for write events
+ fd_set m_efds; ///< file descriptor set monitored for exceptions
+ int m_preverror; ///< debug select() error
+ int m_errcnt; ///< debug select() error
+ time_t m_tlast; ///< timeout control
+
+ // state lists
+ socket_v m_fds; ///< Active file descriptor list
+ socket_v m_fds_erase; ///< File descriptors that are to be erased from m_sockets
+ socket_v m_fds_callonconnect; ///< checklist CallOnConnect
+#ifdef ENABLE_DETACH
+ socket_v m_fds_detach; ///< checklist Detach
+#endif
+ socket_v m_fds_timeout; ///< checklist timeout
+ socket_v m_fds_retry; ///< checklist retry client connect
+ socket_v m_fds_close; ///< checklist close and delete
+
+#ifdef ENABLE_SOCKS4
+ ipaddr_t m_socks4_host; ///< Socks4 server host ip
+ port_t m_socks4_port; ///< Socks4 server port number
+ std::string m_socks4_userid; ///< Socks4 userid
+ bool m_bTryDirect; ///< Try direct connection if socks4 server fails
+#endif
+#ifdef ENABLE_RESOLVER
+ int m_resolv_id; ///< Resolver id counter
+ ResolvServer *m_resolver; ///< Resolver thread pointer
+ port_t m_resolver_port; ///< Resolver listen port
+ std::map<Socket *, bool> m_resolve_q; ///< resolve queue
+#endif
+#ifdef ENABLE_POOL
+ bool m_b_enable_pool; ///< Connection pool enabled if true
+#endif
+#ifdef ENABLE_TRIGGERS
+ int m_next_trigger_id; ///< Unique trigger id counter
+ std::map<int, Socket *> m_trigger_src; ///< mapping trigger id to source socket
+ std::map<int, std::map<Socket *, bool> > m_trigger_dst; ///< mapping trigger id to destination sockets
+#endif
+#ifdef ENABLE_DETACH
+ bool m_slave; ///< Indicates that this is a ISocketHandler run in SocketThread
+#endif
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_SocketHandler_H
+
+
diff --git a/dep/sockets/include/StdLog.h b/dep/sockets/include/StdLog.h
new file mode 100644
index 00000000000..3ff68d6e9ea
--- /dev/null
+++ b/dep/sockets/include/StdLog.h
@@ -0,0 +1,73 @@
+/** \file StdLog.h
+ ** \date 2004-06-01
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_StdLog_H
+#define _SOCKETS_StdLog_H
+
+#include "sockets-config.h"
+#include <string>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** error level enum. */
+typedef enum
+{
+ LOG_LEVEL_WARNING = 0,
+ LOG_LEVEL_ERROR,
+ LOG_LEVEL_FATAL,
+ LOG_LEVEL_INFO
+} loglevel_t;
+
+class ISocketHandler;
+class Socket;
+
+/** \defgroup logging Log help classes */
+/** Log class interface.
+ \ingroup logging */
+class StdLog
+{
+public:
+ virtual ~StdLog() {}
+
+ virtual void error(ISocketHandler *,Socket *,
+ const std::string& user_text,
+ int err,
+ const std::string& sys_err,
+ loglevel_t = LOG_LEVEL_WARNING) = 0;
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_StdLog_H
+
+
diff --git a/dep/sockets/include/StdoutLog.h b/dep/sockets/include/StdoutLog.h
new file mode 100644
index 00000000000..aeb25b3e6e6
--- /dev/null
+++ b/dep/sockets/include/StdoutLog.h
@@ -0,0 +1,55 @@
+/** \file StdoutLog.h
+ ** \date 2004-06-01
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_StdoutLog_H
+#define _SOCKETS_StdoutLog_H
+
+#include "sockets-config.h"
+#include "StdLog.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** StdLog implementation, logs to stdout.
+ \ingroup logging */
+class StdoutLog : public StdLog
+{
+public:
+ void error(ISocketHandler *,Socket *,const std::string& call,int err,const std::string& sys_err,loglevel_t);
+};
+
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_StdoutLog_H
+
+
diff --git a/dep/sockets/include/StreamSocket.h b/dep/sockets/include/StreamSocket.h
new file mode 100644
index 00000000000..bcce10ffbc5
--- /dev/null
+++ b/dep/sockets/include/StreamSocket.h
@@ -0,0 +1,124 @@
+#ifndef _StreamSocket_H
+#define _StreamSocket_H
+
+#include "Socket.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** SOCK_STREAM Socket base class.
+ \ingroup basic */
+class StreamSocket : public Socket
+{
+public:
+ StreamSocket(ISocketHandler& );
+ ~StreamSocket();
+
+ /** Socket should Check Connect on next write event from select(). */
+ void SetConnecting(bool = true);
+
+ /** Check connecting flag.
+ \return true if the socket is still trying to connect */
+ bool Connecting();
+
+ /** Returns true when socket file descriptor is valid,
+ socket connection is established, and socket is not about to
+ be closed. */
+ bool Ready();
+
+ /** Set timeout to use for connection attempt.
+ \param x Timeout in seconds */
+ void SetConnectTimeout(int x);
+
+ /** Return number of seconds to wait for a connection.
+ \return Connection timeout (seconds) */
+ int GetConnectTimeout();
+
+ /** Set flush before close to make a tcp socket completely empty its
+ output buffer before closing the connection. */
+ void SetFlushBeforeClose(bool = true);
+
+ /** Check flush before status.
+ \return true if the socket should send all data before closing */
+ bool GetFlushBeforeClose();
+
+ /** Define number of connection retries (tcp only).
+ n = 0 - no retry
+ n > 0 - number of retries
+ n = -1 - unlimited retries */
+ void SetConnectionRetry(int n);
+
+ /** Get number of maximum connection retries (tcp only). */
+ int GetConnectionRetry();
+
+ /** Increase number of actual connection retries (tcp only). */
+ void IncreaseConnectionRetries();
+
+ /** Get number of actual connection retries (tcp only). */
+ int GetConnectionRetries();
+
+ /** Reset actual connection retries (tcp only). */
+ void ResetConnectionRetries();
+
+ // LIST_CALLONCONNECT
+
+ /** Instruct socket to call OnConnect callback next sockethandler cycle. */
+ void SetCallOnConnect(bool x = true);
+
+ /** Check call on connect flag.
+ \return true if OnConnect() should be called a.s.a.p */
+ bool CallOnConnect();
+
+ // LIST_RETRY
+
+ /** Set flag to initiate a connection attempt after a connection timeout. */
+ void SetRetryClientConnect(bool x = true);
+
+ /** Check if a connection attempt should be made.
+ \return true when another attempt should be made */
+ bool RetryClientConnect();
+
+ /** Called after OnRead if socket is in line protocol mode.
+ \sa SetLineProtocol */
+ /** Enable the OnLine callback. Do not create your own OnRead
+ * callback when using this. */
+ virtual void SetLineProtocol(bool = true);
+
+ /** Check line protocol mode.
+ \return true if socket is in line protocol mode */
+ bool LineProtocol();
+
+ /** Set shutdown status. */
+ void SetShutdown(int);
+
+ /** Get shutdown status. */
+ int GetShutdown();
+
+ /** Returns IPPROTO_TCP or IPPROTO_SCTP */
+ virtual int Protocol() = 0;
+
+protected:
+ StreamSocket(const StreamSocket& ) {} // copy constructor
+
+private:
+ StreamSocket& operator=(const StreamSocket& ) { return *this; } // assignment operator
+
+ bool m_bConnecting; ///< Flag indicating connection in progress
+ int m_connect_timeout; ///< Connection timeout (seconds)
+ bool m_flush_before_close; ///< Send all data before closing (default true)
+ int m_connection_retry; ///< Maximum connection retries (tcp)
+ int m_retries; ///< Actual number of connection retries (tcp)
+ bool m_call_on_connect; ///< OnConnect will be called next ISocketHandler cycle if true
+ bool m_b_retry_connect; ///< Try another connection attempt next ISocketHandler cycle
+ bool m_line_protocol; ///< Line protocol mode flag
+ int m_shutdown; ///< Shutdown status
+};
+
+#ifdef SOCKETS_NAMESPACE
+} // namespace SOCKETS_NAMESPACE {
+#endif
+
+#endif // _StreamSocket_H
+
+
diff --git a/dep/sockets/include/TcpSocket.h b/dep/sockets/include/TcpSocket.h
new file mode 100644
index 00000000000..de1be8bd8b9
--- /dev/null
+++ b/dep/sockets/include/TcpSocket.h
@@ -0,0 +1,356 @@
+/** \file TcpSocket.h
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_TcpSocket_H
+#define _SOCKETS_TcpSocket_H
+#include "sockets-config.h"
+#include "StreamSocket.h"
+#ifdef HAVE_OPENSSL
+#include <openssl/ssl.h>
+#include "SSLInitializer.h"
+#endif
+
+#include <string.h>
+
+#define TCP_BUFSIZE_READ 16400
+#define TCP_OUTPUT_CAPACITY 1024000
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+class SocketAddress;
+
+/** Socket implementation for TCP.
+ \ingroup basic */
+class TcpSocket : public StreamSocket
+{
+ /** \defgroup internal Internal utility */
+protected:
+ /** Buffer class containing one read/write circular buffer.
+ \ingroup internal */
+ class CircularBuffer
+ {
+ public:
+ CircularBuffer(size_t size);
+ ~CircularBuffer();
+
+ /** append l bytes from p to buffer */
+ bool Write(const char *p,size_t l);
+ /** copy l bytes from buffer to dest */
+ bool Read(char *dest,size_t l);
+ /** copy l bytes from buffer to dest, dont touch buffer pointers */
+ bool SoftRead(char *dest, size_t l);
+ /** skip l bytes from buffer */
+ bool Remove(size_t l);
+ /** read l bytes from buffer, returns as string. */
+ std::string ReadString(size_t l);
+
+ /** total buffer length */
+ size_t GetLength();
+ /** pointer to circular buffer beginning */
+ const char *GetStart();
+ /** return number of bytes from circular buffer beginning to buffer physical end */
+ size_t GetL();
+ /** return free space in buffer, number of bytes until buffer overrun */
+ size_t Space();
+
+ /** return total number of bytes written to this buffer, ever */
+ unsigned long ByteCounter(bool clear = false);
+
+ private:
+ CircularBuffer(const CircularBuffer& /*s*/) {}
+ CircularBuffer& operator=(const CircularBuffer& ) { return *this; }
+ char *buf;
+ size_t m_max;
+ size_t m_q;
+ size_t m_b;
+ size_t m_t;
+ unsigned long m_count;
+ };
+ /** Output buffer struct.
+ \ingroup internal */
+ struct OUTPUT {
+ OUTPUT() : _b(0), _t(0), _q(0) {}
+ OUTPUT(const char *buf, size_t len) : _b(0), _t(len), _q(len) {
+ memcpy(_buf, buf, len);
+ }
+ size_t Space() {
+ return TCP_OUTPUT_CAPACITY - _t;
+ }
+ void Add(const char *buf, size_t len) {
+ memcpy(_buf + _t, buf, len);
+ _t += len;
+ _q += len;
+ }
+ size_t Remove(size_t len) {
+ _b += len;
+ _q -= len;
+ return _q;
+ }
+ const char *Buf() {
+ return _buf + _b;
+ }
+ size_t Len() {
+ return _q;
+ }
+ size_t _b;
+ size_t _t;
+ size_t _q;
+ char _buf[TCP_OUTPUT_CAPACITY];
+ };
+ typedef std::list<OUTPUT *> output_l;
+
+public:
+ /** Constructor with standard values on input/output buffers. */
+ TcpSocket(ISocketHandler& );
+ /** Constructor with custom values for i/o buffer.
+ \param h ISocketHandler reference
+ \param isize Input buffer size
+ \param osize Output buffer size */
+ TcpSocket(ISocketHandler& h,size_t isize,size_t osize);
+ ~TcpSocket();
+
+ /** Open a connection to a remote server.
+ If you want your socket to connect to a server,
+ always call Open before Add'ing a socket to the sockethandler.
+ If not, the connection attempt will not be monitored by the
+ socket handler...
+ \param ip IP address
+ \param port Port number
+ \param skip_socks Do not use socks4 even if configured */
+ bool Open(ipaddr_t ip,port_t port,bool skip_socks = false);
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Open connection.
+ \param ip Ipv6 address
+ \param port Port number
+ \param skip_socks Do not use socks4 even if configured */
+ bool Open(in6_addr ip,port_t port,bool skip_socks = false);
+#endif
+#endif
+ bool Open(SocketAddress&,bool skip_socks = false);
+ bool Open(SocketAddress&,SocketAddress& bind_address,bool skip_socks = false);
+ /** Open connection.
+ \param host Hostname
+ \param port Port number */
+ bool Open(const std::string &host,port_t port);
+
+ /** Connect timeout callback. */
+ void OnConnectTimeout();
+#ifdef _WIN32
+ /** Connection failed reported as exception on win32 */
+ void OnException();
+#endif
+
+ /** Close file descriptor - internal use only.
+ \sa SetCloseAndDelete */
+ int Close();
+
+ /** Send a string.
+ \param s String to send
+ \param f Dummy flags -- not used */
+ void Send(const std::string &s,int f = 0);
+ /** Send string using printf formatting. */
+ void Sendf(const char *format, ...);
+ /** Send buffer of bytes.
+ \param buf Buffer pointer
+ \param len Length of data
+ \param f Dummy flags -- not used */
+ void SendBuf(const char *buf,size_t len,int f = 0);
+ /** This callback is executed after a successful read from the socket.
+ \param buf Pointer to the data
+ \param len Length of the data */
+ virtual void OnRawData(const char *buf,size_t len);
+
+ /** Called when output buffer has been sent.
+ Note: Will only be called IF the output buffer has been used.
+ Send's that was successful without needing the output buffer
+ will not generate a call to this method. */
+ virtual void OnWriteComplete();
+ /** Number of bytes in input buffer. */
+ size_t GetInputLength();
+ /** Number of bytes in output buffer. */
+ size_t GetOutputLength();
+
+ /** Callback fires when a socket in line protocol has read one full line.
+ \param line Line read */
+ void OnLine(const std::string& line);
+ /** Get counter of number of bytes received. */
+ uint64_t GetBytesReceived(bool clear = false);
+ /** Get counter of number of bytes sent. */
+ uint64_t GetBytesSent(bool clear = false);
+
+ /** Socks4 specific callback. */
+ void OnSocks4Connect();
+ /** Socks4 specific callback. */
+ void OnSocks4ConnectFailed();
+ /** Socks4 specific callback.
+ \return 'need_more' */
+ bool OnSocks4Read();
+
+#ifdef ENABLE_RESOLVER
+ /** Callback executed when resolver thread has finished a resolve request. */
+ void OnResolved(int id,ipaddr_t a,port_t port);
+#ifdef ENABLE_IPV6
+ void OnResolved(int id,in6_addr& a,port_t port);
+#endif
+#endif
+#ifdef HAVE_OPENSSL
+ /** Callback for 'New' ssl support - replaces SSLSocket. Internal use. */
+ void OnSSLConnect();
+ /** Callback for 'New' ssl support - replaces SSLSocket. Internal use. */
+ void OnSSLAccept();
+ /** This method must be implemented to initialize
+ the ssl context for an outgoing connection. */
+ virtual void InitSSLClient();
+ /** This method must be implemented to initialize
+ the ssl context for an incoming connection. */
+ virtual void InitSSLServer();
+#endif
+
+#ifdef ENABLE_RECONNECT
+ /** Flag that says a broken connection will try to reconnect. */
+ void SetReconnect(bool = true);
+ /** Check reconnect on lost connection flag status. */
+ bool Reconnect();
+ /** Flag to determine if a reconnect is in progress. */
+ void SetIsReconnect(bool x = true);
+ /** Socket is reconnecting. */
+ bool IsReconnect();
+#endif
+
+ void DisableInputBuffer(bool = true);
+
+ void OnOptions(int,int,int,SOCKET);
+
+ void SetLineProtocol(bool = true);
+
+ // TCP options
+ bool SetTcpNodelay(bool = true);
+
+ virtual int Protocol();
+
+ /** Trigger limit for callback OnTransferLimit. */
+ void SetTransferLimit(size_t sz);
+ /** This callback fires when the output buffer drops below the value
+ set by SetTransferLimit. Default: 0 (disabled). */
+ virtual void OnTransferLimit();
+
+protected:
+ TcpSocket(const TcpSocket& );
+ void OnRead();
+ void OnRead( char *buf, size_t n );
+ void OnWrite();
+#ifdef HAVE_OPENSSL
+ /** SSL; Initialize ssl context for a client socket.
+ \param meth_in SSL method */
+ void InitializeContext(const std::string& context, SSL_METHOD *meth_in = NULL);
+ /** SSL; Initialize ssl context for a server socket.
+ \param keyfile Combined private key/certificate file
+ \param password Password for private key
+ \param meth_in SSL method */
+ void InitializeContext(const std::string& context, const std::string& keyfile, const std::string& password, SSL_METHOD *meth_in = NULL);
+ /** SSL; Initialize ssl context for a server socket.
+ \param certfile Separate certificate file
+ \param keyfile Combined private key/certificate file
+ \param password Password for private key
+ \param meth_in SSL method */
+ void InitializeContext(const std::string& context, const std::string& certfile, const std::string& keyfile, const std::string& password, SSL_METHOD *meth_in = NULL);
+ /** SSL; Password callback method. */
+static int SSL_password_cb(char *buf,int num,int rwflag,void *userdata);
+ /** SSL; Get pointer to ssl context structure. */
+ virtual SSL_CTX *GetSslContext();
+ /** SSL; Get pointer to ssl structure. */
+ virtual SSL *GetSsl();
+ /** ssl; still negotiating connection. */
+ bool SSLNegotiate();
+ /** SSL; Get ssl password. */
+ const std::string& GetPassword();
+#endif
+
+ CircularBuffer ibuf; ///< Circular input buffer
+
+private:
+ TcpSocket& operator=(const TcpSocket& ) { return *this; }
+
+ /** the actual send() */
+ int TryWrite(const char *buf, size_t len);
+ /** add data to output buffer top */
+ void Buffer(const char *buf, size_t len);
+
+ //
+ bool m_b_input_buffer_disabled;
+ uint64_t m_bytes_sent;
+ uint64_t m_bytes_received;
+ bool m_skip_c; ///< Skip second char of CRLF or LFCR sequence in OnRead
+ char m_c; ///< First char in CRLF or LFCR sequence
+ std::string m_line; ///< Current line in line protocol mode
+#ifdef SOCKETS_DYNAMIC_TEMP
+ char *m_buf; ///< temporary read buffer
+#endif
+ output_l m_obuf; ///< output buffer
+ OUTPUT *m_obuf_top; ///< output buffer on top
+ size_t m_transfer_limit;
+ size_t m_output_length;
+
+#ifdef HAVE_OPENSSL
+static SSLInitializer m_ssl_init;
+ SSL_CTX *m_ssl_ctx; ///< ssl context
+ SSL *m_ssl; ///< ssl 'socket'
+ BIO *m_sbio; ///< ssl bio
+ std::string m_password; ///< ssl password
+#endif
+
+#ifdef ENABLE_SOCKS4
+ int m_socks4_state; ///< socks4 support
+ char m_socks4_vn; ///< socks4 support, temporary variable
+ char m_socks4_cd; ///< socks4 support, temporary variable
+ unsigned short m_socks4_dstport; ///< socks4 support
+ unsigned long m_socks4_dstip; ///< socks4 support
+#endif
+
+#ifdef ENABLE_RESOLVER
+ int m_resolver_id; ///< Resolver id (if any) for current Open call
+#endif
+
+#ifdef ENABLE_RECONNECT
+ bool m_b_reconnect; ///< Reconnect on lost connection flag
+ bool m_b_is_reconnect; ///< Trying to reconnect
+#endif
+
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_TcpSocket_H
+
+
diff --git a/dep/sockets/include/Thread.h b/dep/sockets/include/Thread.h
new file mode 100644
index 00000000000..efb766e9ee6
--- /dev/null
+++ b/dep/sockets/include/Thread.h
@@ -0,0 +1,100 @@
+/** \file Thread.h
+ ** \date 2004-10-30
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_Thread_H
+#define _SOCKETS_Thread_H
+
+#include "sockets-config.h"
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+#ifdef _WIN32
+// to be
+//typedef DWORD threadfunc_t;
+//typedef LPVOID threadparam_t;
+//#define STDPREFIX WINAPI
+typedef unsigned threadfunc_t;
+typedef void * threadparam_t;
+#define STDPREFIX __stdcall
+#else
+#include <pthread.h>
+
+typedef void * threadfunc_t;
+typedef void * threadparam_t;
+#define STDPREFIX
+#endif
+
+/** \defgroup threading Threading */
+/** Thread base class.
+The Thread class is used by the resolver (ResolvServer) and running a detached socket (SocketThread).
+When you know some processing will take a long time and will freeze up a socket, there is always the
+possibility to call Detach() on that socket before starting the processing.
+When the OnDetached() callback is later called the processing can continue, now in its own thread.
+ \ingroup threading */
+class Thread
+{
+public:
+ Thread(bool release = true);
+ virtual ~Thread();
+
+ static threadfunc_t STDPREFIX StartThread(threadparam_t);
+
+ virtual void Run() = 0;
+
+ bool IsRunning();
+ void SetRunning(bool x);
+ bool IsReleased();
+ void SetRelease(bool x);
+ bool DeleteOnExit();
+ void SetDeleteOnExit(bool x = true);
+ bool IsDestructor();
+
+private:
+ Thread(const Thread& ) {}
+ Thread& operator=(const Thread& ) { return *this; }
+#ifdef _WIN32
+ HANDLE m_thread;
+ unsigned m_dwThreadId;
+#else
+ pthread_t m_thread;
+#endif
+ bool m_running;
+ bool m_release;
+ bool m_b_delete_on_exit;
+ bool m_b_destructor;
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_Thread_H
+
+
diff --git a/dep/sockets/include/UdpSocket.h b/dep/sockets/include/UdpSocket.h
new file mode 100644
index 00000000000..3b06c6955bd
--- /dev/null
+++ b/dep/sockets/include/UdpSocket.h
@@ -0,0 +1,215 @@
+/** \file UdpSocket.h
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_UdpSocket_H
+#define _SOCKETS_UdpSocket_H
+
+#include "sockets-config.h"
+#include "Socket.h"
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+/** Socket implementation for UDP.
+ \ingroup basic */
+class UdpSocket : public Socket
+{
+public:
+ /** Constructor.
+ \param h ISocketHandler reference
+ \param ibufsz Maximum size of receive message (extra bytes will be truncated)
+ \param ipv6 'true' if this is an ipv6 socket */
+ UdpSocket(ISocketHandler& h,int ibufsz = 16384,bool ipv6 = false, int retries = 0);
+ ~UdpSocket();
+
+ /** Called when incoming data has been received.
+ \param buf Pointer to data
+ \param len Length of data
+ \param sa Pointer to sockaddr struct of sender
+ \param sa_len Length of sockaddr struct */
+ virtual void OnRawData(const char *buf,size_t len,struct sockaddr *sa,socklen_t sa_len);
+
+ /** Called when incoming data has been received and read timestamp is enabled.
+ \param buf Pointer to data
+ \param len Length of data
+ \param sa Pointer to sockaddr struct of sender
+ \param sa_len Length of sockaddr struct
+ \param ts Timestamp from message */
+ virtual void OnRawData(const char *buf,size_t len,struct sockaddr *sa,socklen_t sa_len,struct timeval *ts);
+
+ /** To receive incoming data, call Bind to setup an incoming port.
+ \param port Incoming port number
+ \param range Port range to try if ports already in use
+ \return 0 if bind succeeded */
+ int Bind(port_t& port,int range = 1);
+ /** To receive data on a specific interface:port, use this.
+ \param intf Interface ip/hostname
+ \param port Port number
+ \param range Port range
+ \return 0 if bind succeeded */
+ int Bind(const std::string& intf,port_t& port,int range = 1);
+ /** To receive data on a specific interface:port, use this.
+ \param a Ip address
+ \param port Port number
+ \param range Port range
+ \return 0 if bind succeeded */
+ int Bind(ipaddr_t a,port_t& port,int range = 1);
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** To receive data on a specific interface:port, use this.
+ \param a Ipv6 address
+ \param port Port number
+ \param range Port range
+ \return 0 if bind succeeded */
+ int Bind(in6_addr a,port_t& port,int range = 1);
+#endif
+#endif
+ /** To receive data on a specific interface:port, use this.
+ \param ad Socket address
+ \param range Port range
+ \return 0 if bind succeeded */
+ int Bind(SocketAddress& ad,int range = 1);
+
+ /** Define remote host.
+ \param l Address of remote host
+ \param port Port of remote host
+ \return true if successful */
+ bool Open(ipaddr_t l,port_t port);
+ /** Define remote host.
+ \param host Hostname
+ \param port Port number
+ \return true if successful */
+ bool Open(const std::string& host,port_t port);
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Define remote host.
+ \param a Address of remote host, ipv6
+ \param port Port of remote host
+ \return true if successful */
+ bool Open(struct in6_addr& a,port_t port);
+#endif
+#endif
+ /** Define remote host.
+ \param ad Socket address
+ \return true if successful */
+ bool Open(SocketAddress& ad);
+
+ /** Send to specified host */
+ void SendToBuf(const std::string& ,port_t,const char *data,int len,int flags = 0);
+ /** Send to specified address */
+ void SendToBuf(ipaddr_t,port_t,const char *data,int len,int flags = 0);
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Send to specified ipv6 address */
+ void SendToBuf(in6_addr,port_t,const char *data,int len,int flags = 0);
+#endif
+#endif
+ /** Send to specified socket address */
+ void SendToBuf(SocketAddress& ad,const char *data,int len,int flags = 0);
+
+ /** Send string to specified host */
+ void SendTo(const std::string&,port_t,const std::string&,int flags = 0);
+ /** Send string to specified address */
+ void SendTo(ipaddr_t,port_t,const std::string&,int flags = 0);
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Send string to specified ipv6 address */
+ void SendTo(in6_addr,port_t,const std::string&,int flags = 0);
+#endif
+#endif
+ /** Send string to specified socket address */
+ void SendTo(SocketAddress& ad,const std::string&,int flags = 0);
+
+ /** Send to connected address */
+ void SendBuf(const char *data,size_t,int flags = 0);
+ /** Send string to connected address. */
+ void Send(const std::string& ,int flags = 0);
+
+ /** Set broadcast */
+ void SetBroadcast(bool b = true);
+ /** Check broadcast flag.
+ \return true broadcast is enabled. */
+ bool IsBroadcast();
+
+ /** multicast */
+ void SetMulticastTTL(int ttl = 1);
+ int GetMulticastTTL();
+ void SetMulticastLoop(bool = true);
+ bool IsMulticastLoop();
+ void AddMulticastMembership(const std::string& group,const std::string& intf = "0.0.0.0",int if_index = 0);
+ void DropMulticastMembership(const std::string& group,const std::string& intf = "0.0.0.0",int if_index = 0);
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** multicast, ipv6 only */
+ void SetMulticastHops(int = -1);
+ /** multicast, ipv6 only */
+ int GetMulticastHops();
+#endif
+#endif
+ /** Returns true if Bind succeeded. */
+ bool IsBound();
+ /** Return Bind port number */
+ port_t GetPort();
+
+ void OnOptions(int,int,int,SOCKET) {}
+
+ int GetLastSizeWritten();
+
+ /** Also read timestamp information from incoming message */
+ void SetTimestamp(bool = true);
+
+protected:
+ UdpSocket(const UdpSocket& s) : Socket(s) {}
+ void OnRead();
+#if defined(LINUX) || defined(MACOSX)
+ /** This method emulates socket recvfrom, but uses messages so we can get the timestamp */
+ int ReadTS(char *ioBuf, int inBufSize, struct sockaddr *from, socklen_t fromlen, struct timeval *ts);
+#endif
+
+private:
+ UdpSocket& operator=(const UdpSocket& ) { return *this; }
+ /** create before using sendto methods */
+ void CreateConnection();
+ char *m_ibuf; ///< Input buffer
+ int m_ibufsz; ///< Size of input buffer
+ bool m_bind_ok; ///< Bind completed successfully
+ port_t m_port; ///< Bind port number
+ int m_last_size_written;
+ int m_retries;
+ bool m_b_read_ts;
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_UdpSocket_H
+
+
diff --git a/dep/sockets/include/Utility.h b/dep/sockets/include/Utility.h
new file mode 100644
index 00000000000..724a94e4b32
--- /dev/null
+++ b/dep/sockets/include/Utility.h
@@ -0,0 +1,186 @@
+/** \file Utility.h
+ ** \date 2004-02-13
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_Utility_H
+#define _SOCKETS_Utility_H
+
+#include "sockets-config.h"
+#include <ctype.h>
+#include <string.h>
+#include <memory>
+#include "socket_include.h"
+#include <map>
+#include <string>
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+#define TWIST_LEN 624
+
+class SocketAddress;
+
+/** Conversion utilities.
+ \ingroup util */
+class Utility
+{
+ /**
+ The Mersenne Twister
+ http://www.math.keio.ac.jp/~matumoto/emt.html
+ */
+ class Rng {
+ public:
+ Rng(unsigned long seed);
+
+ unsigned long Get();
+
+ private:
+ int m_value;
+ unsigned long m_tmp[TWIST_LEN];
+ };
+ class ncmap_compare {
+ public:
+ bool operator()(const std::string& x, const std::string& y) const {
+ return strcasecmp(x.c_str(), y.c_str()) < 0;
+ }
+ };
+public:
+ template<typename Y> class ncmap : public std::map<std::string, Y, ncmap_compare> {
+ public:
+ ncmap() {}
+ };
+public:
+ static std::string base64(const std::string& str_in);
+ static std::string base64d(const std::string& str_in);
+ static std::string l2string(long l);
+ static std::string bigint2string(uint64_t l);
+ static uint64_t atoi64(const std::string& str);
+ static unsigned int hex2unsigned(const std::string& str);
+ static std::string rfc1738_encode(const std::string& src);
+ static std::string rfc1738_decode(const std::string& src);
+
+ /** Checks whether a string is a valid ipv4/ipv6 ip number. */
+ static bool isipv4(const std::string&);
+ /** Checks whether a string is a valid ipv4/ipv6 ip number. */
+ static bool isipv6(const std::string&);
+
+ /** Hostname to ip resolution ipv4, not asynchronous. */
+ static bool u2ip(const std::string&, ipaddr_t&);
+ static bool u2ip(const std::string&, struct sockaddr_in& sa, int ai_flags = 0);
+
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Hostname to ip resolution ipv6, not asynchronous. */
+ static bool u2ip(const std::string&, struct in6_addr&);
+ static bool u2ip(const std::string&, struct sockaddr_in6& sa, int ai_flags = 0);
+#endif
+#endif
+
+ /** Reverse lookup of address to hostname */
+ static bool reverse(struct sockaddr *sa, socklen_t sa_len, std::string&, int flags = 0);
+ static bool reverse(struct sockaddr *sa, socklen_t sa_len, std::string& hostname, std::string& service, int flags = 0);
+
+ static bool u2service(const std::string& name, int& service, int ai_flags = 0);
+
+ /** Convert binary ip address to string: ipv4. */
+ static void l2ip(const ipaddr_t,std::string& );
+ static void l2ip(const in_addr&,std::string& );
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Convert binary ip address to string: ipv6. */
+ static void l2ip(const struct in6_addr&,std::string& ,bool mixed = false);
+
+ /** ipv6 address compare. */
+ static int in6_addr_compare(in6_addr,in6_addr);
+#endif
+#endif
+ /** ResolveLocal (hostname) - call once before calling any GetLocal method. */
+ static void ResolveLocal();
+ /** Returns local hostname, ResolveLocal must be called once before using.
+ \sa ResolveLocal */
+ static const std::string& GetLocalHostname();
+ /** Returns local ip, ResolveLocal must be called once before using.
+ \sa ResolveLocal */
+ static ipaddr_t GetLocalIP();
+ /** Returns local ip number as string.
+ \sa ResolveLocal */
+ static const std::string& GetLocalAddress();
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ /** Returns local ipv6 ip.
+ \sa ResolveLocal */
+ static const struct in6_addr& GetLocalIP6();
+ /** Returns local ipv6 address.
+ \sa ResolveLocal */
+ static const std::string& GetLocalAddress6();
+#endif
+#endif
+ /** Set environment variable.
+ \param var Name of variable to set
+ \param value Value */
+ static void SetEnv(const std::string& var,const std::string& value);
+ /** Convert sockaddr struct to human readable string.
+ \param sa Ptr to sockaddr struct */
+ static std::string Sa2String(struct sockaddr *sa);
+
+ /** Get current time in sec/microseconds. */
+ static void GetTime(struct timeval *);
+
+ static std::auto_ptr<SocketAddress> CreateAddress(struct sockaddr *,socklen_t);
+
+ static unsigned long ThreadID();
+
+ static std::string ToLower(const std::string& str);
+ static std::string ToUpper(const std::string& str);
+
+ static std::string ToString(double d);
+
+ /** Returns a random 32-bit integer */
+ static unsigned long Rnd();
+
+private:
+ static std::string m_host; ///< local hostname
+ static ipaddr_t m_ip; ///< local ip address
+ static std::string m_addr; ///< local ip address in string format
+#ifdef ENABLE_IPV6
+#ifdef IPPROTO_IPV6
+ static struct in6_addr m_local_ip6; ///< local ipv6 address
+#endif
+ static std::string m_local_addr6; ///< local ipv6 address in string format
+#endif
+ static bool m_local_resolved; ///< ResolveLocal has been called if true
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // _SOCKETS_Utility_H
+
+
diff --git a/dep/sockets/include/socket_include.h b/dep/sockets/include/socket_include.h
new file mode 100644
index 00000000000..89855a54108
--- /dev/null
+++ b/dep/sockets/include/socket_include.h
@@ -0,0 +1,290 @@
+/** \file socket_include.h
+ ** \date 2005-04-12
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_socket_include_H
+#define _SOCKETS_socket_include_H
+#include "sockets-config.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4514)
+#endif
+
+// common defines affecting library and applications using library
+
+/* Define SOCKETS_DYNAMIC_TEMP to use dynamically allocated buffers
+ in read operations - helps on ECOS */
+#define SOCKETS_DYNAMIC_TEMP
+
+// platform specific stuff
+#if (defined(__unix__) || defined(unix)) && !defined(USG)
+#include <sys/param.h>
+#endif
+#include <list>
+
+// int64
+#ifdef _WIN32
+typedef unsigned __int64 uint64_t;
+#else
+#include <stdlib.h>
+#ifdef SOLARIS
+# include <sys/types.h>
+#else
+# include <stdint.h>
+#endif
+#endif
+
+#ifndef _WIN32
+// ----------------------------------------
+// common unix includes / defines
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+//#include <netdb.h>
+
+// all typedefs in this file will be declared outside the sockets namespace,
+// because some os's will already have one or more of the type defined.
+typedef int SOCKET;
+#define Errno errno
+#define StrError strerror
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+// WIN32 adapt
+#define closesocket close
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#endif // INADDR_NONE
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif // !_WIN32
+
+// ----------------------------------------
+// Generic
+#ifndef SOL_IP
+#define SOL_IP IPPROTO_IP
+#endif
+
+// ----------------------------------------
+// OS specific adaptions
+
+#ifdef SOLARIS
+// ----------------------------------------
+// Solaris
+typedef unsigned short port_t;
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+// no defs
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#define s6_addr16 _S6_un._S6_u8
+#define MSG_NOSIGNAL 0
+
+#elif defined __FreeBSD__
+// ----------------------------------------
+// FreeBSD
+# if __FreeBSD_version >= 400014
+# define s6_addr16 __u6_addr.__u6_addr16
+# if !defined(MSG_NOSIGNAL)
+# define MSG_NOSIGNAL 0
+# endif
+# include <netinet/in.h>
+typedef in_addr_t ipaddr_t;
+typedef in_port_t port_t;
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+// no defs
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+# else
+# error FreeBSD versions prior to 400014 does not support ipv6
+# endif
+
+#elif defined (__NetBSD__) || defined (__OpenBSD__)
+# if !defined(MSG_NOSIGNAL)
+# define MSG_NOSIGNAL 0
+# endif
+# include <netinet/in.h>
+typedef in_addr_t ipaddr_t;
+typedef in_port_t port_t;
+#elif defined MACOSX
+// ----------------------------------------
+// Mac OS X
+#include <string.h>
+#ifdef __DARWIN_UNIX03
+typedef unsigned short port_t;
+#else
+#include <mach/port.h>
+#endif // __DARWIN_UNIX03
+typedef unsigned long ipaddr_t;
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+// no defs
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#define s6_addr16 __u6_addr.__u6_addr16
+#define MSG_NOSIGNAL 0 // oops - thanks Derek
+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+
+#elif defined _WIN32
+// ----------------------------------------
+// Win32
+#ifdef _MSC_VER
+#pragma comment(lib, "wsock32.lib")
+#endif
+#define strcasecmp _stricmp
+
+typedef unsigned long ipaddr_t;
+typedef unsigned short port_t;
+typedef int socklen_t;
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+// no defs
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+// 1.8.6: define FD_SETSIZE to something bigger than 64 if there are a lot of
+// simultaneous connections (must be done before including winsock.h)
+#define FD_SETSIZE 1024
+
+// windows 2000 with ipv6 preview installed:
+// http://msdn.microsoft.com/downloads/sdks/platform/tpipv6.asp
+// see the FAQ on how to install
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#if _MSC_VER < 1200
+#ifndef __CYGWIN__
+#ifdef ENABLE_IPV6
+#include <tpipv6.h> // For IPv6 Tech Preview.
+#endif
+#endif
+#endif // _MSC_VER < 1200
+
+#define MSG_NOSIGNAL 0
+//#define SHUT_RDWR 2
+#define SHUT_WR 1
+
+#define Errno WSAGetLastError()
+const char *StrError(int x);
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+
+// class WSAInitializer is a part of the Socket class (on win32)
+// as a static instance - so whenever an application uses a Socket,
+// winsock is initialized
+class WSAInitializer // Winsock Initializer
+{
+public:
+ WSAInitializer() {
+ if (WSAStartup(0x101,&m_wsadata))
+ {
+ exit(-1);
+ }
+ }
+ ~WSAInitializer() {
+ WSACleanup();
+ }
+private:
+ WSADATA m_wsadata;
+};
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#else
+// ----------------------------------------
+// LINUX
+typedef unsigned long ipaddr_t;
+typedef unsigned short port_t;
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+// no defs
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+#endif
+
+#ifdef SOCKETS_NAMESPACE
+namespace SOCKETS_NAMESPACE {
+#endif
+ /** List type containing file descriptors. */
+ typedef std::list<SOCKET> socket_v;
+
+#ifdef SOCKETS_NAMESPACE
+}
+#endif
+
+// getaddrinfo / getnameinfo replacements
+#ifdef NO_GETADDRINFO
+#ifndef AI_NUMERICHOST
+#define AI_NUMERICHOST 1
+#endif
+#ifndef NI_NUMERICHOST
+#define NI_NUMERICHOST 1
+#endif
+#endif
+
+#endif // _SOCKETS_socket_include_H
+
+
diff --git a/dep/sockets/include/sockets-config.h b/dep/sockets/include/sockets-config.h
new file mode 100644
index 00000000000..1c8dc439092
--- /dev/null
+++ b/dep/sockets/include/sockets-config.h
@@ -0,0 +1,90 @@
+/**
+ ** \file sockets-config.h
+ ** \date 2007-04-14
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2007 Anders Hedstrom
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#ifndef _SOCKETS_CONFIG_H
+#define _SOCKETS_CONFIG_H
+
+#ifndef _RUN_DP
+/* First undefine symbols if already defined. */
+#undef HAVE_OPENSSL
+#undef ENABLE_IPV6
+#undef USE_SCTP
+#undef NO_GETADDRINFO
+#undef ENABLE_POOL
+#undef ENABLE_SOCKS4
+#undef ENABLE_RESOLVER
+#undef ENABLE_RECONNECT
+#undef ENABLE_DETACH
+#undef ENABLE_TRIGGERS
+#undef ENABLE_EXCEPTIONS
+#endif // _RUN_DP
+
+// define MACOSX for internal socket library checks
+#if defined(__APPLE__) && defined(__MACH__) && !defined(MACOSX)
+#define MACOSX
+#endif
+
+/* OpenSSL support. */
+//#define HAVE_OPENSSL
+
+/* Ipv6 support. */
+//#define ENABLE_IPV6
+
+/* SCTP support. */
+//#define USE_SCTP
+
+/* Define NO_GETADDRINFO if your operating system does not support
+ the "getaddrinfo" and "getnameinfo" function calls. */
+#define NO_GETADDRINFO
+
+/* Connection pool support. */
+#define ENABLE_POOL
+
+/* Socks4 client support. */
+//#define ENABLE_SOCKS4
+
+/* Asynchronous resolver. */
+#define ENABLE_RESOLVER
+
+/* Enable TCP reconnect on lost connection.
+ Socket::OnReconnect
+ Socket::OnDisconnect
+*/
+#define ENABLE_RECONNECT
+
+/* Enable socket thread detach functionality. */
+#define ENABLE_DETACH
+
+/* Enable socket to socket triggers. Not yet in use. */
+//#define ENABLE_TRIGGERS
+
+/* Enabled exceptions. */
+//#define ENABLE_EXCEPTIONS
+
+/* Resolver uses the detach function so either enable both or disable both. */
+#ifndef ENABLE_DETACH
+#undef ENABLE_RESOLVER
+#endif
+
+#endif // _SOCKETS_CONFIG_H
+
+
diff --git a/dep/sockets/network_kist.txt b/dep/sockets/network_kist.txt
new file mode 100644
index 00000000000..f6597bf9c77
--- /dev/null
+++ b/dep/sockets/network_kist.txt
@@ -0,0 +1,20 @@
+The following are the only .cpp files used from the new network library (v2.2.8) This file is just for future reference.
+
+Base64.cpp
+Exception.cpp
+Ipv4Address.cpp
+Ipv6Address.cpp
+Lock.cpp
+Mutex.cpp
+Parse.cpp
+ResolvServer.cpp
+ResolvSocket.cpp
+Socket.cpp
+SocketHandler.cpp
+socket_include.cpp
+StdoutLog.cpp
+StreamSocket.cpp
+TcpSocket.cpp
+Thread.cpp
+UdpSocket.cpp
+Utility.cpp
diff --git a/dep/sockets/socket_include.cpp b/dep/sockets/socket_include.cpp
new file mode 100644
index 00000000000..290602c1b52
--- /dev/null
+++ b/dep/sockets/socket_include.cpp
@@ -0,0 +1,89 @@
+/** \file socket_include.cpp
+ ** \date 2004-11-28
+ ** \author grymse@alhem.net
+**/
+/*
+Copyright (C) 2004-2007 Anders Hedstrom
+
+This library is made available under the terms of the GNU GPL.
+
+If you would like to use this library in a closed-source application,
+a separate license agreement is available. For information about
+the closed-source license agreement for the C++ sockets library,
+please visit http://www.alhem.net/Sockets/license.html and/or
+email license@alhem.net.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include <stdio.h>
+
+// only to be included in win32 projects
+const char *StrError(int x)
+{
+static char tmp[100];
+ switch (x)
+ {
+ case 10004: return "Interrupted function call.";
+ case 10013: return "Permission denied.";
+ case 10014: return "Bad address.";
+ case 10022: return "Invalid argument.";
+ case 10024: return "Too many open files.";
+ case 10035: return "Resource temporarily unavailable.";
+ case 10036: return "Operation now in progress.";
+ case 10037: return "Operation already in progress.";
+ case 10038: return "Socket operation on nonsocket.";
+ case 10039: return "Destination address required.";
+ case 10040: return "Message too long.";
+ case 10041: return "Protocol wrong type for socket.";
+ case 10042: return "Bad protocol option.";
+ case 10043: return "Protocol not supported.";
+ case 10044: return "Socket type not supported.";
+ case 10045: return "Operation not supported.";
+ case 10046: return "Protocol family not supported.";
+ case 10047: return "Address family not supported by protocol family.";
+ case 10048: return "Address already in use.";
+ case 10049: return "Cannot assign requested address.";
+ case 10050: return "Network is down.";
+ case 10051: return "Network is unreachable.";
+ case 10052: return "Network dropped connection on reset.";
+ case 10053: return "Software caused connection abort.";
+ case 10054: return "Connection reset by peer.";
+ case 10055: return "No buffer space available.";
+ case 10056: return "Socket is already connected.";
+ case 10057: return "Socket is not connected.";
+ case 10058: return "Cannot send after socket shutdown.";
+ case 10060: return "Connection timed out.";
+ case 10061: return "Connection refused.";
+ case 10064: return "Host is down.";
+ case 10065: return "No route to host.";
+ case 10067: return "Too many processes.";
+ case 10091: return "Network subsystem is unavailable.";
+ case 10092: return "Winsock.dll version out of range.";
+ case 10093: return "Successful WSAStartup not yet performed.";
+ case 10101: return "Graceful shutdown in progress.";
+ case 10109: return "Class type not found.";
+ case 11001: return "Host not found.";
+ case 11002: return "Nonauthoritative host not found.";
+ case 11003: return "This is a nonrecoverable error.";
+ case 11004: return "Valid name, no data record of requested type.";
+
+ default:
+ break;
+ }
+ sprintf(tmp, "Winsock error code: %d", x);
+ return tmp;
+}
+
+