commit b720a4c397c0060d6b2a1de6b888653fc0a4a625
Author: Tom "spot" Callaway <tcallawa(a)redhat.com>
Date: Fri Apr 1 01:26:49 2011 -0400
0.5.2
.gitignore | 1 +
libjingle-0.5.2-chromium12-changes.patch | 6829 +++++++++++++++++++++++++++
libjingle-0.5.2-compilefix.patch | 13 +
libjingle-0.5.2-devicemanager-alsafix.patch | 30 +
libjingle.spec | 16 +-
sources | 2 +-
6 files changed, 6887 insertions(+), 4 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 8507512..9c6c477 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
libjingle-0.3.12.tar.gz
/libjingle-0.5.1.zip
+/libjingle-0.5.2.zip
diff --git a/libjingle-0.5.2-chromium12-changes.patch
b/libjingle-0.5.2-chromium12-changes.patch
new file mode 100644
index 0000000..a888023
--- /dev/null
+++ b/libjingle-0.5.2-chromium12-changes.patch
@@ -0,0 +1,6829 @@
+diff -upN libjingle-0.5.2/talk/base/asyncpacketsocket.cc.chromium12
libjingle-0.5.2/talk/base/asyncpacketsocket.cc
+--- libjingle-0.5.2/talk/base/asyncpacketsocket.cc.chromium12 2011-01-11
19:25:48.000000000 -0500
++++ libjingle-0.5.2/talk/base/asyncpacketsocket.cc 1969-12-31 19:00:00.000000000 -0500
+@@ -1,92 +0,0 @@
+-/*
+- * libjingle
+- * Copyright 2004--2005, Google Inc.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions are met:
+- *
+- * 1. Redistributions of source code must retain the above copyright notice,
+- * this list of conditions and the following disclaimer.
+- * 2. Redistributions in binary form must reproduce the above copyright notice,
+- * this list of conditions and the following disclaimer in the documentation
+- * and/or other materials provided with the distribution.
+- * 3. The name of the author may not be used to endorse or promote products
+- * derived from this software without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+- */
+-
+-#if defined(_MSC_VER) && _MSC_VER < 1300
+-#pragma warning(disable:4786)
+-#endif
+-
+-#include "talk/base/asyncpacketsocket.h"
+-
+-namespace talk_base {
+-
+-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();
+-}
+-
+-Socket::ConnState AsyncPacketSocket::GetState() const {
+- return socket_->GetState();
+-}
+-
+-int AsyncPacketSocket::GetOption(Socket::Option opt, int* value) {
+- return socket_->GetOption(opt, value);
+-}
+-
+-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 talk_base
+diff -upN libjingle-0.5.2/talk/base/asyncpacketsocket.h.chromium12
libjingle-0.5.2/talk/base/asyncpacketsocket.h
+--- libjingle-0.5.2/talk/base/asyncpacketsocket.h.chromium12 2011-01-11
19:25:48.000000000 -0500
++++ libjingle-0.5.2/talk/base/asyncpacketsocket.h 2011-03-30 21:51:32.694287001 -0400
+@@ -28,38 +28,61 @@
+ #ifndef TALK_BASE_ASYNCPACKETSOCKET_H_
+ #define TALK_BASE_ASYNCPACKETSOCKET_H_
+
+-#include "talk/base/asyncsocket.h"
++#include "talk/base/sigslot.h"
++#include "talk/base/socket.h"
+
+ namespace talk_base {
+
+-// Provides the ability to receive packets asynchronously. Sends are not
++// 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:
+- explicit AsyncPacketSocket(AsyncSocket* socket);
+- virtual ~AsyncPacketSocket();
++ AsyncPacketSocket() { }
++ 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 Socket::ConnState GetState() const;
+- virtual int GetOption(Socket::Option opt, int* value);
+- 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;
++ // Returns current local address. If port or IP address is not
++ // assigned yet, then they set to 0 in the result and |allocated| is
++ // set to false. Otherwise |allocated| is set to true.
++ virtual SocketAddress GetLocalAddress(bool* allocated) const = 0;
+
+- protected:
+- AsyncSocket* socket_;
++ // Returns remote address. Returns zeroes if this is not a client TCP socket.
++ virtual SocketAddress GetRemoteAddress() const = 0;
++
++ // Send a packet.
++ virtual int Send(const void *pv, size_t cb) = 0;
++ virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) = 0;
++
++ // Close the socket.
++ virtual int Close() = 0;
++
++ // Returns current state of the socket.
++ virtual Socket::ConnState GetState() const = 0;
++
++ // Get/set options.
++ virtual int GetOption(Socket::Option opt, int* value) = 0;
++ virtual int SetOption(Socket::Option opt, int value) = 0;
++
++ // Get/Set current error.
++ // TODO: Do we really need SetError() here?
++ virtual int GetError() const = 0;
++ virtual void SetError(int error) = 0;
++
++ // Emitted after address for the socket is allocated.
++ sigslot::signal2<AsyncPacketSocket*, const SocketAddress&>
SignalAddressReady;
++
++ // Emitted each time a packet is read. Used only for UDP and
++ // connected TCP sockets.
++ sigslot::signal4<AsyncPacketSocket*, const char*, size_t,
++ const SocketAddress&> SignalReadPacket;
++
++ // Used only for connected TCP sockets.
++ sigslot::signal1<AsyncPacketSocket*> SignalConnect;
++ sigslot::signal2<AsyncPacketSocket*, int> SignalClose;
++
++ // Used only for listening TCP sockets.
++ sigslot::signal2<AsyncPacketSocket*, AsyncPacketSocket*> SignalNewConnection;
++
++ private:
+ DISALLOW_EVIL_CONSTRUCTORS(AsyncPacketSocket);
+ };
+
+diff -upN libjingle-0.5.2/talk/base/asynctcpsocket.cc.chromium12
libjingle-0.5.2/talk/base/asynctcpsocket.cc
+--- libjingle-0.5.2/talk/base/asynctcpsocket.cc.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/asynctcpsocket.cc 2011-03-30 21:51:32.694287001 -0400
+@@ -39,20 +39,30 @@
+
+ namespace talk_base {
+
+-const size_t MAX_PACKET_SIZE = 64 * 1024;
++static const size_t MAX_PACKET_SIZE = 64 * 1024;
+
+ typedef uint16 PacketLength;
+-const size_t PKT_LEN_SIZE = sizeof(PacketLength);
++static const size_t PKT_LEN_SIZE = sizeof(PacketLength);
+
+-const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE;
++static const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE;
+
+-AsyncTCPSocket* AsyncTCPSocket::Create(SocketFactory* factory) {
++static const int LISTEN_BACKLOG = 5;
++
++AsyncTCPSocket* AsyncTCPSocket::Create(SocketFactory* factory, bool listen) {
+ AsyncSocket* sock = factory->CreateAsyncSocket(SOCK_STREAM);
+- return (sock) ? new AsyncTCPSocket(sock) : NULL;
++ // This will still return a socket even if we failed to listen on
++ // it. It is neccessary because even if we can't accept new
++ // connections on this socket, the corresponding port is still
++ // useful for outgoing connections.
++ //
++ // TODO: It might be better to pass listen() error to the
++ // upper layer and let it handle the problem.
++ return (sock) ? new AsyncTCPSocket(sock, listen) : NULL;
+ }
+
+-AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket)
+- : AsyncPacketSocket(socket),
++AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket, bool listen)
++ : socket_(socket),
++ listen_(listen),
+ insize_(BUF_SIZE),
+ inpos_(0),
+ outsize_(BUF_SIZE),
+@@ -60,11 +70,17 @@ AsyncTCPSocket::AsyncTCPSocket(AsyncSock
+ inbuf_ = new char[insize_];
+ outbuf_ = new char[outsize_];
+
+- ASSERT(socket_ != NULL);
++ ASSERT(socket_.get() != 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);
++
++ if (listen_) {
++ if (socket_->Listen(LISTEN_BACKLOG) < 0) {
++ LOG(LS_ERROR) << "Listen() failed with error " <<
socket_->GetError();
++ }
++ }
+ }
+
+ AsyncTCPSocket::~AsyncTCPSocket() {
+@@ -72,6 +88,16 @@ AsyncTCPSocket::~AsyncTCPSocket() {
+ delete [] outbuf_;
+ }
+
++SocketAddress AsyncTCPSocket::GetLocalAddress(bool* allocated) const {
++ if (allocated)
++ *allocated = true;
++ return socket_->GetLocalAddress();
++}
++
++SocketAddress AsyncTCPSocket::GetRemoteAddress() const {
++ return socket_->GetRemoteAddress();
++}
++
+ int AsyncTCPSocket::Send(const void *pv, size_t cb) {
+ if (cb > MAX_PACKET_SIZE) {
+ socket_->SetError(EMSGSIZE);
+@@ -108,6 +134,30 @@ int AsyncTCPSocket::SendTo(const void *p
+ return -1;
+ }
+
++int AsyncTCPSocket::Close() {
++ return socket_->Close();
++}
++
++Socket::ConnState AsyncTCPSocket::GetState() const {
++ return socket_->GetState();
++}
++
++int AsyncTCPSocket::GetOption(Socket::Option opt, int* value) {
++ return socket_->GetOption(opt, value);
++}
++
++int AsyncTCPSocket::SetOption(Socket::Option opt, int value) {
++ return socket_->SetOption(opt, value);
++}
++
++int AsyncTCPSocket::GetError() const {
++ return socket_->GetError();
++}
++
++void AsyncTCPSocket::SetError(int error) {
++ return socket_->SetError(error);
++}
++
+ int AsyncTCPSocket::SendRaw(const void * pv, size_t cb) {
+ if (outpos_ + cb > outsize_) {
+ socket_->SetError(EMSGSIZE);
+@@ -134,7 +184,7 @@ void AsyncTCPSocket::ProcessInput(char *
+ if (len < PKT_LEN_SIZE + pkt_len)
+ return;
+
+- SignalReadPacket(data + PKT_LEN_SIZE, pkt_len, remote_addr, this);
++ SignalReadPacket(this, data + PKT_LEN_SIZE, pkt_len, remote_addr);
+
+ len -= PKT_LEN_SIZE + pkt_len;
+ if (len > 0) {
+@@ -165,30 +215,46 @@ void AsyncTCPSocket::OnConnectEvent(Asyn
+ }
+
+ void AsyncTCPSocket::OnReadEvent(AsyncSocket* socket) {
+- ASSERT(socket == socket_);
++ ASSERT(socket_.get() == socket);
+
+- int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_);
+- if (len < 0) {
+- // TODO: Do something better like forwarding the error to the user.
+- if (!socket_->IsBlocking()) {
+- LOG_ERR(LS_ERROR) << "recvfrom";
++ if (listen_) {
++ talk_base::SocketAddress address;
++ talk_base::AsyncSocket* new_socket = socket->Accept(&address);
++ if (!new_socket) {
++ // TODO: Do something better like forwarding the error
++ // to the user.
++ LOG(LS_ERROR) << "TCP accept failed with error " <<
socket_->GetError();
++ return;
+ }
+- return;
+- }
+
+- inpos_ += len;
++ SignalNewConnection(this, new AsyncTCPSocket(new_socket, false));
+
+- ProcessInput(inbuf_, inpos_);
++ // Prime a read event in case data is waiting.
++ new_socket->SignalReadEvent(new_socket);
++ } else {
++ int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_);
++ if (len < 0) {
++ // TODO: Do something better like forwarding the error to the user.
++ if (!socket_->IsBlocking()) {
++ LOG(LS_ERROR) << "Recv() returned error: " <<
socket_->GetError();
++ }
++ return;
++ }
+
+- if (inpos_ >= insize_) {
+- LOG(INFO) << "input buffer overflow";
+- ASSERT(false);
+- inpos_ = 0;
++ inpos_ += len;
++
++ ProcessInput(inbuf_, inpos_);
++
++ if (inpos_ >= insize_) {
++ LOG(LS_ERROR) << "input buffer overflow";
++ ASSERT(false);
++ inpos_ = 0;
++ }
+ }
+ }
+
+ void AsyncTCPSocket::OnWriteEvent(AsyncSocket* socket) {
+- ASSERT(socket == socket_);
++ ASSERT(socket_.get() == socket);
+
+ if (outpos_ > 0) {
+ Flush();
+diff -upN libjingle-0.5.2/talk/base/asynctcpsocket.h.chromium12
libjingle-0.5.2/talk/base/asynctcpsocket.h
+--- libjingle-0.5.2/talk/base/asynctcpsocket.h.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/asynctcpsocket.h 2011-03-30 21:51:32.695287001 -0400
+@@ -29,6 +29,7 @@
+ #define TALK_BASE_ASYNCTCPSOCKET_H_
+
+ #include "talk/base/asyncpacketsocket.h"
++#include "talk/base/scoped_ptr.h"
+ #include "talk/base/socketfactory.h"
+
+ namespace talk_base {
+@@ -38,15 +39,21 @@ namespace talk_base {
+ // buffer them in user space.
+ class AsyncTCPSocket : public AsyncPacketSocket {
+ public:
+- static AsyncTCPSocket* Create(SocketFactory* factory);
+- explicit AsyncTCPSocket(AsyncSocket* socket);
++ static AsyncTCPSocket* Create(SocketFactory* factory, bool listen);
++ explicit AsyncTCPSocket(AsyncSocket* socket, bool listen);
+ 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;
++ virtual SocketAddress GetLocalAddress(bool* allocated) const;
++ virtual SocketAddress GetRemoteAddress() const;
++ 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 Socket::ConnState GetState() const;
++ virtual int GetOption(Socket::Option opt, int* value);
++ virtual int SetOption(Socket::Option opt, int value);
++ virtual int GetError() const;
++ virtual void SetError(int error);
+
+ protected:
+ int SendRaw(const void* pv, size_t cb);
+@@ -61,8 +68,12 @@ class AsyncTCPSocket : public AsyncPacke
+ void OnWriteEvent(AsyncSocket* socket);
+ void OnCloseEvent(AsyncSocket* socket, int error);
+
++ scoped_ptr<AsyncSocket> socket_;
++ bool listen_;
+ char* inbuf_, * outbuf_;
+ size_t insize_, inpos_, outsize_, outpos_;
++
++ DISALLOW_EVIL_CONSTRUCTORS(AsyncTCPSocket);
+ };
+
+ } // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/asyncudpsocket.cc.chromium12
libjingle-0.5.2/talk/base/asyncudpsocket.cc
+--- libjingle-0.5.2/talk/base/asyncudpsocket.cc.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/asyncudpsocket.cc 2011-03-30 21:51:32.695287001 -0400
+@@ -34,11 +34,23 @@
+
+ namespace talk_base {
+
+-const int BUF_SIZE = 64 * 1024;
++static const int BUF_SIZE = 64 * 1024;
++
++AsyncUDPSocket* AsyncUDPSocket::Create(SocketFactory* factory,
++ const SocketAddress& address) {
++ scoped_ptr<AsyncSocket> socket(factory->CreateAsyncSocket(SOCK_DGRAM));
++ if (!socket.get())
++ return NULL;
++ if (socket->Bind(address)) {
++ LOG(LS_INFO) << "Failed to bind UDP socket " <<
socket->GetError();
++ return NULL;
++ }
++ return new AsyncUDPSocket(socket.release());
++}
+
+ AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket)
+- : AsyncPacketSocket(socket) {
+- ASSERT(socket_ != NULL);
++ : socket_(socket) {
++ ASSERT(socket_.get() != NULL);
+ size_ = BUF_SIZE;
+ buf_ = new char[size_];
+
+@@ -50,8 +62,51 @@ AsyncUDPSocket::~AsyncUDPSocket() {
+ delete [] buf_;
+ }
+
++SocketAddress AsyncUDPSocket::GetLocalAddress(bool* allocated) const {
++ if (allocated)
++ *allocated = true;
++ return socket_->GetLocalAddress();
++}
++
++SocketAddress AsyncUDPSocket::GetRemoteAddress() const {
++ return socket_->GetRemoteAddress();
++}
++
++int AsyncUDPSocket::Send(const void *pv, size_t cb) {
++ return socket_->Send(pv, cb);
++}
++
++int AsyncUDPSocket::SendTo(
++ const void *pv, size_t cb, const SocketAddress& addr) {
++ return socket_->SendTo(pv, cb, addr);
++}
++
++int AsyncUDPSocket::Close() {
++ return socket_->Close();
++}
++
++Socket::ConnState AsyncUDPSocket::GetState() const {
++ return socket_->GetState();
++}
++
++int AsyncUDPSocket::GetOption(Socket::Option opt, int* value) {
++ return socket_->GetOption(opt, value);
++}
++
++int AsyncUDPSocket::SetOption(Socket::Option opt, int value) {
++ return socket_->SetOption(opt, value);
++}
++
++int AsyncUDPSocket::GetError() const {
++ return socket_->GetError();
++}
++
++void AsyncUDPSocket::SetError(int error) {
++ return socket_->SetError(error);
++}
++
+ void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) {
+- ASSERT(socket == socket_);
++ ASSERT(socket_.get() == socket);
+
+ SocketAddress remote_addr;
+ int len = socket_->RecvFrom(buf_, size_, &remote_addr);
+@@ -68,7 +123,7 @@ void AsyncUDPSocket::OnReadEvent(AsyncSo
+
+ // 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);
++ SignalReadPacket(this, buf_, (size_t)len, remote_addr);
+ }
+
+ } // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/asyncudpsocket.h.chromium12
libjingle-0.5.2/talk/base/asyncudpsocket.h
+--- libjingle-0.5.2/talk/base/asyncudpsocket.h.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/asyncudpsocket.h 2011-03-30 21:51:32.695287001 -0400
+@@ -29,6 +29,7 @@
+ #define TALK_BASE_ASYNCUDPSOCKET_H_
+
+ #include "talk/base/asyncpacketsocket.h"
++#include "talk/base/scoped_ptr.h"
+ #include "talk/base/socketfactory.h"
+
+ namespace talk_base {
+@@ -39,26 +40,32 @@ class AsyncUDPSocket : public AsyncPacke
+ public:
+ // Creates a new socket for sending asynchronous UDP packets using an
+ // asynchronous socket from the given factory.
+- static AsyncUDPSocket* Create(SocketFactory* factory) {
+- AsyncSocket* sock = factory->CreateAsyncSocket(SOCK_DGRAM);
+- return (sock) ? new AsyncUDPSocket(sock) : NULL;
+- }
++ static AsyncUDPSocket* Create(SocketFactory* factory,
++ const SocketAddress& address);
+ explicit AsyncUDPSocket(AsyncSocket* socket);
+ virtual ~AsyncUDPSocket();
+
++ virtual SocketAddress GetLocalAddress(bool* allocated) const;
++ virtual SocketAddress GetRemoteAddress() const;
++ 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 Socket::ConnState GetState() const;
++ virtual int GetOption(Socket::Option opt, int* value);
++ virtual int SetOption(Socket::Option opt, int value);
++ virtual int GetError() const;
++ virtual void SetError(int error);
++
+ private:
+ // Called when the underlying socket is ready to be read from.
+ void OnReadEvent(AsyncSocket* socket);
+
++ scoped_ptr<AsyncSocket> socket_;
+ char* buf_;
+ size_t size_;
+ };
+
+-// TODO: This is now deprecated. Remove it.
+-inline AsyncUDPSocket* CreateAsyncUDPSocket(SocketFactory* factory) {
+- return AsyncUDPSocket::Create(factory);
+-}
+-
+ } // namespace talk_base
+
+ #endif // TALK_BASE_ASYNCUDPSOCKET_H_
+diff -upN libjingle-0.5.2/talk/base/basicpacketsocketfactory.cc.chromium12
libjingle-0.5.2/talk/base/basicpacketsocketfactory.cc
+--- libjingle-0.5.2/talk/base/basicpacketsocketfactory.cc.chromium12 2011-03-30
21:51:32.695287001 -0400
++++ libjingle-0.5.2/talk/base/basicpacketsocketfactory.cc 2011-03-30 21:51:32.695287001
-0400
+@@ -0,0 +1,159 @@
++/*
++ * libjingle
++ * Copyright 2011, 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/basicpacketsocketfactory.h"
++
++#include "talk/base/asyncudpsocket.h"
++#include "talk/base/asynctcpsocket.h"
++#include "talk/base/logging.h"
++#include "talk/base/socketadapters.h"
++#include "talk/base/thread.h"
++
++namespace talk_base {
++
++BasicPacketSocketFactory::BasicPacketSocketFactory(
++ Thread* thread)
++ : thread_(thread),
++ socket_factory_(NULL) {
++}
++
++BasicPacketSocketFactory::BasicPacketSocketFactory(
++ SocketFactory* socket_factory)
++ : thread_(NULL),
++ socket_factory_(socket_factory) {
++}
++
++BasicPacketSocketFactory::~BasicPacketSocketFactory() {
++}
++
++AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket(
++ const SocketAddress& address, int min_port, int max_port) {
++ // UDP sockets are simple.
++ talk_base::AsyncSocket* socket =
++ socket_factory()->CreateAsyncSocket(SOCK_DGRAM);
++ if (!socket) {
++ return NULL;
++ }
++ if (BindSocket(socket, address, min_port, max_port) < 0) {
++ LOG(LS_ERROR) << "UDP bind failed with error "
++ << socket->GetError();
++ delete socket;
++ return NULL;
++ }
++ return new talk_base::AsyncUDPSocket(socket);
++}
++
++AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket(
++ const SocketAddress& local_address, int min_port, int max_port,
++ bool listen, bool ssl) {
++ talk_base::AsyncSocket* socket =
++ socket_factory()->CreateAsyncSocket(SOCK_STREAM);
++ if (!socket) {
++ return NULL;
++ }
++
++ if (BindSocket(socket, local_address, min_port, max_port) < 0) {
++ LOG(LS_ERROR) << "TCP bind failed with error "
++ << socket->GetError();
++ delete socket;
++ return NULL;
++ }
++
++ // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
++ if (ssl) {
++ socket = new talk_base::AsyncSSLSocket(socket);
++ }
++
++ return new talk_base::AsyncTCPSocket(socket, true);
++}
++
++AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
++ const SocketAddress& local_address, const SocketAddress& remote_address,
++ const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl) {
++ talk_base::AsyncSocket* socket =
++ socket_factory()->CreateAsyncSocket(SOCK_STREAM);
++ if (!socket) {
++ return NULL;
++ }
++
++ if (BindSocket(socket, local_address, 0, 0) < 0) {
++ LOG(LS_ERROR) << "TCP bind failed with error "
++ << socket->GetError();
++ delete socket;
++ return NULL;
++ }
++
++ // If using a proxy, wrap the socket in a proxy socket.
++ if (proxy_info.type == talk_base::PROXY_SOCKS5) {
++ socket = new talk_base::AsyncSocksProxySocket(
++ socket, proxy_info.address, proxy_info.username, proxy_info.password);
++ } else if (proxy_info.type == talk_base::PROXY_HTTPS) {
++ socket = new talk_base::AsyncHttpsProxySocket(
++ socket, user_agent, proxy_info.address,
++ proxy_info.username, proxy_info.password);
++ }
++
++ // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
++ if (ssl) {
++ socket = new talk_base::AsyncSSLSocket(socket);
++ }
++
++ if (socket->Connect(remote_address) < 0) {
++ LOG(LS_ERROR) << "TCP connect failed with error "
++ << socket->GetError();
++ delete socket;
++ return NULL;
++ }
++
++ // Finally, wrap that socket in a TCP packet socket.
++ return new talk_base::AsyncTCPSocket(socket, false);
++}
++
++int BasicPacketSocketFactory::BindSocket(
++ AsyncSocket* socket, const SocketAddress& local_address,
++ int min_port, int max_port) {
++ int ret = -1;
++ if (min_port == 0 && max_port == 0) {
++ // If there's no port range, let the OS pick a port for us.
++ ret = socket->Bind(local_address);
++ } else {
++ // Otherwise, try to find a port in the provided range.
++ for (int port = min_port; ret < 0 && port <= max_port; ++port) {
++ ret = socket->Bind(talk_base::SocketAddress(local_address.ip(), port));
++ }
++ }
++ return ret;
++}
++
++SocketFactory* BasicPacketSocketFactory::socket_factory() {
++ if (thread_)
++ return thread_->socketserver();
++ else
++ return socket_factory_;
++}
++
++} // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/basicpacketsocketfactory.h.chromium12
libjingle-0.5.2/talk/base/basicpacketsocketfactory.h
+--- libjingle-0.5.2/talk/base/basicpacketsocketfactory.h.chromium12 2011-03-30
21:51:32.696287001 -0400
++++ libjingle-0.5.2/talk/base/basicpacketsocketfactory.h 2011-03-30 21:51:32.696287001
-0400
+@@ -0,0 +1,67 @@
++/*
++ * libjingle
++ * Copyright 2011, 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 TALK_BASE_BASICPACKETSOCKETFACTORY_H_
++#define TALK_BASE_BASICPACKETSOCKETFACTORY_H_
++
++#include "talk/base/asyncsocket.h"
++#include "talk/base/packetsocketfactory.h"
++
++namespace talk_base {
++
++class AsyncSocket;
++class SocketFactory;
++class Thread;
++
++class BasicPacketSocketFactory : public PacketSocketFactory {
++ public:
++ explicit BasicPacketSocketFactory(Thread* thread);
++ explicit BasicPacketSocketFactory(SocketFactory* socket_factory);
++ virtual ~BasicPacketSocketFactory();
++
++ virtual AsyncPacketSocket* CreateUdpSocket(
++ const SocketAddress& local_address, int min_port, int max_port);
++ virtual AsyncPacketSocket* CreateServerTcpSocket(
++ const SocketAddress& local_address, int min_port, int max_port,
++ bool listen, bool ssl);
++ virtual AsyncPacketSocket* CreateClientTcpSocket(
++ const SocketAddress& local_address, const SocketAddress& remote_address,
++ const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl);
++
++ private:
++ int BindSocket(AsyncSocket* socket, const SocketAddress& local_address,
++ int min_port, int max_port);
++
++ SocketFactory* socket_factory();
++
++ Thread* thread_;
++ SocketFactory* socket_factory_;
++};
++
++} // namespace talk_base
++
++#endif // TALK_BASE_BASICPACKETSOCKETFACTORY_H_
+diff -upN libjingle-0.5.2/talk/base/basictypes.h.chromium12
libjingle-0.5.2/talk/base/basictypes.h
+--- libjingle-0.5.2/talk/base/basictypes.h.chromium12 2011-03-30 21:51:32.681287001
-0400
++++ libjingle-0.5.2/talk/base/basictypes.h 2011-03-30 21:51:32.696287001 -0400
+@@ -1,6 +1,6 @@
+ /*
+ * libjingle
+- * Copyright 2004--2005, Google Inc.
++ * Copyright 2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+@@ -97,6 +97,12 @@ extern "C++" {
+ const int kForever = -1;
+ }
+
++// Detect compiler is for x86 or x64.
++#if defined(__x86_64__) || defined(_M_X64) || \
++ defined(__i386__) || defined(_M_IX86)
++#define CPU_X86 1
++#endif
++
+ #ifdef WIN32
+ #define alignof(t) __alignof(t)
+ #else // !WIN32
+diff -upN libjingle-0.5.2/talk/base/linux.cc.chromium12
libjingle-0.5.2/talk/base/linux.cc
+--- libjingle-0.5.2/talk/base/linux.cc.chromium12 2011-03-30 21:51:32.691287001 -0400
++++ libjingle-0.5.2/talk/base/linux.cc 2011-03-30 21:51:32.696287001 -0400
+@@ -1,6 +1,30 @@
+-// Copyright 2008 Google Inc. All Rights Reserved.
++/*
++ * libjingle
++ * Copyright 2011, 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/linux.h"
+
+ #ifdef LINUX
+@@ -25,25 +49,50 @@ ProcCpuInfo::~ProcCpuInfo() {
+
+ bool ProcCpuInfo::LoadFromSystem() {
+ ConfigParser procfs;
+- if (!procfs.Open(kCpuInfoFile))
++ if (!procfs.Open(kCpuInfoFile)) {
+ return false;
++ }
+ return procfs.Parse(&cpu_info_);
+ };
+
+ bool ProcCpuInfo::GetNumCpus(int *num) {
+- if (cpu_info_.size() == 0)
++ if (cpu_info_.size() == 0) {
+ return false;
++ }
+ *num = cpu_info_.size();
+ return true;
+ }
+
++bool ProcCpuInfo::GetNumPhysicalCpus(int *num) {
++ if (cpu_info_.size() == 0) {
++ return false;
++ }
++ int total_cores = 0;
++ int physical_id_prev = -1;
++ int cpus = static_cast<int>(cpu_info_.size());
++ for (int i = 0; i < cpus; ++i) {
++ int physical_id;
++ if (GetCpuIntValue(i, "physical id", &physical_id)) {
++ if (physical_id != physical_id_prev) {
++ physical_id_prev = physical_id;
++ int cores;
++ if (GetCpuIntValue(i, "cpu cores", &cores)) {
++ total_cores += cores;
++ }
++ }
++ }
++ }
++ return total_cores;
++}
++
+ bool ProcCpuInfo::GetCpuStringValue(int cpu_id, const std::string& key,
+ std::string *result) {
+ if (cpu_id >= static_cast<int>(cpu_info_.size()))
+ return false;
+ ConfigParser::SimpleMap::iterator iter = cpu_info_[cpu_id].find(key);
+- if (iter == cpu_info_[cpu_id].end())
++ if (iter == cpu_info_[cpu_id].end()) {
+ return false;
++ }
+ *result = iter->second;
+ return true;
+ }
+@@ -67,8 +116,9 @@ ConfigParser::~ConfigParser() {}
+
+ bool ConfigParser::Open(const std::string& filename) {
+ FileStream *fs = new FileStream();
+- if (!fs->Open(filename, "r"))
++ if (!fs->Open(filename, "r")) {
+ return false;
++ }
+ instream_.reset(fs);
+ return true;
+ }
+@@ -101,20 +151,24 @@ bool ConfigParser::ParseLine(std::string
+ // Parses the next line in the filestream and places the found key-value
+ // pair into key and val.
+ std::string line;
+- if ((instream_->ReadLine(&line)) == EOF)
++ if ((instream_->ReadLine(&line)) == EOF) {
+ return false;
++ }
+ std::vector<std::string> tokens;
+- if (2 != split(line, ':', &tokens))
++ if (2 != split(line, ':', &tokens)) {
+ return false;
++ }
+ // Removes whitespace at the end of Key name
+ size_t pos = tokens[0].length() - 1;
+- while ((pos > 0) && isspace(tokens[0][pos]))
++ while ((pos > 0) && isspace(tokens[0][pos])) {
+ pos--;
++ }
+ tokens[0].erase(pos + 1);
+ // Removes whitespace at the start of value
+ pos = 0;
+- while (pos < tokens[1].length() && isspace(tokens[1][pos]))
++ while (pos < tokens[1].length() && isspace(tokens[1][pos])) {
+ pos++;
++ }
+ tokens[1].erase(0, pos);
+ *key = tokens[0];
+ *value = tokens[1];
+diff -upN libjingle-0.5.2/talk/base/linux.h.chromium12 libjingle-0.5.2/talk/base/linux.h
+--- libjingle-0.5.2/talk/base/linux.h.chromium12 2011-03-30 21:51:32.691287001 -0400
++++ libjingle-0.5.2/talk/base/linux.h 2011-03-30 21:51:32.696287001 -0400
+@@ -1,5 +1,29 @@
+-// Copyright 2008 Google Inc. All Rights Reserved.
+-
++/*
++ * libjingle
++ * Copyright 2011, 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 TALK_BASE_LINUX_H_
+ #define TALK_BASE_LINUX_H_
+@@ -70,9 +94,12 @@ class ProcCpuInfo {
+ // returns false; if it succeeds, it returns true.
+ virtual bool LoadFromSystem();
+
+- // Obtains the number of CPUs and places the value num.
++ // Obtains the number of logical CPU threads and places the value num.
+ virtual bool GetNumCpus(int *num);
+
++ // Obtains the number of physical CPU cores and places the value num.
++ virtual bool GetNumPhysicalCpus(int *num);
++
+ // Looks for the CPU proc item with the given name for the given CPU number
+ // and places the string value in result.
+ virtual bool GetCpuStringValue(int cpu_id, const std::string& key,
+diff -upN libjingle-0.5.2/talk/base/logging.cc.chromium12
libjingle-0.5.2/talk/base/logging.cc
+--- libjingle-0.5.2/talk/base/logging.cc.chromium12 2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/logging.cc 2011-03-30 21:51:32.697287001 -0400
+@@ -1,6 +1,6 @@
+ /*
+ * libjingle
+- * Copyright 2004--2005, Google Inc.
++ * Copyright 2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+@@ -37,6 +37,10 @@
+ #elif defined(ANDROID)
+ #include <android/log.h>
+ static const char kLibjingle[] = "libjingle";
++// Android has a 1024 limit on log inputs. We use 60 chars as an
++// approx for the header/tag portion.
++// See android/system/core/liblog/logd_write.c
++static const int kMaxLogLineSize = 1024 - 60;
+ #endif // OSX || ANDROID
+
+ #include <iostream>
+@@ -270,7 +274,7 @@ void LogMessage::ConfigureLogging(const
+ int file_level = GetLogToStream();
+
+ std::vector<std::string> tokens;
+- split(params, ' ', &tokens);
++ tokenize(params, ' ', &tokens);
+
+ for (size_t i = 0; i < tokens.size(); ++i) {
+ if (tokens[i].empty())
+@@ -429,6 +433,10 @@ void LogMessage::OutputToDebug(const std
+ switch (severity) {
+ case LS_SENSITIVE:
+ __android_log_write(ANDROID_LOG_INFO, kLibjingle, "SENSITIVE");
++ if (log_to_stderr) {
++ std::cerr << "SENSITIVE";
++ std::cerr.flush();
++ }
+ return;
+ case LS_VERBOSE:
+ prio = ANDROID_LOG_VERBOSE;
+@@ -445,8 +453,26 @@ void LogMessage::OutputToDebug(const std
+ default:
+ prio = ANDROID_LOG_UNKNOWN;
+ }
+- // Use the size of the string in the format (str may have \0 in the middle).
+- __android_log_print(prio, kLibjingle, "%.*s", str.size(), str.c_str());
++
++ int size = str.size();
++ int line = 0;
++ int idx = 0;
++ const int max_lines = size / kMaxLogLineSize + 1;
++ if (max_lines == 1) {
++ __android_log_print(prio, kLibjingle, "%.*s", size, str.c_str());
++ } else {
++ while (size > 0) {
++ const int len = std::min(size, kMaxLogLineSize);
++ // Use the size of the string in the format (str may have \0 in the
++ // middle).
++ __android_log_print(prio, kLibjingle, "[%d/%d] %.*s",
++ line + 1, max_lines,
++ len, str.c_str() + idx);
++ idx += len;
++ size -= len;
++ ++line;
++ }
++ }
+ #endif // ANDROID
+ if (log_to_stderr) {
+ std::cerr << str;
+diff -upN libjingle-0.5.2/talk/base/Makefile.am.chromium12
libjingle-0.5.2/talk/base/Makefile.am
+--- libjingle-0.5.2/talk/base/Makefile.am.chromium12 2011-03-30 21:51:32.656287001 -0400
++++ libjingle-0.5.2/talk/base/Makefile.am 2011-03-30 21:53:50.328287005 -0400
+@@ -2,12 +2,12 @@ lib_LTLIBRARIES = libjinglebase.la
+
+ libjinglebase_la_SOURCES = asyncfile.cc \
+ asynchttprequest.cc \
+- asyncpacketsocket.cc \
+ asyncsocket.cc \
+ asynctcpsocket.cc \
+ asyncudpsocket.cc \
+ autodetectproxy.cc \
+ base64.cc \
++ basicpacketsocketfactory.cc \
+ bytebuffer.cc \
+ checks.cc \
+ common.cc \
+@@ -22,6 +22,7 @@ libjinglebase_la_SOURCES = asyncfile.cc
+ httpclient.cc \
+ httpcommon.cc \
+ httprequest.cc \
++ latebindingsymboltable.cc \
+ linux.cc \
+ logging.cc \
+ md5c.c \
+@@ -36,6 +37,7 @@ libjinglebase_la_SOURCES = asyncfile.cc
+ physicalsocketserver.cc \
+ proxydetect.cc \
+ proxyinfo.cc \
++ ratetracker.cc \
+ signalthread.cc \
+ socketadapters.cc \
+ socketaddress.cc \
+@@ -73,6 +75,7 @@ libjinglebase_include_HEADERS = asyncfil
+ autodetectproxy.h \
+ base64.h \
+ basicdefs.h \
++ basicpacketsocketfactory.h \
+ basictypes.h \
+ bytebuffer.h \
+ byteorder.h \
+@@ -101,10 +104,12 @@ libjinglebase_include_HEADERS = asyncfil
+ messagequeue.h \
+ nethelpers.h \
+ network.h \
++ packetsocketfactory.h \
+ pathutils.h \
+ physicalsocketserver.h \
+ proxydetect.h \
+ proxyinfo.h \
++ ratetracker.h \
+ scoped_ptr.h \
+ sec_buffer.h \
+ signalthread.h \
+diff -upN libjingle-0.5.2/talk/base/nethelpers.cc.chromium12
libjingle-0.5.2/talk/base/nethelpers.cc
+--- libjingle-0.5.2/talk/base/nethelpers.cc.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/nethelpers.cc 2011-03-30 21:51:32.697287001 -0400
+@@ -25,6 +25,8 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
++#include "config.h"
++
+ #include "talk/base/nethelpers.h"
+
+ #include "talk/base/byteorder.h"
+@@ -32,6 +34,11 @@
+
+ namespace talk_base {
+
++#if defined(LINUX) || defined(ANDROID)
++static const size_t kInitHostentLen = 1024;
++static const size_t kMaxHostentLen = kInitHostentLen * 8;
++#endif
++
+ // AsyncResolver
+
+ AsyncResolver::AsyncResolver() : result_(NULL), error_(0) {
+@@ -55,17 +62,16 @@ void AsyncResolver::OnWorkDone() {
+ // The functions below are used to do gethostbyname, but with an allocated
+ // instead of a static buffer.
+ hostent* SafeGetHostByName(const char* hostname, int* herrno) {
++ if (NULL == hostname || NULL == herrno) {
++ return NULL;
++ }
+ hostent* result = NULL;
+-#if defined(WIN32) || (defined(POSIX) && !defined(OSX))
++#if defined(WIN32)
+ // On Windows we have to allocate a buffer, and manually copy the hostent,
+ // along with its embedded pointers.
+ hostent* ent = gethostbyname(hostname);
+ if (!ent) {
+-#ifdef WIN32
+ *herrno = WSAGetLastError();
+-#else // POSIX
+- *herrno = h_errno;
+-#endif
+ return NULL;
+ }
+
+@@ -85,6 +91,9 @@ hostent* SafeGetHostByName(const char* h
+ total_len += sizeof(char*);
+
+ result = static_cast<hostent*>(malloc(total_len));
++ if (NULL == result) {
++ return NULL;
++ }
+ char* p = reinterpret_cast<char*>(result) + sizeof(hostent);
+
+ // Copy the hostent into it, along with its embedded pointers.
+@@ -114,7 +123,37 @@ hostent* SafeGetHostByName(const char* h
+ result->h_addr_list[num_addrs] = NULL;
+
+ *herrno = 0;
+-#elif defined(OSX)
++#elif defined(LINUX) || defined(ANDROID)
++ // gethostbyname() is not thread safe, so we need to call gethostbyname_r()
++ // which is a reentrant version of gethostbyname().
++ ASSERT(kInitHostentLen > sizeof(hostent));
++ size_t size = kInitHostentLen;
++ int ret;
++ void* buf = malloc(size);
++ if (NULL == buf) {
++ return NULL;
++ }
++ char* aux = static_cast<char*>(buf) + sizeof(hostent);
++ size_t aux_len = size - sizeof(hostent);
++ while ((ret = gethostbyname_r(hostname, reinterpret_cast<hostent*>(buf), aux,
++ aux_len, &result, herrno)) == ERANGE) {
++ size *= 2;
++ if (size > kMaxHostentLen) {
++ break; // Just to be safe.
++ }
++ buf = realloc(buf, size);
++ if (NULL == buf) {
++ return NULL;
++ }
++ aux = static_cast<char*>(buf) + sizeof(hostent);
++ aux_len = size - sizeof(hostent);
++ }
++ if (ret != 0 || buf != result) {
++ free(buf);
++ return NULL;
++ }
++ *herrno = 0;
++#elif defined(OSX) || defined(IOS)
+ // Mac OS returns an object with everything allocated.
+ result = getipnodebyname(hostname, AF_INET, AI_DEFAULT, herrno);
+ #else
+@@ -126,10 +165,10 @@ hostent* SafeGetHostByName(const char* h
+ // This function should mirror the above function, and free any resources
+ // allocated by the above.
+ void FreeHostEnt(hostent* host) {
+-#if defined(WIN32) || (defined(POSIX) && !defined(OSX))
+- free(host);
+-#elif defined(OSX)
++#if defined(OSX) || defined(IOS)
+ freehostent(host);
++#elif defined(WIN32) || defined(POSIX)
++ free(host);
+ #else
+ #error "I don't know how to free a hostent on your system."
+ #endif
+diff -upN libjingle-0.5.2/talk/base/packetsocketfactory.h.chromium12
libjingle-0.5.2/talk/base/packetsocketfactory.h
+--- libjingle-0.5.2/talk/base/packetsocketfactory.h.chromium12 2011-03-30
21:51:32.697287001 -0400
++++ libjingle-0.5.2/talk/base/packetsocketfactory.h 2011-03-30 21:51:32.697287001 -0400
+@@ -0,0 +1,57 @@
++/*
++ * libjingle
++ * Copyright 2011, 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 TALK_BASE_PACKETSOCKETFACTORY_H_
++#define TALK_BASE_PACKETSOCKETFACTORY_H_
++
++#include "talk/base/proxyinfo.h"
++
++namespace talk_base {
++
++class AsyncPacketSocket;
++
++class PacketSocketFactory {
++ public:
++ PacketSocketFactory() { }
++ virtual ~PacketSocketFactory() { }
++
++ virtual AsyncPacketSocket* CreateUdpSocket(
++ const SocketAddress& address, int min_port, int max_port) = 0;
++ virtual AsyncPacketSocket* CreateServerTcpSocket(
++ const SocketAddress& local_address, int min_port, int max_port,
++ bool listen, bool ssl) = 0;
++ virtual AsyncPacketSocket* CreateClientTcpSocket(
++ const SocketAddress& local_address, const SocketAddress& remote_address,
++ const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl) =
0;
++
++ private:
++ DISALLOW_EVIL_CONSTRUCTORS(PacketSocketFactory);
++};
++
++} // namespace talk_base
++
++#endif // TALK_BASE_PACKETSOCKETFACTORY_H_
+diff -upN libjingle-0.5.2/talk/base/physicalsocketserver.cc.chromium12
libjingle-0.5.2/talk/base/physicalsocketserver.cc
+--- libjingle-0.5.2/talk/base/physicalsocketserver.cc.chromium12 2011-03-30
21:51:32.664287001 -0400
++++ libjingle-0.5.2/talk/base/physicalsocketserver.cc 2011-03-30 21:51:32.698287001
-0400
+@@ -216,7 +216,6 @@ class PhysicalSocket : public AsyncSocke
+ addr.ToSockAddr(&saddr);
+ int err = ::connect(s_, (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_)) {
+@@ -284,8 +283,8 @@ class PhysicalSocket : public AsyncSocke
+ #endif
+ );
+ 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
++ // We have seen minidumps where this may be false.
++ ASSERT(sent <= static_cast<int>(cb));
+ if ((sent < 0) && IsBlockingError(error_)) {
+ enabled_events_ |= DE_WRITE;
+ }
+@@ -305,11 +304,11 @@ class PhysicalSocket : public AsyncSocke
+ #endif
+ (sockaddr*)&saddr, sizeof(saddr));
+ UpdateLastError();
+- ASSERT(sent <= static_cast<int>(cb)); // We have seen minidumps where this
may be false
++ // We have seen minidumps where this may be false.
++ ASSERT(sent <= static_cast<int>(cb));
+ if ((sent < 0) && IsBlockingError(error_)) {
+ enabled_events_ |= DE_WRITE;
+ }
+- //LOG_F(LS_INFO) << cb << ":" << addr.ToString()
<< ":" << sent << ":" << error_;
+ return sent;
+ }
+
+@@ -387,7 +386,6 @@ class PhysicalSocket : public AsyncSocke
+ 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;
+@@ -427,14 +425,14 @@ class PhysicalSocket : public AsyncSocke
+
+ ASSERT(false);
+ return -1;
+-#elif defined(OSX)
++#elif defined(IOS) || defined(OSX)
+ // No simple way to do this on Mac OS X.
+ // SIOCGIFMTU would work if we knew which interface would be used, but
+ // figuring that out is pretty complicated. For now we'll return an error
+ // and let the caller pick a default MTU.
+ error_ = EINVAL;
+ return -1;
+-#elif defined(LINUX)
++#elif defined(LINUX) || defined(ANDROID)
+ // Gets the path MTU.
+ int value;
+ socklen_t vlen = sizeof(value);
+@@ -482,7 +480,7 @@ class PhysicalSocket : public AsyncSocke
+ *slevel = IPPROTO_IP;
+ *sopt = IP_DONTFRAGMENT;
+ break;
+-#elif defined(OSX) || defined(BSD)
++#elif defined(IOS) || defined(OSX) || defined(BSD)
+ LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported.";
+ return -1;
+ #elif defined(POSIX)
+@@ -582,71 +580,43 @@ class EventDispatcher : public Dispatche
+ CriticalSection crit_;
+ };
+
+-// This is a class customized to use the self-pipe trick to deliver POSIX
+-// signals. This is the only safe, reliable, cross-platform way to do
+-// non-trivial things with a POSIX signal (until proper pselect()
+-// implementations become ubiquitous).
+-class PosixSignalDeliveryDispatcher : public Dispatcher {
++// These two classes use the self-pipe trick to deliver POSIX signals to our
++// select loop. This is the only safe, reliable, cross-platform way to do
++// non-trivial things with a POSIX signal in an event-driven program (until
++// proper pselect() implementations become ubiquitous).
++
++class PosixSignalHandler {
+ public:
+- virtual ~PosixSignalDeliveryDispatcher() {
+- close(afd_[0]);
+- close(afd_[1]);
+- }
++ // POSIX only specifies 32 signals, but in principle the system might have
++ // more and the programmer might choose to use them, so we size our array
++ // for 128.
++ static const int kNumPosixSignals = 128;
+
+- virtual uint32 GetRequestedEvents() {
+- return DE_READ;
+- }
++ static PosixSignalHandler *Instance() { return &instance_; }
+
+- virtual void OnPreEvent(uint32 ff) {
+- // Events might get grouped if signals come very fast, so we read out up to
+- // 16 bytes to make sure we keep the pipe empty.
+- uint8 b[16];
+- ssize_t ret = read(afd_[0], b, sizeof(b));
+- if (ret < 0) {
+- LOG_ERR(LS_WARNING) << "Error in read()";
+- } else if (ret == 0) {
+- LOG(LS_WARNING) << "Should have read at least one byte";
++ // Returns true if the given signal number is set.
++ bool IsSignalSet(int signum) const {
++ ASSERT(signum < ARRAY_SIZE(received_signal_));
++ if (signum < ARRAY_SIZE(received_signal_)) {
++ return received_signal_[signum];
++ } else {
++ return false;
+ }
+ }
+
+- virtual void OnEvent(uint32 ff, int err) {
+- for (int signum = 0; signum < ARRAY_SIZE(received_signal_); ++signum) {
+- if (received_signal_[signum]) {
+- received_signal_[signum] = false;
+- HandlerMap::iterator i = handlers_.find(signum);
+- if (i == handlers_.end()) {
+- // This can happen if a signal is delivered to our process at around
+- // the same time as we unset our handler for it. It is not an error
+- // condidion, but it's unusual enough to be worth logging.
+- LOG(LS_INFO) << "Received signal with no handler: " <<
signum;
+- } else {
+- // Otherwise, execute the handler.
+- (*i->second)(signum);
+- }
+- }
++ // Clears the given signal number.
++ void ClearSignal(int signum) {
++ ASSERT(signum < ARRAY_SIZE(received_signal_));
++ if (signum < ARRAY_SIZE(received_signal_)) {
++ received_signal_[signum] = false;
+ }
+ }
+
+- virtual int GetDescriptor() {
++ // Returns the file descriptor to monitor for signal events.
++ int GetDescriptor() const {
+ return afd_[0];
+ }
+
+- virtual bool IsDescriptorClosed() {
+- return false;
+- }
+-
+- void SetHandler(int signum, void (*handler)(int)) {
+- handlers_[signum] = handler;
+- }
+-
+- void ClearHandler(int signum) {
+- handlers_.erase(signum);
+- }
+-
+- bool HasHandlers() {
+- return !handlers_.empty();
+- }
+-
+ // This is called directly from our real signal handler, so it must be
+ // signal-handler-safe. That means it cannot assume anything about the
+ // user-level state of the process, since the handler could be executed at any
+@@ -658,7 +628,7 @@ class PosixSignalDeliveryDispatcher : pu
+ }
+ // Set a flag saying we've seen this signal.
+ received_signal_[signum] = true;
+- // Tell the thread running our PhysicalSocketServer that we got a signal.
++ // Notify application code that we got a signal.
+ const uint8 b[1] = { 0 };
+ if (-1 == write(afd_[1], b, sizeof(b))) {
+ // Nothing we can do here. If there's an error somehow then there's
+@@ -670,49 +640,8 @@ class PosixSignalDeliveryDispatcher : pu
+ }
+ }
+
+- // Sets a PhysicalSocketServer to own signal delivery, or fails if already
+- // owned.
+- bool SetOwner(PhysicalSocketServer *owner) {
+- CritScope cs(&owner_critsec_);
+- if (owner == owner_) {
+- return true;
+- } else if (owner_) {
+- return false;
+- } else {
+- owner_ = owner;
+- owner_->Add(this);
+- return true;
+- }
+- }
+-
+- bool IsOwner(PhysicalSocketServer *ss) {
+- CritScope cs(&owner_critsec_);
+- return owner_ == ss;
+- }
+-
+- void ClearOwner(PhysicalSocketServer *ss) {
+- CritScope cs(&owner_critsec_);
+- if (owner_ != ss) {
+- return;
+- }
+- owner_->Remove(this);
+- owner_ = NULL;
+- }
+-
+- // There is just a single global instance. (Signal handlers do not get any
+- // sort of user-defined void * parameter, so they can't access anything that
+- // isn't global.)
+- static PosixSignalDeliveryDispatcher instance_;
+-
+ private:
+- // POSIX only specifies 32 signals, but in principle the system might have
+- // more and the programmer might choose to use them, so we size our array
+- // for 128.
+- static const int kNumPosixSignals = 128;
+-
+- typedef std::map<int, void (*)(int)> HandlerMap;
+-
+- PosixSignalDeliveryDispatcher() : owner_(NULL) {
++ PosixSignalHandler() {
+ if (pipe(afd_) < 0) {
+ LOG_ERR(LS_ERROR) << "pipe failed";
+ return;
+@@ -728,8 +657,30 @@ class PosixSignalDeliveryDispatcher : pu
+ sizeof(received_signal_));
+ }
+
++ ~PosixSignalHandler() {
++ int fd1 = afd_[0];
++ int fd2 = afd_[1];
++ // We clobber the stored file descriptor numbers here or else in principle
++ // a signal that happens to be delivered during application termination
++ // could erroneously write a zero byte to an unrelated file handle in
++ // OnPosixSignalReceived() if some other file happens to be opened later
++ // during shutdown and happens to be given the same file descriptor number
++ // as our pipe had. Unfortunately even with this precaution there is still a
++ // race where that could occur if said signal happens to be handled
++ // concurrently with this code and happens to have already read the value of
++ // afd_[1] from memory before we clobber it, but that's unlikely.
++ afd_[0] = -1;
++ afd_[1] = -1;
++ close(fd1);
++ close(fd2);
++ }
++
++ // There is just a single global instance. (Signal handlers do not get any
++ // sort of user-defined void * parameter, so they can't access anything that
++ // isn't global.)
++ static PosixSignalHandler instance_;
++
+ int afd_[2];
+- HandlerMap handlers_;
+ // These are boolean flags that will be set in our signal handler and read
+ // and cleared from Wait(). There is a race involved in this, but it is
+ // benign. The signal handler sets the flag before signaling the pipe, so
+@@ -741,14 +692,83 @@ class PosixSignalDeliveryDispatcher : pu
+ // Volatile is not necessary here for correctness, but this data _is_ volatile
+ // so I've marked it as such.
+ volatile uint8 received_signal_[kNumPosixSignals];
++};
++
++PosixSignalHandler PosixSignalHandler::instance_;
++
++class PosixSignalDispatcher : public Dispatcher {
++ public:
++ PosixSignalDispatcher(PhysicalSocketServer *owner) : owner_(owner) {
++ owner_->Add(this);
++ }
++
++ virtual ~PosixSignalDispatcher() {
++ owner_->Remove(this);
++ }
++
++ virtual uint32 GetRequestedEvents() {
++ return DE_READ;
++ }
++
++ virtual void OnPreEvent(uint32 ff) {
++ // Events might get grouped if signals come very fast, so we read out up to
++ // 16 bytes to make sure we keep the pipe empty.
++ uint8 b[16];
++ ssize_t ret = read(GetDescriptor(), b, sizeof(b));
++ if (ret < 0) {
++ LOG_ERR(LS_WARNING) << "Error in read()";
++ } else if (ret == 0) {
++ LOG(LS_WARNING) << "Should have read at least one byte";
++ }
++ }
++
++ virtual void OnEvent(uint32 ff, int err) {
++ for (int signum = 0; signum < PosixSignalHandler::kNumPosixSignals;
++ ++signum) {
++ if (PosixSignalHandler::Instance()->IsSignalSet(signum)) {
++ PosixSignalHandler::Instance()->ClearSignal(signum);
++ HandlerMap::iterator i = handlers_.find(signum);
++ if (i == handlers_.end()) {
++ // This can happen if a signal is delivered to our process at around
++ // the same time as we unset our handler for it. It is not an error
++ // condition, but it's unusual enough to be worth logging.
++ LOG(LS_INFO) << "Received signal with no handler: " <<
signum;
++ } else {
++ // Otherwise, execute our handler.
++ (*i->second)(signum);
++ }
++ }
++ }
++ }
++
++ virtual int GetDescriptor() {
++ return PosixSignalHandler::Instance()->GetDescriptor();
++ }
++
++ virtual bool IsDescriptorClosed() {
++ return false;
++ }
++
++ void SetHandler(int signum, void (*handler)(int)) {
++ handlers_[signum] = handler;
++ }
++
++ void ClearHandler(int signum) {
++ handlers_.erase(signum);
++ }
++
++ bool HasHandlers() {
++ return !handlers_.empty();
++ }
++
++ private:
++ typedef std::map<int, void (*)(int)> HandlerMap;
++
++ HandlerMap handlers_;
+ // Our owner.
+ PhysicalSocketServer *owner_;
+- // To synchronize ownership changes.
+- CriticalSection owner_critsec_;
+ };
+
+-PosixSignalDeliveryDispatcher PosixSignalDeliveryDispatcher::instance_;
+-
+ class SocketDispatcher : public Dispatcher, public PhysicalSocket {
+ public:
+ explicit SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) {
+@@ -994,9 +1014,16 @@ class SocketDispatcher : public Dispatch
+ bool signal_close_;
+ int signal_err_;
+
+- SocketDispatcher(PhysicalSocketServer* ss) : PhysicalSocket(ss), id_(0),
signal_close_(false) {
++ SocketDispatcher(PhysicalSocketServer* ss)
++ : PhysicalSocket(ss),
++ id_(0),
++ signal_close_(false) {
+ }
+- SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) : PhysicalSocket(ss, s), id_(0),
signal_close_(false) {
++
++ SocketDispatcher(SOCKET s, PhysicalSocketServer* ss)
++ : PhysicalSocket(ss, s),
++ id_(0),
++ signal_close_(false) {
+ }
+
+ virtual ~SocketDispatcher() {
+@@ -1069,7 +1096,6 @@ class SocketDispatcher : public Dispatch
+ SignalReadEvent(this);
+ }
+ if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) {
+- //LOG(INFO) << "SOCK[" << static_cast<int>(s_)
<< "] OnClose() Error: " << err;
+ signal_close_ = true;
+ signal_err_ = err;
+ }
+@@ -1134,7 +1160,7 @@ PhysicalSocketServer::~PhysicalSocketSer
+ WSACloseEvent(socket_ev_);
+ #endif
+ #ifdef POSIX
+- PosixSignalDeliveryDispatcher::instance_.ClearOwner(this);
++ signal_dispatcher_.reset();
+ #endif
+ delete signal_wakeup_;
+ ASSERT(dispatchers_.empty());
+@@ -1355,7 +1381,7 @@ bool PhysicalSocketServer::Wait(int cmsW
+ }
+
+ static void GlobalSignalHandler(int signum) {
+- PosixSignalDeliveryDispatcher::instance_.OnPosixSignalReceived(signum);
++ PosixSignalHandler::Instance()->OnPosixSignalReceived(signum);
+ }
+
+ bool PhysicalSocketServer::SetPosixSignalHandler(int signum,
+@@ -1366,19 +1392,17 @@ bool PhysicalSocketServer::SetPosixSigna
+ if (!InstallSignal(signum, handler)) {
+ return false;
+ }
+- if (PosixSignalDeliveryDispatcher::instance_.IsOwner(this)) {
+- PosixSignalDeliveryDispatcher::instance_.ClearHandler(signum);
+- if (!PosixSignalDeliveryDispatcher::instance_.HasHandlers()) {
+- PosixSignalDeliveryDispatcher::instance_.ClearOwner(this);
++ if (signal_dispatcher_.get()) {
++ signal_dispatcher_->ClearHandler(signum);
++ if (!signal_dispatcher_->HasHandlers()) {
++ signal_dispatcher_.reset();
+ }
+ }
+ } else {
+- if (!PosixSignalDeliveryDispatcher::instance_.SetOwner(this)) {
+- LOG(LS_ERROR) <<
+- "Cannot do POSIX signal delivery on more than one
PhysicalSocketServer";
+- return false;
++ if (!signal_dispatcher_.get()) {
++ signal_dispatcher_.reset(new PosixSignalDispatcher(this));
+ }
+- PosixSignalDeliveryDispatcher::instance_.SetHandler(signum, handler);
++ signal_dispatcher_->SetHandler(signum, handler);
+ if (!InstallSignal(signum, &GlobalSignalHandler)) {
+ return false;
+ }
+@@ -1439,7 +1463,9 @@ bool PhysicalSocketServer::Wait(int cmsW
+ if (disp->CheckSignalClose()) {
+ // We just signalled close, don't poll this socket
+ } else if (s != INVALID_SOCKET) {
+- WSAEventSelect(s, events[0], FlagsToEvents(disp->GetRequestedEvents()));
++ WSAEventSelect(s,
++ events[0],
++ FlagsToEvents(disp->GetRequestedEvents()));
+ } else {
+ events.push_back(disp->GetWSAEvent());
+ event_owners.push_back(disp);
+@@ -1459,14 +1485,19 @@ bool PhysicalSocketServer::Wait(int cmsW
+ }
+
+ // Wait for one of the events to signal
+- DWORD dw = WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()),
&events[0], false, cmsNext, false);
++ 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) {
+ int32 elapsed = TimeSince(last_tick_tracked_);
+- LOG(INFO) << "PhysicalSocketServer took " << elapsed
<< "ms for 1000 events";
++ LOG(INFO) << "PhysicalSocketServer took " << elapsed
++ << "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).
+@@ -1510,20 +1541,30 @@ bool PhysicalSocketServer::Wait(int cmsW
+
+ #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_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_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_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_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];
++ 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
+diff -upN libjingle-0.5.2/talk/base/physicalsocketserver.h.chromium12
libjingle-0.5.2/talk/base/physicalsocketserver.h
+--- libjingle-0.5.2/talk/base/physicalsocketserver.h.chromium12 2011-01-11
19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/physicalsocketserver.h 2011-03-30 21:51:32.698287001 -0400
+@@ -31,6 +31,7 @@
+ #include <vector>
+
+ #include "talk/base/asyncfile.h"
++#include "talk/base/scoped_ptr.h"
+ #include "talk/base/socketserver.h"
+ #include "talk/base/criticalsection.h"
+
+@@ -51,7 +52,7 @@ enum DispatcherEvent {
+
+ class Signaler;
+ #ifdef POSIX
+-class PosixSignalDeliveryDispatcher;
++class PosixSignalDispatcher;
+ #endif
+
+ class Dispatcher {
+@@ -99,9 +100,8 @@ public:
+ // manipulate user-level data structures.
+ // "handler" may be SIG_IGN, SIG_DFL, or a user-specified function, just
like
+ // with signal(2).
+- // Only one PhysicalSocketServer may have user-level signal handlers.
+- // Attempting to install a signal handler for a PhysicalSocketServer when
+- // another already owns some will fail.
++ // Only one PhysicalSocketServer should have user-level signal handlers.
++ // Dispatching signals on multiple PhysicalSocketServers is not reliable.
+ // The signal mask is not modified. It is the caller's responsibily to
+ // maintain it as desired.
+ bool SetPosixSignalHandler(int signum, void (*handler)(int));
+@@ -113,8 +113,9 @@ private:
+
+ #ifdef POSIX
+ static bool InstallSignal(int signum, void (*handler)(int));
+-#endif
+
++ scoped_ptr<PosixSignalDispatcher> signal_dispatcher_;
++#endif
+ DispatcherList dispatchers_;
+ IteratorList iterators_;
+ Signaler* signal_wakeup_;
+diff -upN libjingle-0.5.2/talk/base/socketpool.cc.chromium12
libjingle-0.5.2/talk/base/socketpool.cc
+--- libjingle-0.5.2/talk/base/socketpool.cc.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/socketpool.cc 2011-03-30 21:51:32.699287001 -0400
+@@ -218,11 +218,25 @@ ReuseSocketPool::ReturnConnectedStream(S
+
+ void
+ ReuseSocketPool::OnStreamEvent(StreamInterface* stream, int events, int err) {
+- LOG_F(LS_VERBOSE) << "Connection closed with error: " << err;
+ ASSERT(stream == stream_);
+ ASSERT(!checked_out_);
+- ASSERT(0 != (events & SE_CLOSE));
+- // Socket has closed. We'll reconnect it the next time it is used.
++
++ // If the stream was written to and then immediately returned to us then
++ // we may get a writable notification for it, which we should ignore.
++ if (events == SE_WRITE) {
++ LOG_F(LS_VERBOSE) << "Pooled Socket unexpectedly writable:
ignoring";
++ return;
++ }
++
++ // If the peer sent data, we can't process it, so drop the connection.
++ // If the socket has closed, clean it up.
++ // In either case, we'll reconnect it the next time it is used.
++ ASSERT(0 != (events & (SE_READ|SE_CLOSE)));
++ if (0 != (events & SE_CLOSE)) {
++ LOG_F(LS_VERBOSE) << "Connection closed with error: " << err;
++ } else {
++ LOG_F(LS_VERBOSE) << "Pooled Socket unexpectedly readable:
closing";
++ }
+ stream_->Close();
+ }
+
+diff -upN libjingle-0.5.2/talk/base/socketpool.h.chromium12
libjingle-0.5.2/talk/base/socketpool.h
+--- libjingle-0.5.2/talk/base/socketpool.h.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/socketpool.h 2011-03-30 21:51:32.699287001 -0400
+@@ -25,8 +25,8 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+-#ifndef TALK_BASE_SOCKETPOOL_H__
+-#define TALK_BASE_SOCKETPOOL_H__
++#ifndef TALK_BASE_SOCKETPOOL_H_
++#define TALK_BASE_SOCKETPOOL_H_
+
+ #include <deque>
+ #include <list>
+@@ -155,6 +155,6 @@ private:
+
+ //////////////////////////////////////////////////////////////////////
+
+-} // namespace talk_base
++} // namespace talk_base
+
+-#endif // TALK_BASE_SOCKETPOOL_H__
++#endif // TALK_BASE_SOCKETPOOL_H_
+diff -upN libjingle-0.5.2/talk/base/stream.cc.chromium12
libjingle-0.5.2/talk/base/stream.cc
+--- libjingle-0.5.2/talk/base/stream.cc.chromium12 2011-03-30 21:51:32.664287001 -0400
++++ libjingle-0.5.2/talk/base/stream.cc 2011-03-30 21:51:32.699287001 -0400
+@@ -1,6 +1,6 @@
+ /*
+ * libjingle
+- * Copyright 2004--2010, Google Inc.
++ * Copyright 2011, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+@@ -552,7 +552,8 @@ void POpenStream::DoClose() {
+ ///////////////////////////////////////////////////////////////////////////////
+
+ MemoryStreamBase::MemoryStreamBase()
+- : buffer_(NULL), buffer_length_(0), data_length_(0), seek_position_(0) {
++ : buffer_(NULL), buffer_length_(0), data_length_(0),
++ seek_position_(0) {
+ }
+
+ StreamState MemoryStreamBase::GetState() const {
+@@ -647,25 +648,29 @@ StreamResult MemoryStreamBase::DoReserve
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+-MemoryStream::MemoryStream() {
++MemoryStream::MemoryStream()
++ : buffer_alloc_(NULL) {
+ }
+
+-MemoryStream::MemoryStream(const char* data) {
++MemoryStream::MemoryStream(const char* data)
++ : buffer_alloc_(NULL) {
+ SetData(data, strlen(data));
+ }
+
+-MemoryStream::MemoryStream(const void* data, size_t length) {
++MemoryStream::MemoryStream(const void* data, size_t length)
++ : buffer_alloc_(NULL) {
+ SetData(data, length);
+ }
+
+ MemoryStream::~MemoryStream() {
+- delete [] buffer_;
++ delete [] buffer_alloc_;
+ }
+
+ void MemoryStream::SetData(const void* data, size_t length) {
+ data_length_ = buffer_length_ = length;
+- delete [] buffer_;
+- buffer_ = new char[buffer_length_];
++ delete [] buffer_alloc_;
++ buffer_alloc_ = new char[buffer_length_ + kAlignment];
++ buffer_ = reinterpret_cast<char*>(ALIGNP(buffer_alloc_, kAlignment));
+ memcpy(buffer_, data, data_length_);
+ seek_position_ = 0;
+ }
+@@ -674,9 +679,12 @@ StreamResult MemoryStream::DoReserve(siz
+ if (buffer_length_ >= size)
+ return SR_SUCCESS;
+
+- if (char* new_buffer = new char[size]) {
++ if (char* new_buffer_alloc = new char[size + kAlignment]) {
++ char* new_buffer = reinterpret_cast<char*>(
++ ALIGNP(new_buffer_alloc, kAlignment));
+ memcpy(new_buffer, buffer_, data_length_);
+- delete [] buffer_;
++ delete [] buffer_alloc_;
++ buffer_alloc_ = new_buffer_alloc;
+ buffer_ = new_buffer;
+ buffer_length_ = size;
+ return SR_SUCCESS;
+diff -upN libjingle-0.5.2/talk/base/stream.h.chromium12
libjingle-0.5.2/talk/base/stream.h
+--- libjingle-0.5.2/talk/base/stream.h.chromium12 2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/stream.h 2011-03-30 21:51:32.700287001 -0400
+@@ -530,6 +530,9 @@ class MemoryStream : public MemoryStream
+
+ protected:
+ virtual StreamResult DoReserve(size_t size, int* error);
++ // Memory Streams are aligned for efficiency.
++ static const int kAlignment = 16;
++ char* buffer_alloc_;
+ };
+
+ // ExternalMemoryStream adapts an external memory buffer, so writes which would
+diff -upN libjingle-0.5.2/talk/base/stringencode.cc.chromium12
libjingle-0.5.2/talk/base/stringencode.cc
+--- libjingle-0.5.2/talk/base/stringencode.cc.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/stringencode.cc 2011-03-30 21:51:32.700287001 -0400
+@@ -1,27 +1,27 @@
+ /*
+ * libjingle
+- * Copyright 2004--2005, Google Inc.
++ * Copyright 2011, Google Inc.
+ *
+- * Redistribution and use in source and binary forms, with or without
++ * 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,
++ * 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
++ * 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
++ * 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,
++ * 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
++ * 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.
+ */
+
+@@ -168,7 +168,7 @@ const unsigned char HTML_UNSAFE = 0x2; /
+
+ // ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 6 5 7 8 9 : ; < = > ?
+ //@ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
+-//` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
++//` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
+
+ const unsigned char ASCII_CLASS[128] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+@@ -251,7 +251,7 @@ size_t utf8_decode(const char* source, s
+ return 0;
+ }
+ value16 = (value16 << 6) | (s[2] & 0x3F);
+- if ((s[0] & 0xF0) == 0xE0) { // Check s[0] == 1110xxxx
++ if ((s[0] & 0xF0) == 0xE0) { // Check s[0] == 1110xxxx
+ *value = ((s[0] & 0x0F) << 12) | value16;
+ return 3;
+ }
+@@ -259,7 +259,7 @@ size_t utf8_decode(const char* source, s
+ return 0;
+ }
+ value16 = (value16 << 6) | (s[3] & 0x3F);
+- if ((s[0] & 0xF8) == 0xF0) { // Check s[0] == 11110xxx
++ if ((s[0] & 0xF8) == 0xF0) { // Check s[0] == 11110xxx
+ *value = ((s[0] & 0x07) << 18) | value16;
+ return 4;
+ }
+@@ -511,8 +511,8 @@ std::string s_transform(const std::strin
+ return result;
+ }
+
+-size_t split(const std::string& source, char delimiter,
+- std::vector<std::string>* fields) {
++size_t tokenize(const std::string& source, char delimiter,
++ std::vector<std::string>* fields) {
+ ASSERT(NULL != fields);
+ fields->clear();
+ size_t last = 0;
+@@ -530,20 +530,19 @@ size_t split(const std::string& source,
+ return fields->size();
+ }
+
+-std::string split_one(const std::string& source, char delimiter, int* index) {
+- std::string substring;
+- size_t start = source.find_first_not_of(delimiter, *index);
+- size_t end = source.find_first_of(delimiter, start);
+- if (start != std::string::npos) {
+- if (end == std::string::npos) {
+- substring = source.substr(start);
+- *index = source.length();
+- } else {
+- substring = source.substr(start, end - start);
+- *index = source.find_first_not_of(delimiter, end);
++size_t split(const std::string& source, char delimiter,
++ std::vector<std::string>* fields) {
++ ASSERT(NULL != fields);
++ fields->clear();
++ size_t last = 0;
++ for (size_t i = 0; i < source.length(); ++i) {
++ if (source[i] == delimiter) {
++ fields->push_back(source.substr(last, i - last));
++ last = i + 1;
+ }
+ }
+- return substring;
++ fields->push_back(source.substr(last, source.length() - last));
++ return fields->size();
+ }
+
+ char make_char_safe_for_filename(char c) {
+diff -upN libjingle-0.5.2/talk/base/stringencode.h.chromium12
libjingle-0.5.2/talk/base/stringencode.h
+--- libjingle-0.5.2/talk/base/stringencode.h.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/stringencode.h 2011-03-30 21:51:32.700287001 -0400
+@@ -1,27 +1,27 @@
+ /*
+ * libjingle
+- * Copyright 2004--2005, Google Inc.
++ * Copyright 2011, Google Inc.
+ *
+- * Redistribution and use in source and binary forms, with or without
++ * 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,
++ * 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
++ * 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
++ * 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,
++ * 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
++ * 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.
+ */
+
+@@ -58,7 +58,7 @@ size_t escape(char * buffer, size_t bufl
+ // Note: in-place unescaping (buffer == source) is allowed.
+ size_t unescape(char * buffer, size_t buflen,
+ const char * source, size_t srclen,
+- char escape);
++ char escape);
+
+ // Encoding replaces illegal characters with the escape character and 2 hex
+ // chars, so it's a little less compact than escape, but completely removes
+@@ -125,14 +125,15 @@ inline std::string s_url_decode(const st
+ return s_transform(source, url_decode);
+ }
+
+-// Splits the source string into multiple fields separated by delimiter.
++// Splits the source string into multiple fields separated by delimiter,
++// with duplicates of delimiter creating empty fields.
+ size_t split(const std::string& source, char delimiter,
+ std::vector<std::string>* fields);
+
+-// Returns the first part of a string separated by delimiter.
+-// Index indicates the location to start parsing in the string and
+-// is increased to the start of the next substring.
+-std::string split_one(const std::string& source, char delimiter, int* index);
++// Splits the source string into multiple fields separated by delimiter,
++// with duplicates of delimiter ignored. Trailing delimiter ignored.
++size_t tokenize(const std::string& source, char delimiter,
++ std::vector<std::string>* fields);
+
+ // Safe sprintf to std::string
+ //void sprintf(std::string& value, size_t maxlen, const char * format, ...)
+diff -upN libjingle-0.5.2/talk/base/stringutils.cc.chromium12
libjingle-0.5.2/talk/base/stringutils.cc
+--- libjingle-0.5.2/talk/base/stringutils.cc.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/stringutils.cc 2011-03-30 21:51:32.701287001 -0400
+@@ -2,26 +2,26 @@
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+- * Redistribution and use in source and binary forms, with or without
++ * 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,
++ * 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
++ * 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
++ * 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,
++ * 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
++ * 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.
+ */
+
+@@ -33,7 +33,7 @@ namespace talk_base {
+ bool memory_check(const void* memory, int c, size_t count) {
+ const char* char_memory = static_cast<const char*>(memory);
+ char char_c = static_cast<char>(c);
+- for (size_t i=0; i<count; ++i) {
++ for (size_t i = 0; i < count; ++i) {
+ if (char_memory[i] != char_c) {
+ return false;
+ }
+@@ -88,7 +88,7 @@ size_t asccpyn(wchar_t* buffer, size_t b
+ const char* source, size_t srclen) {
+ if (buflen <= 0)
+ return 0;
+-
++
+ if (srclen == SIZE_UNKNOWN) {
+ srclen = strlenn(source, buflen - 1);
+ } else if (srclen >= buflen) {
+@@ -129,4 +129,17 @@ bool starts_with(const char *s1, const c
+ return true;
+ }
+
++static const std::string kWhitespace(" \n\r\t");
++
++std::string string_trim(const std::string& s) {
++ std::string::size_type first = s.find_first_not_of(kWhitespace);
++ std::string::size_type last = s.find_last_not_of(kWhitespace);
++
++ if (first == std::string::npos || last == std::string::npos) {
++ return std::string("");
++ }
++
++ return s.substr(first, last - first + 1);
++}
++
+ } // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/stringutils.h.chromium12
libjingle-0.5.2/talk/base/stringutils.h
+--- libjingle-0.5.2/talk/base/stringutils.h.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/stringutils.h 2011-03-30 21:51:32.701287001 -0400
+@@ -332,6 +332,9 @@ void replace_substrs(const char *search,
+ // True iff s1 starts with s2.
+ bool starts_with(const char *s1, const char *s2);
+
++// Remove leading and trailing whitespaces.
++std::string string_trim(const std::string& s);
++
+ } // namespace talk_base
+
+ #endif // TALK_BASE_STRINGUTILS_H__
+diff -upN libjingle-0.5.2/talk/examples/call/callclient.cc.chromium12
libjingle-0.5.2/talk/examples/call/callclient.cc
+--- libjingle-0.5.2/talk/examples/call/callclient.cc.chromium12 2011-01-11
19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/examples/call/callclient.cc 2011-03-30 21:51:32.701287001 -0400
+@@ -29,19 +29,14 @@
+
+ #include <string>
+
+-#include "talk/xmpp/constants.h"
++#include "talk/base/basicpacketsocketfactory.h"
+ #include "talk/base/helpers.h"
+-#include "talk/base/thread.h"
++#include "talk/base/logging.h"
+ #include "talk/base/network.h"
+ #include "talk/base/socketaddress.h"
+-#include "talk/base/stringutils.h"
+ #include "talk/base/stringencode.h"
+-#include "talk/p2p/base/sessionmanager.h"
+-#include "talk/p2p/client/basicportallocator.h"
+-#include "talk/p2p/client/sessionmanagertask.h"
+-#include "talk/session/phone/devicemanager.h"
+-#include "talk/session/phone/mediaengine.h"
+-#include "talk/session/phone/mediasessionclient.h"
++#include "talk/base/stringutils.h"
++#include "talk/base/thread.h"
+ #include "talk/examples/call/console.h"
+ #include "talk/examples/call/presencepushtask.h"
+ #include "talk/examples/call/presenceouttask.h"
+@@ -50,11 +45,14 @@
+ #include "talk/examples/call/friendinvitesendtask.h"
+ #include "talk/examples/call/muc.h"
+ #include "talk/examples/call/voicemailjidrequester.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/platformsoundsystemfactory.h"
+-#endif
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/client/basicportallocator.h"
++#include "talk/p2p/client/sessionmanagertask.h"
++#include "talk/session/phone/devicemanager.h"
++#include "talk/session/phone/mediaengine.h"
++#include "talk/session/phone/mediasessionclient.h"
++#include "talk/xmpp/constants.h"
+
+-#include "talk/base/logging.h"
+
+ class NullRenderer : public cricket::VideoRenderer {
+ public:
+@@ -250,11 +248,7 @@ CallClient::CallClient(buzz::XmppClient*
+ portallocator_flags_(0),
+ allow_local_ips_(false),
+ initial_protocol_(cricket::PROTOCOL_HYBRID),
+- secure_policy_(cricket::SEC_DISABLED)
+-#ifdef USE_TALK_SOUND
+- , sound_system_factory_(NULL)
+-#endif
+- {
++ secure_policy_(cricket::SEC_DISABLED) {
+ xmpp_client_->SignalStateChange.connect(this, &CallClient::OnStateChange);
+ }
+
+@@ -342,14 +336,19 @@ void CallClient::InitPhone() {
+ // dispatched by it.
+ worker_thread_->Start();
+
++ // TODO: It looks like we are leaking many
++ // objects. E.g. |network_manager_| and |socket_factory_| are never
++ // deleted.
++
+ network_manager_ = new talk_base::NetworkManager();
++ socket_factory_ = new talk_base::BasicPacketSocketFactory(worker_thread_);
+
+ // TODO: Decide if the relay address should be specified here.
+ talk_base::SocketAddress stun_addr("stun.l.google.com", 19302);
+- port_allocator_ =
+- new cricket::BasicPortAllocator(network_manager_, stun_addr,
+- talk_base::SocketAddress(), talk_base::SocketAddress(),
+- talk_base::SocketAddress());
++ port_allocator_ = new cricket::BasicPortAllocator(
++ network_manager_, socket_factory_, stun_addr,
++ talk_base::SocketAddress(), talk_base::SocketAddress(),
++ talk_base::SocketAddress());
+
+ if (portallocator_flags_ != 0) {
+ port_allocator_->set_flags(portallocator_flags_);
+@@ -367,29 +366,15 @@ void CallClient::InitPhone() {
+ session_manager_task_->EnableOutgoingMessages();
+ session_manager_task_->Start();
+
+-#ifdef USE_TALK_SOUND
+- if (!sound_system_factory_) {
+- sound_system_factory_ = new cricket::PlatformSoundSystemFactory();
+- }
+-#endif
+-
+ if (!media_engine_) {
+- media_engine_ = cricket::MediaEngine::Create(
+-#ifdef USE_TALK_SOUND
+- sound_system_factory_
+-#endif
+- );
++ media_engine_ = cricket::MediaEngine::Create();
+ }
+
+ media_client_ = new cricket::MediaSessionClient(
+ xmpp_client_->jid(),
+ session_manager_,
+ media_engine_,
+- new cricket::DeviceManager(
+-#ifdef USE_TALK_SOUND
+- sound_system_factory_
+-#endif
+- ));
++ new cricket::DeviceManager());
+ media_client_->SignalCallCreate.connect(this, &CallClient::OnCallCreate);
+ media_client_->SignalDevicesChange.connect(this,
+ &CallClient::OnDevicesChange);
+diff -upN libjingle-0.5.2/talk/examples/call/callclient.h.chromium12
libjingle-0.5.2/talk/examples/call/callclient.h
+--- libjingle-0.5.2/talk/examples/call/callclient.h.chromium12 2011-01-11
19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/examples/call/callclient.h 2011-03-30 21:51:32.701287001 -0400
+@@ -38,9 +38,6 @@
+ #include "talk/xmpp/xmppclient.h"
+ #include "talk/examples/call/status.h"
+ #include "talk/examples/call/console.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/soundsystemfactory.h"
+-#endif
+
+ namespace buzz {
+ class PresencePushTask;
+@@ -92,7 +89,7 @@ class CallClient: public sigslot::has_sl
+ auto_accept_ = auto_accept;
+ }
+ void SetPmucDomain(const std::string &pmuc_domain) {
+- pmuc_domain_ = pmuc_domain;
++ pmuc_domain_ = pmuc_domain;
+ }
+ void SetConsole(Console *console) {
+ console_ = console;
+@@ -171,6 +168,7 @@ class CallClient: public sigslot::has_sl
+ buzz::XmppClient* xmpp_client_;
+ talk_base::Thread* worker_thread_;
+ talk_base::NetworkManager* network_manager_;
++ talk_base::PacketSocketFactory* socket_factory_;
+ cricket::PortAllocator* port_allocator_;
+ cricket::SessionManager* session_manager_;
+ cricket::SessionManagerTask* session_manager_task_;
+@@ -199,9 +197,6 @@ class CallClient: public sigslot::has_sl
+ cricket::SignalingProtocol initial_protocol_;
+ cricket::SecureMediaPolicy secure_policy_;
+ std::string last_sent_to_;
+-#ifdef USE_TALK_SOUND
+- cricket::SoundSystemFactory* sound_system_factory_;
+-#endif
+ };
+
+ #endif // TALK_EXAMPLES_CALL_CALLCLIENT_H_
+diff -upN libjingle-0.5.2/talk/libjingle.scons.chromium12
libjingle-0.5.2/talk/libjingle.scons
+--- libjingle-0.5.2/talk/libjingle.scons.chromium12 2011-01-11 19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/libjingle.scons 2011-03-30 21:51:32.702287001 -0400
+@@ -56,7 +56,9 @@ talk.Library(env, name = "libsrtp",
+ )
+ talk.Library(env, name = "libjingle",
+ lin_srcs = [
++ "base/latebindingsymboltable.cc",
+ "base/linux.cc",
++ "session/phone/libudevsymboltable.cc",
+ "session/phone/v4llookup.cc",
+ ],
+ mac_srcs = [
+@@ -80,12 +82,12 @@ talk.Library(env, name = "libjingle",
+ srcs = [
+ "base/asyncfile.cc",
+ "base/asynchttprequest.cc",
+- "base/asyncpacketsocket.cc",
+ "base/asyncsocket.cc",
+ "base/asynctcpsocket.cc",
+ "base/asyncudpsocket.cc",
+ "base/autodetectproxy.cc",
+ "base/base64.cc",
++ "base/basicpacketsocketfactory.cc",
+ "base/bytebuffer.cc",
+ "base/checks.cc",
+ "base/common.cc",
+@@ -100,7 +102,6 @@ talk.Library(env, name = "libjingle",
+ "base/httpclient.cc",
+ "base/httpcommon.cc",
+ "base/httprequest.cc",
+- "base/latebindingsymboltable.cc",
+ "base/logging.cc",
+ "base/md5c.c",
+ "base/messagehandler.cc",
+@@ -166,7 +167,6 @@ talk.Library(env, name = "libjingle",
+ "session/phone/channelmanager.cc",
+ "session/phone/codec.cc",
+ "session/phone/devicemanager.cc",
+- "session/phone/libudevsymboltable.cc",
+ "session/phone/filemediaengine.cc",
+ "session/phone/mediaengine.cc",
+ "session/phone/mediamonitor.cc",
+diff -upN libjingle-0.5.2/talk/main.scons.chromium12 libjingle-0.5.2/talk/main.scons
+--- libjingle-0.5.2/talk/main.scons.chromium12 2011-01-11 19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/main.scons 2011-03-30 21:51:32.702287001 -0400
+@@ -188,7 +188,7 @@ win_dbg_env = win_env.Clone(
+ )
+
+ win_dbg_env.Prepend(
+- CCFLAGS=[
++ CCFLAGS = [
+ '/ZI', # enable debugging
+ '/Od', # disable optimizations
+ '/MTd', # link with LIBCMTD.LIB debug lib
+@@ -198,6 +198,21 @@ win_dbg_env.Prepend(
+
+ envs.append(win_dbg_env)
+
++win_coverage_env = win_dbg_env.Clone(
++ tools = ['code_coverage'],
++ BUILD_TYPE = 'coverage',
++ BUILD_TYPE_DESCRIPTION = 'Windows code coverage build',
++ BUILD_GROUPS = ['all'],
++)
++
++win_coverage_env.Append(
++ CPPDEFINES = [
++ 'COVERAGE_ENABLED',
++ ],
++)
++
++envs.append(win_coverage_env)
++
+ win_opt_env = win_env.Clone(
+ BUILD_TYPE = 'opt',
+ BUILD_TYPE_DESCRIPTION = 'Windows opt build',
+@@ -285,6 +300,7 @@ mac_env.Append(
+ 'SystemConfiguration',
+ 'OpenGL',
+ 'CoreAudio',
++ 'Quartz',
+ 'QuickTime',
+ 'Cocoa',
+ 'QTKit',
+@@ -334,9 +350,7 @@ linux_common_env.Append(
+ CPPDEFINES = [
+ 'LINUX',
+ 'HAVE_GLIB',
+- # TODO() Enable once we figure out multiple defines with gips lib
+- # Also consider other linux flags: 64bit, no-strict-aliasing, wrap, etc
+- #'USE_TALK_SOUND',
++# 'HAVE_DBUS_GLIB',
+ ],
+ CCFLAGS = [
+ # TODO: Some or all of this may be desirable for Mac too.
+@@ -469,6 +483,7 @@ if win_env.Bit('vsproj'):
+
+ # Solution and target projects
+ s = vs_env.ComponentVSSolution(
++ # 'libjingle', # Please uncomment this line if you build VS proj files.
+ ['all_libraries', 'all_programs', 'all_test_programs'],
+ projects = [p],
+ )
+diff -upN libjingle-0.5.2/talk/p2p/base/common.h.chromium12
libjingle-0.5.2/talk/p2p/base/common.h
+--- libjingle-0.5.2/talk/p2p/base/common.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/common.h 2011-03-30 21:51:32.702287001 -0400
+@@ -25,12 +25,13 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+-#ifndef CRICKET_P2P_BASE_COMMON_H__
+-#define CRICKET_P2P_BASE_COMMON_H__
++#ifndef TALK_P2P_BASE_COMMON_H_
++#define TALK_P2P_BASE_COMMON_H_
+
+ #include "talk/base/logging.h"
+
+ // Common log description format for jingle messages
+-#define LOG_J(sev,obj) LOG(sev) << "Jingle:" << obj->ToString()
<< ": "
++#define LOG_J(sev, obj) LOG(sev) << "Jingle:" <<
obj->ToString() << ": "
++#define LOG_JV(sev, obj) LOG_V(sev) << "Jingle:" <<
obj->ToString() << ": "
+
+-#endif // CRICKET_P2P_BASE_COMMON_H__
++#endif // TALK_P2P_BASE_COMMON_H_
+diff -upN libjingle-0.5.2/talk/p2p/base/constants.cc.chromium12
libjingle-0.5.2/talk/p2p/base/constants.cc
+--- libjingle-0.5.2/talk/p2p/base/constants.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/constants.cc 2011-03-30 21:51:32.702287001 -0400
+@@ -65,6 +65,7 @@ const std::string GINGLE_ACTION_TERMINAT
+ const std::string GINGLE_ACTION_CANDIDATES("candidates");
+ const std::string GINGLE_ACTION_NOTIFY("notify");
+ const std::string GINGLE_ACTION_UPDATE("update");
++const std::string GINGLE_ACTION_VIEW("view");
+
+ const std::string LN_ERROR("error");
+ const buzz::QName QN_GINGLE_REDIRECT(true, NS_GINGLE, "redirect");
+@@ -75,6 +76,7 @@ const std::string STR_REDIRECT_PREFIX("x
+ const std::string LN_DESCRIPTION("description");
+ const std::string LN_PAYLOADTYPE("payload-type");
+ const buzz::QName QN_ID(true, NS_EMPTY, "id");
++const buzz::QName QN_SID(true, NS_EMPTY, "sid");
+ const buzz::QName QN_NAME(true, NS_EMPTY, "name");
+ const buzz::QName QN_CLOCKRATE(true, NS_EMPTY, "clockrate");
+ const buzz::QName QN_BITRATE(true, NS_EMPTY, "bitrate");
+@@ -190,6 +192,34 @@ const std::string STR_TERMINATE_PROTOCOL
+ const std::string
STR_TERMINATE_INTERNAL_SERVER_ERROR("internal-server-error");
+ const std::string STR_TERMINATE_UNKNOWN_ERROR("unknown-error");
+
++// Session notify messages
++const buzz::QName QN_GINGLE_NOTIFY(true, NS_GINGLE, "notify");
++const buzz::QName QN_GINGLE_NOTIFY_NICK(true, cricket::NS_EMPTY, "nick");
++const buzz::QName QN_GINGLE_NOTIFY_SOURCE(true, NS_GINGLE, "source");
++const buzz::QName QN_GINGLE_NOTIFY_SOURCE_MTYPE(
++ true, cricket::NS_EMPTY, "mtype");
++const buzz::QName QN_GINGLE_NOTIFY_SOURCE_SSRC(true, cricket::NS_EMPTY,
"ssrc");
++const std::string GINGLE_NOTIFY_SOURCE_MTYPE_AUDIO("audio");
++const std::string GINGLE_NOTIFY_SOURCE_MTYPE_VIDEO("video");
++
++// Session view messages
++const buzz::QName QN_GINGLE_VIEW(true, cricket::NS_EMPTY, "view");
++const buzz::QName QN_GINGLE_VIEW_TYPE(true, cricket::NS_EMPTY, "type");
++const buzz::QName QN_GINGLE_VIEW_NICK(true, cricket::NS_EMPTY, "nick");
++const buzz::QName QN_GINGLE_VIEW_MEDIA_TYPE(true, cricket::NS_EMPTY,
"mtype");
++const buzz::QName QN_GINGLE_VIEW_SSRC(true, cricket::NS_EMPTY, "ssrc");
++const std::string GINGLE_VIEW_TYPE_STATIC("static");
++const std::string GINGLE_VIEW_TYPE_DYNAMIC("dynamic");
++const std::string GINGLE_VIEW_MEDIA_TYPE_AUDIO("audio");
++const std::string GINGLE_VIEW_MEDIA_TYPE_VIDEO("video");
++const buzz::QName QN_GINGLE_VIEW_PARAMS(true, cricket::NS_EMPTY, "params");
++const buzz::QName QN_GINGLE_VIEW_PARAMS_WIDTH(true, cricket::NS_EMPTY,
"width");
++const buzz::QName QN_GINGLE_VIEW_PARAMS_HEIGHT(
++ true, cricket::NS_EMPTY, "height");
++const buzz::QName QN_GINGLE_VIEW_PARAMS_FRAMERATE(
++ true, cricket::NS_EMPTY, "framerate");
++
++
+ // old stuff
+ #ifdef FEATURE_ENABLE_VOICEMAIL
+ const std::string
NS_VOICEMAIL("http://www.google.com/session/voicemail");
+diff -upN libjingle-0.5.2/talk/p2p/base/constants.h.chromium12
libjingle-0.5.2/talk/p2p/base/constants.h
+--- libjingle-0.5.2/talk/p2p/base/constants.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/constants.h 2011-03-30 21:51:32.703287001 -0400
+@@ -81,6 +81,7 @@ extern const std::string GINGLE_ACTION_T
+ extern const std::string GINGLE_ACTION_CANDIDATES;
+ extern const std::string GINGLE_ACTION_NOTIFY;
+ extern const std::string GINGLE_ACTION_UPDATE;
++extern const std::string GINGLE_ACTION_VIEW;
+
+ extern const std::string LN_ERROR;
+ extern const buzz::QName QN_GINGLE_REDIRECT;
+@@ -91,6 +92,7 @@ extern const std::string STR_REDIRECT_PR
+ extern const std::string LN_DESCRIPTION;
+ extern const std::string LN_PAYLOADTYPE;
+ extern const buzz::QName QN_ID;
++extern const buzz::QName QN_SID;
+ extern const buzz::QName QN_NAME;
+ extern const buzz::QName QN_CLOCKRATE;
+ extern const buzz::QName QN_BITRATE;
+@@ -205,6 +207,30 @@ extern const std::string STR_TERMINATE_P
+ extern const std::string STR_TERMINATE_INTERNAL_SERVER_ERROR;
+ extern const std::string STR_TERMINATE_UNKNOWN_ERROR;
+
++// Session notify messages
++extern const buzz::QName QN_GINGLE_NOTIFY;
++extern const buzz::QName QN_GINGLE_NOTIFY_NICK;
++extern const buzz::QName QN_GINGLE_NOTIFY_SOURCE;
++extern const buzz::QName QN_GINGLE_NOTIFY_SOURCE_MTYPE;
++extern const buzz::QName QN_GINGLE_NOTIFY_SOURCE_SSRC;
++extern const std::string GINGLE_NOTIFY_SOURCE_MTYPE_AUDIO;
++extern const std::string GINGLE_NOTIFY_SOURCE_MTYPE_VIDEO;
++
++// Session view messages
++extern const buzz::QName QN_GINGLE_VIEW;
++extern const buzz::QName QN_GINGLE_VIEW_TYPE;
++extern const buzz::QName QN_GINGLE_VIEW_NICK;
++extern const buzz::QName QN_GINGLE_VIEW_MEDIA_TYPE;
++extern const buzz::QName QN_GINGLE_VIEW_SSRC;
++extern const std::string GINGLE_VIEW_TYPE_STATIC;
++extern const std::string GINGLE_VIEW_TYPE_DYNAMIC;
++extern const std::string GINGLE_VIEW_MEDIA_TYPE_AUDIO;
++extern const std::string GINGLE_VIEW_MEDIA_TYPE_VIDEO;
++extern const buzz::QName QN_GINGLE_VIEW_PARAMS;
++extern const buzz::QName QN_GINGLE_VIEW_PARAMS_WIDTH;
++extern const buzz::QName QN_GINGLE_VIEW_PARAMS_HEIGHT;
++extern const buzz::QName QN_GINGLE_VIEW_PARAMS_FRAMERATE;
++
+ // old stuff
+ #ifdef FEATURE_ENABLE_VOICEMAIL
+ extern const std::string NS_VOICEMAIL;
+diff -upN libjingle-0.5.2/talk/p2p/base/p2ptransportchannel.cc.chromium12
libjingle-0.5.2/talk/p2p/base/p2ptransportchannel.cc
+--- libjingle-0.5.2/talk/p2p/base/p2ptransportchannel.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/p2ptransportchannel.cc 2011-03-30 21:51:32.703287001
-0400
+@@ -621,12 +621,21 @@ void P2PTransportChannel::SortConnection
+
+ // Track the best connection, and let listeners know
+ void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) {
+- // Note: the previous best_connection_ may be destroyed by now, so don't
++ // Note: if conn is NULL, the previous best_connection_ has been destroyed,
++ // so don't use it.
+ // use it.
++ Connection* old_best_connection = best_connection_;
+ best_connection_ = conn;
+ if (best_connection_) {
+- LOG_J(LS_INFO, this) << "New best connection: " <<
conn->ToString();
++ if (old_best_connection) {
++ LOG_J(LS_INFO, this) << "Previous best connection: "
++ << old_best_connection->ToString();
++ }
++ LOG_J(LS_INFO, this) << "New best connection: "
++ << best_connection_->ToString();
+ SignalRouteChange(this, best_connection_->remote_candidate().address());
++ } else {
++ LOG_J(LS_INFO, this) << "No best connection";
+ }
+ }
+
+diff -upN libjingle-0.5.2/talk/p2p/base/portallocator.h.chromium12
libjingle-0.5.2/talk/p2p/base/portallocator.h
+--- libjingle-0.5.2/talk/p2p/base/portallocator.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/portallocator.h 2011-03-30 21:51:32.703287001 -0400
+@@ -25,13 +25,14 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+-#ifndef _PORTALLOCATOR_H_
+-#define _PORTALLOCATOR_H_
++#ifndef TALK_P2P_BASE_PORTALLOCATOR_H_
++#define TALK_P2P_BASE_PORTALLOCATOR_H_
++
++#include <string>
++#include <vector>
+
+ #include "talk/base/sigslot.h"
+ #include "talk/p2p/base/port.h"
+-#include <string>
+-#undef SetPort
+
+ namespace cricket {
+
+@@ -50,8 +51,8 @@ const uint32 PORTALLOCATOR_ENABLE_SHAKER
+ const uint32 kDefaultPortAllocatorFlags = 0;
+
+ class PortAllocatorSession : public sigslot::has_slots<> {
+-public:
+- PortAllocatorSession(uint32 flags) : flags_(flags) {}
++ public:
++ explicit PortAllocatorSession(uint32 flags) : flags_(flags) {}
+
+ // Subclasses should clean up any ports created.
+ virtual ~PortAllocatorSession() {}
+@@ -68,22 +69,28 @@ public:
+ virtual bool IsGettingAllPorts() = 0;
+
+ sigslot::signal2<PortAllocatorSession*, Port*> SignalPortReady;
+- sigslot::signal2<PortAllocatorSession*, const std::vector<Candidate>&>
SignalCandidatesReady;
++ sigslot::signal2<PortAllocatorSession*,
++ const std::vector<Candidate>&> SignalCandidatesReady;
+
+ uint32 generation() { return generation_; }
+ void set_generation(uint32 generation) { generation_ = generation; }
+
+-private:
++ private:
+ uint32 flags_;
+ uint32 generation_;
+ };
+
+ class PortAllocator {
+-public:
+- PortAllocator() : flags_(kDefaultPortAllocatorFlags) {}
++ public:
++ PortAllocator() :
++ flags_(kDefaultPortAllocatorFlags),
++ min_port_(0),
++ max_port_(0) {
++ }
+ virtual ~PortAllocator() {}
+
+- virtual PortAllocatorSession *CreateSession(const std::string &name, const
std::string &session_type) = 0;
++ virtual PortAllocatorSession *CreateSession(const std::string &name,
++ const std::string &session_type) = 0;
+
+ uint32 flags() const { return flags_; }
+ void set_flags(uint32 flags) { flags_ = flags; }
+@@ -91,15 +98,31 @@ public:
+ const std::string& user_agent() const { return agent_; }
+ const talk_base::ProxyInfo& proxy() const { return proxy_; }
+ void set_proxy(const std::string& agent, const talk_base::ProxyInfo& proxy) {
+- agent_ = agent; proxy_ = proxy;
++ agent_ = agent;
++ proxy_ = proxy;
++ }
++
++ // Gets/Sets the port range to use when choosing client ports.
++ int min_port() const { return min_port_; }
++ int max_port() const { return max_port_; }
++ bool SetPortRange(int min_port, int max_port) {
++ if (min_port > max_port) {
++ return false;
++ }
++
++ min_port_ = min_port;
++ max_port_ = max_port;
++ return true;
+ }
+
+-protected:
++ protected:
+ uint32 flags_;
+ std::string agent_;
+ talk_base::ProxyInfo proxy_;
++ int min_port_;
++ int max_port_;
+ };
+
+-} // namespace cricket
++} // namespace cricket
+
+-#endif // _PORTALLOCATOR_H_
++#endif // TALK_P2P_BASE_PORTALLOCATOR_H_
+diff -upN libjingle-0.5.2/talk/p2p/base/port.cc.chromium12
libjingle-0.5.2/talk/p2p/base/port.cc
+--- libjingle-0.5.2/talk/p2p/base/port.cc.chromium12 2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/port.cc 2011-03-30 21:51:32.704287001 -0400
+@@ -30,12 +30,9 @@
+ #include <algorithm>
+ #include <vector>
+
+-#include "talk/base/asyncudpsocket.h"
+-#include "talk/base/asynctcpsocket.h"
+ #include "talk/base/helpers.h"
+ #include "talk/base/logging.h"
+ #include "talk/base/scoped_ptr.h"
+-#include "talk/base/socketadapters.h"
+ #include "talk/base/stringutils.h"
+ #include "talk/p2p/base/common.h"
+
+@@ -128,11 +125,19 @@ bool StringToProto(const char* value, Pr
+ }
+
+ Port::Port(talk_base::Thread* thread, const std::string& type,
+- talk_base::SocketFactory* factory, talk_base::Network* network)
+- : thread_(thread), factory_(factory), type_(type), network_(network),
+- preference_(-1), lifetime_(LT_PRESTART), enable_port_packets_(false) {
+- if (factory_ == NULL)
+- factory_ = thread_->socketserver();
++ talk_base::PacketSocketFactory* factory, talk_base::Network* network,
++ uint32 ip, int min_port, int max_port)
++ : thread_(thread),
++ factory_(factory),
++ type_(type),
++ network_(network),
++ ip_(ip),
++ min_port_(min_port),
++ max_port_(max_port),
++ preference_(-1),
++ lifetime_(LT_PRESTART),
++ enable_port_packets_(false) {
++ ASSERT(factory_ != NULL);
+
+ set_username_fragment(talk_base::CreateRandomString(16));
+ set_password(talk_base::CreateRandomString(16));
+@@ -200,7 +205,7 @@ void Port::OnReadPacket(
+ // send back a proper binding response.
+ StunMessage* msg;
+ std::string remote_username;
+- if (!GetStunMessage(data, size, addr, msg, remote_username)) {
++ if (!GetStunMessage(data, size, addr, &msg, &remote_username)) {
+ LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address
("
+ << addr.ToString() << ")";
+ } else if (!msg) {
+@@ -219,34 +224,16 @@ void Port::OnReadPacket(
+ }
+ }
+
+-void Port::SendBindingRequest(Connection* conn) {
+- // Construct the request message.
+- StunMessage request;
+- request.SetType(STUN_BINDING_REQUEST);
+- request.SetTransactionID(talk_base::CreateRandomString(16));
+-
+- StunByteStringAttribute* username_attr =
+- StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+- std::string username = conn->remote_candidate().username();
+- username.append(username_frag_);
+- username_attr->CopyBytes(username.c_str(), username.size());
+- request.AddAttribute(username_attr);
+-
+- // Send the request message.
+- // NOTE: If we wanted to, this is where we would add the HMAC.
+- talk_base::ByteBuffer buf;
+- request.Write(&buf);
+- SendTo(buf.Data(), buf.Length(), conn->remote_candidate().address(), false);
+-}
+-
+ bool Port::GetStunMessage(const char* data, size_t size,
+ const talk_base::SocketAddress& addr,
+- StunMessage *& msg, std::string& remote_username) {
++ StunMessage** out_msg, std::string* out_username) {
+ // NOTE: This could clearly be optimized to avoid allocating any memory.
+ // However, at the data rates we'll be looking at on the client side,
+ // this probably isn't worth worrying about.
+-
+- msg = 0;
++ ASSERT(out_msg != NULL);
++ ASSERT(out_username != NULL);
++ *out_msg = NULL;
++ out_username->clear();
+
+ // Parse the request message. If the packet is not a complete and correct
+ // STUN message, then ignore it.
+@@ -268,68 +255,73 @@ bool Port::GetStunMessage(const char* da
+ if (stun_msg->type() == STUN_BINDING_REQUEST) {
+ if (remote_frag_len < 0) {
+ // Username not present or corrupted, don't reply.
+- LOG_J(LS_ERROR, this) << "Received STUN request without
username";
++ LOG_J(LS_ERROR, this) << "Received STUN request without username from
"
++ << addr.ToString();
+ return true;
+ } else if (std::memcmp(username_attr->bytes(), username_frag_.c_str(),
+ username_frag_.size()) != 0) {
+- LOG_J(LS_ERROR, this) << "Received STUN request with bad
username";
++ LOG_J(LS_ERROR, this) << "Received STUN request with bad local username
"
++ << std::string(username_attr->bytes(),
++ username_attr->length()) << "
from "
++ << addr.ToString();
+ SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
+ STUN_ERROR_REASON_BAD_REQUEST);
+ return true;
+ }
+
+- remote_username.assign(username_attr->bytes() + username_frag_.size(),
+- username_attr->bytes() + username_attr->length());
++ out_username->assign(username_attr->bytes() + username_frag_.size(),
++ username_attr->bytes() + username_attr->length());
+ } else if ((stun_msg->type() == STUN_BINDING_RESPONSE)
+ || (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
+ if (remote_frag_len < 0) {
+- // NOTE(tschmelcher): This is benign. It occurs when the response to a
+- // StunBindingRequest to the real STUN server (which involves no
+- // usernames) took too long to reach us and so the base StunRequest
+- // re-sent itself, resulting in us getting an extraneous second response
+- // that gets forwarded on to this code and correctly discarded.
+- LOG_J(LS_ERROR, this) << "Received STUN response without
username";
++ LOG_J(LS_ERROR, this) << "Received STUN response without username from
"
++ << addr.ToString();
+ // Do not send error response to a response
+ return true;
+ } else if (std::memcmp(username_attr->bytes() + remote_frag_len,
+ username_frag_.c_str(),
+ username_frag_.size()) != 0) {
+- LOG_J(LS_ERROR, this) << "Received STUN response with bad
username";
++ LOG_J(LS_ERROR, this) << "Received STUN response with bad local
username "
++ << std::string(username_attr->bytes(),
++ username_attr->length()) << "
from "
++ << addr.ToString();
+ // Do not send error response to a response
+ return true;
+ }
+
+- remote_username.assign(username_attr->bytes(),
+- username_attr->bytes() + remote_frag_len);
++ out_username->assign(username_attr->bytes(),
++ username_attr->bytes() + remote_frag_len);
+
+ if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
+ if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
+ LOG_J(LS_ERROR, this) << "Received STUN binding error:"
+- << " class=" <<
error_code->error_class()
+- << " number=" <<
error_code->number()
+- << " reason='" <<
error_code->reason() << "'";
++ << " class="
++ <<
static_cast<int>(error_code->error_class())
++ << " number="
++ << static_cast<int>(error_code->number())
++ << " reason='" <<
error_code->reason() << "'"
++ << " from " << addr.ToString();
+ // Return message to allow error-specific processing
+ } else {
+- LOG_J(LS_ERROR, this)
+- << "Received STUN error response with no error code";
++ LOG_J(LS_ERROR, this) << "Received STUN binding error without a error
"
++ << "code from " << addr.ToString();
+ // Drop corrupt message
+ return true;
+ }
+ }
+ } else {
+ LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type ("
+- << stun_msg->type() << ")";
++ << stun_msg->type() << ") from "
<< addr.ToString();
+ return true;
+ }
+
+ // Return the STUN message found.
+- msg = stun_msg.release();
++ *out_msg = stun_msg.release();
+ return true;
+ }
+
+-void Port::SendBindingResponse(
+- StunMessage* request, const talk_base::SocketAddress& addr) {
+-
++void Port::SendBindingResponse(StunMessage* request,
++ const talk_base::SocketAddress& addr) {
+ ASSERT(request->type() == STUN_BINDING_REQUEST);
+
+ // Retrieve the username from the request.
+@@ -362,7 +354,10 @@ void Port::SendBindingResponse(
+ // NOTE: If we wanted to, this is where we would add the HMAC.
+ talk_base::ByteBuffer buf;
+ response.Write(&buf);
+- SendTo(buf.Data(), buf.Length(), addr, false);
++ if (SendTo(buf.Data(), buf.Length(), addr, false) < 0) {
++ LOG_J(LS_ERROR, this) << "Failed to send STUN ping response to "
++ << addr.ToString();
++ }
+
+ // The fact that we received a successful request means that this connection
+ // (if one exists) should now be readable.
+@@ -372,13 +367,12 @@ void Port::SendBindingResponse(
+ conn->ReceivedPing();
+ }
+
+-void Port::SendBindingErrorResponse(
+- StunMessage* request, const talk_base::SocketAddress& addr, int error_code,
+- const std::string& reason) {
+-
++void Port::SendBindingErrorResponse(StunMessage* request,
++ const talk_base::SocketAddress& addr,
++ int error_code, const std::string& reason) {
+ ASSERT(request->type() == STUN_BINDING_REQUEST);
+
+- // Retrieve the username from the request. If it didn't have one, we
++ // Retrieve the username from the request. If it didn't have one, we
+ // shouldn't be responding at all.
+ const StunByteStringAttribute* username_attr =
+ request->GetByteString(STUN_ATTR_USERNAME);
+@@ -408,41 +402,8 @@ void Port::SendBindingErrorResponse(
+ talk_base::ByteBuffer buf;
+ response.Write(&buf);
+ SendTo(buf.Data(), buf.Length(), addr, false);
+-}
+-
+-talk_base::AsyncPacketSocket* Port::CreatePacketSocket(ProtocolType proto) {
+- if (proto == PROTO_UDP) {
+- // UDP sockets are simple.
+- return talk_base::AsyncUDPSocket::Create(factory_);
+- } else if (proto == PROTO_TCP || proto == PROTO_SSLTCP) {
+- // Create the base TCP socket. Bail out if this fails.
+- talk_base::AsyncSocket* socket = factory_->CreateAsyncSocket(SOCK_STREAM);
+- if (!socket) {
+- return NULL;
+- }
+-
+- // If using a proxy, wrap the socket in a proxy socket.
+- if (proxy().type == talk_base::PROXY_SOCKS5) {
+- socket = new talk_base::AsyncSocksProxySocket(
+- socket, proxy().address, proxy().username, proxy().password);
+- } else if (proxy().type == talk_base::PROXY_HTTPS) {
+- socket = new talk_base::AsyncHttpsProxySocket(
+- socket, user_agent(), proxy().address,
+- proxy().username, proxy().password);
+- }
+-
+- // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
+- if (proto == PROTO_SSLTCP) {
+- socket = new talk_base::AsyncSSLSocket(socket);
+- }
+-
+- // Finally, wrap that socket in a TCP packet socket.
+- // [Insert obligatory Taco Town reference here]
+- return new talk_base::AsyncTCPSocket(socket);
+- } else {
+- LOG_J(LS_ERROR, this) << "Unknown protocol (" << proto
<< ")";
+- return NULL;
+- }
++ LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" <<
reason
++ << " to " << addr.ToString();
+ }
+
+ void Port::OnMessage(talk_base::Message *pmsg) {
+@@ -519,15 +480,15 @@ class ConnectionRequest : public StunReq
+ }
+
+ virtual void OnResponse(StunMessage* response) {
+- connection_->OnConnectionRequestResponse(response, Elapsed());
++ connection_->OnConnectionRequestResponse(this, response);
+ }
+
+ virtual void OnErrorResponse(StunMessage* response) {
+- connection_->OnConnectionRequestErrorResponse(response, Elapsed());
++ connection_->OnConnectionRequestErrorResponse(this, response);
+ }
+
+ virtual void OnTimeout() {
+- LOG_J(LS_VERBOSE, connection_) << "Timing-out STUN ping " <<
id();
++ connection_->OnConnectionRequestTimeout(this);
+ }
+
+ virtual int GetNextDelay() {
+@@ -551,7 +512,8 @@ Connection::Connection(Port* port, size_
+ remote_candidate_(remote_candidate), read_state_(STATE_READ_TIMEOUT),
+ write_state_(STATE_WRITE_CONNECT), connected_(true), pruned_(false),
+ requests_(port->thread()), rtt_(DEFAULT_RTT),
+- last_ping_sent_(0), last_ping_received_(0), reported_(false) {
++ last_ping_sent_(0), last_ping_received_(0), last_data_received_(0),
++ reported_(false) {
+ // Wire up to send stun packets
+ requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
+ LOG_J(LS_INFO, this) << "Connection created";
+@@ -596,16 +558,18 @@ void Connection::set_connected(bool valu
+ }
+ }
+
+-void Connection::OnSendStunPacket(
+- const void* data, size_t size, StunRequest* req) {
+- port_->SendTo(data, size, remote_candidate_.address(), false);
++void Connection::OnSendStunPacket(const void* data, size_t size,
++ StunRequest* req) {
++ if (port_->SendTo(data, size, remote_candidate_.address(), false) < 0) {
++ LOG_J(LS_WARNING, this) << "Failed to send STUN ping " <<
req->id();
++ }
+ }
+
+ void Connection::OnReadPacket(const char* data, size_t size) {
+ StunMessage* msg;
+ std::string remote_username;
+ const talk_base::SocketAddress& addr(remote_candidate_.address());
+- if (!port_->GetStunMessage(data, size, addr, msg, remote_username)) {
++ if (!port_->GetStunMessage(data, size, addr, &msg, &remote_username)) {
+ // The packet did not parse as a valid STUN message
+
+ // If this connection is readable, then pass along the packet.
+@@ -613,6 +577,7 @@ void Connection::OnReadPacket(const char
+ // readable means data from this address is acceptable
+ // Send it on!
+
++ last_data_received_ = talk_base::Time();
+ recv_rate_tracker_.Update(size);
+ SignalReadPacket(this, data, size);
+
+@@ -620,24 +585,30 @@ void Connection::OnReadPacket(const char
+ if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
+ set_write_state(STATE_WRITE_CONNECT);
+ } else {
+- // Not readable means the remote address hasn't send a valid
++ // Not readable means the remote address hasn't sent a valid
+ // binding request yet.
+
+ LOG_J(LS_WARNING, this)
+ << "Received non-STUN packet from an unreadable connection.";
+ }
+ } else if (!msg) {
+- // The packet was STUN, but was already handled
++ // The packet was STUN, but was already handled internally.
+ } else if (remote_username != remote_candidate_.username()) {
+- // Not destined this connection
+- LOG_J(LS_ERROR, this) << "Received STUN packet on wrong address.";
++ // The packet had the right local username, but the remote username was
++ // not the right one for the remote address.
+ if (msg->type() == STUN_BINDING_REQUEST) {
++ LOG_J(LS_ERROR, this) << "Received STUN request with bad remote
username "
++ << remote_username;
+ port_->SendBindingErrorResponse(msg, addr, STUN_ERROR_BAD_REQUEST,
+ STUN_ERROR_REASON_BAD_REQUEST);
++ } else if (msg->type() == STUN_BINDING_RESPONSE ||
++ msg->type() == STUN_BINDING_ERROR_RESPONSE) {
++ LOG_J(LS_ERROR, this) << "Received STUN response with bad remote
username"
++ " " << remote_username;
+ }
+ delete msg;
+ } else {
+- // The packet is STUN, with the current username
++ // The packet is STUN, with the right username.
+ // If this is a STUN request, then update the readable bit and respond.
+ // If this is a STUN response, then update the writable bit.
+
+@@ -688,6 +659,18 @@ void Connection::Destroy() {
+ }
+
+ void Connection::UpdateState(uint32 now) {
++ uint32 rtt = ConservativeRTTEstimate(rtt_);
++
++ std::string pings;
++ for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
++ char buf[32];
++ talk_base::sprintfn(buf, sizeof(buf), "%u",
++ pings_since_last_response_[i]);
++ pings.append(buf).append(" ");
++ }
++ LOG_J(LS_VERBOSE, this) << "UpdateState():
pings_since_last_response_=" <<
++ pings << ", rtt=" << rtt << ", now="
<< now;
++
+ // Check the readable state.
+ //
+ // Since we don't know how many pings the other side has attempted, the best
+@@ -695,6 +678,9 @@ void Connection::UpdateState(uint32 now)
+
+ if ((read_state_ == STATE_READABLE) &&
+ (last_ping_received_ + CONNECTION_READ_TIMEOUT <= now)) {
++ LOG_J(LS_INFO, this) << "Unreadable after "
++ << now - last_ping_received_
++ << " ms without a ping, rtt=" << rtt;
+ set_read_state(STATE_READ_TIMEOUT);
+ }
+
+@@ -707,18 +693,6 @@ void Connection::UpdateState(uint32 now)
+ // Before timing out writability, we give a fixed amount of time. This is to
+ // allow for changes in network conditions.
+
+- uint32 rtt = ConservativeRTTEstimate(rtt_);
+-
+- std::string pings;
+- for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
+- char buf[32];
+- talk_base::sprintfn(buf, sizeof(buf), "%u",
+- pings_since_last_response_[i]);
+- pings.append(buf).append(" ");
+- }
+- LOG_J(LS_VERBOSE, this) << "UpdateState(): pings_since_last_response_ =
" <<
+- pings << ", rtt = " << rtt << ", now = "
<< now;
+-
+ if ((write_state_ == STATE_WRITABLE) &&
+ TooManyFailures(pings_since_last_response_,
+ CONNECTION_WRITE_CONNECT_FAILURES,
+@@ -727,6 +701,16 @@ void Connection::UpdateState(uint32 now)
+ TooLongWithoutResponse(pings_since_last_response_,
+ CONNECTION_WRITE_CONNECT_TIMEOUT,
+ now)) {
++ uint32 max_pings = CONNECTION_WRITE_CONNECT_FAILURES;
++ LOG_J(LS_INFO, this) << "Unwritable after " << max_pings
++ << " ping failures and "
++ << now - pings_since_last_response_[0]
++ << " ms without a response,"
++ << " ms since last received ping="
++ << now - last_ping_received_
++ << " ms since last received data="
++ << now - last_data_received_
++ << " rtt=" << rtt;
+ set_write_state(STATE_WRITE_CONNECT);
+ }
+
+@@ -734,6 +718,9 @@ void Connection::UpdateState(uint32 now)
+ TooLongWithoutResponse(pings_since_last_response_,
+ CONNECTION_WRITE_TIMEOUT,
+ now)) {
++ LOG_J(LS_INFO, this) << "Timed out after "
++ << now - pings_since_last_response_[0]
++ << " ms without a response, rtt=" <<
rtt;
+ set_write_state(STATE_WRITE_TIMEOUT);
+ }
+ }
+@@ -778,79 +765,46 @@ std::string Connection::ToString() const
+ << CONNECT_STATE_ABBREV[connected()]
+ << READ_STATE_ABBREV[read_state()]
+ << WRITE_STATE_ABBREV[write_state()]
+- << "|" << rtt_ << "]";
++ << "|";
++ if (rtt_ < DEFAULT_RTT) {
++ ss << rtt_ << "]";
++ } else {
++ ss << "-]";
++ }
+ return ss.str();
+ }
+
+-void Connection::OnConnectionRequestResponse(StunMessage* response,
+- uint32 rtt) {
+- // We have a potentially valid reply from the remote address.
+- // The packet must include a username that ends with our fragment,
+- // since it is a response.
+-
+- // Check exact message type
+- bool valid = true;
+- if (response->type() != STUN_BINDING_RESPONSE)
+- valid = false;
+-
+- // Must have username attribute
+- const StunByteStringAttribute* username_attr =
+- response->GetByteString(STUN_ATTR_USERNAME);
+- if (valid) {
+- if (!username_attr) {
+- LOG_J(LS_ERROR, this) << "Received likely STUN packet with no
username";
+- valid = false;
+- }
+- }
+-
+- // Length must be at least the size of our fragment (actually, should
+- // be bigger since our fragment is at the end!)
+- if (valid) {
+- if (username_attr->length() <= port_->username_fragment().size()) {
+- LOG_J(LS_ERROR, this) << "Received likely STUN packet with short
username";
+- valid = false;
+- }
+- }
++void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
++ StunMessage* response) {
++ // We've already validated that this is a STUN binding response with
++ // the correct local and remote username for this connection.
++ // So if we're not already, become writable. We may be bringing a pruned
++ // connection back to life, but if we don't really want it, we can always
++ // prune it again.
++ uint32 rtt = request->Elapsed();
++ set_write_state(STATE_WRITABLE);
+
+- // Compare our fragment with the end of the username - must be exact match
+- if (valid) {
+- std::string username_fragment = port_->username_fragment();
+- int offset = (int)(username_attr->length() - username_fragment.size());
+- if (std::memcmp(username_attr->bytes() + offset,
+- username_fragment.c_str(), username_fragment.size()) != 0) {
+- LOG_J(LS_ERROR, this) << "Received STUN response with bad
username";
+- valid = false;
+- }
++ std::string pings;
++ for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
++ char buf[32];
++ talk_base::sprintfn(buf, sizeof(buf), "%u",
++ pings_since_last_response_[i]);
++ pings.append(buf).append(" ");
+ }
+
+- if (valid) {
+- // Valid response. If we're not already, become writable. We may be
+- // bringing a pruned connection back to life, but if we don't really want
+- // it, we can always prune it again.
+- set_write_state(STATE_WRITABLE);
+-
+- std::string pings;
+- for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
+- char buf[32];
+- talk_base::sprintfn(buf, sizeof(buf), "%u",
+- pings_since_last_response_[i]);
+- pings.append(buf).append(" ");
+- }
+- LOG_J(LS_VERBOSE, this) << "OnConnectionRequestResponse(): "
+- "pings_since_last_response_ = " << pings << ", rtt =
" << rtt;
+-
+- pings_since_last_response_.clear();
+- rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
++ LOG_J(LS_VERBOSE, this) << "Received STUN ping response " <<
request->id()
++ << ", pings_since_last_response_=" <<
pings
++ << ", rtt=" << rtt;
+
+- LOG_J(LS_VERBOSE, this) << "Received STUN ping response " <<
+- response->transaction_id() << " after rtt = " << rtt;
+- }
++ pings_since_last_response_.clear();
++ rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
+ }
+
+-void Connection::OnConnectionRequestErrorResponse(StunMessage *response,
+- uint32 rtt) {
++void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
++ StunMessage* response) {
+ const StunErrorCodeAttribute* error = response->GetErrorCode();
+- uint32 error_code = error ? error->error_code() : STUN_ERROR_GLOBAL_FAILURE;
++ uint32 error_code = error ?
++ error->error_code() : static_cast<uint32>(STUN_ERROR_GLOBAL_FAILURE);
+
+ if ((error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE)
+ || (error_code == STUN_ERROR_SERVER_ERROR)
+@@ -860,16 +814,33 @@ void Connection::OnConnectionRequestErro
+ // Race failure, retry
+ } else {
+ // This is not a valid connection.
+- LOG_J(LS_ERROR, this) << "Received STUN error response; killing
connection";
++ LOG_J(LS_ERROR, this) << "Received STUN error response, code="
++ << error_code << "; killing
connection";
+ set_write_state(STATE_WRITE_TIMEOUT);
+ }
+ }
+
++void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
++ // Log at LS_INFO if we miss a ping on a writable connection.
++ talk_base::LoggingSeverity sev = (write_state_ == STATE_WRITABLE) ?
++ talk_base::LS_INFO : talk_base::LS_VERBOSE;
++ uint32 when = talk_base::Time() - request->Elapsed();
++ size_t failures;
++ for (failures = 0; failures < pings_since_last_response_.size(); ++failures) {
++ if (pings_since_last_response_[failures] > when) {
++ break;
++ }
++ }
++ LOG_JV(sev, this) << "Timing-out STUN ping " <<
request->id()
++ << " after " << request->Elapsed()
++ << " ms, failures=" << failures;
++}
++
+ void Connection::CheckTimeout() {
+ // If both read and write have timed out, then this connection can contribute
+ // no more to p2p socket unless at some later date readability were to come
+ // back. However, we gave readability a long time to timeout, so at this
+- // point, it seems fair to get rid of this connectoin.
++ // point, it seems fair to get rid of this connection.
+ if ((read_state_ == STATE_READ_TIMEOUT) &&
+ (write_state_ == STATE_WRITE_TIMEOUT)) {
+ port_->thread()->Post(this, MSG_DELETE);
+diff -upN libjingle-0.5.2/talk/p2p/base/port.h.chromium12
libjingle-0.5.2/talk/p2p/base/port.h
+--- libjingle-0.5.2/talk/p2p/base/port.h.chromium12 2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/port.h 2011-03-30 21:51:32.704287001 -0400
+@@ -33,10 +33,11 @@
+ #include <map>
+
+ #include "talk/base/network.h"
+-#include "talk/base/socketaddress.h"
++#include "talk/base/packetsocketfactory.h"
+ #include "talk/base/proxyinfo.h"
+ #include "talk/base/ratetracker.h"
+ #include "talk/base/sigslot.h"
++#include "talk/base/socketaddress.h"
+ #include "talk/base/thread.h"
+ #include "talk/p2p/base/candidate.h"
+ #include "talk/p2p/base/stun.h"
+@@ -49,6 +50,7 @@ class AsyncPacketSocket;
+ namespace cricket {
+
+ class Connection;
++class ConnectionRequest;
+
+ enum ProtocolType {
+ PROTO_UDP,
+@@ -73,17 +75,19 @@ struct ProtocolAddress {
+ // one add support for specific mechanisms like local UDP ports.
+ class Port : public talk_base::MessageHandler, public sigslot::has_slots<> {
+ public:
+- Port(talk_base::Thread* thread, const std::string &type,
+- talk_base::SocketFactory* factory, talk_base::Network* network);
++ Port(talk_base::Thread* thread, const std::string& type,
++ talk_base::PacketSocketFactory* factory, talk_base::Network* network,
++ uint32 ip, int min_port, int max_port);
+ virtual ~Port();
+
+ // The thread on which this port performs its I/O.
+ talk_base::Thread* thread() { return thread_; }
+
+ // The factory used to create the sockets of this port.
+- talk_base::SocketFactory* socket_factory() const { return factory_; }
+- void set_socket_factory(talk_base::SocketFactory* factory)
+- { factory_ = factory; }
++ talk_base::PacketSocketFactory* socket_factory() const { return factory_; }
++ void set_socket_factory(talk_base::PacketSocketFactory* factory) {
++ factory_ = factory;
++ }
+
+ // Each port is identified by a name (for debugging purposes).
+ const std::string& name() const { return name_; }
+@@ -110,7 +114,6 @@ class Port : public talk_base::MessageHa
+ void set_preference(float preference) { preference_ = preference; }
+
+ // Identifies the port type.
+- //const std::string& protocol() const { return proto_; }
+ const std::string& type() const { return type_; }
+
+ // Identifies network that this port was allocated on.
+@@ -185,8 +188,6 @@ class Port : public talk_base::MessageHa
+ const std::string& user_agent() { return user_agent_; }
+ const talk_base::ProxyInfo& proxy() { return proxy_; }
+
+- talk_base::AsyncPacketSocket * CreatePacketSocket(ProtocolType proto);
+-
+ // Normally, packets arrive through a connection (or they result signaling of
+ // unknown address). Calling this method turns off delivery of packets
+ // through their respective connection and instead delivers every packet
+@@ -212,20 +213,6 @@ class Port : public talk_base::MessageHa
+ std::string ToString() const;
+
+ protected:
+- talk_base::Thread* thread_;
+- talk_base::SocketFactory* factory_;
+- std::string type_;
+- talk_base::Network* network_;
+- uint32 generation_;
+- std::string name_;
+- std::string username_frag_;
+- std::string password_;
+- float preference_;
+- std::vector<Candidate> candidates_;
+- AddressMap connections_;
+- enum Lifetime { LT_PRESTART, LT_PRETIMEOUT, LT_POSTTIMEOUT } lifetime_;
+- bool enable_port_packets_;
+-
+ // Fills in the local address of the port.
+ void AddAddress(const talk_base::SocketAddress& address,
+ const std::string& protocol, bool final);
+@@ -239,8 +226,6 @@ class Port : public talk_base::MessageHa
+ void OnReadPacket(const char* data, size_t size,
+ const talk_base::SocketAddress& addr);
+
+- // Constructs a STUN binding request for the given connection and sends it.
+- void SendBindingRequest(Connection* conn);
+
+ // If the given data comprises a complete and correct STUN message then the
+ // return value is true, otherwise false. If the message username corresponds
+@@ -249,9 +234,25 @@ class Port : public talk_base::MessageHa
+ // remote_username contains the remote fragment of the STUN username.
+ bool GetStunMessage(const char* data, size_t size,
+ const talk_base::SocketAddress& addr,
+- StunMessage *& msg, std::string& remote_username);
++ StunMessage** out_msg, std::string* out_username);
+
+- friend class Connection;
++ // TODO: make these members private
++ talk_base::Thread* thread_;
++ talk_base::PacketSocketFactory* factory_;
++ std::string type_;
++ talk_base::Network* network_;
++ uint32 ip_;
++ int min_port_;
++ int max_port_;
++ uint32 generation_;
++ std::string name_;
++ std::string username_frag_;
++ std::string password_;
++ float preference_;
++ std::vector<Candidate> candidates_;
++ AddressMap connections_;
++ enum Lifetime { LT_PRESTART, LT_PRETIMEOUT, LT_POSTTIMEOUT } lifetime_;
++ bool enable_port_packets_;
+
+ private:
+ // Called when one of our connections deletes itself.
+@@ -263,6 +264,8 @@ class Port : public talk_base::MessageHa
+ // Information to use when going through a proxy.
+ std::string user_agent_;
+ talk_base::ProxyInfo proxy_;
++
++ friend class Connection;
+ };
+
+ // Represents a communication link between a port on the local client and a
+@@ -331,7 +334,7 @@ class Connection : public talk_base::Mes
+ // still keep it around in case the other side wants to use it. But we can
+ // safely stop pinging on it and we can allow it to time out if the other
+ // side stops using it as well.
+- bool pruned() { return pruned_; }
++ bool pruned() const { return pruned_; }
+ void Prune();
+
+ // Makes the connection go away.
+@@ -342,7 +345,7 @@ class Connection : public talk_base::Mes
+ void UpdateState(uint32 now);
+
+ // Called when this connection should try checking writability again.
+- uint32 last_ping_sent() { return last_ping_sent_; }
++ uint32 last_ping_sent() const { return last_ping_sent_; }
+ void Ping(uint32 now);
+
+ // Called whenever a valid ping is received on this connection. This is
+@@ -352,10 +355,33 @@ class Connection : public talk_base::Mes
+ // Debugging description of this connection
+ std::string ToString() const;
+
+- bool reported() { return reported_; }
++ bool reported() const { return reported_; }
+ void set_reported(bool reported) { reported_ = reported;}
+
+ protected:
++ // Constructs a new connection to the given remote port.
++ Connection(Port* port, size_t index, const Candidate& candidate);
++
++ // Called back when StunRequestManager has a stun packet to send
++ void OnSendStunPacket(const void* data, size_t size, StunRequest* req);
++
++ // Callbacks from ConnectionRequest
++ void OnConnectionRequestResponse(ConnectionRequest* req,
++ StunMessage* response);
++ void OnConnectionRequestErrorResponse(ConnectionRequest* req,
++ StunMessage* response);
++ void OnConnectionRequestTimeout(ConnectionRequest* req);
++
++ // Changes the state and signals if necessary.
++ void set_read_state(ReadState value);
++ void set_write_state(WriteState value);
++ void set_connected(bool value);
++
++ // Checks if this connection is useless, and hence, should be destroyed.
++ void CheckTimeout();
++
++ void OnMessage(talk_base::Message *pmsg);
++
+ Port* port_;
+ size_t local_candidate_index_;
+ Candidate remote_candidate_;
+@@ -368,36 +394,17 @@ class Connection : public talk_base::Mes
+ uint32 last_ping_sent_; // last time we sent a ping to the other side
+ uint32 last_ping_received_; // last time we received a ping from the other
+ // side
++ uint32 last_data_received_;
+ std::vector<uint32> pings_since_last_response_;
+
+ talk_base::RateTracker recv_rate_tracker_;
+ talk_base::RateTracker send_rate_tracker_;
+
+- // Callbacks from ConnectionRequest
+- void OnConnectionRequestResponse(StunMessage *response, uint32 rtt);
+- void OnConnectionRequestErrorResponse(StunMessage *response, uint32 rtt);
+-
+- // Called back when StunRequestManager has a stun packet to send
+- void OnSendStunPacket(const void* data, size_t size, StunRequest* req);
+-
+- // Constructs a new connection to the given remote port.
+- Connection(Port* port, size_t index, const Candidate& candidate);
+-
+- // Changes the state and signals if necessary.
+- void set_read_state(ReadState value);
+- void set_write_state(WriteState value);
+- void set_connected(bool value);
+-
+- // Checks if this connection is useless, and hence, should be destroyed.
+- void CheckTimeout();
+-
+- void OnMessage(talk_base::Message *pmsg);
++ private:
++ bool reported_;
+
+ friend class Port;
+ friend class ConnectionRequest;
+-
+- private:
+- bool reported_;
+ };
+
+ // ProxyConnection defers all the interesting work to the port
+diff -upN libjingle-0.5.2/talk/p2p/base/pseudotcp.cc.chromium12
libjingle-0.5.2/talk/p2p/base/pseudotcp.cc
+--- libjingle-0.5.2/talk/p2p/base/pseudotcp.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/pseudotcp.cc 2011-03-30 21:51:32.705287001 -0400
+@@ -118,7 +118,7 @@ const uint32 PACKET_OVERHEAD = HEADER_SI
+ const uint32 MIN_RTO = 250; // 250 ms (RFC1122, Sec 4.2.3.1 "fractions of a
second")
+ const uint32 DEF_RTO = 3000; // 3 seconds (RFC1122, Sec 4.2.3.1)
+ const uint32 MAX_RTO = 60000; // 60 seconds
+-const uint32 ACK_DELAY = 100; // 100 milliseconds
++const uint32 DEF_ACK_DELAY = 100; // 100 milliseconds
+
+ const uint8 FLAG_CTL = 0x02;
+ const uint8 FLAG_RST = 0x04;
+@@ -256,6 +256,9 @@ PseudoTcp::PseudoTcp(IPseudoTcpNotify* n
+
+ m_rx_rto = DEF_RTO;
+ m_rx_srtt = m_rx_rttvar = 0;
++
++ m_use_nagling = true;
++ m_ack_delay = DEF_ACK_DELAY;
+ }
+
+ PseudoTcp::~PseudoTcp() {
+@@ -337,7 +340,7 @@ void PseudoTcp::NotifyClock(uint32 now)
+ }
+
+ // Check if it's time to send delayed acks
+- if (m_t_ack && (talk_base::TimeDiff(m_t_ack + ACK_DELAY, now) <= 0)) {
++ if (m_t_ack && (talk_base::TimeDiff(m_t_ack + m_ack_delay, now) <= 0)) {
+ packet(m_snd_nxt, 0, 0, 0);
+ }
+
+@@ -367,6 +370,26 @@ bool PseudoTcp::GetNextClock(uint32 now,
+ return clock_check(now, timeout);
+ }
+
++void PseudoTcp::GetOption(Option opt, int* value) {
++ if (opt == OPT_NODELAY) {
++ *value = m_use_nagling ? 0 : 1;
++ } else if (opt == OPT_ACKDELAY) {
++ *value = m_ack_delay;
++ } else {
++ ASSERT(false);
++ }
++}
++
++void PseudoTcp::SetOption(Option opt, int value) {
++ if (opt == OPT_NODELAY) {
++ m_use_nagling = value == 0;
++ } else if (opt == OPT_ACKDELAY) {
++ m_ack_delay = value;
++ } else {
++ ASSERT(false);
++ }
++}
++
+ //
+ // IPStream Implementation
+ //
+@@ -554,7 +577,7 @@ bool PseudoTcp::clock_check(uint32 now,
+
+ if (m_t_ack) {
+ nTimeout = talk_base::_min<int32>(nTimeout,
+- talk_base::TimeDiff(m_t_ack + ACK_DELAY, now));
++ talk_base::TimeDiff(m_t_ack + m_ack_delay, now));
+ }
+ if (m_rto_base) {
+ nTimeout = talk_base::_min<int32>(nTimeout,
+@@ -774,7 +797,11 @@ bool PseudoTcp::process(Segment& seg) {
+ if (seg.seq != m_rcv_nxt) {
+ sflags = sfImmediateAck; // (Fast Recovery)
+ } else if (seg.len != 0) {
+- sflags = sfDelayedAck;
++ if (m_ack_delay == 0) {
++ sflags = sfImmediateAck;
++ } else {
++ sflags = sfDelayedAck;
++ }
+ }
+ #if _DEBUGMSG >= _DBG_NORMAL
+ if (sflags == sfImmediateAck) {
+@@ -992,8 +1019,11 @@ void PseudoTcp::attemptSend(SendFlags sf
+ return;
+ }
+
+- // Nagle algorithm
+- if ((m_snd_nxt > m_snd_una) && (nAvailable < m_mss)) {
++ // Nagle's algorithm.
++ // If there is data already in-flight, and we haven't a full segment of
++ // data ready to send then hold off until we get more to send, or the
++ // in-flight data is acknowledged.
++ if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable <
m_mss)) {
+ return;
+ }
+
+diff -upN libjingle-0.5.2/talk/p2p/base/pseudotcp.h.chromium12
libjingle-0.5.2/talk/p2p/base/pseudotcp.h
+--- libjingle-0.5.2/talk/p2p/base/pseudotcp.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/pseudotcp.h 2011-03-30 21:51:32.705287001 -0400
+@@ -92,6 +92,18 @@ class PseudoTcp {
+ // Returns false if the socket is ready to be destroyed.
+ bool GetNextClock(uint32 now, long& timeout);
+
++ // Call these to get/set option values to tailor this PseudoTcp
++ // instance's behaviour for the kind of data it will carry.
++ // If an unrecognized option is set or got, an assertion will fire.
++ enum Option {
++ OPT_NODELAY, // Whether to enable Nagle's algorithm (0 == off)
++ OPT_ACKDELAY, // The Delayed ACK timeout (0 == off).
++ //kOptRcvBuf, // Set the receive buffer size, in bytes.
++ //kOptSndBuf, // Set the send buffer size, in bytes.
++ };
++ void GetOption(Option opt, int* value);
++ void SetOption(Option opt, int value);
++
+ protected:
+ enum SendFlags { sfNone, sfDelayedAck, sfImmediateAck };
+ enum {
+@@ -180,6 +192,10 @@ class PseudoTcp {
+ uint8 m_dup_acks;
+ uint32 m_recover;
+ uint32 m_t_ack;
++
++ // Configuration options
++ bool m_use_nagling;
++ uint32 m_ack_delay;
+ };
+
+ } // namespace cricket
+diff -upN libjingle-0.5.2/talk/p2p/base/relayport.cc.chromium12
libjingle-0.5.2/talk/p2p/base/relayport.cc
+--- libjingle-0.5.2/talk/p2p/base/relayport.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/relayport.cc 2011-03-30 21:51:32.706287001 -0400
+@@ -25,11 +25,7 @@
+ * 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/asyncpacketsocket.h"
+ #include "talk/base/helpers.h"
+ #include "talk/base/logging.h"
+ #include "talk/p2p/base/relayport.h"
+@@ -96,8 +92,7 @@ class RelayConnection : public sigslot::
+ class RelayEntry : public talk_base::MessageHandler,
+ public sigslot::has_slots<> {
+ public:
+- RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr,
+- const talk_base::SocketAddress& local_addr);
++ RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr);
+ ~RelayEntry();
+
+ RelayPort* port() { return port_; }
+@@ -148,21 +143,20 @@ class RelayEntry : public talk_base::Mes
+
+ private:
+ RelayPort* port_;
+- talk_base::SocketAddress ext_addr_, local_addr_;
++ talk_base::SocketAddress ext_addr_;
+ size_t server_index_;
+ bool connected_;
+ bool locked_;
+ RelayConnection* current_connection_;
+
+ // Called when a TCP connection is established or fails
+- void OnSocketConnect(talk_base::AsyncTCPSocket* socket);
+- void OnSocketClose(talk_base::AsyncTCPSocket* socket, int error);
++ void OnSocketConnect(talk_base::AsyncPacketSocket* socket);
++ void OnSocketClose(talk_base::AsyncPacketSocket* socket, int error);
+
+ // Called when a packet is received on this socket.
+- void OnReadPacket(
+- const char* data, size_t size,
+- const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket);
++ void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr);
+
+ // Sends the given data on the socket to the server with no wrapping. This
+ // returns the number of bytes written or -1 if an error occurred.
+@@ -192,14 +186,16 @@ class AllocateRequest : public StunReque
+ const std::string RELAY_PORT_TYPE("relay");
+
+ RelayPort::RelayPort(
+- talk_base::Thread* thread, talk_base::SocketFactory* factory,
+- talk_base::Network* network, const talk_base::SocketAddress& local_addr,
++ talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++ talk_base::Network* network, uint32 ip, int min_port, int max_port,
+ const std::string& username, const std::string& password,
+ const std::string& magic_cookie)
+- : Port(thread, RELAY_PORT_TYPE, factory, network), local_addr_(local_addr),
+- ready_(false), magic_cookie_(magic_cookie), error_(0) {
++ : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port),
++ ready_(false),
++ magic_cookie_(magic_cookie),
++ error_(0) {
+ entries_.push_back(
+- new RelayEntry(this, talk_base::SocketAddress(), local_addr_));
++ new RelayEntry(this, talk_base::SocketAddress()));
+
+ set_username_fragment(username);
+ set_password(password);
+@@ -316,7 +312,7 @@ int RelayPort::SendTo(const void* data,
+ // If we did not find one, then we make a new one. This will not be useable
+ // until it becomes connected, however.
+ if (!entry && payload) {
+- entry = new RelayEntry(this, addr, local_addr_);
++ entry = new RelayEntry(this, addr);
+ if (!entries_.empty()) {
+ entry->SetServerIndex(entries_[0]->ServerIndex());
+ }
+@@ -345,7 +341,7 @@ int RelayPort::SendTo(const void* data,
+ }
+ // The caller of the function is expecting the number of user data bytes,
+ // rather than the size of the packet.
+- return (int)size;
++ return size;
+ }
+
+ int RelayPort::SetOption(talk_base::Socket::Option opt, int value) {
+@@ -420,9 +416,8 @@ void RelayConnection::SendAllocateReques
+ }
+
+ RelayEntry::RelayEntry(RelayPort* port,
+- const talk_base::SocketAddress& ext_addr,
+- const talk_base::SocketAddress& local_addr)
+- : port_(port), ext_addr_(ext_addr), local_addr_(local_addr),
++ const talk_base::SocketAddress& ext_addr)
++ : port_(port), ext_addr_(ext_addr),
+ server_index_(0), connected_(false), locked_(false),
+ current_connection_(NULL) {
+ }
+@@ -455,13 +450,23 @@ void RelayEntry::Connect() {
+ LOG(LS_INFO) << "Connecting to relay via " <<
ProtoToString(ra->proto) <<
+ " @ " << ra->address.ToString();
+
+- talk_base::AsyncPacketSocket* socket = port_->CreatePacketSocket(ra->proto);
++ talk_base::AsyncPacketSocket* socket = NULL;
++
++ if (ra->proto == PROTO_UDP) {
++ // UDP sockets are simple.
++ socket = port_->socket_factory()->CreateUdpSocket(
++ talk_base::SocketAddress(port_->ip_, 0),
++ port_->min_port_, port_->max_port_);
++ } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) {
++ socket = port_->socket_factory()->CreateClientTcpSocket(
++ talk_base::SocketAddress(port_->ip_, 0), ra->address,
++ port_->proxy(), port_->user_agent(), ra->proto == PROTO_SSLTCP);
++ } else {
++ LOG(LS_WARNING) << "Unknown protocol (" << ra->proto
<< ")";
++ }
++
+ if (!socket) {
+ LOG(LS_WARNING) << "Socket creation failed";
+- } else if (socket->Bind(local_addr_) < 0) {
+- LOG(LS_WARNING) << "Socket bind failed with error " <<
socket->GetError();
+- delete socket;
+- socket = NULL;
+ }
+
+ // If we failed to get a socket, move on to the next protocol.
+@@ -479,13 +484,10 @@ void RelayEntry::Connect() {
+ }
+
+ // If we're trying UDP, start binding requests.
+- // If we're trying TCP, initiate a connection with a fixed timeout.
++ // If we're trying TCP, wait for connection with a fixed timeout.
+ if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
+- talk_base::AsyncTCPSocket* tcp =
+- static_cast<talk_base::AsyncTCPSocket*>(socket);
+- tcp->SignalClose.connect(this, &RelayEntry::OnSocketClose);
+- tcp->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
+- tcp->Connect(ra->address);
++ socket->SignalClose.connect(this, &RelayEntry::OnSocketClose);
++ socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
+ port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this,
+ kMessageConnectTimeout);
+ } else {
+@@ -538,13 +540,13 @@ int RelayEntry::SendTo(const void* data,
+ StunByteStringAttribute* magic_cookie_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+ magic_cookie_attr->CopyBytes(port_->magic_cookie().c_str(),
+- (uint16)port_->magic_cookie().size());
++ port_->magic_cookie().size());
+ request.AddAttribute(magic_cookie_attr);
+
+ StunByteStringAttribute* username_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ username_attr->CopyBytes(port_->username_fragment().c_str(),
+- (uint16)port_->username_fragment().size());
++ port_->username_fragment().size());
+ request.AddAttribute(username_attr);
+
+ StunAddressAttribute* addr_attr =
+@@ -564,7 +566,7 @@ int RelayEntry::SendTo(const void* data,
+
+ StunByteStringAttribute* data_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_DATA);
+- data_attr->CopyBytes(data, (uint16)size);
++ data_attr->CopyBytes(data, size);
+ request.AddAttribute(data_attr);
+
+ // TODO: compute the HMAC.
+@@ -616,8 +618,8 @@ void RelayEntry::OnMessage(talk_base::Me
+ // the next address, otherwise give this connection more time and
+ // await the real timeout.
+ //
+- // TODO: Connect to servers in pararel to speed up connect time
+- // and to avoid giving up to early.
++ // TODO: Connect to servers in parallel to speed up connect time
++ // and to avoid giving up too early.
+ port_->SignalSoftTimeout(ra);
+ HandleConnectFailure(current_connection_->socket());
+ } else {
+@@ -625,7 +627,7 @@ void RelayEntry::OnMessage(talk_base::Me
+ }
+ }
+
+-void RelayEntry::OnSocketConnect(talk_base::AsyncTCPSocket* socket) {
++void RelayEntry::OnSocketConnect(talk_base::AsyncPacketSocket* socket) {
+ LOG(INFO) << "relay tcp connected to " <<
+ socket->GetRemoteAddress().ToString();
+ if (current_connection_ != NULL) {
+@@ -633,14 +635,15 @@ void RelayEntry::OnSocketConnect(talk_ba
+ }
+ }
+
+-void RelayEntry::OnSocketClose(talk_base::AsyncTCPSocket* socket, int error) {
++void RelayEntry::OnSocketClose(talk_base::AsyncPacketSocket* socket,
++ int error) {
+ PLOG(LERROR, error) << "Relay connection failed: socket closed";
+ HandleConnectFailure(socket);
+ }
+
+-void RelayEntry::OnReadPacket(const char* data, size_t size,
+- const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket) {
++void RelayEntry::OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr) {
+ // ASSERT(remote_addr == port_->server_addr());
+ // TODO: are we worried about this?
+
+@@ -732,14 +735,14 @@ void AllocateRequest::Prepare(StunMessag
+ StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+ magic_cookie_attr->CopyBytes(
+ entry_->port()->magic_cookie().c_str(),
+- (uint16)entry_->port()->magic_cookie().size());
++ entry_->port()->magic_cookie().size());
+ request->AddAttribute(magic_cookie_attr);
+
+ StunByteStringAttribute* username_attr =
+ StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+ username_attr->CopyBytes(
+ entry_->port()->username_fragment().c_str(),
+- (uint16)entry_->port()->username_fragment().size());
++ entry_->port()->username_fragment().size());
+ request->AddAttribute(username_attr);
+ }
+
+diff -upN libjingle-0.5.2/talk/p2p/base/relayport.h.chromium12
libjingle-0.5.2/talk/p2p/base/relayport.h
+--- libjingle-0.5.2/talk/p2p/base/relayport.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/relayport.h 2011-03-30 21:51:32.706287001 -0400
+@@ -28,8 +28,11 @@
+ #ifndef TALK_P2P_BASE_RELAYPORT_H_
+ #define TALK_P2P_BASE_RELAYPORT_H_
+
++#include <deque>
+ #include <string>
++#include <utility>
+ #include <vector>
++
+ #include "talk/p2p/base/port.h"
+ #include "talk/p2p/base/stunrequest.h"
+
+@@ -51,18 +54,13 @@ class RelayPort : public Port {
+
+ // RelayPort doesn't yet do anything fancy in the ctor.
+ static RelayPort* Create(
+- talk_base::Thread* thread, talk_base::SocketFactory* factory,
+- talk_base::Network* network, const talk_base::SocketAddress& local_addr,
+- const std::string& username, const std::string& password,
+- const std::string& magic_cookie) {
+- return new RelayPort(thread, factory, network, local_addr,
++ talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++ talk_base::Network* network, uint32 ip, int min_port, int max_port,
++ const std::string& username, const std::string& password,
++ const std::string& magic_cookie) {
++ return new RelayPort(thread, factory, network, ip, min_port, max_port,
+ username, password, magic_cookie);
+ }
+- RelayPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+- talk_base::Network*, const talk_base::SocketAddress& local_addr,
+- const std::string& username, const std::string& password,
+- const std::string& magic_cookie);
+- bool Init();
+ virtual ~RelayPort();
+
+ void AddServerAddress(const ProtocolAddress& addr);
+@@ -86,6 +84,12 @@ class RelayPort : public Port {
+ sigslot::signal1<const ProtocolAddress*> SignalSoftTimeout;
+
+ protected:
++ RelayPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++ talk_base::Network*, uint32 ip, int min_port, int max_port,
++ const std::string& username, const std::string& password,
++ const std::string& magic_cookie);
++ bool Init();
++
+ void SetReady();
+
+ virtual int SendTo(const void* data, size_t size,
+@@ -98,7 +102,6 @@ class RelayPort : public Port {
+ private:
+ friend class RelayEntry;
+
+- talk_base::SocketAddress local_addr_;
+ std::deque<ProtocolAddress> server_addr_;
+ bool ready_;
+ std::vector<RelayEntry*> entries_;
+diff -upN libjingle-0.5.2/talk/p2p/base/relayserver.cc.chromium12
libjingle-0.5.2/talk/p2p/base/relayserver.cc
+--- libjingle-0.5.2/talk/p2p/base/relayserver.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/relayserver.cc 2011-03-30 21:51:32.706287001 -0400
+@@ -159,12 +159,24 @@ void RelayServer::RemoveInternalServerSo
+ socket->SignalReadEvent.disconnect(this);
+ }
+
+-int RelayServer::GetConnectionCount() {
++int RelayServer::GetConnectionCount() const {
+ return connections_.size();
+ }
+
+-bool RelayServer::HasConnection(const talk_base::SocketAddress& address) {
+- for (ConnectionMap::iterator it = connections_.begin();
++talk_base::SocketAddressPair RelayServer::GetConnection(int connection) const {
++ int i = 0;
++ for (ConnectionMap::const_iterator it = connections_.begin();
++ it != connections_.end(); ++it) {
++ if (i == connection) {
++ return it->second->addr_pair();
++ }
++ ++i;
++ }
++ return talk_base::SocketAddressPair();
++}
++
++bool RelayServer::HasConnection(const talk_base::SocketAddress& address) const {
++ for (ConnectionMap::const_iterator it = connections_.begin();
+ it != connections_.end(); ++it) {
+ if (it->second->addr_pair().destination() == address) {
+ return true;
+@@ -180,11 +192,14 @@ void RelayServer::OnReadEvent(talk_base:
+ }
+
+ void RelayServer::OnInternalPacket(
+- const char* bytes, size_t size, const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket) {
++ talk_base::AsyncPacketSocket* socket, const char* bytes, size_t size,
++ const talk_base::SocketAddress& remote_addr) {
+
+ // Get the address of the connection we just received on.
+- talk_base::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
++ bool allocated;
++ talk_base::SocketAddressPair ap(
++ remote_addr, socket->GetLocalAddress(&allocated));
++ ASSERT(allocated);
+ ASSERT(!ap.destination().IsAny());
+
+ // If this did not come from an existing connection, it should be a STUN
+@@ -224,11 +239,14 @@ void RelayServer::OnInternalPacket(
+ }
+
+ void RelayServer::OnExternalPacket(
+- const char* bytes, size_t size, const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket) {
++ talk_base::AsyncPacketSocket* socket, const char* bytes, size_t size,
++ const talk_base::SocketAddress& remote_addr) {
+
+ // Get the address of the connection we just received on.
+- talk_base::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
++ bool allocated;
++ talk_base::SocketAddressPair ap(
++ remote_addr, socket->GetLocalAddress(&allocated));
++ ASSERT(allocated);
+ ASSERT(!ap.destination().IsAny());
+
+ // If this connection already exists, then forward the traffic.
+@@ -425,8 +443,10 @@ void RelayServer::HandleStunAllocate(
+ response.AddAttribute(magic_cookie_attr);
+
+ size_t index = rand() % external_sockets_.size();
++ bool allocated;
+ talk_base::SocketAddress ext_addr =
+- external_sockets_[index]->GetLocalAddress();
++ external_sockets_[index]->GetLocalAddress(&allocated);
++ ASSERT(allocated);
+
+ StunAddressAttribute* addr_attr =
+ StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+@@ -472,7 +492,10 @@ void RelayServer::HandleStunSend(
+ // Create a new connection to establish the relationship with this binding.
+ ASSERT(external_sockets_.size() == 1);
+ talk_base::AsyncPacketSocket* socket = external_sockets_[0];
+- talk_base::SocketAddressPair ap(ext_addr, socket->GetLocalAddress());
++ bool allocated;
++ talk_base::SocketAddressPair ap(
++ ext_addr, socket->GetLocalAddress(&allocated));
++ ASSERT(allocated);
+ ext_conn = new RelayServerConnection(int_conn->binding(), ap, socket);
+ ext_conn->binding()->AddExternalConnection(ext_conn);
+ AddConnection(ext_conn);
+@@ -559,7 +582,7 @@ void RelayServer::AcceptConnection(talk_
+ accepted_socket = new talk_base::AsyncSSLServerSocket(accepted_socket);
+ }
+ talk_base::AsyncTCPSocket* tcp_socket =
+- new talk_base::AsyncTCPSocket(accepted_socket);
++ new talk_base::AsyncTCPSocket(accepted_socket, false);
+
+ // Finally add the socket so it can start communicating with the client.
+ AddInternalSocket(tcp_socket);
+diff -upN libjingle-0.5.2/talk/p2p/base/relayserver.h.chromium12
libjingle-0.5.2/talk/p2p/base/relayserver.h
+--- libjingle-0.5.2/talk/p2p/base/relayserver.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/relayserver.h 2011-03-30 21:51:32.707287001 -0400
+@@ -25,8 +25,12 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+-#ifndef __RELAYSERVER_H__
+-#define __RELAYSERVER_H__
++#ifndef TALK_P2P_BASE_RELAYSERVER_H_
++#define TALK_P2P_BASE_RELAYSERVER_H_
++
++#include <string>
++#include <vector>
++#include <map>
+
+ #include "talk/base/asyncudpsocket.h"
+ #include "talk/base/socketaddresspair.h"
+@@ -35,10 +39,6 @@
+ #include "talk/p2p/base/port.h"
+ #include "talk/p2p/base/stun.h"
+
+-#include <string>
+-#include <vector>
+-#include <map>
+-
+ namespace cricket {
+
+ class RelayServerBinding;
+@@ -48,9 +48,9 @@ class RelayServerConnection;
+ // All connections created with the same username/password are bound together.
+ class RelayServer : public talk_base::MessageHandler,
+ public sigslot::has_slots<> {
+-public:
++ public:
+ // Creates a server, which will use this thread to post messages to itself.
+- RelayServer(talk_base::Thread* thread);
++ explicit RelayServer(talk_base::Thread* thread);
+ ~RelayServer();
+
+ talk_base::Thread* thread() { return thread_; }
+@@ -79,16 +79,18 @@ public:
+ // Removes this server socket from the list.
+ void RemoveInternalServerSocket(talk_base::AsyncSocket* socket);
+
+- int GetConnectionCount();
++ // Methods for testing and debuging.
++ int GetConnectionCount() const;
++ talk_base::SocketAddressPair GetConnection(int connection) const;
++ bool HasConnection(const talk_base::SocketAddress& address) const;
+
+- bool HasConnection(const talk_base::SocketAddress& address);
+-
+-private:
++ private:
+ typedef std::vector<talk_base::AsyncPacketSocket*> SocketList;
+ typedef std::map<talk_base::AsyncSocket*,
+ cricket::ProtocolType> ServerSocketMap;
+- typedef std::map<std::string,RelayServerBinding*> BindingMap;
+- typedef std::map<talk_base::SocketAddressPair,RelayServerConnection*>
ConnectionMap;
++ typedef std::map<std::string, RelayServerBinding*> BindingMap;
++ typedef std::map<talk_base::SocketAddressPair,
++ RelayServerConnection*> ConnectionMap;
+
+ talk_base::Thread* thread_;
+ bool log_bindings_;
+@@ -99,18 +101,19 @@ private:
+ ConnectionMap connections_;
+
+ // Called when a packet is received by the server on one of its sockets.
+- void OnInternalPacket(
+- const char* bytes, size_t size, const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket);
+- void OnExternalPacket(
+- const char* bytes, size_t size, const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket);
++ void OnInternalPacket(talk_base::AsyncPacketSocket* socket,
++ const char* bytes, size_t size,
++ const talk_base::SocketAddress& remote_addr);
++ void OnExternalPacket(talk_base::AsyncPacketSocket* socket,
++ const char* bytes, size_t size,
++ const talk_base::SocketAddress& remote_addr);
+
+ void OnReadEvent(talk_base::AsyncSocket* socket);
+
+ // Processes the relevant STUN request types from the client.
+ bool HandleStun(const char* bytes, size_t size,
+- const talk_base::SocketAddress& remote_addr,
talk_base::AsyncPacketSocket* socket,
++ const talk_base::SocketAddress& remote_addr,
++ talk_base::AsyncPacketSocket* socket,
+ std::string* username, StunMessage* msg);
+ void HandleStunAllocate(const char* bytes, size_t size,
+ const talk_base::SocketAddressPair& ap,
+@@ -142,7 +145,7 @@ private:
+ // Maintains information about a connection to the server. Each connection is
+ // part of one and only one binding.
+ class RelayServerConnection {
+-public:
++ public:
+ RelayServerConnection(RelayServerBinding* binding,
+ const talk_base::SocketAddressPair& addrs,
+ talk_base::AsyncPacketSocket* socket);
+@@ -158,7 +161,8 @@ public:
+ // Sends a packet to the connected client. If an address is provided, then
+ // we make sure the internal client receives it, wrapping if necessary.
+ void Send(const char* data, size_t size);
+- void Send(const char* data, size_t size, const talk_base::SocketAddress&
ext_addr);
++ void Send(const char* data, size_t size,
++ const talk_base::SocketAddress& ext_addr);
+
+ // Sends a STUN message to the connected client with no wrapping.
+ void SendStun(const StunMessage& msg);
+@@ -172,12 +176,14 @@ public:
+
+ // Records the address that raw packets should be forwarded to (for internal
+ // packets only; for external, we already know where they go).
+- const talk_base::SocketAddress& default_destination() const { return
default_dest_; }
++ const talk_base::SocketAddress& default_destination() const {
++ return default_dest_;
++ }
+ void set_default_destination(const talk_base::SocketAddress& addr) {
+ default_dest_ = addr;
+ }
+
+-private:
++ private:
+ RelayServerBinding* binding_;
+ talk_base::SocketAddressPair addr_pair_;
+ talk_base::AsyncPacketSocket* socket_;
+@@ -188,7 +194,7 @@ private:
+ // Records a set of internal and external connections that we relay between,
+ // or in other words, that are "bound" together.
+ class RelayServerBinding : public talk_base::MessageHandler {
+-public:
++ public:
+ RelayServerBinding(
+ RelayServer* server, const std::string& username,
+ const std::string& password, uint32 lifetime);
+@@ -215,13 +221,15 @@ public:
+
+ // Determines the connection to use to send packets to or from the given
+ // external address.
+- RelayServerConnection* GetInternalConnection(const talk_base::SocketAddress&
ext_addr);
+- RelayServerConnection* GetExternalConnection(const talk_base::SocketAddress&
ext_addr);
++ RelayServerConnection* GetInternalConnection(
++ const talk_base::SocketAddress& ext_addr);
++ RelayServerConnection* GetExternalConnection(
++ const talk_base::SocketAddress& ext_addr);
+
+ // MessageHandler:
+ void OnMessage(talk_base::Message *pmsg);
+
+-private:
++ private:
+ RelayServer* server_;
+
+ std::string username_;
+@@ -236,6 +244,6 @@ private:
+ // TODO: bandwidth
+ };
+
+-} // namespace cricket
++} // namespace cricket
+
+-#endif // __RELAYSERVER_H__
++#endif // TALK_P2P_BASE_RELAYSERVER_H_
+diff -upN libjingle-0.5.2/talk/p2p/base/relayserver_main.cc.chromium12
libjingle-0.5.2/talk/p2p/base/relayserver_main.cc
+--- libjingle-0.5.2/talk/p2p/base/relayserver_main.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/relayserver_main.cc 2011-03-30 21:51:32.707287001
-0400
+@@ -53,18 +53,18 @@ int main(int argc, char **argv) {
+ talk_base::Thread *pthMain = talk_base::Thread::Current();
+
+ talk_base::scoped_ptr<talk_base::AsyncUDPSocket> int_socket(
+- talk_base::CreateAsyncUDPSocket(pthMain->socketserver()));
+- if (int_socket->Bind(int_addr) < 0) {
+- std::cerr << "Internal socket bind(" << int_addr.ToString()
<< "): "
+- << std::strerror(int_socket->GetError()) << std::endl;
++ talk_base::AsyncUDPSocket::Create(pthMain->socketserver(), int_addr));
++ if (!int_socket.get()) {
++ std::cerr << "Failed to create a UDP socket bound at"
++ << int_addr.ToString() << std::endl;
+ return 1;
+ }
+
+ talk_base::scoped_ptr<talk_base::AsyncUDPSocket> ext_socket(
+- talk_base::CreateAsyncUDPSocket(pthMain->socketserver()));
+- if (ext_socket->Bind(ext_addr) < 0) {
+- std::cerr << "External socket bind(" << ext_addr.ToString()
<< "): "
+- << std::strerror(ext_socket->GetError()) << std::endl;
++ talk_base::AsyncUDPSocket::Create(pthMain->socketserver(), ext_addr));
++ if (ext_socket.get()) {
++ std::cerr << "Failed to create a UDP socket bound at"
++ << ext_addr.ToString() << std::endl;
+ return 1;
+ }
+
+diff -upN libjingle-0.5.2/talk/p2p/base/session.cc.chromium12
libjingle-0.5.2/talk/p2p/base/session.cc
+--- libjingle-0.5.2/talk/p2p/base/session.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/session.cc 2011-03-30 21:51:32.707287001 -0400
+@@ -180,8 +180,6 @@ void BaseSession::SetError(Error error)
+ if (error != error_) {
+ error_ = error;
+ SignalError(this, error);
+- if (error_ != ERROR_NONE)
+- signaling_thread_->Post(this, MSG_ERROR);
+ }
+ }
+
+@@ -647,12 +645,10 @@ void Session::OnIncomingMessage(const Se
+ valid = OnTransportAcceptMessage(msg, &error);
+ break;
+ case ACTION_NOTIFY:
++ valid = OnNotifyMessage(msg, &error);
++ break;
+ case ACTION_UPDATE:
+- // TODO: Process these non-standard messages, but
+- // only once we figure out how in a jingle-specific way (or
+- // remove the need altogether). For now, just don't send an
+- // error back, because it disrupts call establishment.
+- valid = true;
++ valid = OnUpdateMessage(msg, &error);
+ break;
+ default:
+ valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
+@@ -697,13 +693,16 @@ void Session::OnFailedSend(const buzz::X
+ std::string error_type = "cancel";
+
+ const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
+- ASSERT(error != NULL);
+ if (error) {
+ ASSERT(error->HasAttr(buzz::QN_TYPE));
+ error_type = error->Attr(buzz::QN_TYPE);
+
+ LOG(LS_ERROR) << "Session error:\n" << error->Str()
<< "\n"
+ << "in response to:\n" <<
orig_stanza->Str();
++ } else {
++ // don't crash if <error> is missing
++ LOG(LS_ERROR) << "Session error without <error/> element,
ignoring";
++ return;
+ }
+
+ if (msg.type == ACTION_TRANSPORT_INFO) {
+@@ -832,6 +831,30 @@ bool Session::OnTransportAcceptMessage(c
+ return true;
+ }
+
++bool Session::OnNotifyMessage(const SessionMessage& msg,
++ MessageError* error) {
++ SessionNotify notify;
++ if (!ParseSessionNotify(msg.action_elem, ¬ify, error)) {
++ return false;
++ }
++
++ SignalMediaSources(notify.nickname_to_sources);
++
++ return true;
++}
++
++bool Session::OnUpdateMessage(const SessionMessage& msg,
++ MessageError* error) {
++ SessionUpdate update;
++ if (!ParseSessionUpdate(msg.action_elem, &update, error)) {
++ return false;
++ }
++
++ // TODO: Process this message appropriately.
++
++ return true;
++}
++
+ bool BareJidsEqual(const std::string& name1,
+ const std::string& name2) {
+ buzz::Jid jid1(name1);
+@@ -868,6 +891,12 @@ bool Session::CheckState(State state, Me
+ return true;
+ }
+
++void Session::SetError(Error error) {
++ BaseSession::SetError(error);
++ if (error_ != ERROR_NONE)
++ signaling_thread_->Post(this, MSG_ERROR);
++}
++
+ void Session::OnMessage(talk_base::Message *pmsg) {
+ // preserve this because BaseSession::OnMessage may modify it
+ BaseSession::State orig_state = state_;
+@@ -909,6 +938,16 @@ bool Session::WriteSessionAction(
+ elems, error);
+ }
+
++bool Session::SetVideoView(
++ const std::vector<VideoViewRequest>& view_requests) {
++ SessionView view;
++ SessionError error;
++
++ view.view_requests = view_requests;
++
++ return !SendViewMessage(view, &error);
++}
++
+ bool Session::SendAcceptMessage(const SessionDescription* sdesc,
+ SessionError* error) {
+ XmlElements elems;
+@@ -958,6 +997,12 @@ bool Session::WriteSessionAction(Signali
+ elems, error);
+ }
+
++bool Session::SendViewMessage(const SessionView& view, SessionError* error) {
++ XmlElements elems;
++ WriteSessionView(view, &elems);
++ return SendMessage(ACTION_VIEW, elems, error);
++}
++
+ bool Session::ResendAllTransportInfoMessages(SessionError* error) {
+ for (TransportMap::iterator iter = transports_.begin();
+ iter != transports_.end(); ++iter) {
+diff -upN libjingle-0.5.2/talk/p2p/base/session.h.chromium12
libjingle-0.5.2/talk/p2p/base/session.h
+--- libjingle-0.5.2/talk/p2p/base/session.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/session.h 2011-03-30 21:51:32.708287001 -0400
+@@ -42,8 +42,6 @@
+ #include "talk/xmllite/xmlelement.h"
+ #include "talk/xmpp/constants.h"
+
+-class JingleMessageHandler;
+-
+ namespace cricket {
+
+ class P2PTransportChannel;
+@@ -163,6 +161,7 @@ class BaseSession : public sigslot::has_
+ ERROR_TIME = 1, // no response to signaling
+ ERROR_RESPONSE = 2, // error during signaling
+ ERROR_NETWORK = 3, // network error, could not allocate network resources
++ ERROR_CONTENT = 4, // channel errors in SetLocalContent/SetRemoteContent
+ };
+
+ explicit BaseSession(talk_base::Thread *signaling_thread);
+@@ -172,7 +171,7 @@ class BaseSession : public sigslot::has_
+ void SetState(State state);
+
+ // Updates the error state, signaling if necessary.
+- void SetError(Error error);
++ virtual void SetError(Error error);
+
+ // Handles messages posted to us.
+ virtual void OnMessage(talk_base::Message *pmsg);
+@@ -364,9 +363,20 @@ class Session : public BaseSession {
+ virtual void DestroyChannel(const std::string& content_name,
+ const std::string& channel_name);
+
++ // Updates the error state, signaling if necessary.
++ virtual void SetError(Error error);
++
+ // Handles messages posted to us.
+ virtual void OnMessage(talk_base::Message *pmsg);
+
++ // Fired when notification of media sources is received from the server.
++ // Passes a map whose keys are strings containing nick names for users
++ // in the session and whose values contain the SSRCs for each user.
++ sigslot::signal1<const StringToMediaSourcesMap&> SignalMediaSources;
++
++ // Sets the video streams to receive from the server.
++ bool SetVideoView(const VideoViewRequestVector& view_requests);
++
+ private:
+ // Creates or destroys a session. (These are called only SessionManager.)
+ Session(SessionManager *session_manager,
+@@ -439,6 +449,7 @@ class Session : public BaseSession {
+ bool SendTerminateMessage(const std::string& reason, SessionError* error);
+ bool SendTransportInfoMessage(const TransportInfo& tinfo,
+ SessionError* error);
++ bool SendViewMessage(const SessionView& view, SessionError* error);
+ bool ResendAllTransportInfoMessages(SessionError* error);
+
+ // Both versions of SendMessage send a message of the given type to
+@@ -510,6 +521,8 @@ class Session : public BaseSession {
+ bool OnTerminateMessage(const SessionMessage& msg, MessageError* error);
+ bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error);
+ bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error);
++ bool OnNotifyMessage(const SessionMessage& msg, MessageError* error);
++ bool OnUpdateMessage(const SessionMessage& msg, MessageError* error);
+ bool OnRedirectError(const SessionRedirect& redirect, SessionError* error);
+
+ // Verifies that we are in the appropriate state to receive this message.
+diff -upN libjingle-0.5.2/talk/p2p/base/sessionmessages.cc.chromium12
libjingle-0.5.2/talk/p2p/base/sessionmessages.cc
+--- libjingle-0.5.2/talk/p2p/base/sessionmessages.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/sessionmessages.cc 2011-03-30 21:51:32.708287001 -0400
+@@ -25,11 +25,13 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
++#include <stdio.h>
+ #include <string>
+ #include "talk/p2p/base/sessionmessages.h"
+
+ #include "talk/base/logging.h"
+ #include "talk/base/scoped_ptr.h"
++#include "talk/base/stringutils.h"
+ #include "talk/xmllite/xmlconstants.h"
+ #include "talk/xmpp/constants.h"
+ #include "talk/p2p/base/constants.h"
+@@ -38,6 +40,7 @@
+ #include "talk/p2p/base/sessionclient.h"
+ #include "talk/p2p/base/sessiondescription.h"
+ #include "talk/p2p/base/transport.h"
++#include "talk/xmllite/xmlconstants.h"
+
+ namespace cricket {
+
+@@ -112,6 +115,8 @@ std::string ToGingleString(ActionType ty
+ return GINGLE_ACTION_REJECT;
+ case ACTION_SESSION_TERMINATE:
+ return GINGLE_ACTION_TERMINATE;
++ case ACTION_VIEW:
++ return GINGLE_ACTION_VIEW;
+ case ACTION_TRANSPORT_INFO:
+ return GINGLE_ACTION_CANDIDATES;
+ default:
+@@ -126,7 +131,12 @@ bool IsJingleMessage(const buzz::XmlElem
+ return false;
+
+ return (jingle->HasAttr(buzz::QN_ACTION) &&
+- jingle->HasAttr(buzz::QN_ID));
++ (jingle->HasAttr(QN_SID)
++ // TODO: This works around a bug in old jingle
++ // clients that set QN_ID instead of QN_SID. Once we know
++ // there are no clients which have this bug, we can remove
++ // this code.
++ || jingle->HasAttr(QN_ID)));
+ }
+
+ bool IsGingleMessage(const buzz::XmlElement* stanza) {
+@@ -168,7 +178,13 @@ bool ParseJingleSessionMessage(const buz
+ msg->protocol = PROTOCOL_JINGLE;
+ std::string type_string = jingle->Attr(buzz::QN_ACTION);
+ msg->type = ToActionType(type_string);
+- msg->sid = jingle->Attr(buzz::QN_ID);
++ msg->sid = jingle->Attr(QN_SID);
++ // TODO: This works around a bug in old jingle clients
++ // that set QN_ID instead of QN_SID. Once we know there are no
++ // clients which have this bug, we can remove this code.
++ if (msg->sid.empty()) {
++ msg->sid = jingle->Attr(buzz::QN_ID);
++ }
+ msg->initiator = GetXmlAttr(jingle, QN_INITIATOR, buzz::STR_EMPTY);
+ msg->action_elem = jingle;
+
+@@ -221,7 +237,11 @@ buzz::XmlElement* WriteJingleAction(cons
+ const XmlElements& action_elems) {
+ buzz::XmlElement* jingle = new buzz::XmlElement(QN_JINGLE, true);
+ jingle->AddAttr(buzz::QN_ACTION, ToJingleString(msg.type));
+- jingle->AddAttr(buzz::QN_ID, msg.sid);
++ jingle->AddAttr(QN_SID, msg.sid);
++ // TODO: This works around a bug in old jingle clinets
++ // that expected QN_ID instead of QN_SID. Once we know there are no
++ // clients which have this bug, we can remove this code.
++ jingle->AddAttr(QN_ID, msg.sid);
+ // TODO: Right now, the XMPP server rejects a jingle-only
+ // (non hybrid) message with "feature-not-implemented" if there is
+ // no initiator. Fix the server, and then only set the initiator on
+@@ -824,6 +844,40 @@ bool WriteTransportInfos(SignalingProtoc
+ }
+ }
+
++bool ParseSessionNotify(const buzz::XmlElement* action_elem,
++ SessionNotify* notify, ParseError* error) {
++ const buzz::XmlElement* notify_elem;
++ for (notify_elem = action_elem->FirstNamed(QN_GINGLE_NOTIFY);
++ notify_elem != NULL;
++ notify_elem = notify_elem->NextNamed(QN_GINGLE_NOTIFY)) {
++ // Note that a subsequent notify element for the same user will override a
++ // previous. We don't merge them.
++ std::string nick(notify_elem->Attr(QN_GINGLE_NOTIFY_NICK));
++ if (nick != buzz::STR_EMPTY) {
++ MediaSources sources;
++ const buzz::XmlElement* source_elem;
++ for (source_elem = notify_elem->FirstNamed(QN_GINGLE_NOTIFY_SOURCE);
++ source_elem != NULL;
++ source_elem = source_elem->NextNamed(QN_GINGLE_NOTIFY_SOURCE)) {
++ std::string ssrc = source_elem->Attr(QN_GINGLE_NOTIFY_SOURCE_SSRC);
++ if (ssrc != buzz::STR_EMPTY) {
++ std::string mtype = source_elem->Attr(QN_GINGLE_NOTIFY_SOURCE_MTYPE);
++ if (mtype == GINGLE_NOTIFY_SOURCE_MTYPE_AUDIO) {
++ sources.audio_ssrc = strtoul(ssrc.c_str(), NULL, 10);
++ } else if (mtype == GINGLE_NOTIFY_SOURCE_MTYPE_VIDEO) {
++ sources.video_ssrc = strtoul(ssrc.c_str(), NULL, 10);
++ }
++ }
++ }
++
++ notify->nickname_to_sources.insert(
++ std::pair<std::string, MediaSources>(nick, sources));
++ }
++ }
++
++ return true;
++}
++
+ bool GetUriTarget(const std::string& prefix, const std::string& str,
+ std::string* after) {
+ size_t pos = str.find(prefix);
+@@ -834,6 +888,65 @@ bool GetUriTarget(const std::string& pre
+ return true;
+ }
+
++bool ParseSessionUpdate(const buzz::XmlElement* action_elem,
++ SessionUpdate* update, ParseError* error) {
++ // TODO: Parse the update message.
++ return true;
++}
++
++void WriteSessionView(const SessionView& view, XmlElements* elems) {
++ std::vector<VideoViewRequest>::const_iterator it;
++ for (it = view.view_requests.begin(); it != view.view_requests.end(); it++) {
++ talk_base::scoped_ptr<buzz::XmlElement> view_elem(
++ new buzz::XmlElement(QN_GINGLE_VIEW));
++ if (view_elem.get() == NULL) {
++ return;
++ }
++
++ view_elem->SetAttr(QN_GINGLE_VIEW_TYPE, GINGLE_VIEW_TYPE_STATIC);
++ view_elem->SetAttr(QN_GINGLE_VIEW_NICK, it->nick_name);
++ view_elem->SetAttr(QN_GINGLE_VIEW_MEDIA_TYPE,
++ GINGLE_VIEW_MEDIA_TYPE_VIDEO);
++
++ // A 32-bit uint, expressed as decimal, has a max of 10 digits, plus one
++ // for the null.
++ char str[11];
++ int result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u",
it->ssrc);
++ if (result < 0 || result >= ARRAY_SIZE(str)) {
++ continue;
++ }
++ view_elem->SetAttr(QN_GINGLE_VIEW_SSRC, str);
++
++ // Include video-specific parameters in a child <params> element.
++ talk_base::scoped_ptr<buzz::XmlElement> params_elem(
++ new buzz::XmlElement(QN_GINGLE_VIEW_PARAMS));
++ if (params_elem.get() == NULL) {
++ return;
++ }
++
++ result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->width);
++ if (result < 0 || result >= ARRAY_SIZE(str)) {
++ continue;
++ }
++ params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_WIDTH, str);
++
++ result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->height);
++ if (result < 0 || result >= ARRAY_SIZE(str)) {
++ continue;
++ }
++ params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_HEIGHT, str);
++
++ result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u",
it->framerate);
++ if (result < 0 || result >= ARRAY_SIZE(str)) {
++ continue;
++ }
++ params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_FRAMERATE, str);
++
++ view_elem->AddElement(params_elem.release());
++ elems->push_back(view_elem.release());
++ }
++}
++
+ bool FindSessionRedirect(const buzz::XmlElement* stanza,
+ SessionRedirect* redirect) {
+ const buzz::XmlElement* error_elem = GetXmlChild(stanza, LN_ERROR);
+diff -upN libjingle-0.5.2/talk/p2p/base/sessionmessages.h.chromium12
libjingle-0.5.2/talk/p2p/base/sessionmessages.h
+--- libjingle-0.5.2/talk/p2p/base/sessionmessages.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/sessionmessages.h 2011-03-30 21:51:32.709287001 -0400
+@@ -35,6 +35,7 @@
+ #include "talk/xmllite/xmlelement.h"
+ #include "talk/p2p/base/constants.h"
+ #include "talk/p2p/base/sessiondescription.h" // Needed to delete contents.
++#include "talk/base/basictypes.h"
+
+ namespace cricket {
+
+@@ -66,6 +67,7 @@ enum ActionType {
+ // being needed at all.
+ ACTION_NOTIFY,
+ ACTION_UPDATE,
++ ACTION_VIEW,
+ };
+
+ // Abstraction of a <jingle> element within an <iq> stanza, per XMPP
+@@ -159,6 +161,45 @@ struct SessionRedirect {
+ std::string target;
+ };
+
++// Holds the ssrcs for a user's media streams.
++struct MediaSources {
++ uint32 audio_ssrc;
++ uint32 video_ssrc;
++ MediaSources() : audio_ssrc(0), video_ssrc(0) {}
++};
++
++typedef std::map<std::string, MediaSources> StringToMediaSourcesMap;
++
++struct SessionNotify {
++ // A mapping of room users (identified by their nicknames) to their ssrcs.
++ StringToMediaSourcesMap nickname_to_sources;
++};
++
++// TODO: Populate the update message.
++struct SessionUpdate {
++};
++
++// Represents an individual <view> element in the <session
type="view">
++// message.
++struct VideoViewRequest {
++ std::string nick_name;
++ uint32 ssrc;
++ uint32 width;
++ uint32 height;
++ uint32 framerate;
++
++ VideoViewRequest(const std::string& nick_name, uint32 ssrc, uint32 width,
++ uint32 height, uint32 framerate) :
++ nick_name(nick_name), ssrc(ssrc), width(width), height(height),
++ framerate(framerate) {}
++};
++
++typedef std::vector<VideoViewRequest> VideoViewRequestVector;
++
++struct SessionView {
++ VideoViewRequestVector view_requests;
++};
++
+ bool IsSessionMessage(const buzz::XmlElement* stanza);
+ bool ParseSessionMessage(const buzz::XmlElement* stanza,
+ SessionMessage* msg,
+@@ -218,6 +259,11 @@ bool WriteTransportInfos(SignalingProtoc
+ const TransportParserMap& trans_parsers,
+ XmlElements* elems,
+ WriteError* error);
++bool ParseSessionNotify(const buzz::XmlElement* action_elem,
++ SessionNotify* notify, ParseError* error);
++bool ParseSessionUpdate(const buzz::XmlElement* action_elem,
++ SessionUpdate* update, ParseError* error);
++void WriteSessionView(const SessionView& view, XmlElements* elems);
+ // Handles both Gingle and Jingle syntax.
+ bool FindSessionRedirect(const buzz::XmlElement* stanza,
+ SessionRedirect* redirect);
+diff -upN libjingle-0.5.2/talk/p2p/base/stunport.cc.chromium12
libjingle-0.5.2/talk/p2p/base/stunport.cc
+--- libjingle-0.5.2/talk/p2p/base/stunport.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/stunport.cc 2011-03-30 21:51:32.709287001 -0400
+@@ -102,8 +102,8 @@ class StunPortBindingRequest : public St
+
+ virtual void OnTimeout() {
+ LOG(LS_ERROR) << "Binding request timed out from "
+- << port_->GetLocalAddress().ToString()
+- << " (" << port_->network()->name() <<
")";
++ << port_->socket_->GetLocalAddress(NULL).ToString()
++ << " (" << port_->network()->name()
<< ")";
+
+ port_->SignalAddressError(port_);
+
+@@ -124,26 +124,27 @@ class StunPortBindingRequest : public St
+
+ const std::string STUN_PORT_TYPE("stun");
+
+-StunPort::StunPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
++StunPort::StunPort(talk_base::Thread* thread,
++ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
++ uint32 ip, int min_port, int max_port,
+ const talk_base::SocketAddress& server_addr)
+- : Port(thread, STUN_PORT_TYPE, factory, network),
+- server_addr_(server_addr), requests_(thread), socket_(NULL), error_(0),
++ : Port(thread, STUN_PORT_TYPE, factory, network, ip, min_port, max_port),
++ server_addr_(server_addr),
++ requests_(thread),
++ socket_(NULL),
++ error_(0),
+ resolver_(NULL) {
+ requests_.SignalSendPacket.connect(this, &StunPort::OnSendPacket);
+ }
+
+-bool StunPort::Init(const talk_base::SocketAddress& local_addr) {
+- socket_ = CreatePacketSocket(PROTO_UDP);
++bool StunPort::Init() {
++ socket_ = factory_->CreateUdpSocket(
++ talk_base::SocketAddress(ip_, 0), min_port_, max_port_);
+ if (!socket_) {
+ LOG_J(LS_WARNING, this) << "UDP socket creation failed";
+ return false;
+ }
+- if (socket_->Bind(local_addr) < 0) {
+- LOG_J(LS_WARNING, this) << "UDP bind failed with error "
+- << socket_->GetError();
+- return false;
+- }
+ socket_->SignalReadPacket.connect(this, &StunPort::OnReadPacket);
+ return true;
+ }
+@@ -200,14 +201,20 @@ int StunPort::GetError() {
+ return error_;
+ }
+
+-void StunPort::OnReadPacket(
+- const char* data, size_t size, const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket) {
++void StunPort::OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr) {
+ ASSERT(socket == socket_);
+
+- // Look for a response to a binding request.
+- if (requests_.CheckResponse(data, size))
++ // Look for a response from the STUN server.
++ // Even if the response doesn't match one of our outstanding requests, we
++ // will eat it because it might be a response to a retransmitted packet, and
++ // we already cleared the request when we got the first response.
++ ASSERT(!server_addr_.IsUnresolved());
++ if (remote_addr == server_addr_ || remote_addr == server_addr2_) {
++ requests_.CheckResponse(data, size);
+ return;
++ }
+
+ if (Connection* conn = GetConnection(remote_addr)) {
+ conn->OnReadPacket(data, size);
+diff -upN libjingle-0.5.2/talk/p2p/base/stunport.h.chromium12
libjingle-0.5.2/talk/p2p/base/stunport.h
+--- libjingle-0.5.2/talk/p2p/base/stunport.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/stunport.h 2011-03-30 21:51:32.709287001 -0400
+@@ -29,7 +29,8 @@
+ #define TALK_P2P_BASE_STUNPORT_H_
+
+ #include <string>
+-#include "talk/base/asyncudpsocket.h"
++
++#include "talk/base/asyncpacketsocket.h"
+ #include "talk/p2p/base/udpport.h"
+ #include "talk/p2p/base/stunrequest.h"
+
+@@ -46,27 +47,20 @@ extern const std::string STUN_PORT_TYPE;
+ class StunPort : public Port {
+ public:
+ static StunPort* Create(talk_base::Thread* thread,
+- talk_base::SocketFactory* factory,
++ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
+- const talk_base::SocketAddress& local_addr,
++ uint32 ip, int min_port, int max_port,
+ const talk_base::SocketAddress& server_addr) {
+- StunPort* port = new StunPort(thread, factory, network, server_addr);
+- if (!port->Init(local_addr)) {
++ StunPort* port = new StunPort(thread, factory, network,
++ ip, min_port, max_port, server_addr);
++ if (!port->Init()) {
+ delete port;
+ port = NULL;
+ }
+ return port;
+ }
+- StunPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+- talk_base::Network* network,
+- const talk_base::SocketAddress& server_addr);
+- bool Init(const talk_base::SocketAddress& local_addr);
+ virtual ~StunPort();
+
+- talk_base::SocketAddress GetLocalAddress() const {
+- return socket_->GetLocalAddress();
+- }
+-
+ const talk_base::SocketAddress& server_addr() const { return server_addr_; }
+ void set_server_addr(const talk_base::SocketAddress& addr) {
+ server_addr_ = addr;
+@@ -89,13 +83,17 @@ class StunPort : public Port {
+ virtual int GetError();
+
+ protected:
++ StunPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++ talk_base::Network* network, uint32 ip, int min_port, int max_port,
++ const talk_base::SocketAddress& server_addr);
++ bool Init();
++
+ virtual int SendTo(const void* data, size_t size,
+ const talk_base::SocketAddress& addr, bool payload);
+
+- void OnReadPacket(
+- const char* data, size_t size,
+- const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket);
++ void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr);
+
+ private:
+ // DNS resolution of the STUN server.
+diff -upN libjingle-0.5.2/talk/p2p/base/stunserver.cc.chromium12
libjingle-0.5.2/talk/p2p/base/stunserver.cc
+--- libjingle-0.5.2/talk/p2p/base/stunserver.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/stunserver.cc 2011-03-30 21:51:32.709287001 -0400
+@@ -44,8 +44,8 @@ StunServer::~StunServer() {
+ }
+
+ void StunServer::OnPacket(
+- const char* buf, size_t size, const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket) {
++ talk_base::AsyncPacketSocket* socket, const char* buf, size_t size,
++ const talk_base::SocketAddress& remote_addr) {
+
+ // TODO: If appropriate, look for the magic cookie before parsing.
+
+@@ -97,7 +97,12 @@ void StunServer::OnBindingRequest(
+ response.AddAttribute(mapped_addr);
+
+ // Tell the user the address that we are sending the response from.
+- talk_base::SocketAddress local_addr = socket_->GetLocalAddress();
++ // This method should not be called if socket address is not
++ // allocated yet.
++ bool allocated;
++ talk_base::SocketAddress local_addr = socket_->GetLocalAddress(&allocated);
++ ASSERT(allocated);
++
+ StunAddressAttribute* source_addr =
+ StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS);
+ source_addr->SetFamily(1);
+diff -upN libjingle-0.5.2/talk/p2p/base/stunserver.h.chromium12
libjingle-0.5.2/talk/p2p/base/stunserver.h
+--- libjingle-0.5.2/talk/p2p/base/stunserver.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/stunserver.h 2011-03-30 21:51:32.710287001 -0400
+@@ -46,8 +46,8 @@ class StunServer : public sigslot::has_s
+ protected:
+ // Slot for AsyncSocket.PacketRead:
+ void OnPacket(
+- const char* buf, size_t size, const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket);
++ talk_base::AsyncPacketSocket* socket, const char* buf, size_t size,
++ const talk_base::SocketAddress& remote_addr);
+
+ // Handlers for the different types of STUN/TURN requests:
+ void OnBindingRequest(StunMessage* msg,
+diff -upN libjingle-0.5.2/talk/p2p/base/stunserver_main.cc.chromium12
libjingle-0.5.2/talk/p2p/base/stunserver_main.cc
+--- libjingle-0.5.2/talk/p2p/base/stunserver_main.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/stunserver_main.cc 2011-03-30 21:51:32.710287001 -0400
+@@ -52,9 +52,9 @@ int main(int argc, char* argv[]) {
+ talk_base::Thread *pthMain = talk_base::Thread::Current();
+
+ talk_base::AsyncUDPSocket* server_socket =
+- talk_base::CreateAsyncUDPSocket(pthMain->socketserver());
+- if (server_socket->Bind(server_addr) < 0) {
+- std::cerr << "bind: " << std::strerror(errno) <<
std::endl;
++ talk_base::AsyncUDPSocket::Create(pthMain->socketserver(), server_addr);
++ if (!server_socket) {
++ std::cerr << "Failed to create a UDP socket" << std::endl;
+ return 1;
+ }
+
+diff -upN libjingle-0.5.2/talk/p2p/base/tcpport.cc.chromium12
libjingle-0.5.2/talk/p2p/base/tcpport.cc
+--- libjingle-0.5.2/talk/p2p/base/tcpport.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/tcpport.cc 2011-03-30 21:51:32.710287001 -0400
+@@ -25,10 +25,6 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+-#if defined(_MSC_VER) && _MSC_VER < 1300
+-#pragma warning(disable:4786)
+-#endif
+-
+ #include "talk/p2p/base/tcpport.h"
+
+ #include "talk/base/common.h"
+@@ -37,30 +33,28 @@
+
+ namespace cricket {
+
+-TCPPort::TCPPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+- talk_base::Network* network,
+- const talk_base::SocketAddress& address,
+- bool allow_listen)
+- : Port(thread, LOCAL_PORT_TYPE, factory, network), address_(address),
+- incoming_only_(address_.port() != 0), allow_listen_(allow_listen),
+- socket_(NULL), error_(0) {
++TCPPort::TCPPort(talk_base::Thread* thread,
++ talk_base::PacketSocketFactory* factory,
++ talk_base::Network* network, uint32 ip,
++ int min_port, int max_port, bool allow_listen)
++ : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port),
++ incoming_only_(false),
++ allow_listen_(allow_listen),
++ socket_(NULL),
++ error_(0) {
+ }
+
+ bool TCPPort::Init() {
+- // We don't use CreatePacketSocket here since we're creating a listen socket.
+- // However we will treat failure to create or bind a TCP socket as fatal.
+- // This should never happen.
+- socket_ = factory_->CreateAsyncSocket(SOCK_STREAM);
++ // Treat failure to create or bind a TCP socket as fatal. This
++ // should never happen.
++ socket_ = factory_->CreateServerTcpSocket(
++ talk_base::SocketAddress(ip_, 0), min_port_, max_port_, allow_listen_,
++ false /* ssl */);
+ if (!socket_) {
+ LOG_J(LS_ERROR, this) << "TCP socket creation failed.";
+ return false;
+ }
+- if (socket_->Bind(address_) < 0) {
+- LOG_J(LS_ERROR, this) << "TCP bind failed with error "
+- << socket_->GetError();
+- return false;
+- }
+- socket_->SignalReadEvent.connect(this, &TCPPort::OnAcceptEvent);
++ socket_->SignalNewConnection.connect(this, &TCPPort::OnNewConnection);
+ return true;
+ }
+
+@@ -87,8 +81,8 @@ Connection* TCPPort::CreateConnection(co
+ return NULL;
+
+ TCPConnection* conn = NULL;
+- if (talk_base::AsyncTCPSocket * socket
+- = GetIncoming(address.address(), true)) {
++ if (talk_base::AsyncPacketSocket* socket =
++ GetIncoming(address.address(), true)) {
+ socket->SignalReadPacket.disconnect(this);
+ conn = new TCPConnection(this, address, socket);
+ } else {
+@@ -101,18 +95,21 @@ Connection* TCPPort::CreateConnection(co
+ void TCPPort::PrepareAddress() {
+ if (!allow_listen_) {
+ LOG_J(LS_INFO, this) << "Not listening due to firewall
restrictions.";
+- } else if (socket_->Listen(5) < 0) {
+- LOG_J(LS_WARNING, this) << "TCP listen failed with error "
+- << socket_->GetError();
+ }
+ // Note: We still add the address, since otherwise the remote side won't
+ // recognize our incoming TCP connections.
+- AddAddress(socket_->GetLocalAddress(), "tcp", true);
++ bool allocated;
++ talk_base::SocketAddress address = socket_->GetLocalAddress(&allocated);
++ if (allocated) {
++ AddAddress(address, "tcp", true);
++ } else {
++ socket_->SignalAddressReady.connect(this, &TCPPort::OnAddresReady);
++ }
+ }
+
+ int TCPPort::SendTo(const void* data, size_t size,
+ const talk_base::SocketAddress& addr, bool payload) {
+- talk_base::AsyncTCPSocket * socket = NULL;
++ talk_base::AsyncPacketSocket * socket = NULL;
+ if (TCPConnection * conn = static_cast<TCPConnection*>(GetConnection(addr))) {
+ socket = conn->socket();
+ } else {
+@@ -141,31 +138,23 @@ int TCPPort::GetError() {
+ return error_;
+ }
+
+-void TCPPort::OnAcceptEvent(talk_base::AsyncSocket* socket) {
++void TCPPort::OnNewConnection(talk_base::AsyncPacketSocket* socket,
++ talk_base::AsyncPacketSocket* new_socket) {
+ ASSERT(socket == socket_);
+
+ Incoming incoming;
+- talk_base::AsyncSocket* newsocket = socket->Accept(&incoming.addr);
+- if (!newsocket) {
+- // TODO: Do something better like forwarding the error to the user.
+- LOG_J(LS_ERROR, this) << "TCP accept failed with error "
+- << socket_->GetError();
+- return;
+- }
+- incoming.socket = new talk_base::AsyncTCPSocket(newsocket);
++ incoming.addr = new_socket->GetRemoteAddress();
++ incoming.socket = new_socket;
+ incoming.socket->SignalReadPacket.connect(this, &TCPPort::OnReadPacket);
+
+ LOG_J(LS_VERBOSE, this) << "Accepted connection from "
+ << incoming.addr.ToString();
+ incoming_.push_back(incoming);
+-
+- // Prime a read event in case data is waiting
+- newsocket->SignalReadEvent(newsocket);
+ }
+
+-talk_base::AsyncTCPSocket* TCPPort::GetIncoming(
++talk_base::AsyncPacketSocket* TCPPort::GetIncoming(
+ const talk_base::SocketAddress& addr, bool remove) {
+- talk_base::AsyncTCPSocket* socket = NULL;
++ talk_base::AsyncPacketSocket* socket = NULL;
+ for (std::list<Incoming>::iterator it = incoming_.begin();
+ it != incoming_.end(); ++it) {
+ if (it->addr == addr) {
+@@ -178,34 +167,46 @@ talk_base::AsyncTCPSocket* TCPPort::GetI
+ return socket;
+ }
+
+-void TCPPort::OnReadPacket(const char* data, size_t size,
+- const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket) {
++void TCPPort::OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr) {
+ Port::OnReadPacket(data, size, remote_addr);
+ }
+
++void TCPPort::OnAddresReady(talk_base::AsyncPacketSocket* socket,
++ const talk_base::SocketAddress& address) {
++ AddAddress(address, "tcp", true);
++}
++
+ TCPConnection::TCPConnection(TCPPort* port, const Candidate& candidate,
+- talk_base::AsyncTCPSocket* socket)
++ talk_base::AsyncPacketSocket* socket)
+ : Connection(port, 0, candidate), socket_(socket), error_(0) {
+ bool outgoing = (socket_ == NULL);
+ if (outgoing) {
+- // TODO: Handle failures here (unlikely since TCP)
+- socket_ =
static_cast<talk_base::AsyncTCPSocket*>(port->CreatePacketSocket(
+- (candidate.protocol() == "ssltcp") ? PROTO_SSLTCP : PROTO_TCP));
++ // TODO: Handle failures here (unlikely since TCP).
++
++ socket_ = port->socket_factory()->CreateClientTcpSocket(
++ talk_base::SocketAddress(port_->network()->ip(), 0),
++ candidate.address(), port->proxy(), port->user_agent(),
++ candidate.protocol() == "ssltcp");
++ if (socket_) {
++ LOG_J(LS_VERBOSE, this) << "Connecting from "
++ << socket_->GetLocalAddress(NULL).ToString()
++ << " to " <<
candidate.address().ToString();
++ set_connected(false);
++ socket_->SignalConnect.connect(this, &TCPConnection::OnConnect);
++ } else {
++ LOG_J(LS_WARNING, this) << "Failed to create connection to "
++ << candidate.address().ToString();
++ }
+ } else {
+- // Incoming connections should match the network address
+- ASSERT(socket_->GetLocalAddress().EqualIPs(port->address_));
++ // Incoming connections should match the network address.
++ ASSERT(socket_->GetLocalAddress(NULL).ip() == port->ip_);
+ }
+- socket_->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket);
+- socket_->SignalClose.connect(this, &TCPConnection::OnClose);
+- if (outgoing) {
+- set_connected(false);
+- talk_base::SocketAddress local_address(port->address_.ip(), 0);
+- socket_->SignalConnect.connect(this, &TCPConnection::OnConnect);
+- socket_->Bind(local_address);
+- socket_->Connect(candidate.address());
+- LOG_J(LS_VERBOSE, this) << "Connecting from " <<
local_address.ToString()
+- << " to " <<
candidate.address().ToString();
++
++ if (socket_) {
++ socket_->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket);
++ socket_->SignalClose.connect(this, &TCPConnection::OnClose);
+ }
+ }
+
+@@ -214,6 +215,11 @@ TCPConnection::~TCPConnection() {
+ }
+
+ int TCPConnection::Send(const void* data, size_t size) {
++ if (!socket_) {
++ error_ = ENOTCONN;
++ return SOCKET_ERROR;
++ }
++
+ if (write_state() != STATE_WRITABLE) {
+ // TODO: Should STATE_WRITE_TIMEOUT return a non-blocking error?
+ error_ = EWOULDBLOCK;
+@@ -232,23 +238,23 @@ int TCPConnection::GetError() {
+ return error_;
+ }
+
+-void TCPConnection::OnConnect(talk_base::AsyncTCPSocket* socket) {
++void TCPConnection::OnConnect(talk_base::AsyncPacketSocket* socket) {
+ ASSERT(socket == socket_);
+ LOG_J(LS_VERBOSE, this) << "Connection established to "
+ << socket->GetRemoteAddress().ToString();
+ set_connected(true);
+ }
+
+-void TCPConnection::OnClose(talk_base::AsyncTCPSocket* socket, int error) {
++void TCPConnection::OnClose(talk_base::AsyncPacketSocket* socket, int error) {
+ ASSERT(socket == socket_);
+ LOG_J(LS_VERBOSE, this) << "Connection closed with error " <<
error;
+ set_connected(false);
+ set_write_state(STATE_WRITE_TIMEOUT);
+ }
+
+-void TCPConnection::OnReadPacket(const char* data, size_t size,
+- const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket) {
++void TCPConnection::OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr) {
+ ASSERT(socket == socket_);
+ Connection::OnReadPacket(data, size);
+ }
+diff -upN libjingle-0.5.2/talk/p2p/base/tcpport.h.chromium12
libjingle-0.5.2/talk/p2p/base/tcpport.h
+--- libjingle-0.5.2/talk/p2p/base/tcpport.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/tcpport.h 2011-03-30 21:51:32.710287001 -0400
+@@ -30,7 +30,7 @@
+
+ #include <string>
+ #include <list>
+-#include "talk/base/asynctcpsocket.h"
++#include "talk/base/asyncpacketsocket.h"
+ #include "talk/p2p/base/port.h"
+
+ namespace cricket {
+@@ -48,19 +48,18 @@ extern const std::string LOCAL_PORT_TYPE
+ class TCPPort : public Port {
+ public:
+ static TCPPort* Create(talk_base::Thread* thread,
+- talk_base::SocketFactory* factory,
++ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
+- const talk_base::SocketAddress& local_addr,
++ uint32 ip, int min_port, int max_port,
+ bool allow_listen) {
+- TCPPort* port = new TCPPort(thread, factory, network, local_addr,
+- allow_listen);
++ TCPPort* port = new TCPPort(thread, factory, network,
++ ip, min_port, max_port, allow_listen);
+ if (!port->Init()) {
+ delete port;
+ port = NULL;
+ }
+ return port;
+ }
+- bool Init();
+ virtual ~TCPPort();
+
+ virtual Connection* CreateConnection(const Candidate& address,
+@@ -72,36 +71,40 @@ class TCPPort : public Port {
+ virtual int GetError();
+
+ protected:
+- TCPPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+- talk_base::Network* network, const talk_base::SocketAddress& address,
++ TCPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++ talk_base::Network* network, uint32 ip, int min_port, int max_port,
+ bool allow_listen);
++ bool Init();
+
+ // Handles sending using the local TCP socket.
+ virtual int SendTo(const void* data, size_t size,
+ const talk_base::SocketAddress& addr, bool payload);
+
+- // Creates TCPConnection for incoming sockets
+- void OnAcceptEvent(talk_base::AsyncSocket* socket);
++ // Accepts incoming TCP connection.
++ void OnNewConnection(talk_base::AsyncPacketSocket* socket,
++ talk_base::AsyncPacketSocket* new_socket);
+
+ private:
+ struct Incoming {
+ talk_base::SocketAddress addr;
+- talk_base::AsyncTCPSocket * socket;
++ talk_base::AsyncPacketSocket* socket;
+ };
+
+- talk_base::AsyncTCPSocket* GetIncoming(const talk_base::SocketAddress& addr,
+- bool remove = false);
++ talk_base::AsyncPacketSocket* GetIncoming(
++ const talk_base::SocketAddress& addr, bool remove = false);
+
+ // Receives packet signal from the local TCP Socket.
+- void OnReadPacket(const char* data, size_t size,
+- const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket);
++ void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr);
++
++ void OnAddresReady(talk_base::AsyncPacketSocket* socket,
++ const talk_base::SocketAddress& address);
+
+- // Note: use this until Network ips are stable, then use network->ip
+- talk_base::SocketAddress address_;
++ // TODO: Is this still needed?
+ bool incoming_only_;
+ bool allow_listen_;
+- talk_base::AsyncSocket* socket_;
++ talk_base::AsyncPacketSocket* socket_;
+ int error_;
+ std::list<Incoming> incoming_;
+
+@@ -112,22 +115,22 @@ class TCPConnection : public Connection
+ public:
+ // Connection is outgoing unless socket is specified
+ TCPConnection(TCPPort* port, const Candidate& candidate,
+- talk_base::AsyncTCPSocket* socket = 0);
++ talk_base::AsyncPacketSocket* socket = 0);
+ virtual ~TCPConnection();
+
+ virtual int Send(const void* data, size_t size);
+ virtual int GetError();
+
+- talk_base::AsyncTCPSocket * socket() { return socket_; }
++ talk_base::AsyncPacketSocket* socket() { return socket_; }
+
+ private:
+- void OnConnect(talk_base::AsyncTCPSocket* socket);
+- void OnClose(talk_base::AsyncTCPSocket* socket, int error);
+- void OnReadPacket(const char* data, size_t size,
+- const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket);
++ void OnConnect(talk_base::AsyncPacketSocket* socket);
++ void OnClose(talk_base::AsyncPacketSocket* socket, int error);
++ void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr);
+
+- talk_base::AsyncTCPSocket* socket_;
++ talk_base::AsyncPacketSocket* socket_;
+ int error_;
+
+ friend class TCPPort;
+diff -upN libjingle-0.5.2/talk/p2p/base/transport.cc.chromium12
libjingle-0.5.2/talk/p2p/base/transport.cc
+--- libjingle-0.5.2/talk/p2p/base/transport.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/transport.cc 2011-03-30 21:51:32.711287001 -0400
+@@ -28,6 +28,7 @@
+ #include "talk/p2p/base/transport.h"
+
+ #include "talk/base/common.h"
++#include "talk/base/logging.h"
+ #include "talk/p2p/base/candidate.h"
+ #include "talk/p2p/base/constants.h"
+ #include "talk/p2p/base/sessionmanager.h"
+@@ -145,11 +146,13 @@ void Transport::DestroyChannel(const std
+
+ void Transport::DestroyChannel_w(const std::string& name) {
+ ASSERT(worker_thread()->IsCurrent());
++
+ TransportChannelImpl* impl = NULL;
+ {
+ talk_base::CritScope cs(&crit_);
+ ChannelMap::iterator iter = channels_.find(name);
+- ASSERT(iter != channels_.end());
++ if (iter == channels_.end())
++ return;
+ impl = iter->second;
+ channels_.erase(iter);
+ }
+@@ -173,7 +176,7 @@ void Transport::ConnectChannels() {
+
+ void Transport::ConnectChannels_w() {
+ ASSERT(worker_thread()->IsCurrent());
+- if (connect_requested_)
++ if (connect_requested_ || channels_.empty())
+ return;
+ connect_requested_ = true;
+ signaling_thread()->Post(
+@@ -192,6 +195,8 @@ void Transport::OnConnecting_s() {
+ void Transport::DestroyAllChannels() {
+ ASSERT(signaling_thread()->IsCurrent());
+ worker_thread()->Send(this, MSG_DESTROYALLCHANNELS, NULL);
++ worker_thread()->Clear(this);
++ signaling_thread()->Clear(this);
+ destroyed_ = true;
+ }
+
+@@ -233,6 +238,8 @@ void Transport::ResetChannels_w() {
+
+ void Transport::OnSignalingReady() {
+ ASSERT(signaling_thread()->IsCurrent());
++ if (destroyed_) return;
++
+ worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL);
+
+ // Notify the subclass.
+@@ -283,7 +290,13 @@ void Transport::OnRemoteCandidates(const
+
+ void Transport::OnRemoteCandidate(const Candidate& candidate) {
+ ASSERT(signaling_thread()->IsCurrent());
+- ASSERT(HasChannel(candidate.name()));
++ if (destroyed_) return;
++ if (!HasChannel(candidate.name())) {
++ LOG(LS_WARNING) << "Ignoring candidate for unknown channel "
++ << candidate.name();
++ return;
++ }
++
+ // new candidate deleted when params is deleted
+ ChannelParams* params = new ChannelParams(new Candidate(candidate));
+ ChannelMessage* msg = new ChannelMessage(params);
+@@ -445,7 +458,7 @@ bool TransportParser::ParseAddress(const
+
+ address->SetIP(elem->Attr(address_name));
+ std::istringstream ist(elem->Attr(port_name));
+- int port;
++ int port = 0;
+ ist >> port;
+ address->SetPort(port);
+
+diff -upN libjingle-0.5.2/talk/p2p/base/udpport.cc.chromium12
libjingle-0.5.2/talk/p2p/base/udpport.cc
+--- libjingle-0.5.2/talk/p2p/base/udpport.cc.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/udpport.cc 2011-03-30 21:51:32.711287001 -0400
+@@ -27,6 +27,7 @@
+
+ #include "talk/p2p/base/udpport.h"
+
++#include "talk/base/asyncpacketsocket.h"
+ #include "talk/base/logging.h"
+ #include "talk/p2p/base/common.h"
+
+@@ -34,23 +35,22 @@ namespace cricket {
+
+ const std::string LOCAL_PORT_TYPE("local");
+
+-UDPPort::UDPPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+- talk_base::Network* network)
+- : Port(thread, LOCAL_PORT_TYPE, factory, network),
+- socket_(NULL), error_(0) {
++UDPPort::UDPPort(talk_base::Thread* thread,
++ talk_base::PacketSocketFactory* factory,
++ talk_base::Network* network,
++ uint32 ip, int min_port, int max_port)
++ : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port),
++ socket_(NULL),
++ error_(0) {
+ }
+
+-bool UDPPort::Init(const talk_base::SocketAddress& local_addr) {
+- socket_ = CreatePacketSocket(PROTO_UDP);
++bool UDPPort::Init() {
++ socket_ = factory_->CreateUdpSocket(
++ talk_base::SocketAddress(ip_, 0), min_port_, max_port_);
+ if (!socket_) {
+ LOG_J(LS_WARNING, this) << "UDP socket creation failed";
+ return false;
+ }
+- if (socket_->Bind(local_addr) < 0) {
+- LOG_J(LS_WARNING, this) << "UDP bind failed with error "
+- << socket_->GetError();
+- return false;
+- }
+ socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
+ return true;
+ }
+@@ -60,7 +60,13 @@ UDPPort::~UDPPort() {
+ }
+
+ void UDPPort::PrepareAddress() {
+- AddAddress(socket_->GetLocalAddress(), "udp", true);
++ bool allocated;
++ talk_base::SocketAddress address = socket_->GetLocalAddress(&allocated);
++ if (allocated) {
++ AddAddress(address, "udp", true);
++ } else {
++ socket_->SignalAddressReady.connect(this, &UDPPort::OnAddresReady);
++ }
+ }
+
+ Connection* UDPPort::CreateConnection(const Candidate& address,
+@@ -80,7 +86,7 @@ int UDPPort::SendTo(const void* data, si
+ error_ = socket_->GetError();
+ LOG_J(LS_ERROR, this) << "UDP send of " << size
+ << " bytes failed with error " <<
error_;
+- }
++ }
+ return sent;
+ }
+
+@@ -92,9 +98,14 @@ int UDPPort::GetError() {
+ return error_;
+ }
+
++void UDPPort::OnAddresReady(talk_base::AsyncPacketSocket* socket,
++ const talk_base::SocketAddress& address) {
++ AddAddress(address, "udp", true);
++}
++
+ void UDPPort::OnReadPacket(
+- const char* data, size_t size, const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket) {
++ talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr) {
+ ASSERT(socket == socket_);
+ if (Connection* conn = GetConnection(remote_addr)) {
+ conn->OnReadPacket(data, size);
+diff -upN libjingle-0.5.2/talk/p2p/base/udpport.h.chromium12
libjingle-0.5.2/talk/p2p/base/udpport.h
+--- libjingle-0.5.2/talk/p2p/base/udpport.h.chromium12 2011-01-11 19:25:50.000000000
-0500
++++ libjingle-0.5.2/talk/p2p/base/udpport.h 2011-03-30 21:51:32.711287001 -0400
+@@ -30,7 +30,6 @@
+
+ #include <string>
+
+-#include "talk/base/asyncudpsocket.h"
+ #include "talk/p2p/base/port.h"
+
+ namespace talk_base {
+@@ -47,19 +46,17 @@ extern const std::string LOCAL_PORT_TYPE
+ class UDPPort : public Port {
+ public:
+ static UDPPort* Create(talk_base::Thread* thread,
+- talk_base::SocketFactory* factory,
++ talk_base::PacketSocketFactory* factory,
+ talk_base::Network* network,
+- const talk_base::SocketAddress& local_addr) {
+- UDPPort* port = new UDPPort(thread, factory, network);
+- if (!port->Init(local_addr)) {
++ uint32 ip, int min_port, int max_port) {
++ UDPPort* port = new UDPPort(thread, factory, network,
++ ip, min_port, max_port);
++ if (!port->Init()) {
+ delete port;
+ port = NULL;
+ }
+ return port;
+ }
+- UDPPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+- talk_base::Network* network);
+- bool Init(const talk_base::SocketAddress& local_addr);
+ virtual ~UDPPort();
+
+ virtual void PrepareAddress();
+@@ -70,14 +67,21 @@ class UDPPort : public Port {
+ virtual int GetError();
+
+ protected:
++ UDPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++ talk_base::Network* network, uint32 ip, int min_port, int max_port);
++ bool Init();
++
+ // Handles sending using the local UDP socket.
+ virtual int SendTo(const void* data, size_t size,
+ const talk_base::SocketAddress& remote_addr, bool payload);
+
++ void OnAddresReady(talk_base::AsyncPacketSocket* socket,
++ const talk_base::SocketAddress& address);
++
+ // Dispatches the given packet to the port or connection as appropriate.
+- void OnReadPacket(const char* data, size_t size,
+- const talk_base::SocketAddress& remote_addr,
+- talk_base::AsyncPacketSocket* socket);
++ void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++ const char* data, size_t size,
++ const talk_base::SocketAddress& remote_addr);
+
+ private:
+ talk_base::AsyncPacketSocket* socket_;
+diff -upN libjingle-0.5.2/talk/p2p/client/basicportallocator.cc.chromium12
libjingle-0.5.2/talk/p2p/client/basicportallocator.cc
+--- libjingle-0.5.2/talk/p2p/client/basicportallocator.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/client/basicportallocator.cc 2011-03-30 21:51:32.712287001
-0400
+@@ -166,17 +166,24 @@ class AllocationSequence : public talk_b
+ // BasicPortAllocator
+
+ BasicPortAllocator::BasicPortAllocator(
+- talk_base::NetworkManager* network_manager)
+- : network_manager_(network_manager), best_writable_phase_(-1) {
++ talk_base::NetworkManager* network_manager,
++ talk_base::PacketSocketFactory* socket_factory)
++ : network_manager_(network_manager),
++ socket_factory_(socket_factory),
++ best_writable_phase_(-1),
++ allow_tcp_listen_(true) {
++ ASSERT(socket_factory_ != NULL);
+ }
+
+ BasicPortAllocator::BasicPortAllocator(
+ talk_base::NetworkManager* network_manager,
++ talk_base::PacketSocketFactory* socket_factory,
+ const talk_base::SocketAddress& stun_address,
+ const talk_base::SocketAddress& relay_address_udp,
+ const talk_base::SocketAddress& relay_address_tcp,
+ const talk_base::SocketAddress& relay_address_ssl)
+ : network_manager_(network_manager),
++ socket_factory_(socket_factory),
+ stun_address_(stun_address),
+ relay_address_udp_(relay_address_udp),
+ relay_address_tcp_(relay_address_tcp),
+@@ -656,8 +663,11 @@ void AllocationSequence::CreateUDPPorts(
+ return;
+ }
+
+- Port* port = UDPPort::Create(session_->network_thread(), NULL, network_,
+- talk_base::SocketAddress(ip_, 0));
++ Port* port = UDPPort::Create(session_->network_thread(),
++ session_->allocator()->socket_factory(),
++ network_, ip_,
++ session_->allocator()->min_port(),
++ session_->allocator()->max_port());
+ if (port)
+ session_->AddAllocatedPort(port, this, PREF_LOCAL_UDP);
+ }
+@@ -668,8 +678,11 @@ void AllocationSequence::CreateTCPPorts(
+ return;
+ }
+
+- Port* port = TCPPort::Create(session_->network_thread(), NULL, network_,
+- talk_base::SocketAddress(ip_, 0),
++ Port* port = TCPPort::Create(session_->network_thread(),
++ session_->allocator()->socket_factory(),
++ network_, ip_,
++ session_->allocator()->min_port(),
++ session_->allocator()->max_port(),
+ session_->allocator()->allow_tcp_listen());
+ if (port)
+ session_->AddAllocatedPort(port, this, PREF_LOCAL_TCP);
+@@ -690,8 +703,11 @@ void AllocationSequence::CreateStunPorts
+ return;
+ }
+
+- Port* port = StunPort::Create(session_->network_thread(), NULL, network_,
+- talk_base::SocketAddress(ip_, 0),
++ Port* port = StunPort::Create(session_->network_thread(),
++ session_->allocator()->socket_factory(),
++ network_, ip_,
++ session_->allocator()->min_port(),
++ session_->allocator()->max_port(),
+ config_->stun_address);
+ if (port)
+ session_->AddAllocatedPort(port, this, PREF_LOCAL_STUN);
+@@ -715,9 +731,11 @@ void AllocationSequence::CreateRelayPort
+ PortConfiguration::RelayList::const_iterator relay;
+ for (relay = config_->relays.begin();
+ relay != config_->relays.end(); ++relay) {
+- RelayPort* port = RelayPort::Create(session_->network_thread(), NULL,
+- network_,
+- talk_base::SocketAddress(ip_, 0),
++ RelayPort* port = RelayPort::Create(session_->network_thread(),
++ session_->allocator()->socket_factory(),
++ network_, ip_,
++ session_->allocator()->min_port(),
++ session_->allocator()->max_port(),
+ config_->username, config_->password,
+ config_->magic_cookie);
+ if (port) {
+diff -upN libjingle-0.5.2/talk/p2p/client/basicportallocator.h.chromium12
libjingle-0.5.2/talk/p2p/client/basicportallocator.h
+--- libjingle-0.5.2/talk/p2p/client/basicportallocator.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/client/basicportallocator.h 2011-03-30 21:51:32.712287001
-0400
+@@ -40,8 +40,10 @@ namespace cricket {
+
+ class BasicPortAllocator : public PortAllocator {
+ public:
+- explicit BasicPortAllocator(talk_base::NetworkManager* network_manager);
+ BasicPortAllocator(talk_base::NetworkManager* network_manager,
++ talk_base::PacketSocketFactory* socket_factory);
++ BasicPortAllocator(talk_base::NetworkManager* network_manager,
++ talk_base::PacketSocketFactory* socket_factory,
+ const talk_base::SocketAddress& stun_server,
+ const talk_base::SocketAddress& relay_server_udp,
+ const talk_base::SocketAddress& relay_server_tcp,
+@@ -50,6 +52,8 @@ class BasicPortAllocator : public PortAl
+
+ talk_base::NetworkManager* network_manager() { return network_manager_; }
+
++ talk_base::PacketSocketFactory* socket_factory() { return socket_factory_; }
++
+ const talk_base::SocketAddress& stun_address() const {
+ return stun_address_;
+ }
+@@ -84,6 +88,7 @@ class BasicPortAllocator : public PortAl
+
+ private:
+ talk_base::NetworkManager* network_manager_;
++ talk_base::PacketSocketFactory* socket_factory_;
+ const talk_base::SocketAddress stun_address_;
+ const talk_base::SocketAddress relay_address_udp_;
+ const talk_base::SocketAddress relay_address_tcp_;
+diff -upN libjingle-0.5.2/talk/p2p/client/httpportallocator.cc.chromium12
libjingle-0.5.2/talk/p2p/client/httpportallocator.cc
+--- libjingle-0.5.2/talk/p2p/client/httpportallocator.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/client/httpportallocator.cc 2011-03-30 21:51:32.712287001
-0400
+@@ -96,9 +96,11 @@ const int HttpPortAllocator::kNumRetries
+
+ const std::string HttpPortAllocator::kCreateSessionURL = "/create_session";
+
+-HttpPortAllocator::HttpPortAllocator(talk_base::NetworkManager* network_manager,
+- const std::string &user_agent)
+- : BasicPortAllocator(network_manager), agent_(user_agent) {
++HttpPortAllocator::HttpPortAllocator(
++ talk_base::NetworkManager* network_manager,
++ talk_base::PacketSocketFactory* socket_factory,
++ const std::string &user_agent)
++ : BasicPortAllocator(network_manager, socket_factory), agent_(user_agent) {
+ relay_hosts_.push_back("relay.google.com");
+ stun_hosts_.push_back(
+ talk_base::SocketAddress("stun.l.google.com", 19302));
+diff -upN libjingle-0.5.2/talk/p2p/client/httpportallocator.h.chromium12
libjingle-0.5.2/talk/p2p/client/httpportallocator.h
+--- libjingle-0.5.2/talk/p2p/client/httpportallocator.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/client/httpportallocator.h 2011-03-30 21:51:32.712287001
-0400
+@@ -50,6 +50,7 @@ class HttpPortAllocator : public BasicPo
+ static const std::string kCreateSessionURL;
+
+ HttpPortAllocator(talk_base::NetworkManager* network_manager,
++ talk_base::PacketSocketFactory* socket_factory,
+ const std::string& user_agent);
+ virtual ~HttpPortAllocator();
+
+diff -upN libjingle-0.5.2/talk/session/phone/channel.cc.chromium12
libjingle-0.5.2/talk/session/phone/channel.cc
+--- libjingle-0.5.2/talk/session/phone/channel.cc.chromium12 2011-01-11
19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/channel.cc 2011-03-30 21:51:32.713287001 -0400
+@@ -43,6 +43,24 @@ struct PacketMessageData : public talk_b
+ talk_base::Buffer packet;
+ };
+
++struct VoiceChannelErrorMessageData : public talk_base::MessageData {
++ VoiceChannelErrorMessageData(uint32 in_ssrc,
++ VoiceMediaChannel::Error in_error)
++ : ssrc(in_ssrc),
++ error(in_error) {}
++ uint32 ssrc;
++ VoiceMediaChannel::Error error;
++};
++
++struct VideoChannelErrorMessageData : public talk_base::MessageData {
++ VideoChannelErrorMessageData(uint32 in_ssrc,
++ VideoMediaChannel::Error in_error)
++ : ssrc(in_ssrc),
++ error(in_error) {}
++ uint32 ssrc;
++ VideoMediaChannel::Error error;
++};
++
+ static const char* PacketType(bool rtcp) {
+ return (!rtcp) ? "RTP" : "RTCP";
+ }
+@@ -101,6 +119,7 @@ BaseChannel::BaseChannel(talk_base::Thre
+ BaseChannel::~BaseChannel() {
+ ASSERT(worker_thread_ == talk_base::Thread::Current());
+ StopConnectionMonitor();
++ FlushRtcpMessages(); // Send any outstanding RTCP packets.
+ Clear(); // eats any outstanding messages or packets
+ // We must destroy the media channel before the transport channel, otherwise
+ // the media channel may try to send on the dead transport channel. NULLing
+@@ -365,32 +384,34 @@ void BaseChannel::HandlePacket(bool rtcp
+
+ void BaseChannel::OnSessionState(BaseSession* session,
+ BaseSession::State state) {
+- // TODO: tear down the call via session->SetError() if the
+- // SetXXXXDescription calls fail.
+ const MediaContentDescription* content = NULL;
+ switch (state) {
+ case Session::STATE_SENTINITIATE:
+ content = GetFirstContent(session->local_description());
+- if (content) {
+- SetLocalContent(content, CA_OFFER);
++ if (content && !SetLocalContent(content, CA_OFFER)) {
++ LOG(LS_ERROR) << "Failure in SetLocalContent with CA_OFFER";
++ session->SetError(BaseSession::ERROR_CONTENT);
+ }
+ break;
+ case Session::STATE_SENTACCEPT:
+ content = GetFirstContent(session->local_description());
+- if (content) {
+- SetLocalContent(content, CA_ANSWER);
++ if (content && !SetLocalContent(content, CA_ANSWER)) {
++ LOG(LS_ERROR) << "Failure in SetLocalContent with CA_ANSWER";
++ session->SetError(BaseSession::ERROR_CONTENT);
+ }
+ break;
+ case Session::STATE_RECEIVEDINITIATE:
+ content = GetFirstContent(session->remote_description());
+- if (content) {
+- SetRemoteContent(content, CA_OFFER);
++ if (content && !SetRemoteContent(content, CA_OFFER)) {
++ LOG(LS_ERROR) << "Failure in SetRemoteContent with CA_OFFER";
++ session->SetError(BaseSession::ERROR_CONTENT);
+ }
+ break;
+ case Session::STATE_RECEIVEDACCEPT:
+ content = GetFirstContent(session->remote_description());
+- if (content) {
+- SetRemoteContent(content, CA_ANSWER);
++ if (content && !SetRemoteContent(content, CA_ANSWER)) {
++ LOG(LS_ERROR) << "Failure in SetRemoteContent with CA_ANSWER";
++ session->SetError(BaseSession::ERROR_CONTENT);
+ }
+ break;
+ default:
+@@ -578,6 +599,18 @@ void BaseChannel::Clear(uint32 id, talk_
+ worker_thread_->Clear(this, id, removed);
+ }
+
++void BaseChannel::FlushRtcpMessages() {
++ // Flush all remaining RTCP messages. This should only be called in
++ // destructor.
++ ASSERT(talk_base::Thread::Current() == worker_thread_);
++ talk_base::MessageList rtcp_messages;
++ Clear(MSG_RTCPPACKET, &rtcp_messages);
++ for (talk_base::MessageList::iterator it = rtcp_messages.begin();
++ it != rtcp_messages.end(); ++it) {
++ Send(MSG_RTCPPACKET, it->pdata);
++ }
++}
++
+ VoiceChannel::VoiceChannel(talk_base::Thread* thread,
+ MediaEngine* media_engine,
+ VoiceMediaChannel* media_channel,
+@@ -593,6 +626,9 @@ VoiceChannel::VoiceChannel(talk_base::Th
+ // Can't go in BaseChannel because certain session states will
+ // trigger pure virtual functions, such as GetFirstContent().
+ OnSessionState(session, session->state());
++
++ media_channel->SignalMediaError.connect(
++ this, &VoiceChannel::OnVoiceChannelError);
+ }
+
+ VoiceChannel::~VoiceChannel() {
+@@ -692,8 +728,10 @@ void VoiceChannel::OnChannelRead(Transpo
+ // If we were playing out our local ringback, make sure it is stopped to
+ // prevent it from interfering with the incoming media.
+ if (!received_media_) {
+- received_media_ = false;
+- PlayRingbackTone_w(false, false);
++ if (!PlayRingbackTone_w(false, false)) {
++ LOG(LS_ERROR) << "Failed to stop ringback tone.";
++ SendLastMediaError();
++ }
+ }
+ }
+
+@@ -701,13 +739,19 @@ void VoiceChannel::ChangeState() {
+ // render incoming data if we are the active call
+ // we receive data on the default channel and multiplexed streams
+ bool recv = enabled();
+- media_channel()->SetPlayout(recv);
++ if (!media_channel()->SetPlayout(recv)) {
++ SendLastMediaError();
++ }
+
+ // send outgoing data if we are the active call, have the
+ // remote party's codec, and have a writable transport
+ // we only send data on the default channel
+ bool send = enabled() && has_codec() && writable();
+- media_channel()->SetSend(send ? SEND_MICROPHONE : SEND_NOTHING);
++ SendFlags send_flag = send ? SEND_MICROPHONE : SEND_NOTHING;
++ if (!media_channel()->SetSend(send_flag)) {
++ LOG(LS_ERROR) << "Failed to SetSend " << send_flag <<
" on voice channel";
++ SendLastMediaError();
++ }
+
+ LOG(LS_INFO) << "Changing voice state, recv=" << recv <<
" send=" << send;
+ }
+@@ -769,7 +813,10 @@ bool VoiceChannel::SetRemoteContent_w(co
+ ret = media_channel()->SetSendCodecs(audio->codecs());
+ }
+
+- int audio_options = audio->conference_mode() ? OPT_CONFERENCE : 0;
++ int audio_options = 0;
++ if (audio->conference_mode()) {
++ audio_options |= OPT_CONFERENCE;
++ }
+ if (!media_channel()->SetOptions(audio_options)) {
+ // Log an error on failure, but don't abort the call.
+ LOG(LS_ERROR) << "Failed to set voice channel options";
+@@ -850,6 +897,13 @@ void VoiceChannel::OnMessage(talk_base::
+ data->result = PressDTMF_w(data->digit, data->playout);
+ break;
+ }
++ case MSG_CHANNEL_ERROR: {
++ VoiceChannelErrorMessageData* data =
++ static_cast<VoiceChannelErrorMessageData*>(pmsg->pdata);
++ SignalMediaError(this, data->ssrc, data->error);
++ delete data;
++ break;
++ }
+
+ default:
+ BaseChannel::OnMessage(pmsg);
+@@ -873,6 +927,13 @@ void VoiceChannel::OnAudioMonitorUpdate(
+ SignalAudioMonitor(this, info);
+ }
+
++void VoiceChannel::OnVoiceChannelError(
++ uint32 ssrc, VoiceMediaChannel::Error error) {
++ VoiceChannelErrorMessageData *data = new VoiceChannelErrorMessageData(
++ ssrc, error);
++ signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
++}
++
+ VideoChannel::VideoChannel(talk_base::Thread* thread,
+ MediaEngine* media_engine,
+ VideoMediaChannel* media_channel,
+@@ -891,6 +952,15 @@ VideoChannel::VideoChannel(talk_base::Th
+ // trigger pure virtual functions, such as GetFirstContent()
+ OnSessionState(session, session->state());
+
++ media_channel->SignalMediaError.connect(
++ this, &VideoChannel::OnVideoChannelError);
++}
++
++void VoiceChannel::SendLastMediaError() {
++ uint32 ssrc;
++ VoiceMediaChannel::Error error;
++ media_channel()->GetLastMediaError(&ssrc, &error);
++ SignalMediaError(this, ssrc, error);
+ }
+
+ VideoChannel::~VideoChannel() {
+@@ -926,13 +996,19 @@ void VideoChannel::ChangeState() {
+ // render incoming data if we are the active call
+ // we receive data on the default channel and multiplexed streams
+ bool recv = enabled();
+- media_channel()->SetRender(recv);
++ if (!media_channel()->SetRender(recv)) {
++ LOG(LS_ERROR) << "Failed to SetRender on video channel";
++ // TODO: Report error back to server.
++ }
+
+ // send outgoing data if we are the active call, have the
+ // remote party's codec, and have a writable transport
+ // we only send data on the default channel
+ bool send = enabled() && has_codec() && writable();
+- media_channel()->SetSend(send);
++ if (!media_channel()->SetSend(send)) {
++ LOG(LS_ERROR) << "Failed to SetSend on video channel";
++ // TODO: Report error back to server.
++ }
+
+ LOG(LS_INFO) << "Changing video state, recv=" << recv <<
" send=" << send;
+ }
+@@ -1053,10 +1129,16 @@ void VideoChannel::OnMessage(talk_base::
+ case MSG_REQUESTINTRAFRAME:
+ RequestIntraFrame_w();
+ break;
+-
+- default:
+- BaseChannel::OnMessage(pmsg);
+- break;
++ case MSG_CHANNEL_ERROR: {
++ const VideoChannelErrorMessageData* data =
++ static_cast<VideoChannelErrorMessageData*>(pmsg->pdata);
++ SignalMediaError(this, data->ssrc, data->error);
++ delete data;
++ break;
++ }
++ default:
++ BaseChannel::OnMessage(pmsg);
++ break;
+ }
+ }
+
+@@ -1072,4 +1154,11 @@ void VideoChannel::OnMediaMonitorUpdate(
+ }
+
+
++void VideoChannel::OnVideoChannelError(uint32 ssrc,
++ VideoMediaChannel::Error error) {
++ VideoChannelErrorMessageData* data = new VideoChannelErrorMessageData(
++ ssrc, error);
++ signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
++}
++
+ } // namespace cricket
+diff -upN libjingle-0.5.2/talk/session/phone/channel.h.chromium12
libjingle-0.5.2/talk/session/phone/channel.h
+--- libjingle-0.5.2/talk/session/phone/channel.h.chromium12 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/session/phone/channel.h 2011-03-30 21:51:32.713287001 -0400
+@@ -69,7 +69,8 @@ enum {
+ MSG_SENDINTRAFRAME = 19,
+ MSG_REQUESTINTRAFRAME = 20,
+ MSG_RTPPACKET = 22,
+- MSG_RTCPPACKET = 23
++ MSG_RTCPPACKET = 23,
++ MSG_CHANNEL_ERROR = 24
+ };
+
+ // BaseChannel contains logic common to voice and video, including
+@@ -83,7 +84,7 @@ class BaseChannel
+ MediaChannel* channel, BaseSession* session,
+ const std::string& content_name,
+ TransportChannel* transport_channel);
+- ~BaseChannel();
++ virtual ~BaseChannel();
+
+ talk_base::Thread* worker_thread() const { return worker_thread_; }
+ BaseSession* session() const { return session_; }
+@@ -94,6 +95,7 @@ class BaseChannel
+ TransportChannel* rtcp_transport_channel() const {
+ return rtcp_transport_channel_;
+ }
++ bool enabled() const { return enabled_; }
+ bool secure() const { return srtp_filter_.IsActive(); }
+
+ // Channel control
+@@ -136,7 +138,6 @@ class BaseChannel
+ MediaEngine* media_engine() const { return media_engine_; }
+ virtual MediaChannel* media_channel() const { return media_channel_; }
+ void set_rtcp_transport_channel(TransportChannel* transport);
+- bool enabled() const { return enabled_; }
+ bool writable() const { return writable_; }
+ bool has_codec() const { return has_codec_; }
+ void set_has_codec(bool has_codec) { has_codec_ = has_codec; }
+@@ -149,6 +150,7 @@ class BaseChannel
+ talk_base::MessageData *pdata = NULL);
+ void Clear(uint32 id = talk_base::MQID_ANY,
+ talk_base::MessageList* removed = NULL);
++ void FlushRtcpMessages();
+
+ // NetworkInterface implementation, called by MediaEngine
+ virtual bool SendPacket(talk_base::Buffer* packet);
+@@ -290,6 +292,11 @@ class VoiceChannel : public BaseChannel
+ int GetOutputLevel_w();
+ void GetActiveStreams_w(AudioInfo::StreamList* actives);
+
++ // Signal errors from VoiceMediaChannel. Arguments are:
++ // ssrc(uint32), and error(VoiceMediaChannel::Error).
++ sigslot::signal3<VoiceChannel*, uint32, VoiceMediaChannel::Error>
++ SignalMediaError;
++
+ private:
+ struct SetRingbackToneMessageData : public talk_base::MessageData {
+ SetRingbackToneMessageData(const void* b, int l)
+@@ -345,6 +352,8 @@ class VoiceChannel : public BaseChannel
+ virtual void OnMediaMonitorUpdate(
+ VoiceMediaChannel *media_channel, const VoiceMediaInfo& info);
+ void OnAudioMonitorUpdate(AudioMonitor *monitor, const AudioInfo& info);
++ void OnVoiceChannelError(uint32 ssrc, VoiceMediaChannel::Error error);
++ void SendLastMediaError();
+
+ static const int kEarlyMediaTimeout = 1000;
+ bool received_media_;
+@@ -382,6 +391,9 @@ class VideoChannel : public BaseChannel
+ bool SendIntraFrame();
+ bool RequestIntraFrame();
+
++ sigslot::signal3<VideoChannel*, uint32, VideoMediaChannel::Error>
++ SignalMediaError;
++
+ private:
+ // overrides from BaseChannel
+ virtual void ChangeState();
+@@ -417,6 +429,8 @@ class VideoChannel : public BaseChannel
+ SocketMonitor *monitor, const std::vector<ConnectionInfo> &infos);
+ virtual void OnMediaMonitorUpdate(
+ VideoMediaChannel *media_channel, const VideoMediaInfo& info);
++ void OnVideoChannelError(uint32 ssrc, VideoMediaChannel::Error error);
++
+ VoiceChannel *voice_channel_;
+ VideoRenderer *renderer_;
+ talk_base::scoped_ptr<VideoMediaMonitor> media_monitor_;
+diff -upN libjingle-0.5.2/talk/session/phone/channelmanager.cc.chromium12
libjingle-0.5.2/talk/session/phone/channelmanager.cc
+--- libjingle-0.5.2/talk/session/phone/channelmanager.cc.chromium12 2011-01-11
19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/channelmanager.cc 2011-03-30 21:51:32.714287001
-0400
+@@ -39,10 +39,6 @@
+ #include "talk/base/stringencode.h"
+ #include "talk/session/phone/mediaengine.h"
+ #include "talk/session/phone/soundclip.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/platformsoundsystemfactory.h"
+-#include "talk/sound/soundsysteminterface.h"
+-#endif
+
+ namespace cricket {
+
+@@ -134,23 +130,13 @@ struct CaptureParams : public talk_base:
+ };
+
+ ChannelManager::ChannelManager(talk_base::Thread* worker_thread)
+- :
+-#ifdef USE_TALK_SOUND
+- sound_system_factory_(new PlatformSoundSystemFactory()),
+-#endif
+- media_engine_(MediaEngine::Create(
+-#ifdef USE_TALK_SOUND
+- sound_system_factory_.get()
+-#endif
+- )),
+- device_manager_(new DeviceManager(
+-#ifdef USE_TALK_SOUND
+- sound_system_factory_.get()
+-#endif
+- )),
++ : media_engine_(MediaEngine::Create()),
++ device_manager_(new DeviceManager()),
+ initialized_(false),
+ main_thread_(talk_base::Thread::Current()),
+ worker_thread_(worker_thread),
++ audio_in_device_(DeviceManager::kDefaultDeviceName),
++ audio_out_device_(DeviceManager::kDefaultDeviceName),
+ audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+ local_renderer_(NULL),
+ capturing_(false),
+@@ -160,15 +146,13 @@ ChannelManager::ChannelManager(talk_base
+
+ ChannelManager::ChannelManager(MediaEngine* me, DeviceManager* dm,
+ talk_base::Thread* worker_thread)
+- :
+-#ifdef USE_TALK_SOUND
+- sound_system_factory_(NULL),
+-#endif
+- media_engine_(me),
++ : media_engine_(me),
+ device_manager_(dm),
+ initialized_(false),
+ main_thread_(talk_base::Thread::Current()),
+ worker_thread_(worker_thread),
++ audio_in_device_(DeviceManager::kDefaultDeviceName),
++ audio_out_device_(DeviceManager::kDefaultDeviceName),
+ audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+ local_renderer_(NULL),
+ capturing_(false),
+@@ -180,7 +164,8 @@ void ChannelManager::Construct() {
+ // Init the device manager immediately, and set up our default video device.
+ SignalDevicesChange.repeat(device_manager_->SignalDevicesChange);
+ device_manager_->Init();
+- SetVideoOptions("");
++ // Set camera_device_ to the name of the default video capturer.
++ SetVideoOptions(DeviceManager::kDefaultDeviceName);
+
+ // Camera is started asynchronously, request callbacks when startup
+ // completes to be able to forward them to the rendering manager.
+@@ -230,18 +215,47 @@ bool ChannelManager::Init() {
+ if (media_engine_->Init()) {
+ initialized_ = true;
+
+- // Now that we're initialized, apply any stored preferences.
++ // Now that we're initialized, apply any stored preferences. A preferred
++ // device might have been unplugged. In this case, we fallback to the
++ // default device but keep the user preferences. The preferences are
++ // changed only when the Javascript FE changes them.
++ const std::string preferred_audio_in_device = audio_in_device_;
++ const std::string preferred_audio_out_device = audio_out_device_;
++ const std::string preferred_camera_device = camera_device_;
++ Device device;
++ if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
++ LOG(LS_WARNING) << "The preferred microphone '" <<
audio_in_device_
++ << "' is unavailable. Fall back to the
default.";
++ audio_in_device_ = DeviceManager::kDefaultDeviceName;
++ }
++ if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
++ LOG(LS_WARNING) << "The preferred speaker '" <<
audio_out_device_
++ << "' is unavailable. Fall back to the
default.";
++ audio_out_device_ = DeviceManager::kDefaultDeviceName;
++ }
++ if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
++ LOG(LS_WARNING) << "The preferred camera '" <<
camera_device_
++ << "' is unavailable. Fall back to the
default.";
++ camera_device_ = DeviceManager::kDefaultDeviceName;
++ }
++
+ if (!SetAudioOptions(audio_in_device_, audio_out_device_,
+ audio_options_)) {
+- audio_in_device_.clear();
+- audio_out_device_.clear();
++ LOG(LS_WARNING) << "Failed to SetAudioOptions with"
++ << " microphone: " << audio_in_device_
++ << " speaker: " << audio_out_device_
++ << " options: " << audio_options_;
+ }
+ if (!SetVideoOptions(camera_device_)) {
+- // Perhaps it's been unplugged, fall back to default device
+- if (!SetVideoOptions("")) {
+- camera_device_.clear();
+- }
++ LOG(LS_WARNING) << "Failed to SetVideoOptions with camera: "
++ << camera_device_;
+ }
++
++ // Restore the user preferences.
++ audio_in_device_ = preferred_audio_in_device;
++ audio_out_device_ = preferred_audio_out_device;
++ camera_device_ = preferred_camera_device;
++
+ // Now apply the default video codec that has been set earlier.
+ if (default_video_encoder_config_.max_codec.id != 0) {
+ SetDefaultVideoEncoderConfig(default_video_encoder_config_);
+@@ -480,29 +494,15 @@ bool ChannelManager::GetVideoOptions(std
+ }
+
+ bool ChannelManager::SetVideoOptions(const std::string& cam_name) {
+- bool ret;
+ Device device;
+-
+- if (cam_name.empty()) {
+- // If we're passed the default device name, get the default device.
+- ret = device_manager_->GetDefaultVideoCaptureDevice(&device);
+- } else {
+- // Convert the camera name to a device, fail if it can't be found.
+- std::vector<Device> devices;
+- ret = device_manager_->GetVideoCaptureDevices(&devices);
+- if (ret) {
+- for (size_t i = 0; i < devices.size(); ++i) {
+- if (devices[i].name == cam_name) {
+- device = devices[i];
+- break;
+- }
+- }
+- ret = !device.name.empty();
+- }
++ if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
++ LOG(LS_WARNING) << "Device manager can't find camera: " <<
cam_name;
++ return false;
+ }
+
+ // If we're running, tell the media engine about it.
+- if (ret && initialized_) {
++ bool ret = true;
++ if (initialized_) {
+ VideoOptions options(&device);
+ ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result);
+ }
+@@ -628,10 +628,10 @@ bool ChannelManager::Send(uint32 id, tal
+ return true;
+ }
+
+-void ChannelManager::OnVideoCaptureResult(bool result) {
+- capturing_ = result;
++void ChannelManager::OnVideoCaptureResult(CaptureResult result) {
++ capturing_ = result == CR_SUCCESS;
+ main_thread_->Post(this, MSG_CAMERASTARTED,
+- new talk_base::TypedMessageData<bool>(result));
++ new talk_base::TypedMessageData<CaptureResult>(result));
+ }
+
+ void ChannelManager::OnMessage(talk_base::Message* message) {
+@@ -718,8 +718,9 @@ void ChannelManager::OnMessage(talk_base
+ break;
+ }
+ case MSG_CAMERASTARTED: {
+- talk_base::TypedMessageData<bool> *data =
+-
static_cast<talk_base::TypedMessageData<bool>*>(message->pdata);
++ talk_base::TypedMessageData<CaptureResult>* data =
++ static_cast<talk_base::TypedMessageData<CaptureResult>*>(
++ message->pdata);
+ SignalVideoCaptureResult(data->data());
+ delete data;
+ break;
+diff -upN libjingle-0.5.2/talk/session/phone/channelmanager.h.chromium12
libjingle-0.5.2/talk/session/phone/channelmanager.h
+--- libjingle-0.5.2/talk/session/phone/channelmanager.h.chromium12 2011-01-11
19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/channelmanager.h 2011-03-30 21:51:32.714287001
-0400
+@@ -38,9 +38,6 @@
+ #include "talk/session/phone/voicechannel.h"
+ #include "talk/session/phone/mediaengine.h"
+ #include "talk/session/phone/devicemanager.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/soundsystemfactory.h"
+-#endif
+
+ namespace cricket {
+
+@@ -157,7 +154,7 @@ class ChannelManager : public talk_base:
+ bool GetAudioOutputDevices(std::vector<std::string>* names);
+ bool GetVideoCaptureDevices(std::vector<std::string>* names);
+ sigslot::repeater0<> SignalDevicesChange;
+- sigslot::signal1<bool> SignalVideoCaptureResult;
++ sigslot::signal1<CaptureResult> SignalVideoCaptureResult;
+
+ private:
+ typedef std::vector<VoiceChannel*> VoiceChannels;
+@@ -185,13 +182,10 @@ class ChannelManager : public talk_base:
+ CaptureResult SetVideoCapture_w(bool capture);
+ void SetMediaLogging(bool video, int level, const char* filter);
+ void SetMediaLogging_w(bool video, int level, const char* filter);
+- void OnVideoCaptureResult(bool result);
++ void OnVideoCaptureResult(CaptureResult result);
+ void OnMessage(talk_base::Message *message);
+
+ talk_base::CriticalSection crit_;
+-#ifdef USE_TALK_SOUND
+- talk_base::scoped_ptr<SoundSystemFactory> sound_system_factory_;
+-#endif
+ talk_base::scoped_ptr<MediaEngine> media_engine_;
+ talk_base::scoped_ptr<DeviceManager> device_manager_;
+ bool initialized_;
+diff -upN libjingle-0.5.2/talk/session/phone/cryptoparams.h.chromium12
libjingle-0.5.2/talk/session/phone/cryptoparams.h
+--- libjingle-0.5.2/talk/session/phone/cryptoparams.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/cryptoparams.h 2011-03-30 21:51:32.714287001
-0400
+@@ -32,7 +32,7 @@
+
+ namespace cricket {
+
+-// Parameters for SRTP negotiation, as described in RFC 4586.
++// Parameters for SRTP negotiation, as described in RFC 4568.
+ struct CryptoParams {
+ CryptoParams() : tag(0) {}
+ CryptoParams(int t, const std::string& cs,
+diff -upN libjingle-0.5.2/talk/session/phone/Makefile.am.chromium12
libjingle-0.5.2/talk/session/phone/Makefile.am
+--- libjingle-0.5.2/talk/session/phone/Makefile.am.chromium12 2011-03-30
21:51:32.658287001 -0400
++++ libjingle-0.5.2/talk/session/phone/Makefile.am 2011-03-30 21:51:32.715287001 -0400
+@@ -7,9 +7,11 @@
+ codec.cc \
+ devicemanager.cc \
+ filemediaengine.cc \
++ libudevsymboltable.cc \
+ mediaengine.cc \
+ mediamonitor.cc \
+ mediasessionclient.cc \
++ rtcpmuxfilter.cc \
+ rtpdump.cc \
+ soundclip.cc \
+ srtpfilter.cc \
+@@ -26,8 +28,10 @@
+ channel.h \
+ filemediaengine.h \
+ mediasessionclient.h \
++ rtcpmuxfilter.h \
+ rtpdump.h \
+ srtpfilter.h \
++ libudevsymboltable.h \
+ videocommon.h
+
+ libjinglesessionphone_la_LDFLAGS = -version-info $(LIBJINGLE_LIBRARY_VERSION)
+diff -upN libjingle-0.5.2/talk/session/phone/mediachannel.h.chromium12
libjingle-0.5.2/talk/session/phone/mediachannel.h
+--- libjingle-0.5.2/talk/session/phone/mediachannel.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/mediachannel.h 2011-03-30 21:51:32.715287001
-0400
+@@ -187,6 +187,24 @@ struct VideoMediaInfo {
+
+ class VoiceMediaChannel : public MediaChannel {
+ public:
++ enum Error {
++ ERROR_NONE = 0, // No error.
++ ERROR_OTHER, // Other errors.
++ ERROR_REC_DEVICE_OPEN_FAILED = 100, // Could not open mic.
++ ERROR_REC_DEVICE_MUTED, // Mic was muted by OS.
++ ERROR_REC_DEVICE_SILENT, // No background noise picked up.
++ ERROR_REC_DEVICE_SATURATION, // Mic input is clipping.
++ ERROR_REC_DEVICE_REMOVED, // Mic was removed while active.
++ ERROR_REC_RUNTIME_ERROR, // Processing is encountering errors.
++ ERROR_REC_SRTP_ERROR, // Generic SRTP failure.
++ ERROR_PLAY_DEVICE_OPEN_FAILED = 200, // Could not open playout.
++ ERROR_PLAY_DEVICE_MUTED, // Playout muted by OS.
++ ERROR_PLAY_DEVICE_REMOVED, // Playout removed while active.
++ ERROR_PLAY_RUNTIME_ERROR, // Errors in voice processing.
++ ERROR_PLAY_SRTP_ERROR, // Generic SRTP failure.
++ ERROR_PLAY_SRTP_AUTH_FAILED, // Failed to authenticate packets.
++ };
++
+ VoiceMediaChannel() {}
+ virtual ~VoiceMediaChannel() {}
+ // Sets the codecs/payload types to be used for incoming media.
+@@ -213,6 +231,16 @@ class VoiceMediaChannel : public MediaCh
+ virtual bool PressDTMF(int event, bool playout) = 0;
+ // Gets quality stats for the channel.
+ virtual bool GetStats(VoiceMediaInfo* info) = 0;
++ // Gets last reported error for this media channel.
++ virtual void GetLastMediaError(uint32* ssrc,
++ VoiceMediaChannel::Error* error) {
++ ASSERT(error != NULL);
++ *error = ERROR_NONE;
++ }
++
++ // Signal errors from MediaChannel. Arguments are:
++ // ssrc(uint32), and error(VoiceMediaChannel::Error).
++ sigslot::signal2<uint32, VoiceMediaChannel::Error> SignalMediaError;
+ };
+
+ // Represents a YUV420 (a.k.a. I420) video frame.
+@@ -390,6 +418,18 @@ class NullVideoRenderer : public VideoRe
+
+ class VideoMediaChannel : public MediaChannel {
+ public:
++ enum Error {
++ ERROR_NONE = 0, // No error.
++ ERROR_OTHER, // Other errors.
++ ERROR_REC_DEVICE_OPEN_FAILED = 100, // Could not open camera.
++ ERROR_REC_DEVICE_NO_DEVICE, // No camera.
++ ERROR_REC_DEVICE_IN_USE, // Device is in already use.
++ ERROR_REC_DEVICE_REMOVED, // Device is removed.
++ ERROR_REC_SRTP_ERROR, // Generic sender SRTP failure.
++ ERROR_PLAY_SRTP_ERROR = 200, // Generic receiver SRTP failure.
++ ERROR_PLAY_SRTP_AUTH_FAILED, // Failed to authenticate packets.
++ };
++
+ VideoMediaChannel() { renderer_ = NULL; }
+ virtual ~VideoMediaChannel() {}
+ // Sets the codecs/payload types to be used for incoming media.
+@@ -415,6 +455,7 @@ class VideoMediaChannel : public MediaCh
+ // Reuqest each of the remote senders to send an intra frame.
+ virtual bool RequestIntraFrame() = 0;
+
++ sigslot::signal2<uint32, Error> SignalMediaError;
+
+ protected:
+ VideoRenderer *renderer_;
+diff -upN libjingle-0.5.2/talk/session/phone/mediaengine.cc.chromium12
libjingle-0.5.2/talk/session/phone/mediaengine.cc
+--- libjingle-0.5.2/talk/session/phone/mediaengine.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/mediaengine.cc 2011-03-30 21:51:32.716287001
-0400
+@@ -33,11 +33,7 @@ namespace cricket {
+ // TODO: according to thaloun, HAVE_GIPSVIDEO will always
+ // be false, so we can get rid of it.
+
+-MediaEngine* MediaEngine::Create(
+-#ifdef USE_TALK_SOUND
+- SoundSystemFactory *factory
+-#endif
+- ) {
++MediaEngine* MediaEngine::Create() {
+ return new NullMediaEngine();
+ }
+
+diff -upN libjingle-0.5.2/talk/session/phone/mediaengine.h.chromium12
libjingle-0.5.2/talk/session/phone/mediaengine.h
+--- libjingle-0.5.2/talk/session/phone/mediaengine.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/mediaengine.h 2011-03-30 21:51:32.716287001 -0400
+@@ -39,9 +39,6 @@
+ #include "talk/session/phone/codec.h"
+ #include "talk/session/phone/devicemanager.h"
+ #include "talk/session/phone/mediachannel.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/soundsystemfactory.h"
+-#endif
+ #include "talk/session/phone/videocommon.h"
+
+ namespace cricket {
+@@ -88,11 +85,7 @@ class MediaEngine {
+ };
+
+ virtual ~MediaEngine() {}
+- static MediaEngine* Create(
+-#ifdef USE_TALK_SOUND
+- SoundSystemFactory *factory
+-#endif
+- );
++ static MediaEngine* Create();
+
+ // Initialization
+ // Starts the engine.
+@@ -154,7 +147,7 @@ class MediaEngine {
+ virtual void SetVoiceLogging(int min_sev, const char* filter) = 0;
+ virtual void SetVideoLogging(int min_sev, const char* filter) = 0;
+
+- sigslot::repeater1<bool> SignalVideoCaptureResult;
++ sigslot::repeater1<CaptureResult> SignalVideoCaptureResult;
+ };
+
+ // CompositeMediaEngine constructs a MediaEngine from separate
+@@ -162,11 +155,6 @@ class MediaEngine {
+ template<class VOICE, class VIDEO>
+ class CompositeMediaEngine : public MediaEngine {
+ public:
+-#ifdef USE_TALK_SOUND
+- explicit CompositeMediaEngine(SoundSystemFactory *factory)
+- : voice_(factory) {
+- }
+-#endif
+ CompositeMediaEngine() {}
+ virtual bool Init() {
+ if (!voice_.Init())
+@@ -257,6 +245,37 @@ class CompositeMediaEngine : public Medi
+ VIDEO video_;
+ };
+
++class NullVoiceMediaChannel : public VoiceMediaChannel {
++ public:
++ explicit NullVoiceMediaChannel() {}
++ ~NullVoiceMediaChannel() {}
++ // MediaChannel implementations
++ virtual void OnPacketReceived(talk_base::Buffer* packet) {}
++ virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
++ virtual void SetSendSsrc(uint32 id) {}
++ virtual bool SetRtcpCName(const std::string& cname) { return true; }
++ virtual bool Mute(bool on) { return true; }
++ virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
++ virtual bool SetOptions(int options) { return true; }
++ // VoiceMediaChannel implementations
++ virtual bool SetRecvCodecs(const std::vector<AudioCodec> &codecs) {
++ return true;
++ }
++ virtual bool SetSendCodecs(const std::vector<AudioCodec> &codecs) {
++ return true;
++ }
++ virtual bool SetPlayout(bool playout) { return true; }
++ virtual bool SetSend(SendFlags flag) { return true; }
++ virtual bool AddStream(uint32 ssrc) { return true; }
++ virtual bool RemoveStream(uint32 ssrc) { return true; }
++ virtual bool GetActiveStreams(AudioInfo::StreamList* streams) { return true; }
++ virtual int GetOutputLevel() { return 0; }
++ virtual void SetRingbackTone(const char *buf, int len) {}
++ virtual bool PlayRingbackTone(bool play, bool loop) { return true; }
++ virtual bool PressDTMF(int event, bool playout) { return true; }
++ virtual bool GetStats(VoiceMediaInfo* info) { return false; }
++};
++
+ // NullVoiceEngine can be used with CompositeMediaEngine in the case where only
+ // a video engine is desired.
+ class NullVoiceEngine {
+@@ -265,7 +284,9 @@ class NullVoiceEngine {
+ void Terminate() {}
+ int GetCapabilities() { return 0; }
+ VoiceMediaChannel* CreateChannel() {
+- return NULL;
++ // TODO: See if we can make things work without requiring
++ // allocation of a channel.
++ return new NullVoiceMediaChannel();
+ }
+ SoundclipMedia* CreateSoundclip() {
+ return NULL;
+@@ -304,7 +325,7 @@ class NullVideoEngine {
+ const std::vector<VideoCodec>& codecs() { return codecs_; }
+ bool FindCodec(const VideoCodec&) { return false; }
+ void SetLogging(int min_sev, const char* filter) {}
+- sigslot::signal1<bool> SignalCaptureResult;
++ sigslot::signal1<CaptureResult> SignalCaptureResult;
+ private:
+ std::vector<VideoCodec> codecs_;
+ };
+diff -upN libjingle-0.5.2/talk/session/phone/rtpdump.cc.chromium12
libjingle-0.5.2/talk/session/phone/rtpdump.cc
+--- libjingle-0.5.2/talk/session/phone/rtpdump.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/rtpdump.cc 2011-03-30 21:51:32.716287001 -0400
+@@ -262,9 +262,9 @@ void RtpDumpLoopReader::UpdateDumpPacket
+
+ if (packet->IsValidRtpPacket()) {
+ // Get the old RTP sequence number and timestamp.
+- uint16 sequence;
++ uint16 sequence = 0;
+ packet->GetRtpSeqNum(&sequence);
+- uint32 timestamp;
++ uint32 timestamp = 0;
+ packet->GetRtpTimestamp(×tamp);
+ // Increase the RTP sequence number and timestamp.
+ sequence += loop_count_ * rtp_seq_num_increase_;
+diff -upN libjingle-0.5.2/talk/session/phone/videocommon.h.chromium12
libjingle-0.5.2/talk/session/phone/videocommon.h
+--- libjingle-0.5.2/talk/session/phone/videocommon.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/videocommon.h 2011-03-30 21:51:32.716287001 -0400
+@@ -1,5 +1,5 @@
+ // libjingle
+-// Copyright 2004--2005, Google Inc.
++// Copyright 2011, Google Inc.
+ //
+ // Redistribution and use in source and binary forms, with or without
+ // modification, are permitted provided that the following conditions are met:
+@@ -59,34 +59,35 @@ inline std::string GetFourccName(uint32
+ //
http://developer.apple.com/quicktime/icefloe/dispatch020.html
+ //
http://www.fourcc.org/yuv.php
+ enum FourCC {
+- // Canonical fourccs used in our code.
++ // Canonical fourcc codes used in our code.
+ FOURCC_I420 = FOURCC('I', '4', '2', '0'),
+ FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
+ FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
++ FOURCC_M420 = FOURCC('M', '4', '2', '0'),
+ FOURCC_24BG = FOURCC('2', '4', 'B', 'G'),
+- FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'),
++ FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'),
+ FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'),
+ FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'),
+ FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
+- FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'),
+ FOURCC_RAW = FOURCC('r', 'a', 'w', ' '),
+- // Next five are Bayer RGB formats. The four characters define the order of
++ FOURCC_NV21 = FOURCC('N', 'V', '2', '1'),
++ FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
++ // Next four are Bayer RGB formats. The four characters define the order of
+ // the colours in each 2x2 pixel grid, going left-to-right and top-to-bottom.
+ FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'),
+ FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'),
+ FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'),
+ FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'),
+
+- // Aliases for canonical fourccs, replaced with their canonical equivalents by
+- // CanonicalFourCC().
++ // Aliases for canonical fourcc codes, replaced with their canonical
++ // equivalents by CanonicalFourCC().
+ FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias
for I420
+ FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Alias
for I420
+ FOURCC_YUYV = FOURCC('Y', 'U', 'Y', 'V'), // Alias
for YUY2
+- FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'), // Alias
for YUY2
++ FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'), // Alias
for YUY2 on Mac
+ FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'), // Alias
for UYVY
+ FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'), // Alias
for UYVY
+- FOURCC_RGB1 = FOURCC('R', 'G', 'B', '1'), // Alias
for ABGR
+- FOURCC_RGB2 = FOURCC('R', 'G', 'B', '2'), // Alias
for BGRA
++ FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'), // Alias
for MJPG
+ FOURCC_BA81 = FOURCC('B', 'A', '8', '1'), // Alias
for BGGR
+
+ // Match any fourcc.
+diff -upN libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.cc.chromium12
libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.cc
+--- libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.cc.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.cc 2011-03-30 21:51:32.717287001
-0400
+@@ -198,6 +198,26 @@ void PseudoTcpChannel::OnSessionTerminat
+ if (stream_ != NULL)
+ stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, -1));
+ }
++
++ // Even though session_ is being destroyed, we mustn't clear the pointer,
++ // since we'll need it to tear down channel_.
++ //
++ // TODO(wez): Is it always the case that if channel_ != NULL then we'll get
++ // a channel-destroyed notification?
++}
++
++void PseudoTcpChannel::GetOption(PseudoTcp::Option opt, int* value) {
++ ASSERT(signal_thread_->IsCurrent());
++ CritScope lock(&cs_);
++ ASSERT(tcp_ != NULL);
++ tcp_->GetOption(opt, value);
++}
++
++void PseudoTcpChannel::SetOption(PseudoTcp::Option opt, int value) {
++ ASSERT(signal_thread_->IsCurrent());
++ CritScope lock(&cs_);
++ ASSERT(tcp_ != NULL);
++ tcp_->SetOption(opt, value);
+ }
+
+ //
+diff -upN libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.h.chromium12
libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.h
+--- libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.h 2011-03-30 21:51:32.717287001
-0400
+@@ -43,18 +43,22 @@ namespace cricket {
+ class TransportChannel;
+
+ ///////////////////////////////////////////////////////////////////////////////
+-// ChannelStream
+-// Note: The lifetime of TunnelSession is complicated. It needs to survive
+-// until the following three conditions are true:
+-// 1) TunnelStream has called Close (tracked via non-null stream_)
+-// 2) PseudoTcp has completed (tracked via non-null tcp_)
+-// 3) Session has been destroyed (tracked via non-null session_)
+-// This is accomplished by calling CheckDestroy after these indicators change.
++// PseudoTcpChannel
++// Note: The PseudoTcpChannel must persist until both of:
++// 1) The StreamInterface provided via GetStream has been closed.
++// This is tracked via non-null stream_.
++// 2) The PseudoTcp session has completed.
++// This is tracked via non-null worker_thread_. When PseudoTcp is done,
++// the TransportChannel is signalled to tear-down. Once the channel is
++// torn down, the worker thread is purged.
++// These indicators are checked by CheckDestroy, invoked whenever one of them
++// changes.
+ ///////////////////////////////////////////////////////////////////////////////
+-// TunnelStream
+-// Note: Because TunnelStream provides a stream interface, it's lifetime is
+-// controlled by the owner of the stream pointer. As a result, we must support
+-// both the TunnelSession disappearing before TunnelStream, and vice versa.
++// PseudoTcpChannel::GetStream
++// Note: The stream pointer returned by GetStream is owned by the caller.
++// They can close & immediately delete the stream while PseudoTcpChannel still
++// has cleanup work to do. They can also close the stream but not delete it
++// until long after PseudoTcpChannel has finished. We must cope with both.
+ ///////////////////////////////////////////////////////////////////////////////
+
+ class PseudoTcpChannel
+@@ -72,8 +76,14 @@ public:
+
+ sigslot::signal1<PseudoTcpChannel*> SignalChannelClosed;
+
++ // Call this when the Session used to create this channel is being torn
++ // down, to ensure that things get cleaned up properly.
+ void OnSessionTerminate(Session* session);
+
++ // See the PseudoTcp class for available options.
++ void GetOption(PseudoTcp::Option opt, int* value);
++ void SetOption(PseudoTcp::Option opt, int value);
++
+ private:
+ class InternalStream;
+ friend class InternalStream;
+diff -upN libjingle-0.5.2/talk/site_scons/talk.py.chromium12
libjingle-0.5.2/talk/site_scons/talk.py
+--- libjingle-0.5.2/talk/site_scons/talk.py.chromium12 2011-01-11 19:25:51.000000000
-0500
++++ libjingle-0.5.2/talk/site_scons/talk.py 2011-03-30 21:51:32.717287001 -0400
+@@ -211,7 +211,7 @@ def AddMediaLibs(env, **kwargs):
+ elif env.Bit('mac'):
+ gips_lib = 'VoiceEngine_mac_universal_gcc'
+ elif env.Bit('linux'):
+- gips_lib = 'VoiceEngine_Linux_external_gcc'
++ gips_lib = 'VoiceEngine_Linux_gcc'
+
+
+ AddToDict(kwargs, 'libs', [
+--- libjingle-0.5.2/talk/session/phone/devicemanager.h.chromium12 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/devicemanager.h 2011-03-30 23:57:46.524287064
-0400
+@@ -59,11 +59,7 @@
+ // Methods are virtual to allow for easy stubbing/mocking in tests.
+ class DeviceManager {
+ public:
+- DeviceManager(
+-#ifdef USE_TALK_SOUND
+- SoundSystemFactory *factory
+-#endif
+- );
++ DeviceManager();
+ virtual ~DeviceManager();
+
+ // Initialization
+@@ -82,7 +78,7 @@
+ bool GetAudioOutputDevice(const std::string& name, Device* out);
+
+ virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
+- virtual bool GetDefaultVideoCaptureDevice(Device* device);
++ bool GetVideoCaptureDevice(const std::string& name, Device* out);
+
+ sigslot::signal0<> SignalDevicesChange;
+
+@@ -93,10 +89,15 @@
+ protected:
+ virtual bool GetAudioDevice(bool is_input, const std::string& name,
+ Device* out);
++ virtual bool GetDefaultVideoCaptureDevice(Device* device);
++
+ private:
+ bool GetAudioDevicesByPlatform(bool input, std::vector<Device>* devs);
+
+ bool initialized_;
++#ifdef WIN32
++ bool need_couninitialize_;
++#endif
+ DeviceWatcher* watcher_;
+ #ifdef USE_TALK_SOUND
+ SoundSystemHandle sound_system_;
+--- libjingle-0.5.2/talk/session/phone/devicemanager.cc.chromium12 2011-03-30
23:58:32.819287002 -0400
++++ libjingle-0.5.2/talk/session/phone/devicemanager.cc 2011-03-31 00:03:00.810286990
-0400
+@@ -53,17 +53,18 @@
+ #include "talk/base/stream.h"
+ #include "talk/session/phone/libudevsymboltable.h"
+ #include "talk/session/phone/v4llookup.h"
++#if USE_TALK_SOUND
++#include "talk/sound/platformsoundsystem.h"
++#include "talk/sound/platformsoundsystemfactory.h"
++#include "talk/sound/sounddevicelocator.h"
++#include "talk/sound/soundsysteminterface.h"
++#endif
+ #endif
+
+ #include "talk/session/phone/devicemanager.h"
+ #include "talk/base/logging.h"
+ #include "talk/base/stringutils.h"
+ #include "talk/session/phone/mediaengine.h"
+-#if USE_TALK_SOUND
+-#include "talk/sound/platformsoundsystem.h"
+-#include "talk/sound/sounddevicelocator.h"
+-#include "talk/sound/soundsysteminterface.h"
+-#endif
+
+ namespace cricket {
+ // Initialize to empty string.
+@@ -116,9 +117,17 @@
+ DeviceManager* manager_;
+ void* impl_;
+ };
++#elif defined(IOS) || defined(ANDROID)
++// We don't use DeviceWatcher on iOS or Android, so just stub out a noop class.
++class DeviceWatcher {
++ public:
++ explicit DeviceWatcher(DeviceManager* dm) {}
++ bool Start() { return true; }
++ void Stop() {}
++};
+ #endif
+
+-#ifndef LINUX
++#if !defined(LINUX) && !defined(IOS)
+ static bool ShouldDeviceBeIgnored(const std::string& device_name);
+ #endif
+ #ifndef OSX
+@@ -142,15 +151,14 @@
+ static bool GetAudioDeviceName(AudioDeviceID id, bool input, std::string* out);
+ #endif
+
+-DeviceManager::DeviceManager(
+-#ifdef USE_TALK_SOUND
+- SoundSystemFactory *factory
+-#endif
+- )
++DeviceManager::DeviceManager()
+ : initialized_(false),
++#if defined(WIN32)
++ need_couninitialize_(false),
++#endif
+ watcher_(new DeviceWatcher(this))
+ #ifdef USE_TALK_SOUND
+- , sound_system_(factory)
++ , sound_system_(new PlatformSoundSystemFactory())
+ #endif
+ {
+ }
+@@ -164,6 +172,16 @@
+
+ bool DeviceManager::Init() {
+ if (!initialized_) {
++#if defined(WIN32)
++ HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
++ need_couninitialize_ = SUCCEEDED(hr);
++ if (FAILED(hr)) {
++ LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
++ if (hr != RPC_E_CHANGED_MODE) {
++ return false;
++ }
++ }
++#endif
+ if (!watcher_->Start()) {
+ return false;
+ }
+@@ -175,6 +193,12 @@
+ void DeviceManager::Terminate() {
+ if (initialized_) {
+ watcher_->Stop();
++#if defined(WIN32)
++ if (need_couninitialize_) {
++ CoUninitialize();
++ need_couninitialize_ = false;
++ }
++#endif
+ initialized_ = false;
+ }
+ }
+@@ -259,6 +283,28 @@
+ return ret;
+ }
+
++bool DeviceManager::GetVideoCaptureDevice(const std::string& name,
++ Device* out) {
++ // If the name is empty, return the default device.
++ if (name.empty() || name == kDefaultDeviceName) {
++ return GetDefaultVideoCaptureDevice(out);
++ }
++
++ std::vector<Device> devices;
++ if (!GetVideoCaptureDevices(&devices)) {
++ return false;
++ }
++
++ for (std::vector<Device>::const_iterator it = devices.begin();
++ it != devices.end(); ++it) {
++ if (name == it->name) {
++ *out = *it;
++ return true;
++ }
++ }
++
++ return false;
++}
+
+ bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name,
+ Device* out) {
+@@ -287,6 +333,7 @@
+ bool DeviceManager::GetAudioDevicesByPlatform(bool input,
+ std::vector<Device>* devs) {
+ devs->clear();
++
+ #if defined(USE_TALK_SOUND)
+ if (!sound_system_.get()) {
+ return false;
+@@ -332,7 +379,6 @@
+ }
+ }
+ return ret;
+-
+ #elif defined(LINUX)
+ int card = -1, dev = -1;
+ snd_ctl_t *handle = NULL;
+@@ -385,20 +431,7 @@
+
+ #if defined(WIN32)
+ bool GetVideoDevices(std::vector<Device>* devices) {
+- // TODO: Move the CoInit stuff to Initialize/Terminate.
+- HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+- if (FAILED(hr)) {
+- LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
+- if (hr != RPC_E_CHANGED_MODE) {
+- return false;
+- }
+- }
+-
+- bool ret = GetDevices(CLSID_VideoInputDeviceCategory, devices);
+- if (SUCCEEDED(hr)) {
+- CoUninitialize();
+- }
+- return ret;
++ return GetDevices(CLSID_VideoInputDeviceCategory, devices);
+ }
+
+ bool GetDevices(const CLSID& catid, std::vector<Device>* devices) {
+@@ -977,7 +1010,7 @@
+
+ // TODO: Try to get hold of a copy of Final Cut to understand why we
+ // crash while scanning their components on OS X.
+-#ifndef LINUX
++#if !defined(LINUX) && !defined(IOS)
+ static bool ShouldDeviceBeIgnored(const std::string& device_name) {
+ static const char* const kFilteredDevices[] = {
+ "Google Camera Adapter", // Our own magiccams
diff --git a/libjingle-0.5.2-compilefix.patch b/libjingle-0.5.2-compilefix.patch
new file mode 100644
index 0000000..2e17641
--- /dev/null
+++ b/libjingle-0.5.2-compilefix.patch
@@ -0,0 +1,13 @@
+diff -upN libjingle-0.5.2/talk/base/ratetracker.cc.compilefix
libjingle-0.5.2/talk/base/ratetracker.cc
+--- libjingle-0.5.2/talk/base/ratetracker.cc.compilefix 2011-01-11 19:25:49.000000000
-0500
++++ libjingle-0.5.2/talk/base/ratetracker.cc 2011-03-30 23:53:08.288286757 -0400
+@@ -25,8 +25,8 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+-#include "talk/base/ratetracker.h"
+ #include "talk/base/time.h"
++#include "talk/base/ratetracker.h"
+
+ namespace talk_base {
+
diff --git a/libjingle-0.5.2-devicemanager-alsafix.patch
b/libjingle-0.5.2-devicemanager-alsafix.patch
new file mode 100644
index 0000000..a7f271b
--- /dev/null
+++ b/libjingle-0.5.2-devicemanager-alsafix.patch
@@ -0,0 +1,30 @@
+diff -up libjingle-0.5.2/talk/session/phone/devicemanager.cc.alsa
libjingle-0.5.2/talk/session/phone/devicemanager.cc
+--- libjingle-0.5.2/talk/session/phone/devicemanager.cc.alsa 2011-01-11
19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/devicemanager.cc 2011-03-30 19:49:54.989287610
-0400
+@@ -25,7 +25,7 @@
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+-#include "talk/session/phone/devicemanager.h"
++#include "config.h"
+
+ #if WIN32
+ #include <atlbase.h>
+@@ -45,9 +45,7 @@
+ #elif LINUX
+ #include <libudev.h>
+ #include <unistd.h>
+-#ifndef USE_TALK_SOUND
+ #include <alsa/asoundlib.h>
+-#endif
+ #include "talk/base/linux.h"
+ #include "talk/base/fileutils.h"
+ #include "talk/base/pathutils.h"
+@@ -57,6 +55,7 @@
+ #include "talk/session/phone/v4llookup.h"
+ #endif
+
++#include "talk/session/phone/devicemanager.h"
+ #include "talk/base/logging.h"
+ #include "talk/base/stringutils.h"
+ #include "talk/session/phone/mediaengine.h"
diff --git a/libjingle.spec b/libjingle.spec
index 3d4ee5d..643d716 100644
--- a/libjingle.spec
+++ b/libjingle.spec
@@ -1,6 +1,6 @@
Name: libjingle
-Version: 0.5.1
-Release: 5%{?dist}
+Version: 0.5.2
+Release: 1%{?dist}
Summary: GoogleTalk implementation of Jingle
Group: System Environment/Libraries
License: BSD
@@ -34,7 +34,7 @@ Patch6: libjingle-0.5.1-unixfilesystemfix.patch
Patch7: libjingle-0.5.1-system-expat.patch
Patch8: libjingle-0.5.1-system-srtp.patch
# Fix devicemanager.cc to compile, alsa as linux default
-Patch9: libjingle-0.5.1-devicemanager-alsafix.patch
+Patch9: libjingle-0.5.2-devicemanager-alsafix.patch
# Fix v4llookup.cc to compile
Patch10: libjingle-0.5.1-v4llookup-fix.patch
# Fix type and definition conflicts with Chromium
@@ -45,6 +45,10 @@ Patch12: libjingle-0.5.1-64bittypes.patch
Patch13: libjingle-0.5.1-qname-threadsafe.patch
# Make sure linux.h/linux.cc pulls in config.h for LINUX define
Patch14: libjingle-0.5.1-config-linux.patch
+# Chromium 12 forks libjingle. Again. :P
+Patch15: libjingle-0.5.2-chromium12-changes.patch
+# Fix 0.5.2 compilation
+Patch16: libjingle-0.5.2-compilefix.patch
BuildRequires: libtool, autoconf, automake
BuildRequires: openssl-devel
@@ -94,6 +98,8 @@ developing applications that use %{name}.
%patch12 -p1 -b .64bit
%patch13 -p1 -b .threadsafe
%patch14 -p1 -b .config
+%patch15 -p1 -b .chromium12
+%patch16 -p1 -b .compilefix
touch NEWS ChangeLog
autoreconf -i
@@ -138,6 +144,10 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Wed Mar 30 2011 Tom Callaway <spot(a)fedoraproject.org> - 0.5.2-1
+- update to 0.5.2
+- merge Google's unpublished Chromium 12 changes
+
* Tue Feb 08 2011 Fedora Release Engineering <rel-eng(a)lists.fedoraproject.org> -
0.5.1-5
- Rebuilt for
https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
diff --git a/sources b/sources
index e3e55b0..d908674 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-a59bac5b6111afc79efd3d1e821c13d8 libjingle-0.5.1.zip
+b5b7e91adb38aa2d79920ad27cec7759 libjingle-0.5.2.zip