diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | bcb704366cb5e333a626c18c308c7e0448a8e69f (patch) | |
tree | f0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /kopete/protocols/jabber/jingle/libjingle/talk/base | |
download | tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kopete/protocols/jabber/jingle/libjingle/talk/base')
53 files changed, 11482 insertions, 0 deletions
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am new file mode 100644 index 00000000..2921049a --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/Makefile.am @@ -0,0 +1,62 @@ +## 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 \ + md5c.c \ + base64.cc \ + task.cc \ + taskrunner.cc \ + host.cc \ + socketaddresspair.cc + +noinst_HEADERS = asyncfile.h \ + common.h \ + asyncpacketsocket.h \ + socketfactory.h \ + asyncsocket.h \ + socket.h \ + asynctcpsocket.h \ + linked_ptr.h \ + asyncudpsocket.h \ + logging.h \ + socketserver.h \ + base64.h \ + md5.h \ + stl_decl.h \ + basicdefs.h \ + messagequeue.h \ + basictypes.h \ + stringutils.h \ + bytebuffer.h \ + task.h \ + byteorder.h \ + taskrunner.h \ + criticalsection.h \ + network.h \ + thread.h \ + jtime.h \ + physicalsocketserver.h \ + proxyinfo.h \ + host.h \ + scoped_ptr.h \ + sigslot.h \ + winping.h \ + socketadapters.h \ + socketaddress.h \ + host.h \ + socketaddresspair.h + +AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../.. -I$(top_builddir) $(all_includes) +noinst_LTLIBRARIES = libcricketbase.la +DEFAULT_INCLUDES = -I$(srcdir)/../.. + diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h new file mode 100644 index 00000000..0faac9ea --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncfile.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef CRICKET_BASE_ASYNCFILEH_H__ +#define CRICKET_BASE_ASYNCFILEH_H__ + +#include "talk/base/sigslot.h" + +namespace cricket { + +// Provides the ability to perform file I/O asynchronously. +// TODO: Create a common base class with AsyncSocket. +class AsyncFile { +public: + virtual ~AsyncFile() {} + + // Determines whether the file will receive read events. + virtual bool readable() = 0; + virtual void set_readable(bool value) = 0; + + // Determines whether the file will receive write events. + virtual bool writable() = 0; + virtual void set_writable(bool value) = 0; + + sigslot::signal1<AsyncFile*> SignalReadEvent; + sigslot::signal1<AsyncFile*> SignalWriteEvent; + sigslot::signal2<AsyncFile*,int> SignalCloseEvent; +}; + +} // namespace cricket + +#endif // CRICKET_BASE_ASYNCFILEH_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc new file mode 100644 index 00000000..10cfa617 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.cc @@ -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/asyncpacketsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.h new file mode 100644 index 00000000..b5119c8d --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncpacketsocket.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef __ASYNCPACKETSOCKET_H__ +#define __ASYNCPACKETSOCKET_H__ + +#include "talk/base/asyncsocket.h" + +namespace cricket { + +// Provides the ability to receive packets asynchronously. Sends are not +// buffered since it is acceptable to drop packets under high load. +class AsyncPacketSocket : public sigslot::has_slots<> { +public: + AsyncPacketSocket(AsyncSocket* socket); + virtual ~AsyncPacketSocket(); + + // Relevant socket methods: + virtual SocketAddress GetLocalAddress() const; + virtual SocketAddress GetRemoteAddress() const; + virtual int Bind(const SocketAddress& addr); + virtual int Connect(const SocketAddress& addr); + virtual int Send(const void *pv, size_t cb); + virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr); + virtual int Close(); + virtual int SetOption(Socket::Option opt, int value); + virtual int GetError() const; + virtual void SetError(int error); + + // Emitted each time a packet is read. + sigslot::signal4<const char*, size_t, const SocketAddress&, AsyncPacketSocket*> SignalReadPacket; + +protected: + AsyncSocket* socket_; +}; + +} // namespace cricket + +#endif // __ASYNCPACKETSOCKET_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h new file mode 100644 index 00000000..d6404232 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncsocket.h @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#ifndef __ASYNCSOCKET_H__ +#define __ASYNCSOCKET_H__ + +#include "talk/base/sigslot.h" +#include "talk/base/socket.h" + +namespace cricket { + +// Provides the ability to perform socket I/O asynchronously. +class AsyncSocket : public Socket, public sigslot::has_slots<> { +public: + virtual ~AsyncSocket() {} + + sigslot::signal1<AsyncSocket*> SignalReadEvent; // ready to read + sigslot::signal1<AsyncSocket*> SignalWriteEvent; // ready to write + sigslot::signal1<AsyncSocket*> SignalConnectEvent; // connected + sigslot::signal2<AsyncSocket*,int> SignalCloseEvent; // closed + // TODO: error +}; + +class AsyncSocketAdapter : public AsyncSocket { +public: + AsyncSocketAdapter(Socket * socket) : socket_(socket) { + } + AsyncSocketAdapter(AsyncSocket * socket) : socket_(socket) { + socket->SignalConnectEvent.connect(this, &AsyncSocketAdapter::OnConnectEvent); + socket->SignalReadEvent.connect(this, &AsyncSocketAdapter::OnReadEvent); + socket->SignalWriteEvent.connect(this, &AsyncSocketAdapter::OnWriteEvent); + socket->SignalCloseEvent.connect(this, &AsyncSocketAdapter::OnCloseEvent); + } + virtual ~AsyncSocketAdapter() { delete socket_; } + + virtual SocketAddress GetLocalAddress() const { return socket_->GetLocalAddress(); } + virtual SocketAddress GetRemoteAddress() const { return socket_->GetRemoteAddress(); } + + virtual int Bind(const SocketAddress& addr) { return socket_->Bind(addr); } + virtual int Connect(const SocketAddress& addr) { return socket_->Connect(addr); } + virtual int Send(const void *pv, size_t cb) { return socket_->Send(pv, cb); } + virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) { return socket_->SendTo(pv, cb, addr); } + virtual int Recv(void *pv, size_t cb) { return socket_->Recv(pv, cb); } + virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) { return socket_->RecvFrom(pv, cb, paddr); } + virtual int Listen(int backlog) { return socket_->Listen(backlog); } + virtual Socket *Accept(SocketAddress *paddr) { return socket_->Accept(paddr); } + virtual int Close() { return socket_->Close(); } + virtual int GetError() const { return socket_->GetError(); } + virtual void SetError(int error) { return socket_->SetError(error); } + + virtual ConnState GetState() const { return socket_->GetState(); } + + virtual int EstimateMTU(uint16* mtu) { return socket_->EstimateMTU(mtu); } + virtual int SetOption(Option opt, int value) { return socket_->SetOption(opt, value); } + +protected: + virtual void OnConnectEvent(AsyncSocket * socket) { SignalConnectEvent(this); } + virtual void OnReadEvent(AsyncSocket * socket) { SignalReadEvent(this); } + virtual void OnWriteEvent(AsyncSocket * socket) { SignalWriteEvent(this); } + virtual void OnCloseEvent(AsyncSocket * socket, int err) { SignalCloseEvent(this, err); } + + Socket * socket_; +}; + +} // namespace cricket + +#endif // __ASYNCSOCKET_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc new file mode 100644 index 00000000..6d4697a6 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.cc @@ -0,0 +1,197 @@ +/* + * 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" + +#if defined(_MSC_VER) && _MSC_VER < 1300 +namespace std { + using ::strerror; +} +#endif + +#ifdef POSIX +extern "C" { +#include <errno.h> +} +#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<int>(cb); + + PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(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<int>(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<size_t>(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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.h new file mode 100644 index 00000000..e93e5e7d --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asynctcpsocket.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef __ASYNCTCPSOCKET_H__ +#define __ASYNCTCPSOCKET_H__ + +#include "talk/base/asyncpacketsocket.h" + +namespace cricket { + +// Simulates UDP semantics over TCP. Send and Recv packet sizes +// are preserved, and drops packets silently on Send, rather than +// buffer them in user space. +class AsyncTCPSocket : public AsyncPacketSocket { +public: + AsyncTCPSocket(AsyncSocket* socket); + virtual ~AsyncTCPSocket(); + + virtual int Send(const void *pv, size_t cb); + virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr); + + sigslot::signal1<AsyncTCPSocket*> SignalConnect; + sigslot::signal2<AsyncTCPSocket*,int> SignalClose; + +protected: + int SendRaw(const void * pv, size_t cb); + virtual void ProcessInput(char * data, size_t& len); + +private: + char* inbuf_, * outbuf_; + size_t insize_, inpos_, outsize_, outpos_; + + int Flush(); + + // Called by the underlying socket + void OnConnectEvent(AsyncSocket* socket); + void OnReadEvent(AsyncSocket* socket); + void OnWriteEvent(AsyncSocket* socket); + void OnCloseEvent(AsyncSocket* socket, int error); +}; + +} // namespace cricket + +#endif // __ASYNCSTCPOCKET_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc new file mode 100644 index 00000000..5b8c2466 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.cc @@ -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 <cassert> +#include <cstring> +#include <iostream> + +#if defined(_MSC_VER) && _MSC_VER < 1300 +namespace std { + using ::strerror; +} +#endif + +#ifdef POSIX +extern "C" { +#include <errno.h> +} +#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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.h new file mode 100644 index 00000000..7fac7713 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/asyncudpsocket.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef __ASYNCUDPSOCKET_H__ +#define __ASYNCUDPSOCKET_H__ + +#include "talk/base/asyncpacketsocket.h" +#include "talk/base/socketfactory.h" + +namespace cricket { + +// Provides the ability to receive packets asynchronously. Sends are not +// buffered since it is acceptable to drop packets under high load. +class AsyncUDPSocket : public AsyncPacketSocket { +public: + AsyncUDPSocket(AsyncSocket* socket); + virtual ~AsyncUDPSocket(); + +private: + char* buf_; + size_t size_; + + // Called when the underlying socket is ready to be read from. + void OnReadEvent(AsyncSocket* socket); +}; + +// Creates a new socket for sending asynchronous UDP packets using an +// asynchronous socket from the given factory. +inline AsyncUDPSocket* CreateAsyncUDPSocket(SocketFactory* factory) { + return new AsyncUDPSocket(factory->CreateAsyncSocket(SOCK_DGRAM)); +} + +} // namespace cricket + +#endif // __ASYNCSUDPOCKET_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc new file mode 100644 index 00000000..e0ec1b90 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.cc @@ -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<char>(DecodeTable[static_cast<unsigned char>(data[i])]); + ++i; + c1 = static_cast<char>(DecodeTable[static_cast<unsigned char>(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<char>(DecodeTable[static_cast<unsigned char>(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<char>(DecodeTable[static_cast<unsigned char>(data[i])]); + c = ((c << 6) & 0xc0) | c1; + ret.append(1, c); + } + } + + return(ret); +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h new file mode 100644 index 00000000..4622b329 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/base64.h @@ -0,0 +1,29 @@ + +//********************************************************************* +//* C_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. +//********************************************************************* + +#ifndef Base64_H +#define Base64_H + +#include <string> +using std::string; // comment if your compiler doesn't use namespaces + +class Base64 +{ +public: + static string encode(const string & data); + static string decode(const string & data); + static string encodeFromArray(const char * data, size_t len); +private: + static const string Base64Table; + static const string::size_type DecodeTable[]; +}; + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h new file mode 100644 index 00000000..171bc9f9 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/basicdefs.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef __BASICDEFS_H__ +#define __BASICDEFS_H__ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + + +// Used in GUI when referring to the product name (& Version Resource Product Name) +#define PRODUCT_NAME "Google Talk" + +// Used in GUI when referring to the publisher of the product +#define COMPANY_NAME "Google" + +// Used in filenames, directories, registry key names, etc to refer to the product +#define DIRECTORY_NAME "Google Talk" + +// Used in URLs, registry values, etc, where we prefer not to use a space +#define PRODUCT_SIGNATURE "googletalk" + +// Used whenever we do HTTP +#define USERAGENT_STRING "Google Talk" + +#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0])))) + +#endif // __BASICDEFS_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h new file mode 100644 index 00000000..ea393c09 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/basictypes.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#ifndef __BASICTYPES_H__ +#define __BASICTYPES_H__ + +#ifdef COMPILER_MSVC +typedef __int64 int64; +#else +typedef long long int64; +#endif /* COMPILER_MSVC */ +typedef long int32; +typedef short int16; +typedef char int8; + +#ifdef COMPILER_MSVC +typedef unsigned __int64 uint64; +typedef __int64 int64; +#else +typedef unsigned long long uint64; +typedef long long int64; +#endif /* COMPILER_MSVC */ +typedef unsigned long uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +#ifdef WIN32 +typedef int socklen_t; +#endif + +namespace cricket { + template<class T> inline T _min(T a, T b) { return (a > b) ? b : a; } + template<class T> inline T _max(T a, T b) { return (a < b) ? b : a; } +} + +// A macro to disallow the evil copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_EVIL_CONSTRUCTORS(TypeName) + +#ifndef UNUSED +#define UNUSED(x) Unused(static_cast<const void *>(&x)) +#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)) +#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)) +#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)) +#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b)) +inline void Unused(const void *) { } +#endif // UNUSED + +#endif // __BASICTYPES_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc new file mode 100644 index 00000000..067f50ed --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.cc @@ -0,0 +1,165 @@ +/* + * 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 <algorithm> +#include <cassert> + +#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<char*>(&val), 1); +} + +bool ByteBuffer::ReadUInt16(uint16& val) { + uint16 v; + if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) { + return false; + } else { + val = NetworkToHost16(v); + return true; + } +} + +bool ByteBuffer::ReadUInt32(uint32& val) { + uint32 v; + if (!ReadBytes(reinterpret_cast<char*>(&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<const char*>(&val), 1); +} + +void ByteBuffer::WriteUInt16(uint16 val) { + uint16 v = HostToNetwork16(val); + WriteBytes(reinterpret_cast<const char*>(&v), 2); +} + +void ByteBuffer::WriteUInt32(uint32 val) { + uint32 v = HostToNetwork32(val); + WriteBytes(reinterpret_cast<const char*>(&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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.h new file mode 100644 index 00000000..b0a52344 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/bytebuffer.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#ifndef __BYTEBUFFER_H__ +#define __BYTEBUFFER_H__ + +#include "talk/base/basictypes.h" +#include <string> + +namespace cricket { + +class ByteBuffer { +public: + ByteBuffer(); + ByteBuffer(const char* bytes, size_t len); + ByteBuffer(const char* bytes); // uses strlen + ~ByteBuffer(); + + const char* Data() const { return bytes_ + start_; } + size_t Length() { return end_ - start_; } + size_t Capacity() { return size_ - start_; } + + bool ReadUInt8(uint8& val); + bool ReadUInt16(uint16& val); + bool ReadUInt32(uint32& val); + bool ReadString(std::string& val, size_t len); // append to val + bool ReadBytes(char* val, size_t len); + + void WriteUInt8(uint8 val); + void WriteUInt16(uint16 val); + void WriteUInt32(uint32 val); + void WriteString(const std::string& val); + void WriteBytes(const char* val, size_t len); + + void Resize(size_t size); + void Shift(size_t size); + +private: + char* bytes_; + size_t size_; + size_t start_; + size_t end_; +}; + +} // namespace cricket + +#endif // __BYTEBUFFER_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h new file mode 100644 index 00000000..4b70f47e --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/byteorder.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef __BYTEORDER_H__ +#define __BYTEORDER_H__ + +#include "talk/base/basictypes.h" + +#ifdef POSIX +extern "C" { +#include <arpa/inet.h> +} +#endif + +#ifdef WIN32 +#include <winsock2.h> +#endif + +namespace cricket { + +inline uint16 HostToNetwork16(uint16 n) { + return htons(n); +} + +inline uint32 HostToNetwork32(uint32 n) { + return htonl(n); +} + +inline uint16 NetworkToHost16(uint16 n) { + return ntohs(n); +} + +inline uint32 NetworkToHost32(uint32 n) { + return ntohl(n); +} + +} // namespace cricket + +#endif // __BYTEORDER_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h new file mode 100644 index 00000000..b21be2f1 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/common.h @@ -0,0 +1,231 @@ +/* + * 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. + */ + +#ifndef _common_h_ +#define _common_h_ + +#if defined(_MSC_VER) +// warning C4355: 'this' : used in base member initializer list +#pragma warning(disable:4355) +#endif + +#if defined(ENABLE_DEBUG_MALLOC) && !defined(ENABLE_DEBUG) +#define ENABLE_DEBUG 1 +#endif + +////////////////////////////////////////////////////////////////////// +// General Utilities +////////////////////////////////////////////////////////////////////// + +#ifndef UNUSED +#define UNUSED(x) Unused(static_cast<const void *>(&x)) +#define UNUSED2(x,y) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)) +#define UNUSED3(x,y,z) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)) +#define UNUSED4(x,y,z,a) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)) +#define UNUSED5(x,y,z,a,b) Unused(static_cast<const void *>(&x)); Unused(static_cast<const void *>(&y)); Unused(static_cast<const void *>(&z)); Unused(static_cast<const void *>(&a)); Unused(static_cast<const void *>(&b)) +inline void Unused(const void *) { } +#endif // UNUSED + +#define ARRAY_SIZE(x) (static_cast<int>((sizeof(x)/sizeof(x[0])))) + +///////////////////////////////////////////////////////////////////////////// +// std:min/std:max on msvc +///////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0 + +#undef min +#undef max + +namespace std { + + + /** + * @brief This does what you think it does. + * @param a A thing of arbitrary type. + * @param b Another thing of arbitrary type. + * @return The lesser of the parameters. + * + * This is the simple classic generic implementation. It will work on + * temporary expressions, since they are only evaluated once, unlike a + * preprocessor macro. + */ + template<typename _Tp> + inline const _Tp& + min(const _Tp& __a, const _Tp& __b) + { + //return __b < __a ? __b : __a; + if (__b < __a) return __b; return __a; + } + + /** + * @brief This does what you think it does. + * @param a A thing of arbitrary type. + * @param b Another thing of arbitrary type. + * @return The greater of the parameters. + * + * This is the simple classic generic implementation. It will work on + * temporary expressions, since they are only evaluated once, unlike a + * preprocessor macro. + */ + template<typename _Tp> + inline const _Tp& + max(const _Tp& __a, const _Tp& __b) + { + //return __a < __b ? __b : __a; + if (__a < __b) return __b; return __a; + } + + /** + * @brief This does what you think it does. + * @param a A thing of arbitrary type. + * @param b Another thing of arbitrary type. + * @param comp A @link s20_3_3_comparisons comparison functor@endlink. + * @return The lesser of the parameters. + * + * This will work on temporary expressions, since they are only evaluated + * once, unlike a preprocessor macro. + */ + template<typename _Tp, typename _Compare> + inline const _Tp& + min(const _Tp& __a, const _Tp& __b, _Compare __comp) + { + //return __comp(__b, __a) ? __b : __a; + if (__comp(__b, __a)) return __b; return __a; + } + + /** + * @brief This does what you think it does. + * @param a A thing of arbitrary type. + * @param b Another thing of arbitrary type. + * @param comp A @link s20_3_3_comparisons comparison functor@endlink. + * @return The greater of the parameters. + * + * This will work on temporary expressions, since they are only evaluated + * once, unlike a preprocessor macro. + */ + template<typename _Tp, typename _Compare> + inline const _Tp& + max(const _Tp& __a, const _Tp& __b, _Compare __comp) + { + //return __comp(__a, __b) ? __b : __a; + if (__comp(__a, __b)) return __b; return __a; + } + +} + +#endif // _MSC_VER <= 1200 + + +///////////////////////////////////////////////////////////////////////////// +// Assertions +///////////////////////////////////////////////////////////////////////////// + +#ifdef ENABLE_DEBUG + +namespace buzz { + +// Break causes the debugger to stop executing, or the program to abort +void Break(); + +// LogAssert writes information about an assertion to the log +void LogAssert(const char * function, const char * file, int line, const char * expression); + +inline void Assert(bool result, const char * function, const char * file, int line, const char * expression) { + if (!result) { + LogAssert(function, file, line, expression); + Break(); + } +} + +}; // namespace buzz + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define __FUNCTION__ "" +#endif + +#define ASSERT(x) buzz::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x) +#define VERIFY(x) buzz::Assert((x),__FUNCTION__,__FILE__,__LINE__,#x) + +#else // !ENABLE_DEBUG + +#define ASSERT(x) (void)0 +#define VERIFY(x) (void)(x) + +#endif // !ENABLE_DEBUG + +#define COMPILE_TIME_ASSERT(expr) char CTA_UNIQUE_NAME[expr] +#define CTA_UNIQUE_NAME MAKE_NAME(__LINE__) +#define CTA_MAKE_NAME(line) MAKE_NAME2(line) +#define CTA_MAKE_NAME2(line) constraint_ ## line + +////////////////////////////////////////////////////////////////////// +// Memory leak tracking +////////////////////////////////////////////////////////////////////// + +#include <sys/types.h> + +#ifdef ENABLE_DEBUG_MALLOC + +namespace buzz { + +void * DebugAllocate(size_t size, const char * fname = 0, int line = 0); +void DebugDeallocate(void * ptr, const char * fname = 0, int line = 0); +bool LeakCheck(); +bool LeakCheckU(); +void LeakMarkBaseline(); +void LeakClearBaseline(); + +}; // namespace buzz + +inline void * operator new(size_t size, const char * fname, int line) { return buzz::DebugAllocate(size, fname, line); } +inline void operator delete(void * ptr, const char * fname, int line) { buzz::DebugDeallocate(ptr, fname, line); } + +#if !(defined(TRACK_ARRAY_ALLOC_PROBLEM) && \ + defined(_MSC_VER) && _MSC_VER <= 1200) // 1200 == VC++ 6.0 + +inline void * operator new[](size_t size, const char * fname, int line) { return buzz::DebugAllocate(size, fname, line); } +inline void operator delete[](void * ptr, const char * fname, int line) { buzz::DebugDeallocate(ptr, fname, line); } + +#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 + +#define TRACK_NEW new(__FILE__,__LINE__) +#define TRACK_DEL delete(__FILE__,__LINE__) + +#else // !ENABLE_DEBUG_MALLOC + +#define TRACK_NEW new +#define TRACK_DEL delete + +#endif // !ENABLE_DEBUG_MALLOC + +////////////////////////////////////////////////////////////////////// + +#endif // _common_h_ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h new file mode 100644 index 00000000..b75ad5c7 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/criticalsection.h @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#ifndef _criticalsection_h_ +#define _criticalsection_h_ + +#ifdef WIN32 +#include "talk/base/win32.h" +#endif + +#ifdef POSIX +#include <pthread.h> +#endif + +#ifdef _DEBUG +#define CS_TRACK_OWNER 1 +#endif // _DEBUG + +#if CS_TRACK_OWNER +#define TRACK_OWNER(x) x +#else // !CS_TRACK_OWNER +#define TRACK_OWNER(x) +#endif // !CS_TRACK_OWNER + +namespace cricket { + +#ifdef WIN32 +class CriticalSection { +public: + CriticalSection() { + InitializeCriticalSection(&crit_); + // Windows docs say 0 is not a valid thread id + TRACK_OWNER(thread_ = 0); + } + ~CriticalSection() { + DeleteCriticalSection(&crit_); + } + void Enter() { + EnterCriticalSection(&crit_); + TRACK_OWNER(thread_ = GetCurrentThreadId()); + } + void Leave() { + TRACK_OWNER(thread_ = 0); + LeaveCriticalSection(&crit_); + } + +#if CS_TRACK_OWNER + bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); } +#endif // CS_TRACK_OWNER + +private: + CRITICAL_SECTION crit_; + TRACK_OWNER(DWORD thread_); // The section's owning thread id +}; +#endif // WIN32 + +#ifdef POSIX +class CriticalSection { +public: + CriticalSection() { + pthread_mutexattr_t mutex_attribute; + pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mutex_, &mutex_attribute); + } + ~CriticalSection() { + pthread_mutex_destroy(&mutex_); + } + void Enter() { + pthread_mutex_lock(&mutex_); + } + void Leave() { + pthread_mutex_unlock(&mutex_); + } +private: + pthread_mutex_t mutex_; +}; +#endif // POSIX + +// CritScope, for serializing exection through a scope + +class CritScope { +public: + CritScope(CriticalSection *pcrit) { + pcrit_ = pcrit; + pcrit_->Enter(); + } + ~CritScope() { + pcrit_->Leave(); + } +private: + CriticalSection *pcrit_; +}; + +} // namespace cricket + +#endif // _criticalsection_h_ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc new file mode 100644 index 00000000..7b7490d9 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.cc @@ -0,0 +1,99 @@ +/* + * 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 <string> +#include <iostream> +#include <cassert> +#include <errno.h> + +#if defined(_MSC_VER) && _MSC_VER < 1300 +namespace std { + using ::strerror; + using ::exit; +} +#endif + +#ifdef POSIX +extern "C" { +#include <sys/utsname.h> +} +#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<Network*>* networks = new std::vector<Network*>; + 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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.h new file mode 100644 index 00000000..16f31a78 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/host.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef __HOST_H__ +#define __HOST_H__ + +#include "talk/base/network.h" +#include <string> +#include <vector> + +namespace cricket { + +// Provides information about a host in the network. +class Host { +public: + Host(const std::string& name, std::vector<Network*>* networks) + : name_(name), networks_(networks) { } + + const std::string& name() const { return name_; } + const std::vector<Network*>& networks() const { return *networks_; } + +private: + std::string name_; + std::vector<Network*>* networks_; +}; + +// Returns a reference to the description of the local host. +const Host& LocalHost(); + +// Returns the name of the local host. +std::string GetHostName(); + +} // namespace cricket + +#endif // __HOST_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc new file mode 100644 index 00000000..5befe9fd --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.cc @@ -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 <iostream> +#include <cstdlib> +#include <cstring> + +namespace cricket { + +#ifdef POSIX +#include <sys/time.h> +uint32 Time() { + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} +#endif + +#ifdef WIN32 +#include <windows.h> +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<long>(later - earlier); + } else { + return static_cast<long>(later + (LAST - earlier) + 1); + } + } else { + if (later <= earlier) { + return -static_cast<long>(earlier - later); + } else { + return -static_cast<long>(earlier + (LAST - later) + 1); + } + } +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h new file mode 100644 index 00000000..d7dff0fb --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/jtime.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#ifndef __JTIME_H__ +#define __JTIME_H__ + +#include "talk/base/basictypes.h" + +namespace cricket { + +// Returns the current time in milliseconds. +uint32 Time(); + +// TODO: Delete this old version. +#define GetMillisecondCount Time + +// Comparisons between time values, which can wrap around. +bool TimeIsBetween(uint32 later, uint32 middle, uint32 earlier); +int32 TimeDiff(uint32 later, uint32 earlier); + +} // namespace cricket + +#endif // __TIME_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h new file mode 100644 index 00000000..94b62ad3 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/linked_ptr.h @@ -0,0 +1,138 @@ +/* + * 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. + */ + +/* + * linked_ptr - simple reference linked pointer + * (like reference counting, just using a linked list of the references + * instead of their count.) + * + * The implementation stores three pointers for every linked_ptr, but + * does not allocate anything on the free store. + */ + +#ifndef _LINKED_PTR_H_ +#define _LINKED_PTR_H_ + +/* For ANSI-challenged compilers, you may want to #define + * NO_MEMBER_TEMPLATES, explicit or mutable */ +#define NO_MEMBER_TEMPLATES + +template <class X> class linked_ptr +{ +public: + +#ifndef NO_MEMBER_TEMPLATES +# define TEMPLATE_FUNCTION template <class Y> + TEMPLATE_FUNCTION friend class linked_ptr<Y>; +#else +# define TEMPLATE_FUNCTION + typedef X Y; +#endif + + typedef X element_type; + + explicit linked_ptr(X* p = 0) throw() + : itsPtr(p) {itsPrev = itsNext = this;} + ~linked_ptr() + {release();} + linked_ptr(const linked_ptr& r) throw() + {acquire(r);} + linked_ptr& operator=(const linked_ptr& r) + { + if (this != &r) { + release(); + acquire(r); + } + return *this; + } + +#ifndef NO_MEMBER_TEMPLATES + template <class Y> friend class linked_ptr<Y>; + template <class Y> linked_ptr(const linked_ptr<Y>& r) throw() + {acquire(r);} + template <class Y> linked_ptr& operator=(const linked_ptr<Y>& r) + { + if (this != &r) { + release(); + acquire(r); + } + return *this; + } +#endif // NO_MEMBER_TEMPLATES + + X& operator*() const throw() {return *itsPtr;} + X* operator->() const throw() {return itsPtr;} + X* get() const throw() {return itsPtr;} + bool unique() const throw() {return itsPrev ? itsPrev==this : true;} + +private: + X* itsPtr; + mutable const linked_ptr* itsPrev; + mutable const linked_ptr* itsNext; + + void acquire(const linked_ptr& r) throw() + { // insert this to the list + itsPtr = r.itsPtr; + itsNext = r.itsNext; + itsNext->itsPrev = this; + itsPrev = &r; +#ifndef mutable + r.itsNext = this; +#else // for ANSI-challenged compilers + (const_cast<linked_ptr<X>*>(&r))->itsNext = this; +#endif + } + +#ifndef NO_MEMBER_TEMPLATES + template <class Y> void acquire(const linked_ptr<Y>& r) throw() + { // insert this to the list + itsPtr = r.itsPtr; + itsNext = r.itsNext; + itsNext->itsPrev = this; + itsPrev = &r; +#ifndef mutable + r.itsNext = this; +#else // for ANSI-challenged compilers + (const_cast<linked_ptr<X>*>(&r))->itsNext = this; +#endif + } +#endif // NO_MEMBER_TEMPLATES + + void release() + { // erase this from the list, delete if unique + if (unique()) delete itsPtr; + else { + itsPrev->itsNext = itsNext; + itsNext->itsPrev = itsPrev; + itsPrev = itsNext = 0; + } + itsPtr = 0; + } +}; + +#endif // LINKED_PTR_H + diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h new file mode 100644 index 00000000..500386ed --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/logging.h @@ -0,0 +1,222 @@ +/* + * 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. + */ + +// LOG(...) an ostream target that can be used to send formatted +// output to a variety of logging targets, such as debugger console, stderr, +// file, or any StreamInterface. +// The severity level passed as the first argument to the the LOGging +// functions is used as a filter, to limit the verbosity of the logging. +// Static members of LogMessage documented below are used to control the +// verbosity and target of the output. +// There are several variations on the LOG macro which facilitate logging +// of common error conditions, detailed below. + +#ifndef TALK_BASE_LOGGING_H__ +#define TALK_BASE_LOGGING_H__ + +#include <sstream> +#include "talk/base/basictypes.h" +class StreamInterface; + +/////////////////////////////////////////////////////////////////////////////// +// ConstantLabel can be used to easily generate string names from constant +// values. This can be useful for logging descriptive names of error messages. +// Usage: +// const ConstantLabel LIBRARY_ERRORS[] = { +// KLABEL(SOME_ERROR), +// KLABEL(SOME_OTHER_ERROR), +// ... +// LASTLABEL +// } +// +// int err = LibraryFunc(); +// LOG(LS_ERROR) << "LibraryFunc returned: " +// << ErrorName(err, LIBRARY_ERRORS); + +struct ConstantLabel { int value; const char * label; }; +#define KLABEL(x) { x, #x } +#define TLABEL(x,y) { x, y } +#define LASTLABEL { 0, 0 } + +const char * FindLabel(int value, const ConstantLabel entries[]); +std::string ErrorName(int err, const ConstantLabel * err_table); + +////////////////////////////////////////////////////////////////////// + +// Note that the non-standard LoggingSeverity aliases exist because they are +// still in broad use. The meanings of the levels are: +// LS_SENSITIVE: Information which should only be logged with the consent +// of the user, due to privacy concerns. +// LS_VERBOSE: This level is for data which we do not want to appear in the +// normal debug log, but should appear in diagnostic logs. +// LS_INFO: Chatty level used in debugging for all sorts of things, the default +// in debug builds. +// LS_WARNING: Something that may warrant investigation. +// LS_ERROR: Something that should not have occurred. +enum LoggingSeverity { LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, + INFO = LS_INFO, + WARNING = LS_WARNING, + LERROR = LS_ERROR }; + +// LogErrorContext assists in interpreting the meaning of an error value. +// ERRCTX_ERRNO: the value was read from global 'errno' +// ERRCTX_HRESULT: the value is a Windows HRESULT +enum LogErrorContext { ERRCTX_NONE, ERRCTX_ERRNO, ERRCTX_HRESULT }; + +// If LOGGING is not explicitly defined, default to enabled in debug mode +#if !defined(LOGGING) +#if defined(_DEBUG) && !defined(NDEBUG) +#define LOGGING 1 +#else +#define LOGGING 0 +#endif +#endif // !defined(LOGGING) + +#if LOGGING + +#define LOG(sev) \ + if (LogMessage::Loggable(sev)) \ + LogMessage(__FILE__, __LINE__, sev).stream() + +// PLOG and LOG_ERR attempt to provide a string description of an errno derived +// error. LOG_ERR reads errno directly, so care must be taken to call it before +// errno is reset. +#define PLOG(sev, err) \ + if (LogMessage::Loggable(sev)) \ + LogMessage(__FILE__, __LINE__, sev, ERRCTX_ERRNO, err).stream() +#define LOG_ERR(sev) \ + if (LogMessage::Loggable(sev)) \ + LogMessage(__FILE__, __LINE__, sev, ERRCTX_ERRNO, errno).stream() + +// LOG_GLE(M) attempt to provide a string description of the HRESULT returned +// by GetLastError. The second variant allows searching of a dll's string +// table for the error description. +#ifdef WIN32 +#define LOG_GLE(sev) \ + if (LogMessage::Loggable(sev)) \ + LogMessage(__FILE__, __LINE__, sev, ERRCTX_HRESULT, GetLastError()).stream() +#define LOG_GLEM(sev, mod) \ + if (LogMessage::Loggable(sev)) \ + LogMessage(__FILE__, __LINE__, sev, ERRCTX_HRESULT, GetLastError(), mod) \ + .stream() +#endif // WIN32 + +// TODO: Add an "assert" wrapper that logs in the same manner. + +#else // !LOGGING + +// Hopefully, the compiler will optimize away some of this code. +// Note: syntax of "1 ? (void)0 : LogMessage" was causing errors in g++, +// converted to "while (false)" +#define LOG(sev) \ + while (false) LogMessage(NULL, 0, sev).stream() +#define PLOG(sev, err) \ + while (false) LogMessage(NULL, 0, sev, ERRCTX_ERRNO, 0).stream() +#define LOG_ERR(sev) \ + while (false) LogMessage(NULL, 0, sev, ERRCTX_ERRNO, 0).stream() +#ifdef WIN32 +#define LOG_GLE(sev) \ + while (false) LogMessage(NULL, 0, sev, ERRCTX_HRESULT, 0).stream() +#define LOG_GLEM(sev, mod) \ + while (false) LogMessage(NULL, 0, sev, ERRCTX_HRESULT, 0).stream() +#endif // WIN32 + +#endif // !LOGGING + +class LogMessage { + public: + LogMessage(const char* file, int line, LoggingSeverity sev, + LogErrorContext err_ctx = ERRCTX_NONE, int err = 0, + const char* module = NULL); + ~LogMessage(); + + static inline bool Loggable(LoggingSeverity sev) { return (sev >= min_sev_); } + std::ostream& stream() { return print_stream_; } + + enum { NO_LOGGING = LS_ERROR + 1 }; + + // These are attributes which apply to all logging channels + // LogContext: Display the file and line number of the message + static void LogContext(int min_sev); + // LogThreads: Display the thread identifier of the current thread + static void LogThreads(bool on = true); + // LogTimestamps: Display the elapsed time of the program + static void LogTimestamps(bool on = true); + + // Timestamps begin with program execution, but can be reset with this + // function for measuring the duration of an activity, or to synchronize + // timestamps between multiple instances. + static void ResetTimestamps(); + + // These are the available logging channels + // Debug: Debug console on Windows, otherwise stderr + static void LogToDebug(int min_sev); + static int GetLogToDebug() { return dbg_sev_; } + // Stream: Any non-blocking stream interface. LogMessage takes ownership of + // the stream. + static void LogToStream(StreamInterface* stream, int min_sev); + static int GetLogToStream() { return stream_sev_; } + + // Testing against MinLogSeverity allows code to avoid potentially expensive + // logging operations by pre-checking the logging level. + static int GetMinLogSeverity() { return min_sev_; } + + private: + // These assist in formatting some parts of the debug output. + static const char* Describe(LoggingSeverity sev); + static const char* DescribeFile(const char* file); + + // The ostream that buffers the formatted message before output + std::ostringstream print_stream_; + + // The severity level of this message + LoggingSeverity severity_; + + // String data generated in the constructor, that should be appended to + // the message before output. + std::string extra_; + + // dbg_sev_ and stream_sev_ are the thresholds for those output targets + // min_sev_ is the minimum (most verbose) of those levels, and is used + // as a short-circuit in the logging macros to identify messages that won't + // be logged. + // ctx_sev_ is the minimum level at which file context is displayed + static int min_sev_, dbg_sev_, stream_sev_, ctx_sev_; + + // The output stream, if any + static StreamInterface * stream_; + + // Flags for formatting options + static bool thread_, timestamp_; + + // The timestamp at which logging started. + static uint32 start_; + + DISALLOW_EVIL_CONSTRUCTORS(LogMessage); +}; + +#endif // TALK_BASE_LOGGING_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h new file mode 100644 index 00000000..c2e22cc5 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/md5.h @@ -0,0 +1,45 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + */ + +#ifndef MD5_H +#define MD5_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long unsigned int uint32; +typedef struct MD5Context MD5_CTX; + +#define md5byte unsigned char + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + uint32 in[16]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(uint32 buf[4], uint32 const in[16]); + +#ifdef __cplusplus +}; +#endif + +#endif /* !MD5_H */ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c b/kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c new file mode 100644 index 00000000..eb2c034d --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/md5c.c @@ -0,0 +1,256 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ +#include <string.h> /* for memcpy() */ +#include "md5.h" + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(unsigned char *buf, unsigned longs); + +#ifndef ASM_MD5 +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32 t; + do { + t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | + ((unsigned)buf[1]<<8 | buf[0]); + *(uint32 *)buf = t; + buf += 4; + } while (--longs); +} +#endif +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if ( t ) { + unsigned char *p = (unsigned char *)ctx->in + t; + + t = 64-t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = (unsigned char*)(ctx->in) + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count-8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; + ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *)ctx->in); + byteReverse((unsigned char *)ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD5Transform(uint32 buf[4], uint32 const in[16]) +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc new file mode 100644 index 00000000..f10489f7 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.cc @@ -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 <sys/time.h> +} +#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<MessageQueue *>::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<MessageQueue *>::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<DelayedMessage> 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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h new file mode 100644 index 00000000..2a9cbed6 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/messagequeue.h @@ -0,0 +1,164 @@ +/* + * 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. + */ + +#ifndef __MESSAGEQUEUE_H__ +#define __MESSAGEQUEUE_H__ + +#include "talk/base/basictypes.h" +#include "talk/base/criticalsection.h" +#include "talk/base/socketserver.h" +#include "talk/base/jtime.h" +#include <vector> +#include <queue> +#include <algorithm> + +namespace cricket { + +struct Message; +class MessageQueue; +class MessageHandler; + +// MessageQueueManager does cleanup of of message queues + +class MessageQueueManager { +public: + static MessageQueueManager* Instance(); + + void Add(MessageQueue *message_queue); + void Remove(MessageQueue *message_queue); + void Clear(MessageHandler *handler); + +private: + MessageQueueManager(); + ~MessageQueueManager(); + + static MessageQueueManager* instance_; + std::vector<MessageQueue *> message_queues_; + CriticalSection crit_; +}; + +// Messages get dispatched to a MessageHandler + +class MessageHandler { +public: + virtual ~MessageHandler() { + MessageQueueManager::Instance()->Clear(this); + } + + virtual void OnMessage(Message *pmsg) = 0; +}; + +// Derive from this for specialized data +// App manages lifetime, except when messages are purged + +class MessageData { +public: + MessageData() {} + virtual ~MessageData() {} +}; + +template <class arg1_type> +class TypedMessageData : public MessageData { +public: + TypedMessageData(arg1_type data) { + data_ = data; + } + arg1_type data() { + return data_; + } +private: + arg1_type data_; +}; + +// No destructor + +struct Message { + Message() { + memset(this, 0, sizeof(*this)); + } + MessageHandler *phandler; + uint32 message_id; + MessageData *pdata; +}; + +// DelayedMessage goes into a priority queue, sorted by trigger time + +class DelayedMessage { +public: + DelayedMessage(int cmsDelay, Message *pmsg) { + cmsDelay_ = cmsDelay; + msTrigger_ = GetMillisecondCount() + cmsDelay; + msg_ = *pmsg; + } + + bool operator< (const DelayedMessage& dmsg) const { + return dmsg.msTrigger_ < msTrigger_; + } + + int cmsDelay_; // for debugging + uint32 msTrigger_; + Message msg_; +}; + +class MessageQueue { +public: + MessageQueue(SocketServer* ss = 0); + virtual ~MessageQueue(); + + SocketServer* socketserver() { return ss_; } + void set_socketserver(SocketServer* ss); + + // Once the queue is stopped, all calls to Get/Peek will return false. + virtual void Stop(); + virtual bool IsStopping(); + virtual void Restart(); + + virtual bool Get(Message *pmsg, int cmsWait = -1); + virtual bool Peek(Message *pmsg, int cmsWait = 0); + virtual void Post(MessageHandler *phandler, uint32 id = 0, + MessageData *pdata = NULL); + virtual void PostDelayed(int cmsDelay, MessageHandler *phandler, + uint32 id = 0, MessageData *pdata = NULL); + virtual void Clear(MessageHandler *phandler, uint32 id = (uint32)-1); + virtual void Dispatch(Message *pmsg); + virtual void ReceiveSends(); + virtual int GetDelay(); + +protected: + SocketServer* ss_; + bool new_ss; + bool fStop_; + bool fPeekKeep_; + Message msgPeek_; + std::queue<Message> msgq_; + std::priority_queue<DelayedMessage> dmsgq_; + CriticalSection crit_; +}; + +} // namespace cricket + +#endif // __MESSAGEQUEUE_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc new file mode 100644 index 00000000..21b3a08f --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.cc @@ -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 <algorithm> +#include <cassert> +#include <cfloat> +#include <cmath> +#include <sstream> + +#ifdef POSIX +extern "C" { +#include <sys/utsname.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <unistd.h> +#include <errno.h> +} +#endif // POSIX + +#ifdef WIN32 +#include <Iphlpapi.h> +#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<std::string,std::string> 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<char>(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 <typename T> +std::string ToString(T val) { + std::ostringstream ost; + ost << val; + return ost.str(); +} + +template <typename T> +T FromString(std::string str) { + std::istringstream ist(str); + T val; + ist >> val; + return val; +} + +} + +namespace cricket { + +#ifdef POSIX +void NetworkManager::CreateNetworks(std::vector<Network*>& 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<int>(64 * sizeof(struct ifreq))); + + struct ifreq* ptr = reinterpret_cast<struct ifreq*>(ifc.ifc_buf); + struct ifreq* end = + reinterpret_cast<struct ifreq*>(ifc.ifc_buf + ifc.ifc_len); + + while (ptr < end) { + struct sockaddr_in* inaddr = + reinterpret_cast<struct sockaddr_in*>(&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<struct ifreq*>( + reinterpret_cast<char*>(ptr) + _SIZEOF_ADDR_IFREQ(*ptr)); +#else + ptr++; +#endif + } + + delete [] ifc.ifc_buf; + close(fd); +} +#endif + +#ifdef WIN32 +void NetworkManager::CreateNetworks(std::vector<Network*>& 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<Network*>& result) { + std::vector<Network*> 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<uint32>(last_data_time_); + map["un"] = ToString<double>(uniform_numerator_); + map["ud"] = ToString<double>(uniform_denominator_); + map["en"] = ToString<double>(exponential_numerator_); + map["ed"] = ToString<double>(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<uint32>(map["lt"]); + uniform_numerator_ = FromString<double>(map["un"]); + uniform_denominator_ = FromString<double>(map["ud"]); + exponential_numerator_ = FromString<double>(map["en"]); + exponential_denominator_ = FromString<double>(map["ed"]); +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/network.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.h new file mode 100644 index 00000000..2cc9128a --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/network.h @@ -0,0 +1,136 @@ +/* + * 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. + */ + +#ifndef __NETWORK_H__ +#define __NETWORK_H__ + +#include "talk/base/basictypes.h" + +#include <deque> +#include <map> +#include <string> +#include <vector> + +namespace cricket { + +class Network; +class NetworkSession; + +// Keeps track of the available network interfaces over time so that quality +// information can be aggregated and recorded. +class NetworkManager { +public: + + // Updates and returns the current list of networks available on this machine. + // This version will make sure that repeated calls return the same object for + // a given network, so that quality is tracked appropriately. + void GetNetworks(std::vector<Network*>& networks); + + // Reads and writes the state of the quality database in a string format. + std::string GetState(); + void SetState(std::string str); + + // Creates a network object for each network available on the machine. + static void CreateNetworks(std::vector<Network*>& networks); + +private: + typedef std::map<std::string,Network*> NetworkMap; + + NetworkMap networks_; +}; + +// Represents a Unix-type network interface, with a name and single address. +// It also includes the ability to track and estimate quality. +class Network { +public: + Network(const std::string& name, uint32 ip); + + // Returns the OS name of this network. This is considered the primary key + // that identifies each network. + const std::string& name() const { return name_; } + + // Identifies the current IP address used by this network. + uint32 ip() const { return ip_; } + void set_ip(uint32 ip) { ip_ = ip; } + + // Updates the list of sessions that are ongoing. + void StartSession(NetworkSession* session); + void StopSession(NetworkSession* session); + + // Re-computes the estimate of near-future quality based on the information + // as of this exact moment. + void EstimateQuality(); + + // Returns the current estimate of the near-future quality of connections + // that use this local interface. + double quality() { return quality_; } + +private: + typedef std::vector<NetworkSession*> SessionList; + + std::string name_; + uint32 ip_; + SessionList sessions_; + double uniform_numerator_; + double uniform_denominator_; + double exponential_numerator_; + double exponential_denominator_; + uint32 last_data_time_; + double quality_; + + // Updates the statistics maintained to include the given estimate. + void AddDataPoint(uint32 time, double quality); + + // Converts the internal state to and from a string. This is used to record + // quality information into a permanent store. + void SetState(std::string str); + std::string GetState(); + + friend class NetworkManager; +}; + +// Represents a session that is in progress using a particular network and can +// provide data about the quality of the network at any given moment. +class NetworkSession { +public: + // Determines whether this session has an estimate at this moment. We will + // only call GetCurrentQuality when this returns true. + virtual bool HasQuality() = 0; + + // Returns an estimate of the quality at this exact moment. The result should + // be a MOS (mean opinion score) value. + virtual float GetCurrentQuality() = 0; + +}; + +const double QUALITY_BAD = 3.0; +const double QUALITY_FAIR = 3.35; +const double QUALITY_GOOD = 3.7; + +} // namespace cricket + +#endif // __NETWORK_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc new file mode 100644 index 00000000..91d2daad --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.cc @@ -0,0 +1,1117 @@ +/* + * 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 <cassert> + +#ifdef POSIX +extern "C" { +#include <errno.h> +#include <fcntl.h> +#include <sys/time.h> +#include <unistd.h> +} +#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 <winsock2.h> +#include <ws2tcpip.h> +#define _WINSOCKAPI_ +#include <windows.h> +#undef SetPort + +#include <algorithm> +#include <iostream> + +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<int>(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<char*>(&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<const char *>(pv), (int)cb, 0); + UpdateLastError(); + //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Send(" << cb << ") Ret: " << sent << " Error: " << error_; + ASSERT(sent <= static_cast<int>(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<int>(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<int>(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<const struct sockaddr_in*>(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<int>(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<WSAEVENT> events; + std::vector<Dispatcher *> 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<DWORD>(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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.h new file mode 100644 index 00000000..305b64d9 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/physicalsocketserver.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#ifndef __PHYSICALSOCKETSERVER_H__ +#define __PHYSICALSOCKETSERVER_H__ + +#include "talk/base/asyncfile.h" +#include "talk/base/socketserver.h" +#include "talk/base/criticalsection.h" +#include <vector> + +#ifdef POSIX +typedef int SOCKET; +#endif // POSIX + +namespace cricket { + +class Dispatcher; +class Signaler; + +// A socket server that provides the real sockets of the underlying OS. +class PhysicalSocketServer : public SocketServer { +public: + PhysicalSocketServer(); + virtual ~PhysicalSocketServer(); + + // SocketFactory: + virtual Socket* CreateSocket(int type); + virtual AsyncSocket* CreateAsyncSocket(int type); + + // Internal Factory for Accept + AsyncSocket* WrapSocket(SOCKET s); + + // SocketServer: + virtual bool Wait(int cms, bool process_io); + virtual void WakeUp(); + + void Add(Dispatcher* dispatcher); + void Remove(Dispatcher* dispatcher); + +#ifdef POSIX + AsyncFile* CreateFile(int fd); +#endif + +private: + std::vector<Dispatcher*> dispatchers_; + Signaler* signal_wakeup_; + CriticalSection crit_; + bool fWait_; + uint32 last_tick_tracked_; + int last_tick_dispatch_count_; +}; + +} // namespace cricket + +#endif // __PHYSICALSOCKETSERVER_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h new file mode 100644 index 00000000..1bd817b9 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/proxyinfo.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef __PROXYINFO_H__ +#define __PROXYINFO_H__ + +#include <string> +#include "talk/base/socketaddress.h" +// TODO: move xmpppassword into base +#include "talk/xmpp/xmpppassword.h" + +namespace cricket { + +enum ProxyType { PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN }; +const char * ProxyToString(ProxyType proxy); + +struct ProxyInfo { + ProxyType type; + SocketAddress address; + std::string username; + buzz::XmppPassword password; + + ProxyInfo() : type(PROXY_NONE) { } +}; + +} // namespace cricket + +#endif // __PROXYINFO_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h new file mode 100644 index 00000000..0470ff83 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/scoped_ptr.h @@ -0,0 +1,259 @@ +#ifndef SCOPED_PTR_H +#define SCOPED_PTR_H + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. +// + +// scoped_ptr mimics a built-in pointer except that it guarantees deletion +// of the object pointed to, either on destruction of the scoped_ptr or via +// an explicit reset(). scoped_ptr is a simple solution for simple needs; +// use shared_ptr or std::auto_ptr if your needs are more complex. + +// scoped_ptr_malloc added in by Google. When one of +// these goes out of scope, instead of doing a delete or delete[], it +// calls free(). scoped_ptr_malloc<char> is likely to see much more +// use than any other specializations. + +// release() added in by Google. Use this to conditionally +// transfer ownership of a heap-allocated object to the caller, usually on +// method success. + +#include <cstddef> // for std::ptrdiff_t +#include <assert.h> // for assert +#include <stdlib.h> // for free() decl + +#ifdef _WIN32 +namespace std { using ::ptrdiff_t; }; +#endif // _WIN32 + +namespace buzz { + +template <typename T> +class scoped_ptr { + private: + + T* ptr; + + scoped_ptr(scoped_ptr const &); + scoped_ptr & operator=(scoped_ptr const &); + + public: + + typedef T element_type; + + explicit scoped_ptr(T* p = 0): ptr(p) {} + + ~scoped_ptr() { + typedef char type_must_be_complete[sizeof(T)]; + delete ptr; + } + + void reset(T* p = 0) { + typedef char type_must_be_complete[sizeof(T)]; + + if (ptr != p) { + delete ptr; + ptr = p; + } + } + + T& operator*() const { + assert(ptr != 0); + return *ptr; + } + + T* operator->() const { + assert(ptr != 0); + return ptr; + } + + T* get() const { + return ptr; + } + + void swap(scoped_ptr & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = 0; + return tmp; + } + + T** accept() { + if (ptr) { + delete ptr; + ptr = 0; + } + return &ptr; + } + + T** use() { + return &ptr; + } +}; + +template<typename T> inline +void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) { + a.swap(b); +} + + + + +// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to +// is guaranteed, either on destruction of the scoped_array or via an explicit +// reset(). Use shared_array or std::vector if your needs are more complex. + +template<typename T> +class scoped_array { + private: + + T* ptr; + + scoped_array(scoped_array const &); + scoped_array & operator=(scoped_array const &); + + public: + + typedef T element_type; + + explicit scoped_array(T* p = 0) : ptr(p) {} + + ~scoped_array() { + typedef char type_must_be_complete[sizeof(T)]; + delete[] ptr; + } + + void reset(T* p = 0) { + typedef char type_must_be_complete[sizeof(T)]; + + if (ptr != p) { + delete [] ptr; + ptr = p; + } + } + + T& operator[](std::ptrdiff_t i) const { + assert(ptr != 0); + assert(i >= 0); + return ptr[i]; + } + + T* get() const { + return ptr; + } + + void swap(scoped_array & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = 0; + return tmp; + } + + T** accept() { + if (ptr) { + delete [] ptr; + ptr = 0; + } + return &ptr; + } +}; + +template<class T> inline +void swap(scoped_array<T>& a, scoped_array<T>& b) { + a.swap(b); +} + +// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a +// second template argument, the function used to free the object. + +template<typename T, void (*FF)(void*) = free> class scoped_ptr_malloc { + private: + + T* ptr; + + scoped_ptr_malloc(scoped_ptr_malloc const &); + scoped_ptr_malloc & operator=(scoped_ptr_malloc const &); + + public: + + typedef T element_type; + + explicit scoped_ptr_malloc(T* p = 0): ptr(p) {} + + ~scoped_ptr_malloc() { + typedef char type_must_be_complete[sizeof(T)]; + FF(static_cast<void*>(ptr)); + } + + void reset(T* p = 0) { + typedef char type_must_be_complete[sizeof(T)]; + + if (ptr != p) { + FF(static_cast<void*>(ptr)); + ptr = p; + } + } + + T& operator*() const { + assert(ptr != 0); + return *ptr; + } + + T* operator->() const { + assert(ptr != 0); + return ptr; + } + + T* get() const { + return ptr; + } + + void swap(scoped_ptr_malloc & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = 0; + return tmp; + } + + T** accept() { + if (ptr) { + FF(static_cast<void*>(ptr)); + ptr = 0; + } + return &ptr; + } +}; + +template<typename T, void (*FF)(void*)> inline +void swap(scoped_ptr_malloc<T,FF>& a, scoped_ptr_malloc<T,FF>& b) { + a.swap(b); +} + +} + +using buzz::scoped_ptr; + +#endif // #ifndef SCOPED_PTR_H diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h new file mode 100644 index 00000000..446516b8 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/sigslot.h @@ -0,0 +1,2700 @@ +// sigslot.h: Signal/Slot classes +// +// Written by Sarah Thompson (sarah@telergy.com) 2002. +// +// License: Public domain. You are free to use this code however you like, with the proviso that +// the author takes on no responsibility or liability for any use. +// +// QUICK DOCUMENTATION +// +// (see also the full documentation at http://sigslot.sourceforge.net/) +// +// #define switches +// SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables +// all of the thread safety support on platforms where it is +// available. +// +// SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than +// gcc on a platform that supports Posix threads. (When using gcc, +// this is the default - use SIGSLOT_PURE_ISO to disable this if +// necessary) +// +// SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global. +// Otherwise, the default is single_threaded. #define this yourself to +// override the default. In pure ISO mode, anything other than +// single_threaded will cause a compiler error. +// +// PLATFORM NOTES +// +// Win32 - On Win32, the WIN32 symbol must be #defined. Most mainstream +// compilers do this by default, but you may need to define it +// yourself if your build environment is less standard. This causes +// the Win32 thread support to be compiled in and used automatically. +// +// Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads +// available, so they are used automatically. You can override this +// (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using +// something other than gcc but still want to use Posix threads, you +// need to #define SIGSLOT_USE_POSIX_THREADS. +// +// ISO C++ - If none of the supported platforms are detected, or if +// SIGSLOT_PURE_ISO is defined, all multithreading support is turned off, +// along with any code that might cause a pure ISO C++ environment to +// complain. Before you ask, gcc -ansi -pedantic won't compile this +// library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of +// errors that aren't really there. If you feel like investigating this, +// please contact the author. +// +// +// THREADING MODES +// +// single_threaded - Your program is assumed to be single threaded from the point of view +// of signal/slot usage (i.e. all objects using signals and slots are +// created and destroyed from a single thread). Behaviour if objects are +// destroyed concurrently is undefined (i.e. you'll get the occasional +// segmentation fault/memory exception). +// +// multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and +// slots can be safely created and destroyed from any thread, even when +// connections exist. In multi_threaded_global mode, this is achieved by a +// single global mutex (actually a critical section on Windows because they +// are faster). This option uses less OS resources, but results in more +// opportunities for contention, possibly resulting in more context switches +// than are strictly necessary. +// +// multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global, +// except that each signal, and each object that inherits has_slots, all +// have their own mutex/critical section. In practice, this means that +// mutex collisions (and hence context switches) only happen if they are +// absolutely essential. However, on some platforms, creating a lot of +// mutexes can slow down the whole OS, so use this option with care. +// +// USING THE LIBRARY +// +// See the full documentation at http://sigslot.sourceforge.net/ +// +// + +#ifndef SIGSLOT_H__ +#define SIGSLOT_H__ + +#include <set> +#include <list> + +// On our copy of sigslot.h, we force single threading +#define SIGSLOT_PURE_ISO + +#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS)) +# define _SIGSLOT_SINGLE_THREADED +#elif defined(WIN32) +# define _SIGSLOT_HAS_WIN32_THREADS +# include <windows.h> +#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) +# define _SIGSLOT_HAS_POSIX_THREADS +# include <pthread.h> +#else +# define _SIGSLOT_SINGLE_THREADED +#endif + +#ifndef SIGSLOT_DEFAULT_MT_POLICY +# ifdef _SIGSLOT_SINGLE_THREADED +# define SIGSLOT_DEFAULT_MT_POLICY single_threaded +# else +# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local +# endif +#endif + + +namespace sigslot { + + class single_threaded + { + public: + single_threaded() + { + ; + } + + virtual ~single_threaded() + { + ; + } + + virtual void lock() + { + ; + } + + virtual void unlock() + { + ; + } + }; + +#ifdef _SIGSLOT_HAS_WIN32_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + static bool isinitialised = false; + + if(!isinitialised) + { + InitializeCriticalSection(get_critsec()); + isinitialised = true; + } + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + EnterCriticalSection(get_critsec()); + } + + virtual void unlock() + { + LeaveCriticalSection(get_critsec()); + } + + private: + CRITICAL_SECTION* get_critsec() + { + static CRITICAL_SECTION g_critsec; + return &g_critsec; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + InitializeCriticalSection(&m_critsec); + } + + multi_threaded_local(const multi_threaded_local&) + { + InitializeCriticalSection(&m_critsec); + } + + virtual ~multi_threaded_local() + { + DeleteCriticalSection(&m_critsec); + } + + virtual void lock() + { + EnterCriticalSection(&m_critsec); + } + + virtual void unlock() + { + LeaveCriticalSection(&m_critsec); + } + + private: + CRITICAL_SECTION m_critsec; + }; +#endif // _SIGSLOT_HAS_WIN32_THREADS + +#ifdef _SIGSLOT_HAS_POSIX_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + pthread_mutex_init(get_mutex(), NULL); + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + pthread_mutex_lock(get_mutex()); + } + + virtual void unlock() + { + pthread_mutex_unlock(get_mutex()); + } + + private: + pthread_mutex_t* get_mutex() + { + static pthread_mutex_t g_mutex; + return &g_mutex; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + pthread_mutex_init(&m_mutex, NULL); + } + + multi_threaded_local(const multi_threaded_local&) + { + pthread_mutex_init(&m_mutex, NULL); + } + + virtual ~multi_threaded_local() + { + pthread_mutex_destroy(&m_mutex); + } + + virtual void lock() + { + pthread_mutex_lock(&m_mutex); + } + + virtual void unlock() + { + pthread_mutex_unlock(&m_mutex); + } + + private: + pthread_mutex_t m_mutex; + }; +#endif // _SIGSLOT_HAS_POSIX_THREADS + + template<class mt_policy> + class lock_block + { + public: + mt_policy *m_mutex; + + lock_block(mt_policy *mtx) + : m_mutex(mtx) + { + m_mutex->lock(); + } + + ~lock_block() + { + m_mutex->unlock(); + } + }; + + template<class mt_policy> + class has_slots; + + template<class mt_policy> + class _connection_base0 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit() = 0; + virtual _connection_base0* clone() = 0; + virtual _connection_base0* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class arg1_type, class mt_policy> + class _connection_base1 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit(arg1_type) = 0; + virtual _connection_base1<arg1_type, mt_policy>* clone() = 0; + virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class arg1_type, class arg2_type, class mt_policy> + class _connection_base2 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit(arg1_type, arg2_type) = 0; + virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone() = 0; + virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class mt_policy> + class _connection_base3 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type) = 0; + virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone() = 0; + virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy> + class _connection_base4 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0; + virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone() = 0; + virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class mt_policy> + class _connection_base5 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type) = 0; + virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>* clone() = 0; + virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class mt_policy> + class _connection_base6 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type) = 0; + virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>* clone() = 0; + virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class arg7_type, class mt_policy> + class _connection_base7 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type) = 0; + virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>* clone() = 0; + virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy> + class _connection_base8 + { + public: + virtual has_slots<mt_policy>* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type, arg8_type) = 0; + virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone() = 0; + virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0; + }; + + template<class mt_policy> + class _signal_base : public mt_policy + { + public: + virtual void slot_disconnect(has_slots<mt_policy>* pslot) = 0; + virtual void slot_duplicate(const has_slots<mt_policy>* poldslot, has_slots<mt_policy>* pnewslot) = 0; + }; + + template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class has_slots : public mt_policy + { + private: + typedef typename std::set<_signal_base<mt_policy> *> sender_set; + typedef typename sender_set::const_iterator const_iterator; + + public: + has_slots() + { + ; + } + + has_slots(const has_slots& hs) + : mt_policy(hs) + { + lock_block<mt_policy> lock(this); + const_iterator it = hs.m_senders.begin(); + const_iterator itEnd = hs.m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_duplicate(&hs, this); + m_senders.insert(*it); + ++it; + } + } + + void signal_connect(_signal_base<mt_policy>* sender) + { + lock_block<mt_policy> lock(this); + m_senders.insert(sender); + } + + void signal_disconnect(_signal_base<mt_policy>* sender) + { + lock_block<mt_policy> lock(this); + m_senders.erase(sender); + } + + virtual ~has_slots() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + const_iterator it = m_senders.begin(); + const_iterator itEnd = m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_disconnect(this); + ++it; + } + + m_senders.erase(m_senders.begin(), m_senders.end()); + } + + private: + sender_set m_senders; + }; + + template<class mt_policy> + class _signal_base0 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base0<mt_policy> *> connections_list; + + _signal_base0() + { + ; + } + + _signal_base0(const _signal_base0& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + ~_signal_base0() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + protected: + connections_list m_connected_slots; + }; + + template<class arg1_type, class mt_policy> + class _signal_base1 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base1<arg1_type, mt_policy> *> connections_list; + + _signal_base1() + { + ; + } + + _signal_base1(const _signal_base1<arg1_type, mt_policy>& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base1() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + + protected: + connections_list m_connected_slots; + }; + + template<class arg1_type, class arg2_type, class mt_policy> + class _signal_base2 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base2<arg1_type, arg2_type, mt_policy> *> + connections_list; + + _signal_base2() + { + ; + } + + _signal_base2(const _signal_base2<arg1_type, arg2_type, mt_policy>& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base2() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class mt_policy> + class _signal_base3 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base3<arg1_type, arg2_type, arg3_type, mt_policy> *> + connections_list; + + _signal_base3() + { + ; + } + + _signal_base3(const _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base3() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy> + class _signal_base4 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base4<arg1_type, arg2_type, arg3_type, + arg4_type, mt_policy> *> connections_list; + + _signal_base4() + { + ; + } + + _signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base4() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class mt_policy> + class _signal_base5 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base5<arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, mt_policy> *> connections_list; + + _signal_base5() + { + ; + } + + _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base5() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class mt_policy> + class _signal_base6 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base6<arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, mt_policy> *> connections_list; + + _signal_base6() + { + ; + } + + _signal_base6(const _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base6() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class arg7_type, class mt_policy> + class _signal_base7 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base7<arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, arg7_type, mt_policy> *> connections_list; + + _signal_base7() + { + ; + } + + _signal_base7(const _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base7() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy> + class _signal_base8 : public _signal_base<mt_policy> + { + public: + typedef std::list<_connection_base8<arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> *> + connections_list; + + _signal_base8() + { + ; + } + + _signal_base8(const _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s) + : _signal_base<mt_policy>(s) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = s.m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base8() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + +#ifdef _DEBUG + bool connected(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + while(it != itEnd) + { + itNext = it; + ++itNext; + if ((*it)->getdest() == pclass) + return true; + it = itNext; + } + return false; + } +#endif + + void disconnect(has_slots<mt_policy>* pclass) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots<mt_policy>* pslot) + { + lock_block<mt_policy> lock(this); + typename connections_list::iterator it = m_connected_slots.begin(); + typename connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + typename connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + + template<class dest_type, class mt_policy> + class _connection0 : public _connection_base0<mt_policy> + { + public: + _connection0() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection0(dest_type* pobject, void (dest_type::*pmemfun)()) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base0<mt_policy>* clone() + { + return new _connection0<dest_type, mt_policy>(*this); + } + + virtual _connection_base0<mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection0<dest_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit() + { + (m_pobject->*m_pmemfun)(); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(); + }; + + template<class dest_type, class arg1_type, class mt_policy> + class _connection1 : public _connection_base1<arg1_type, mt_policy> + { + public: + _connection1() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base1<arg1_type, mt_policy>* clone() + { + return new _connection1<dest_type, arg1_type, mt_policy>(*this); + } + + virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection1<dest_type, arg1_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1) + { + (m_pobject->*m_pmemfun)(a1); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type); + }; + + template<class dest_type, class arg1_type, class arg2_type, class mt_policy> + class _connection2 : public _connection_base2<arg1_type, arg2_type, mt_policy> + { + public: + _connection2() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone() + { + return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>(*this); + } + + virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2) + { + (m_pobject->*m_pmemfun)(a1, a2); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type); + }; + + template<class dest_type, class arg1_type, class arg2_type, class arg3_type, class mt_policy> + class _connection3 : public _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy> + { + public: + _connection3() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone() + { + return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>(*this); + } + + virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + (m_pobject->*m_pmemfun)(a1, a2, a3); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type); + }; + + template<class dest_type, class arg1_type, class arg2_type, class arg3_type, + class arg4_type, class mt_policy> + class _connection4 : public _connection_base4<arg1_type, arg2_type, + arg3_type, arg4_type, mt_policy> + { + public: + _connection4() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone() + { + return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(*this); + } + + virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, + arg4_type a4) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, + arg4_type); + }; + + template<class dest_type, class arg1_type, class arg2_type, class arg3_type, + class arg4_type, class arg5_type, class mt_policy> + class _connection5 : public _connection_base5<arg1_type, arg2_type, + arg3_type, arg4_type, arg5_type, mt_policy> + { + public: + _connection5() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>* clone() + { + return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>(*this); + } + + virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type); + }; + + template<class dest_type, class arg1_type, class arg2_type, class arg3_type, + class arg4_type, class arg5_type, class arg6_type, class mt_policy> + class _connection6 : public _connection_base6<arg1_type, arg2_type, + arg3_type, arg4_type, arg5_type, arg6_type, mt_policy> + { + public: + _connection6() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>* clone() + { + return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>(*this); + } + + virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type); + }; + + template<class dest_type, class arg1_type, class arg2_type, class arg3_type, + class arg4_type, class arg5_type, class arg6_type, class arg7_type, class mt_policy> + class _connection7 : public _connection_base7<arg1_type, arg2_type, + arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, mt_policy> + { + public: + _connection7() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>* clone() + { + return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>(*this); + } + + virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type); + }; + + template<class dest_type, class arg1_type, class arg2_type, class arg3_type, + class arg4_type, class arg5_type, class arg6_type, class arg7_type, + class arg8_type, class mt_policy> + class _connection8 : public _connection_base8<arg1_type, arg2_type, + arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> + { + public: + _connection8() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone() + { + return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(*this); + } + + virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) + { + return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + virtual has_slots<mt_policy>* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type); + }; + + template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal0 : public _signal_base0<mt_policy> + { + public: + typedef _signal_base0<mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal0() + { + ; + } + + signal0(const signal0<mt_policy>& s) + : _signal_base0<mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)()) + { + lock_block<mt_policy> lock(this); + _connection0<desttype, mt_policy>* conn = + new _connection0<desttype, mt_policy>(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + + void operator()() + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + }; + + template<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal1 : public _signal_base1<arg1_type, mt_policy> + { + public: + typedef _signal_base1<arg1_type, mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal1() + { + ; + } + + signal1(const signal1<arg1_type, mt_policy>& s) + : _signal_base1<arg1_type, mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type)) + { + lock_block<mt_policy> lock(this); + _connection1<desttype, arg1_type, mt_policy>* conn = + new _connection1<desttype, arg1_type, mt_policy>(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + + void operator()(arg1_type a1) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + }; + + template<class arg1_type, class arg2_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal2 : public _signal_base2<arg1_type, arg2_type, mt_policy> + { + public: + typedef _signal_base2<arg1_type, arg2_type, mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal2() + { + ; + } + + signal2(const signal2<arg1_type, arg2_type, mt_policy>& s) + : _signal_base2<arg1_type, arg2_type, mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type)) + { + lock_block<mt_policy> lock(this); + _connection2<desttype, arg1_type, arg2_type, mt_policy>* conn = new + _connection2<desttype, arg1_type, arg2_type, mt_policy>(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + }; + + template<class arg1_type, class arg2_type, class arg3_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal3 : public _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy> + { + public: + typedef _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal3() + { + ; + } + + signal3(const signal3<arg1_type, arg2_type, arg3_type, mt_policy>& s) + : _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + lock_block<mt_policy> lock(this); + _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>* conn = + new _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>(pclass, + pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal4 : public _signal_base4<arg1_type, arg2_type, arg3_type, + arg4_type, mt_policy> + { + public: + typedef _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal4() + { + ; + } + + signal4(const signal4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s) + : _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + lock_block<mt_policy> lock(this); + _connection4<desttype, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* + conn = new _connection4<desttype, arg1_type, arg2_type, arg3_type, + arg4_type, mt_policy>(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal5 : public _signal_base5<arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, mt_policy> + { + public: + typedef _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal5() + { + ; + } + + signal5(const signal5<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>& s) + : _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + lock_block<mt_policy> lock(this); + _connection5<desttype, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, mt_policy>* conn = new _connection5<desttype, arg1_type, arg2_type, + arg3_type, arg4_type, arg5_type, mt_policy>(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + }; + + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal6 : public _signal_base6<arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, mt_policy> + { + public: + typedef _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal6() + { + ; + } + + signal6(const signal6<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>& s) + : _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + lock_block<mt_policy> lock(this); + _connection6<desttype, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, mt_policy>* conn = + new _connection6<desttype, arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, mt_policy>(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class arg7_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal7 : public _signal_base7<arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, arg7_type, mt_policy> + { + public: + typedef _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal7() + { + ; + } + + signal7(const signal7<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>& s) + : _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type)) + { + lock_block<mt_policy> lock(this); + _connection7<desttype, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, mt_policy>* conn = + new _connection7<desttype, arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + }; + + template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, + class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> + class signal8 : public _signal_base8<arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> + { + public: + typedef _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> base; + typedef typename base::connections_list connections_list; + using base::m_connected_slots; + + signal8() + { + ; + } + + signal8(const signal8<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s) + : _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(s) + { + ; + } + + template<class desttype> + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + lock_block<mt_policy> lock(this); + _connection8<desttype, arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* conn = + new _connection8<desttype, arg1_type, arg2_type, arg3_type, + arg4_type, arg5_type, arg6_type, arg7_type, + arg8_type, mt_policy>(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block<mt_policy> lock(this); + typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); + typename connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + }; + +}; // namespace sigslot + +#endif // SIGSLOT_H__ + diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h new file mode 100644 index 00000000..d4a49d96 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socket.h @@ -0,0 +1,158 @@ +/* + * 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. + */ + +#ifndef _socket_h_ +#define _socket_h_ + +#include "talk/base/basictypes.h" +#include "talk/base/socketaddress.h" + +#ifdef POSIX +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <errno.h> +#endif + +#ifdef WIN32 +#include "talk/base/win32.h" +#endif + +// Rather than converting errors into a private namespace, +// Reuse the POSIX socket api errors. Note this depends on +// Win32 compatibility. + +#ifdef WIN32 +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY +#define ENOTSOCK WSAENOTSOCK +#define EDESTADDRREQ WSAEDESTADDRREQ +#define EMSGSIZE WSAEMSGSIZE +#define EPROTOTYPE WSAEPROTOTYPE +#define ENOPROTOOPT WSAENOPROTOOPT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EADDRINUSE WSAEADDRINUSE +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define ENETDOWN WSAENETDOWN +#define ENETUNREACH WSAENETUNREACH +#define ENETRESET WSAENETRESET +#define ECONNABORTED WSAECONNABORTED +#define ECONNRESET WSAECONNRESET +#define ENOBUFS WSAENOBUFS +#define EISCONN WSAEISCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#define ETIMEDOUT WSAETIMEDOUT +#define ECONNREFUSED WSAECONNREFUSED +#define ELOOP WSAELOOP +#undef ENAMETOOLONG // remove errno.h's definition +#define ENAMETOOLONG WSAENAMETOOLONG +#define EHOSTDOWN WSAEHOSTDOWN +#define EHOSTUNREACH WSAEHOSTUNREACH +#undef ENOTEMPTY // remove errno.h's definition +#define ENOTEMPTY WSAENOTEMPTY +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE +#undef EACCES +#define EACCES WSAEACCES +#endif // WIN32 + +#ifdef POSIX +#define INVALID_SOCKET (-1) +#define SOCKET_ERROR (-1) +#define closesocket(s) close(s) +#endif // POSIX + +namespace cricket { + +inline bool IsBlockingError(int e) { + return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS); +} + +// General interface for the socket implementations of various networks. The +// methods match those of normal UNIX sockets very closely. +class Socket { +public: + virtual ~Socket() {} + + // Returns the address to which the socket is bound. If the socket is not + // bound, then the any-address is returned. + virtual SocketAddress GetLocalAddress() const = 0; + + // Returns the address to which the socket is connected. If the socket is + // not connected, then the any-address is returned. + virtual SocketAddress GetRemoteAddress() const = 0; + + virtual int Bind(const SocketAddress& addr) = 0; + virtual int Connect(const SocketAddress& addr) = 0; + virtual int Send(const void *pv, size_t cb) = 0; + virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) = 0; + virtual int Recv(void *pv, size_t cb) = 0; + virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr) = 0; + virtual int Listen(int backlog) = 0; + virtual Socket *Accept(SocketAddress *paddr) = 0; + virtual int Close() = 0; + virtual int GetError() const = 0; + virtual void SetError(int error) = 0; + inline bool IsBlocking() const { return IsBlockingError(GetError()); } + + enum ConnState { + CS_CLOSED, + CS_CONNECTING, + CS_CONNECTED + }; + virtual ConnState GetState() const = 0; + + // Fills in the given uint16 with the current estimate of the MTU along the + // path to the address to which this socket is connected. + virtual int EstimateMTU(uint16* mtu) = 0; + + enum Option { + OPT_DONTFRAGMENT + }; + virtual int SetOption(Option opt, int value) = 0; + +protected: + Socket() {} + +private: + DISALLOW_EVIL_CONSTRUCTORS(Socket); +}; + +} // namespace cricket + +#endif // _socket_h_ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc new file mode 100644 index 00000000..049e923c --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.cc @@ -0,0 +1,1130 @@ +/* + * 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 <time.h> + +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#define _WINSOCKAPI_ +#include <windows.h> +#include <wininet.h> // HTTP_STATUS_PROXY_AUTH_REQ +#define SECURITY_WIN32 +#include <security.h> +#endif + +#include <cassert> + +#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 <errno.h> + + +#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<char *>(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<int>(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 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<unsigned char *>(reinterpret_cast<const unsigned char *>(data.data())), static_cast<unsigned int>(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<str.size(); ++i) { + if ((str[i] == '"') || (str[i] == '\\')) + result.push_back('\\'); + result.push_back(str[i]); + } + result.push_back('"'); + return result; +} + +#ifdef WIN32 +struct NegotiateAuthContext : public AsyncHttpsProxySocket::AuthContext { + CredHandle cred; + CtxtHandle ctx; + size_t steps; + bool specified_credentials; + + NegotiateAuthContext(const std::string& auth, CredHandle c1, CtxtHandle c2) + : AuthContext(auth), cred(c1), ctx(c2), steps(0), specified_credentials(false) { } + + virtual ~NegotiateAuthContext() { + DeleteSecurityContext(&ctx); + FreeCredentialsHandle(&cred); + } +}; +#endif // WIN32 + +AsyncHttpsProxySocket::AuthResult +AsyncHttpsProxySocket::Authenticate(const char * challenge, size_t len, + const SocketAddress& server, + const std::string& method, const std::string& uri, + const std::string& username, const buzz::XmppPassword& password, + AuthContext *& context, std::string& response, std::string& auth_method) { +#if TEST_DIGEST + challenge = DIGEST_CHALLENGE; + len = strlen(challenge); +#endif + + std::map<std::string, std::string> 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<NegotiateAuthContext *>(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<char *>(decoded_challenge.data()); + in_sec.cbBuffer = static_cast<unsigned long>(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<unsigned long>( + _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<unsigned long>( + _min(sizeof(passbuf) - 1, password.GetLength())); + memcpy(passbuf, sensitive, auth_id.PasswordLength); + passbuf[auth_id.PasswordLength] = 0; + } else { + auth_id.UserLength = static_cast<unsigned long>( + _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<unsigned long>( + _min(sizeof(domainbuf) - 1, pos)); + memcpy(domainbuf, username.c_str(), auth_id.DomainLength); + domainbuf[auth_id.DomainLength] = 0; + auth_id.PasswordLength = static_cast<unsigned long>( + _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<std::string,std::string>& 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 <IPV6>:" << 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<uint8>(user_.size())); + request.WriteString(user_); // Username + request.WriteUInt8(static_cast<uint8>(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<uint8>(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<const char *>(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<const char *>(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<const char *>(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<const char *>(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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.h new file mode 100644 index 00000000..1c65aa79 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketadapters.h @@ -0,0 +1,181 @@ +/* + * 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. + */ + +#ifndef __SOCKETADAPTERS_H__ +#define __SOCKETADAPTERS_H__ + +#include <map> + +#include "talk/base/asyncsocket.h" +#include "talk/base/logging.h" +#include "talk/xmpp/xmpppassword.h" // TODO: move xmpppassword to base + +namespace cricket { + +/////////////////////////////////////////////////////////////////////////////// + +class BufferedReadAdapter : public AsyncSocketAdapter { +public: + BufferedReadAdapter(AsyncSocket* socket, size_t buffer_size); + virtual ~BufferedReadAdapter(); + + virtual int Send(const void *pv, size_t cb); + virtual int Recv(void *pv, size_t cb); + +protected: + int DirectSend(const void *pv, size_t cb) { return AsyncSocketAdapter::Send(pv, cb); } + + void BufferInput(bool on = true); + virtual void ProcessInput(char * data, size_t& len) = 0; + + virtual void OnReadEvent(AsyncSocket * socket); + +private: + char * buffer_; + size_t buffer_size_, data_len_; + bool buffering_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class AsyncSSLSocket : public BufferedReadAdapter { +public: + AsyncSSLSocket(AsyncSocket* socket); + + virtual int Connect(const SocketAddress& addr); + +protected: + virtual void OnConnectEvent(AsyncSocket * socket); + virtual void ProcessInput(char * data, size_t& len); +}; + +/////////////////////////////////////////////////////////////////////////////// + +class AsyncHttpsProxySocket : public BufferedReadAdapter { +public: + AsyncHttpsProxySocket(AsyncSocket* socket, const SocketAddress& proxy, + const std::string& username, const buzz::XmppPassword& password); + virtual ~AsyncHttpsProxySocket(); + + virtual int Connect(const SocketAddress& addr); + virtual SocketAddress GetRemoteAddress() const; + virtual int Close(); + + struct AuthContext { + std::string auth_method; + AuthContext(const std::string& auth) : auth_method(auth) { } + virtual ~AuthContext() { } + }; + + // 'context' is used by this function to record information between calls. + // Start by passing a null pointer, then pass the same pointer each additional + // call. When the authentication attempt is finished, delete the context. + enum AuthResult { AR_RESPONSE, AR_IGNORE, AR_CREDENTIALS, AR_ERROR }; + static AuthResult Authenticate(const char * challenge, size_t len, + const SocketAddress& server, + const std::string& method, const std::string& uri, + const std::string& username, const buzz::XmppPassword& password, + AuthContext *& context, std::string& response, std::string& auth_method); + +protected: + virtual void OnConnectEvent(AsyncSocket * socket); + virtual void OnCloseEvent(AsyncSocket * socket, int err); + virtual void ProcessInput(char * data, size_t& len); + + void SendRequest(); + void ProcessLine(char * data, size_t len); + void EndResponse(); + void Error(int error); + + static void ParseAuth(const char * data, size_t len, std::string& method, std::map<std::string,std::string>& args); + +private: + SocketAddress proxy_, dest_; + std::string user_, headers_; + buzz::XmppPassword pass_; + size_t content_length_; + int defer_error_; + bool expect_close_; + enum ProxyState { PS_LEADER, PS_AUTHENTICATE, PS_SKIP_HEADERS, PS_ERROR_HEADERS, PS_TUNNEL_HEADERS, PS_SKIP_BODY, PS_TUNNEL, PS_WAIT_CLOSE, PS_ERROR } state_; + AuthContext * context_; + std::string unknown_mechanisms_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class AsyncSocksProxySocket : public BufferedReadAdapter { +public: + AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy, + const std::string& username, const buzz::XmppPassword& password); + + virtual int Connect(const SocketAddress& addr); + virtual SocketAddress GetRemoteAddress() const; + +protected: + virtual void OnConnectEvent(AsyncSocket * socket); + virtual void ProcessInput(char * data, size_t& len); + + void SendHello(); + void SendConnect(); + void SendAuth(); + void Error(int error); + +private: + SocketAddress proxy_, dest_; + std::string user_; + buzz::XmppPassword pass_; + enum SocksState { SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR } state_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class LoggingAdapter : public AsyncSocketAdapter { +public: + LoggingAdapter(AsyncSocket* socket, LoggingSeverity level, + const char * label); + + virtual int Send(const void *pv, size_t cb); + virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr); + virtual int Recv(void *pv, size_t cb); + virtual int RecvFrom(void *pv, size_t cb, SocketAddress *paddr); + +protected: + virtual void OnConnectEvent(AsyncSocket * socket); + virtual void OnCloseEvent(AsyncSocket * socket, int err); + +private: + void LogMultiline(bool input, const char * data, size_t len); + + LoggingSeverity level_; + std::string label_; +}; + +/////////////////////////////////////////////////////////////////////////////// + +} // namespace cricket + +#endif // __SOCKETADAPTERS_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc new file mode 100644 index 00000000..f0228fbd --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.cc @@ -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 <cstring> +#include <sstream> +#include <cassert> + +#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 <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#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<uint32*>(buf)[0] = ip_; + buf += sizeof(ip_); + reinterpret_cast<uint16*>(buf)[0] = port_; +} + +void SocketAddress::Read_(const char* buf, int len) { + assert((size_t)len >= Size_()); + ip_ = reinterpret_cast<const uint32*>(buf)[0]; + buf += sizeof(ip_); + port_ = reinterpret_cast<const uint16*>(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 ***"; +#if WIN32 + WSASetLastError(WSAHOST_NOT_FOUND); +#endif // WIN32 +#endif // DISABLE_DNS + if (hostent * pHost = gethostbyname(hostname.c_str())) { + ip = NetworkToHost32(*reinterpret_cast<uint32 *>(pHost->h_addr_list[0])); + } else { +#if 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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.h new file mode 100644 index 00000000..b8a165d3 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddress.h @@ -0,0 +1,154 @@ +/* + * 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. + */ + +#ifndef __SOCKETADDRESS_H__ +#define __SOCKETADDRESS_H__ + +#include "talk/base/basictypes.h" +#include <string> +#undef SetPort + +namespace cricket { + +// Records an IP address and port, which are 32 and 16 bit integers, +// respectively, both in <b>host byte-order</b>. +class SocketAddress { +public: + // Creates a missing / unknown address. + SocketAddress(); + + // Creates the address with the given host and port. If use_dns is true, + // the hostname will be immediately resolved to an IP (which may block for + // several seconds if DNS is not available). Alternately, set use_dns to + // false, and then call Resolve() to complete resolution later, or use + // SetResolvedIP to set the IP explictly. + SocketAddress(const std::string& hostname, int port = 0, bool use_dns = true); + + // Creates the address with the given IP and port. + SocketAddress(uint32 ip, int port); + + // Creates a copy of the given address. + SocketAddress(const SocketAddress& addr); + + // Replaces our address with the given one. + SocketAddress& operator =(const SocketAddress& addr); + + // Changes the IP of this address to the given one, and clears the hostname. + void SetIP(uint32 ip); + + // Changes the hostname of this address to the given one. + // Calls Resolve and returns the result. + bool SetIP(const std::string& hostname, bool use_dns = true); + + // Sets the IP address while retaining the hostname. Useful for bypassing + // DNS for a pre-resolved IP. + void SetResolvedIP(uint32 ip); + + // Changes the port of this address to the given one. + void SetPort(int port); + + // Returns the IP address. + uint32 ip() const; + + // Returns the port part of this address. + uint16 port() const; + + // Returns the IP address in dotted form. + std::string IPAsString() const; + + // Returns the port as a string + std::string PortAsString() const; + + // Returns a display version of the IP/port. + std::string ToString() const; + + // Determines whether this represents a missing / any address. + bool IsAny() const; + + // Synomym for missing / any. + bool IsNil() const { return IsAny(); } + + // Determines whether the IP address refers to the local host, i.e. within + // the range 127.0.0.0/8. + bool IsLocalIP() const; + + // Determines whether the IP address is in one of the private ranges: + // 127.0.0.0/8 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12. + bool IsPrivateIP() const; + + // Determines whether the hostname has been resolved to an IP + bool IsUnresolved() const; + + // Attempt to resolve a hostname to IP address. + // Returns false if resolution is required but failed. + // 'force' will cause re-resolution of hostname. + // + bool Resolve(bool force = false, bool use_dns = true); + + // Determines whether this address is identical to the given one. + bool operator ==(const SocketAddress& addr) const; + + // Compares based on IP and then port. + bool operator <(const SocketAddress& addr) const; + + // Determines whether this address has the same IP as the one given. + bool EqualIPs(const SocketAddress& addr) const; + + // Deteremines whether this address has the same port as the one given. + bool EqualPorts(const SocketAddress& addr) const; + + // Hashes this address into a small number. + size_t Hash() const; + + // Returns the size of this address when written. + size_t Size_() const; + + // Writes this address into the given buffer. + void Write_(char* buf, int len) const; + + // Reads this address from the given buffer. + void Read_(const char* buf, int len); + + // Converts the IP address given in compact form into dotted form. + static std::string IPToString(uint32 ip); + + // Converts the IP address given in dotted form into compact form. + // Without 'use_dns', only dotted names (A.B.C.D) are resolved. + static uint32 StringToIP(const std::string& str, bool use_dns = true); + +private: + std::string hostname_; + uint32 ip_; + uint16 port_; + + // Initializes the address to missing / any. + void Zero(); +}; + +} // namespace cricket + +#endif // __SOCKETADDRESS_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc new file mode 100644 index 00000000..2166be09 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.cc @@ -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/socketaddresspair.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.h new file mode 100644 index 00000000..098bafdb --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketaddresspair.h @@ -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. + */ + +#ifndef __SOCKETADDRESSPAIR_H__ +#define __SOCKETADDRESSPAIR_H__ + +#include "talk/base/socketaddress.h" + +namespace cricket { + +// Records a pair (source,destination) of socket addresses. The two addresses +// identify a connection between two machines. (For UDP, this "connection" is +// not maintained explicitly in a socket.) +class SocketAddressPair { +public: + SocketAddressPair() {} + SocketAddressPair(const SocketAddress& srs, const SocketAddress& dest); + + const SocketAddress& source() const { return src_; } + const SocketAddress& destination() const { return dest_; } + + bool operator ==(const SocketAddressPair& r) const; + bool operator <(const SocketAddressPair& r) const; + + size_t Hash() const; + +private: + SocketAddress src_; + SocketAddress dest_; +}; + +} // namespace cricket + +#endif // __SOCKETADDRESSPAIR_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h new file mode 100644 index 00000000..67386160 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketfactory.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef __SOCKETFACTORY_H__ +#define __SOCKETFACTORY_H__ + +#include "talk/base/socket.h" +#include "talk/base/asyncsocket.h" + +namespace cricket { + +class SocketFactory { +public: + + // Returns a new socket for blocking communication. The type can be + // SOCK_DGRAM and SOCK_STREAM. + virtual Socket* CreateSocket(int type) = 0; + + // Returns a new socket for nonblocking communication. The type can be + // SOCK_DGRAM and SOCK_STREAM. + virtual AsyncSocket* CreateAsyncSocket(int type) = 0; +}; + +} // namespace cricket + +#endif // __SOCKETFACTORY_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h new file mode 100644 index 00000000..d0e7a22a --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/socketserver.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef __SOCKETSERVER_H__ +#define __SOCKETSERVER_H__ + +#include "talk/base/socketfactory.h" + +namespace cricket { + +// Provides the ability to wait for activity on a set of sockets. The Thread +// class provides a nice wrapper on a socket server. +// +// The server is also a socket factory. The sockets it creates will be +// notified of asynchronous I/O from this server's Wait method. +class SocketServer : public SocketFactory { +public: + + // Performs I/O or sleeps for the given number of milliseconds. + // If process_io is false, just sleeps until WakeUp. + virtual bool Wait(int cms, bool process_io) = 0; + + // Causes the current wait (if one is in progress) to wake up. + virtual void WakeUp() = 0; +}; + +} // namespace cricket + +#endif // __SOCKETSERVER_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h new file mode 100644 index 00000000..9c2506f1 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/stl_decl.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#ifndef _STL_DECL_H +#define _STL_DECL_H + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0 +#pragma warning(disable:4786) +#endif + +#include <sys/types.h> + +namespace std { + template <class Key> struct hash; + template <class Key> struct equal_to; + template <class Key> struct less; + template <class T> class allocator; + template <class Key, class Val, + class Compare, + class Alloc> class map; + template <class T, class Alloc> class vector; + template <class T, class Alloc> class list; + template <class T, class Alloc> class slist; + template <class T, class Alloc, size_t BufSiz> class deque; + template <class T, class Sequence> class stack; + template <class T, class Sequence> class queue; + template <class T, class Sequence, class Compare> class priority_queue; + template <class T1, class T2> struct pair; + template <class Key, class Compare, class Alloc> class set; +} + +///////////////////////////////////////////////////////////////////////////// +// Workaround declaration problem with defaults +///////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 == VC++ 6.0 + +#define STD_MAP(T1, T2) \ + std::map<T1 , T2, std::less<T1>, std::allocator<T2> > + +#define STD_VECTOR(T1) \ + std::vector<T1, std::allocator<T1> > + +#define STD_SET(T1) \ + std::set<T1, std::less<T1>, std::allocator<T1> > + +#else + +#define STD_MAP(T1, T2) \ + std::map<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2 > > > + +#define STD_VECTOR(T1) \ + std::vector<T1, std::allocator<T1> > + +#define STD_SET(T1) \ + std::set<T1, std::less<T1>, std::allocator<T1> > + +#endif + + +#endif // _STL_DECL_H diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h new file mode 100644 index 00000000..a23132dd --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/stringutils.h @@ -0,0 +1,266 @@ +/* + * 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. + */ + +#ifndef __STRINGUTILS_H__ +#define __STRINGUTILS_H__ + +#include <cctype> +#include <cstdarg> +#include <cstdio> +#ifdef WIN32 +#include <wchar.h> +#endif // WIN32 + +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +// Rename a bunch of common string functions so they are consistent across +// platforms and between char and wchar_t variants. +// Here is the full list of functions that are unified: +// strlen, strcmp, stricmp, strncmp, strnicmp +// strchr, vsnprintf, strtoul, tolowercase +// tolowercase is like tolower, but not compatible with end-of-file value +// Note that the wchar_t versions are not available on Linux +/////////////////////////////////////////////////////////////////////////////// + +inline char tolowercase(char c) { + return static_cast<char>(tolower(c)); +} + +#ifdef WIN32 + +inline size_t strlen(const wchar_t* s) { + return wcslen(s); +} +inline int strcmp(const wchar_t* s1, const wchar_t* s2) { + return wcscmp(s1, s2); +} +inline int stricmp(const wchar_t* s1, const wchar_t* s2) { + return wcsicmp(s1, s2); +} +inline int strncmp(const wchar_t* s1, const wchar_t* s2, size_t n) { + return wcsncmp(s1, s2, n); +} +inline int strnicmp(const wchar_t* s1, const wchar_t* s2, size_t n) { + return wcsnicmp(s1, s2, n); +} +inline const wchar_t* strchr(const wchar_t* s, wchar_t c) { + return wcschr(s, c); +} +inline int vsnprintf(char* buf, size_t n, const char* fmt, va_list args) { + return _vsnprintf(buf, n, fmt, args); +} +inline int vsnprintf(wchar_t* buf, size_t n, const wchar_t* fmt, va_list args) { + return _vsnwprintf(buf, n, fmt, args); +} +inline unsigned long strtoul(const wchar_t* snum, wchar_t** end, int base) { + return wcstoul(snum, end, base); +} +inline wchar_t tolowercase(wchar_t c) { + return static_cast<wchar_t>(towlower(c)); +} + +#endif // WIN32 + +#ifdef POSIX + +inline int stricmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline int strnicmp(const char* s1, const char* s2, size_t n) { + return strncasecmp(s1, s2, n); +} + +#endif // POSIX + +/////////////////////////////////////////////////////////////////////////////// +// Traits simplifies porting string functions to be CTYPE-agnostic +/////////////////////////////////////////////////////////////////////////////// + +namespace cricket { + +const size_t SIZE_UNKNOWN = static_cast<size_t>(-1); + +template<class CTYPE> +struct Traits { + // STL string type + //typedef XXX string; + // Null-terminated string + //inline static const CTYPE* empty_str(); +}; + +/////////////////////////////////////////////////////////////////////////////// +// String utilities which work with char or wchar_t +/////////////////////////////////////////////////////////////////////////////// + +template<class CTYPE> +inline const CTYPE* nonnull(const CTYPE* str, const CTYPE* def_str = NULL) { + return str ? str : (def_str ? def_str : Traits<CTYPE>::empty_str()); +} + +template<class CTYPE> +const CTYPE* strchr(const CTYPE* str, const CTYPE* chs) { + for (size_t i=0; str[i]; ++i) { + for (size_t j=0; chs[j]; ++j) { + if (str[i] == chs[j]) { + return str + i; + } + } + } + return 0; +} + +template<class CTYPE> +const CTYPE* strchrn(const CTYPE* str, size_t slen, CTYPE ch) { + for (size_t i=0; i<slen && str[i]; ++i) { + if (str[i] == ch) { + return str + i; + } + } + return 0; +} + +template<class CTYPE> +size_t strlenn(const CTYPE* buffer, size_t buflen) { + size_t bufpos = 0; + while (buffer[bufpos] && (bufpos < buflen)) { + ++bufpos; + } + return bufpos; +} + +template<class CTYPE> +size_t strcpyn(CTYPE* buffer, size_t buflen, + const CTYPE* source, size_t srclen = SIZE_UNKNOWN) { + if (buflen <= 0) + return 0; + + if (srclen == SIZE_UNKNOWN) { + srclen = strlenn(source, buflen - 1); + } else if (srclen >= buflen) { + srclen = buflen - 1; + } + memcpy(buffer, source, srclen * sizeof(CTYPE)); + buffer[srclen] = 0; + return srclen; +} + +// Safe versions of snprintf and vsnprintf that always null-terminate + +template<class CTYPE> +size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) { + va_list args; + va_start(args, format); + size_t len = vsprintfn(buffer, buflen, format, args); + va_end(args); + return len; +} + +template<class CTYPE> +size_t vsprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, + va_list args) { + int len = vsnprintf(buffer, buflen, format, args); + if ((len < 0) || (static_cast<size_t>(len) >= buflen)) { + len = static_cast<int>(buflen - 1); + buffer[len] = 0; + } + return len; +} + +/////////////////////////////////////////////////////////////////////////////// +// Allow safe comparing and copying ascii (not UTF-8) with both wide and +// non-wide character strings. +/////////////////////////////////////////////////////////////////////////////// + +inline int asccmp(const char* s1, const char* s2) { + return strcmp(s1, s2); +} +inline int ascicmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline int ascncmp(const char* s1, const char* s2, size_t n) { + return strncmp(s1, s2, n); +} +inline int ascnicmp(const char* s1, const char* s2, size_t n) { + return strnicmp(s1, s2, n); +} +inline size_t asccpyn(char* buffer, size_t buflen, + const char* source, size_t srclen = SIZE_UNKNOWN) { + return strcpyn(buffer, buflen, source, srclen); +} + +#ifdef WIN32 + +typedef wchar_t(*CharacterTransformation)(wchar_t); +inline wchar_t identity(wchar_t c) { return c; } +int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n, + CharacterTransformation transformation); + +inline int asccmp(const wchar_t* s1, const char* s2) { + return ascii_string_compare(s1, s2, static_cast<size_t>(-1), identity); +} +inline int ascicmp(const wchar_t* s1, const char* s2) { + return ascii_string_compare(s1, s2, static_cast<size_t>(-1), tolowercase); +} +inline int ascncmp(const wchar_t* s1, const char* s2, size_t n) { + return ascii_string_compare(s1, s2, n, identity); +} +inline int ascnicmp(const wchar_t* s1, const char* s2, size_t n) { + return ascii_string_compare(s1, s2, n, tolowercase); +} +size_t asccpyn(wchar_t* buffer, size_t buflen, + const char* source, size_t srclen = SIZE_UNKNOWN); + +#endif // WIN32 + +/////////////////////////////////////////////////////////////////////////////// +// Traits<char> specializations +/////////////////////////////////////////////////////////////////////////////// + +template<> +struct Traits<char> { + typedef std::string string; + inline static const char* empty_str() { return ""; } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Traits<wchar_t> specializations (Windows only, currently) +/////////////////////////////////////////////////////////////////////////////// + +#ifdef WIN32 + +template<> +struct Traits<wchar_t> { + typedef std::wstring string; + inline static const wchar_t* Traits<wchar_t>::empty_str() { return L""; } +}; + +#endif // WIN32 + +} // namespace cricket + +#endif // __STRINGUTILS_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc new file mode 100644 index 00000000..a5a94941 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.cc @@ -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 <algorithm> + +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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.h new file mode 100644 index 00000000..5a486198 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/task.h @@ -0,0 +1,186 @@ +/* + * 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. + */ + +#ifndef _TASK_H_ +#define _TASK_H_ + +#include <vector> +#include <string> + +#include "talk/base/sigslot.h" + +///////////////////////////////////////////////////////////////////// +// +// TASK +// +///////////////////////////////////////////////////////////////////// +// +// Task is a state machine infrastructure. States are pushed forward by +// pushing forwards a TaskRunner that holds on to all Tasks. The purpose +// of Task is threefold: +// +// (1) It manages ongoing work on the UI thread. Multitasking without +// threads, keeping it easy, keeping it real. :-) It does this by +// organizing a set of states for each task. When you return from your +// Process*() function, you return an integer for the next state. You do +// not go onto the next state yourself. Every time you enter a state, +// you check to see if you can do anything yet. If not, you return +// STATE_BLOCKED. If you _could_ do anything, do not return +// STATE_BLOCKED - even if you end up in the same state, return +// STATE_mysamestate. When you are done, return STATE_DONE and then the +// task will self-delete sometimea afterwards. +// +// (2) It helps you avoid all those reentrancy problems when you chain +// too many triggers on one thread. Basically if you want to tell a task +// to process something for you, you feed your task some information and +// then you Wake() it. Don't tell it to process it right away. If it +// might be working on something as you send it infomration, you may want +// to have a queue in the task. +// +// (3) Finally it helps manage parent tasks and children. If a parent +// task gets aborted, all the children tasks are too. The nice thing +// about this, for example, is if you have one parent task that +// represents, say, and Xmpp connection, then you can spawn a whole bunch +// of infinite lifetime child tasks and now worry about cleaning them up. +// When the parent task goes to STATE_DONE, the task engine will make +// sure all those children are aborted and get deleted. +// +// Notice that Task has a few built-in states, e.g., +// +// STATE_INIT - the task isn't running yet +// STATE_START - the task is in its first state +// STATE_RESPONSE - the task is in its second state +// STATE_DONE - the task is done +// +// STATE_ERROR - indicates an error - we should audit the error code in +// light of any usage of it to see if it should be improved. When I +// first put down the task stuff I didn't have a good sense of what was +// needed for Abort and Error, and now the subclasses of Task will ground +// the design in a stronger way. +// +// STATE_NEXT - the first undefined state number. (like WM_USER) - you +// can start defining more task states there. +// +// When you define more task states, just override Process(int state) and +// add your own switch statement. If you want to delegate to +// Task::Process, you can effectively delegate to its switch statement. +// No fancy method pointers or such - this is all just pretty low tech, +// easy to debug, and fast. +// + +namespace buzz { + +class TaskRunner; + +// A task executes a sequence of steps + +class Task; +class RootTask; + +class Task { +public: + Task(Task * parent); + virtual ~Task() {} + + void Start(); + void Step(); + int GetState() const { return state_; } + bool HasError() const { return (GetState() == STATE_ERROR); } + bool Blocked() const { return blocked_; } + bool IsDone() const { return done_; } + unsigned long long ElapsedTime(); + virtual void Poll() {} + + Task * GetParent() { return parent_; } + TaskRunner * GetRunner() { return runner_; } + virtual Task * GetParent(int code) { return parent_->GetParent(code); } + + // Called from outside to stop task without any more callbacks + void Abort(bool nowake = false); + + // For managing children + bool AllChildrenDone(); + bool AnyChildError(); + + +protected: + + enum { + STATE_BLOCKED = -1, + STATE_INIT = 0, + STATE_START = 1, + STATE_DONE = 2, + STATE_ERROR = 3, + STATE_RESPONSE = 4, + STATE_NEXT = 5, // Subclasses which need more states start here and higher + }; + + // Called inside the task to signal that the task may be unblocked + void Wake(); + + // Called inside to advise that the task should wake and signal an error + void Error(); + + unsigned long long CurrentTime(); + + virtual std::string GetStateName(int state) const; + virtual int Process(int state); + virtual void Stop(); + virtual int ProcessStart() = 0; + virtual int ProcessResponse() { return STATE_DONE; } + + // for managing children (if any) + void AddChild(Task * child); + void AbortAllChildren(); + +private: + void Done(); + void OnChildStopped(Task * child); + + int state_; + Task * parent_; + TaskRunner * runner_; + bool blocked_; + bool done_; + bool aborted_; + bool busy_; + bool error_; + bool child_error_; + unsigned long long start_time_; + + // for managing children + typedef std::set<Task *> ChildSet; + ChildSet children_; + +}; + + + + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc new file mode 100644 index 00000000..b5ecc55e --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.cc @@ -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 <algorithm> + + +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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.h new file mode 100644 index 00000000..eab16eb9 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/taskrunner.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef _TASKRUNNER_H_ +#define _TASKRUNNER_H_ + +#include <vector> + +#include "talk/base/sigslot.h" +#include "talk/base/task.h" + + +namespace buzz { + + +class Task; + +class TaskRunner : public Task, public sigslot::has_slots<> { +public: + TaskRunner() : Task(NULL), tasks_running_(false) {} + virtual ~TaskRunner(); + + virtual void WakeTasks() = 0; + virtual unsigned long long CurrentTime() = 0 ; + + void StartTask(Task * task); + void RunTasks(); + void PollTasks(); + + // dummy state machine - never run. + virtual int ProcessStart() { return STATE_DONE; } + +private: + std::vector<Task *> tasks_; + bool tasks_running_; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc new file mode 100644 index 00000000..8f18a992 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.cc @@ -0,0 +1,273 @@ +/* + * 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 <sys/time.h> +} +#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); + 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.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.h new file mode 100644 index 00000000..56c23384 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/thread.h @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include "talk/base/messagequeue.h" + +#include <algorithm> +#include <list> +#include <vector> + +#ifdef POSIX +#include <pthread.h> +#endif + +#ifdef WIN32 +#include "talk/base/win32.h" +#endif + +namespace cricket { + +class Thread; + +class ThreadManager { +public: + ThreadManager(); + ~ThreadManager(); + + static Thread *CurrentThread(); + static void SetCurrent(Thread *thread); + void Add(Thread *thread); + void Remove(Thread *thread); + +private: + Thread *main_thread_; + std::vector<Thread *> threads_; + CriticalSection crit_; + +#ifdef POSIX + static pthread_key_t key_; +#endif + +#ifdef WIN32 + static DWORD key_; +#endif +}; + +class Thread; + +struct _SendMessage { + _SendMessage() {} + Thread *thread; + Message msg; + bool *ready; +}; + +class Thread : public MessageQueue { +public: + Thread(SocketServer* ss = 0); + virtual ~Thread(); + + static inline Thread* Current() { + return ThreadManager::CurrentThread(); + } + inline bool IsCurrent() const { + return (ThreadManager::CurrentThread() == this); + } + + virtual void Start(); + virtual void Stop(); + virtual void Loop(int cms = -1); + virtual void Send(MessageHandler *phandler, uint32 id = 0, + MessageData *pdata = NULL); + + // From MessageQueue + virtual void Clear(MessageHandler *phandler, uint32 id = (uint32)-1); + virtual void ReceiveSends(); + +#ifdef WIN32 + HANDLE GetHandle() { + return thread_; + } +#endif + +private: + static void *PreLoop(void *pv); + void Join(); + + std::list<_SendMessage> sendlist_; + bool started_; + bool has_sends_; + +#ifdef POSIX + pthread_t thread_; +#endif + +#ifdef WIN32 + HANDLE thread_; +#endif + + friend class ThreadManager; +}; + +// AutoThread automatically installs itself at construction +// uninstalls at destruction, if a Thread object is +// _not already_ associated with the current OS thread. + +class AutoThread : public Thread { +public: + AutoThread(SocketServer* ss = 0); + virtual ~AutoThread(); +}; + +} // namespace cricket + +#endif // __THREAD_H__ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h b/kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h new file mode 100644 index 00000000..99ba2fdc --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/base/winping.h @@ -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. + */ + +#ifndef _WINPING_H_ +#define _WINPING_H_ + +#ifdef WIN32 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "talk/base/basictypes.h" + +#include <winsock2.h> +#define _WINSOCKAPI_ +#include <windows.h> +#undef SetPort + +// This class wraps a Win32 API for doing ICMP pinging. This API, unlike the +// the normal socket APIs (as implemented on Win9x), will return an error if +// an ICMP packet with the dont-fragment bit set is too large. This means this +// class can be used to detect the MTU to a given address. + +typedef struct ip_option_information { + UCHAR Ttl; // Time To Live + UCHAR Tos; // Type Of Service + UCHAR Flags; // IP header flags + UCHAR OptionsSize; // Size in bytes of options data + PUCHAR OptionsData; // Pointer to options data +} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION; + +typedef HANDLE (WINAPI *PIcmpCreateFile)(); + +typedef BOOL (WINAPI *PIcmpCloseHandle)(HANDLE icmp_handle); + +typedef DWORD (WINAPI *PIcmpSendEcho)( + HANDLE IcmpHandle, + ULONG DestinationAddress, + LPVOID RequestData, + WORD RequestSize, + PIP_OPTION_INFORMATION RequestOptions, + LPVOID ReplyBuffer, + DWORD ReplySize, + DWORD Timeout); + +class WinPing { +public: + WinPing(); + ~WinPing(); + + // Determines whether the class was initialized correctly. + bool IsValid() { return valid_; } + + // Attempts to send a ping with the given parameters. + enum PingResult { PING_FAIL, PING_TOO_LARGE, PING_TIMEOUT, PING_SUCCESS }; + PingResult Ping( + uint32 ip, uint32 data_size, uint32 timeout_millis, uint8 ttl, + bool allow_fragments); + +private: + HMODULE dll_; + HANDLE hping_; + PIcmpCreateFile create_; + PIcmpCloseHandle close_; + PIcmpSendEcho send_; + char* data_; + uint32 dlen_; + char* reply_; + uint32 rlen_; + bool valid_; +}; + +#endif // WIN32 + +#endif // _WINPING_H_ + |