From ce469cbad1be7074adbcb346c4aa1acdbfd17a37 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Wed, 9 Dec 2020 14:11:22 +0900 Subject: Renaming of files in preparation for code style tools. Signed-off-by: Michele Calgaro (cherry picked from commit a06e2c2f225d76b67b0058a9880222f75d5495c3) --- .../jingle/libjingle/talk/base/CMakeLists.txt | 8 +- .../jabber/jingle/libjingle/talk/base/Makefile.am | 32 +- .../libjingle/talk/base/asyncpacketsocket.cc | 83 -- .../libjingle/talk/base/asyncpacketsocket.cpp | 83 ++ .../jingle/libjingle/talk/base/asynctcpsocket.cc | 198 ---- .../jingle/libjingle/talk/base/asynctcpsocket.cpp | 198 ++++ .../jingle/libjingle/talk/base/asyncudpsocket.cc | 83 -- .../jingle/libjingle/talk/base/asyncudpsocket.cpp | 83 ++ .../jabber/jingle/libjingle/talk/base/base64.cc | 194 ---- .../jabber/jingle/libjingle/talk/base/base64.cpp | 194 ++++ .../jingle/libjingle/talk/base/bytebuffer.cc | 166 --- .../jingle/libjingle/talk/base/bytebuffer.cpp | 166 +++ .../jabber/jingle/libjingle/talk/base/common.h | 2 +- .../jabber/jingle/libjingle/talk/base/host.cc | 101 -- .../jabber/jingle/libjingle/talk/base/host.cpp | 101 ++ .../jabber/jingle/libjingle/talk/base/jtime.cc | 77 -- .../jabber/jingle/libjingle/talk/base/jtime.cpp | 77 ++ .../jingle/libjingle/talk/base/messagequeue.cc | 321 ------ .../jingle/libjingle/talk/base/messagequeue.cpp | 321 ++++++ .../jabber/jingle/libjingle/talk/base/network.cc | 382 ------- .../jabber/jingle/libjingle/talk/base/network.cpp | 382 +++++++ .../libjingle/talk/base/physicalsocketserver.cc | 1116 ------------------- .../libjingle/talk/base/physicalsocketserver.cpp | 1116 +++++++++++++++++++ .../jingle/libjingle/talk/base/socketadapters.cc | 1131 -------------------- .../jingle/libjingle/talk/base/socketadapters.cpp | 1131 ++++++++++++++++++++ .../jingle/libjingle/talk/base/socketaddress.cc | 267 ----- .../jingle/libjingle/talk/base/socketaddress.cpp | 267 +++++ .../libjingle/talk/base/socketaddresspair.cc | 58 - .../libjingle/talk/base/socketaddresspair.cpp | 58 + .../jabber/jingle/libjingle/talk/base/task.cc | 238 ---- .../jabber/jingle/libjingle/talk/base/task.cpp | 238 ++++ .../jingle/libjingle/talk/base/taskrunner.cc | 92 -- .../jingle/libjingle/talk/base/taskrunner.cpp | 92 ++ .../jabber/jingle/libjingle/talk/base/thread.cc | 274 ----- .../jabber/jingle/libjingle/talk/base/thread.cpp | 274 +++++ 35 files changed, 4802 insertions(+), 4802 deletions(-) delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/host.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/network.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/task.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cpp (limited to 'kopete/protocols/jabber/jingle/libjingle/talk/base') diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/base/CMakeLists.txt index 8f037a9a..978eb5bb 100644 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/CMakeLists.txt +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/CMakeLists.txt @@ -25,8 +25,8 @@ include_directories( tde_add_library( cricketbase STATIC_PIC SOURCES - socketaddress.cc jtime.cc asyncudpsocket.cc messagequeue.cc - thread.cc physicalsocketserver.cc bytebuffer.cc asyncpacketsocket.cc - network.cc asynctcpsocket.cc socketadapters.cc md5c.c base64.cc - task.cc taskrunner.cc host.cc socketaddresspair.cc + socketaddress.cpp jtime.cpp asyncudpsocket.cpp messagequeue.cpp + thread.cpp physicalsocketserver.cpp bytebuffer.cpp asyncpacketsocket.cpp + network.cpp asynctcpsocket.cpp socketadapters.cpp md5c.c base64.cpp + task.cpp taskrunner.cpp host.cpp socketaddresspair.cpp ) diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am index 2921049a..ddffd93e 100644 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am @@ -1,23 +1,23 @@ ## Does not compile with final KDE_OPTIONS = nofinal -libcricketbase_la_SOURCES = socketaddress.cc \ - jtime.cc \ - asyncudpsocket.cc \ - messagequeue.cc \ - thread.cc \ - physicalsocketserver.cc \ - bytebuffer.cc \ - asyncpacketsocket.cc \ - network.cc \ - asynctcpsocket.cc \ - socketadapters.cc \ +libcricketbase_la_SOURCES = socketaddress.cpp \ + jtime.cpp \ + asyncudpsocket.cpp \ + messagequeue.cpp \ + thread.cpp \ + physicalsocketserver.cpp \ + bytebuffer.cpp \ + asyncpacketsocket.cpp \ + network.cpp \ + asynctcpsocket.cpp \ + socketadapters.cpp \ md5c.c \ - base64.cc \ - task.cc \ - taskrunner.cc \ - host.cc \ - socketaddresspair.cc + base64.cpp \ + task.cpp \ + taskrunner.cpp \ + host.cpp \ + socketaddresspair.cpp noinst_HEADERS = asyncfile.h \ common.h \ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc deleted file mode 100644 index 10cfa617..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#pragma warning(disable:4786) -#endif -#include "talk/base/asyncpacketsocket.h" - -namespace cricket { - -AsyncPacketSocket::AsyncPacketSocket(AsyncSocket* socket) : socket_(socket) { -} - -AsyncPacketSocket::~AsyncPacketSocket() { - delete socket_; -} - -SocketAddress AsyncPacketSocket::GetLocalAddress() const { - return socket_->GetLocalAddress(); -} - -SocketAddress AsyncPacketSocket::GetRemoteAddress() const { - return socket_->GetRemoteAddress(); -} - -int AsyncPacketSocket::Bind(const SocketAddress& addr) { - return socket_->Bind(addr); -} - -int AsyncPacketSocket::Connect(const SocketAddress& addr) { - return socket_->Connect(addr); -} - -int AsyncPacketSocket::Send(const void *pv, size_t cb) { - return socket_->Send(pv, cb); -} - -int AsyncPacketSocket::SendTo( - const void *pv, size_t cb, const SocketAddress& addr) { - return socket_->SendTo(pv, cb, addr); -} - -int AsyncPacketSocket::Close() { - return socket_->Close(); -} - -int AsyncPacketSocket::SetOption(Socket::Option opt, int value) { - return socket_->SetOption(opt, value); -} - -int AsyncPacketSocket::GetError() const { - return socket_->GetError(); -} - -void AsyncPacketSocket::SetError(int error) { - return socket_->SetError(error); -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cpp new file mode 100644 index 00000000..10cfa617 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cpp @@ -0,0 +1,83 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable:4786) +#endif +#include "talk/base/asyncpacketsocket.h" + +namespace cricket { + +AsyncPacketSocket::AsyncPacketSocket(AsyncSocket* socket) : socket_(socket) { +} + +AsyncPacketSocket::~AsyncPacketSocket() { + delete socket_; +} + +SocketAddress AsyncPacketSocket::GetLocalAddress() const { + return socket_->GetLocalAddress(); +} + +SocketAddress AsyncPacketSocket::GetRemoteAddress() const { + return socket_->GetRemoteAddress(); +} + +int AsyncPacketSocket::Bind(const SocketAddress& addr) { + return socket_->Bind(addr); +} + +int AsyncPacketSocket::Connect(const SocketAddress& addr) { + return socket_->Connect(addr); +} + +int AsyncPacketSocket::Send(const void *pv, size_t cb) { + return socket_->Send(pv, cb); +} + +int AsyncPacketSocket::SendTo( + const void *pv, size_t cb, const SocketAddress& addr) { + return socket_->SendTo(pv, cb, addr); +} + +int AsyncPacketSocket::Close() { + return socket_->Close(); +} + +int AsyncPacketSocket::SetOption(Socket::Option opt, int value) { + return socket_->SetOption(opt, value); +} + +int AsyncPacketSocket::GetError() const { + return socket_->GetError(); +} + +void AsyncPacketSocket::SetError(int error) { + return socket_->SetError(error); +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc deleted file mode 100644 index 8bf66a38..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc +++ /dev/null @@ -1,198 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#pragma warning(disable:4786) -#endif -#include "talk/base/asynctcpsocket.h" -#include "talk/base/byteorder.h" -#include "talk/base/common.h" -#include "talk/base/logging.h" -#include - -#if defined(_MSC_VER) && _MSC_VER < 1300 -namespace std { - using ::strerror; -} -#endif - -#ifdef POSIX -extern "C" { -#include -} -#endif // POSIX - -namespace cricket { - -const size_t MAX_PACKET_SIZE = 64 * 1024; - -typedef uint16 PacketLength; -const size_t PKT_LEN_SIZE = sizeof(PacketLength); - -const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE; - -AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket), insize_(BUF_SIZE), inpos_(0), outsize_(BUF_SIZE), outpos_(0) { - inbuf_ = new char[insize_]; - outbuf_ = new char[outsize_]; - - ASSERT(socket_ != NULL); - socket_->SignalConnectEvent.connect(this, &AsyncTCPSocket::OnConnectEvent); - socket_->SignalReadEvent.connect(this, &AsyncTCPSocket::OnReadEvent); - socket_->SignalWriteEvent.connect(this, &AsyncTCPSocket::OnWriteEvent); - socket_->SignalCloseEvent.connect(this, &AsyncTCPSocket::OnCloseEvent); -} - -AsyncTCPSocket::~AsyncTCPSocket() { - delete [] inbuf_; - delete [] outbuf_; -} - -int AsyncTCPSocket::Send(const void *pv, size_t cb) { - if (cb > MAX_PACKET_SIZE) { - socket_->SetError(EMSGSIZE); - return -1; - } - - // If we are blocking on send, then silently drop this packet - if (outpos_) - return static_cast(cb); - - PacketLength pkt_len = HostToNetwork16(static_cast(cb)); - memcpy(outbuf_, &pkt_len, PKT_LEN_SIZE); - memcpy(outbuf_ + PKT_LEN_SIZE, pv, cb); - outpos_ = PKT_LEN_SIZE + cb; - - int res = Flush(); - if (res <= 0) { - // drop packet if we made no progress - outpos_ = 0; - return res; - } - - // We claim to have sent the whole thing, even if we only sent partial - return static_cast(cb); -} - -int AsyncTCPSocket::SendTo(const void *pv, size_t cb, const SocketAddress& addr) { - if (addr == GetRemoteAddress()) - return Send(pv, cb); - - ASSERT(false); - socket_->SetError(ENOTCONN); - return -1; -} - -int AsyncTCPSocket::SendRaw(const void * pv, size_t cb) { - if (outpos_ + cb > outsize_) { - socket_->SetError(EMSGSIZE); - return -1; - } - - memcpy(outbuf_ + outpos_, pv, cb); - outpos_ += cb; - - return Flush(); -} - -void AsyncTCPSocket::ProcessInput(char * data, size_t& len) { - SocketAddress remote_addr(GetRemoteAddress()); - - while (true) { - if (len < PKT_LEN_SIZE) - return; - - PacketLength pkt_len; - memcpy(&pkt_len, data, PKT_LEN_SIZE); - pkt_len = NetworkToHost16(pkt_len); - - if (len < PKT_LEN_SIZE + pkt_len) - return; - - SignalReadPacket(data + PKT_LEN_SIZE, pkt_len, remote_addr, this); - - len -= PKT_LEN_SIZE + pkt_len; - if (len > 0) { - memmove(data, data + PKT_LEN_SIZE + pkt_len, len); - } - } -} - -int AsyncTCPSocket::Flush() { - int res = socket_->Send(outbuf_, outpos_); - if (res <= 0) { - return res; - } - if (static_cast(res) <= outpos_) { - outpos_ -= res; - } else { - ASSERT(false); - return -1; - } - if (outpos_ > 0) { - memmove(outbuf_, outbuf_ + res, outpos_); - } - return res; -} - -void AsyncTCPSocket::OnConnectEvent(AsyncSocket* socket) { - SignalConnect(this); -} - -void AsyncTCPSocket::OnReadEvent(AsyncSocket* socket) { - ASSERT(socket == socket_); - - int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_); - if (len < 0) { - // TODO: Do something better like forwarding the error to the user. - LOG(INFO) << "recvfrom: " << errno << " " << std::strerror(errno); - return; - } - - inpos_ += len; - - ProcessInput(inbuf_, inpos_); - - if (inpos_ >= insize_) { - LOG(INFO) << "input buffer overflow"; - ASSERT(false); - inpos_ = 0; - } -} - -void AsyncTCPSocket::OnWriteEvent(AsyncSocket* socket) { - ASSERT(socket == socket_); - - if (outpos_ > 0) { - Flush(); - } -} - -void AsyncTCPSocket::OnCloseEvent(AsyncSocket* socket, int error) { - SignalClose(this, error); -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cpp new file mode 100644 index 00000000..8bf66a38 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cpp @@ -0,0 +1,198 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable:4786) +#endif +#include "talk/base/asynctcpsocket.h" +#include "talk/base/byteorder.h" +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include + +#if defined(_MSC_VER) && _MSC_VER < 1300 +namespace std { + using ::strerror; +} +#endif + +#ifdef POSIX +extern "C" { +#include +} +#endif // POSIX + +namespace cricket { + +const size_t MAX_PACKET_SIZE = 64 * 1024; + +typedef uint16 PacketLength; +const size_t PKT_LEN_SIZE = sizeof(PacketLength); + +const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE; + +AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket), insize_(BUF_SIZE), inpos_(0), outsize_(BUF_SIZE), outpos_(0) { + inbuf_ = new char[insize_]; + outbuf_ = new char[outsize_]; + + ASSERT(socket_ != NULL); + socket_->SignalConnectEvent.connect(this, &AsyncTCPSocket::OnConnectEvent); + socket_->SignalReadEvent.connect(this, &AsyncTCPSocket::OnReadEvent); + socket_->SignalWriteEvent.connect(this, &AsyncTCPSocket::OnWriteEvent); + socket_->SignalCloseEvent.connect(this, &AsyncTCPSocket::OnCloseEvent); +} + +AsyncTCPSocket::~AsyncTCPSocket() { + delete [] inbuf_; + delete [] outbuf_; +} + +int AsyncTCPSocket::Send(const void *pv, size_t cb) { + if (cb > MAX_PACKET_SIZE) { + socket_->SetError(EMSGSIZE); + return -1; + } + + // If we are blocking on send, then silently drop this packet + if (outpos_) + return static_cast(cb); + + PacketLength pkt_len = HostToNetwork16(static_cast(cb)); + memcpy(outbuf_, &pkt_len, PKT_LEN_SIZE); + memcpy(outbuf_ + PKT_LEN_SIZE, pv, cb); + outpos_ = PKT_LEN_SIZE + cb; + + int res = Flush(); + if (res <= 0) { + // drop packet if we made no progress + outpos_ = 0; + return res; + } + + // We claim to have sent the whole thing, even if we only sent partial + return static_cast(cb); +} + +int AsyncTCPSocket::SendTo(const void *pv, size_t cb, const SocketAddress& addr) { + if (addr == GetRemoteAddress()) + return Send(pv, cb); + + ASSERT(false); + socket_->SetError(ENOTCONN); + return -1; +} + +int AsyncTCPSocket::SendRaw(const void * pv, size_t cb) { + if (outpos_ + cb > outsize_) { + socket_->SetError(EMSGSIZE); + return -1; + } + + memcpy(outbuf_ + outpos_, pv, cb); + outpos_ += cb; + + return Flush(); +} + +void AsyncTCPSocket::ProcessInput(char * data, size_t& len) { + SocketAddress remote_addr(GetRemoteAddress()); + + while (true) { + if (len < PKT_LEN_SIZE) + return; + + PacketLength pkt_len; + memcpy(&pkt_len, data, PKT_LEN_SIZE); + pkt_len = NetworkToHost16(pkt_len); + + if (len < PKT_LEN_SIZE + pkt_len) + return; + + SignalReadPacket(data + PKT_LEN_SIZE, pkt_len, remote_addr, this); + + len -= PKT_LEN_SIZE + pkt_len; + if (len > 0) { + memmove(data, data + PKT_LEN_SIZE + pkt_len, len); + } + } +} + +int AsyncTCPSocket::Flush() { + int res = socket_->Send(outbuf_, outpos_); + if (res <= 0) { + return res; + } + if (static_cast(res) <= outpos_) { + outpos_ -= res; + } else { + ASSERT(false); + return -1; + } + if (outpos_ > 0) { + memmove(outbuf_, outbuf_ + res, outpos_); + } + return res; +} + +void AsyncTCPSocket::OnConnectEvent(AsyncSocket* socket) { + SignalConnect(this); +} + +void AsyncTCPSocket::OnReadEvent(AsyncSocket* socket) { + ASSERT(socket == socket_); + + int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_); + if (len < 0) { + // TODO: Do something better like forwarding the error to the user. + LOG(INFO) << "recvfrom: " << errno << " " << std::strerror(errno); + return; + } + + inpos_ += len; + + ProcessInput(inbuf_, inpos_); + + if (inpos_ >= insize_) { + LOG(INFO) << "input buffer overflow"; + ASSERT(false); + inpos_ = 0; + } +} + +void AsyncTCPSocket::OnWriteEvent(AsyncSocket* socket) { + ASSERT(socket == socket_); + + if (outpos_ > 0) { + Flush(); + } +} + +void AsyncTCPSocket::OnCloseEvent(AsyncSocket* socket, int error) { + SignalClose(this, error); +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc deleted file mode 100644 index 5b8c2466..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#pragma warning(disable:4786) -#endif -#include "talk/base/asyncudpsocket.h" -#include "talk/base/logging.h" -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1300 -namespace std { - using ::strerror; -} -#endif - -#ifdef POSIX -extern "C" { -#include -} -#endif // POSIX - -namespace cricket { - -const int BUF_SIZE = 64 * 1024; - -AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket) { - size_ = BUF_SIZE; - buf_ = new char[size_]; - - assert(socket_); - // The socket should start out readable but not writable. - socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent); -} - -AsyncUDPSocket::~AsyncUDPSocket() { - delete [] buf_; -} - -void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) { - assert(socket == socket_); - - SocketAddress remote_addr; - int len = socket_->RecvFrom(buf_, size_, &remote_addr); - if (len < 0) { - // TODO: Do something better like forwarding the error to the user. - PLOG(LS_ERROR, socket_->GetError()) << "recvfrom"; - return; - } - - // TODO: Make sure that we got all of the packet. If we did not, then we - // should resize our buffer to be large enough. - - SignalReadPacket(buf_, (size_t)len, remote_addr, this); -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cpp new file mode 100644 index 00000000..5b8c2466 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cpp @@ -0,0 +1,83 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable:4786) +#endif +#include "talk/base/asyncudpsocket.h" +#include "talk/base/logging.h" +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1300 +namespace std { + using ::strerror; +} +#endif + +#ifdef POSIX +extern "C" { +#include +} +#endif // POSIX + +namespace cricket { + +const int BUF_SIZE = 64 * 1024; + +AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket) : AsyncPacketSocket(socket) { + size_ = BUF_SIZE; + buf_ = new char[size_]; + + assert(socket_); + // The socket should start out readable but not writable. + socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent); +} + +AsyncUDPSocket::~AsyncUDPSocket() { + delete [] buf_; +} + +void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) { + assert(socket == socket_); + + SocketAddress remote_addr; + int len = socket_->RecvFrom(buf_, size_, &remote_addr); + if (len < 0) { + // TODO: Do something better like forwarding the error to the user. + PLOG(LS_ERROR, socket_->GetError()) << "recvfrom"; + return; + } + + // TODO: Make sure that we got all of the packet. If we did not, then we + // should resize our buffer to be large enough. + + SignalReadPacket(buf_, (size_t)len, remote_addr, this); +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc deleted file mode 100644 index e0ec1b90..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc +++ /dev/null @@ -1,194 +0,0 @@ - -//********************************************************************* -//* Base64 - a simple base64 encoder and decoder. -//* -//* Copyright (c) 1999, Bob Withers - bwit@pobox.com -//* -//* This code may be freely used for any purpose, either personal -//* or commercial, provided the authors copyright notice remains -//* intact. -//* -//* Enhancements by Stanley Yamane: -//* o reverse lookup table for the decode function -//* o reserve string buffer space in advance -//* -//********************************************************************* - -#include "talk/base/base64.h" - -using namespace std; - -static const char fillchar = '='; -static const string::size_type np = string::npos; - -const string Base64::Base64Table( - // 0000000000111111111122222222223333333333444444444455555555556666 - // 0123456789012345678901234567890123456789012345678901234567890123 - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); - -// Decode Table gives the index of any valid base64 character in the Base64 table] -// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == / - - // 0 1 2 3 4 5 6 7 8 9 -const string::size_type Base64::DecodeTable[] = { - np,np,np,np,np,np,np,np,np,np, // 0 - 9 - np,np,np,np,np,np,np,np,np,np, //10 -19 - np,np,np,np,np,np,np,np,np,np, //20 -29 - np,np,np,np,np,np,np,np,np,np, //30 -39 - np,np,np,62,np,np,np,63,52,53, //40 -49 - 54,55,56,57,58,59,60,61,np,np, //50 -59 - np,np,np,np,np, 0, 1, 2, 3, 4, //60 -69 - 5, 6, 7, 8, 9,10,11,12,13,14, //70 -79 - 15,16,17,18,19,20,21,22,23,24, //80 -89 - 25,np,np,np,np,np,np,26,27,28, //90 -99 - 29,30,31,32,33,34,35,36,37,38, //100 -109 - 39,40,41,42,43,44,45,46,47,48, //110 -119 - 49,50,51,np,np,np,np,np,np,np, //120 -129 - np,np,np,np,np,np,np,np,np,np, //130 -139 - np,np,np,np,np,np,np,np,np,np, //140 -149 - np,np,np,np,np,np,np,np,np,np, //150 -159 - np,np,np,np,np,np,np,np,np,np, //160 -169 - np,np,np,np,np,np,np,np,np,np, //170 -179 - np,np,np,np,np,np,np,np,np,np, //180 -189 - np,np,np,np,np,np,np,np,np,np, //190 -199 - np,np,np,np,np,np,np,np,np,np, //200 -209 - np,np,np,np,np,np,np,np,np,np, //210 -219 - np,np,np,np,np,np,np,np,np,np, //220 -229 - np,np,np,np,np,np,np,np,np,np, //230 -239 - np,np,np,np,np,np,np,np,np,np, //240 -249 - np,np,np,np,np,np //250 -256 -}; - -string Base64::encodeFromArray(const char * data, size_t len) { - size_t i; - char c; - string ret; - - ret.reserve(len * 2); - - for (i = 0; i < len; ++i) - { - c = (data[i] >> 2) & 0x3f; - ret.append(1, Base64Table[c]); - c = (data[i] << 4) & 0x3f; - if (++i < len) - c |= (data[i] >> 4) & 0x0f; - - ret.append(1, Base64Table[c]); - if (i < len) - { - c = (data[i] << 2) & 0x3f; - if (++i < len) - c |= (data[i] >> 6) & 0x03; - - ret.append(1, Base64Table[c]); - } - else - { - ++i; - ret.append(1, fillchar); - } - - if (i < len) - { - c = data[i] & 0x3f; - ret.append(1, Base64Table[c]); - } - else - { - ret.append(1, fillchar); - } - } - - return(ret); -} - - -string Base64::encode(const string& data) -{ - string::size_type i; - char c; - string::size_type len = data.length(); - string ret; - - ret.reserve(len * 2); - - for (i = 0; i < len; ++i) - { - c = (data[i] >> 2) & 0x3f; - ret.append(1, Base64Table[c]); - c = (data[i] << 4) & 0x3f; - if (++i < len) - c |= (data[i] >> 4) & 0x0f; - - ret.append(1, Base64Table[c]); - if (i < len) - { - c = (data[i] << 2) & 0x3f; - if (++i < len) - c |= (data[i] >> 6) & 0x03; - - ret.append(1, Base64Table[c]); - } - else - { - ++i; - ret.append(1, fillchar); - } - - if (i < len) - { - c = data[i] & 0x3f; - ret.append(1, Base64Table[c]); - } - else - { - ret.append(1, fillchar); - } - } - - return(ret); -} - -string Base64::decode(const string& data) -{ - string::size_type i; - char c; - char c1; - string::size_type len = data.length(); - string ret; - - ret.reserve(len); - - for (i = 0; i < len; ++i) - { - c = static_cast(DecodeTable[static_cast(data[i])]); - ++i; - c1 = static_cast(DecodeTable[static_cast(data[i])]); - c = (c << 2) | ((c1 >> 4) & 0x3); - ret.append(1, c); - if (++i < len) - { - c = data[i]; - if (fillchar == c) - break; - - c = static_cast(DecodeTable[static_cast(data[i])]); - c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf); - ret.append(1, c1); - } - - if (++i < len) - { - c1 = data[i]; - if (fillchar == c1) - break; - - c1 = static_cast(DecodeTable[static_cast(data[i])]); - c = ((c << 6) & 0xc0) | c1; - ret.append(1, c); - } - } - - return(ret); -} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cpp new file mode 100644 index 00000000..e0ec1b90 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cpp @@ -0,0 +1,194 @@ + +//********************************************************************* +//* Base64 - a simple base64 encoder and decoder. +//* +//* Copyright (c) 1999, Bob Withers - bwit@pobox.com +//* +//* This code may be freely used for any purpose, either personal +//* or commercial, provided the authors copyright notice remains +//* intact. +//* +//* Enhancements by Stanley Yamane: +//* o reverse lookup table for the decode function +//* o reserve string buffer space in advance +//* +//********************************************************************* + +#include "talk/base/base64.h" + +using namespace std; + +static const char fillchar = '='; +static const string::size_type np = string::npos; + +const string Base64::Base64Table( + // 0000000000111111111122222222223333333333444444444455555555556666 + // 0123456789012345678901234567890123456789012345678901234567890123 + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); + +// Decode Table gives the index of any valid base64 character in the Base64 table] +// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == / + + // 0 1 2 3 4 5 6 7 8 9 +const string::size_type Base64::DecodeTable[] = { + np,np,np,np,np,np,np,np,np,np, // 0 - 9 + np,np,np,np,np,np,np,np,np,np, //10 -19 + np,np,np,np,np,np,np,np,np,np, //20 -29 + np,np,np,np,np,np,np,np,np,np, //30 -39 + np,np,np,62,np,np,np,63,52,53, //40 -49 + 54,55,56,57,58,59,60,61,np,np, //50 -59 + np,np,np,np,np, 0, 1, 2, 3, 4, //60 -69 + 5, 6, 7, 8, 9,10,11,12,13,14, //70 -79 + 15,16,17,18,19,20,21,22,23,24, //80 -89 + 25,np,np,np,np,np,np,26,27,28, //90 -99 + 29,30,31,32,33,34,35,36,37,38, //100 -109 + 39,40,41,42,43,44,45,46,47,48, //110 -119 + 49,50,51,np,np,np,np,np,np,np, //120 -129 + np,np,np,np,np,np,np,np,np,np, //130 -139 + np,np,np,np,np,np,np,np,np,np, //140 -149 + np,np,np,np,np,np,np,np,np,np, //150 -159 + np,np,np,np,np,np,np,np,np,np, //160 -169 + np,np,np,np,np,np,np,np,np,np, //170 -179 + np,np,np,np,np,np,np,np,np,np, //180 -189 + np,np,np,np,np,np,np,np,np,np, //190 -199 + np,np,np,np,np,np,np,np,np,np, //200 -209 + np,np,np,np,np,np,np,np,np,np, //210 -219 + np,np,np,np,np,np,np,np,np,np, //220 -229 + np,np,np,np,np,np,np,np,np,np, //230 -239 + np,np,np,np,np,np,np,np,np,np, //240 -249 + np,np,np,np,np,np //250 -256 +}; + +string Base64::encodeFromArray(const char * data, size_t len) { + size_t i; + char c; + string ret; + + ret.reserve(len * 2); + + for (i = 0; i < len; ++i) + { + c = (data[i] >> 2) & 0x3f; + ret.append(1, Base64Table[c]); + c = (data[i] << 4) & 0x3f; + if (++i < len) + c |= (data[i] >> 4) & 0x0f; + + ret.append(1, Base64Table[c]); + if (i < len) + { + c = (data[i] << 2) & 0x3f; + if (++i < len) + c |= (data[i] >> 6) & 0x03; + + ret.append(1, Base64Table[c]); + } + else + { + ++i; + ret.append(1, fillchar); + } + + if (i < len) + { + c = data[i] & 0x3f; + ret.append(1, Base64Table[c]); + } + else + { + ret.append(1, fillchar); + } + } + + return(ret); +} + + +string Base64::encode(const string& data) +{ + string::size_type i; + char c; + string::size_type len = data.length(); + string ret; + + ret.reserve(len * 2); + + for (i = 0; i < len; ++i) + { + c = (data[i] >> 2) & 0x3f; + ret.append(1, Base64Table[c]); + c = (data[i] << 4) & 0x3f; + if (++i < len) + c |= (data[i] >> 4) & 0x0f; + + ret.append(1, Base64Table[c]); + if (i < len) + { + c = (data[i] << 2) & 0x3f; + if (++i < len) + c |= (data[i] >> 6) & 0x03; + + ret.append(1, Base64Table[c]); + } + else + { + ++i; + ret.append(1, fillchar); + } + + if (i < len) + { + c = data[i] & 0x3f; + ret.append(1, Base64Table[c]); + } + else + { + ret.append(1, fillchar); + } + } + + return(ret); +} + +string Base64::decode(const string& data) +{ + string::size_type i; + char c; + char c1; + string::size_type len = data.length(); + string ret; + + ret.reserve(len); + + for (i = 0; i < len; ++i) + { + c = static_cast(DecodeTable[static_cast(data[i])]); + ++i; + c1 = static_cast(DecodeTable[static_cast(data[i])]); + c = (c << 2) | ((c1 >> 4) & 0x3); + ret.append(1, c); + if (++i < len) + { + c = data[i]; + if (fillchar == c) + break; + + c = static_cast(DecodeTable[static_cast(data[i])]); + c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf); + ret.append(1, c1); + } + + if (++i < len) + { + c1 = data[i]; + if (fillchar == c1) + break; + + c1 = static_cast(DecodeTable[static_cast(data[i])]); + c = ((c << 6) & 0xc0) | c1; + ret.append(1, c); + } + } + + return(ret); +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc deleted file mode 100644 index e3af08b7..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc +++ /dev/null @@ -1,166 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/base/basictypes.h" -#include "talk/base/bytebuffer.h" -#include "talk/base/byteorder.h" -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1300 -namespace std { - using ::memcpy; -} -#endif - -namespace cricket { - -const int DEFAULT_SIZE = 4096; - -ByteBuffer::ByteBuffer() { - start_ = 0; - end_ = 0; - size_ = DEFAULT_SIZE; - bytes_ = new char[size_]; -} - -ByteBuffer::ByteBuffer(const char* bytes, size_t len) { - start_ = 0; - end_ = len; - size_ = len; - bytes_ = new char[size_]; - memcpy(bytes_, bytes, end_); -} - -ByteBuffer::ByteBuffer(const char* bytes) { - start_ = 0; - end_ = strlen(bytes); - size_ = end_; - bytes_ = new char[size_]; - memcpy(bytes_, bytes, end_); -} - -ByteBuffer::~ByteBuffer() { - delete bytes_; -} - -bool ByteBuffer::ReadUInt8(uint8& val) { - return ReadBytes(reinterpret_cast(&val), 1); -} - -bool ByteBuffer::ReadUInt16(uint16& val) { - uint16 v; - if (!ReadBytes(reinterpret_cast(&v), 2)) { - return false; - } else { - val = NetworkToHost16(v); - return true; - } -} - -bool ByteBuffer::ReadUInt32(uint32& val) { - uint32 v; - if (!ReadBytes(reinterpret_cast(&v), 4)) { - return false; - } else { - val = NetworkToHost32(v); - return true; - } -} - -bool ByteBuffer::ReadString(std::string& val, size_t len) { - if (len > Length()) { - return false; - } else { - val.append(bytes_ + start_, len); - start_ += len; - return true; - } -} - -bool ByteBuffer::ReadBytes(char* val, size_t len) { - if (len > Length()) { - return false; - } else { - memcpy(val, bytes_ + start_, len); - start_ += len; - return true; - } -} - -void ByteBuffer::WriteUInt8(uint8 val) { - WriteBytes(reinterpret_cast(&val), 1); -} - -void ByteBuffer::WriteUInt16(uint16 val) { - uint16 v = HostToNetwork16(val); - WriteBytes(reinterpret_cast(&v), 2); -} - -void ByteBuffer::WriteUInt32(uint32 val) { - uint32 v = HostToNetwork32(val); - WriteBytes(reinterpret_cast(&v), 4); -} - -void ByteBuffer::WriteString(const std::string& val) { - WriteBytes(val.c_str(), val.size()); -} - -void ByteBuffer::WriteBytes(const char* val, size_t len) { - if (Length() + len > Capacity()) - Resize(Length() + len); - - memcpy(bytes_ + end_, val, len); - end_ += len; -} - -void ByteBuffer::Resize(size_t size) { - if (size > size_) - size = _max(size, 3 * size_ / 2); - - size_t len = _min(end_ - start_, size); - char* new_bytes = new char[size]; - memcpy(new_bytes, bytes_ + start_, len); - delete [] bytes_; - - start_ = 0; - end_ = len; - size_ = size; - bytes_ = new_bytes; -} - -void ByteBuffer::Shift(size_t size) { - if (size > Length()) - return; - - end_ = Length() - size; - memmove(bytes_, bytes_ + start_ + size, end_); - start_ = 0; -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cpp new file mode 100644 index 00000000..e3af08b7 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cpp @@ -0,0 +1,166 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/basictypes.h" +#include "talk/base/bytebuffer.h" +#include "talk/base/byteorder.h" +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1300 +namespace std { + using ::memcpy; +} +#endif + +namespace cricket { + +const int DEFAULT_SIZE = 4096; + +ByteBuffer::ByteBuffer() { + start_ = 0; + end_ = 0; + size_ = DEFAULT_SIZE; + bytes_ = new char[size_]; +} + +ByteBuffer::ByteBuffer(const char* bytes, size_t len) { + start_ = 0; + end_ = len; + size_ = len; + bytes_ = new char[size_]; + memcpy(bytes_, bytes, end_); +} + +ByteBuffer::ByteBuffer(const char* bytes) { + start_ = 0; + end_ = strlen(bytes); + size_ = end_; + bytes_ = new char[size_]; + memcpy(bytes_, bytes, end_); +} + +ByteBuffer::~ByteBuffer() { + delete bytes_; +} + +bool ByteBuffer::ReadUInt8(uint8& val) { + return ReadBytes(reinterpret_cast(&val), 1); +} + +bool ByteBuffer::ReadUInt16(uint16& val) { + uint16 v; + if (!ReadBytes(reinterpret_cast(&v), 2)) { + return false; + } else { + val = NetworkToHost16(v); + return true; + } +} + +bool ByteBuffer::ReadUInt32(uint32& val) { + uint32 v; + if (!ReadBytes(reinterpret_cast(&v), 4)) { + return false; + } else { + val = NetworkToHost32(v); + return true; + } +} + +bool ByteBuffer::ReadString(std::string& val, size_t len) { + if (len > Length()) { + return false; + } else { + val.append(bytes_ + start_, len); + start_ += len; + return true; + } +} + +bool ByteBuffer::ReadBytes(char* val, size_t len) { + if (len > Length()) { + return false; + } else { + memcpy(val, bytes_ + start_, len); + start_ += len; + return true; + } +} + +void ByteBuffer::WriteUInt8(uint8 val) { + WriteBytes(reinterpret_cast(&val), 1); +} + +void ByteBuffer::WriteUInt16(uint16 val) { + uint16 v = HostToNetwork16(val); + WriteBytes(reinterpret_cast(&v), 2); +} + +void ByteBuffer::WriteUInt32(uint32 val) { + uint32 v = HostToNetwork32(val); + WriteBytes(reinterpret_cast(&v), 4); +} + +void ByteBuffer::WriteString(const std::string& val) { + WriteBytes(val.c_str(), val.size()); +} + +void ByteBuffer::WriteBytes(const char* val, size_t len) { + if (Length() + len > Capacity()) + Resize(Length() + len); + + memcpy(bytes_ + end_, val, len); + end_ += len; +} + +void ByteBuffer::Resize(size_t size) { + if (size > size_) + size = _max(size, 3 * size_ / 2); + + size_t len = _min(end_ - start_, size); + char* new_bytes = new char[size]; + memcpy(new_bytes, bytes_ + start_, len); + delete [] bytes_; + + start_ = 0; + end_ = len; + size_ = size; + bytes_ = new_bytes; +} + +void ByteBuffer::Shift(size_t size) { + if (size > Length()) + return; + + end_ = Length() - size; + memmove(bytes_, bytes_ + start_ + size, end_); + start_ = 0; +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h index b21be2f1..b5947037 100644 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h @@ -214,7 +214,7 @@ inline void operator delete[](void * ptr, const char * fname, int line) { buzz:: #endif // TRACK_ARRAY_ALLOC_PROBLEM -// If you put "#define new TRACK_NEW" in your .cc file after all includes, it should track the calling function name +// If you put "#define new TRACK_NEW" in your .cpp file after all includes, it should track the calling function name #define TRACK_NEW new(__FILE__,__LINE__) #define TRACK_DEL delete(__FILE__,__LINE__) diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc deleted file mode 100644 index f604050f..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/base/host.h" -#include "talk/base/logging.h" -#include "talk/base/network.h" -#include "talk/base/socket.h" -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1300 -namespace std { - using ::strerror; - using ::exit; -} -#endif - -#ifdef POSIX -extern "C" { -#include -} -#endif // POSIX - -namespace { - -void FatalError(const std::string& name, int err) { - PLOG(LERROR, err) << name; - std::exit(1); -} - -} - -namespace cricket { - -#ifdef POSIX -std::string GetHostName() { - struct utsname nm; - if (uname(&nm) < 0) - FatalError("uname", errno); - return std::string(nm.nodename); -} -#endif - -#ifdef WIN32 -std::string GetHostName() { - // TODO: fix this - return "cricket"; -} -#endif - -// Records information about the local host. -Host* gLocalHost = 0; - -const Host& LocalHost() { - if (!gLocalHost) { - std::vector* networks = new std::vector; - NetworkManager::CreateNetworks(*networks); -#ifdef WIN32 - // This is sort of problematic... one part of the code (the unittests) wants - // 127.0.0.1 to be present and another part (port allocators) don't. Right - // now, they use different APIs, so we can have different behavior. But - // there is something wrong with this. - networks->push_back(new Network("localhost", - SocketAddress::StringToIP("127.0.0.1"))); -#endif - gLocalHost = new Host(GetHostName(), networks); - assert(gLocalHost->networks().size() > 0); - } - - return *gLocalHost; -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cpp new file mode 100644 index 00000000..f604050f --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cpp @@ -0,0 +1,101 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/host.h" +#include "talk/base/logging.h" +#include "talk/base/network.h" +#include "talk/base/socket.h" +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1300 +namespace std { + using ::strerror; + using ::exit; +} +#endif + +#ifdef POSIX +extern "C" { +#include +} +#endif // POSIX + +namespace { + +void FatalError(const std::string& name, int err) { + PLOG(LERROR, err) << name; + std::exit(1); +} + +} + +namespace cricket { + +#ifdef POSIX +std::string GetHostName() { + struct utsname nm; + if (uname(&nm) < 0) + FatalError("uname", errno); + return std::string(nm.nodename); +} +#endif + +#ifdef WIN32 +std::string GetHostName() { + // TODO: fix this + return "cricket"; +} +#endif + +// Records information about the local host. +Host* gLocalHost = 0; + +const Host& LocalHost() { + if (!gLocalHost) { + std::vector* networks = new std::vector; + NetworkManager::CreateNetworks(*networks); +#ifdef WIN32 + // This is sort of problematic... one part of the code (the unittests) wants + // 127.0.0.1 to be present and another part (port allocators) don't. Right + // now, they use different APIs, so we can have different behavior. But + // there is something wrong with this. + networks->push_back(new Network("localhost", + SocketAddress::StringToIP("127.0.0.1"))); +#endif + gLocalHost = new Host(GetHostName(), networks); + assert(gLocalHost->networks().size() > 0); + } + + return *gLocalHost; +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc deleted file mode 100644 index 5befe9fd..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/base/jtime.h" -#include -#include -#include - -namespace cricket { - -#ifdef POSIX -#include -uint32 Time() { - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} -#endif - -#ifdef WIN32 -#include -uint32 Time() { - return GetTickCount(); -} -#endif - -bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier) { - if (earlier <= later) { - return ((earlier <= middle) && (middle <= later)); - } else { - return !((later < middle) && (middle < earlier)); - } -} - -int32 TimeDiff(uint32 later, uint32 earlier) { - uint32 LAST = 0xFFFFFFFF; - uint32 HALF = 0x80000000; - if (TimeIsBetween(earlier + HALF, later, earlier)) { - if (earlier <= later) { - return static_cast(later - earlier); - } else { - return static_cast(later + (LAST - earlier) + 1); - } - } else { - if (later <= earlier) { - return -static_cast(earlier - later); - } else { - return -static_cast(earlier + (LAST - later) + 1); - } - } -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cpp new file mode 100644 index 00000000..5befe9fd --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cpp @@ -0,0 +1,77 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/jtime.h" +#include +#include +#include + +namespace cricket { + +#ifdef POSIX +#include +uint32 Time() { + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} +#endif + +#ifdef WIN32 +#include +uint32 Time() { + return GetTickCount(); +} +#endif + +bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier) { + if (earlier <= later) { + return ((earlier <= middle) && (middle <= later)); + } else { + return !((later < middle) && (middle < earlier)); + } +} + +int32 TimeDiff(uint32 later, uint32 earlier) { + uint32 LAST = 0xFFFFFFFF; + uint32 HALF = 0x80000000; + if (TimeIsBetween(earlier + HALF, later, earlier)) { + if (earlier <= later) { + return static_cast(later - earlier); + } else { + return static_cast(later + (LAST - earlier) + 1); + } + } else { + if (later <= earlier) { + return -static_cast(earlier - later); + } else { + return -static_cast(earlier + (LAST - later) + 1); + } + } +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc deleted file mode 100644 index f10489f7..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc +++ /dev/null @@ -1,321 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#pragma warning(disable:4786) -#endif -#include "talk/base/messagequeue.h" -#include "talk/base/physicalsocketserver.h" - -#ifdef POSIX -extern "C" { -#include -} -#endif - -namespace cricket { - -//------------------------------------------------------------------ -// MessageQueueManager - -MessageQueueManager* MessageQueueManager::instance_; - -MessageQueueManager* MessageQueueManager::Instance() { - // Note: This is not thread safe, but it is first called before threads are - // spawned. - if (!instance_) - instance_ = new MessageQueueManager; - return instance_; -} - -MessageQueueManager::MessageQueueManager() { -} - -MessageQueueManager::~MessageQueueManager() { -} - -void MessageQueueManager::Add(MessageQueue *message_queue) { - CritScope cs(&crit_); - message_queues_.push_back(message_queue); -} - -void MessageQueueManager::Remove(MessageQueue *message_queue) { - CritScope cs(&crit_); - std::vector::iterator iter; - iter = std::find(message_queues_.begin(), message_queues_.end(), message_queue); - if (iter != message_queues_.end()) - message_queues_.erase(iter); -} - -void MessageQueueManager::Clear(MessageHandler *handler) { - CritScope cs(&crit_); - std::vector::iterator iter; - for (iter = message_queues_.begin(); iter != message_queues_.end(); iter++) - (*iter)->Clear(handler); -} - -//------------------------------------------------------------------ -// MessageQueue - -MessageQueue::MessageQueue(SocketServer* ss) - : ss_(ss), new_ss(false), fStop_(false), fPeekKeep_(false) { - if (!ss_) { - new_ss = true; - ss_ = new PhysicalSocketServer(); - } - MessageQueueManager::Instance()->Add(this); -} - -MessageQueue::~MessageQueue() { - Clear(NULL); - if (new_ss) - delete ss_; - MessageQueueManager::Instance()->Remove(this); -} - -void MessageQueue::set_socketserver(SocketServer* ss) { - if (new_ss) - delete ss_; - new_ss = false; - ss_ = ss; -} - -void MessageQueue::Stop() { - fStop_ = true; - ss_->WakeUp(); -} - -bool MessageQueue::IsStopping() { - return fStop_; -} - -void MessageQueue::Restart() { - fStop_ = false; -} - -bool MessageQueue::Peek(Message *pmsg, int cmsWait) { - if (fStop_) - return false; - if (fPeekKeep_) { - *pmsg = msgPeek_; - return true; - } - if (!Get(pmsg, cmsWait)) - return false; - msgPeek_ = *pmsg; - fPeekKeep_ = true; - return true; -} - -bool MessageQueue::Get(Message *pmsg, int cmsWait) { - // Force stopping - - if (fStop_) - return false; - - // Return and clear peek if present - // Always return the peek if it exists so there is Peek/Get symmetry - - if (fPeekKeep_) { - *pmsg = msgPeek_; - fPeekKeep_ = false; - return true; - } - - // Get w/wait + timer scan / dispatch + socket / event multiplexer dispatch - - int cmsTotal = cmsWait; - int cmsElapsed = 0; - uint32 msStart = GetMillisecondCount(); - uint32 msCurrent = msStart; - while (!fStop_) { - // Check for sent messages - - ReceiveSends(); - - // Check queues - - int cmsDelayNext = -1; - { - CritScope cs(&crit_); - - // Check for delayed messages that have been triggered - // Calc the next trigger too - - while (!dmsgq_.empty()) { - if (msCurrent < dmsgq_.top().msTrigger_) { - cmsDelayNext = dmsgq_.top().msTrigger_ - msCurrent; - break; - } - msgq_.push(dmsgq_.top().msg_); - dmsgq_.pop(); - } - - // Check for posted events - - if (!msgq_.empty()) { - *pmsg = msgq_.front(); - msgq_.pop(); - return true; - } - } - - // Which is shorter, the delay wait or the asked wait? - - int cmsNext; - if (cmsWait == -1) { - cmsNext = cmsDelayNext; - } else { - cmsNext = cmsTotal - cmsElapsed; - if (cmsNext < 0) - cmsNext = 0; - if (cmsDelayNext != -1 && cmsDelayNext < cmsNext) - cmsNext = cmsDelayNext; - } - - // Wait and multiplex in the meantime - ss_->Wait(cmsNext, true); - - // If the specified timeout expired, return - - msCurrent = GetMillisecondCount(); - cmsElapsed = msCurrent - msStart; - if (cmsWait != -1) { - if (cmsElapsed >= cmsWait) - return false; - } - } - return false; -} - -void MessageQueue::ReceiveSends() { -} - -void MessageQueue::Post(MessageHandler *phandler, uint32 id, - MessageData *pdata) { - // Keep thread safe - // Add the message to the end of the queue - // Signal for the multiplexer to return - - CritScope cs(&crit_); - Message msg; - msg.phandler = phandler; - msg.message_id = id; - msg.pdata = pdata; - msgq_.push(msg); - ss_->WakeUp(); -} - -void MessageQueue::PostDelayed(int cmsDelay, MessageHandler *phandler, - uint32 id, MessageData *pdata) { - // Keep thread safe - // Add to the priority queue. Gets sorted soonest first. - // Signal for the multiplexer to return. - - CritScope cs(&crit_); - Message msg; - msg.phandler = phandler; - msg.message_id = id; - msg.pdata = pdata; - dmsgq_.push(DelayedMessage(cmsDelay, &msg)); - ss_->WakeUp(); -} - -int MessageQueue::GetDelay() { - CritScope cs(&crit_); - - if (!msgq_.empty()) - return 0; - - if (!dmsgq_.empty()) { - int delay = dmsgq_.top().msTrigger_ - GetMillisecondCount(); - if (delay < 0) - delay = 0; - return delay; - } - - return -1; -} - -void MessageQueue::Clear(MessageHandler *phandler, uint32 id) { - CritScope cs(&crit_); - - // Remove messages with phandler - - if (fPeekKeep_) { - if (phandler == NULL || msgPeek_.phandler == phandler) { - if (id == (uint32)-1 || msgPeek_.message_id == id) { - delete msgPeek_.pdata; - fPeekKeep_ = false; - } - } - } - - // Remove from ordered message queue - - size_t c = msgq_.size(); - while (c-- != 0) { - Message msg = msgq_.front(); - msgq_.pop(); - if (phandler != NULL && msg.phandler != phandler) { - msgq_.push(msg); - } else { - if (id == (uint32)-1 || msg.message_id == id) { - delete msg.pdata; - } else { - msgq_.push(msg); - } - } - } - - // Remove from priority queue. Not directly iterable, so use this approach - - std::queue dmsgs; - while (!dmsgq_.empty()) { - DelayedMessage dmsg = dmsgq_.top(); - dmsgq_.pop(); - if (phandler != NULL && dmsg.msg_.phandler != phandler) { - dmsgs.push(dmsg); - } else { - if (id == (uint32)-1 || dmsg.msg_.message_id == id) { - delete dmsg.msg_.pdata; - } else { - dmsgs.push(dmsg); - } - } - } - while (!dmsgs.empty()) { - dmsgq_.push(dmsgs.front()); - dmsgs.pop(); - } -} - -void MessageQueue::Dispatch(Message *pmsg) { - pmsg->phandler->OnMessage(pmsg); -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cpp new file mode 100644 index 00000000..f10489f7 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cpp @@ -0,0 +1,321 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable:4786) +#endif +#include "talk/base/messagequeue.h" +#include "talk/base/physicalsocketserver.h" + +#ifdef POSIX +extern "C" { +#include +} +#endif + +namespace cricket { + +//------------------------------------------------------------------ +// MessageQueueManager + +MessageQueueManager* MessageQueueManager::instance_; + +MessageQueueManager* MessageQueueManager::Instance() { + // Note: This is not thread safe, but it is first called before threads are + // spawned. + if (!instance_) + instance_ = new MessageQueueManager; + return instance_; +} + +MessageQueueManager::MessageQueueManager() { +} + +MessageQueueManager::~MessageQueueManager() { +} + +void MessageQueueManager::Add(MessageQueue *message_queue) { + CritScope cs(&crit_); + message_queues_.push_back(message_queue); +} + +void MessageQueueManager::Remove(MessageQueue *message_queue) { + CritScope cs(&crit_); + std::vector::iterator iter; + iter = std::find(message_queues_.begin(), message_queues_.end(), message_queue); + if (iter != message_queues_.end()) + message_queues_.erase(iter); +} + +void MessageQueueManager::Clear(MessageHandler *handler) { + CritScope cs(&crit_); + std::vector::iterator iter; + for (iter = message_queues_.begin(); iter != message_queues_.end(); iter++) + (*iter)->Clear(handler); +} + +//------------------------------------------------------------------ +// MessageQueue + +MessageQueue::MessageQueue(SocketServer* ss) + : ss_(ss), new_ss(false), fStop_(false), fPeekKeep_(false) { + if (!ss_) { + new_ss = true; + ss_ = new PhysicalSocketServer(); + } + MessageQueueManager::Instance()->Add(this); +} + +MessageQueue::~MessageQueue() { + Clear(NULL); + if (new_ss) + delete ss_; + MessageQueueManager::Instance()->Remove(this); +} + +void MessageQueue::set_socketserver(SocketServer* ss) { + if (new_ss) + delete ss_; + new_ss = false; + ss_ = ss; +} + +void MessageQueue::Stop() { + fStop_ = true; + ss_->WakeUp(); +} + +bool MessageQueue::IsStopping() { + return fStop_; +} + +void MessageQueue::Restart() { + fStop_ = false; +} + +bool MessageQueue::Peek(Message *pmsg, int cmsWait) { + if (fStop_) + return false; + if (fPeekKeep_) { + *pmsg = msgPeek_; + return true; + } + if (!Get(pmsg, cmsWait)) + return false; + msgPeek_ = *pmsg; + fPeekKeep_ = true; + return true; +} + +bool MessageQueue::Get(Message *pmsg, int cmsWait) { + // Force stopping + + if (fStop_) + return false; + + // Return and clear peek if present + // Always return the peek if it exists so there is Peek/Get symmetry + + if (fPeekKeep_) { + *pmsg = msgPeek_; + fPeekKeep_ = false; + return true; + } + + // Get w/wait + timer scan / dispatch + socket / event multiplexer dispatch + + int cmsTotal = cmsWait; + int cmsElapsed = 0; + uint32 msStart = GetMillisecondCount(); + uint32 msCurrent = msStart; + while (!fStop_) { + // Check for sent messages + + ReceiveSends(); + + // Check queues + + int cmsDelayNext = -1; + { + CritScope cs(&crit_); + + // Check for delayed messages that have been triggered + // Calc the next trigger too + + while (!dmsgq_.empty()) { + if (msCurrent < dmsgq_.top().msTrigger_) { + cmsDelayNext = dmsgq_.top().msTrigger_ - msCurrent; + break; + } + msgq_.push(dmsgq_.top().msg_); + dmsgq_.pop(); + } + + // Check for posted events + + if (!msgq_.empty()) { + *pmsg = msgq_.front(); + msgq_.pop(); + return true; + } + } + + // Which is shorter, the delay wait or the asked wait? + + int cmsNext; + if (cmsWait == -1) { + cmsNext = cmsDelayNext; + } else { + cmsNext = cmsTotal - cmsElapsed; + if (cmsNext < 0) + cmsNext = 0; + if (cmsDelayNext != -1 && cmsDelayNext < cmsNext) + cmsNext = cmsDelayNext; + } + + // Wait and multiplex in the meantime + ss_->Wait(cmsNext, true); + + // If the specified timeout expired, return + + msCurrent = GetMillisecondCount(); + cmsElapsed = msCurrent - msStart; + if (cmsWait != -1) { + if (cmsElapsed >= cmsWait) + return false; + } + } + return false; +} + +void MessageQueue::ReceiveSends() { +} + +void MessageQueue::Post(MessageHandler *phandler, uint32 id, + MessageData *pdata) { + // Keep thread safe + // Add the message to the end of the queue + // Signal for the multiplexer to return + + CritScope cs(&crit_); + Message msg; + msg.phandler = phandler; + msg.message_id = id; + msg.pdata = pdata; + msgq_.push(msg); + ss_->WakeUp(); +} + +void MessageQueue::PostDelayed(int cmsDelay, MessageHandler *phandler, + uint32 id, MessageData *pdata) { + // Keep thread safe + // Add to the priority queue. Gets sorted soonest first. + // Signal for the multiplexer to return. + + CritScope cs(&crit_); + Message msg; + msg.phandler = phandler; + msg.message_id = id; + msg.pdata = pdata; + dmsgq_.push(DelayedMessage(cmsDelay, &msg)); + ss_->WakeUp(); +} + +int MessageQueue::GetDelay() { + CritScope cs(&crit_); + + if (!msgq_.empty()) + return 0; + + if (!dmsgq_.empty()) { + int delay = dmsgq_.top().msTrigger_ - GetMillisecondCount(); + if (delay < 0) + delay = 0; + return delay; + } + + return -1; +} + +void MessageQueue::Clear(MessageHandler *phandler, uint32 id) { + CritScope cs(&crit_); + + // Remove messages with phandler + + if (fPeekKeep_) { + if (phandler == NULL || msgPeek_.phandler == phandler) { + if (id == (uint32)-1 || msgPeek_.message_id == id) { + delete msgPeek_.pdata; + fPeekKeep_ = false; + } + } + } + + // Remove from ordered message queue + + size_t c = msgq_.size(); + while (c-- != 0) { + Message msg = msgq_.front(); + msgq_.pop(); + if (phandler != NULL && msg.phandler != phandler) { + msgq_.push(msg); + } else { + if (id == (uint32)-1 || msg.message_id == id) { + delete msg.pdata; + } else { + msgq_.push(msg); + } + } + } + + // Remove from priority queue. Not directly iterable, so use this approach + + std::queue dmsgs; + while (!dmsgq_.empty()) { + DelayedMessage dmsg = dmsgq_.top(); + dmsgq_.pop(); + if (phandler != NULL && dmsg.msg_.phandler != phandler) { + dmsgs.push(dmsg); + } else { + if (id == (uint32)-1 || dmsg.msg_.message_id == id) { + delete dmsg.msg_.pdata; + } else { + dmsgs.push(dmsg); + } + } + } + while (!dmsgs.empty()) { + dmsgq_.push(dmsgs.front()); + dmsgs.pop(); + } +} + +void MessageQueue::Dispatch(Message *pmsg) { + pmsg->phandler->OnMessage(pmsg); +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc deleted file mode 100644 index 21b3a08f..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc +++ /dev/null @@ -1,382 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/base/host.h" -#include "talk/base/logging.h" -#include "talk/base/network.h" -#include "talk/base/socket.h" // this includes something that makes windows happy -#include "talk/base/jtime.h" -#include "talk/base/basicdefs.h" - -#include -#include -#include -#include -#include - -#ifdef POSIX -extern "C" { -#include -#include -#include -#include -#include -} -#endif // POSIX - -#ifdef WIN32 -#include -#endif - -namespace { - -const double kAlpha = 0.5; // weight for data infinitely far in the past -const double kHalfLife = 2000; // half life of exponential decay (in ms) -const double kLog2 = 0.693147180559945309417; -const double kLambda = kLog2 / kHalfLife; - -// assume so-so quality unless data says otherwise -const double kDefaultQuality = cricket::QUALITY_FAIR; - -typedef std::map StrMap; - -void BuildMap(const StrMap& map, std::string& str) { - str.append("{"); - bool first = true; - for (StrMap::const_iterator i = map.begin(); i != map.end(); ++i) { - if (!first) str.append(","); - str.append(i->first); - str.append("="); - str.append(i->second); - first = false; - } - str.append("}"); -} - -void ParseCheck(std::istringstream& ist, char ch) { - if (ist.get() != ch) - LOG(LERROR) << "Expecting '" << ch << "'"; -} - -std::string ParseString(std::istringstream& ist) { - std::string str; - int count = 0; - while (ist) { - char ch = ist.peek(); - if ((count == 0) && ((ch == '=') || (ch == ',') || (ch == '}'))) { - break; - } else if (ch == '{') { - count += 1; - } else if (ch == '}') { - count -= 1; - if (count < 0) - LOG(LERROR) << "mismatched '{' and '}'"; - } - str.append(1, static_cast(ist.get())); - } - return str; -} - -void ParseMap(const std::string& str, StrMap& map) { - if (str.size() == 0) - return; - std::istringstream ist(str); - ParseCheck(ist, '{'); - for (;;) { - std::string key = ParseString(ist); - ParseCheck(ist, '='); - std::string val = ParseString(ist); - map[key] = val; - if (ist.peek() == ',') - ist.get(); - else - break; - } - ParseCheck(ist, '}'); - if (ist.rdbuf()->in_avail() != 0) - LOG(LERROR) << "Unexpected characters at end"; -} - -#if 0 -const std::string TEST_MAP0_IN = ""; -const std::string TEST_MAP0_OUT = "{}"; -const std::string TEST_MAP1 = "{a=12345}"; -const std::string TEST_MAP2 = "{a=12345,b=67890}"; -const std::string TEST_MAP3 = "{a=12345,b=67890,c=13579}"; -const std::string TEST_MAP4 = "{a={d=12345,e=67890}}"; -const std::string TEST_MAP5 = "{a={d=12345,e=67890},b=67890}"; -const std::string TEST_MAP6 = "{a=12345,b={d=12345,e=67890}}"; -const std::string TEST_MAP7 = "{a=12345,b={d=12345,e=67890},c=13579}"; - -class MyTest { -public: - MyTest() { - test(TEST_MAP0_IN, TEST_MAP0_OUT); - test(TEST_MAP1, TEST_MAP1); - test(TEST_MAP2, TEST_MAP2); - test(TEST_MAP3, TEST_MAP3); - test(TEST_MAP4, TEST_MAP4); - test(TEST_MAP5, TEST_MAP5); - test(TEST_MAP6, TEST_MAP6); - test(TEST_MAP7, TEST_MAP7); - } - void test(const std::string& input, const std::string& exp_output) { - StrMap map; - ParseMap(input, map); - std::string output; - BuildMap(map, output); - LOG(INFO) << " ******** " << (output == exp_output); - } -}; - -static MyTest myTest; -#endif - -template -std::string ToString(T val) { - std::ostringstream ost; - ost << val; - return ost.str(); -} - -template -T FromString(std::string str) { - std::istringstream ist(str); - T val; - ist >> val; - return val; -} - -} - -namespace cricket { - -#ifdef POSIX -void NetworkManager::CreateNetworks(std::vector& networks) { - int fd; - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - PLOG(LERROR, errno) << "socket"; - return; - } - - struct ifconf ifc; - ifc.ifc_len = 64 * sizeof(struct ifreq); - ifc.ifc_buf = new char[ifc.ifc_len]; - - if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { - PLOG(LERROR, errno) << "ioctl"; - return; - } - assert(ifc.ifc_len < static_cast(64 * sizeof(struct ifreq))); - - struct ifreq* ptr = reinterpret_cast(ifc.ifc_buf); - struct ifreq* end = - reinterpret_cast(ifc.ifc_buf + ifc.ifc_len); - - while (ptr < end) { - struct sockaddr_in* inaddr = - reinterpret_cast(&ptr->ifr_ifru.ifru_addr); - if (inaddr->sin_family == AF_INET) { - uint32 ip = ntohl(inaddr->sin_addr.s_addr); - networks.push_back(new Network(std::string(ptr->ifr_name), ip)); - } -#ifdef _SIZEOF_ADDR_IFREQ - ptr = reinterpret_cast( - reinterpret_cast(ptr) + _SIZEOF_ADDR_IFREQ(*ptr)); -#else - ptr++; -#endif - } - - delete [] ifc.ifc_buf; - close(fd); -} -#endif - -#ifdef WIN32 -void NetworkManager::CreateNetworks(std::vector& networks) { - IP_ADAPTER_INFO info_temp; - ULONG len = 0; - - if (GetAdaptersInfo(&info_temp, &len) != ERROR_BUFFER_OVERFLOW) - return; - IP_ADAPTER_INFO *infos = new IP_ADAPTER_INFO[len]; - if (GetAdaptersInfo(infos, &len) != NO_ERROR) - return; - - int count = 0; - for (IP_ADAPTER_INFO *info = infos; info != NULL; info = info->Next) { - if (info->Type == MIB_IF_TYPE_LOOPBACK) - continue; - if (strcmp(info->IpAddressList.IpAddress.String, "0.0.0.0") == 0) - continue; - - // In production, don't transmit the network name because of - // privacy concerns. Transmit a number instead. - - std::string name; -#if defined(PRODUCTION) - std::ostringstream ost; - ost << count; - name = ost.str(); - count++; -#else - name = info->Description; -#endif - - networks.push_back(new Network(name, - SocketAddress::StringToIP(info->IpAddressList.IpAddress.String))); - } - - delete infos; -} -#endif - -void NetworkManager::GetNetworks(std::vector& result) { - std::vector list; - CreateNetworks(list); - - for (uint32 i = 0; i < list.size(); ++i) { - NetworkMap::iterator iter = networks_.find(list[i]->name()); - - Network* network; - if (iter == networks_.end()) { - network = list[i]; - } else { - network = iter->second; - network->set_ip(list[i]->ip()); - delete list[i]; - } - - networks_[network->name()] = network; - result.push_back(network); - } -} - -std::string NetworkManager::GetState() { - StrMap map; - for (NetworkMap::iterator i = networks_.begin(); i != networks_.end(); ++i) - map[i->first] = i->second->GetState(); - - std::string str; - BuildMap(map, str); - return str; -} - -void NetworkManager::SetState(std::string str) { - StrMap map; - ParseMap(str, map); - - for (StrMap::iterator i = map.begin(); i != map.end(); ++i) { - std::string name = i->first; - std::string state = i->second; - - Network* network = new Network(name, 0); - network->SetState(state); - networks_[name] = network; - } -} - -Network::Network(const std::string& name, uint32 ip) - : name_(name), ip_(ip), uniform_numerator_(0), uniform_denominator_(0), - exponential_numerator_(0), exponential_denominator_(0), - quality_(kDefaultQuality) { - - last_data_time_ = Time(); - - // TODO: seed the historical data with one data point based on the link speed - // metric from XP (4.0 if < 50, 3.0 otherwise). -} - -void Network::StartSession(NetworkSession* session) { - assert(std::find(sessions_.begin(), sessions_.end(), session) == sessions_.end()); - sessions_.push_back(session); -} - -void Network::StopSession(NetworkSession* session) { - SessionList::iterator iter = std::find(sessions_.begin(), sessions_.end(), session); - if (iter != sessions_.end()) - sessions_.erase(iter); -} - -void Network::EstimateQuality() { - uint32 now = Time(); - - // Add new data points for the current time. - for (uint32 i = 0; i < sessions_.size(); ++i) { - if (sessions_[i]->HasQuality()) - AddDataPoint(now, sessions_[i]->GetCurrentQuality()); - } - - // Construct the weighted average using both uniform and exponential weights. - - double exp_shift = exp(-kLambda * (now - last_data_time_)); - double numerator = uniform_numerator_ + exp_shift * exponential_numerator_; - double denominator = uniform_denominator_ + exp_shift * exponential_denominator_; - - if (denominator < DBL_EPSILON) - quality_ = kDefaultQuality; - else - quality_ = numerator / denominator; -} - -void Network::AddDataPoint(uint32 time, double quality) { - uniform_numerator_ += kAlpha * quality; - uniform_denominator_ += kAlpha; - - double exp_shift = exp(-kLambda * (time - last_data_time_)); - exponential_numerator_ = (1 - kAlpha) * quality + exp_shift * exponential_numerator_; - exponential_denominator_ = (1 - kAlpha) + exp_shift * exponential_denominator_; - - last_data_time_ = time; -} - -std::string Network::GetState() { - StrMap map; - map["lt"] = ToString(last_data_time_); - map["un"] = ToString(uniform_numerator_); - map["ud"] = ToString(uniform_denominator_); - map["en"] = ToString(exponential_numerator_); - map["ed"] = ToString(exponential_denominator_); - - std::string str; - BuildMap(map, str); - return str; -} - -void Network::SetState(std::string str) { - StrMap map; - ParseMap(str, map); - - last_data_time_ = FromString(map["lt"]); - uniform_numerator_ = FromString(map["un"]); - uniform_denominator_ = FromString(map["ud"]); - exponential_numerator_ = FromString(map["en"]); - exponential_denominator_ = FromString(map["ed"]); -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cpp new file mode 100644 index 00000000..21b3a08f --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cpp @@ -0,0 +1,382 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/host.h" +#include "talk/base/logging.h" +#include "talk/base/network.h" +#include "talk/base/socket.h" // this includes something that makes windows happy +#include "talk/base/jtime.h" +#include "talk/base/basicdefs.h" + +#include +#include +#include +#include +#include + +#ifdef POSIX +extern "C" { +#include +#include +#include +#include +#include +} +#endif // POSIX + +#ifdef WIN32 +#include +#endif + +namespace { + +const double kAlpha = 0.5; // weight for data infinitely far in the past +const double kHalfLife = 2000; // half life of exponential decay (in ms) +const double kLog2 = 0.693147180559945309417; +const double kLambda = kLog2 / kHalfLife; + +// assume so-so quality unless data says otherwise +const double kDefaultQuality = cricket::QUALITY_FAIR; + +typedef std::map StrMap; + +void BuildMap(const StrMap& map, std::string& str) { + str.append("{"); + bool first = true; + for (StrMap::const_iterator i = map.begin(); i != map.end(); ++i) { + if (!first) str.append(","); + str.append(i->first); + str.append("="); + str.append(i->second); + first = false; + } + str.append("}"); +} + +void ParseCheck(std::istringstream& ist, char ch) { + if (ist.get() != ch) + LOG(LERROR) << "Expecting '" << ch << "'"; +} + +std::string ParseString(std::istringstream& ist) { + std::string str; + int count = 0; + while (ist) { + char ch = ist.peek(); + if ((count == 0) && ((ch == '=') || (ch == ',') || (ch == '}'))) { + break; + } else if (ch == '{') { + count += 1; + } else if (ch == '}') { + count -= 1; + if (count < 0) + LOG(LERROR) << "mismatched '{' and '}'"; + } + str.append(1, static_cast(ist.get())); + } + return str; +} + +void ParseMap(const std::string& str, StrMap& map) { + if (str.size() == 0) + return; + std::istringstream ist(str); + ParseCheck(ist, '{'); + for (;;) { + std::string key = ParseString(ist); + ParseCheck(ist, '='); + std::string val = ParseString(ist); + map[key] = val; + if (ist.peek() == ',') + ist.get(); + else + break; + } + ParseCheck(ist, '}'); + if (ist.rdbuf()->in_avail() != 0) + LOG(LERROR) << "Unexpected characters at end"; +} + +#if 0 +const std::string TEST_MAP0_IN = ""; +const std::string TEST_MAP0_OUT = "{}"; +const std::string TEST_MAP1 = "{a=12345}"; +const std::string TEST_MAP2 = "{a=12345,b=67890}"; +const std::string TEST_MAP3 = "{a=12345,b=67890,c=13579}"; +const std::string TEST_MAP4 = "{a={d=12345,e=67890}}"; +const std::string TEST_MAP5 = "{a={d=12345,e=67890},b=67890}"; +const std::string TEST_MAP6 = "{a=12345,b={d=12345,e=67890}}"; +const std::string TEST_MAP7 = "{a=12345,b={d=12345,e=67890},c=13579}"; + +class MyTest { +public: + MyTest() { + test(TEST_MAP0_IN, TEST_MAP0_OUT); + test(TEST_MAP1, TEST_MAP1); + test(TEST_MAP2, TEST_MAP2); + test(TEST_MAP3, TEST_MAP3); + test(TEST_MAP4, TEST_MAP4); + test(TEST_MAP5, TEST_MAP5); + test(TEST_MAP6, TEST_MAP6); + test(TEST_MAP7, TEST_MAP7); + } + void test(const std::string& input, const std::string& exp_output) { + StrMap map; + ParseMap(input, map); + std::string output; + BuildMap(map, output); + LOG(INFO) << " ******** " << (output == exp_output); + } +}; + +static MyTest myTest; +#endif + +template +std::string ToString(T val) { + std::ostringstream ost; + ost << val; + return ost.str(); +} + +template +T FromString(std::string str) { + std::istringstream ist(str); + T val; + ist >> val; + return val; +} + +} + +namespace cricket { + +#ifdef POSIX +void NetworkManager::CreateNetworks(std::vector& networks) { + int fd; + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + PLOG(LERROR, errno) << "socket"; + return; + } + + struct ifconf ifc; + ifc.ifc_len = 64 * sizeof(struct ifreq); + ifc.ifc_buf = new char[ifc.ifc_len]; + + if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { + PLOG(LERROR, errno) << "ioctl"; + return; + } + assert(ifc.ifc_len < static_cast(64 * sizeof(struct ifreq))); + + struct ifreq* ptr = reinterpret_cast(ifc.ifc_buf); + struct ifreq* end = + reinterpret_cast(ifc.ifc_buf + ifc.ifc_len); + + while (ptr < end) { + struct sockaddr_in* inaddr = + reinterpret_cast(&ptr->ifr_ifru.ifru_addr); + if (inaddr->sin_family == AF_INET) { + uint32 ip = ntohl(inaddr->sin_addr.s_addr); + networks.push_back(new Network(std::string(ptr->ifr_name), ip)); + } +#ifdef _SIZEOF_ADDR_IFREQ + ptr = reinterpret_cast( + reinterpret_cast(ptr) + _SIZEOF_ADDR_IFREQ(*ptr)); +#else + ptr++; +#endif + } + + delete [] ifc.ifc_buf; + close(fd); +} +#endif + +#ifdef WIN32 +void NetworkManager::CreateNetworks(std::vector& networks) { + IP_ADAPTER_INFO info_temp; + ULONG len = 0; + + if (GetAdaptersInfo(&info_temp, &len) != ERROR_BUFFER_OVERFLOW) + return; + IP_ADAPTER_INFO *infos = new IP_ADAPTER_INFO[len]; + if (GetAdaptersInfo(infos, &len) != NO_ERROR) + return; + + int count = 0; + for (IP_ADAPTER_INFO *info = infos; info != NULL; info = info->Next) { + if (info->Type == MIB_IF_TYPE_LOOPBACK) + continue; + if (strcmp(info->IpAddressList.IpAddress.String, "0.0.0.0") == 0) + continue; + + // In production, don't transmit the network name because of + // privacy concerns. Transmit a number instead. + + std::string name; +#if defined(PRODUCTION) + std::ostringstream ost; + ost << count; + name = ost.str(); + count++; +#else + name = info->Description; +#endif + + networks.push_back(new Network(name, + SocketAddress::StringToIP(info->IpAddressList.IpAddress.String))); + } + + delete infos; +} +#endif + +void NetworkManager::GetNetworks(std::vector& result) { + std::vector list; + CreateNetworks(list); + + for (uint32 i = 0; i < list.size(); ++i) { + NetworkMap::iterator iter = networks_.find(list[i]->name()); + + Network* network; + if (iter == networks_.end()) { + network = list[i]; + } else { + network = iter->second; + network->set_ip(list[i]->ip()); + delete list[i]; + } + + networks_[network->name()] = network; + result.push_back(network); + } +} + +std::string NetworkManager::GetState() { + StrMap map; + for (NetworkMap::iterator i = networks_.begin(); i != networks_.end(); ++i) + map[i->first] = i->second->GetState(); + + std::string str; + BuildMap(map, str); + return str; +} + +void NetworkManager::SetState(std::string str) { + StrMap map; + ParseMap(str, map); + + for (StrMap::iterator i = map.begin(); i != map.end(); ++i) { + std::string name = i->first; + std::string state = i->second; + + Network* network = new Network(name, 0); + network->SetState(state); + networks_[name] = network; + } +} + +Network::Network(const std::string& name, uint32 ip) + : name_(name), ip_(ip), uniform_numerator_(0), uniform_denominator_(0), + exponential_numerator_(0), exponential_denominator_(0), + quality_(kDefaultQuality) { + + last_data_time_ = Time(); + + // TODO: seed the historical data with one data point based on the link speed + // metric from XP (4.0 if < 50, 3.0 otherwise). +} + +void Network::StartSession(NetworkSession* session) { + assert(std::find(sessions_.begin(), sessions_.end(), session) == sessions_.end()); + sessions_.push_back(session); +} + +void Network::StopSession(NetworkSession* session) { + SessionList::iterator iter = std::find(sessions_.begin(), sessions_.end(), session); + if (iter != sessions_.end()) + sessions_.erase(iter); +} + +void Network::EstimateQuality() { + uint32 now = Time(); + + // Add new data points for the current time. + for (uint32 i = 0; i < sessions_.size(); ++i) { + if (sessions_[i]->HasQuality()) + AddDataPoint(now, sessions_[i]->GetCurrentQuality()); + } + + // Construct the weighted average using both uniform and exponential weights. + + double exp_shift = exp(-kLambda * (now - last_data_time_)); + double numerator = uniform_numerator_ + exp_shift * exponential_numerator_; + double denominator = uniform_denominator_ + exp_shift * exponential_denominator_; + + if (denominator < DBL_EPSILON) + quality_ = kDefaultQuality; + else + quality_ = numerator / denominator; +} + +void Network::AddDataPoint(uint32 time, double quality) { + uniform_numerator_ += kAlpha * quality; + uniform_denominator_ += kAlpha; + + double exp_shift = exp(-kLambda * (time - last_data_time_)); + exponential_numerator_ = (1 - kAlpha) * quality + exp_shift * exponential_numerator_; + exponential_denominator_ = (1 - kAlpha) + exp_shift * exponential_denominator_; + + last_data_time_ = time; +} + +std::string Network::GetState() { + StrMap map; + map["lt"] = ToString(last_data_time_); + map["un"] = ToString(uniform_numerator_); + map["ud"] = ToString(uniform_denominator_); + map["en"] = ToString(exponential_numerator_); + map["ed"] = ToString(exponential_denominator_); + + std::string str; + BuildMap(map, str); + return str; +} + +void Network::SetState(std::string str) { + StrMap map; + ParseMap(str, map); + + last_data_time_ = FromString(map["lt"]); + uniform_numerator_ = FromString(map["un"]); + uniform_denominator_ = FromString(map["ud"]); + exponential_numerator_ = FromString(map["en"]); + exponential_denominator_ = FromString(map["ed"]); +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc deleted file mode 100644 index 37836302..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc +++ /dev/null @@ -1,1116 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#pragma warning(disable:4786) -#endif - -#include -#include - -#ifdef POSIX -extern "C" { -#include -#include -#include -#include -#include -} -#endif - -#include "talk/base/basictypes.h" -#include "talk/base/byteorder.h" -#include "talk/base/common.h" -#include "talk/base/logging.h" -#include "talk/base/physicalsocketserver.h" -#include "talk/base/jtime.h" -#include "talk/base/winping.h" - -#ifdef __linux -#define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h -#endif // __linux - -#ifdef WIN32 -#include -#include -#define _WINSOCKAPI_ -#include -#undef SetPort - -class WinsockInitializer { -public: - WinsockInitializer() { - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD(1, 0); - err_ = WSAStartup(wVersionRequested, &wsaData); - } - ~WinsockInitializer() { - WSACleanup(); - } - int error() { - return err_; - } -private: - int err_; -}; -WinsockInitializer g_winsockinit; -#endif - -namespace cricket { - -const int kfRead = 0x0001; -const int kfWrite = 0x0002; -const int kfConnect = 0x0004; -const int kfClose = 0x0008; - - -// Standard MTUs -const uint16 PACKET_MAXIMUMS[] = { - 65535, // Theoretical maximum, Hyperchannel - 32000, // Nothing - 17914, // 16Mb IBM Token Ring - 8166, // IEEE 802.4 - //4464, // IEEE 802.5 (4Mb max) - 4352, // FDDI - //2048, // Wideband Network - 2002, // IEEE 802.5 (4Mb recommended) - //1536, // Expermental Ethernet Networks - //1500, // Ethernet, Point-to-Point (default) - 1492, // IEEE 802.3 - 1006, // SLIP, ARPANET - //576, // X.25 Networks - //544, // DEC IP Portal - //512, // NETBIOS - 508, // IEEE 802/Source-Rt Bridge, ARCNET - 296, // Point-to-Point (low delay) - 68, // Official minimum - 0, // End of list marker -}; - -const uint32 IP_HEADER_SIZE = 20; -const uint32 ICMP_HEADER_SIZE = 8; - -class PhysicalSocket : public AsyncSocket { -public: - PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET) - : ss_(ss), s_(s), enabled_events_(0), error_(0), - state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED) { - if (s != INVALID_SOCKET) - enabled_events_ = kfRead | kfWrite; - } - - virtual ~PhysicalSocket() { - Close(); - } - - // Creates the underlying OS socket (same as the "socket" function). - virtual bool Create(int type) { - Close(); - s_ = ::socket(AF_INET, type, 0); - UpdateLastError(); - enabled_events_ = kfRead | kfWrite; - return s_ != INVALID_SOCKET; - } - - SocketAddress GetLocalAddress() const { - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int result = ::getsockname(s_, (struct sockaddr*)&addr, &addrlen); - assert(addrlen == sizeof(addr)); - if (result >= 0) { - return SocketAddress(NetworkToHost32(addr.sin_addr.s_addr), - NetworkToHost16(addr.sin_port)); - } else { - return SocketAddress(); - } - } - - SocketAddress GetRemoteAddress() const { - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); - int result = ::getpeername(s_, (struct sockaddr*)&addr, &addrlen); - assert(addrlen == sizeof(addr)); - if (result >= 0) { - return SocketAddress( - NetworkToHost32(addr.sin_addr.s_addr), - NetworkToHost16(addr.sin_port)); - } else { - assert(errno == ENOTCONN); - return SocketAddress(); - } - } - - int Bind(const SocketAddress& addr) { - struct sockaddr_in saddr; - IP2SA(&addr, &saddr); - int err = ::bind(s_, (struct sockaddr*)&saddr, sizeof(saddr)); - UpdateLastError(); - return err; - } - - int Connect(const SocketAddress& addr) { - // TODO: Implicit creation is required to reconnect... - // ...but should we make it more explicit? - if ((s_ == INVALID_SOCKET) && !Create(SOCK_STREAM)) - return SOCKET_ERROR; - SocketAddress addr2(addr); - if (addr2.IsUnresolved()) { - LOG(INFO) << "Resolving addr in PhysicalSocket::Connect"; - addr2.Resolve(); // TODO: Do this async later? - } - struct sockaddr_in saddr; - IP2SA(&addr2, &saddr); - int err = ::connect(s_, (struct sockaddr*)&saddr, sizeof(saddr)); - UpdateLastError(); - //LOG(INFO) << "SOCK[" << static_cast(s_) << "] Connect(" << addr2.ToString() << ") Ret: " << err << " Error: " << error_; - if (err == 0) { - state_ = CS_CONNECTED; - } else if (IsBlockingError(error_)) { - state_ = CS_CONNECTING; - enabled_events_ |= kfConnect; - } - return err; - } - - int GetError() const { - return error_; - } - - void SetError(int error) { - error_ = error; - } - - ConnState GetState() const { - return state_; - } - - int SetOption(Option opt, int value) { - assert(opt == OPT_DONTFRAGMENT); -#ifdef WIN32 - value = (value == 0) ? 0 : 1; - return ::setsockopt( - s_, IPPROTO_IP, IP_DONTFRAGMENT, reinterpret_cast(&value), - sizeof(value)); -#endif -#ifdef __linux - value = (value == 0) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO; - return ::setsockopt( - s_, IPPROTO_IP, IP_MTU_DISCOVER, &value, sizeof(value)); -#endif -#ifdef OSX - // This is not possible on OSX. - return -1; -#endif - } - - int Send(const void *pv, size_t cb) { - int sent = ::send(s_, reinterpret_cast(pv), (int)cb, 0); - UpdateLastError(); - //LOG(INFO) << "SOCK[" << static_cast(s_) << "] Send(" << cb << ") Ret: " << sent << " Error: " << error_; - ASSERT(sent <= static_cast(cb)); // We have seen minidumps where this may be false - if ((sent < 0) && IsBlockingError(error_)) { - enabled_events_ |= kfWrite; - } - return sent; - } - - int SendTo(const void *pv, size_t cb, const SocketAddress& addr) { - struct sockaddr_in saddr; - IP2SA(&addr, &saddr); - int sent = ::sendto( - s_, (const char *)pv, (int)cb, 0, (struct sockaddr*)&saddr, - sizeof(saddr)); - UpdateLastError(); - ASSERT(sent <= static_cast(cb)); // We have seen minidumps where this may be false - if ((sent < 0) && IsBlockingError(error_)) { - enabled_events_ |= kfWrite; - } - return sent; - } - - int Recv(void *pv, size_t cb) { - int received = ::recv(s_, (char *)pv, (int)cb, 0); - UpdateLastError(); - if ((received >= 0) || IsBlockingError(error_)) { - enabled_events_ |= kfRead; - } - return received; - } - - int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) { - struct sockaddr saddr; - socklen_t cbAddr = sizeof(saddr); - int received = ::recvfrom(s_, (char *)pv, (int)cb, 0, &saddr, &cbAddr); - UpdateLastError(); - if ((received >= 0) && (paddr != NULL)) - SA2IP(&saddr, paddr); - if ((received >= 0) || IsBlockingError(error_)) { - enabled_events_ |= kfRead; - } - return received; - } - - int Listen(int backlog) { - int err = ::listen(s_, backlog); - UpdateLastError(); - if (err == 0) - state_ = CS_CONNECTING; - return err; - } - - Socket* Accept(SocketAddress *paddr) { - struct sockaddr saddr; - socklen_t cbAddr = sizeof(saddr); - SOCKET s = ::accept(s_, &saddr, &cbAddr); - UpdateLastError(); - if (s == INVALID_SOCKET) - return NULL; - if (paddr != NULL) - SA2IP(&saddr, paddr); - return ss_->WrapSocket(s); - } - - int Close() { - if (s_ == INVALID_SOCKET) - return 0; - int err = ::closesocket(s_); - UpdateLastError(); - //LOG(INFO) << "SOCK[" << static_cast(s_) << "] Close() Ret: " << err << " Error: " << error_; - s_ = INVALID_SOCKET; - state_ = CS_CLOSED; - enabled_events_ = 0; - return err; - } - - int EstimateMTU(uint16* mtu) { - SocketAddress addr = GetRemoteAddress(); - if (addr.IsAny()) { - error_ = ENOTCONN; - return -1; - } - -#ifdef WIN32 - - WinPing ping; - if (!ping.IsValid()) { - error_ = EINVAL; // can't think of a better error ID - return -1; - } - - for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) { - int32 size = PACKET_MAXIMUMS[level] - IP_HEADER_SIZE - ICMP_HEADER_SIZE; - if (ping.Ping(addr.ip(), size, 0, 1, false) != WinPing::PING_TOO_LARGE) { - *mtu = PACKET_MAXIMUMS[level]; - return 0; - } - } - - assert(false); - return 0; - -#endif // WIN32 - -#ifdef __linux - - int value; - socklen_t vlen = sizeof(value); - int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen); - if (err < 0) { - UpdateLastError(); - return err; - } - - assert((0 <= value) && (value <= 65536)); - *mtu = uint16(value); - return 0; - -#endif // __linux - - // TODO: OSX support - } - - SocketServer* socketserver() { return ss_; } - -protected: - PhysicalSocketServer* ss_; - SOCKET s_; - uint32 enabled_events_; - int error_; - ConnState state_; - - void UpdateLastError() { -#ifdef WIN32 - error_ = WSAGetLastError(); -#endif -#ifdef POSIX - error_ = errno; -#endif - } - - void IP2SA(const SocketAddress *paddr, struct sockaddr_in *psaddr) { - memset(psaddr, 0, sizeof(*psaddr)); - psaddr->sin_family = AF_INET; - psaddr->sin_port = HostToNetwork16(paddr->port()); - if (paddr->ip() == 0) - psaddr->sin_addr.s_addr = INADDR_ANY; - else - psaddr->sin_addr.s_addr = HostToNetwork32(paddr->ip()); - } - - void SA2IP(const struct sockaddr *psaddr, SocketAddress *paddr) { - const struct sockaddr_in *psaddr_in = - reinterpret_cast(psaddr); - paddr->SetIP(NetworkToHost32(psaddr_in->sin_addr.s_addr)); - paddr->SetPort(NetworkToHost16(psaddr_in->sin_port)); - } -}; - -#ifdef POSIX -class Dispatcher { -public: - virtual uint32 GetRequestedEvents() = 0; - virtual void OnPreEvent(uint32 ff) = 0; - virtual void OnEvent(uint32 ff, int err) = 0; - virtual int GetDescriptor() = 0; -}; - -class EventDispatcher : public Dispatcher { -public: - EventDispatcher(PhysicalSocketServer* ss) : ss_(ss), fSignaled_(false) { - if (pipe(afd_) < 0) - LOG(LERROR) << "pipe failed"; - ss_->Add(this); - } - - virtual ~EventDispatcher() { - ss_->Remove(this); - close(afd_[0]); - close(afd_[1]); - } - - virtual void Signal() { - CritScope cs(&crit_); - if (!fSignaled_) { - uint8 b = 0; - if (write(afd_[1], &b, sizeof(b)) < 0) - LOG(LERROR) << "write failed"; - fSignaled_ = true; - } - } - - virtual uint32 GetRequestedEvents() { - return kfRead; - } - - virtual void OnPreEvent(uint32 ff) { - // It is not possible to perfectly emulate an auto-resetting event with - // pipes. This simulates it by resetting before the event is handled. - - CritScope cs(&crit_); - if (fSignaled_) { - uint8 b; - read(afd_[0], &b, sizeof(b)); - fSignaled_ = false; - } - } - - virtual void OnEvent(uint32 ff, int err) { - assert(false); - } - - virtual int GetDescriptor() { - return afd_[0]; - } - -private: - PhysicalSocketServer *ss_; - int afd_[2]; - bool fSignaled_; - CriticalSection crit_; -}; - -class SocketDispatcher : public Dispatcher, public PhysicalSocket { -public: - SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) { - ss_->Add(this); - } - SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) : PhysicalSocket(ss, s) { - ss_->Add(this); - } - - virtual ~SocketDispatcher() { - ss_->Remove(this); - } - - bool Initialize() { - fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK); - return true; - } - - virtual bool Create(int type) { - // Change the socket to be non-blocking. - if (!PhysicalSocket::Create(type)) - return false; - - return Initialize(); - } - - virtual int GetDescriptor() { - return s_; - } - - virtual uint32 GetRequestedEvents() { - return enabled_events_; - } - - virtual void OnPreEvent(uint32 ff) { - } - - virtual void OnEvent(uint32 ff, int err) { - if ((ff & kfRead) != 0) { - enabled_events_ &= ~kfRead; - SignalReadEvent(this); - } - if ((ff & kfWrite) != 0) { - enabled_events_ &= ~kfWrite; - SignalWriteEvent(this); - } - if ((ff & kfConnect) != 0) { - enabled_events_ &= ~kfConnect; - SignalConnectEvent(this); - } - if ((ff & kfClose) != 0) - SignalCloseEvent(this, err); - } -}; - -class FileDispatcher: public Dispatcher, public AsyncFile { -public: - FileDispatcher(int fd, PhysicalSocketServer *ss) : ss_(ss), fd_(fd) { - set_readable(true); - - ss_->Add(this); - - fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL, 0) | O_NONBLOCK); - } - - virtual ~FileDispatcher() { - ss_->Remove(this); - } - - SocketServer* socketserver() { return ss_; } - - virtual int GetDescriptor() { - return fd_; - } - - virtual uint32 GetRequestedEvents() { - return flags_; - } - - virtual void OnPreEvent(uint32 ff) { - } - - virtual void OnEvent(uint32 ff, int err) { - if ((ff & kfRead) != 0) - SignalReadEvent(this); - if ((ff & kfWrite) != 0) - SignalWriteEvent(this); - if ((ff & kfClose) != 0) - SignalCloseEvent(this, err); - } - - virtual bool readable() { - return (flags_ & kfRead) != 0; - } - - virtual void set_readable(bool value) { - flags_ = value ? (flags_ | kfRead) : (flags_ & ~kfRead); - } - - virtual bool writable() { - return (flags_ & kfWrite) != 0; - } - - virtual void set_writable(bool value) { - flags_ = value ? (flags_ | kfWrite) : (flags_ & ~kfWrite); - } - -private: - PhysicalSocketServer* ss_; - int fd_; - int flags_; -}; - -AsyncFile* PhysicalSocketServer::CreateFile(int fd) { - return new FileDispatcher(fd, this); -} - -#endif // POSIX - -#ifdef WIN32 -class Dispatcher { -public: - virtual uint32 GetRequestedEvents() = 0; - virtual void OnPreEvent(uint32 ff) = 0; - virtual void OnEvent(uint32 ff, int err) = 0; - virtual WSAEVENT GetWSAEvent() = 0; - virtual SOCKET GetSocket() = 0; - virtual bool CheckSignalClose() = 0; -}; - -uint32 FlagsToEvents(uint32 events) { - uint32 ffFD = FD_CLOSE | FD_ACCEPT; - if (events & kfRead) - ffFD |= FD_READ; - if (events & kfWrite) - ffFD |= FD_WRITE; - if (events & kfConnect) - ffFD |= FD_CONNECT; - return ffFD; -} - -class EventDispatcher : public Dispatcher { -public: - EventDispatcher(PhysicalSocketServer *ss) : ss_(ss) { - if (hev_ = WSACreateEvent()) { - ss_->Add(this); - } - } - - ~EventDispatcher() { - if (hev_ != NULL) { - ss_->Remove(this); - WSACloseEvent(hev_); - hev_ = NULL; - } - } - - virtual void Signal() { - if (hev_ != NULL) - WSASetEvent(hev_); - } - - virtual uint32 GetRequestedEvents() { - return 0; - } - - virtual void OnPreEvent(uint32 ff) { - WSAResetEvent(hev_); - } - - virtual void OnEvent(uint32 ff, int err) { - } - - virtual WSAEVENT GetWSAEvent() { - return hev_; - } - - virtual SOCKET GetSocket() { - return INVALID_SOCKET; - } - - virtual bool CheckSignalClose() { return false; } - -private: - PhysicalSocketServer* ss_; - WSAEVENT hev_; -}; - -class SocketDispatcher : public Dispatcher, public PhysicalSocket { -public: - static int next_id_; - int id_; - bool signal_close_; - int signal_err_; - - SocketDispatcher(PhysicalSocketServer* ss) : PhysicalSocket(ss), id_(0), signal_close_(false) { - } - SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) : PhysicalSocket(ss, s), id_(0), signal_close_(false) { - } - - virtual ~SocketDispatcher() { - Close(); - } - - bool Initialize() { - assert(s_ != INVALID_SOCKET); - // Must be a non-blocking - u_long argp = 1; - ioctlsocket(s_, FIONBIO, &argp); - ss_->Add(this); - return true; - } - - virtual bool Create(int type) { - // Create socket - if (!PhysicalSocket::Create(type)) - return false; - - if (!Initialize()) - return false; - - do { id_ = ++next_id_; } while (id_ == 0); - return true; - } - - virtual int Close() { - if (s_ == INVALID_SOCKET) - return 0; - - id_ = 0; - signal_close_ = false; - ss_->Remove(this); - return PhysicalSocket::Close(); - } - - virtual uint32 GetRequestedEvents() { - return enabled_events_; - } - - virtual void OnPreEvent(uint32 ff) { - if ((ff & kfConnect) != 0) - state_ = CS_CONNECTED; - } - - virtual void OnEvent(uint32 ff, int err) { - int cache_id = id_; - if ((ff & kfRead) != 0) { - enabled_events_ &= ~kfRead; - SignalReadEvent(this); - } - if (((ff & kfWrite) != 0) && (id_ == cache_id)) { - enabled_events_ &= ~kfWrite; - SignalWriteEvent(this); - } - if (((ff & kfConnect) != 0) && (id_ == cache_id)) { - enabled_events_ &= ~kfConnect; - SignalConnectEvent(this); - } - if (((ff & kfClose) != 0) && (id_ == cache_id)) { - //LOG(INFO) << "SOCK[" << static_cast(s_) << "] OnClose() Error: " << err; - signal_close_ = true; - signal_err_ = err; - } - } - - virtual WSAEVENT GetWSAEvent() { - return WSA_INVALID_EVENT; - } - - virtual SOCKET GetSocket() { - return s_; - } - - virtual bool CheckSignalClose() { - if (!signal_close_) - return false; - - char ch; - if (recv(s_, &ch, 1, MSG_PEEK) > 0) - return false; - - signal_close_ = false; - SignalCloseEvent(this, signal_err_); - return true; - } -}; - -int SocketDispatcher::next_id_ = 0; - -#endif // WIN32 - -// Sets the value of a boolean value to false when signaled. -class Signaler : public EventDispatcher { -public: - Signaler(PhysicalSocketServer* ss, bool* pf) - : EventDispatcher(ss), pf_(pf) { - } - virtual ~Signaler() { } - - void OnEvent(uint32 ff, int err) { - if (pf_) - *pf_ = false; - } - -private: - bool *pf_; -}; - -PhysicalSocketServer::PhysicalSocketServer() : fWait_(false), - last_tick_tracked_(0), last_tick_dispatch_count_(0) { - signal_wakeup_ = new Signaler(this, &fWait_); -} - -PhysicalSocketServer::~PhysicalSocketServer() { - delete signal_wakeup_; -} - -void PhysicalSocketServer::WakeUp() { - signal_wakeup_->Signal(); -} - -Socket* PhysicalSocketServer::CreateSocket(int type) { - PhysicalSocket* socket = new PhysicalSocket(this); - if (socket->Create(type)) { - return socket; - } else { - delete socket; - return 0; - } -} - -AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int type) { - SocketDispatcher* dispatcher = new SocketDispatcher(this); - if (dispatcher->Create(type)) { - return dispatcher; - } else { - delete dispatcher; - return 0; - } -} - -AsyncSocket* PhysicalSocketServer::WrapSocket(SOCKET s) { - SocketDispatcher* dispatcher = new SocketDispatcher(s, this); - if (dispatcher->Initialize()) { - return dispatcher; - } else { - delete dispatcher; - return 0; - } -} - -void PhysicalSocketServer::Add(Dispatcher *pdispatcher) { - CritScope cs(&crit_); - dispatchers_.push_back(pdispatcher); -} - -void PhysicalSocketServer::Remove(Dispatcher *pdispatcher) { - CritScope cs(&crit_); - dispatchers_.erase(std::remove(dispatchers_.begin(), dispatchers_.end(), pdispatcher), dispatchers_.end()); -} - -#ifdef POSIX -bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) { - // Calculate timing information - - struct timeval *ptvWait = NULL; - struct timeval tvWait; - struct timeval tvStop; - if (cmsWait != -1) { - // Calculate wait timeval - tvWait.tv_sec = cmsWait / 1000; - tvWait.tv_usec = (cmsWait % 1000) * 1000; - ptvWait = &tvWait; - - // Calculate when to return in a timeval - gettimeofday(&tvStop, NULL); - tvStop.tv_sec += tvWait.tv_sec; - tvStop.tv_usec += tvWait.tv_usec; - if (tvStop.tv_usec >= 1000000) { - tvStop.tv_usec -= 1000000; - tvStop.tv_sec += 1; - } - } - - // Zero all fd_sets. Don't need to do this inside the loop since - // select() zeros the descriptors not signaled - - fd_set fdsRead; - FD_ZERO(&fdsRead); - fd_set fdsWrite; - FD_ZERO(&fdsWrite); - - fWait_ = true; - - while (fWait_) { - int fdmax = -1; - { - CritScope cr(&crit_); - for (unsigned i = 0; i < dispatchers_.size(); i++) { - // Query dispatchers for read and write wait state - - Dispatcher *pdispatcher = dispatchers_[i]; - assert(pdispatcher); - if (!process_io && (pdispatcher != signal_wakeup_)) - continue; - int fd = pdispatcher->GetDescriptor(); - if (fd > fdmax) - fdmax = fd; - uint32 ff = pdispatcher->GetRequestedEvents(); - if (ff & kfRead) - FD_SET(fd, &fdsRead); - if (ff & (kfWrite | kfConnect)) - FD_SET(fd, &fdsWrite); - } - } - - // Wait then call handlers as appropriate - // < 0 means error - // 0 means timeout - // > 0 means count of descriptors ready - int n = select(fdmax + 1, &fdsRead, &fdsWrite, NULL, ptvWait); - - // If error, return error - // todo: do something intelligent - - if (n < 0) - return false; - - // If timeout, return success - - if (n == 0) - return true; - - // We have signaled descriptors - - { - CritScope cr(&crit_); - for (unsigned i = 0; i < dispatchers_.size(); i++) { - Dispatcher *pdispatcher = dispatchers_[i]; - int fd = pdispatcher->GetDescriptor(); - uint32 ff = 0; - if (FD_ISSET(fd, &fdsRead)) { - FD_CLR(fd, &fdsRead); - ff |= kfRead; - } - if (FD_ISSET(fd, &fdsWrite)) { - FD_CLR(fd, &fdsWrite); - if (pdispatcher->GetRequestedEvents() & kfConnect) { - ff |= kfConnect; - } else { - ff |= kfWrite; - } - } - if (ff != 0) { - pdispatcher->OnPreEvent(ff); - pdispatcher->OnEvent(ff, 0); - } - } - } - - // Recalc the time remaining to wait. Doing it here means it doesn't get - // calced twice the first time through the loop - - if (cmsWait != -1) { - ptvWait->tv_sec = 0; - ptvWait->tv_usec = 0; - struct timeval tvT; - gettimeofday(&tvT, NULL); - if (tvStop.tv_sec >= tvT.tv_sec) { - ptvWait->tv_sec = tvStop.tv_sec - tvT.tv_sec; - ptvWait->tv_usec = tvStop.tv_usec - tvT.tv_usec; - if (ptvWait->tv_usec < 0) { - ptvWait->tv_usec += 1000000; - ptvWait->tv_sec -= 1; - } - } - } - } - - return true; -} -#endif // POSIX - -#ifdef WIN32 -bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) -{ - int cmsTotal = cmsWait; - int cmsElapsed = 0; - uint32 msStart = GetMillisecondCount(); - -#if LOGGING - if (last_tick_dispatch_count_ == 0) { - last_tick_tracked_ = msStart; - } -#endif - - WSAEVENT socket_ev = WSACreateEvent(); - - fWait_ = true; - while (fWait_) { - std::vector events; - std::vector event_owners; - - events.push_back(socket_ev); - - { - CritScope cr(&crit_); - for (size_t i = 0; i < dispatchers_.size(); ++i) { - Dispatcher * disp = dispatchers_[i]; - if (!process_io && (disp != signal_wakeup_)) - continue; - SOCKET s = disp->GetSocket(); - if (disp->CheckSignalClose()) { - // We just signalled close, don't poll this socket - } else if (s != INVALID_SOCKET) { - WSAEventSelect(s, events[0], FlagsToEvents(disp->GetRequestedEvents())); - } else { - events.push_back(disp->GetWSAEvent()); - event_owners.push_back(disp); - } - } - } - - // Which is shorter, the delay wait or the asked wait? - - int cmsNext; - if (cmsWait == -1) { - cmsNext = cmsWait; - } else { - cmsNext = cmsTotal - cmsElapsed; - if (cmsNext < 0) - cmsNext = 0; - } - - // Wait for one of the events to signal - DWORD dw = WSAWaitForMultipleEvents(static_cast(events.size()), &events[0], false, cmsNext, false); - -#if 0 // LOGGING - // we track this information purely for logging purposes. - last_tick_dispatch_count_++; - if (last_tick_dispatch_count_ >= 1000) { - uint32 now = GetMillisecondCount(); - LOG(INFO) << "PhysicalSocketServer took " << TimeDiff(now, last_tick_tracked_) << "ms for 1000 events"; - - // If we get more than 1000 events in a second, we are spinning badly - // (normally it should take about 8-20 seconds). - assert(TimeDiff(now, last_tick_tracked_) > 1000); - - last_tick_tracked_ = now; - last_tick_dispatch_count_ = 0; - } -#endif - - // Failed? - // todo: need a better strategy than this! - - if (dw == WSA_WAIT_FAILED) { - int error = WSAGetLastError(); - assert(false); - WSACloseEvent(socket_ev); - return false; - } - - // Timeout? - - if (dw == WSA_WAIT_TIMEOUT) { - WSACloseEvent(socket_ev); - return true; - } - - // Figure out which one it is and call it - - { - CritScope cr(&crit_); - int index = dw - WSA_WAIT_EVENT_0; - if (index > 0) { - --index; // The first event is the socket event - event_owners[index]->OnPreEvent(0); - event_owners[index]->OnEvent(0, 0); - } else if (process_io) { - for (size_t i = 0; i < dispatchers_.size(); ++i) { - Dispatcher * disp = dispatchers_[i]; - SOCKET s = disp->GetSocket(); - if (s == INVALID_SOCKET) - continue; - - WSANETWORKEVENTS wsaEvents; - int err = WSAEnumNetworkEvents(s, events[0], &wsaEvents); - if (err == 0) { - -#if LOGGING - { - if ((wsaEvents.lNetworkEvents & FD_READ) && wsaEvents.iErrorCode[FD_READ_BIT] != 0) { - LOG(WARNING) << "PhysicalSocketServer got FD_READ_BIT error " << wsaEvents.iErrorCode[FD_READ_BIT]; - } - if ((wsaEvents.lNetworkEvents & FD_WRITE) && wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) { - LOG(WARNING) << "PhysicalSocketServer got FD_WRITE_BIT error " << wsaEvents.iErrorCode[FD_WRITE_BIT]; - } - if ((wsaEvents.lNetworkEvents & FD_CONNECT) && wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) { - LOG(WARNING) << "PhysicalSocketServer got FD_CONNECT_BIT error " << wsaEvents.iErrorCode[FD_CONNECT_BIT]; - } - if ((wsaEvents.lNetworkEvents & FD_ACCEPT) && wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) { - LOG(WARNING) << "PhysicalSocketServer got FD_ACCEPT_BIT error " << wsaEvents.iErrorCode[FD_ACCEPT_BIT]; - } - if ((wsaEvents.lNetworkEvents & FD_CLOSE) && wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) { - LOG(WARNING) << "PhysicalSocketServer got FD_CLOSE_BIT error " << wsaEvents.iErrorCode[FD_CLOSE_BIT]; - } - } -#endif - uint32 ff = 0; - int errcode = 0; - if (wsaEvents.lNetworkEvents & FD_READ) - ff |= kfRead; - if (wsaEvents.lNetworkEvents & FD_WRITE) - ff |= kfWrite; - if (wsaEvents.lNetworkEvents & FD_CONNECT) { - if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) { - ff |= kfConnect; - } else { - // TODO: Decide whether we want to signal connect, but with an error code - ff |= kfClose; - errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT]; - } - } - if (wsaEvents.lNetworkEvents & FD_ACCEPT) - ff |= kfRead; - if (wsaEvents.lNetworkEvents & FD_CLOSE) { - ff |= kfClose; - errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT]; - } - if (ff != 0) { - disp->OnPreEvent(ff); - disp->OnEvent(ff, errcode); - } - } - } - } - - // Reset the network event until new activity occurs - WSAResetEvent(socket_ev); - } - - // Break? - - if (!fWait_) - break; - cmsElapsed = GetMillisecondCount() - msStart; - if (cmsWait != -1) { - if (cmsElapsed >= cmsWait) - break; - } - } - - // Done - - WSACloseEvent(socket_ev); - return true; -} -#endif // WIN32 - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cpp new file mode 100644 index 00000000..37836302 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cpp @@ -0,0 +1,1116 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable:4786) +#endif + +#include +#include + +#ifdef POSIX +extern "C" { +#include +#include +#include +#include +#include +} +#endif + +#include "talk/base/basictypes.h" +#include "talk/base/byteorder.h" +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include "talk/base/physicalsocketserver.h" +#include "talk/base/jtime.h" +#include "talk/base/winping.h" + +#ifdef __linux +#define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h +#endif // __linux + +#ifdef WIN32 +#include +#include +#define _WINSOCKAPI_ +#include +#undef SetPort + +class WinsockInitializer { +public: + WinsockInitializer() { + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(1, 0); + err_ = WSAStartup(wVersionRequested, &wsaData); + } + ~WinsockInitializer() { + WSACleanup(); + } + int error() { + return err_; + } +private: + int err_; +}; +WinsockInitializer g_winsockinit; +#endif + +namespace cricket { + +const int kfRead = 0x0001; +const int kfWrite = 0x0002; +const int kfConnect = 0x0004; +const int kfClose = 0x0008; + + +// Standard MTUs +const uint16 PACKET_MAXIMUMS[] = { + 65535, // Theoretical maximum, Hyperchannel + 32000, // Nothing + 17914, // 16Mb IBM Token Ring + 8166, // IEEE 802.4 + //4464, // IEEE 802.5 (4Mb max) + 4352, // FDDI + //2048, // Wideband Network + 2002, // IEEE 802.5 (4Mb recommended) + //1536, // Expermental Ethernet Networks + //1500, // Ethernet, Point-to-Point (default) + 1492, // IEEE 802.3 + 1006, // SLIP, ARPANET + //576, // X.25 Networks + //544, // DEC IP Portal + //512, // NETBIOS + 508, // IEEE 802/Source-Rt Bridge, ARCNET + 296, // Point-to-Point (low delay) + 68, // Official minimum + 0, // End of list marker +}; + +const uint32 IP_HEADER_SIZE = 20; +const uint32 ICMP_HEADER_SIZE = 8; + +class PhysicalSocket : public AsyncSocket { +public: + PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET) + : ss_(ss), s_(s), enabled_events_(0), error_(0), + state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED) { + if (s != INVALID_SOCKET) + enabled_events_ = kfRead | kfWrite; + } + + virtual ~PhysicalSocket() { + Close(); + } + + // Creates the underlying OS socket (same as the "socket" function). + virtual bool Create(int type) { + Close(); + s_ = ::socket(AF_INET, type, 0); + UpdateLastError(); + enabled_events_ = kfRead | kfWrite; + return s_ != INVALID_SOCKET; + } + + SocketAddress GetLocalAddress() const { + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int result = ::getsockname(s_, (struct sockaddr*)&addr, &addrlen); + assert(addrlen == sizeof(addr)); + if (result >= 0) { + return SocketAddress(NetworkToHost32(addr.sin_addr.s_addr), + NetworkToHost16(addr.sin_port)); + } else { + return SocketAddress(); + } + } + + SocketAddress GetRemoteAddress() const { + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int result = ::getpeername(s_, (struct sockaddr*)&addr, &addrlen); + assert(addrlen == sizeof(addr)); + if (result >= 0) { + return SocketAddress( + NetworkToHost32(addr.sin_addr.s_addr), + NetworkToHost16(addr.sin_port)); + } else { + assert(errno == ENOTCONN); + return SocketAddress(); + } + } + + int Bind(const SocketAddress& addr) { + struct sockaddr_in saddr; + IP2SA(&addr, &saddr); + int err = ::bind(s_, (struct sockaddr*)&saddr, sizeof(saddr)); + UpdateLastError(); + return err; + } + + int Connect(const SocketAddress& addr) { + // TODO: Implicit creation is required to reconnect... + // ...but should we make it more explicit? + if ((s_ == INVALID_SOCKET) && !Create(SOCK_STREAM)) + return SOCKET_ERROR; + SocketAddress addr2(addr); + if (addr2.IsUnresolved()) { + LOG(INFO) << "Resolving addr in PhysicalSocket::Connect"; + addr2.Resolve(); // TODO: Do this async later? + } + struct sockaddr_in saddr; + IP2SA(&addr2, &saddr); + int err = ::connect(s_, (struct sockaddr*)&saddr, sizeof(saddr)); + UpdateLastError(); + //LOG(INFO) << "SOCK[" << static_cast(s_) << "] Connect(" << addr2.ToString() << ") Ret: " << err << " Error: " << error_; + if (err == 0) { + state_ = CS_CONNECTED; + } else if (IsBlockingError(error_)) { + state_ = CS_CONNECTING; + enabled_events_ |= kfConnect; + } + return err; + } + + int GetError() const { + return error_; + } + + void SetError(int error) { + error_ = error; + } + + ConnState GetState() const { + return state_; + } + + int SetOption(Option opt, int value) { + assert(opt == OPT_DONTFRAGMENT); +#ifdef WIN32 + value = (value == 0) ? 0 : 1; + return ::setsockopt( + s_, IPPROTO_IP, IP_DONTFRAGMENT, reinterpret_cast(&value), + sizeof(value)); +#endif +#ifdef __linux + value = (value == 0) ? IP_PMTUDISC_DONT : IP_PMTUDISC_DO; + return ::setsockopt( + s_, IPPROTO_IP, IP_MTU_DISCOVER, &value, sizeof(value)); +#endif +#ifdef OSX + // This is not possible on OSX. + return -1; +#endif + } + + int Send(const void *pv, size_t cb) { + int sent = ::send(s_, reinterpret_cast(pv), (int)cb, 0); + UpdateLastError(); + //LOG(INFO) << "SOCK[" << static_cast(s_) << "] Send(" << cb << ") Ret: " << sent << " Error: " << error_; + ASSERT(sent <= static_cast(cb)); // We have seen minidumps where this may be false + if ((sent < 0) && IsBlockingError(error_)) { + enabled_events_ |= kfWrite; + } + return sent; + } + + int SendTo(const void *pv, size_t cb, const SocketAddress& addr) { + struct sockaddr_in saddr; + IP2SA(&addr, &saddr); + int sent = ::sendto( + s_, (const char *)pv, (int)cb, 0, (struct sockaddr*)&saddr, + sizeof(saddr)); + UpdateLastError(); + ASSERT(sent <= static_cast(cb)); // We have seen minidumps where this may be false + if ((sent < 0) && IsBlockingError(error_)) { + enabled_events_ |= kfWrite; + } + return sent; + } + + int Recv(void *pv, size_t cb) { + int received = ::recv(s_, (char *)pv, (int)cb, 0); + UpdateLastError(); + if ((received >= 0) || IsBlockingError(error_)) { + enabled_events_ |= kfRead; + } + return received; + } + + int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) { + struct sockaddr saddr; + socklen_t cbAddr = sizeof(saddr); + int received = ::recvfrom(s_, (char *)pv, (int)cb, 0, &saddr, &cbAddr); + UpdateLastError(); + if ((received >= 0) && (paddr != NULL)) + SA2IP(&saddr, paddr); + if ((received >= 0) || IsBlockingError(error_)) { + enabled_events_ |= kfRead; + } + return received; + } + + int Listen(int backlog) { + int err = ::listen(s_, backlog); + UpdateLastError(); + if (err == 0) + state_ = CS_CONNECTING; + return err; + } + + Socket* Accept(SocketAddress *paddr) { + struct sockaddr saddr; + socklen_t cbAddr = sizeof(saddr); + SOCKET s = ::accept(s_, &saddr, &cbAddr); + UpdateLastError(); + if (s == INVALID_SOCKET) + return NULL; + if (paddr != NULL) + SA2IP(&saddr, paddr); + return ss_->WrapSocket(s); + } + + int Close() { + if (s_ == INVALID_SOCKET) + return 0; + int err = ::closesocket(s_); + UpdateLastError(); + //LOG(INFO) << "SOCK[" << static_cast(s_) << "] Close() Ret: " << err << " Error: " << error_; + s_ = INVALID_SOCKET; + state_ = CS_CLOSED; + enabled_events_ = 0; + return err; + } + + int EstimateMTU(uint16* mtu) { + SocketAddress addr = GetRemoteAddress(); + if (addr.IsAny()) { + error_ = ENOTCONN; + return -1; + } + +#ifdef WIN32 + + WinPing ping; + if (!ping.IsValid()) { + error_ = EINVAL; // can't think of a better error ID + return -1; + } + + for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) { + int32 size = PACKET_MAXIMUMS[level] - IP_HEADER_SIZE - ICMP_HEADER_SIZE; + if (ping.Ping(addr.ip(), size, 0, 1, false) != WinPing::PING_TOO_LARGE) { + *mtu = PACKET_MAXIMUMS[level]; + return 0; + } + } + + assert(false); + return 0; + +#endif // WIN32 + +#ifdef __linux + + int value; + socklen_t vlen = sizeof(value); + int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen); + if (err < 0) { + UpdateLastError(); + return err; + } + + assert((0 <= value) && (value <= 65536)); + *mtu = uint16(value); + return 0; + +#endif // __linux + + // TODO: OSX support + } + + SocketServer* socketserver() { return ss_; } + +protected: + PhysicalSocketServer* ss_; + SOCKET s_; + uint32 enabled_events_; + int error_; + ConnState state_; + + void UpdateLastError() { +#ifdef WIN32 + error_ = WSAGetLastError(); +#endif +#ifdef POSIX + error_ = errno; +#endif + } + + void IP2SA(const SocketAddress *paddr, struct sockaddr_in *psaddr) { + memset(psaddr, 0, sizeof(*psaddr)); + psaddr->sin_family = AF_INET; + psaddr->sin_port = HostToNetwork16(paddr->port()); + if (paddr->ip() == 0) + psaddr->sin_addr.s_addr = INADDR_ANY; + else + psaddr->sin_addr.s_addr = HostToNetwork32(paddr->ip()); + } + + void SA2IP(const struct sockaddr *psaddr, SocketAddress *paddr) { + const struct sockaddr_in *psaddr_in = + reinterpret_cast(psaddr); + paddr->SetIP(NetworkToHost32(psaddr_in->sin_addr.s_addr)); + paddr->SetPort(NetworkToHost16(psaddr_in->sin_port)); + } +}; + +#ifdef POSIX +class Dispatcher { +public: + virtual uint32 GetRequestedEvents() = 0; + virtual void OnPreEvent(uint32 ff) = 0; + virtual void OnEvent(uint32 ff, int err) = 0; + virtual int GetDescriptor() = 0; +}; + +class EventDispatcher : public Dispatcher { +public: + EventDispatcher(PhysicalSocketServer* ss) : ss_(ss), fSignaled_(false) { + if (pipe(afd_) < 0) + LOG(LERROR) << "pipe failed"; + ss_->Add(this); + } + + virtual ~EventDispatcher() { + ss_->Remove(this); + close(afd_[0]); + close(afd_[1]); + } + + virtual void Signal() { + CritScope cs(&crit_); + if (!fSignaled_) { + uint8 b = 0; + if (write(afd_[1], &b, sizeof(b)) < 0) + LOG(LERROR) << "write failed"; + fSignaled_ = true; + } + } + + virtual uint32 GetRequestedEvents() { + return kfRead; + } + + virtual void OnPreEvent(uint32 ff) { + // It is not possible to perfectly emulate an auto-resetting event with + // pipes. This simulates it by resetting before the event is handled. + + CritScope cs(&crit_); + if (fSignaled_) { + uint8 b; + read(afd_[0], &b, sizeof(b)); + fSignaled_ = false; + } + } + + virtual void OnEvent(uint32 ff, int err) { + assert(false); + } + + virtual int GetDescriptor() { + return afd_[0]; + } + +private: + PhysicalSocketServer *ss_; + int afd_[2]; + bool fSignaled_; + CriticalSection crit_; +}; + +class SocketDispatcher : public Dispatcher, public PhysicalSocket { +public: + SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) { + ss_->Add(this); + } + SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) : PhysicalSocket(ss, s) { + ss_->Add(this); + } + + virtual ~SocketDispatcher() { + ss_->Remove(this); + } + + bool Initialize() { + fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK); + return true; + } + + virtual bool Create(int type) { + // Change the socket to be non-blocking. + if (!PhysicalSocket::Create(type)) + return false; + + return Initialize(); + } + + virtual int GetDescriptor() { + return s_; + } + + virtual uint32 GetRequestedEvents() { + return enabled_events_; + } + + virtual void OnPreEvent(uint32 ff) { + } + + virtual void OnEvent(uint32 ff, int err) { + if ((ff & kfRead) != 0) { + enabled_events_ &= ~kfRead; + SignalReadEvent(this); + } + if ((ff & kfWrite) != 0) { + enabled_events_ &= ~kfWrite; + SignalWriteEvent(this); + } + if ((ff & kfConnect) != 0) { + enabled_events_ &= ~kfConnect; + SignalConnectEvent(this); + } + if ((ff & kfClose) != 0) + SignalCloseEvent(this, err); + } +}; + +class FileDispatcher: public Dispatcher, public AsyncFile { +public: + FileDispatcher(int fd, PhysicalSocketServer *ss) : ss_(ss), fd_(fd) { + set_readable(true); + + ss_->Add(this); + + fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL, 0) | O_NONBLOCK); + } + + virtual ~FileDispatcher() { + ss_->Remove(this); + } + + SocketServer* socketserver() { return ss_; } + + virtual int GetDescriptor() { + return fd_; + } + + virtual uint32 GetRequestedEvents() { + return flags_; + } + + virtual void OnPreEvent(uint32 ff) { + } + + virtual void OnEvent(uint32 ff, int err) { + if ((ff & kfRead) != 0) + SignalReadEvent(this); + if ((ff & kfWrite) != 0) + SignalWriteEvent(this); + if ((ff & kfClose) != 0) + SignalCloseEvent(this, err); + } + + virtual bool readable() { + return (flags_ & kfRead) != 0; + } + + virtual void set_readable(bool value) { + flags_ = value ? (flags_ | kfRead) : (flags_ & ~kfRead); + } + + virtual bool writable() { + return (flags_ & kfWrite) != 0; + } + + virtual void set_writable(bool value) { + flags_ = value ? (flags_ | kfWrite) : (flags_ & ~kfWrite); + } + +private: + PhysicalSocketServer* ss_; + int fd_; + int flags_; +}; + +AsyncFile* PhysicalSocketServer::CreateFile(int fd) { + return new FileDispatcher(fd, this); +} + +#endif // POSIX + +#ifdef WIN32 +class Dispatcher { +public: + virtual uint32 GetRequestedEvents() = 0; + virtual void OnPreEvent(uint32 ff) = 0; + virtual void OnEvent(uint32 ff, int err) = 0; + virtual WSAEVENT GetWSAEvent() = 0; + virtual SOCKET GetSocket() = 0; + virtual bool CheckSignalClose() = 0; +}; + +uint32 FlagsToEvents(uint32 events) { + uint32 ffFD = FD_CLOSE | FD_ACCEPT; + if (events & kfRead) + ffFD |= FD_READ; + if (events & kfWrite) + ffFD |= FD_WRITE; + if (events & kfConnect) + ffFD |= FD_CONNECT; + return ffFD; +} + +class EventDispatcher : public Dispatcher { +public: + EventDispatcher(PhysicalSocketServer *ss) : ss_(ss) { + if (hev_ = WSACreateEvent()) { + ss_->Add(this); + } + } + + ~EventDispatcher() { + if (hev_ != NULL) { + ss_->Remove(this); + WSACloseEvent(hev_); + hev_ = NULL; + } + } + + virtual void Signal() { + if (hev_ != NULL) + WSASetEvent(hev_); + } + + virtual uint32 GetRequestedEvents() { + return 0; + } + + virtual void OnPreEvent(uint32 ff) { + WSAResetEvent(hev_); + } + + virtual void OnEvent(uint32 ff, int err) { + } + + virtual WSAEVENT GetWSAEvent() { + return hev_; + } + + virtual SOCKET GetSocket() { + return INVALID_SOCKET; + } + + virtual bool CheckSignalClose() { return false; } + +private: + PhysicalSocketServer* ss_; + WSAEVENT hev_; +}; + +class SocketDispatcher : public Dispatcher, public PhysicalSocket { +public: + static int next_id_; + int id_; + bool signal_close_; + int signal_err_; + + SocketDispatcher(PhysicalSocketServer* ss) : PhysicalSocket(ss), id_(0), signal_close_(false) { + } + SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) : PhysicalSocket(ss, s), id_(0), signal_close_(false) { + } + + virtual ~SocketDispatcher() { + Close(); + } + + bool Initialize() { + assert(s_ != INVALID_SOCKET); + // Must be a non-blocking + u_long argp = 1; + ioctlsocket(s_, FIONBIO, &argp); + ss_->Add(this); + return true; + } + + virtual bool Create(int type) { + // Create socket + if (!PhysicalSocket::Create(type)) + return false; + + if (!Initialize()) + return false; + + do { id_ = ++next_id_; } while (id_ == 0); + return true; + } + + virtual int Close() { + if (s_ == INVALID_SOCKET) + return 0; + + id_ = 0; + signal_close_ = false; + ss_->Remove(this); + return PhysicalSocket::Close(); + } + + virtual uint32 GetRequestedEvents() { + return enabled_events_; + } + + virtual void OnPreEvent(uint32 ff) { + if ((ff & kfConnect) != 0) + state_ = CS_CONNECTED; + } + + virtual void OnEvent(uint32 ff, int err) { + int cache_id = id_; + if ((ff & kfRead) != 0) { + enabled_events_ &= ~kfRead; + SignalReadEvent(this); + } + if (((ff & kfWrite) != 0) && (id_ == cache_id)) { + enabled_events_ &= ~kfWrite; + SignalWriteEvent(this); + } + if (((ff & kfConnect) != 0) && (id_ == cache_id)) { + enabled_events_ &= ~kfConnect; + SignalConnectEvent(this); + } + if (((ff & kfClose) != 0) && (id_ == cache_id)) { + //LOG(INFO) << "SOCK[" << static_cast(s_) << "] OnClose() Error: " << err; + signal_close_ = true; + signal_err_ = err; + } + } + + virtual WSAEVENT GetWSAEvent() { + return WSA_INVALID_EVENT; + } + + virtual SOCKET GetSocket() { + return s_; + } + + virtual bool CheckSignalClose() { + if (!signal_close_) + return false; + + char ch; + if (recv(s_, &ch, 1, MSG_PEEK) > 0) + return false; + + signal_close_ = false; + SignalCloseEvent(this, signal_err_); + return true; + } +}; + +int SocketDispatcher::next_id_ = 0; + +#endif // WIN32 + +// Sets the value of a boolean value to false when signaled. +class Signaler : public EventDispatcher { +public: + Signaler(PhysicalSocketServer* ss, bool* pf) + : EventDispatcher(ss), pf_(pf) { + } + virtual ~Signaler() { } + + void OnEvent(uint32 ff, int err) { + if (pf_) + *pf_ = false; + } + +private: + bool *pf_; +}; + +PhysicalSocketServer::PhysicalSocketServer() : fWait_(false), + last_tick_tracked_(0), last_tick_dispatch_count_(0) { + signal_wakeup_ = new Signaler(this, &fWait_); +} + +PhysicalSocketServer::~PhysicalSocketServer() { + delete signal_wakeup_; +} + +void PhysicalSocketServer::WakeUp() { + signal_wakeup_->Signal(); +} + +Socket* PhysicalSocketServer::CreateSocket(int type) { + PhysicalSocket* socket = new PhysicalSocket(this); + if (socket->Create(type)) { + return socket; + } else { + delete socket; + return 0; + } +} + +AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int type) { + SocketDispatcher* dispatcher = new SocketDispatcher(this); + if (dispatcher->Create(type)) { + return dispatcher; + } else { + delete dispatcher; + return 0; + } +} + +AsyncSocket* PhysicalSocketServer::WrapSocket(SOCKET s) { + SocketDispatcher* dispatcher = new SocketDispatcher(s, this); + if (dispatcher->Initialize()) { + return dispatcher; + } else { + delete dispatcher; + return 0; + } +} + +void PhysicalSocketServer::Add(Dispatcher *pdispatcher) { + CritScope cs(&crit_); + dispatchers_.push_back(pdispatcher); +} + +void PhysicalSocketServer::Remove(Dispatcher *pdispatcher) { + CritScope cs(&crit_); + dispatchers_.erase(std::remove(dispatchers_.begin(), dispatchers_.end(), pdispatcher), dispatchers_.end()); +} + +#ifdef POSIX +bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) { + // Calculate timing information + + struct timeval *ptvWait = NULL; + struct timeval tvWait; + struct timeval tvStop; + if (cmsWait != -1) { + // Calculate wait timeval + tvWait.tv_sec = cmsWait / 1000; + tvWait.tv_usec = (cmsWait % 1000) * 1000; + ptvWait = &tvWait; + + // Calculate when to return in a timeval + gettimeofday(&tvStop, NULL); + tvStop.tv_sec += tvWait.tv_sec; + tvStop.tv_usec += tvWait.tv_usec; + if (tvStop.tv_usec >= 1000000) { + tvStop.tv_usec -= 1000000; + tvStop.tv_sec += 1; + } + } + + // Zero all fd_sets. Don't need to do this inside the loop since + // select() zeros the descriptors not signaled + + fd_set fdsRead; + FD_ZERO(&fdsRead); + fd_set fdsWrite; + FD_ZERO(&fdsWrite); + + fWait_ = true; + + while (fWait_) { + int fdmax = -1; + { + CritScope cr(&crit_); + for (unsigned i = 0; i < dispatchers_.size(); i++) { + // Query dispatchers for read and write wait state + + Dispatcher *pdispatcher = dispatchers_[i]; + assert(pdispatcher); + if (!process_io && (pdispatcher != signal_wakeup_)) + continue; + int fd = pdispatcher->GetDescriptor(); + if (fd > fdmax) + fdmax = fd; + uint32 ff = pdispatcher->GetRequestedEvents(); + if (ff & kfRead) + FD_SET(fd, &fdsRead); + if (ff & (kfWrite | kfConnect)) + FD_SET(fd, &fdsWrite); + } + } + + // Wait then call handlers as appropriate + // < 0 means error + // 0 means timeout + // > 0 means count of descriptors ready + int n = select(fdmax + 1, &fdsRead, &fdsWrite, NULL, ptvWait); + + // If error, return error + // todo: do something intelligent + + if (n < 0) + return false; + + // If timeout, return success + + if (n == 0) + return true; + + // We have signaled descriptors + + { + CritScope cr(&crit_); + for (unsigned i = 0; i < dispatchers_.size(); i++) { + Dispatcher *pdispatcher = dispatchers_[i]; + int fd = pdispatcher->GetDescriptor(); + uint32 ff = 0; + if (FD_ISSET(fd, &fdsRead)) { + FD_CLR(fd, &fdsRead); + ff |= kfRead; + } + if (FD_ISSET(fd, &fdsWrite)) { + FD_CLR(fd, &fdsWrite); + if (pdispatcher->GetRequestedEvents() & kfConnect) { + ff |= kfConnect; + } else { + ff |= kfWrite; + } + } + if (ff != 0) { + pdispatcher->OnPreEvent(ff); + pdispatcher->OnEvent(ff, 0); + } + } + } + + // Recalc the time remaining to wait. Doing it here means it doesn't get + // calced twice the first time through the loop + + if (cmsWait != -1) { + ptvWait->tv_sec = 0; + ptvWait->tv_usec = 0; + struct timeval tvT; + gettimeofday(&tvT, NULL); + if (tvStop.tv_sec >= tvT.tv_sec) { + ptvWait->tv_sec = tvStop.tv_sec - tvT.tv_sec; + ptvWait->tv_usec = tvStop.tv_usec - tvT.tv_usec; + if (ptvWait->tv_usec < 0) { + ptvWait->tv_usec += 1000000; + ptvWait->tv_sec -= 1; + } + } + } + } + + return true; +} +#endif // POSIX + +#ifdef WIN32 +bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) +{ + int cmsTotal = cmsWait; + int cmsElapsed = 0; + uint32 msStart = GetMillisecondCount(); + +#if LOGGING + if (last_tick_dispatch_count_ == 0) { + last_tick_tracked_ = msStart; + } +#endif + + WSAEVENT socket_ev = WSACreateEvent(); + + fWait_ = true; + while (fWait_) { + std::vector events; + std::vector event_owners; + + events.push_back(socket_ev); + + { + CritScope cr(&crit_); + for (size_t i = 0; i < dispatchers_.size(); ++i) { + Dispatcher * disp = dispatchers_[i]; + if (!process_io && (disp != signal_wakeup_)) + continue; + SOCKET s = disp->GetSocket(); + if (disp->CheckSignalClose()) { + // We just signalled close, don't poll this socket + } else if (s != INVALID_SOCKET) { + WSAEventSelect(s, events[0], FlagsToEvents(disp->GetRequestedEvents())); + } else { + events.push_back(disp->GetWSAEvent()); + event_owners.push_back(disp); + } + } + } + + // Which is shorter, the delay wait or the asked wait? + + int cmsNext; + if (cmsWait == -1) { + cmsNext = cmsWait; + } else { + cmsNext = cmsTotal - cmsElapsed; + if (cmsNext < 0) + cmsNext = 0; + } + + // Wait for one of the events to signal + DWORD dw = WSAWaitForMultipleEvents(static_cast(events.size()), &events[0], false, cmsNext, false); + +#if 0 // LOGGING + // we track this information purely for logging purposes. + last_tick_dispatch_count_++; + if (last_tick_dispatch_count_ >= 1000) { + uint32 now = GetMillisecondCount(); + LOG(INFO) << "PhysicalSocketServer took " << TimeDiff(now, last_tick_tracked_) << "ms for 1000 events"; + + // If we get more than 1000 events in a second, we are spinning badly + // (normally it should take about 8-20 seconds). + assert(TimeDiff(now, last_tick_tracked_) > 1000); + + last_tick_tracked_ = now; + last_tick_dispatch_count_ = 0; + } +#endif + + // Failed? + // todo: need a better strategy than this! + + if (dw == WSA_WAIT_FAILED) { + int error = WSAGetLastError(); + assert(false); + WSACloseEvent(socket_ev); + return false; + } + + // Timeout? + + if (dw == WSA_WAIT_TIMEOUT) { + WSACloseEvent(socket_ev); + return true; + } + + // Figure out which one it is and call it + + { + CritScope cr(&crit_); + int index = dw - WSA_WAIT_EVENT_0; + if (index > 0) { + --index; // The first event is the socket event + event_owners[index]->OnPreEvent(0); + event_owners[index]->OnEvent(0, 0); + } else if (process_io) { + for (size_t i = 0; i < dispatchers_.size(); ++i) { + Dispatcher * disp = dispatchers_[i]; + SOCKET s = disp->GetSocket(); + if (s == INVALID_SOCKET) + continue; + + WSANETWORKEVENTS wsaEvents; + int err = WSAEnumNetworkEvents(s, events[0], &wsaEvents); + if (err == 0) { + +#if LOGGING + { + if ((wsaEvents.lNetworkEvents & FD_READ) && wsaEvents.iErrorCode[FD_READ_BIT] != 0) { + LOG(WARNING) << "PhysicalSocketServer got FD_READ_BIT error " << wsaEvents.iErrorCode[FD_READ_BIT]; + } + if ((wsaEvents.lNetworkEvents & FD_WRITE) && wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) { + LOG(WARNING) << "PhysicalSocketServer got FD_WRITE_BIT error " << wsaEvents.iErrorCode[FD_WRITE_BIT]; + } + if ((wsaEvents.lNetworkEvents & FD_CONNECT) && wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) { + LOG(WARNING) << "PhysicalSocketServer got FD_CONNECT_BIT error " << wsaEvents.iErrorCode[FD_CONNECT_BIT]; + } + if ((wsaEvents.lNetworkEvents & FD_ACCEPT) && wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) { + LOG(WARNING) << "PhysicalSocketServer got FD_ACCEPT_BIT error " << wsaEvents.iErrorCode[FD_ACCEPT_BIT]; + } + if ((wsaEvents.lNetworkEvents & FD_CLOSE) && wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) { + LOG(WARNING) << "PhysicalSocketServer got FD_CLOSE_BIT error " << wsaEvents.iErrorCode[FD_CLOSE_BIT]; + } + } +#endif + uint32 ff = 0; + int errcode = 0; + if (wsaEvents.lNetworkEvents & FD_READ) + ff |= kfRead; + if (wsaEvents.lNetworkEvents & FD_WRITE) + ff |= kfWrite; + if (wsaEvents.lNetworkEvents & FD_CONNECT) { + if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) { + ff |= kfConnect; + } else { + // TODO: Decide whether we want to signal connect, but with an error code + ff |= kfClose; + errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT]; + } + } + if (wsaEvents.lNetworkEvents & FD_ACCEPT) + ff |= kfRead; + if (wsaEvents.lNetworkEvents & FD_CLOSE) { + ff |= kfClose; + errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT]; + } + if (ff != 0) { + disp->OnPreEvent(ff); + disp->OnEvent(ff, errcode); + } + } + } + } + + // Reset the network event until new activity occurs + WSAResetEvent(socket_ev); + } + + // Break? + + if (!fWait_) + break; + cmsElapsed = GetMillisecondCount() - msStart; + if (cmsWait != -1) { + if (cmsElapsed >= cmsWait) + break; + } + } + + // Done + + WSACloseEvent(socket_ev); + return true; +} +#endif // WIN32 + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc deleted file mode 100644 index 99f663b2..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#pragma warning(disable:4786) -#endif - -#include - -#ifdef WIN32 -#include -#include -#define _WINSOCKAPI_ -#include -#include // HTTP_STATUS_PROXY_AUTH_REQ -#define SECURITY_WIN32 -#include -#endif - -#include -#include - -#include "talk/base/base64.h" -#include "talk/base/basicdefs.h" -#include "talk/base/bytebuffer.h" -#include "talk/base/common.h" -#include "talk/base/logging.h" -#include "talk/base/md5.h" -#include "talk/base/socketadapters.h" -#include "talk/base/stringutils.h" - -#include - - -#ifdef WIN32 -#include "talk/base/sec_buffer.h" -#endif // WIN32 - -namespace cricket { - -#ifdef WIN32 -extern const ConstantLabel SECURITY_ERRORS[]; -#endif - -BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size) - : AsyncSocketAdapter(socket), buffer_size_(buffer_size), data_len_(0), buffering_(false) { - buffer_ = new char[buffer_size_]; -} - -BufferedReadAdapter::~BufferedReadAdapter() { - delete [] buffer_; -} - -int BufferedReadAdapter::Send(const void *pv, size_t cb) { - if (buffering_) { - // TODO: Spoof error better; Signal Writeable - socket_->SetError(EWOULDBLOCK); - return -1; - } - return AsyncSocketAdapter::Send(pv, cb); -} - -int BufferedReadAdapter::Recv(void *pv, size_t cb) { - if (buffering_) { - socket_->SetError(EWOULDBLOCK); - return -1; - } - - size_t read = 0; - - if (data_len_) { - read = _min(cb, data_len_); - memcpy(pv, buffer_, read); - data_len_ -= read; - if (data_len_ > 0) { - memmove(buffer_, buffer_ + read, data_len_); - } - pv = static_cast(pv) + read; - cb -= read; - } - - // FIX: If cb == 0, we won't generate another read event - - int res = AsyncSocketAdapter::Recv(pv, cb); - if (res < 0) - return res; - - return res + static_cast(read); -} - -void BufferedReadAdapter::BufferInput(bool on) { - buffering_ = on; -} - -void BufferedReadAdapter::OnReadEvent(AsyncSocket * socket) { - assert(socket == socket_); - - if (!buffering_) { - AsyncSocketAdapter::OnReadEvent(socket); - return; - } - - if (data_len_ >= buffer_size_) { - LOG(INFO) << "Input buffer overflow"; - assert(false); - data_len_ = 0; - } - - int len = socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_); - if (len < 0) { - // TODO: Do something better like forwarding the error to the user. - LOG(INFO) << "Recv: " << errno << " " << std::strerror(errno); - return; - } - - data_len_ += len; - - ProcessInput(buffer_, data_len_); -} - -/////////////////////////////////////////////////////////////////////////////// - -const uint8 SSL_SERVER_HELLO[] = { - 22,3,1,0,74,2,0,0,70,3,1,66,133,69,167,39,169,93,160, - 179,197,231,83,218,72,43,63,198,90,202,137,193,88,82, - 161,120,60,91,23,70,0,133,63,32,14,211,6,114,91,91, - 27,95,21,172,19,249,136,83,157,155,232,61,123,12,48, - 50,110,56,77,162,117,87,65,108,52,92,0,4,0 -}; - -const signed char SSL_CLIENT_HELLO[] = { - -128,70,1,3,1,0,45,0,0,0,16,1,0,-128,3,0,-128,7,0,-64,6,0,64,2,0, - -128,4,0,-128,0,0,4,0,-2,-1,0,0,10,0,-2,-2,0,0,9,0,0,100,0,0,98,0, - 0,3,0,0,6,31,23,12,-90,47,0,120,-4,70,85,46,-79,-125,57,-15,-22 -}; - -AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket) : BufferedReadAdapter(socket, 1024) { -} - -int AsyncSSLSocket::Connect(const SocketAddress& addr) { - // Begin buffering before we connect, so that there isn't a race condition between - // potential senders and receiving the OnConnectEvent signal - BufferInput(true); - return BufferedReadAdapter::Connect(addr); -} - -void AsyncSSLSocket::OnConnectEvent(AsyncSocket * socket) { - assert(socket == socket_); - - // TODO: we could buffer output too... - int res = DirectSend(SSL_CLIENT_HELLO, sizeof(SSL_CLIENT_HELLO)); - assert(res == sizeof(SSL_CLIENT_HELLO)); -} - -void AsyncSSLSocket::ProcessInput(char * data, size_t& len) { - if (len < sizeof(SSL_SERVER_HELLO)) - return; - - if (memcmp(SSL_SERVER_HELLO, data, sizeof(SSL_SERVER_HELLO)) != 0) { - Close(); - SignalCloseEvent(this, 0); // TODO: error code? - return; - } - - len -= sizeof(SSL_SERVER_HELLO); - if (len > 0) { - memmove(data, data + sizeof(SSL_SERVER_HELLO), len); - } - - bool remainder = (len > 0); - BufferInput(false); - SignalConnectEvent(this); - - // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble - if (remainder) - SignalReadEvent(this); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define TEST_DIGEST 0 -#if TEST_DIGEST -/* -const char * const DIGEST_CHALLENGE = - "Digest realm=\"testrealm@host.com\"," - " qop=\"auth,auth-int\"," - " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\"," - " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; -const char * const DIGEST_METHOD = "GET"; -const char * const DIGEST_URI = - "/dir/index.html";; -const char * const DIGEST_CNONCE = - "0a4f113b"; -const char * const DIGEST_RESPONSE = - "6629fae49393a05397450978507c4ef1"; -//user_ = "Mufasa"; -//pass_ = "Circle Of Life"; -*/ -const char * const DIGEST_CHALLENGE = - "Digest realm=\"Squid proxy-caching web server\"," - " nonce=\"Nny4QuC5PwiSDixJ\"," - " qop=\"auth\"," - " stale=false"; -const char * const DIGEST_URI = - "/"; -const char * const DIGEST_CNONCE = - "6501d58e9a21cee1e7b5fec894ded024"; -const char * const DIGEST_RESPONSE = - "edffcb0829e755838b073a4a42de06bc"; -#endif - -static std::string MD5(const std::string& data) { - MD5_CTX ctx; - MD5Init(&ctx); - MD5Update(&ctx, const_cast(reinterpret_cast(data.data())), static_cast(data.size())); - unsigned char digest[16]; - MD5Final(digest, &ctx); - std::string hex_digest; - const char HEX[] = "0123456789abcdef"; - for (int i=0; i<16; ++i) { - hex_digest += HEX[digest[i] >> 4]; - hex_digest += HEX[digest[i] & 0xf]; - } - return hex_digest; -} - -static std::string Quote(const std::string& str) { - std::string result; - result.push_back('"'); - for (size_t i=0; i args; - ParseAuth(challenge, len, auth_method, args); - - if (context && (context->auth_method != auth_method)) - return AR_IGNORE; - - // BASIC - if (stricmp(auth_method.c_str(), "basic") == 0) { - if (context) - return AR_CREDENTIALS; // Bad credentials - if (username.empty()) - return AR_CREDENTIALS; // Missing credentials - - context = new AuthContext(auth_method); - - // TODO: convert sensitive to a secure buffer that gets securely deleted - //std::string decoded = username + ":" + password; - size_t len = username.size() + password.GetLength() + 2; - char * sensitive = new char[len]; - size_t pos = strcpyn(sensitive, len, username.data(), username.size()); - pos += strcpyn(sensitive + pos, len - pos, ":"); - password.CopyTo(sensitive + pos, true); - - response = auth_method; - response.append(" "); - // TODO: create a sensitive-source version of Base64::encode - response.append(Base64::encode(sensitive)); - memset(sensitive, 0, len); - delete [] sensitive; - return AR_RESPONSE; - } - - // DIGEST - if (stricmp(auth_method.c_str(), "digest") == 0) { - if (context) - return AR_CREDENTIALS; // Bad credentials - if (username.empty()) - return AR_CREDENTIALS; // Missing credentials - - context = new AuthContext(auth_method); - - std::string cnonce, ncount; -#if TEST_DIGEST - method = DIGEST_METHOD; - uri = DIGEST_URI; - cnonce = DIGEST_CNONCE; -#else - char buffer[256]; - sprintf(buffer, "%d", time(0)); - cnonce = MD5(buffer); -#endif - ncount = "00000001"; - - // TODO: convert sensitive to be secure buffer - //std::string A1 = username + ":" + args["realm"] + ":" + password; - size_t len = username.size() + args["realm"].size() + password.GetLength() + 3; - char * sensitive = new char[len]; // A1 - size_t pos = strcpyn(sensitive, len, username.data(), username.size()); - pos += strcpyn(sensitive + pos, len - pos, ":"); - pos += strcpyn(sensitive + pos, len - pos, args["realm"].c_str()); - pos += strcpyn(sensitive + pos, len - pos, ":"); - password.CopyTo(sensitive + pos, true); - - std::string A2 = method + ":" + uri; - std::string middle; - if (args.find("qop") != args.end()) { - args["qop"] = "auth"; - middle = args["nonce"] + ":" + ncount + ":" + cnonce + ":" + args["qop"]; - } else { - middle = args["nonce"]; - } - std::string HA1 = MD5(sensitive); - memset(sensitive, 0, len); - delete [] sensitive; - std::string HA2 = MD5(A2); - std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2); - -#if TEST_DIGEST - assert(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0); -#endif - - std::stringstream ss; - ss << auth_method; - ss << " username=" << Quote(username); - ss << ", realm=" << Quote(args["realm"]); - ss << ", nonce=" << Quote(args["nonce"]); - ss << ", uri=" << Quote(uri); - if (args.find("qop") != args.end()) { - ss << ", qop=" << args["qop"]; - ss << ", nc=" << ncount; - ss << ", cnonce=" << Quote(cnonce); - } - ss << ", response=\"" << dig_response << "\""; - if (args.find("opaque") != args.end()) { - ss << ", opaque=" << Quote(args["opaque"]); - } - response = ss.str(); - return AR_RESPONSE; - } - -#ifdef WIN32 -#if 1 - bool want_negotiate = (stricmp(auth_method.c_str(), "negotiate") == 0); - bool want_ntlm = (stricmp(auth_method.c_str(), "ntlm") == 0); - // SPNEGO & NTLM - if (want_negotiate || want_ntlm) { - const size_t MAX_MESSAGE = 12000, MAX_SPN = 256; - char out_buf[MAX_MESSAGE], spn[MAX_SPN]; - -#if 0 // Requires funky windows versions - DWORD len = MAX_SPN; - if (DsMakeSpn("HTTP", server.IPAsString().c_str(), NULL, server.port(), 0, &len, spn) != ERROR_SUCCESS) { - LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) - DsMakeSpn failed"; - return AR_IGNORE; - } -#else - sprintfn(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str()); -#endif - - SecBuffer out_sec; - out_sec.pvBuffer = out_buf; - out_sec.cbBuffer = sizeof(out_buf); - out_sec.BufferType = SECBUFFER_TOKEN; - - SecBufferDesc out_buf_desc; - out_buf_desc.ulVersion = 0; - out_buf_desc.cBuffers = 1; - out_buf_desc.pBuffers = &out_sec; - - const ULONG NEG_FLAGS_DEFAULT = - //ISC_REQ_ALLOCATE_MEMORY - ISC_REQ_CONFIDENTIALITY - //| ISC_REQ_EXTENDED_ERROR - //| ISC_REQ_INTEGRITY - | ISC_REQ_REPLAY_DETECT - | ISC_REQ_SEQUENCE_DETECT - //| ISC_REQ_STREAM - //| ISC_REQ_USE_SUPPLIED_CREDS - ; - - TimeStamp lifetime; - SECURITY_STATUS ret = S_OK; - ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT; - - bool specify_credentials = !username.empty(); - size_t steps = 0; - - //uint32 now = cricket::Time(); - - NegotiateAuthContext * neg = static_cast(context); - if (neg) { - const size_t max_steps = 10; - if (++neg->steps >= max_steps) { - LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) too many retries"; - return AR_ERROR; - } - steps = neg->steps; - - std::string decoded_challenge = Base64::decode(args[""]); - if (!decoded_challenge.empty()) { - SecBuffer in_sec; - in_sec.pvBuffer = const_cast(decoded_challenge.data()); - in_sec.cbBuffer = static_cast(decoded_challenge.size()); - in_sec.BufferType = SECBUFFER_TOKEN; - - SecBufferDesc in_buf_desc; - in_buf_desc.ulVersion = 0; - in_buf_desc.cBuffers = 1; - in_buf_desc.pBuffers = &in_sec; - - ret = InitializeSecurityContextA(&neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime); - //LOG(INFO) << "$$$ InitializeSecurityContext @ " << cricket::TimeDiff(cricket::Time(), now); - if (FAILED(ret)) { - LOG(LS_ERROR) << "InitializeSecurityContext returned: " - << ErrorName(ret, SECURITY_ERRORS); - return AR_ERROR; - } - } else if (neg->specified_credentials) { - // Try again with default credentials - specify_credentials = false; - delete context; - context = neg = 0; - } else { - return AR_CREDENTIALS; - } - } - - if (!neg) { - unsigned char userbuf[256], passbuf[256], domainbuf[16]; - SEC_WINNT_AUTH_IDENTITY_A auth_id, * pauth_id = 0; - if (specify_credentials) { - memset(&auth_id, 0, sizeof(auth_id)); - size_t len = password.GetLength()+1; - char * sensitive = new char[len]; - password.CopyTo(sensitive, true); - std::string::size_type pos = username.find('\\'); - if (pos == std::string::npos) { - auth_id.UserLength = static_cast( - _min(sizeof(userbuf) - 1, username.size())); - memcpy(userbuf, username.c_str(), auth_id.UserLength); - userbuf[auth_id.UserLength] = 0; - auth_id.DomainLength = 0; - domainbuf[auth_id.DomainLength] = 0; - auth_id.PasswordLength = static_cast( - _min(sizeof(passbuf) - 1, password.GetLength())); - memcpy(passbuf, sensitive, auth_id.PasswordLength); - passbuf[auth_id.PasswordLength] = 0; - } else { - auth_id.UserLength = static_cast( - _min(sizeof(userbuf) - 1, username.size() - pos - 1)); - memcpy(userbuf, username.c_str() + pos + 1, auth_id.UserLength); - userbuf[auth_id.UserLength] = 0; - auth_id.DomainLength = static_cast( - _min(sizeof(domainbuf) - 1, pos)); - memcpy(domainbuf, username.c_str(), auth_id.DomainLength); - domainbuf[auth_id.DomainLength] = 0; - auth_id.PasswordLength = static_cast( - _min(sizeof(passbuf) - 1, password.GetLength())); - memcpy(passbuf, sensitive, auth_id.PasswordLength); - passbuf[auth_id.PasswordLength] = 0; - } - memset(sensitive, 0, len); - delete [] sensitive; - auth_id.User = userbuf; - auth_id.Domain = domainbuf; - auth_id.Password = passbuf; - auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; - pauth_id = &auth_id; - LOG(LS_VERBOSE) << "Negotiate protocol: Using specified credentials"; - } else { - LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials"; - } - - CredHandle cred; - ret = AcquireCredentialsHandleA(0, want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A, SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime); - //LOG(INFO) << "$$$ AcquireCredentialsHandle @ " << cricket::TimeDiff(cricket::Time(), now); - if (ret != SEC_E_OK) { - LOG(LS_ERROR) << "AcquireCredentialsHandle error: " - << ErrorName(ret, SECURITY_ERRORS); - return AR_IGNORE; - } - - //CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out; - - CtxtHandle ctx; - ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, SECURITY_NATIVE_DREP, 0, 0, &ctx, &out_buf_desc, &ret_flags, &lifetime); - //LOG(INFO) << "$$$ InitializeSecurityContext @ " << cricket::TimeDiff(cricket::Time(), now); - if (FAILED(ret)) { - LOG(LS_ERROR) << "InitializeSecurityContext returned: " - << ErrorName(ret, SECURITY_ERRORS); - FreeCredentialsHandle(&cred); - return AR_IGNORE; - } - - assert(!context); - context = neg = new NegotiateAuthContext(auth_method, cred, ctx); - neg->specified_credentials = specify_credentials; - neg->steps = steps; - } - - if ((ret == SEC_I_COMPLETE_NEEDED) || (ret == SEC_I_COMPLETE_AND_CONTINUE)) { - ret = CompleteAuthToken(&neg->ctx, &out_buf_desc); - //LOG(INFO) << "$$$ CompleteAuthToken @ " << cricket::TimeDiff(cricket::Time(), now); - LOG(LS_VERBOSE) << "CompleteAuthToken returned: " - << ErrorName(ret, SECURITY_ERRORS); - if (FAILED(ret)) { - return AR_ERROR; - } - } - - //LOG(INFO) << "$$$ NEGOTIATE took " << cricket::TimeDiff(cricket::Time(), now) << "ms"; - - std::string decoded(out_buf, out_buf + out_sec.cbBuffer); - response = auth_method; - response.append(" "); - response.append(Base64::encode(decoded)); - return AR_RESPONSE; - } -#endif -#endif // WIN32 - - return AR_IGNORE; -} - -inline bool end_of_name(size_t pos, size_t len, const char * data) { - if (pos >= len) - return true; - if (isspace(data[pos])) - return true; - // The reason for this complexity is that some non-compliant auth schemes (like Negotiate) - // use base64 tokens in the challenge instead of name=value. This could confuse us when the - // base64 ends in equal signs. - if ((pos+1 < len) && (data[pos] == '=') && !isspace(data[pos+1]) && (data[pos+1] != '=')) - return true; - return false; -} - -void AsyncHttpsProxySocket::ParseAuth(const char * data, size_t len, std::string& method, std::map& args) { - size_t pos = 0; - while ((pos < len) && isspace(data[pos])) ++pos; - size_t start = pos; - while ((pos < len) && !isspace(data[pos])) ++pos; - method.assign(data + start, data + pos); - while (pos < len) { - while ((pos < len) && isspace(data[pos])) ++pos; - if (pos >= len) - return; - - start = pos; - while (!end_of_name(pos, len, data)) ++pos; - //while ((pos < len) && !isspace(data[pos]) && (data[pos] != '=')) ++pos; - std::string name(data + start, data + pos), value; - - if ((pos < len) && (data[pos] == '=')) { - ++pos; // Skip '=' - // Check if quoted value - if ((pos < len) && (data[pos] == '"')) { - while (++pos < len) { - if (data[pos] == '"') { - ++pos; - break; - } - if ((data[pos] == '\\') && (pos + 1 < len)) - ++pos; - value.append(1, data[pos]); - } - } else { - while ((pos < len) && !isspace(data[pos]) && (data[pos] != ',')) - value.append(1, data[pos++]); - } - } else { - value = name; - name.clear(); - } - - args.insert(std::make_pair(name, value)); - if ((pos < len) && (data[pos] == ',')) ++pos; // Skip ',' - } -} - -AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket, const SocketAddress& proxy, - const std::string& username, const buzz::XmppPassword& password) - : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password), - state_(PS_ERROR), context_(0) { -} - -AsyncHttpsProxySocket::~AsyncHttpsProxySocket() { - delete context_; -} - -int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) { - LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect(" << proxy_.ToString() << ")"; - dest_ = addr; - if (dest_.port() != 80) { - BufferInput(true); - } - return BufferedReadAdapter::Connect(proxy_); -} - -SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const { - return dest_; -} - -int AsyncHttpsProxySocket::Close() { - headers_.clear(); - state_ = PS_ERROR; - delete context_; - context_ = 0; - return BufferedReadAdapter::Close(); -} - -void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket * socket) { - LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent"; - // TODO: Decide whether tunneling or not should be explicitly set, - // or indicated by destination port (as below) - if (dest_.port() == 80) { - state_ = PS_TUNNEL; - BufferedReadAdapter::OnConnectEvent(socket); - return; - } - SendRequest(); -} - -void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket * socket, int err) { - LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")"; - if ((state_ == PS_WAIT_CLOSE) && (err == 0)) { - state_ = PS_ERROR; - Connect(dest_); - } else { - BufferedReadAdapter::OnCloseEvent(socket, err); - } -} - -void AsyncHttpsProxySocket::ProcessInput(char * data, size_t& len) { - size_t start = 0; - for (size_t pos = start; (state_ < PS_TUNNEL) && (pos < len); ) { - if (state_ == PS_SKIP_BODY) { - size_t consume = _min(len - pos, content_length_); - pos += consume; - start = pos; - content_length_ -= consume; - if (content_length_ == 0) { - EndResponse(); - } - continue; - } - - if (data[pos++] != '\n') - continue; - - size_t len = pos - start - 1; - if ((len > 0) && (data[start + len - 1] == '\r')) - --len; - - data[start + len] = 0; - ProcessLine(data + start, len); - start = pos; - } - - len -= start; - if (len > 0) { - memmove(data, data + start, len); - } - - if (state_ != PS_TUNNEL) - return; - - bool remainder = (len > 0); - BufferInput(false); - SignalConnectEvent(this); - - // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble - if (remainder) - SignalReadEvent(this); // TODO: signal this?? -} - -void AsyncHttpsProxySocket::SendRequest() { - std::stringstream ss; - ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n"; - ss << "User-Agent: " USERAGENT_STRING "\r\n"; - ss << "Host: " << dest_.IPAsString() << "\r\n"; - ss << "Content-Length: 0\r\n"; - ss << "Proxy-Connection: Keep-Alive\r\n"; - ss << headers_; - ss << "\r\n"; - std::string str = ss.str(); - DirectSend(str.c_str(), str.size()); - state_ = PS_LEADER; - expect_close_ = true; - content_length_ = 0; - headers_.clear(); - - LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str; -} - -void AsyncHttpsProxySocket::ProcessLine(char * data, size_t len) { - LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data; - - if (len == 0) { - if (state_ == PS_TUNNEL_HEADERS) { - state_ = PS_TUNNEL; - } else if (state_ == PS_ERROR_HEADERS) { - Error(defer_error_); - return; - } else if (state_ == PS_SKIP_HEADERS) { - if (content_length_) { - state_ = PS_SKIP_BODY; - } else { - EndResponse(); - return; - } - } else { - static bool report = false; - if (!unknown_mechanisms_.empty() && !report) { - report = true; - std::string msg( - "Unable to connect to the Google Talk service due to an incompatibility " - "with your proxy.\r\nPlease help us resolve this issue by submitting the " - "following information to us using our technical issue submission form " - "at:\r\n\r\n" - "http://www.google.com/support/talk/bin/request.py\r\n\r\n" - "We apologize for the inconvenience.\r\n\r\n" - "Information to submit to Google: " - ); - //std::string msg("Please report the following information to foo@bar.com:\r\nUnknown methods: "); - msg.append(unknown_mechanisms_); -#ifdef WIN32 - MessageBoxA(0, msg.c_str(), "Oops!", MB_OK); -#endif -#ifdef POSIX - //TODO: Raise a signal or something so the UI can be separated. - LOG(LS_ERROR) << "Oops!\n\n" << msg; -#endif - } - // Unexpected end of headers - Error(0); - return; - } - } else if (state_ == PS_LEADER) { - uint32 code; - if (sscanf(data, "HTTP/%*lu.%*lu %lu", &code) != 1) { - Error(0); - return; - } - switch (code) { - case 200: - // connection good! - state_ = PS_TUNNEL_HEADERS; - return; -#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407) -#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ -#endif - case 407: // HTTP_STATUS_PROXY_AUTH_REQ - state_ = PS_AUTHENTICATE; - return; - default: - defer_error_ = 0; - state_ = PS_ERROR_HEADERS; - return; - } - } else if ((state_ == PS_AUTHENTICATE) && (strnicmp(data, "Proxy-Authenticate:", 19) == 0)) { - std::string response, auth_method; - switch (Authenticate(data + 19, len - 19, proxy_, "CONNECT", "/", user_, pass_, context_, response, auth_method)) { - case AR_IGNORE: - LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method; - if (!unknown_mechanisms_.empty()) - unknown_mechanisms_.append(", "); - unknown_mechanisms_.append(auth_method); - break; - case AR_RESPONSE: - headers_ = "Proxy-Authorization: "; - headers_.append(response); - headers_.append("\r\n"); - state_ = PS_SKIP_HEADERS; - unknown_mechanisms_.clear(); - break; - case AR_CREDENTIALS: - defer_error_ = EACCES; - state_ = PS_ERROR_HEADERS; - unknown_mechanisms_.clear(); - break; - case AR_ERROR: - defer_error_ = 0; - state_ = PS_ERROR_HEADERS; - unknown_mechanisms_.clear(); - break; - } - } else if (strnicmp(data, "Content-Length:", 15) == 0) { - content_length_ = strtoul(data + 15, 0, 0); - } else if (strnicmp(data, "Proxy-Connection: Keep-Alive", 28) == 0) { - expect_close_ = false; - /* - } else if (strnicmp(data, "Connection: close", 17) == 0) { - expect_close_ = true; - */ - } -} - -void AsyncHttpsProxySocket::EndResponse() { - if (!expect_close_) { - SendRequest(); - return; - } - - // No point in waiting for the server to close... let's close now - // TODO: Refactor out PS_WAIT_CLOSE - state_ = PS_WAIT_CLOSE; - BufferedReadAdapter::Close(); - OnCloseEvent(this, 0); -} - -void AsyncHttpsProxySocket::Error(int error) { - BufferInput(false); - Close(); - SetError(error); - SignalCloseEvent(this, error); -} - -/////////////////////////////////////////////////////////////////////////////// - -AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy, - const std::string& username, const buzz::XmppPassword& password) - : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password), - state_(SS_ERROR) { -} - -int AsyncSocksProxySocket::Connect(const SocketAddress& addr) { - dest_ = addr; - BufferInput(true); - return BufferedReadAdapter::Connect(proxy_); -} - -SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const { - return dest_; -} - -void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket * socket) { - SendHello(); -} - -void AsyncSocksProxySocket::ProcessInput(char * data, size_t& len) { - assert(state_ < SS_TUNNEL); - - ByteBuffer response(data, len); - - if (state_ == SS_HELLO) { - uint8 ver, method; - if (!response.ReadUInt8(ver) || - !response.ReadUInt8(method)) - return; - - if (ver != 5) { - Error(0); - return; - } - - if (method == 0) { - SendConnect(); - } else if (method == 2) { - SendAuth(); - } else { - Error(0); - return; - } - } else if (state_ == SS_AUTH) { - uint8 ver, status; - if (!response.ReadUInt8(ver) || - !response.ReadUInt8(status)) - return; - - if ((ver != 1) || (status != 0)) { - Error(EACCES); - return; - } - - SendConnect(); - } else if (state_ == SS_CONNECT) { - uint8 ver, rep, rsv, atyp; - if (!response.ReadUInt8(ver) || - !response.ReadUInt8(rep) || - !response.ReadUInt8(rsv) || - !response.ReadUInt8(atyp)) - return; - - if ((ver != 5) || (rep != 0)) { - Error(0); - return; - } - - uint16 port; - if (atyp == 1) { - uint32 addr; - if (!response.ReadUInt32(addr) || - !response.ReadUInt16(port)) - return; - LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port; - } else if (atyp == 3) { - uint8 len; - std::string addr; - if (!response.ReadUInt8(len) || - !response.ReadString(addr, len) || - !response.ReadUInt16(port)) - return; - LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port; - } else if (atyp == 4) { - std::string addr; - if (!response.ReadString(addr, 16) || - !response.ReadUInt16(port)) - return; - LOG(LS_VERBOSE) << "Bound on :" << port; - } else { - Error(0); - return; - } - - state_ = SS_TUNNEL; - } - - // Consume parsed data - len = response.Length(); - memcpy(data, response.Data(), len); - - if (state_ != SS_TUNNEL) - return; - - bool remainder = (len > 0); - BufferInput(false); - SignalConnectEvent(this); - - // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble - if (remainder) - SignalReadEvent(this); // TODO: signal this?? -} - -void AsyncSocksProxySocket::SendHello() { - ByteBuffer request; - request.WriteUInt8(5); // Socks Version - if (user_.empty()) { - request.WriteUInt8(1); // Authentication Mechanisms - request.WriteUInt8(0); // No authentication - } else { - request.WriteUInt8(2); // Authentication Mechanisms - request.WriteUInt8(0); // No authentication - request.WriteUInt8(2); // Username/Password - } - DirectSend(request.Data(), request.Length()); - state_ = SS_HELLO; -} - -void AsyncSocksProxySocket::SendAuth() { - ByteBuffer request; - request.WriteUInt8(1); // Negotiation Version - request.WriteUInt8(static_cast(user_.size())); - request.WriteString(user_); // Username - request.WriteUInt8(static_cast(pass_.GetLength())); - size_t len = pass_.GetLength() + 1; - char * sensitive = new char[len]; - pass_.CopyTo(sensitive, true); - request.WriteString(sensitive); // Password - memset(sensitive, 0, len); - delete [] sensitive; - DirectSend(request.Data(), request.Length()); - state_ = SS_AUTH; -} - -void AsyncSocksProxySocket::SendConnect() { - ByteBuffer request; - request.WriteUInt8(5); // Socks Version - request.WriteUInt8(1); // CONNECT - request.WriteUInt8(0); // Reserved - if (dest_.IsUnresolved()) { - std::string hostname = dest_.IPAsString(); - request.WriteUInt8(3); // DOMAINNAME - request.WriteUInt8(static_cast(hostname.size())); - request.WriteString(hostname); // Destination Hostname - } else { - request.WriteUInt8(1); // IPV4 - request.WriteUInt32(dest_.ip()); // Destination IP - } - request.WriteUInt16(dest_.port()); // Destination Port - DirectSend(request.Data(), request.Length()); - state_ = SS_CONNECT; -} - -void AsyncSocksProxySocket::Error(int error) { - state_ = SS_ERROR; - BufferInput(false); - Close(); - SetError(EACCES); - SignalCloseEvent(this, error); -} - -/////////////////////////////////////////////////////////////////////////////// - -LoggingAdapter::LoggingAdapter(AsyncSocket* socket, LoggingSeverity level, - const char * label) - : AsyncSocketAdapter(socket), level_(level) -{ - label_.append("["); - label_.append(label); - label_.append("]"); -} - -int -LoggingAdapter::Send(const void *pv, size_t cb) { - int res = AsyncSocketAdapter::Send(pv, cb); - if (res > 0) - LogMultiline(false, static_cast(pv), res); - return res; -} - -int -LoggingAdapter::SendTo(const void *pv, size_t cb, const SocketAddress& addr) { - int res = AsyncSocketAdapter::SendTo(pv, cb, addr); - if (res > 0) - LogMultiline(false, static_cast(pv), res); - return res; -} - -int -LoggingAdapter::Recv(void *pv, size_t cb) { - int res = AsyncSocketAdapter::Recv(pv, cb); - if (res > 0) - LogMultiline(true, static_cast(pv), res); - return res; -} - -int -LoggingAdapter::RecvFrom(void *pv, size_t cb, SocketAddress *paddr) { - int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr); - if (res > 0) - LogMultiline(true, static_cast(pv), res); - return res; -} - -void -LoggingAdapter::OnConnectEvent(AsyncSocket * socket) { - LOG(level_) << label_ << " Connected"; - AsyncSocketAdapter::OnConnectEvent(socket); -} - -void -LoggingAdapter::OnCloseEvent(AsyncSocket * socket, int err) { - LOG(level_) << label_ << " Closed with error: " << err; - AsyncSocketAdapter::OnCloseEvent(socket, err); -} - -void -LoggingAdapter::LogMultiline(bool input, const char * data, size_t len) { - const char * direction = (input ? " << " : " >> "); - std::string str(data, len); - while (!str.empty()) { - std::string::size_type pos = str.find('\n'); - std::string substr = str; - if (pos == std::string::npos) { - substr = str; - str.clear(); - } else if ((pos > 0) && (str[pos-1] == '\r')) { - substr = str.substr(0, pos - 1); - str = str.substr(pos + 1); - } else { - substr = str.substr(0, pos); - str = str.substr(pos + 1); - } - - // Filter out any private data - std::string::size_type pos_private = substr.find("Email"); - if (pos_private == std::string::npos) { - pos_private = substr.find("Passwd"); - } - if (pos_private == std::string::npos) { - LOG(level_) << label_ << direction << substr; - } else { - LOG(level_) << label_ << direction << "## TEXT REMOVED ##"; - } - } -} - -/////////////////////////////////////////////////////////////////////////////// - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cpp new file mode 100644 index 00000000..99f663b2 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cpp @@ -0,0 +1,1131 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable:4786) +#endif + +#include + +#ifdef WIN32 +#include +#include +#define _WINSOCKAPI_ +#include +#include // HTTP_STATUS_PROXY_AUTH_REQ +#define SECURITY_WIN32 +#include +#endif + +#include +#include + +#include "talk/base/base64.h" +#include "talk/base/basicdefs.h" +#include "talk/base/bytebuffer.h" +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include "talk/base/md5.h" +#include "talk/base/socketadapters.h" +#include "talk/base/stringutils.h" + +#include + + +#ifdef WIN32 +#include "talk/base/sec_buffer.h" +#endif // WIN32 + +namespace cricket { + +#ifdef WIN32 +extern const ConstantLabel SECURITY_ERRORS[]; +#endif + +BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size) + : AsyncSocketAdapter(socket), buffer_size_(buffer_size), data_len_(0), buffering_(false) { + buffer_ = new char[buffer_size_]; +} + +BufferedReadAdapter::~BufferedReadAdapter() { + delete [] buffer_; +} + +int BufferedReadAdapter::Send(const void *pv, size_t cb) { + if (buffering_) { + // TODO: Spoof error better; Signal Writeable + socket_->SetError(EWOULDBLOCK); + return -1; + } + return AsyncSocketAdapter::Send(pv, cb); +} + +int BufferedReadAdapter::Recv(void *pv, size_t cb) { + if (buffering_) { + socket_->SetError(EWOULDBLOCK); + return -1; + } + + size_t read = 0; + + if (data_len_) { + read = _min(cb, data_len_); + memcpy(pv, buffer_, read); + data_len_ -= read; + if (data_len_ > 0) { + memmove(buffer_, buffer_ + read, data_len_); + } + pv = static_cast(pv) + read; + cb -= read; + } + + // FIX: If cb == 0, we won't generate another read event + + int res = AsyncSocketAdapter::Recv(pv, cb); + if (res < 0) + return res; + + return res + static_cast(read); +} + +void BufferedReadAdapter::BufferInput(bool on) { + buffering_ = on; +} + +void BufferedReadAdapter::OnReadEvent(AsyncSocket * socket) { + assert(socket == socket_); + + if (!buffering_) { + AsyncSocketAdapter::OnReadEvent(socket); + return; + } + + if (data_len_ >= buffer_size_) { + LOG(INFO) << "Input buffer overflow"; + assert(false); + data_len_ = 0; + } + + int len = socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_); + if (len < 0) { + // TODO: Do something better like forwarding the error to the user. + LOG(INFO) << "Recv: " << errno << " " << std::strerror(errno); + return; + } + + data_len_ += len; + + ProcessInput(buffer_, data_len_); +} + +/////////////////////////////////////////////////////////////////////////////// + +const uint8 SSL_SERVER_HELLO[] = { + 22,3,1,0,74,2,0,0,70,3,1,66,133,69,167,39,169,93,160, + 179,197,231,83,218,72,43,63,198,90,202,137,193,88,82, + 161,120,60,91,23,70,0,133,63,32,14,211,6,114,91,91, + 27,95,21,172,19,249,136,83,157,155,232,61,123,12,48, + 50,110,56,77,162,117,87,65,108,52,92,0,4,0 +}; + +const signed char SSL_CLIENT_HELLO[] = { + -128,70,1,3,1,0,45,0,0,0,16,1,0,-128,3,0,-128,7,0,-64,6,0,64,2,0, + -128,4,0,-128,0,0,4,0,-2,-1,0,0,10,0,-2,-2,0,0,9,0,0,100,0,0,98,0, + 0,3,0,0,6,31,23,12,-90,47,0,120,-4,70,85,46,-79,-125,57,-15,-22 +}; + +AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket) : BufferedReadAdapter(socket, 1024) { +} + +int AsyncSSLSocket::Connect(const SocketAddress& addr) { + // Begin buffering before we connect, so that there isn't a race condition between + // potential senders and receiving the OnConnectEvent signal + BufferInput(true); + return BufferedReadAdapter::Connect(addr); +} + +void AsyncSSLSocket::OnConnectEvent(AsyncSocket * socket) { + assert(socket == socket_); + + // TODO: we could buffer output too... + int res = DirectSend(SSL_CLIENT_HELLO, sizeof(SSL_CLIENT_HELLO)); + assert(res == sizeof(SSL_CLIENT_HELLO)); +} + +void AsyncSSLSocket::ProcessInput(char * data, size_t& len) { + if (len < sizeof(SSL_SERVER_HELLO)) + return; + + if (memcmp(SSL_SERVER_HELLO, data, sizeof(SSL_SERVER_HELLO)) != 0) { + Close(); + SignalCloseEvent(this, 0); // TODO: error code? + return; + } + + len -= sizeof(SSL_SERVER_HELLO); + if (len > 0) { + memmove(data, data + sizeof(SSL_SERVER_HELLO), len); + } + + bool remainder = (len > 0); + BufferInput(false); + SignalConnectEvent(this); + + // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble + if (remainder) + SignalReadEvent(this); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define TEST_DIGEST 0 +#if TEST_DIGEST +/* +const char * const DIGEST_CHALLENGE = + "Digest realm=\"testrealm@host.com\"," + " qop=\"auth,auth-int\"," + " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\"," + " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; +const char * const DIGEST_METHOD = "GET"; +const char * const DIGEST_URI = + "/dir/index.html";; +const char * const DIGEST_CNONCE = + "0a4f113b"; +const char * const DIGEST_RESPONSE = + "6629fae49393a05397450978507c4ef1"; +//user_ = "Mufasa"; +//pass_ = "Circle Of Life"; +*/ +const char * const DIGEST_CHALLENGE = + "Digest realm=\"Squid proxy-caching web server\"," + " nonce=\"Nny4QuC5PwiSDixJ\"," + " qop=\"auth\"," + " stale=false"; +const char * const DIGEST_URI = + "/"; +const char * const DIGEST_CNONCE = + "6501d58e9a21cee1e7b5fec894ded024"; +const char * const DIGEST_RESPONSE = + "edffcb0829e755838b073a4a42de06bc"; +#endif + +static std::string MD5(const std::string& data) { + MD5_CTX ctx; + MD5Init(&ctx); + MD5Update(&ctx, const_cast(reinterpret_cast(data.data())), static_cast(data.size())); + unsigned char digest[16]; + MD5Final(digest, &ctx); + std::string hex_digest; + const char HEX[] = "0123456789abcdef"; + for (int i=0; i<16; ++i) { + hex_digest += HEX[digest[i] >> 4]; + hex_digest += HEX[digest[i] & 0xf]; + } + return hex_digest; +} + +static std::string Quote(const std::string& str) { + std::string result; + result.push_back('"'); + for (size_t i=0; i args; + ParseAuth(challenge, len, auth_method, args); + + if (context && (context->auth_method != auth_method)) + return AR_IGNORE; + + // BASIC + if (stricmp(auth_method.c_str(), "basic") == 0) { + if (context) + return AR_CREDENTIALS; // Bad credentials + if (username.empty()) + return AR_CREDENTIALS; // Missing credentials + + context = new AuthContext(auth_method); + + // TODO: convert sensitive to a secure buffer that gets securely deleted + //std::string decoded = username + ":" + password; + size_t len = username.size() + password.GetLength() + 2; + char * sensitive = new char[len]; + size_t pos = strcpyn(sensitive, len, username.data(), username.size()); + pos += strcpyn(sensitive + pos, len - pos, ":"); + password.CopyTo(sensitive + pos, true); + + response = auth_method; + response.append(" "); + // TODO: create a sensitive-source version of Base64::encode + response.append(Base64::encode(sensitive)); + memset(sensitive, 0, len); + delete [] sensitive; + return AR_RESPONSE; + } + + // DIGEST + if (stricmp(auth_method.c_str(), "digest") == 0) { + if (context) + return AR_CREDENTIALS; // Bad credentials + if (username.empty()) + return AR_CREDENTIALS; // Missing credentials + + context = new AuthContext(auth_method); + + std::string cnonce, ncount; +#if TEST_DIGEST + method = DIGEST_METHOD; + uri = DIGEST_URI; + cnonce = DIGEST_CNONCE; +#else + char buffer[256]; + sprintf(buffer, "%d", time(0)); + cnonce = MD5(buffer); +#endif + ncount = "00000001"; + + // TODO: convert sensitive to be secure buffer + //std::string A1 = username + ":" + args["realm"] + ":" + password; + size_t len = username.size() + args["realm"].size() + password.GetLength() + 3; + char * sensitive = new char[len]; // A1 + size_t pos = strcpyn(sensitive, len, username.data(), username.size()); + pos += strcpyn(sensitive + pos, len - pos, ":"); + pos += strcpyn(sensitive + pos, len - pos, args["realm"].c_str()); + pos += strcpyn(sensitive + pos, len - pos, ":"); + password.CopyTo(sensitive + pos, true); + + std::string A2 = method + ":" + uri; + std::string middle; + if (args.find("qop") != args.end()) { + args["qop"] = "auth"; + middle = args["nonce"] + ":" + ncount + ":" + cnonce + ":" + args["qop"]; + } else { + middle = args["nonce"]; + } + std::string HA1 = MD5(sensitive); + memset(sensitive, 0, len); + delete [] sensitive; + std::string HA2 = MD5(A2); + std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2); + +#if TEST_DIGEST + assert(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0); +#endif + + std::stringstream ss; + ss << auth_method; + ss << " username=" << Quote(username); + ss << ", realm=" << Quote(args["realm"]); + ss << ", nonce=" << Quote(args["nonce"]); + ss << ", uri=" << Quote(uri); + if (args.find("qop") != args.end()) { + ss << ", qop=" << args["qop"]; + ss << ", nc=" << ncount; + ss << ", cnonce=" << Quote(cnonce); + } + ss << ", response=\"" << dig_response << "\""; + if (args.find("opaque") != args.end()) { + ss << ", opaque=" << Quote(args["opaque"]); + } + response = ss.str(); + return AR_RESPONSE; + } + +#ifdef WIN32 +#if 1 + bool want_negotiate = (stricmp(auth_method.c_str(), "negotiate") == 0); + bool want_ntlm = (stricmp(auth_method.c_str(), "ntlm") == 0); + // SPNEGO & NTLM + if (want_negotiate || want_ntlm) { + const size_t MAX_MESSAGE = 12000, MAX_SPN = 256; + char out_buf[MAX_MESSAGE], spn[MAX_SPN]; + +#if 0 // Requires funky windows versions + DWORD len = MAX_SPN; + if (DsMakeSpn("HTTP", server.IPAsString().c_str(), NULL, server.port(), 0, &len, spn) != ERROR_SUCCESS) { + LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) - DsMakeSpn failed"; + return AR_IGNORE; + } +#else + sprintfn(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str()); +#endif + + SecBuffer out_sec; + out_sec.pvBuffer = out_buf; + out_sec.cbBuffer = sizeof(out_buf); + out_sec.BufferType = SECBUFFER_TOKEN; + + SecBufferDesc out_buf_desc; + out_buf_desc.ulVersion = 0; + out_buf_desc.cBuffers = 1; + out_buf_desc.pBuffers = &out_sec; + + const ULONG NEG_FLAGS_DEFAULT = + //ISC_REQ_ALLOCATE_MEMORY + ISC_REQ_CONFIDENTIALITY + //| ISC_REQ_EXTENDED_ERROR + //| ISC_REQ_INTEGRITY + | ISC_REQ_REPLAY_DETECT + | ISC_REQ_SEQUENCE_DETECT + //| ISC_REQ_STREAM + //| ISC_REQ_USE_SUPPLIED_CREDS + ; + + TimeStamp lifetime; + SECURITY_STATUS ret = S_OK; + ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT; + + bool specify_credentials = !username.empty(); + size_t steps = 0; + + //uint32 now = cricket::Time(); + + NegotiateAuthContext * neg = static_cast(context); + if (neg) { + const size_t max_steps = 10; + if (++neg->steps >= max_steps) { + LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) too many retries"; + return AR_ERROR; + } + steps = neg->steps; + + std::string decoded_challenge = Base64::decode(args[""]); + if (!decoded_challenge.empty()) { + SecBuffer in_sec; + in_sec.pvBuffer = const_cast(decoded_challenge.data()); + in_sec.cbBuffer = static_cast(decoded_challenge.size()); + in_sec.BufferType = SECBUFFER_TOKEN; + + SecBufferDesc in_buf_desc; + in_buf_desc.ulVersion = 0; + in_buf_desc.cBuffers = 1; + in_buf_desc.pBuffers = &in_sec; + + ret = InitializeSecurityContextA(&neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime); + //LOG(INFO) << "$$$ InitializeSecurityContext @ " << cricket::TimeDiff(cricket::Time(), now); + if (FAILED(ret)) { + LOG(LS_ERROR) << "InitializeSecurityContext returned: " + << ErrorName(ret, SECURITY_ERRORS); + return AR_ERROR; + } + } else if (neg->specified_credentials) { + // Try again with default credentials + specify_credentials = false; + delete context; + context = neg = 0; + } else { + return AR_CREDENTIALS; + } + } + + if (!neg) { + unsigned char userbuf[256], passbuf[256], domainbuf[16]; + SEC_WINNT_AUTH_IDENTITY_A auth_id, * pauth_id = 0; + if (specify_credentials) { + memset(&auth_id, 0, sizeof(auth_id)); + size_t len = password.GetLength()+1; + char * sensitive = new char[len]; + password.CopyTo(sensitive, true); + std::string::size_type pos = username.find('\\'); + if (pos == std::string::npos) { + auth_id.UserLength = static_cast( + _min(sizeof(userbuf) - 1, username.size())); + memcpy(userbuf, username.c_str(), auth_id.UserLength); + userbuf[auth_id.UserLength] = 0; + auth_id.DomainLength = 0; + domainbuf[auth_id.DomainLength] = 0; + auth_id.PasswordLength = static_cast( + _min(sizeof(passbuf) - 1, password.GetLength())); + memcpy(passbuf, sensitive, auth_id.PasswordLength); + passbuf[auth_id.PasswordLength] = 0; + } else { + auth_id.UserLength = static_cast( + _min(sizeof(userbuf) - 1, username.size() - pos - 1)); + memcpy(userbuf, username.c_str() + pos + 1, auth_id.UserLength); + userbuf[auth_id.UserLength] = 0; + auth_id.DomainLength = static_cast( + _min(sizeof(domainbuf) - 1, pos)); + memcpy(domainbuf, username.c_str(), auth_id.DomainLength); + domainbuf[auth_id.DomainLength] = 0; + auth_id.PasswordLength = static_cast( + _min(sizeof(passbuf) - 1, password.GetLength())); + memcpy(passbuf, sensitive, auth_id.PasswordLength); + passbuf[auth_id.PasswordLength] = 0; + } + memset(sensitive, 0, len); + delete [] sensitive; + auth_id.User = userbuf; + auth_id.Domain = domainbuf; + auth_id.Password = passbuf; + auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + pauth_id = &auth_id; + LOG(LS_VERBOSE) << "Negotiate protocol: Using specified credentials"; + } else { + LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials"; + } + + CredHandle cred; + ret = AcquireCredentialsHandleA(0, want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A, SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime); + //LOG(INFO) << "$$$ AcquireCredentialsHandle @ " << cricket::TimeDiff(cricket::Time(), now); + if (ret != SEC_E_OK) { + LOG(LS_ERROR) << "AcquireCredentialsHandle error: " + << ErrorName(ret, SECURITY_ERRORS); + return AR_IGNORE; + } + + //CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out; + + CtxtHandle ctx; + ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, SECURITY_NATIVE_DREP, 0, 0, &ctx, &out_buf_desc, &ret_flags, &lifetime); + //LOG(INFO) << "$$$ InitializeSecurityContext @ " << cricket::TimeDiff(cricket::Time(), now); + if (FAILED(ret)) { + LOG(LS_ERROR) << "InitializeSecurityContext returned: " + << ErrorName(ret, SECURITY_ERRORS); + FreeCredentialsHandle(&cred); + return AR_IGNORE; + } + + assert(!context); + context = neg = new NegotiateAuthContext(auth_method, cred, ctx); + neg->specified_credentials = specify_credentials; + neg->steps = steps; + } + + if ((ret == SEC_I_COMPLETE_NEEDED) || (ret == SEC_I_COMPLETE_AND_CONTINUE)) { + ret = CompleteAuthToken(&neg->ctx, &out_buf_desc); + //LOG(INFO) << "$$$ CompleteAuthToken @ " << cricket::TimeDiff(cricket::Time(), now); + LOG(LS_VERBOSE) << "CompleteAuthToken returned: " + << ErrorName(ret, SECURITY_ERRORS); + if (FAILED(ret)) { + return AR_ERROR; + } + } + + //LOG(INFO) << "$$$ NEGOTIATE took " << cricket::TimeDiff(cricket::Time(), now) << "ms"; + + std::string decoded(out_buf, out_buf + out_sec.cbBuffer); + response = auth_method; + response.append(" "); + response.append(Base64::encode(decoded)); + return AR_RESPONSE; + } +#endif +#endif // WIN32 + + return AR_IGNORE; +} + +inline bool end_of_name(size_t pos, size_t len, const char * data) { + if (pos >= len) + return true; + if (isspace(data[pos])) + return true; + // The reason for this complexity is that some non-compliant auth schemes (like Negotiate) + // use base64 tokens in the challenge instead of name=value. This could confuse us when the + // base64 ends in equal signs. + if ((pos+1 < len) && (data[pos] == '=') && !isspace(data[pos+1]) && (data[pos+1] != '=')) + return true; + return false; +} + +void AsyncHttpsProxySocket::ParseAuth(const char * data, size_t len, std::string& method, std::map& args) { + size_t pos = 0; + while ((pos < len) && isspace(data[pos])) ++pos; + size_t start = pos; + while ((pos < len) && !isspace(data[pos])) ++pos; + method.assign(data + start, data + pos); + while (pos < len) { + while ((pos < len) && isspace(data[pos])) ++pos; + if (pos >= len) + return; + + start = pos; + while (!end_of_name(pos, len, data)) ++pos; + //while ((pos < len) && !isspace(data[pos]) && (data[pos] != '=')) ++pos; + std::string name(data + start, data + pos), value; + + if ((pos < len) && (data[pos] == '=')) { + ++pos; // Skip '=' + // Check if quoted value + if ((pos < len) && (data[pos] == '"')) { + while (++pos < len) { + if (data[pos] == '"') { + ++pos; + break; + } + if ((data[pos] == '\\') && (pos + 1 < len)) + ++pos; + value.append(1, data[pos]); + } + } else { + while ((pos < len) && !isspace(data[pos]) && (data[pos] != ',')) + value.append(1, data[pos++]); + } + } else { + value = name; + name.clear(); + } + + args.insert(std::make_pair(name, value)); + if ((pos < len) && (data[pos] == ',')) ++pos; // Skip ',' + } +} + +AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket, const SocketAddress& proxy, + const std::string& username, const buzz::XmppPassword& password) + : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password), + state_(PS_ERROR), context_(0) { +} + +AsyncHttpsProxySocket::~AsyncHttpsProxySocket() { + delete context_; +} + +int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) { + LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect(" << proxy_.ToString() << ")"; + dest_ = addr; + if (dest_.port() != 80) { + BufferInput(true); + } + return BufferedReadAdapter::Connect(proxy_); +} + +SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const { + return dest_; +} + +int AsyncHttpsProxySocket::Close() { + headers_.clear(); + state_ = PS_ERROR; + delete context_; + context_ = 0; + return BufferedReadAdapter::Close(); +} + +void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket * socket) { + LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent"; + // TODO: Decide whether tunneling or not should be explicitly set, + // or indicated by destination port (as below) + if (dest_.port() == 80) { + state_ = PS_TUNNEL; + BufferedReadAdapter::OnConnectEvent(socket); + return; + } + SendRequest(); +} + +void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket * socket, int err) { + LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")"; + if ((state_ == PS_WAIT_CLOSE) && (err == 0)) { + state_ = PS_ERROR; + Connect(dest_); + } else { + BufferedReadAdapter::OnCloseEvent(socket, err); + } +} + +void AsyncHttpsProxySocket::ProcessInput(char * data, size_t& len) { + size_t start = 0; + for (size_t pos = start; (state_ < PS_TUNNEL) && (pos < len); ) { + if (state_ == PS_SKIP_BODY) { + size_t consume = _min(len - pos, content_length_); + pos += consume; + start = pos; + content_length_ -= consume; + if (content_length_ == 0) { + EndResponse(); + } + continue; + } + + if (data[pos++] != '\n') + continue; + + size_t len = pos - start - 1; + if ((len > 0) && (data[start + len - 1] == '\r')) + --len; + + data[start + len] = 0; + ProcessLine(data + start, len); + start = pos; + } + + len -= start; + if (len > 0) { + memmove(data, data + start, len); + } + + if (state_ != PS_TUNNEL) + return; + + bool remainder = (len > 0); + BufferInput(false); + SignalConnectEvent(this); + + // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble + if (remainder) + SignalReadEvent(this); // TODO: signal this?? +} + +void AsyncHttpsProxySocket::SendRequest() { + std::stringstream ss; + ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n"; + ss << "User-Agent: " USERAGENT_STRING "\r\n"; + ss << "Host: " << dest_.IPAsString() << "\r\n"; + ss << "Content-Length: 0\r\n"; + ss << "Proxy-Connection: Keep-Alive\r\n"; + ss << headers_; + ss << "\r\n"; + std::string str = ss.str(); + DirectSend(str.c_str(), str.size()); + state_ = PS_LEADER; + expect_close_ = true; + content_length_ = 0; + headers_.clear(); + + LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str; +} + +void AsyncHttpsProxySocket::ProcessLine(char * data, size_t len) { + LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data; + + if (len == 0) { + if (state_ == PS_TUNNEL_HEADERS) { + state_ = PS_TUNNEL; + } else if (state_ == PS_ERROR_HEADERS) { + Error(defer_error_); + return; + } else if (state_ == PS_SKIP_HEADERS) { + if (content_length_) { + state_ = PS_SKIP_BODY; + } else { + EndResponse(); + return; + } + } else { + static bool report = false; + if (!unknown_mechanisms_.empty() && !report) { + report = true; + std::string msg( + "Unable to connect to the Google Talk service due to an incompatibility " + "with your proxy.\r\nPlease help us resolve this issue by submitting the " + "following information to us using our technical issue submission form " + "at:\r\n\r\n" + "http://www.google.com/support/talk/bin/request.py\r\n\r\n" + "We apologize for the inconvenience.\r\n\r\n" + "Information to submit to Google: " + ); + //std::string msg("Please report the following information to foo@bar.com:\r\nUnknown methods: "); + msg.append(unknown_mechanisms_); +#ifdef WIN32 + MessageBoxA(0, msg.c_str(), "Oops!", MB_OK); +#endif +#ifdef POSIX + //TODO: Raise a signal or something so the UI can be separated. + LOG(LS_ERROR) << "Oops!\n\n" << msg; +#endif + } + // Unexpected end of headers + Error(0); + return; + } + } else if (state_ == PS_LEADER) { + uint32 code; + if (sscanf(data, "HTTP/%*lu.%*lu %lu", &code) != 1) { + Error(0); + return; + } + switch (code) { + case 200: + // connection good! + state_ = PS_TUNNEL_HEADERS; + return; +#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407) +#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ +#endif + case 407: // HTTP_STATUS_PROXY_AUTH_REQ + state_ = PS_AUTHENTICATE; + return; + default: + defer_error_ = 0; + state_ = PS_ERROR_HEADERS; + return; + } + } else if ((state_ == PS_AUTHENTICATE) && (strnicmp(data, "Proxy-Authenticate:", 19) == 0)) { + std::string response, auth_method; + switch (Authenticate(data + 19, len - 19, proxy_, "CONNECT", "/", user_, pass_, context_, response, auth_method)) { + case AR_IGNORE: + LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method; + if (!unknown_mechanisms_.empty()) + unknown_mechanisms_.append(", "); + unknown_mechanisms_.append(auth_method); + break; + case AR_RESPONSE: + headers_ = "Proxy-Authorization: "; + headers_.append(response); + headers_.append("\r\n"); + state_ = PS_SKIP_HEADERS; + unknown_mechanisms_.clear(); + break; + case AR_CREDENTIALS: + defer_error_ = EACCES; + state_ = PS_ERROR_HEADERS; + unknown_mechanisms_.clear(); + break; + case AR_ERROR: + defer_error_ = 0; + state_ = PS_ERROR_HEADERS; + unknown_mechanisms_.clear(); + break; + } + } else if (strnicmp(data, "Content-Length:", 15) == 0) { + content_length_ = strtoul(data + 15, 0, 0); + } else if (strnicmp(data, "Proxy-Connection: Keep-Alive", 28) == 0) { + expect_close_ = false; + /* + } else if (strnicmp(data, "Connection: close", 17) == 0) { + expect_close_ = true; + */ + } +} + +void AsyncHttpsProxySocket::EndResponse() { + if (!expect_close_) { + SendRequest(); + return; + } + + // No point in waiting for the server to close... let's close now + // TODO: Refactor out PS_WAIT_CLOSE + state_ = PS_WAIT_CLOSE; + BufferedReadAdapter::Close(); + OnCloseEvent(this, 0); +} + +void AsyncHttpsProxySocket::Error(int error) { + BufferInput(false); + Close(); + SetError(error); + SignalCloseEvent(this, error); +} + +/////////////////////////////////////////////////////////////////////////////// + +AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy, + const std::string& username, const buzz::XmppPassword& password) + : BufferedReadAdapter(socket, 1024), proxy_(proxy), user_(username), pass_(password), + state_(SS_ERROR) { +} + +int AsyncSocksProxySocket::Connect(const SocketAddress& addr) { + dest_ = addr; + BufferInput(true); + return BufferedReadAdapter::Connect(proxy_); +} + +SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const { + return dest_; +} + +void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket * socket) { + SendHello(); +} + +void AsyncSocksProxySocket::ProcessInput(char * data, size_t& len) { + assert(state_ < SS_TUNNEL); + + ByteBuffer response(data, len); + + if (state_ == SS_HELLO) { + uint8 ver, method; + if (!response.ReadUInt8(ver) || + !response.ReadUInt8(method)) + return; + + if (ver != 5) { + Error(0); + return; + } + + if (method == 0) { + SendConnect(); + } else if (method == 2) { + SendAuth(); + } else { + Error(0); + return; + } + } else if (state_ == SS_AUTH) { + uint8 ver, status; + if (!response.ReadUInt8(ver) || + !response.ReadUInt8(status)) + return; + + if ((ver != 1) || (status != 0)) { + Error(EACCES); + return; + } + + SendConnect(); + } else if (state_ == SS_CONNECT) { + uint8 ver, rep, rsv, atyp; + if (!response.ReadUInt8(ver) || + !response.ReadUInt8(rep) || + !response.ReadUInt8(rsv) || + !response.ReadUInt8(atyp)) + return; + + if ((ver != 5) || (rep != 0)) { + Error(0); + return; + } + + uint16 port; + if (atyp == 1) { + uint32 addr; + if (!response.ReadUInt32(addr) || + !response.ReadUInt16(port)) + return; + LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port; + } else if (atyp == 3) { + uint8 len; + std::string addr; + if (!response.ReadUInt8(len) || + !response.ReadString(addr, len) || + !response.ReadUInt16(port)) + return; + LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port; + } else if (atyp == 4) { + std::string addr; + if (!response.ReadString(addr, 16) || + !response.ReadUInt16(port)) + return; + LOG(LS_VERBOSE) << "Bound on :" << port; + } else { + Error(0); + return; + } + + state_ = SS_TUNNEL; + } + + // Consume parsed data + len = response.Length(); + memcpy(data, response.Data(), len); + + if (state_ != SS_TUNNEL) + return; + + bool remainder = (len > 0); + BufferInput(false); + SignalConnectEvent(this); + + // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble + if (remainder) + SignalReadEvent(this); // TODO: signal this?? +} + +void AsyncSocksProxySocket::SendHello() { + ByteBuffer request; + request.WriteUInt8(5); // Socks Version + if (user_.empty()) { + request.WriteUInt8(1); // Authentication Mechanisms + request.WriteUInt8(0); // No authentication + } else { + request.WriteUInt8(2); // Authentication Mechanisms + request.WriteUInt8(0); // No authentication + request.WriteUInt8(2); // Username/Password + } + DirectSend(request.Data(), request.Length()); + state_ = SS_HELLO; +} + +void AsyncSocksProxySocket::SendAuth() { + ByteBuffer request; + request.WriteUInt8(1); // Negotiation Version + request.WriteUInt8(static_cast(user_.size())); + request.WriteString(user_); // Username + request.WriteUInt8(static_cast(pass_.GetLength())); + size_t len = pass_.GetLength() + 1; + char * sensitive = new char[len]; + pass_.CopyTo(sensitive, true); + request.WriteString(sensitive); // Password + memset(sensitive, 0, len); + delete [] sensitive; + DirectSend(request.Data(), request.Length()); + state_ = SS_AUTH; +} + +void AsyncSocksProxySocket::SendConnect() { + ByteBuffer request; + request.WriteUInt8(5); // Socks Version + request.WriteUInt8(1); // CONNECT + request.WriteUInt8(0); // Reserved + if (dest_.IsUnresolved()) { + std::string hostname = dest_.IPAsString(); + request.WriteUInt8(3); // DOMAINNAME + request.WriteUInt8(static_cast(hostname.size())); + request.WriteString(hostname); // Destination Hostname + } else { + request.WriteUInt8(1); // IPV4 + request.WriteUInt32(dest_.ip()); // Destination IP + } + request.WriteUInt16(dest_.port()); // Destination Port + DirectSend(request.Data(), request.Length()); + state_ = SS_CONNECT; +} + +void AsyncSocksProxySocket::Error(int error) { + state_ = SS_ERROR; + BufferInput(false); + Close(); + SetError(EACCES); + SignalCloseEvent(this, error); +} + +/////////////////////////////////////////////////////////////////////////////// + +LoggingAdapter::LoggingAdapter(AsyncSocket* socket, LoggingSeverity level, + const char * label) + : AsyncSocketAdapter(socket), level_(level) +{ + label_.append("["); + label_.append(label); + label_.append("]"); +} + +int +LoggingAdapter::Send(const void *pv, size_t cb) { + int res = AsyncSocketAdapter::Send(pv, cb); + if (res > 0) + LogMultiline(false, static_cast(pv), res); + return res; +} + +int +LoggingAdapter::SendTo(const void *pv, size_t cb, const SocketAddress& addr) { + int res = AsyncSocketAdapter::SendTo(pv, cb, addr); + if (res > 0) + LogMultiline(false, static_cast(pv), res); + return res; +} + +int +LoggingAdapter::Recv(void *pv, size_t cb) { + int res = AsyncSocketAdapter::Recv(pv, cb); + if (res > 0) + LogMultiline(true, static_cast(pv), res); + return res; +} + +int +LoggingAdapter::RecvFrom(void *pv, size_t cb, SocketAddress *paddr) { + int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr); + if (res > 0) + LogMultiline(true, static_cast(pv), res); + return res; +} + +void +LoggingAdapter::OnConnectEvent(AsyncSocket * socket) { + LOG(level_) << label_ << " Connected"; + AsyncSocketAdapter::OnConnectEvent(socket); +} + +void +LoggingAdapter::OnCloseEvent(AsyncSocket * socket, int err) { + LOG(level_) << label_ << " Closed with error: " << err; + AsyncSocketAdapter::OnCloseEvent(socket, err); +} + +void +LoggingAdapter::LogMultiline(bool input, const char * data, size_t len) { + const char * direction = (input ? " << " : " >> "); + std::string str(data, len); + while (!str.empty()) { + std::string::size_type pos = str.find('\n'); + std::string substr = str; + if (pos == std::string::npos) { + substr = str; + str.clear(); + } else if ((pos > 0) && (str[pos-1] == '\r')) { + substr = str.substr(0, pos - 1); + str = str.substr(pos + 1); + } else { + substr = str.substr(0, pos); + str = str.substr(pos + 1); + } + + // Filter out any private data + std::string::size_type pos_private = substr.find("Email"); + if (pos_private == std::string::npos) { + pos_private = substr.find("Passwd"); + } + if (pos_private == std::string::npos) { + LOG(level_) << label_ << direction << substr; + } else { + LOG(level_) << label_ << direction << "## TEXT REMOVED ##"; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc deleted file mode 100644 index 30d43fc6..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc +++ /dev/null @@ -1,267 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/base/socketaddress.h" -#include "talk/base/byteorder.h" -#include "talk/base/logging.h" -#include -#include -#include - -#ifdef WIN32 -#undef SetPort -int inet_aton(const char * cp, struct in_addr * inp) { - inp->s_addr = inet_addr(cp); - return (inp->s_addr == INADDR_NONE) ? 0 : 1; -} -#endif // WIN32 - -#ifdef POSIX -#include -#include -#include -#include -#include -#endif - -#ifdef _DEBUG -#define DISABLE_DNS 0 -#else // !_DEBUG -#define DISABLE_DNS 0 -#endif // !_DEBUG - -namespace cricket { - -SocketAddress::SocketAddress() { - Zero(); -} - -SocketAddress::SocketAddress(const std::string& hostname, int port, bool use_dns) { - Zero(); - SetIP(hostname, use_dns); - SetPort(port); -} - -SocketAddress::SocketAddress(uint32 ip, int port) { - Zero(); - SetIP(ip); - SetPort(port); -} - -SocketAddress::SocketAddress(const SocketAddress& addr) { - Zero(); - this->operator=(addr); -} - -void SocketAddress::Zero() { - ip_ = 0; - port_ = 0; -} - -SocketAddress& SocketAddress::operator =(const SocketAddress& addr) { - hostname_ = addr.hostname_; - ip_ = addr.ip_; - port_ = addr.port_; - return *this; -} - -void SocketAddress::SetIP(uint32 ip) { - hostname_.clear(); - ip_ = ip; -} - -bool SocketAddress::SetIP(const std::string& hostname, bool use_dns) { - hostname_ = hostname; - ip_ = 0; - return Resolve(true, use_dns); -} - -void SocketAddress::SetResolvedIP(uint32 ip) { - ip_ = ip; -} - -void SocketAddress::SetPort(int port) { - assert((0 <= port) && (port < 65536)); - port_ = port; -} - -uint32 SocketAddress::ip() const { - return ip_; -} - -uint16 SocketAddress::port() const { - return port_; -} - -std::string SocketAddress::IPAsString() const { - if (!hostname_.empty()) - return hostname_; - return IPToString(ip_); -} - -std::string SocketAddress::PortAsString() const { - std::ostringstream ost; - ost << port_; - return ost.str(); -} - -std::string SocketAddress::ToString() const { - std::ostringstream ost; - ost << IPAsString(); - ost << ":"; - ost << port(); - return ost.str(); -} - -bool SocketAddress::IsAny() const { - return (ip_ == 0); -} - -bool SocketAddress::IsLocalIP() const { - return (ip_ >> 24) == 127; -} - -bool SocketAddress::IsPrivateIP() const { - return ((ip_ >> 24) == 127) || - ((ip_ >> 24) == 10) || - ((ip_ >> 20) == ((172 << 4) | 1)) || - ((ip_ >> 16) == ((192 << 8) | 168)); -} - -bool SocketAddress::IsUnresolved() const { - return IsAny() && !hostname_.empty(); -} - -bool SocketAddress::Resolve(bool force, bool use_dns) { - if (hostname_.empty()) { - // nothing to resolve - } else if (!force && !IsAny()) { - // already resolved - } else if (uint32 ip = StringToIP(hostname_, use_dns)) { - ip_ = ip; - } else { - return false; - } - return true; -} - -bool SocketAddress::operator ==(const SocketAddress& addr) const { - return EqualIPs(addr) && EqualPorts(addr); -} - -bool SocketAddress::operator <(const SocketAddress& addr) const { - if (ip_ < addr.ip_) - return true; - else if (addr.ip_ < ip_) - return false; - - // We only check hostnames if both IPs are zero. This matches EqualIPs() - if (addr.ip_ == 0) { - if (hostname_ < addr.hostname_) - return true; - else if (addr.hostname_ < hostname_) - return false; - } - - return port_ < addr.port_; -} - -bool SocketAddress::EqualIPs(const SocketAddress& addr) const { - return (ip_ == addr.ip_) && ((ip_ != 0) || (hostname_ == addr.hostname_)); -} - -bool SocketAddress::EqualPorts(const SocketAddress& addr) const { - return (port_ == addr.port_); -} - -size_t SocketAddress::Hash() const { - size_t h = 0; - h ^= ip_; - h ^= port_ | (port_ << 16); - return h; -} - -size_t SocketAddress::Size_() const { - return sizeof(ip_) + sizeof(port_); -} - -void SocketAddress::Write_(char* buf, int len) const { - // TODO: Depending on how this is used, we may want/need to write hostname - assert((size_t)len >= Size_()); - reinterpret_cast(buf)[0] = ip_; - buf += sizeof(ip_); - reinterpret_cast(buf)[0] = port_; -} - -void SocketAddress::Read_(const char* buf, int len) { - assert((size_t)len >= Size_()); - ip_ = reinterpret_cast(buf)[0]; - buf += sizeof(ip_); - port_ = reinterpret_cast(buf)[0]; -} - -std::string SocketAddress::IPToString(uint32 ip) { - std::ostringstream ost; - ost << ((ip >> 24) & 0xff); - ost << '.'; - ost << ((ip >> 16) & 0xff); - ost << '.'; - ost << ((ip >> 8) & 0xff); - ost << '.'; - ost << ((ip >> 0) & 0xff); - return ost.str(); -} - -uint32 SocketAddress::StringToIP(const std::string& hostname, bool use_dns) { - uint32 ip = 0; - in_addr addr; - if (inet_aton(hostname.c_str(), &addr) != 0) { - ip = NetworkToHost32(addr.s_addr); - } else if (use_dns) { - // Note: this is here so we can spot spurious DNS resolutions for a while - LOG(INFO) << "=== DNS RESOLUTION (" << hostname << ") ==="; -#if DISABLE_DNS - LOG(WARNING) << "*** DNS DISABLED ***"; -#ifdef WIN32 - WSASetLastError(WSAHOST_NOT_FOUND); -#endif // WIN32 -#endif // DISABLE_DNS - if (hostent * pHost = gethostbyname(hostname.c_str())) { - ip = NetworkToHost32(*reinterpret_cast(pHost->h_addr_list[0])); - } else { -#ifdef WIN32 - LOG(LS_ERROR) << "gethostbyname error: " << WSAGetLastError(); -#else - LOG(LS_ERROR) << "gethostbyname error: " << strerror(h_errno); -#endif - } - LOG(INFO) << hostname << " resolved to " << IPToString(ip); - } - return ip; -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cpp new file mode 100644 index 00000000..30d43fc6 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cpp @@ -0,0 +1,267 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/socketaddress.h" +#include "talk/base/byteorder.h" +#include "talk/base/logging.h" +#include +#include +#include + +#ifdef WIN32 +#undef SetPort +int inet_aton(const char * cp, struct in_addr * inp) { + inp->s_addr = inet_addr(cp); + return (inp->s_addr == INADDR_NONE) ? 0 : 1; +} +#endif // WIN32 + +#ifdef POSIX +#include +#include +#include +#include +#include +#endif + +#ifdef _DEBUG +#define DISABLE_DNS 0 +#else // !_DEBUG +#define DISABLE_DNS 0 +#endif // !_DEBUG + +namespace cricket { + +SocketAddress::SocketAddress() { + Zero(); +} + +SocketAddress::SocketAddress(const std::string& hostname, int port, bool use_dns) { + Zero(); + SetIP(hostname, use_dns); + SetPort(port); +} + +SocketAddress::SocketAddress(uint32 ip, int port) { + Zero(); + SetIP(ip); + SetPort(port); +} + +SocketAddress::SocketAddress(const SocketAddress& addr) { + Zero(); + this->operator=(addr); +} + +void SocketAddress::Zero() { + ip_ = 0; + port_ = 0; +} + +SocketAddress& SocketAddress::operator =(const SocketAddress& addr) { + hostname_ = addr.hostname_; + ip_ = addr.ip_; + port_ = addr.port_; + return *this; +} + +void SocketAddress::SetIP(uint32 ip) { + hostname_.clear(); + ip_ = ip; +} + +bool SocketAddress::SetIP(const std::string& hostname, bool use_dns) { + hostname_ = hostname; + ip_ = 0; + return Resolve(true, use_dns); +} + +void SocketAddress::SetResolvedIP(uint32 ip) { + ip_ = ip; +} + +void SocketAddress::SetPort(int port) { + assert((0 <= port) && (port < 65536)); + port_ = port; +} + +uint32 SocketAddress::ip() const { + return ip_; +} + +uint16 SocketAddress::port() const { + return port_; +} + +std::string SocketAddress::IPAsString() const { + if (!hostname_.empty()) + return hostname_; + return IPToString(ip_); +} + +std::string SocketAddress::PortAsString() const { + std::ostringstream ost; + ost << port_; + return ost.str(); +} + +std::string SocketAddress::ToString() const { + std::ostringstream ost; + ost << IPAsString(); + ost << ":"; + ost << port(); + return ost.str(); +} + +bool SocketAddress::IsAny() const { + return (ip_ == 0); +} + +bool SocketAddress::IsLocalIP() const { + return (ip_ >> 24) == 127; +} + +bool SocketAddress::IsPrivateIP() const { + return ((ip_ >> 24) == 127) || + ((ip_ >> 24) == 10) || + ((ip_ >> 20) == ((172 << 4) | 1)) || + ((ip_ >> 16) == ((192 << 8) | 168)); +} + +bool SocketAddress::IsUnresolved() const { + return IsAny() && !hostname_.empty(); +} + +bool SocketAddress::Resolve(bool force, bool use_dns) { + if (hostname_.empty()) { + // nothing to resolve + } else if (!force && !IsAny()) { + // already resolved + } else if (uint32 ip = StringToIP(hostname_, use_dns)) { + ip_ = ip; + } else { + return false; + } + return true; +} + +bool SocketAddress::operator ==(const SocketAddress& addr) const { + return EqualIPs(addr) && EqualPorts(addr); +} + +bool SocketAddress::operator <(const SocketAddress& addr) const { + if (ip_ < addr.ip_) + return true; + else if (addr.ip_ < ip_) + return false; + + // We only check hostnames if both IPs are zero. This matches EqualIPs() + if (addr.ip_ == 0) { + if (hostname_ < addr.hostname_) + return true; + else if (addr.hostname_ < hostname_) + return false; + } + + return port_ < addr.port_; +} + +bool SocketAddress::EqualIPs(const SocketAddress& addr) const { + return (ip_ == addr.ip_) && ((ip_ != 0) || (hostname_ == addr.hostname_)); +} + +bool SocketAddress::EqualPorts(const SocketAddress& addr) const { + return (port_ == addr.port_); +} + +size_t SocketAddress::Hash() const { + size_t h = 0; + h ^= ip_; + h ^= port_ | (port_ << 16); + return h; +} + +size_t SocketAddress::Size_() const { + return sizeof(ip_) + sizeof(port_); +} + +void SocketAddress::Write_(char* buf, int len) const { + // TODO: Depending on how this is used, we may want/need to write hostname + assert((size_t)len >= Size_()); + reinterpret_cast(buf)[0] = ip_; + buf += sizeof(ip_); + reinterpret_cast(buf)[0] = port_; +} + +void SocketAddress::Read_(const char* buf, int len) { + assert((size_t)len >= Size_()); + ip_ = reinterpret_cast(buf)[0]; + buf += sizeof(ip_); + port_ = reinterpret_cast(buf)[0]; +} + +std::string SocketAddress::IPToString(uint32 ip) { + std::ostringstream ost; + ost << ((ip >> 24) & 0xff); + ost << '.'; + ost << ((ip >> 16) & 0xff); + ost << '.'; + ost << ((ip >> 8) & 0xff); + ost << '.'; + ost << ((ip >> 0) & 0xff); + return ost.str(); +} + +uint32 SocketAddress::StringToIP(const std::string& hostname, bool use_dns) { + uint32 ip = 0; + in_addr addr; + if (inet_aton(hostname.c_str(), &addr) != 0) { + ip = NetworkToHost32(addr.s_addr); + } else if (use_dns) { + // Note: this is here so we can spot spurious DNS resolutions for a while + LOG(INFO) << "=== DNS RESOLUTION (" << hostname << ") ==="; +#if DISABLE_DNS + LOG(WARNING) << "*** DNS DISABLED ***"; +#ifdef WIN32 + WSASetLastError(WSAHOST_NOT_FOUND); +#endif // WIN32 +#endif // DISABLE_DNS + if (hostent * pHost = gethostbyname(hostname.c_str())) { + ip = NetworkToHost32(*reinterpret_cast(pHost->h_addr_list[0])); + } else { +#ifdef WIN32 + LOG(LS_ERROR) << "gethostbyname error: " << WSAGetLastError(); +#else + LOG(LS_ERROR) << "gethostbyname error: " << strerror(h_errno); +#endif + } + LOG(INFO) << hostname << " resolved to " << IPToString(ip); + } + return ip; +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc deleted file mode 100644 index 2166be09..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/base/socketaddresspair.h" - -namespace cricket { - -SocketAddressPair::SocketAddressPair( - const SocketAddress& src, const SocketAddress& dest) - : src_(src), dest_(dest) { -} - - -bool SocketAddressPair::operator ==(const SocketAddressPair& p) const { - return (src_ == p.src_) && (dest_ == p.dest_); -} - -bool SocketAddressPair::operator <(const SocketAddressPair& p) const { - if (src_ < p.src_) - return true; - if (p.src_ < src_) - return false; - if (dest_ < p.dest_) - return true; - if (p.dest_ < dest_) - return false; - return false; -} - -size_t SocketAddressPair::Hash() const { - return src_.Hash() ^ dest_.Hash(); -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cpp new file mode 100644 index 00000000..2166be09 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cpp @@ -0,0 +1,58 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/socketaddresspair.h" + +namespace cricket { + +SocketAddressPair::SocketAddressPair( + const SocketAddress& src, const SocketAddress& dest) + : src_(src), dest_(dest) { +} + + +bool SocketAddressPair::operator ==(const SocketAddressPair& p) const { + return (src_ == p.src_) && (dest_ == p.dest_); +} + +bool SocketAddressPair::operator <(const SocketAddressPair& p) const { + if (src_ < p.src_) + return true; + if (p.src_ < src_) + return false; + if (dest_ < p.dest_) + return true; + if (p.dest_ < dest_) + return false; + return false; +} + +size_t SocketAddressPair::Hash() const { + return src_.Hash() ^ dest_.Hash(); +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc deleted file mode 100644 index a5a94941..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc +++ /dev/null @@ -1,238 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "task.h" -#include "taskrunner.h" - -#include - -namespace buzz { - -Task::Task(Task * parent) : - state_(STATE_INIT), - parent_(parent), - blocked_(false), - done_(false), - aborted_(false), - busy_(false), - error_(false), - child_error_(false), - start_time_(0) { - runner_ = ((parent == NULL) ? (TaskRunner *)this : parent->GetRunner()); - if (parent_ != NULL) { - parent_->AddChild(this); - } -} - -unsigned long long -Task::CurrentTime() { - return runner_->CurrentTime(); -} - -unsigned long long -Task::ElapsedTime() { - return CurrentTime() - start_time_; -} - -void -Task::Start() { - if (state_ != STATE_INIT) - return; - GetRunner()->StartTask(this); - start_time_ = CurrentTime(); -} - -void -Task::Step() { - if (done_) { -#ifdef DEBUG - // we do not know how !blocked_ happens when done_ - should be impossible. - // But it causes problems, so in retail build, we force blocked_, and - // under debug we assert. - assert(blocked_); -#else - blocked_ = true; -#endif - return; - } - - // Async Error() was called - if (error_) { - done_ = true; - state_ = STATE_ERROR; - blocked_ = true; -// obsolete - an errored task is not considered done now -// SignalDone(); - Stop(); - return; - } - - busy_ = true; - int new_state = Process(state_); - busy_ = false; - - if (aborted_) { - Abort(true); // no need to wake because we're awake - return; - } - - if (new_state == STATE_BLOCKED) { - blocked_ = true; - } - else { - state_ = new_state; - blocked_ = false; - } - - if (new_state == STATE_DONE) { - done_ = true; - } - else if (new_state == STATE_ERROR) { - done_ = true; - error_ = true; - } - - if (done_) { -// obsolete - call this yourself -// SignalDone(); - Stop(); - blocked_ = true; - } -} - -void -Task::Abort(bool nowake) { - if (aborted_ || done_) - return; - aborted_ = true; - if (!busy_) { - done_ = true; - blocked_ = true; - error_ = true; - Stop(); - if (!nowake) - Wake(); // to self-delete - } -} - -void -Task::Wake() { - if (done_) - return; - if (blocked_) { - blocked_ = false; - GetRunner()->WakeTasks(); - } -} - -void -Task::Error() { - if (error_ || done_) - return; - error_ = true; - Wake(); -} - -std::string -Task::GetStateName(int state) const { - static const std::string STR_BLOCKED("BLOCKED"); - static const std::string STR_INIT("INIT"); - static const std::string STR_START("START"); - static const std::string STR_DONE("DONE"); - static const std::string STR_ERROR("ERROR"); - static const std::string STR_RESPONSE("RESPONSE"); - static const std::string STR_HUH("??"); - switch (state) { - case STATE_BLOCKED: return STR_BLOCKED; - case STATE_INIT: return STR_INIT; - case STATE_START: return STR_START; - case STATE_DONE: return STR_DONE; - case STATE_ERROR: return STR_ERROR; - case STATE_RESPONSE: return STR_RESPONSE; - } - return STR_HUH; -} - -int Task::Process(int state) { - switch (state) { - case STATE_INIT: - return STATE_START; - case STATE_START: - return ProcessStart(); - case STATE_RESPONSE: - return ProcessResponse(); - case STATE_DONE: - case STATE_ERROR: - return STATE_BLOCKED; - } - return STATE_ERROR; -} - -void -Task::AddChild(Task * child) { - children_.insert(child); -} - -bool -Task::AllChildrenDone() { - for (ChildSet::iterator it = children_.begin(); it != children_.end(); ++it) { - if (!(*it)->IsDone()) - return false; - } - return true; -} - -bool -Task::AnyChildError() { - return child_error_; -} - -void -Task::AbortAllChildren() { - if (children_.size() > 0) { - ChildSet copy = children_; - for (ChildSet::iterator it = copy.begin(); it != copy.end(); ++it) { - (*it)->Abort(true); // Note we do not wake - } - } -} - -void -Task::Stop() { - AbortAllChildren(); // No need to wake because we're either awake or in abort - parent_->OnChildStopped(this); -} - -void -Task::OnChildStopped(Task * child) { - if (child->HasError()) - child_error_ = true; - children_.erase(child); -} - - -} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cpp new file mode 100644 index 00000000..a5a94941 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cpp @@ -0,0 +1,238 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "task.h" +#include "taskrunner.h" + +#include + +namespace buzz { + +Task::Task(Task * parent) : + state_(STATE_INIT), + parent_(parent), + blocked_(false), + done_(false), + aborted_(false), + busy_(false), + error_(false), + child_error_(false), + start_time_(0) { + runner_ = ((parent == NULL) ? (TaskRunner *)this : parent->GetRunner()); + if (parent_ != NULL) { + parent_->AddChild(this); + } +} + +unsigned long long +Task::CurrentTime() { + return runner_->CurrentTime(); +} + +unsigned long long +Task::ElapsedTime() { + return CurrentTime() - start_time_; +} + +void +Task::Start() { + if (state_ != STATE_INIT) + return; + GetRunner()->StartTask(this); + start_time_ = CurrentTime(); +} + +void +Task::Step() { + if (done_) { +#ifdef DEBUG + // we do not know how !blocked_ happens when done_ - should be impossible. + // But it causes problems, so in retail build, we force blocked_, and + // under debug we assert. + assert(blocked_); +#else + blocked_ = true; +#endif + return; + } + + // Async Error() was called + if (error_) { + done_ = true; + state_ = STATE_ERROR; + blocked_ = true; +// obsolete - an errored task is not considered done now +// SignalDone(); + Stop(); + return; + } + + busy_ = true; + int new_state = Process(state_); + busy_ = false; + + if (aborted_) { + Abort(true); // no need to wake because we're awake + return; + } + + if (new_state == STATE_BLOCKED) { + blocked_ = true; + } + else { + state_ = new_state; + blocked_ = false; + } + + if (new_state == STATE_DONE) { + done_ = true; + } + else if (new_state == STATE_ERROR) { + done_ = true; + error_ = true; + } + + if (done_) { +// obsolete - call this yourself +// SignalDone(); + Stop(); + blocked_ = true; + } +} + +void +Task::Abort(bool nowake) { + if (aborted_ || done_) + return; + aborted_ = true; + if (!busy_) { + done_ = true; + blocked_ = true; + error_ = true; + Stop(); + if (!nowake) + Wake(); // to self-delete + } +} + +void +Task::Wake() { + if (done_) + return; + if (blocked_) { + blocked_ = false; + GetRunner()->WakeTasks(); + } +} + +void +Task::Error() { + if (error_ || done_) + return; + error_ = true; + Wake(); +} + +std::string +Task::GetStateName(int state) const { + static const std::string STR_BLOCKED("BLOCKED"); + static const std::string STR_INIT("INIT"); + static const std::string STR_START("START"); + static const std::string STR_DONE("DONE"); + static const std::string STR_ERROR("ERROR"); + static const std::string STR_RESPONSE("RESPONSE"); + static const std::string STR_HUH("??"); + switch (state) { + case STATE_BLOCKED: return STR_BLOCKED; + case STATE_INIT: return STR_INIT; + case STATE_START: return STR_START; + case STATE_DONE: return STR_DONE; + case STATE_ERROR: return STR_ERROR; + case STATE_RESPONSE: return STR_RESPONSE; + } + return STR_HUH; +} + +int Task::Process(int state) { + switch (state) { + case STATE_INIT: + return STATE_START; + case STATE_START: + return ProcessStart(); + case STATE_RESPONSE: + return ProcessResponse(); + case STATE_DONE: + case STATE_ERROR: + return STATE_BLOCKED; + } + return STATE_ERROR; +} + +void +Task::AddChild(Task * child) { + children_.insert(child); +} + +bool +Task::AllChildrenDone() { + for (ChildSet::iterator it = children_.begin(); it != children_.end(); ++it) { + if (!(*it)->IsDone()) + return false; + } + return true; +} + +bool +Task::AnyChildError() { + return child_error_; +} + +void +Task::AbortAllChildren() { + if (children_.size() > 0) { + ChildSet copy = children_; + for (ChildSet::iterator it = copy.begin(); it != copy.end(); ++it) { + (*it)->Abort(true); // Note we do not wake + } + } +} + +void +Task::Stop() { + AbortAllChildren(); // No need to wake because we're either awake or in abort + parent_->OnChildStopped(this); +} + +void +Task::OnChildStopped(Task * child) { + if (child->HasError()) + child_error_ = true; + children_.erase(child); +} + + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc deleted file mode 100644 index b5ecc55e..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "taskrunner.h" -#include "task.h" -#include - - -namespace buzz { - -TaskRunner::~TaskRunner() { - // this kills and deletes children silently! - AbortAllChildren(); - RunTasks(); -} - -void -TaskRunner::StartTask(Task * task) { - tasks_.push_back(task); - WakeTasks(); -} - -void -TaskRunner::RunTasks() { - // Running continues until all tasks are Blocked (ok for a small # of tasks) - if (tasks_running_) { - return; // don't reenter - } - - tasks_running_ = true; - - int did_run = true; - while (did_run) { - did_run = false; - // use indexing instead of iterators because tasks_ may grow - for (size_t i = 0; i < tasks_.size(); ++i) { - while (!tasks_[i]->Blocked()) { - tasks_[i]->Step(); - did_run = true; - } - } - } - // Tasks are deleted when running has paused - for (size_t i = 0; i < tasks_.size(); ++i) { - if (tasks_[i]->IsDone()) { - Task* task = tasks_[i]; - delete task; - tasks_[i] = NULL; - } - } - // Finally, remove nulls - tasks_.erase(std::remove(tasks_.begin(), tasks_.end(), (Task *)NULL), tasks_.end()); - - tasks_running_ = false; -} - -void -TaskRunner::PollTasks() { - // every task gets hit once with a poll - they wake if needed - for (size_t i = 0; i < tasks_.size(); ++i) { - if (!tasks_[i]->IsDone()) { - tasks_[i]->Poll(); - } - } -} - - -} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cpp new file mode 100644 index 00000000..b5ecc55e --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cpp @@ -0,0 +1,92 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "taskrunner.h" +#include "task.h" +#include + + +namespace buzz { + +TaskRunner::~TaskRunner() { + // this kills and deletes children silently! + AbortAllChildren(); + RunTasks(); +} + +void +TaskRunner::StartTask(Task * task) { + tasks_.push_back(task); + WakeTasks(); +} + +void +TaskRunner::RunTasks() { + // Running continues until all tasks are Blocked (ok for a small # of tasks) + if (tasks_running_) { + return; // don't reenter + } + + tasks_running_ = true; + + int did_run = true; + while (did_run) { + did_run = false; + // use indexing instead of iterators because tasks_ may grow + for (size_t i = 0; i < tasks_.size(); ++i) { + while (!tasks_[i]->Blocked()) { + tasks_[i]->Step(); + did_run = true; + } + } + } + // Tasks are deleted when running has paused + for (size_t i = 0; i < tasks_.size(); ++i) { + if (tasks_[i]->IsDone()) { + Task* task = tasks_[i]; + delete task; + tasks_[i] = NULL; + } + } + // Finally, remove nulls + tasks_.erase(std::remove(tasks_.begin(), tasks_.end(), (Task *)NULL), tasks_.end()); + + tasks_running_ = false; +} + +void +TaskRunner::PollTasks() { + // every task gets hit once with a poll - they wake if needed + for (size_t i = 0; i < tasks_.size(); ++i) { + if (!tasks_[i]->IsDone()) { + tasks_[i]->Poll(); + } + } +} + + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc deleted file mode 100644 index b189e621..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc +++ /dev/null @@ -1,274 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef POSIX -extern "C" { -#include -} -#endif - -#include "talk/base/common.h" -#include "talk/base/logging.h" -#include "talk/base/thread.h" -#include "talk/base/jtime.h" - -namespace cricket { - -ThreadManager g_thmgr; - -#ifdef POSIX -pthread_key_t ThreadManager::key_; - -ThreadManager::ThreadManager() { - pthread_key_create(&key_, NULL); - main_thread_ = new Thread(); - SetCurrent(main_thread_); -} - -ThreadManager::~ThreadManager() { - pthread_key_delete(key_); - delete main_thread_; -} - -Thread *ThreadManager::CurrentThread() { - return (Thread *)pthread_getspecific(key_); -} - -void ThreadManager::SetCurrent(Thread *thread) { - pthread_setspecific(key_, thread); -} -#endif - -#ifdef WIN32 -DWORD ThreadManager::key_; - -ThreadManager::ThreadManager() { - key_ = TlsAlloc(); - main_thread_ = new Thread(); - SetCurrent(main_thread_); -} - -ThreadManager::~ThreadManager() { - TlsFree(key_); - delete main_thread_; -} - -Thread *ThreadManager::CurrentThread() { - return (Thread *)TlsGetValue(key_); -} - -void ThreadManager::SetCurrent(Thread *thread) { - TlsSetValue(key_, thread); -} -#endif - -void ThreadManager::Add(Thread *thread) { - CritScope cs(&crit_); - threads_.push_back(thread); -} - -void ThreadManager::Remove(Thread *thread) { - CritScope cs(&crit_); - threads_.erase(std::remove(threads_.begin(), threads_.end(), thread), threads_.end()); -} - -Thread::Thread(SocketServer* ss) : MessageQueue(ss) { - g_thmgr.Add(this); - started_ = false; - has_sends_ = false; -} - -Thread::~Thread() { - Stop(); - Clear(NULL); - g_thmgr.Remove(this); -} - -#ifdef POSIX -void Thread::Start() { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_create(&thread_, &attr, PreLoop, this); - pthread_attr_destroy(&attr); - started_ = true; -} - -void Thread::Join() { - if (started_) { - void *pv; - pthread_join(thread_, &pv); - } -} -#endif - -#ifdef WIN32 -void Thread::Start() { - thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreLoop, this, 0, NULL); - started_ = true; -} - -void Thread::Join() { - if (started_) { - WaitForSingleObject(thread_, INFINITE); - CloseHandle(thread_); - started_ = false; - } -} -#endif - -void *Thread::PreLoop(void *pv) { - Thread *thread = (Thread *)pv; - ThreadManager::SetCurrent(thread); - thread->Loop(); - return NULL; -} - -void Thread::Loop(int cmsLoop) { - uint32 msEnd; - if (cmsLoop != -1) - msEnd = GetMillisecondCount() + cmsLoop; - int cmsNext = cmsLoop; - - while (true) { - Message msg; - if (!Get(&msg, cmsNext)) - return; - Dispatch(&msg); - - if (cmsLoop != -1) { - uint32 msCur = GetMillisecondCount(); - if (msCur >= msEnd) - return; - cmsNext = msEnd - msCur; - } - } -} - -void Thread::Stop() { - MessageQueue::Stop(); - Join(); -} - -void Thread::Send(MessageHandler *phandler, uint32 id, MessageData *pdata) { - // Sent messages are sent to the MessageHandler directly, in the context - // of "thread", like Win32 SendMessage. If in the right context, - // call the handler directly. - - Message msg; - msg.phandler = phandler; - msg.message_id = id; - msg.pdata = pdata; - if (IsCurrent()) { - phandler->OnMessage(&msg); - return; - } - - AutoThread thread; - Thread *current_thread = Thread::Current(); - ASSERT(current_thread != NULL); // AutoThread ensures this - - crit_.Enter(); - bool ready = false; - _SendMessage smsg; - smsg.thread = current_thread; - smsg.msg = msg; - smsg.ready = &ready; - sendlist_.push_back(smsg); - has_sends_ = true; - crit_.Leave(); - - // Wait for a reply - - ss_->WakeUp(); - while (!ready) { - current_thread->ReceiveSends(); - current_thread->socketserver()->Wait(-1, false); - } -} - -void Thread::ReceiveSends() { - // Before entering critical section, check boolean. - - if (!has_sends_) - return; - - // Receive a sent message. Cleanup scenarios: - // - thread sending exits: We don't allow this, since thread can exit - // only via Join, so Send must complete. - // - thread receiving exits: Wakeup/set ready in Thread::Clear() - // - object target cleared: Wakeup/set ready in Thread::Clear() - crit_.Enter(); - while (!sendlist_.empty()) { - _SendMessage smsg = sendlist_.front(); - sendlist_.pop_front(); - crit_.Leave(); - smsg.msg.phandler->OnMessage(&smsg.msg); - crit_.Enter(); - *smsg.ready = true; - smsg.thread->socketserver()->WakeUp(); - } - has_sends_ = false; - crit_.Leave(); -} - -void Thread::Clear(MessageHandler *phandler, uint32 id) { - CritScope cs(&crit_); - - // Remove messages on sendlist_ with phandler - // Object target cleared: remove from send list, wakeup/set ready - // if sender not NULL. - - std::list<_SendMessage>::iterator iter = sendlist_.begin(); - while (iter != sendlist_.end()) { - _SendMessage smsg = *iter; - if (phandler == NULL || smsg.msg.phandler == phandler) { - if (id == (uint32)-1 || smsg.msg.message_id == id) { - iter = sendlist_.erase(iter); - *smsg.ready = true; - smsg.thread->socketserver()->WakeUp(); - continue; - } - } - ++iter; - } - - MessageQueue::Clear(phandler, id); -} - -AutoThread::AutoThread(SocketServer* ss) : Thread(ss) { - if (!ThreadManager::CurrentThread()) { - ThreadManager::SetCurrent(this); - } -} - -AutoThread::~AutoThread() { - if (ThreadManager::CurrentThread() == this) { - ThreadManager::SetCurrent(NULL); - } -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cpp new file mode 100644 index 00000000..b189e621 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cpp @@ -0,0 +1,274 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef POSIX +extern "C" { +#include +} +#endif + +#include "talk/base/common.h" +#include "talk/base/logging.h" +#include "talk/base/thread.h" +#include "talk/base/jtime.h" + +namespace cricket { + +ThreadManager g_thmgr; + +#ifdef POSIX +pthread_key_t ThreadManager::key_; + +ThreadManager::ThreadManager() { + pthread_key_create(&key_, NULL); + main_thread_ = new Thread(); + SetCurrent(main_thread_); +} + +ThreadManager::~ThreadManager() { + pthread_key_delete(key_); + delete main_thread_; +} + +Thread *ThreadManager::CurrentThread() { + return (Thread *)pthread_getspecific(key_); +} + +void ThreadManager::SetCurrent(Thread *thread) { + pthread_setspecific(key_, thread); +} +#endif + +#ifdef WIN32 +DWORD ThreadManager::key_; + +ThreadManager::ThreadManager() { + key_ = TlsAlloc(); + main_thread_ = new Thread(); + SetCurrent(main_thread_); +} + +ThreadManager::~ThreadManager() { + TlsFree(key_); + delete main_thread_; +} + +Thread *ThreadManager::CurrentThread() { + return (Thread *)TlsGetValue(key_); +} + +void ThreadManager::SetCurrent(Thread *thread) { + TlsSetValue(key_, thread); +} +#endif + +void ThreadManager::Add(Thread *thread) { + CritScope cs(&crit_); + threads_.push_back(thread); +} + +void ThreadManager::Remove(Thread *thread) { + CritScope cs(&crit_); + threads_.erase(std::remove(threads_.begin(), threads_.end(), thread), threads_.end()); +} + +Thread::Thread(SocketServer* ss) : MessageQueue(ss) { + g_thmgr.Add(this); + started_ = false; + has_sends_ = false; +} + +Thread::~Thread() { + Stop(); + Clear(NULL); + g_thmgr.Remove(this); +} + +#ifdef POSIX +void Thread::Start() { + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_create(&thread_, &attr, PreLoop, this); + pthread_attr_destroy(&attr); + started_ = true; +} + +void Thread::Join() { + if (started_) { + void *pv; + pthread_join(thread_, &pv); + } +} +#endif + +#ifdef WIN32 +void Thread::Start() { + thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreLoop, this, 0, NULL); + started_ = true; +} + +void Thread::Join() { + if (started_) { + WaitForSingleObject(thread_, INFINITE); + CloseHandle(thread_); + started_ = false; + } +} +#endif + +void *Thread::PreLoop(void *pv) { + Thread *thread = (Thread *)pv; + ThreadManager::SetCurrent(thread); + thread->Loop(); + return NULL; +} + +void Thread::Loop(int cmsLoop) { + uint32 msEnd; + if (cmsLoop != -1) + msEnd = GetMillisecondCount() + cmsLoop; + int cmsNext = cmsLoop; + + while (true) { + Message msg; + if (!Get(&msg, cmsNext)) + return; + Dispatch(&msg); + + if (cmsLoop != -1) { + uint32 msCur = GetMillisecondCount(); + if (msCur >= msEnd) + return; + cmsNext = msEnd - msCur; + } + } +} + +void Thread::Stop() { + MessageQueue::Stop(); + Join(); +} + +void Thread::Send(MessageHandler *phandler, uint32 id, MessageData *pdata) { + // Sent messages are sent to the MessageHandler directly, in the context + // of "thread", like Win32 SendMessage. If in the right context, + // call the handler directly. + + Message msg; + msg.phandler = phandler; + msg.message_id = id; + msg.pdata = pdata; + if (IsCurrent()) { + phandler->OnMessage(&msg); + return; + } + + AutoThread thread; + Thread *current_thread = Thread::Current(); + ASSERT(current_thread != NULL); // AutoThread ensures this + + crit_.Enter(); + bool ready = false; + _SendMessage smsg; + smsg.thread = current_thread; + smsg.msg = msg; + smsg.ready = &ready; + sendlist_.push_back(smsg); + has_sends_ = true; + crit_.Leave(); + + // Wait for a reply + + ss_->WakeUp(); + while (!ready) { + current_thread->ReceiveSends(); + current_thread->socketserver()->Wait(-1, false); + } +} + +void Thread::ReceiveSends() { + // Before entering critical section, check boolean. + + if (!has_sends_) + return; + + // Receive a sent message. Cleanup scenarios: + // - thread sending exits: We don't allow this, since thread can exit + // only via Join, so Send must complete. + // - thread receiving exits: Wakeup/set ready in Thread::Clear() + // - object target cleared: Wakeup/set ready in Thread::Clear() + crit_.Enter(); + while (!sendlist_.empty()) { + _SendMessage smsg = sendlist_.front(); + sendlist_.pop_front(); + crit_.Leave(); + smsg.msg.phandler->OnMessage(&smsg.msg); + crit_.Enter(); + *smsg.ready = true; + smsg.thread->socketserver()->WakeUp(); + } + has_sends_ = false; + crit_.Leave(); +} + +void Thread::Clear(MessageHandler *phandler, uint32 id) { + CritScope cs(&crit_); + + // Remove messages on sendlist_ with phandler + // Object target cleared: remove from send list, wakeup/set ready + // if sender not NULL. + + std::list<_SendMessage>::iterator iter = sendlist_.begin(); + while (iter != sendlist_.end()) { + _SendMessage smsg = *iter; + if (phandler == NULL || smsg.msg.phandler == phandler) { + if (id == (uint32)-1 || smsg.msg.message_id == id) { + iter = sendlist_.erase(iter); + *smsg.ready = true; + smsg.thread->socketserver()->WakeUp(); + continue; + } + } + ++iter; + } + + MessageQueue::Clear(phandler, id); +} + +AutoThread::AutoThread(SocketServer* ss) : Thread(ss) { + if (!ThreadManager::CurrentThread()) { + ThreadManager::SetCurrent(this); + } +} + +AutoThread::~AutoThread() { + if (ThreadManager::CurrentThread() == this) { + ThreadManager::SetCurrent(NULL); + } +} + +} // namespace cricket -- cgit v1.2.1