summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2011-06-09 11:47:42 +0100
committerKristian Monsen <kristianm@google.com>2011-06-29 14:33:03 +0100
commitdc0f95d653279beabeb9817299e2902918ba123e (patch)
tree32eb121cd532053a5b9cb0c390331349af8d6baa /third_party
parentba160cd4054d13d0cb0b1b46e61c3bed67095811 (diff)
downloadexternal_chromium-dc0f95d653279beabeb9817299e2902918ba123e.zip
external_chromium-dc0f95d653279beabeb9817299e2902918ba123e.tar.gz
external_chromium-dc0f95d653279beabeb9817299e2902918ba123e.tar.bz2
Merge Chromium at r11.0.696.0: Initial merge by git
Change-Id: I273dde2843af0839dfc08b419bb443fbd449532d
Diffstat (limited to 'third_party')
-rw-r--r--third_party/libjingle/libjingle.gyp9
-rw-r--r--third_party/libjingle/overrides/talk/base/basictypes.h12
-rw-r--r--third_party/libjingle/source/CHANGELOG8
-rw-r--r--third_party/libjingle/source/README2
-rw-r--r--third_party/libjingle/source/talk/base/asyncpacketsocket.cc92
-rw-r--r--third_party/libjingle/source/talk/base/asyncpacketsocket.h75
-rw-r--r--third_party/libjingle/source/talk/base/asynctcpsocket.cc114
-rw-r--r--third_party/libjingle/source/talk/base/asynctcpsocket.h23
-rw-r--r--third_party/libjingle/source/talk/base/asyncudpsocket.cc65
-rw-r--r--third_party/libjingle/source/talk/base/asyncudpsocket.h25
-rw-r--r--third_party/libjingle/source/talk/base/basictypes.h8
-rw-r--r--third_party/libjingle/source/talk/base/linux.cc75
-rw-r--r--third_party/libjingle/source/talk/base/linux.h33
-rw-r--r--third_party/libjingle/source/talk/base/logging.cc34
-rw-r--r--third_party/libjingle/source/talk/base/nethelpers.cc55
-rw-r--r--third_party/libjingle/source/talk/base/physicalsocketserver.cc466
-rw-r--r--third_party/libjingle/source/talk/base/physicalsocketserver.h39
-rw-r--r--third_party/libjingle/source/talk/base/socket.h62
-rw-r--r--third_party/libjingle/source/talk/base/socketpool.cc20
-rw-r--r--third_party/libjingle/source/talk/base/socketpool.h8
-rw-r--r--third_party/libjingle/source/talk/base/stream.cc28
-rw-r--r--third_party/libjingle/source/talk/base/stream.h3
-rw-r--r--third_party/libjingle/source/talk/base/stringencode.cc62
-rw-r--r--third_party/libjingle/source/talk/base/stringencode.h29
-rw-r--r--third_party/libjingle/source/talk/base/stringutils.cc31
-rw-r--r--third_party/libjingle/source/talk/base/stringutils.h3
-rw-r--r--third_party/libjingle/source/talk/examples/call/call_main.cc20
-rw-r--r--third_party/libjingle/source/talk/examples/call/callclient.cc80
-rw-r--r--third_party/libjingle/source/talk/examples/call/callclient.h16
-rw-r--r--third_party/libjingle/source/talk/libjingle.scons7
-rw-r--r--third_party/libjingle/source/talk/main.scons46
-rw-r--r--third_party/libjingle/source/talk/p2p/base/common.h9
-rw-r--r--third_party/libjingle/source/talk/p2p/base/constants.cc32
-rw-r--r--third_party/libjingle/source/talk/p2p/base/constants.h28
-rw-r--r--third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc13
-rw-r--r--third_party/libjingle/source/talk/p2p/base/port.cc406
-rw-r--r--third_party/libjingle/source/talk/p2p/base/port.h131
-rw-r--r--third_party/libjingle/source/talk/p2p/base/portallocator.h53
-rw-r--r--third_party/libjingle/source/talk/p2p/base/pseudotcp.cc42
-rw-r--r--third_party/libjingle/source/talk/p2p/base/pseudotcp.h16
-rw-r--r--third_party/libjingle/source/talk/p2p/base/relayport.cc97
-rw-r--r--third_party/libjingle/source/talk/p2p/base/relayport.h25
-rw-r--r--third_party/libjingle/source/talk/p2p/base/relayserver.cc47
-rw-r--r--third_party/libjingle/source/talk/p2p/base/relayserver.h70
-rw-r--r--third_party/libjingle/source/talk/p2p/base/relayserver_main.cc16
-rw-r--r--third_party/libjingle/source/talk/p2p/base/session.cc59
-rw-r--r--third_party/libjingle/source/talk/p2p/base/session.h19
-rw-r--r--third_party/libjingle/source/talk/p2p/base/sessionmessages.cc123
-rw-r--r--third_party/libjingle/source/talk/p2p/base/sessionmessages.h52
-rw-r--r--third_party/libjingle/source/talk/p2p/base/stunport.cc41
-rw-r--r--third_party/libjingle/source/talk/p2p/base/stunport.h32
-rw-r--r--third_party/libjingle/source/talk/p2p/base/stunserver.cc11
-rw-r--r--third_party/libjingle/source/talk/p2p/base/stunserver.h4
-rw-r--r--third_party/libjingle/source/talk/p2p/base/stunserver_main.cc6
-rw-r--r--third_party/libjingle/source/talk/p2p/base/tcpport.cc138
-rw-r--r--third_party/libjingle/source/talk/p2p/base/tcpport.h57
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transport.cc21
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc7
-rw-r--r--third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h1
-rw-r--r--third_party/libjingle/source/talk/p2p/base/udpport.cc41
-rw-r--r--third_party/libjingle/source/talk/p2p/base/udpport.h26
-rw-r--r--third_party/libjingle/source/talk/p2p/client/basicportallocator.cc40
-rw-r--r--third_party/libjingle/source/talk/p2p/client/basicportallocator.h7
-rw-r--r--third_party/libjingle/source/talk/p2p/client/httpportallocator.cc8
-rw-r--r--third_party/libjingle/source/talk/p2p/client/httpportallocator.h1
-rw-r--r--third_party/libjingle/source/talk/session/phone/channel.cc386
-rw-r--r--third_party/libjingle/source/talk/session/phone/channel.h55
-rw-r--r--third_party/libjingle/source/talk/session/phone/channelmanager.cc125
-rw-r--r--third_party/libjingle/source/talk/session/phone/channelmanager.h10
-rw-r--r--third_party/libjingle/source/talk/session/phone/cryptoparams.h2
-rw-r--r--third_party/libjingle/source/talk/session/phone/devicemanager.cc380
-rw-r--r--third_party/libjingle/source/talk/session/phone/devicemanager.h20
-rw-r--r--third_party/libjingle/source/talk/session/phone/devicemanager_mac.mm45
-rw-r--r--third_party/libjingle/source/talk/session/phone/filemediaengine.cc60
-rw-r--r--third_party/libjingle/source/talk/session/phone/filemediaengine.h8
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediachannel.h145
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediaengine.cc6
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediaengine.h53
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediamonitor.h6
-rw-r--r--third_party/libjingle/source/talk/session/phone/mediasessionclient.cc2
-rw-r--r--third_party/libjingle/source/talk/session/phone/rtpdump.cc65
-rw-r--r--third_party/libjingle/source/talk/session/phone/rtpdump.h18
-rw-r--r--third_party/libjingle/source/talk/session/phone/srtpfilter.cc86
-rw-r--r--third_party/libjingle/source/talk/session/phone/testdata/video.rtpdumpbin134998 -> 134998 bytes
-rw-r--r--third_party/libjingle/source/talk/session/phone/testdata/voice.rtpdumpbin78339 -> 78339 bytes
-rw-r--r--third_party/libjingle/source/talk/session/phone/videocommon.h21
-rw-r--r--third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc20
-rw-r--r--third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.h32
-rw-r--r--third_party/libjingle/source/talk/site_scons/talk.py73
-rw-r--r--third_party/modp_b64/LICENSE.html296
-rw-r--r--third_party/modp_b64/README.chromium7
-rw-r--r--third_party/modp_b64/modp_b64.gyp2
92 files changed, 3026 insertions, 2126 deletions
diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp
index 16b9d11..18b235f 100644
--- a/third_party/libjingle/libjingle.gyp
+++ b/third_party/libjingle/libjingle.gyp
@@ -1,4 +1,4 @@
-# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -155,7 +155,6 @@
'source/talk/base/asyncfile.h',
'source/talk/base/asynchttprequest.cc',
'source/talk/base/asynchttprequest.h',
- 'source/talk/base/asyncpacketsocket.cc',
'source/talk/base/asyncpacketsocket.h',
'source/talk/base/asyncsocket.cc',
'source/talk/base/asyncsocket.h',
@@ -168,6 +167,8 @@
'source/talk/base/base64.cc',
'source/talk/base/base64.h',
'source/talk/base/basicdefs.h',
+ 'source/talk/base/basicpacketsocketfactory.cc',
+ 'source/talk/base/basicpacketsocketfactory.h',
'source/talk/base/bytebuffer.cc',
'source/talk/base/bytebuffer.h',
'source/talk/base/byteorder.h',
@@ -183,7 +184,6 @@
'source/talk/base/event.h',
'source/talk/base/fileutils.cc',
'source/talk/base/fileutils.h',
- 'source/talk/base/fileutils_mock.h',
'source/talk/base/firewallsocketserver.cc',
'source/talk/base/firewallsocketserver.h',
'source/talk/base/flags.cc',
@@ -201,7 +201,6 @@
'source/talk/base/httpcommon.h',
'source/talk/base/httprequest.cc',
'source/talk/base/httprequest.h',
- 'source/talk/base/icftypes.h',
'source/talk/base/linked_ptr.h',
'source/talk/base/logging.cc',
'source/talk/base/md5.h',
@@ -222,6 +221,8 @@
'source/talk/base/proxydetect.h',
'source/talk/base/proxyinfo.cc',
'source/talk/base/proxyinfo.h',
+ 'source/talk/base/ratetracker.cc',
+ 'source/talk/base/ratetracker.h',
'source/talk/base/sec_buffer.h',
'source/talk/base/signalthread.cc',
'source/talk/base/signalthread.h',
diff --git a/third_party/libjingle/overrides/talk/base/basictypes.h b/third_party/libjingle/overrides/talk/base/basictypes.h
index d6f90cf..4ea193e 100644
--- a/third_party/libjingle/overrides/talk/base/basictypes.h
+++ b/third_party/libjingle/overrides/talk/base/basictypes.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -50,4 +50,14 @@ template<class T> inline T _max(T a, T b) { return (a < b) ? b : a; }
const int kForever = -1;
}
+#ifdef WIN32
+#define alignof(t) __alignof(t)
+#else // !WIN32
+#define alignof(t) __alignof__(t)
+#endif // !WIN32
+#define IS_ALIGNED(p, a) (0==(reinterpret_cast<uintptr_t>(p) & ((a)-1)))
+#define ALIGNP(p, t) \
+ (reinterpret_cast<uint8*>(((reinterpret_cast<uintptr_t>(p) + \
+ ((t)-1)) & ~((t)-1))))
+
#endif // OVERRIDES_TALK_BASE_BASICTYPES_H__
diff --git a/third_party/libjingle/source/CHANGELOG b/third_party/libjingle/source/CHANGELOG
index d1574d8..e0c746e 100644
--- a/third_party/libjingle/source/CHANGELOG
+++ b/third_party/libjingle/source/CHANGELOG
@@ -1,5 +1,13 @@
Libjingle
+0.5.2 - Jan 11, 2010
+ - Fixed build on Windows 7 with VS 2010
+ - Fixed build on Windows x64
+ - Fixed build on Mac OSX
+ - Added option to examples/call to enable encryption
+ - Improved logging
+ - Bug fixes
+
0.5.1 - Nov 2, 2010
- Added support for call encryption.
- Added addtional XEP-166 and XEP-167 features:
diff --git a/third_party/libjingle/source/README b/third_party/libjingle/source/README
index b127b56..f70b726 100644
--- a/third_party/libjingle/source/README
+++ b/third_party/libjingle/source/README
@@ -30,6 +30,8 @@ illustrate the basic concepts of how the provided classes work.
Libjingle is built with swtoolkit (http://code.google.com/p/swtoolkit/), which
is a set of extensions to the open-source SCons build tool (www.scons.org).
* First, install Python 2.4 or later from http://www.python.org/.
+ Please note that since swtoolkit only works with Python 2.x, you will
+ not be able to use Python 3.x.
* Second, install the stand alone scons-local package 2.0.0 or later from
http://www.scons.org/download.php and set an environment variable,
diff --git a/third_party/libjingle/source/talk/base/asyncpacketsocket.cc b/third_party/libjingle/source/talk/base/asyncpacketsocket.cc
deleted file mode 100644
index 7628c12..0000000
--- a/third_party/libjingle/source/talk/base/asyncpacketsocket.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * libjingle
- * Copyright 2004--2005, Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#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 --git a/third_party/libjingle/source/talk/base/asyncpacketsocket.h b/third_party/libjingle/source/talk/base/asyncpacketsocket.h
index 9cb82ec..47a1bf3 100644
--- a/third_party/libjingle/source/talk/base/asyncpacketsocket.h
+++ b/third_party/libjingle/source/talk/base/asyncpacketsocket.h
@@ -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();
-
- // 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;
-
- protected:
- AsyncSocket* socket_;
+ AsyncPacketSocket() { }
+ virtual ~AsyncPacketSocket() { }
+
+ // 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;
+
+ // 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 --git a/third_party/libjingle/source/talk/base/asynctcpsocket.cc b/third_party/libjingle/source/talk/base/asynctcpsocket.cc
index 37c7a6c..03fc01a 100644
--- a/third_party/libjingle/source/talk/base/asynctcpsocket.cc
+++ b/third_party/libjingle/source/talk/base/asynctcpsocket.cc
@@ -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(AsyncSocket* socket)
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 *pv, size_t cb,
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 * data, size_t& len) {
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(AsyncSocket* socket) {
}
void AsyncTCPSocket::OnReadEvent(AsyncSocket* socket) {
- ASSERT(socket == socket_);
+ ASSERT(socket_.get() == socket);
+
+ 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;
+ }
+
+ SignalNewConnection(this, new AsyncTCPSocket(new_socket, false));
- 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";
+ // 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;
}
- return;
- }
- inpos_ += len;
+ inpos_ += len;
- ProcessInput(inbuf_, inpos_);
+ ProcessInput(inbuf_, inpos_);
- if (inpos_ >= insize_) {
- LOG(INFO) << "input buffer overflow";
- ASSERT(false);
- inpos_ = 0;
+ 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 --git a/third_party/libjingle/source/talk/base/asynctcpsocket.h b/third_party/libjingle/source/talk/base/asynctcpsocket.h
index 8f24861..06bbbf4 100644
--- a/third_party/libjingle/source/talk/base/asynctcpsocket.h
+++ b/third_party/libjingle/source/talk/base/asynctcpsocket.h
@@ -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);
+ 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();
- sigslot::signal1<AsyncTCPSocket*> SignalConnect;
- sigslot::signal2<AsyncTCPSocket*, int> SignalClose;
+ 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 AsyncPacketSocket {
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 --git a/third_party/libjingle/source/talk/base/asyncudpsocket.cc b/third_party/libjingle/source/talk/base/asyncudpsocket.cc
index 2899606..dd2dc64 100644
--- a/third_party/libjingle/source/talk/base/asyncudpsocket.cc
+++ b/third_party/libjingle/source/talk/base/asyncudpsocket.cc
@@ -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(AsyncSocket* socket) {
// 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 --git a/third_party/libjingle/source/talk/base/asyncudpsocket.h b/third_party/libjingle/source/talk/base/asyncudpsocket.h
index 3a6960c..e3012a5 100644
--- a/third_party/libjingle/source/talk/base/asyncudpsocket.h
+++ b/third_party/libjingle/source/talk/base/asyncudpsocket.h
@@ -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 AsyncPacketSocket {
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 --git a/third_party/libjingle/source/talk/base/basictypes.h b/third_party/libjingle/source/talk/base/basictypes.h
index 781d428..a26a3ff 100644
--- a/third_party/libjingle/source/talk/base/basictypes.h
+++ b/third_party/libjingle/source/talk/base/basictypes.h
@@ -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:
@@ -88,6 +88,12 @@ namespace talk_base {
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 --git a/third_party/libjingle/source/talk/base/linux.cc b/third_party/libjingle/source/talk/base/linux.cc
index 03d486b..5ae103e 100644
--- a/third_party/libjingle/source/talk/base/linux.cc
+++ b/third_party/libjingle/source/talk/base/linux.cc
@@ -1,6 +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.
+ */
#ifdef LINUX
#include "talk/base/linux.h"
@@ -26,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;
}
@@ -68,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;
}
@@ -102,20 +151,24 @@ bool ConfigParser::ParseLine(std::string *key, std::string *value) {
// 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 --git a/third_party/libjingle/source/talk/base/linux.h b/third_party/libjingle/source/talk/base/linux.h
index 37b845b..e56eb95 100644
--- a/third_party/libjingle/source/talk/base/linux.h
+++ b/third_party/libjingle/source/talk/base/linux.h
@@ -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_
@@ -68,9 +92,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 --git a/third_party/libjingle/source/talk/base/logging.cc b/third_party/libjingle/source/talk/base/logging.cc
index d632a2c..3515312 100644
--- a/third_party/libjingle/source/talk/base/logging.cc
+++ b/third_party/libjingle/source/talk/base/logging.cc
@@ -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 char* params, const char* filename) {
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::string& str,
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::string& str,
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 --git a/third_party/libjingle/source/talk/base/nethelpers.cc b/third_party/libjingle/source/talk/base/nethelpers.cc
index 5740dc3..b877d78 100644
--- a/third_party/libjingle/source/talk/base/nethelpers.cc
+++ b/third_party/libjingle/source/talk/base/nethelpers.cc
@@ -32,6 +32,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 +60,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 +89,9 @@ hostent* SafeGetHostByName(const char* hostname, int* herrno) {
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 +121,37 @@ hostent* SafeGetHostByName(const char* hostname, int* herrno) {
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 +163,10 @@ hostent* SafeGetHostByName(const char* hostname, int* herrno) {
// 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 --git a/third_party/libjingle/source/talk/base/physicalsocketserver.cc b/third_party/libjingle/source/talk/base/physicalsocketserver.cc
index d97cba7..9cb5f4f 100644
--- a/third_party/libjingle/source/talk/base/physicalsocketserver.cc
+++ b/third_party/libjingle/source/talk/base/physicalsocketserver.cc
@@ -78,12 +78,6 @@ typedef char* SockOptArg;
namespace talk_base {
-const int kfRead = 0x0001;
-const int kfWrite = 0x0002;
-const int kfConnect = 0x0004;
-const int kfClose = 0x0008;
-const int kfAccept = 0x0010;
-
// Standard MTUs, from RFC 1191
const uint16 PACKET_MAXIMUMS[] = {
65535, // Theoretical maximum, Hyperchannel
@@ -125,7 +119,7 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
EnsureWinsockInit();
#endif
if (s_ != INVALID_SOCKET) {
- enabled_events_ = kfRead | kfWrite;
+ enabled_events_ = DE_READ | DE_WRITE;
int type = SOCK_STREAM;
socklen_t len = sizeof(type);
@@ -145,7 +139,7 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
udp_ = (SOCK_DGRAM == type);
UpdateLastError();
if (udp_)
- enabled_events_ = kfRead | kfWrite;
+ enabled_events_ = DE_READ | DE_WRITE;
return s_ != INVALID_SOCKET;
}
@@ -221,17 +215,16 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
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_)) {
state_ = CS_CONNECTING;
- enabled_events_ |= kfConnect;
+ enabled_events_ |= DE_CONNECT;
} else {
return SOCKET_ERROR;
}
- enabled_events_ |= kfRead | kfWrite;
+ enabled_events_ |= DE_READ | DE_WRITE;
return 0;
}
@@ -289,10 +282,10 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
#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_ |= kfWrite;
+ enabled_events_ |= DE_WRITE;
}
return sent;
}
@@ -310,11 +303,11 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
#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_ |= kfWrite;
+ enabled_events_ |= DE_WRITE;
}
- //LOG_F(LS_INFO) << cb << ":" << addr.ToString() << ":" << sent << ":" << error_;
return sent;
}
@@ -327,14 +320,14 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
LOG(LS_WARNING) << "EOF from socket; deferring close event";
// Must turn this back on so that the select() loop will notice the close
// event.
- enabled_events_ |= kfRead;
+ enabled_events_ |= DE_READ;
error_ = EWOULDBLOCK;
return SOCKET_ERROR;
}
UpdateLastError();
bool success = (received >= 0) || IsBlockingError(error_);
if (udp_ || success) {
- enabled_events_ |= kfRead;
+ enabled_events_ |= DE_READ;
}
if (!success) {
LOG_F(LS_VERBOSE) << "Error = " << error_;
@@ -352,7 +345,7 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
paddr->FromSockAddr(saddr);
bool success = (received >= 0) || IsBlockingError(error_);
if (udp_ || success) {
- enabled_events_ |= kfRead;
+ enabled_events_ |= DE_READ;
}
if (!success) {
LOG_F(LS_VERBOSE) << "Error = " << error_;
@@ -365,7 +358,7 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
UpdateLastError();
if (err == 0) {
state_ = CS_CONNECTING;
- enabled_events_ |= kfAccept;
+ enabled_events_ |= DE_ACCEPT;
#ifdef _DEBUG
dbg_addr_ = "Listening @ ";
dbg_addr_.append(GetLocalAddress().ToString());
@@ -381,7 +374,7 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
UpdateLastError();
if (s == INVALID_SOCKET)
return NULL;
- enabled_events_ |= kfAccept;
+ enabled_events_ |= DE_ACCEPT;
if (paddr != NULL)
paddr->FromSockAddr(saddr);
return ss_->WrapSocket(s);
@@ -392,7 +385,6 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
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;
@@ -432,14 +424,14 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
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);
@@ -487,7 +479,7 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
*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)
@@ -528,16 +520,6 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
};
#ifdef POSIX
-class Dispatcher {
- public:
- virtual ~Dispatcher() { }
- virtual uint32 GetRequestedEvents() = 0;
- virtual void OnPreEvent(uint32 ff) = 0;
- virtual void OnEvent(uint32 ff, int err) = 0;
- virtual int GetDescriptor() = 0;
- virtual bool IsDescriptorClosed() = 0;
-};
-
class EventDispatcher : public Dispatcher {
public:
EventDispatcher(PhysicalSocketServer* ss) : ss_(ss), fSignaled_(false) {
@@ -563,7 +545,7 @@ class EventDispatcher : public Dispatcher {
}
virtual uint32 GetRequestedEvents() {
- return kfRead;
+ return DE_READ;
}
virtual void OnPreEvent(uint32 ff) {
@@ -597,71 +579,43 @@ class EventDispatcher : public Dispatcher {
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 kfRead;
- }
+ 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
@@ -673,7 +627,7 @@ class PosixSignalDeliveryDispatcher : public Dispatcher {
}
// 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
@@ -685,49 +639,8 @@ class PosixSignalDeliveryDispatcher : public Dispatcher {
}
}
- // 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;
@@ -743,8 +656,30 @@ class PosixSignalDeliveryDispatcher : public Dispatcher {
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
@@ -756,14 +691,83 @@ class PosixSignalDeliveryDispatcher : public Dispatcher {
// 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) {
@@ -833,30 +837,30 @@ class SocketDispatcher : public Dispatcher, public PhysicalSocket {
}
virtual void OnPreEvent(uint32 ff) {
- if ((ff & kfConnect) != 0)
+ if ((ff & DE_CONNECT) != 0)
state_ = CS_CONNECTED;
- if ((ff & kfClose) != 0)
+ if ((ff & DE_CLOSE) != 0)
state_ = CS_CLOSED;
}
virtual void OnEvent(uint32 ff, int err) {
- if ((ff & kfRead) != 0) {
- enabled_events_ &= ~kfRead;
+ if ((ff & DE_READ) != 0) {
+ enabled_events_ &= ~DE_READ;
SignalReadEvent(this);
}
- if ((ff & kfWrite) != 0) {
- enabled_events_ &= ~kfWrite;
+ if ((ff & DE_WRITE) != 0) {
+ enabled_events_ &= ~DE_WRITE;
SignalWriteEvent(this);
}
- if ((ff & kfConnect) != 0) {
- enabled_events_ &= ~kfConnect;
+ if ((ff & DE_CONNECT) != 0) {
+ enabled_events_ &= ~DE_CONNECT;
SignalConnectEvent(this);
}
- if ((ff & kfAccept) != 0) {
- enabled_events_ &= ~kfAccept;
+ if ((ff & DE_ACCEPT) != 0) {
+ enabled_events_ &= ~DE_ACCEPT;
SignalReadEvent(this);
}
- if ((ff & kfClose) != 0) {
+ if ((ff & DE_CLOSE) != 0) {
// The socket is now dead to us, so stop checking it.
enabled_events_ = 0;
SignalCloseEvent(this, err);
@@ -904,28 +908,28 @@ class FileDispatcher: public Dispatcher, public AsyncFile {
}
virtual void OnEvent(uint32 ff, int err) {
- if ((ff & kfRead) != 0)
+ if ((ff & DE_READ) != 0)
SignalReadEvent(this);
- if ((ff & kfWrite) != 0)
+ if ((ff & DE_WRITE) != 0)
SignalWriteEvent(this);
- if ((ff & kfClose) != 0)
+ if ((ff & DE_CLOSE) != 0)
SignalCloseEvent(this, err);
}
virtual bool readable() {
- return (flags_ & kfRead) != 0;
+ return (flags_ & DE_READ) != 0;
}
virtual void set_readable(bool value) {
- flags_ = value ? (flags_ | kfRead) : (flags_ & ~kfRead);
+ flags_ = value ? (flags_ | DE_READ) : (flags_ & ~DE_READ);
}
virtual bool writable() {
- return (flags_ & kfWrite) != 0;
+ return (flags_ & DE_WRITE) != 0;
}
virtual void set_writable(bool value) {
- flags_ = value ? (flags_ | kfWrite) : (flags_ & ~kfWrite);
+ flags_ = value ? (flags_ | DE_WRITE) : (flags_ & ~DE_WRITE);
}
private:
@@ -941,26 +945,15 @@ AsyncFile* PhysicalSocketServer::CreateFile(int fd) {
#endif // POSIX
#ifdef WIN32
-class Dispatcher {
- public:
- virtual ~Dispatcher() {}
- virtual uint32 GetRequestedEvents() = 0;
- virtual void OnPreEvent(uint32 ff) = 0;
- virtual void OnEvent(uint32 ff, int err) = 0;
- virtual WSAEVENT GetWSAEvent() = 0;
- virtual SOCKET GetSocket() = 0;
- virtual bool CheckSignalClose() = 0;
-};
-
static uint32 FlagsToEvents(uint32 events) {
uint32 ffFD = FD_CLOSE;
- if (events & kfRead)
+ if (events & DE_READ)
ffFD |= FD_READ;
- if (events & kfWrite)
+ if (events & DE_WRITE)
ffFD |= FD_WRITE;
- if (events & kfConnect)
+ if (events & DE_CONNECT)
ffFD |= FD_CONNECT;
- if (events & kfAccept)
+ if (events & DE_ACCEPT)
ffFD |= FD_ACCEPT;
return ffFD;
}
@@ -1020,9 +1013,16 @@ class SocketDispatcher : public Dispatcher, public PhysicalSocket {
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() {
@@ -1065,37 +1065,36 @@ class SocketDispatcher : public Dispatcher, public PhysicalSocket {
}
virtual void OnPreEvent(uint32 ff) {
- if ((ff & kfConnect) != 0)
+ if ((ff & DE_CONNECT) != 0)
state_ = CS_CONNECTED;
// We set CS_CLOSED from CheckSignalClose.
}
virtual void OnEvent(uint32 ff, int err) {
int cache_id = id_;
- if ((ff & kfRead) != 0) {
- enabled_events_ &= ~kfRead;
+ if ((ff & DE_READ) != 0) {
+ enabled_events_ &= ~DE_READ;
SignalReadEvent(this);
}
- if (((ff & kfWrite) != 0) && (id_ == cache_id)) {
- enabled_events_ &= ~kfWrite;
+ if (((ff & DE_WRITE) != 0) && (id_ == cache_id)) {
+ enabled_events_ &= ~DE_WRITE;
SignalWriteEvent(this);
}
- if (((ff & kfConnect) != 0) && (id_ == cache_id)) {
- if (ff != kfConnect)
- LOG(LS_VERBOSE) << "Signalled with kfConnect: " << ff;
- enabled_events_ &= ~kfConnect;
+ if (((ff & DE_CONNECT) != 0) && (id_ == cache_id)) {
+ if (ff != DE_CONNECT)
+ LOG(LS_VERBOSE) << "Signalled with DE_CONNECT: " << ff;
+ enabled_events_ &= ~DE_CONNECT;
#ifdef _DEBUG
dbg_addr_ = "Connected @ ";
dbg_addr_.append(GetRemoteAddress().ToString());
#endif // _DEBUG
SignalConnectEvent(this);
}
- if (((ff & kfAccept) != 0) && (id_ == cache_id)) {
- enabled_events_ &= ~kfAccept;
+ if (((ff & DE_ACCEPT) != 0) && (id_ == cache_id)) {
+ enabled_events_ &= ~DE_ACCEPT;
SignalReadEvent(this);
}
- if (((ff & kfClose) != 0) && (id_ == cache_id)) {
- //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] OnClose() Error: " << err;
+ if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) {
signal_close_ = true;
signal_err_ = err;
}
@@ -1160,7 +1159,7 @@ PhysicalSocketServer::~PhysicalSocketServer() {
WSACloseEvent(socket_ev_);
#endif
#ifdef POSIX
- PosixSignalDeliveryDispatcher::instance_.ClearOwner(this);
+ signal_dispatcher_.reset();
#endif
delete signal_wakeup_;
ASSERT(dispatchers_.empty());
@@ -1275,9 +1274,9 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
fdmax = fd;
uint32 ff = pdispatcher->GetRequestedEvents();
- if (ff & (kfRead | kfAccept))
+ if (ff & (DE_READ | DE_ACCEPT))
FD_SET(fd, &fdsRead);
- if (ff & (kfWrite | kfConnect))
+ if (ff & (DE_WRITE | DE_CONNECT))
FD_SET(fd, &fdsWrite);
}
}
@@ -1323,12 +1322,12 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
// TODO: Only peek at TCP descriptors.
if (FD_ISSET(fd, &fdsRead)) {
FD_CLR(fd, &fdsRead);
- if (pdispatcher->GetRequestedEvents() & kfAccept) {
- ff |= kfAccept;
+ if (pdispatcher->GetRequestedEvents() & DE_ACCEPT) {
+ ff |= DE_ACCEPT;
} else if (errcode || pdispatcher->IsDescriptorClosed()) {
- ff |= kfClose;
+ ff |= DE_CLOSE;
} else {
- ff |= kfRead;
+ ff |= DE_READ;
}
}
@@ -1336,14 +1335,14 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
// success versus failure by the reaped error code.
if (FD_ISSET(fd, &fdsWrite)) {
FD_CLR(fd, &fdsWrite);
- if (pdispatcher->GetRequestedEvents() & kfConnect) {
+ if (pdispatcher->GetRequestedEvents() & DE_CONNECT) {
if (!errcode) {
- ff |= kfConnect;
+ ff |= DE_CONNECT;
} else {
- ff |= kfClose;
+ ff |= DE_CLOSE;
}
} else {
- ff |= kfWrite;
+ ff |= DE_WRITE;
}
}
@@ -1381,7 +1380,7 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
}
static void GlobalSignalHandler(int signum) {
- PosixSignalDeliveryDispatcher::instance_.OnPosixSignalReceived(signum);
+ PosixSignalHandler::Instance()->OnPosixSignalReceived(signum);
}
bool PhysicalSocketServer::SetPosixSignalHandler(int signum,
@@ -1392,19 +1391,17 @@ bool PhysicalSocketServer::SetPosixSignalHandler(int signum,
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;
}
@@ -1465,7 +1462,9 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
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);
@@ -1485,14 +1484,19 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
}
// 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).
@@ -1536,41 +1540,51 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
#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
uint32 ff = 0;
int errcode = 0;
if (wsaEvents.lNetworkEvents & FD_READ)
- ff |= kfRead;
+ ff |= DE_READ;
if (wsaEvents.lNetworkEvents & FD_WRITE)
- ff |= kfWrite;
+ ff |= DE_WRITE;
if (wsaEvents.lNetworkEvents & FD_CONNECT) {
if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) {
- ff |= kfConnect;
+ ff |= DE_CONNECT;
} else {
- ff |= kfClose;
+ ff |= DE_CLOSE;
errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT];
}
}
if (wsaEvents.lNetworkEvents & FD_ACCEPT)
- ff |= kfAccept;
+ ff |= DE_ACCEPT;
if (wsaEvents.lNetworkEvents & FD_CLOSE) {
- ff |= kfClose;
+ ff |= DE_CLOSE;
errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT];
}
if (ff != 0) {
diff --git a/third_party/libjingle/source/talk/base/physicalsocketserver.h b/third_party/libjingle/source/talk/base/physicalsocketserver.h
index 282e14c..aeb8348 100644
--- a/third_party/libjingle/source/talk/base/physicalsocketserver.h
+++ b/third_party/libjingle/source/talk/base/physicalsocketserver.h
@@ -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"
@@ -38,13 +39,37 @@
typedef int SOCKET;
#endif // POSIX
-namespace talk_base {
+namespace talk_base {
+
+// Event constants for the Dispatcher class.
+enum DispatcherEvent {
+ DE_READ = 0x0001,
+ DE_WRITE = 0x0002,
+ DE_CONNECT = 0x0004,
+ DE_CLOSE = 0x0008,
+ DE_ACCEPT = 0x0010,
+};
-class Dispatcher;
class Signaler;
#ifdef POSIX
-class PosixSignalDeliveryDispatcher;
+class PosixSignalDispatcher;
+#endif
+
+class Dispatcher {
+ public:
+ virtual ~Dispatcher() {}
+ virtual uint32 GetRequestedEvents() = 0;
+ virtual void OnPreEvent(uint32 ff) = 0;
+ virtual void OnEvent(uint32 ff, int err) = 0;
+#ifdef WIN32
+ virtual WSAEVENT GetWSAEvent() = 0;
+ virtual SOCKET GetSocket() = 0;
+ virtual bool CheckSignalClose() = 0;
+#elif POSIX
+ virtual int GetDescriptor() = 0;
+ virtual bool IsDescriptorClosed() = 0;
#endif
+};
// A socket server that provides the real sockets of the underlying OS.
class PhysicalSocketServer : public SocketServer {
@@ -75,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));
@@ -89,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 --git a/third_party/libjingle/source/talk/base/socket.h b/third_party/libjingle/source/talk/base/socket.h
index 3094918..a55b3dc 100644
--- a/third_party/libjingle/source/talk/base/socket.h
+++ b/third_party/libjingle/source/talk/base/socket.h
@@ -50,55 +50,89 @@
// Win32 compatibility.
#ifdef WIN32
+#undef EWOULDBLOCK // Remove errno.h's definition for each macro below.
#define EWOULDBLOCK WSAEWOULDBLOCK
+#undef EINPROGRESS
#define EINPROGRESS WSAEINPROGRESS
+#undef EALREADY
#define EALREADY WSAEALREADY
+#undef ENOTSOCK
#define ENOTSOCK WSAENOTSOCK
+#undef EDESTADDRREQ
#define EDESTADDRREQ WSAEDESTADDRREQ
+#undef EMSGSIZE
#define EMSGSIZE WSAEMSGSIZE
+#undef EPROTOTYPE
#define EPROTOTYPE WSAEPROTOTYPE
+#undef ENOPROTOOPT
#define ENOPROTOOPT WSAENOPROTOOPT
+#undef EPROTONOSUPPORT
#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#undef ESOCKTNOSUPPORT
#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#undef EOPNOTSUPP
#define EOPNOTSUPP WSAEOPNOTSUPP
+#undef EPFNOSUPPORT
#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#undef EAFNOSUPPORT
#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#undef EADDRINUSE
#define EADDRINUSE WSAEADDRINUSE
+#undef EADDRNOTAVAIL
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#undef ENETDOWN
#define ENETDOWN WSAENETDOWN
+#undef ENETUNREACH
#define ENETUNREACH WSAENETUNREACH
+#undef ENETRESET
#define ENETRESET WSAENETRESET
+#undef ECONNABORTED
#define ECONNABORTED WSAECONNABORTED
+#undef ECONNRESET
#define ECONNRESET WSAECONNRESET
+#undef ENOBUFS
#define ENOBUFS WSAENOBUFS
+#undef EISCONN
#define EISCONN WSAEISCONN
+#undef ENOTCONN
#define ENOTCONN WSAENOTCONN
+#undef ESHUTDOWN
#define ESHUTDOWN WSAESHUTDOWN
+#undef ETOOMANYREFS
#define ETOOMANYREFS WSAETOOMANYREFS
-#undef ETIMEDOUT // remove pthreads.h's definition
+#undef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
+#undef ECONNREFUSED
#define ECONNREFUSED WSAECONNREFUSED
+#undef ELOOP
#define ELOOP WSAELOOP
-#undef ENAMETOOLONG // remove errno.h's definition
+#undef ENAMETOOLONG
#define ENAMETOOLONG WSAENAMETOOLONG
+#undef EHOSTDOWN
#define EHOSTDOWN WSAEHOSTDOWN
+#undef EHOSTUNREACH
#define EHOSTUNREACH WSAEHOSTUNREACH
-#undef ENOTEMPTY // remove errno.h's definition
+#undef ENOTEMPTY
#define ENOTEMPTY WSAENOTEMPTY
+#undef EPROCLIM
#define EPROCLIM WSAEPROCLIM
+#undef EUSERS
#define EUSERS WSAEUSERS
+#undef EDQUOT
#define EDQUOT WSAEDQUOT
+#undef ESTALE
#define ESTALE WSAESTALE
+#undef EREMOTE
#define EREMOTE WSAEREMOTE
#undef EACCES
#define SOCKET_EACCES WSAEACCES
-#endif // WIN32
+#endif // WIN32
#ifdef POSIX
#define INVALID_SOCKET (-1)
#define SOCKET_ERROR (-1)
#define closesocket(s) close(s)
-#endif // POSIX
+#endif // POSIX
namespace talk_base {
@@ -109,9 +143,9 @@ inline bool IsBlockingError(int e) {
// General interface for the socket implementations of various networks. The
// methods match those of normal UNIX sockets very closely.
class Socket {
-public:
+ public:
virtual ~Socket() {}
-
+
// Returns the address to which the socket is bound. If the socket is not
// bound, then the any-address is returned.
virtual SocketAddress GetLocalAddress() const = 0;
@@ -146,20 +180,20 @@ public:
enum Option {
OPT_DONTFRAGMENT,
- OPT_RCVBUF, // receive buffer size
- OPT_SNDBUF, // send buffer size
- OPT_NODELAY // whether Nagle algorithm is enabled
+ OPT_RCVBUF, // receive buffer size
+ OPT_SNDBUF, // send buffer size
+ OPT_NODELAY // whether Nagle algorithm is enabled
};
virtual int GetOption(Option opt, int* value) = 0;
virtual int SetOption(Option opt, int value) = 0;
-protected:
+ protected:
Socket() {}
-private:
+ private:
DISALLOW_EVIL_CONSTRUCTORS(Socket);
};
-} // namespace talk_base
+} // namespace talk_base
-#endif // TALK_BASE_SOCKET_H__
+#endif // TALK_BASE_SOCKET_H__
diff --git a/third_party/libjingle/source/talk/base/socketpool.cc b/third_party/libjingle/source/talk/base/socketpool.cc
index 6e89964..a5e3bcc 100644
--- a/third_party/libjingle/source/talk/base/socketpool.cc
+++ b/third_party/libjingle/source/talk/base/socketpool.cc
@@ -218,11 +218,25 @@ ReuseSocketPool::ReturnConnectedStream(StreamInterface* stream) {
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 --git a/third_party/libjingle/source/talk/base/socketpool.h b/third_party/libjingle/source/talk/base/socketpool.h
index 3bfd108..847d8ff 100644
--- a/third_party/libjingle/source/talk/base/socketpool.h
+++ b/third_party/libjingle/source/talk/base/socketpool.h
@@ -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 --git a/third_party/libjingle/source/talk/base/stream.cc b/third_party/libjingle/source/talk/base/stream.cc
index 45ba7ad..755fb08 100644
--- a/third_party/libjingle/source/talk/base/stream.cc
+++ b/third_party/libjingle/source/talk/base/stream.cc
@@ -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:
@@ -551,7 +551,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 {
@@ -646,25 +647,29 @@ StreamResult MemoryStreamBase::DoReserve(size_t size, int* error) {
///////////////////////////////////////////////////////////////////////////////
-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;
}
@@ -673,9 +678,12 @@ StreamResult MemoryStream::DoReserve(size_t size, int* error) {
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 --git a/third_party/libjingle/source/talk/base/stream.h b/third_party/libjingle/source/talk/base/stream.h
index ea91eac..a8d399d 100644
--- a/third_party/libjingle/source/talk/base/stream.h
+++ b/third_party/libjingle/source/talk/base/stream.h
@@ -530,6 +530,9 @@ class MemoryStream : public MemoryStreamBase {
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 --git a/third_party/libjingle/source/talk/base/stringencode.cc b/third_party/libjingle/source/talk/base/stringencode.cc
index d588514..7433bdd 100644
--- a/third_party/libjingle/source/talk/base/stringencode.cc
+++ b/third_party/libjingle/source/talk/base/stringencode.cc
@@ -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, size_t srclen, unsigned long* value) {
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, size_t srclen, unsigned long* value) {
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,36 +511,38 @@ std::string s_transform(const std::string& source, Transform t) {
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;
- for (size_t i=0; i<source.length(); ++i) {
+ for (size_t i = 0; i < source.length(); ++i) {
if (source[i] == delimiter) {
- fields->push_back(source.substr(last, i - last));
- last = i+1;
+ if (i != last) {
+ fields->push_back(source.substr(last, i - last));
+ }
+ last = i + 1;
}
}
- fields->push_back(source.substr(last, source.length() - last));
+ if (last != source.length()) {
+ fields->push_back(source.substr(last, source.length() - last));
+ }
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 --git a/third_party/libjingle/source/talk/base/stringencode.h b/third_party/libjingle/source/talk/base/stringencode.h
index 143b220..fd29f87 100644
--- a/third_party/libjingle/source/talk/base/stringencode.h
+++ b/third_party/libjingle/source/talk/base/stringencode.h
@@ -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 buflen,
// 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 std::string& source) {
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 --git a/third_party/libjingle/source/talk/base/stringutils.cc b/third_party/libjingle/source/talk/base/stringutils.cc
index 44dc7c8..8d8b7e0 100644
--- a/third_party/libjingle/source/talk/base/stringutils.cc
+++ b/third_party/libjingle/source/talk/base/stringutils.cc
@@ -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 buflen,
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 char *s2) {
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 --git a/third_party/libjingle/source/talk/base/stringutils.h b/third_party/libjingle/source/talk/base/stringutils.h
index 3e1771f..6aa9b18 100644
--- a/third_party/libjingle/source/talk/base/stringutils.h
+++ b/third_party/libjingle/source/talk/base/stringutils.h
@@ -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 --git a/third_party/libjingle/source/talk/examples/call/call_main.cc b/third_party/libjingle/source/talk/examples/call/call_main.cc
index 541aca8..4312399 100644
--- a/third_party/libjingle/source/talk/examples/call/call_main.cc
+++ b/third_party/libjingle/source/talk/examples/call/call_main.cc
@@ -44,6 +44,7 @@
#include "talk/examples/call/callclient.h"
#include "talk/examples/call/console.h"
#include "talk/session/phone/filemediaengine.h"
+#include "talk/session/phone/mediasessionclient.h"
class DebugLog : public sigslot::has_slots<> {
public:
@@ -218,6 +219,9 @@ int main(int argc, char **argv) {
DEFINE_string(
protocol, "hybrid",
"Initial signaling protocol to use: jingle, gingle, or hybrid.");
+ DEFINE_string(
+ secure, "disable",
+ "Disable or enable encryption: disable, enable, require.");
DEFINE_bool(testserver, false, "Use test server");
DEFINE_bool(plainserver, false, "Turn off tls and allow plain password.");
DEFINE_int(portallocator, 0, "Filter out unwanted connection types.");
@@ -245,6 +249,7 @@ int main(int argc, char **argv) {
int32 portallocator_flags = FLAG_portallocator;
std::string pmuc_domain = FLAG_pmuc;
std::string server = FLAG_s;
+ std::string secure = FLAG_secure;
cricket::SignalingProtocol initial_protocol = cricket::PROTOCOL_HYBRID;
if (protocol == "jingle") {
@@ -254,7 +259,19 @@ int main(int argc, char **argv) {
} else if (protocol == "hybrid") {
initial_protocol = cricket::PROTOCOL_HYBRID;
} else {
- printf("Invalid protocol. Must be jingle, gingle, or hybrid.");
+ printf("Invalid protocol. Must be jingle, gingle, or hybrid.\n");
+ return 1;
+ }
+
+ cricket::SecureMediaPolicy secure_policy = cricket::SEC_DISABLED;
+ if (secure == "disable") {
+ secure_policy = cricket::SEC_DISABLED;
+ } else if (secure == "enable") {
+ secure_policy = cricket::SEC_ENABLED;
+ } else if (secure == "require") {
+ secure_policy = cricket::SEC_REQUIRED;
+ } else {
+ printf("Invalid encryption. Must be enable, disable, or require.\n");
return 1;
}
@@ -354,6 +371,7 @@ int main(int argc, char **argv) {
client->SetPortAllocatorFlags(portallocator_flags);
client->SetAllowLocalIps(true);
client->SetInitialProtocol(initial_protocol);
+ client->SetSecurePolicy(secure_policy);
console->Start();
if (debug) {
diff --git a/third_party/libjingle/source/talk/examples/call/callclient.cc b/third_party/libjingle/source/talk/examples/call/callclient.cc
index eb761d1..94581e7 100644
--- a/third_party/libjingle/source/talk/examples/call/callclient.cc
+++ b/third_party/libjingle/source/talk/examples/call/callclient.cc
@@ -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:
@@ -237,16 +235,20 @@ void CallClient::ParseLine(const std::string& line) {
}
CallClient::CallClient(buzz::XmppClient* xmpp_client)
- : xmpp_client_(xmpp_client), media_engine_(NULL), media_client_(NULL),
- call_(NULL), incoming_call_(false),
- auto_accept_(false), pmuc_domain_("groupchat.google.com"),
- local_renderer_(NULL), remote_renderer_(NULL),
- roster_(new RosterMap), portallocator_flags_(0),
- allow_local_ips_(false), initial_protocol_(cricket::PROTOCOL_HYBRID)
-#ifdef USE_TALK_SOUND
- , sound_system_factory_(NULL)
-#endif
- {
+ : xmpp_client_(xmpp_client),
+ media_engine_(NULL),
+ media_client_(NULL),
+ call_(NULL),
+ incoming_call_(false),
+ auto_accept_(false),
+ pmuc_domain_("groupchat.google.com"),
+ local_renderer_(NULL),
+ remote_renderer_(NULL),
+ roster_(new RosterMap),
+ portallocator_flags_(0),
+ allow_local_ips_(false),
+ initial_protocol_(cricket::PROTOCOL_HYBRID),
+ secure_policy_(cricket::SEC_DISABLED) {
xmpp_client_->SignalStateChange.connect(this, &CallClient::OnStateChange);
}
@@ -334,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_);
@@ -359,32 +366,19 @@ 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);
+ media_client_->set_secure(secure_policy_);
}
void CallClient::OnRequestSignaling() {
diff --git a/third_party/libjingle/source/talk/examples/call/callclient.h b/third_party/libjingle/source/talk/examples/call/callclient.h
index a5686b4..d2b806e 100644
--- a/third_party/libjingle/source/talk/examples/call/callclient.h
+++ b/third_party/libjingle/source/talk/examples/call/callclient.h
@@ -34,12 +34,10 @@
#include "talk/p2p/base/session.h"
#include "talk/session/phone/mediachannel.h"
+#include "talk/session/phone/mediasessionclient.h"
#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;
@@ -68,7 +66,6 @@ class Receiver;
class Call;
struct CallOptions;
class SessionManagerTask;
-enum SignalingProtocol;
}
struct RosterItem {
@@ -92,7 +89,7 @@ class CallClient: public sigslot::has_slots<> {
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;
@@ -114,6 +111,10 @@ class CallClient: public sigslot::has_slots<> {
initial_protocol_ = initial_protocol;
}
+ void SetSecurePolicy(cricket::SecureMediaPolicy secure_policy) {
+ secure_policy_ = secure_policy;
+ }
+
typedef std::map<buzz::Jid, buzz::Muc*> MucMap;
@@ -167,6 +168,7 @@ class CallClient: public sigslot::has_slots<> {
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_;
@@ -193,10 +195,8 @@ class CallClient: public sigslot::has_slots<> {
bool allow_local_ips_;
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 --git a/third_party/libjingle/source/talk/libjingle.scons b/third_party/libjingle/source/talk/libjingle.scons
index 09a3bc1..870a5d8 100644
--- a/third_party/libjingle/source/talk/libjingle.scons
+++ b/third_party/libjingle/source/talk/libjingle.scons
@@ -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",
@@ -111,6 +113,7 @@ talk.Library(env, name = "libjingle",
"base/physicalsocketserver.cc",
"base/proxydetect.cc",
"base/proxyinfo.cc",
+ "base/ratetracker.cc",
"base/signalthread.cc",
"base/socketadapters.cc",
"base/socketaddress.cc",
@@ -169,6 +172,7 @@ talk.Library(env, name = "libjingle",
"session/phone/mediamonitor.cc",
"session/phone/mediasessionclient.cc",
"session/phone/rtpdump.cc",
+ "session/phone/rtcpmuxfilter.cc",
"session/phone/soundclip.cc",
"session/phone/srtpfilter.cc",
"xmllite/qname.cc",
@@ -190,6 +194,7 @@ talk.Library(env, name = "libjingle",
"xmpp/xmpptask.cc",
],
includedirs = [
+ "third_party/libudev",
"third_party/expat-2.0.1/",
"third_party/srtp/include",
"third_party/srtp/crypto/include",
diff --git a/third_party/libjingle/source/talk/main.scons b/third_party/libjingle/source/talk/main.scons
index a1348ff..b8705d1 100644
--- a/third_party/libjingle/source/talk/main.scons
+++ b/third_party/libjingle/source/talk/main.scons
@@ -92,6 +92,8 @@ win_env = root_env.Clone(
CCPDBFLAGS = '',
CCFLAGS_DEBUG = '',
CCFLAGS_OPTIMIZED = '',
+ # We force a x86 target even when building on x64 Windows platforms.
+ TARGET_ARCH = 'x86',
)
win_env.Append(
@@ -186,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
@@ -196,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',
@@ -210,6 +227,9 @@ win_opt_env.Prepend(
'/MT', # link with LIBCMT.LIB (multi-threaded, static linked crt)
'/GS', # enable security checks
],
+ LINKFLAGS = [
+ '/safeseh',
+ ],
)
envs.append(win_opt_env)
@@ -230,7 +250,6 @@ posix_env.Append(
'_REENTRANT',
],
CCFLAGS = [
- '-m32',
'-Wall',
'-Werror',
'-Wno-switch',
@@ -241,9 +260,6 @@ posix_env.Append(
'-Wno-ctor-dtor-privacy',
'-fno-rtti',
],
- LINKFLAGS = [
- '-m32',
- ],
)
#-------------------------------------------------------------------------------
@@ -262,6 +278,7 @@ mac_env.Append(
'MAC_OS_X_VERSION_MIN_REQUIRED=1040',
],
CCFLAGS = [
+ '-m32',
'-arch', 'i386',
'-isysroot', '/Developer/SDKs/MacOSX10.5.sdk',
'-fasm-blocks',
@@ -274,6 +291,7 @@ mac_env.Append(
# TODO: consider only defining for libs that actually have objc.
'-ObjC',
'-arch', 'i386',
+ '-m32',
],
FRAMEWORKS = [
'CoreServices',
@@ -281,6 +299,11 @@ mac_env.Append(
'Security',
'SystemConfiguration',
'OpenGL',
+ 'CoreAudio',
+ 'Quartz',
+ 'QuickTime',
+ 'Cocoa',
+ 'QTKit',
]
)
@@ -327,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.
@@ -373,6 +394,14 @@ linux_env = linux_common_env.Clone()
# product would end up being broken on any computer with a different version
# installed. So instead we build it ourself and statically link to it.
linux_env.SetBits('use_static_openssl')
+linux_env.Append(
+ CCFLAGS = [
+ '-m32',
+ ],
+ LINKFLAGS = [
+ '-m32',
+ ],
+)
linux_dbg_env = linux_env.Clone(
BUILD_TYPE = 'dbg',
@@ -454,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 --git a/third_party/libjingle/source/talk/p2p/base/common.h b/third_party/libjingle/source/talk/p2p/base/common.h
index 72f8cfa..5a38180 100644
--- a/third_party/libjingle/source/talk/p2p/base/common.h
+++ b/third_party/libjingle/source/talk/p2p/base/common.h
@@ -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 --git a/third_party/libjingle/source/talk/p2p/base/constants.cc b/third_party/libjingle/source/talk/p2p/base/constants.cc
index 1becb39..f44ce21 100644
--- a/third_party/libjingle/source/talk/p2p/base/constants.cc
+++ b/third_party/libjingle/source/talk/p2p/base/constants.cc
@@ -63,6 +63,9 @@ const std::string GINGLE_ACTION_ACCEPT("accept");
const std::string GINGLE_ACTION_REJECT("reject");
const std::string GINGLE_ACTION_TERMINATE("terminate");
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");
@@ -73,6 +76,7 @@ const std::string STR_REDIRECT_PREFIX("xmpp:");
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");
@@ -188,6 +192,34 @@ const std::string STR_TERMINATE_PROTOCOL_ERROR("protocol-error");
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 --git a/third_party/libjingle/source/talk/p2p/base/constants.h b/third_party/libjingle/source/talk/p2p/base/constants.h
index 9f93cbc..cd2e2c5 100644
--- a/third_party/libjingle/source/talk/p2p/base/constants.h
+++ b/third_party/libjingle/source/talk/p2p/base/constants.h
@@ -79,6 +79,9 @@ extern const std::string GINGLE_ACTION_ACCEPT;
extern const std::string GINGLE_ACTION_REJECT;
extern const std::string GINGLE_ACTION_TERMINATE;
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;
@@ -89,6 +92,7 @@ extern const std::string STR_REDIRECT_PREFIX;
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;
@@ -203,6 +207,30 @@ extern const std::string STR_TERMINATE_PROTOCOL_ERROR;
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 --git a/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc b/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
index 0cd9b71..1b2bec2 100644
--- a/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
+++ b/third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.cc
@@ -621,12 +621,21 @@ void P2PTransportChannel::SortConnections() {
// 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 --git a/third_party/libjingle/source/talk/p2p/base/port.cc b/third_party/libjingle/source/talk/p2p/base/port.cc
index 2aa66a4..edf52c5 100644
--- a/third_party/libjingle/source/talk/p2p/base/port.cc
+++ b/third_party/libjingle/source/talk/p2p/base/port.cc
@@ -25,28 +25,16 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#if defined(_MSC_VER) && _MSC_VER < 1300
-#pragma warning(disable:4786)
-#endif
+#include "talk/p2p/base/port.h"
#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"
-#include "talk/p2p/base/port.h"
-
-#if defined(_MSC_VER) && _MSC_VER < 1300
-namespace std {
- using ::memcmp;
-}
-#endif
namespace {
@@ -137,11 +125,19 @@ bool StringToProto(const char* value, ProtocolType* proto) {
}
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));
@@ -209,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) {
@@ -228,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.
@@ -277,68 +255,73 @@ bool Port::GetStunMessage(const char* data, size_t size,
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.
@@ -371,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.
@@ -381,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);
@@ -417,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) {
@@ -528,15 +480,15 @@ class ConnectionRequest : public StunRequest {
}
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() {
@@ -560,7 +512,8 @@ Connection::Connection(Port* port, size_t index,
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";
@@ -605,16 +558,18 @@ void Connection::set_connected(bool value) {
}
}
-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.
@@ -622,6 +577,7 @@ void Connection::OnReadPacket(const char* data, size_t size) {
// 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);
@@ -629,24 +585,30 @@ void Connection::OnReadPacket(const char* data, size_t size) {
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.
@@ -697,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
@@ -704,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);
}
@@ -716,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,
@@ -736,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);
}
@@ -743,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);
}
}
@@ -787,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.
+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);
- // 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;
- }
- }
-
- // 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)
@@ -869,16 +814,33 @@ void Connection::OnConnectionRequestErrorResponse(StunMessage *response,
// 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);
@@ -894,19 +856,19 @@ void Connection::OnMessage(talk_base::Message *pmsg) {
}
size_t Connection::recv_bytes_second() {
- return recv_rate_tracker_.bytes_second();
+ return recv_rate_tracker_.units_second();
}
size_t Connection::recv_total_bytes() {
- return recv_rate_tracker_.total_bytes();
+ return recv_rate_tracker_.total_units();
}
size_t Connection::sent_bytes_second() {
- return send_rate_tracker_.bytes_second();
+ return send_rate_tracker_.units_second();
}
size_t Connection::sent_total_bytes() {
- return send_rate_tracker_.total_bytes();
+ return send_rate_tracker_.total_units();
}
ProxyConnection::ProxyConnection(Port* port, size_t index,
@@ -929,48 +891,4 @@ int ProxyConnection::Send(const void* data, size_t size) {
return sent;
}
-RateTracker::RateTracker()
- : total_bytes_(0), bytes_second_(0),
- last_bytes_second_time_(static_cast<uint32>(-1)),
- last_bytes_second_calc_(0) {
-}
-
-size_t RateTracker::total_bytes() const {
- return total_bytes_;
-}
-
-size_t RateTracker::bytes_second() {
- // Snapshot bytes / second calculator. Determine how many seconds have
- // elapsed since our last reference point. If over 1 second, establish
- // a new reference point that is an integer number of seconds since the
- // last one, and compute the bytes over that interval.
-
- uint32 current_time = talk_base::Time();
- if (last_bytes_second_time_ != static_cast<uint32>(-1)) {
- int delta = talk_base::TimeDiff(current_time, last_bytes_second_time_);
- if (delta >= 1000) {
- int fraction_time = delta % 1000;
- int seconds = delta / 1000;
- int fraction_bytes =
- static_cast<int>(total_bytes_ - last_bytes_second_calc_) *
- fraction_time / delta;
- // Compute "bytes received during the interval" / "seconds in interval"
- bytes_second_ =
- (total_bytes_ - last_bytes_second_calc_ - fraction_bytes) / seconds;
- last_bytes_second_time_ = current_time - fraction_time;
- last_bytes_second_calc_ = total_bytes_ - fraction_bytes;
- }
- }
- if (last_bytes_second_time_ == static_cast<uint32>(-1)) {
- last_bytes_second_time_ = current_time;
- last_bytes_second_calc_ = total_bytes_;
- }
-
- return bytes_second_;
-}
-
-void RateTracker::Update(size_t bytes) {
- total_bytes_ += bytes;
-}
-
} // namespace cricket
diff --git a/third_party/libjingle/source/talk/p2p/base/port.h b/third_party/libjingle/source/talk/p2p/base/port.h
index 88b15c6..8304146 100644
--- a/third_party/libjingle/source/talk/p2p/base/port.h
+++ b/third_party/libjingle/source/talk/p2p/base/port.h
@@ -33,9 +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"
@@ -48,6 +50,7 @@ class AsyncPacketSocket;
namespace cricket {
class Connection;
+class ConnectionRequest;
enum ProtocolType {
PROTO_UDP,
@@ -67,37 +70,24 @@ struct ProtocolAddress {
: address(a), proto(p) { }
};
-// Computes instantaneous bytes per second.
-class RateTracker {
- public:
- RateTracker();
- size_t total_bytes() const;
- size_t bytes_second();
- void Update(size_t bytes);
-
- private:
- size_t total_bytes_;
- size_t bytes_second_;
- uint32 last_bytes_second_time_;
- size_t last_bytes_second_calc_;
-};
-
// Represents a local communication mechanism that can be used to create
// connections to similar mechanisms of the other client. Subclasses of this
// 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_; }
@@ -124,7 +114,6 @@ class Port : public talk_base::MessageHandler, public sigslot::has_slots<> {
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.
@@ -199,8 +188,6 @@ class Port : public talk_base::MessageHandler, public sigslot::has_slots<> {
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
@@ -226,20 +213,6 @@ class Port : public talk_base::MessageHandler, public sigslot::has_slots<> {
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);
@@ -253,8 +226,6 @@ class Port : public talk_base::MessageHandler, public sigslot::has_slots<> {
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
@@ -263,9 +234,25 @@ class Port : public talk_base::MessageHandler, public sigslot::has_slots<> {
// 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.
@@ -277,6 +264,8 @@ class Port : public talk_base::MessageHandler, public sigslot::has_slots<> {
// 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
@@ -345,7 +334,7 @@ class Connection : public talk_base::MessageHandler,
// 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.
@@ -356,7 +345,7 @@ class Connection : public talk_base::MessageHandler,
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
@@ -366,36 +355,22 @@ class Connection : public talk_base::MessageHandler,
// 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:
- Port* port_;
- size_t local_candidate_index_;
- Candidate remote_candidate_;
- ReadState read_state_;
- WriteState write_state_;
- bool connected_;
- bool pruned_;
- StunRequestManager requests_;
- uint32 rtt_;
- 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
- std::vector<uint32> pings_since_last_response_;
-
- RateTracker recv_rate_tracker_;
- RateTracker send_rate_tracker_;
-
- // Callbacks from ConnectionRequest
- void OnConnectionRequestResponse(StunMessage *response, uint32 rtt);
- void OnConnectionRequestErrorResponse(StunMessage *response, uint32 rtt);
+ // 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);
- // Constructs a new connection to the given remote port.
- Connection(Port* port, size_t index, const Candidate& candidate);
+ // 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);
@@ -407,11 +382,29 @@ class Connection : public talk_base::MessageHandler,
void OnMessage(talk_base::Message *pmsg);
- friend class Port;
- friend class ConnectionRequest;
+ Port* port_;
+ size_t local_candidate_index_;
+ Candidate remote_candidate_;
+ ReadState read_state_;
+ WriteState write_state_;
+ bool connected_;
+ bool pruned_;
+ StunRequestManager requests_;
+ uint32 rtt_;
+ 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_;
private:
bool reported_;
+
+ friend class Port;
+ friend class ConnectionRequest;
};
// ProxyConnection defers all the interesting work to the port
diff --git a/third_party/libjingle/source/talk/p2p/base/portallocator.h b/third_party/libjingle/source/talk/p2p/base/portallocator.h
index 332326e..175bdbc 100644
--- a/third_party/libjingle/source/talk/p2p/base/portallocator.h
+++ b/third_party/libjingle/source/talk/p2p/base/portallocator.h
@@ -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 = 0x10;
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 --git a/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc b/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
index c342dbc..955584e 100644
--- a/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
+++ b/third_party/libjingle/source/talk/p2p/base/pseudotcp.cc
@@ -118,7 +118,7 @@ const uint32 PACKET_OVERHEAD = HEADER_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE +
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* notify, uint32 conv)
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, long& timeout) {
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, long& nTimeout) {
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 sflags) {
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 --git a/third_party/libjingle/source/talk/p2p/base/pseudotcp.h b/third_party/libjingle/source/talk/p2p/base/pseudotcp.h
index 1446201..e8e0d3a 100644
--- a/third_party/libjingle/source/talk/p2p/base/pseudotcp.h
+++ b/third_party/libjingle/source/talk/p2p/base/pseudotcp.h
@@ -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 --git a/third_party/libjingle/source/talk/p2p/base/relayport.cc b/third_party/libjingle/source/talk/p2p/base/relayport.cc
index ff6d55a..2d3be61 100644
--- a/third_party/libjingle/source/talk/p2p/base/relayport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/relayport.cc
@@ -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::has_slots<> {
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::MessageHandler,
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 StunRequest {
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, size_t size,
// 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, size_t size,
}
// 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::SendAllocateRequest(RelayEntry* entry, int delay) {
}
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, size_t size,
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, size_t size,
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::Message *pmsg) {
// 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::Message *pmsg) {
}
}
-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_base::AsyncTCPSocket* socket) {
}
}
-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(StunMessage* request) {
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 --git a/third_party/libjingle/source/talk/p2p/base/relayport.h b/third_party/libjingle/source/talk/p2p/base/relayport.h
index fd0f83d..025668a 100644
--- a/third_party/libjingle/source/talk/p2p/base/relayport.h
+++ b/third_party/libjingle/source/talk/p2p/base/relayport.h
@@ -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 --git a/third_party/libjingle/source/talk/p2p/base/relayserver.cc b/third_party/libjingle/source/talk/p2p/base/relayserver.cc
index 525da34..111b340 100644
--- a/third_party/libjingle/source/talk/p2p/base/relayserver.cc
+++ b/third_party/libjingle/source/talk/p2p/base/relayserver.cc
@@ -159,12 +159,24 @@ void RelayServer::RemoveInternalServerSocket(
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::AsyncSocket* socket) {
}
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_base::AsyncSocket* server_socket) {
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 --git a/third_party/libjingle/source/talk/p2p/base/relayserver.h b/third_party/libjingle/source/talk/p2p/base/relayserver.h
index 3337991..d34c099 100644
--- a/third_party/libjingle/source/talk/p2p/base/relayserver.h
+++ b/third_party/libjingle/source/talk/p2p/base/relayserver.h
@@ -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 --git a/third_party/libjingle/source/talk/p2p/base/relayserver_main.cc b/third_party/libjingle/source/talk/p2p/base/relayserver_main.cc
index 2f07458..2de4247 100644
--- a/third_party/libjingle/source/talk/p2p/base/relayserver_main.cc
+++ b/third_party/libjingle/source/talk/p2p/base/relayserver_main.cc
@@ -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 --git a/third_party/libjingle/source/talk/p2p/base/session.cc b/third_party/libjingle/source/talk/p2p/base/session.cc
index 38b91ff..27b39dd 100644
--- a/third_party/libjingle/source/talk/p2p/base/session.cc
+++ b/third_party/libjingle/source/talk/p2p/base/session.cc
@@ -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);
}
}
@@ -646,6 +644,12 @@ void Session::OnIncomingMessage(const SessionMessage& msg) {
case ACTION_TRANSPORT_ACCEPT:
valid = OnTransportAcceptMessage(msg, &error);
break;
+ case ACTION_NOTIFY:
+ valid = OnNotifyMessage(msg, &error);
+ break;
+ case ACTION_UPDATE:
+ valid = OnUpdateMessage(msg, &error);
+ break;
default:
valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
"unknown session message type",
@@ -689,13 +693,16 @@ void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
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) {
@@ -824,6 +831,30 @@ bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
return true;
}
+bool Session::OnNotifyMessage(const SessionMessage& msg,
+ MessageError* error) {
+ SessionNotify notify;
+ if (!ParseSessionNotify(msg.action_elem, &notify, 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);
@@ -860,6 +891,12 @@ bool Session::CheckState(State state, MessageError* error) {
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_;
@@ -901,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;
@@ -950,6 +997,12 @@ bool Session::WriteSessionAction(SignalingProtocol protocol,
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 --git a/third_party/libjingle/source/talk/p2p/base/session.h b/third_party/libjingle/source/talk/p2p/base/session.h
index ddbc663..b00e809 100644
--- a/third_party/libjingle/source/talk/p2p/base/session.h
+++ b/third_party/libjingle/source/talk/p2p/base/session.h
@@ -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_slots<>,
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_slots<>,
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 --git a/third_party/libjingle/source/talk/p2p/base/sessionmessages.cc b/third_party/libjingle/source/talk/p2p/base/sessionmessages.cc
index cfd035d..d61b666 100644
--- a/third_party/libjingle/source/talk/p2p/base/sessionmessages.cc
+++ b/third_party/libjingle/source/talk/p2p/base/sessionmessages.cc
@@ -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 {
@@ -70,6 +73,10 @@ ActionType ToActionType(const std::string& type) {
return ACTION_TRANSPORT_INFO;
if (type == JINGLE_ACTION_TRANSPORT_ACCEPT)
return ACTION_TRANSPORT_ACCEPT;
+ if (type == GINGLE_ACTION_NOTIFY)
+ return ACTION_NOTIFY;
+ if (type == GINGLE_ACTION_UPDATE)
+ return ACTION_UPDATE;
return ACTION_UNKNOWN;
}
@@ -108,6 +115,8 @@ std::string ToGingleString(ActionType type) {
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:
@@ -122,7 +131,12 @@ bool IsJingleMessage(const buzz::XmlElement* stanza) {
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) {
@@ -164,7 +178,13 @@ bool ParseJingleSessionMessage(const buzz::XmlElement* jingle,
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;
@@ -217,7 +237,11 @@ buzz::XmlElement* WriteJingleAction(const SessionMessage& msg,
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
@@ -820,6 +844,40 @@ bool WriteTransportInfos(SignalingProtocol protocol,
}
}
+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);
@@ -830,6 +888,65 @@ bool GetUriTarget(const std::string& prefix, const std::string& str,
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 --git a/third_party/libjingle/source/talk/p2p/base/sessionmessages.h b/third_party/libjingle/source/talk/p2p/base/sessionmessages.h
index eee8452..affb4d9 100644
--- a/third_party/libjingle/source/talk/p2p/base/sessionmessages.h
+++ b/third_party/libjingle/source/talk/p2p/base/sessionmessages.h
@@ -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 {
@@ -60,6 +61,13 @@ enum ActionType {
ACTION_TRANSPORT_INFO,
ACTION_TRANSPORT_ACCEPT,
+
+ // TODO: Make better names for these when we think of a
+ // "jingley" way of signaling them. Even better, remove them from
+ // being needed at all.
+ ACTION_NOTIFY,
+ ACTION_UPDATE,
+ ACTION_VIEW,
};
// Abstraction of a <jingle> element within an <iq> stanza, per XMPP
@@ -153,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,
@@ -212,6 +259,11 @@ bool WriteTransportInfos(SignalingProtocol protocol,
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 --git a/third_party/libjingle/source/talk/p2p/base/stunport.cc b/third_party/libjingle/source/talk/p2p/base/stunport.cc
index 7f5dad7..aa6e1d3 100644
--- a/third_party/libjingle/source/talk/p2p/base/stunport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/stunport.cc
@@ -102,8 +102,8 @@ class StunPortBindingRequest : public StunRequest {
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 StunRequest {
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 --git a/third_party/libjingle/source/talk/p2p/base/stunport.h b/third_party/libjingle/source/talk/p2p/base/stunport.h
index 569e229..0b41724 100644
--- a/third_party/libjingle/source/talk/p2p/base/stunport.h
+++ b/third_party/libjingle/source/talk/p2p/base/stunport.h
@@ -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 --git a/third_party/libjingle/source/talk/p2p/base/stunserver.cc b/third_party/libjingle/source/talk/p2p/base/stunserver.cc
index 1ff02ee..a0686a1 100644
--- a/third_party/libjingle/source/talk/p2p/base/stunserver.cc
+++ b/third_party/libjingle/source/talk/p2p/base/stunserver.cc
@@ -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 --git a/third_party/libjingle/source/talk/p2p/base/stunserver.h b/third_party/libjingle/source/talk/p2p/base/stunserver.h
index 83ac174..6e51ad1 100644
--- a/third_party/libjingle/source/talk/p2p/base/stunserver.h
+++ b/third_party/libjingle/source/talk/p2p/base/stunserver.h
@@ -46,8 +46,8 @@ class StunServer : public sigslot::has_slots<> {
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 --git a/third_party/libjingle/source/talk/p2p/base/stunserver_main.cc b/third_party/libjingle/source/talk/p2p/base/stunserver_main.cc
index e4a2df6..e697728 100644
--- a/third_party/libjingle/source/talk/p2p/base/stunserver_main.cc
+++ b/third_party/libjingle/source/talk/p2p/base/stunserver_main.cc
@@ -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 --git a/third_party/libjingle/source/talk/p2p/base/tcpport.cc b/third_party/libjingle/source/talk/p2p/base/tcpport.cc
index 806c258..41e04d2 100644
--- a/third_party/libjingle/source/talk/p2p/base/tcpport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/tcpport.cc
@@ -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(const Candidate& address,
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(const Candidate& address,
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::GetIncoming(
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 --git a/third_party/libjingle/source/talk/p2p/base/tcpport.h b/third_party/libjingle/source/talk/p2p/base/tcpport.h
index d4ce575..0de3561 100644
--- a/third_party/libjingle/source/talk/p2p/base/tcpport.h
+++ b/third_party/libjingle/source/talk/p2p/base/tcpport.h
@@ -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; // type of TCP ports
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 --git a/third_party/libjingle/source/talk/p2p/base/transport.cc b/third_party/libjingle/source/talk/p2p/base/transport.cc
index 9d8fc32..dc571d4 100644
--- a/third_party/libjingle/source/talk/p2p/base/transport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/transport.cc
@@ -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::string& name) {
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 std::vector<Candidate>& candidates) {
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 buzz::XmlElement* elem,
address->SetIP(elem->Attr(address_name));
std::istringstream ist(elem->Attr(port_name));
- int port;
+ int port = 0;
ist >> port;
address->SetPort(port);
diff --git a/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc b/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
index 405ed76..1be9194 100644
--- a/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
+++ b/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.cc
@@ -75,6 +75,13 @@ int TransportChannelProxy::GetError() {
return impl_->GetError();
}
+P2PTransportChannel* TransportChannelProxy::GetP2PChannel() {
+ if (impl_) {
+ return impl_->GetP2PChannel();
+ }
+ return NULL;
+}
+
void TransportChannelProxy::OnReadableState(TransportChannel* channel) {
ASSERT(channel == impl_);
set_readable(impl_->readable());
diff --git a/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h b/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
index 2184477..4601185 100644
--- a/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
+++ b/third_party/libjingle/source/talk/p2p/base/transportchannelproxy.h
@@ -55,6 +55,7 @@ class TransportChannelProxy: public TransportChannel {
virtual int SendPacket(const char *data, size_t len);
virtual int SetOption(talk_base::Socket::Option opt, int value);
virtual int GetError();
+ virtual P2PTransportChannel* GetP2PChannel();
private:
typedef std::pair<talk_base::Socket::Option, int> OptionPair;
diff --git a/third_party/libjingle/source/talk/p2p/base/udpport.cc b/third_party/libjingle/source/talk/p2p/base/udpport.cc
index a34c17e..28cf5d2 100644
--- a/third_party/libjingle/source/talk/p2p/base/udpport.cc
+++ b/third_party/libjingle/source/talk/p2p/base/udpport.cc
@@ -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, size_t size,
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 --git a/third_party/libjingle/source/talk/p2p/base/udpport.h b/third_party/libjingle/source/talk/p2p/base/udpport.h
index 7fcad6c..f7588a6 100644
--- a/third_party/libjingle/source/talk/p2p/base/udpport.h
+++ b/third_party/libjingle/source/talk/p2p/base/udpport.h
@@ -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; // type of UDP ports
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 --git a/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc b/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc
index 3762b34..c023e9e 100644
--- a/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc
+++ b/third_party/libjingle/source/talk/p2p/client/basicportallocator.cc
@@ -166,17 +166,24 @@ class AllocationSequence : public talk_base::MessageHandler {
// 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::CreateRelayPorts() {
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 --git a/third_party/libjingle/source/talk/p2p/client/basicportallocator.h b/third_party/libjingle/source/talk/p2p/client/basicportallocator.h
index 0891e86..b2c1b8c 100644
--- a/third_party/libjingle/source/talk/p2p/client/basicportallocator.h
+++ b/third_party/libjingle/source/talk/p2p/client/basicportallocator.h
@@ -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 PortAllocator {
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 PortAllocator {
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 --git a/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc b/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc
index c9cce12..4ef0825 100644
--- a/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc
+++ b/third_party/libjingle/source/talk/p2p/client/httpportallocator.cc
@@ -96,9 +96,11 @@ const int HttpPortAllocator::kNumRetries = 5;
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 --git a/third_party/libjingle/source/talk/p2p/client/httpportallocator.h b/third_party/libjingle/source/talk/p2p/client/httpportallocator.h
index d695062..478f278 100644
--- a/third_party/libjingle/source/talk/p2p/client/httpportallocator.h
+++ b/third_party/libjingle/source/talk/p2p/client/httpportallocator.h
@@ -50,6 +50,7 @@ class HttpPortAllocator : public BasicPortAllocator {
static const std::string kCreateSessionURL;
HttpPortAllocator(talk_base::NetworkManager* network_manager,
+ talk_base::PacketSocketFactory* socket_factory,
const std::string& user_agent);
virtual ~HttpPortAllocator();
diff --git a/third_party/libjingle/source/talk/session/phone/channel.cc b/third_party/libjingle/source/talk/session/phone/channel.cc
index 76c1cb4..1083ec7 100644
--- a/third_party/libjingle/source/talk/session/phone/channel.cc
+++ b/third_party/libjingle/source/talk/session/phone/channel.cc
@@ -26,6 +26,8 @@
*/
#include "talk/session/phone/channel.h"
+
+#include "talk/base/buffer.h"
#include "talk/base/byteorder.h"
#include "talk/base/common.h"
#include "talk/base/logging.h"
@@ -33,15 +35,58 @@
#include "talk/session/phone/channelmanager.h"
#include "talk/session/phone/mediasessionclient.h"
#include "talk/session/phone/mediasink.h"
+#include "talk/session/phone/rtcpmuxfilter.h"
namespace cricket {
-static const size_t kMaxPacketLen = 2048;
+struct PacketMessageData : public talk_base::MessageData {
+ 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";
}
+static bool ValidPacket(bool rtcp, const talk_base::Buffer* packet) {
+ // Check the packet size. We could check the header too if needed.
+ return (packet &&
+ packet->length() >= (!rtcp ? kMinRtpPacketLen : kMinRtcpPacketLen) &&
+ packet->length() <= kMaxRtpPacketLen);
+}
+
+static uint16 GetRtpSeqNum(const talk_base::Buffer* packet) {
+ return (packet->length() >= kMinRtpPacketLen) ?
+ talk_base::GetBE16(packet->data() + 2) : 0;
+}
+
+static uint32 GetRtpSsrc(const talk_base::Buffer* packet) {
+ return (packet->length() >= kMinRtpPacketLen) ?
+ talk_base::GetBE32(packet->data() + 8) : 0;
+}
+
+static int GetRtcpType(const talk_base::Buffer* packet) {
+ return (packet->length() >= kMinRtcpPacketLen) ?
+ static_cast<int>(packet->data()[1]) : 0;
+}
+
BaseChannel::BaseChannel(talk_base::Thread* thread, MediaEngine* media_engine,
MediaChannel* media_channel, BaseSession* session,
const std::string& content_name,
@@ -74,7 +119,8 @@ BaseChannel::BaseChannel(talk_base::Thread* thread, MediaEngine* media_engine,
BaseChannel::~BaseChannel() {
ASSERT(worker_thread_ == talk_base::Thread::Current());
StopConnectionMonitor();
- Clear();
+ 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
// is not an effective strategy since the sends will come on another thread.
@@ -160,17 +206,12 @@ void BaseChannel::set_rtcp_transport_channel(TransportChannel* channel) {
}
}
-int BaseChannel::SendPacket(const void *data, size_t len) {
- // SendPacket gets called from MediaEngine; send to socket
- // MediaEngine will call us on a random thread. The Send operation on the
- // socket is special in that it can handle this.
- // TODO: Actually, SendPacket cannot handle this. Need to fix ASAP.
-
- return SendPacket(false, data, len);
+bool BaseChannel::SendPacket(talk_base::Buffer* packet) {
+ return SendPacket(false, packet);
}
-int BaseChannel::SendRtcp(const void *data, size_t len) {
- return SendPacket(true, data, len);
+bool BaseChannel::SendRtcp(talk_base::Buffer* packet) {
+ return SendPacket(true, packet);
}
int BaseChannel::SetOption(SocketType type, talk_base::Socket::Option opt,
@@ -197,19 +238,29 @@ void BaseChannel::OnChannelRead(TransportChannel* channel,
// OnChannelRead gets called from P2PSocket; now pass data to MediaEngine
ASSERT(worker_thread_ == talk_base::Thread::Current());
+ talk_base::Buffer packet(data, len);
// When using RTCP multiplexing we might get RTCP packets on the RTP
// transport. We feed RTP traffic into the demuxer to determine if it is RTCP.
bool rtcp = (channel == rtcp_transport_channel_ ||
- rtcp_mux_filter_.DemuxRtcp(data, len));
- HandlePacket(rtcp, data, len);
-}
-
-int BaseChannel::SendPacket(bool rtcp, const void* data, size_t len) {
- // Protect ourselves against crazy data.
- if (len > kMaxPacketLen) {
- LOG(LS_ERROR) << "Dropping outgoing large "
- << PacketType(rtcp) << " packet, size " << len;
- return -1;
+ rtcp_mux_filter_.DemuxRtcp(packet.data(), packet.length()));
+ HandlePacket(rtcp, &packet);
+}
+
+bool BaseChannel::SendPacket(bool rtcp, talk_base::Buffer* packet) {
+ // SendPacket gets called from MediaEngine, typically on an encoder thread.
+ // If the thread is not our worker thread, we will post to our worker
+ // so that the real work happens on our worker. This avoids us having to
+ // synchronize access to all the pieces of the send path, including
+ // SRTP and the inner workings of the transport channels.
+ // The only downside is that we can't return a proper failure code if
+ // needed. Since UDP is unreliable anyway, this should be a non-issue.
+ if (talk_base::Thread::Current() != worker_thread_) {
+ // Avoid a copy by transferring the ownership of the packet data.
+ int message_id = (!rtcp) ? MSG_RTPPACKET : MSG_RTCPPACKET;
+ PacketMessageData* data = new PacketMessageData;
+ packet->TransferTo(&data->packet);
+ worker_thread_->Post(this, message_id, data);
+ return true;
}
// Make sure we have a place to send this packet before doing anything.
@@ -218,89 +269,114 @@ int BaseChannel::SendPacket(bool rtcp, const void* data, size_t len) {
TransportChannel* channel = (!rtcp || rtcp_mux_filter_.IsActive()) ?
transport_channel_ : rtcp_transport_channel_;
if (!channel) {
- return -1;
+ return false;
}
- // Protect if needed.
- uint8 work[kMaxPacketLen];
- const char* real_data = static_cast<const char*>(data);
- int real_len = len;
- if (srtp_filter_.IsActive()) {
- bool res;
- memcpy(work, data, len);
- if (!rtcp) {
- res = srtp_filter_.ProtectRtp(work, len, sizeof(work), &real_len);
- } else {
- res = srtp_filter_.ProtectRtcp(work, len, sizeof(work), &real_len);
- }
- if (!res) {
- LOG(LS_ERROR) << "Failed to protect "
- << PacketType(rtcp) << " packet, size " << len;
- return -1;
- }
-
- real_data = reinterpret_cast<const char*>(work);
+ // Protect ourselves against crazy data.
+ if (!ValidPacket(rtcp, packet)) {
+ LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " "
+ << PacketType(rtcp) << " packet: wrong size="
+ << packet->length();
+ return false;
}
+ // Push the packet down to the media sink.
+ // Need to do this before protecting the packet.
{
talk_base::CritScope cs(&sink_critical_section_);
if (sent_media_sink_) {
- // Put the sent RTP or RTCP packet to the sink.
if (!rtcp) {
- sent_media_sink_->OnRtpPacket(real_data, real_len);
+ sent_media_sink_->OnRtpPacket(packet->data(), packet->length());
} else {
- sent_media_sink_->OnRtcpPacket(real_data, real_len);
+ sent_media_sink_->OnRtcpPacket(packet->data(), packet->length());
}
}
}
- // Bon voyage. Return a number that the caller can understand.
- return (channel->SendPacket(real_data, real_len) == real_len) ? len : -1;
+ // Protect if needed.
+ if (srtp_filter_.IsActive()) {
+ bool res;
+ char* data = packet->data();
+ int len = packet->length();
+ if (!rtcp) {
+ res = srtp_filter_.ProtectRtp(data, len, packet->capacity(), &len);
+ if (!res) {
+ LOG(LS_ERROR) << "Failed to protect " << content_name_
+ << " RTP packet: size=" << len
+ << ", seqnum=" << GetRtpSeqNum(packet)
+ << ", SSRC=" << GetRtpSsrc(packet);
+ return false;
+ }
+ } else {
+ res = srtp_filter_.ProtectRtcp(data, len, packet->capacity(), &len);
+ if (!res) {
+ LOG(LS_ERROR) << "Failed to protect " << content_name_
+ << " RTCP packet: size=" << len
+ << ", type=" << GetRtcpType(packet);
+ return false;
+ }
+ }
+
+ // Update the length of the packet now that we've added the auth tag.
+ packet->SetLength(len);
+ }
+
+ // Bon voyage.
+ return (channel->SendPacket(packet->data(), packet->length())
+ == static_cast<int>(packet->length()));
}
-void BaseChannel::HandlePacket(bool rtcp, const char* data, size_t len) {
+void BaseChannel::HandlePacket(bool rtcp, talk_base::Buffer* packet) {
// Protect ourselvs against crazy data.
- if (len > kMaxPacketLen) {
- LOG(LS_ERROR) << "Dropping incoming large "
- << PacketType(rtcp) << " packet, size " << len;
+ if (!ValidPacket(rtcp, packet)) {
+ LOG(LS_ERROR) << "Dropping incoming " << content_name_ << " "
+ << PacketType(rtcp) << " packet: wrong size="
+ << packet->length();
return;
}
// Unprotect the packet, if needed.
- uint8 work[kMaxPacketLen];
- const char* real_data = data;
- int real_len = len;
if (srtp_filter_.IsActive()) {
+ char* data = packet->data();
+ int len = packet->length();
bool res;
- memcpy(work, data, len);
if (!rtcp) {
- res = srtp_filter_.UnprotectRtp(work, len, &real_len);
+ res = srtp_filter_.UnprotectRtp(data, len, &len);
+ if (!res) {
+ LOG(LS_ERROR) << "Failed to unprotect " << content_name_
+ << " RTP packet: size=" << len
+ << ", seqnum=" << GetRtpSeqNum(packet)
+ << ", SSRC=" << GetRtpSsrc(packet);
+ return;
+ }
} else {
- res = srtp_filter_.UnprotectRtcp(work, len, &real_len);
- }
- if (!res) {
- LOG(LS_ERROR) << "Failed to unprotect "
- << PacketType(rtcp) << " packet, size " << len;
- return;
+ res = srtp_filter_.UnprotectRtcp(data, len, &len);
+ if (!res) {
+ LOG(LS_ERROR) << "Failed to unprotect " << content_name_
+ << " RTCP packet: size=" << len
+ << ", type=" << GetRtcpType(packet);
+ return;
+ }
}
- real_data = reinterpret_cast<const char*>(work);
+
+ packet->SetLength(len);
}
// Push it down to the media channel.
if (!rtcp) {
- media_channel_->OnPacketReceived(real_data, real_len);
+ media_channel_->OnPacketReceived(packet);
} else {
- media_channel_->OnRtcpReceived(real_data, real_len);
+ media_channel_->OnRtcpReceived(packet);
}
+ // Push it down to the media sink.
{
talk_base::CritScope cs(&sink_critical_section_);
if (received_media_sink_) {
- // Put the received RTP or RTCP packet to the sink.
if (!rtcp) {
- received_media_sink_->OnRtpPacket(real_data, real_len);
+ received_media_sink_->OnRtpPacket(packet->data(), packet->length());
} else {
- received_media_sink_->OnRtcpPacket(real_data, real_len);
+ received_media_sink_->OnRtcpPacket(packet->data(), packet->length());
}
}
}
@@ -308,32 +384,34 @@ void BaseChannel::HandlePacket(bool rtcp, const char* data, size_t len) {
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:
@@ -493,6 +571,14 @@ void BaseChannel::OnMessage(talk_base::Message *pmsg) {
data->result = SetMaxSendBandwidth_w(data->value);
break;
}
+
+ case MSG_RTPPACKET:
+ case MSG_RTCPPACKET: {
+ PacketMessageData* data = static_cast<PacketMessageData*>(pmsg->pdata);
+ SendPacket(pmsg->message_id == MSG_RTCPPACKET, &data->packet);
+ delete data; // because it is Posted
+ break;
+ }
}
}
@@ -513,6 +599,18 @@ void BaseChannel::Clear(uint32 id, talk_base::MessageList* removed) {
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,
@@ -528,6 +626,9 @@ VoiceChannel::VoiceChannel(talk_base::Thread* thread,
// 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() {
@@ -627,8 +728,10 @@ void VoiceChannel::OnChannelRead(TransportChannel* channel,
// 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();
+ }
}
}
@@ -636,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;
}
@@ -704,7 +813,10 @@ bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
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";
@@ -785,6 +897,13 @@ void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
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);
@@ -808,6 +927,13 @@ void VoiceChannel::OnAudioMonitorUpdate(AudioMonitor* monitor,
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,
@@ -826,6 +952,15 @@ VideoChannel::VideoChannel(talk_base::Thread* thread,
// 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() {
@@ -861,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;
}
@@ -988,10 +1129,16 @@ void VideoChannel::OnMessage(talk_base::Message *pmsg) {
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;
}
}
@@ -1007,64 +1154,11 @@ void VideoChannel::OnMediaMonitorUpdate(
}
-// TODO: Move to own file in a future CL.
-// Leaving here for now to avoid having to mess with the Mac build.
-RtcpMuxFilter::RtcpMuxFilter() : state_(ST_INIT), offer_enable_(false) {
-}
-
-bool RtcpMuxFilter::IsActive() const {
- // We can receive muxed media prior to the accept, so we have to be able to
- // deal with that.
- return (state_ == ST_SENTOFFER || state_ == ST_ACTIVE);
-}
-
-bool RtcpMuxFilter::SetOffer(bool offer_enable, ContentSource source) {
- bool ret = false;
- if (state_ == ST_INIT) {
- offer_enable_ = offer_enable;
- state_ = (source == CS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER;
- ret = true;
- } else {
- LOG(LS_ERROR) << "Invalid state for RTCP mux offer";
- }
- return ret;
-}
-
-bool RtcpMuxFilter::SetAnswer(bool answer_enable, ContentSource source) {
- bool ret = false;
- if ((state_ == ST_SENTOFFER && source == CS_REMOTE) ||
- (state_ == ST_RECEIVEDOFFER && source == CS_LOCAL)) {
- if (offer_enable_) {
- state_ = (answer_enable) ? ST_ACTIVE : ST_INIT;
- ret = true;
- } else {
- // If the offer didn't specify RTCP mux, the answer shouldn't either.
- if (!answer_enable) {
- ret = true;
- state_ = ST_INIT;
- } else {
- LOG(LS_WARNING) << "Invalid parameters in RTCP mux answer";
- }
- }
- } else {
- LOG(LS_ERROR) << "Invalid state for RTCP mux answer";
- }
- return ret;
-}
-
-bool RtcpMuxFilter::DemuxRtcp(const char* data, int len) {
- // If we're muxing RTP/RTCP, we must inspect each packet delivered and
- // determine whether it is RTP or RTCP. We do so by checking the packet type,
- // and assuming RTP if type is 0-63 or 96-127. For additional details, see
- // http://tools.ietf.org/html/draft-ietf-avt-rtp-and-rtcp-mux-07.
- // Note that if we offer RTCP mux, we may receive muxed RTCP before we
- // receive the answer, so we operate in that state too.
- if (!IsActive()) {
- return false;
- }
-
- int type = (len >= 2) ? (static_cast<uint8>(data[1]) & 0x7F) : 0;
- return (type >= 64 && type < 96);
+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 --git a/third_party/libjingle/source/talk/session/phone/channel.h b/third_party/libjingle/source/talk/session/phone/channel.h
index b82a4bf..e7bee83 100644
--- a/third_party/libjingle/source/talk/session/phone/channel.h
+++ b/third_party/libjingle/source/talk/session/phone/channel.h
@@ -41,6 +41,7 @@
#include "talk/session/phone/mediaengine.h"
#include "talk/session/phone/mediachannel.h"
#include "talk/session/phone/mediamonitor.h"
+#include "talk/session/phone/rtcpmuxfilter.h"
#include "talk/session/phone/srtpfilter.h"
namespace cricket {
@@ -67,37 +68,14 @@ enum {
MSG_SETRTCPCNAME = 18,
MSG_SENDINTRAFRAME = 19,
MSG_REQUESTINTRAFRAME = 20,
-};
-
-// TODO: Move to own file.
-class RtcpMuxFilter {
- public:
- RtcpMuxFilter();
-
- // Whether the filter is active, i.e. has RTCP mux been properly negotiated.
- bool IsActive() const;
-
- // Specifies whether the offer indicates the use of RTCP mux.
- bool SetOffer(bool offer_enable, ContentSource src);
-
- // Specifies whether the answer indicates the use of RTCP mux.
- bool SetAnswer(bool answer_enable, ContentSource src);
-
- // Determines whether the specified packet is RTCP.
- bool DemuxRtcp(const char* data, int len);
-
- private:
- enum State { ST_INIT, ST_SENTOFFER, ST_RECEIVEDOFFER, ST_ACTIVE };
- State state_;
- bool offer_enable_;
+ MSG_RTPPACKET = 22,
+ MSG_RTCPPACKET = 23,
+ MSG_CHANNEL_ERROR = 24
};
// BaseChannel contains logic common to voice and video, including
// enable/mute, marshaling calls to a worker thread, and
// connection and media monitors.
-// TODO: Break the dependency on BaseSession. The only thing we need
-// it for is to Create/Destroy TransportChannels, and set codecs, both of which
-// could be done by the calling class.
class BaseChannel
: public talk_base::MessageHandler, public sigslot::has_slots<>,
public MediaChannel::NetworkInterface {
@@ -106,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_; }
@@ -117,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
@@ -159,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; }
@@ -172,18 +150,19 @@ 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 int SendPacket(const void *data, size_t len);
- virtual int SendRtcp(const void *data, size_t len);
+ virtual bool SendPacket(talk_base::Buffer* packet);
+ virtual bool SendRtcp(talk_base::Buffer* packet);
virtual int SetOption(SocketType type, talk_base::Socket::Option o, int val);
// From TransportChannel
void OnWritableState(TransportChannel* channel);
void OnChannelRead(TransportChannel* channel, const char *data, size_t len);
- int SendPacket(bool rtcp, const void* data, size_t len);
- void HandlePacket(bool rtcp, const char* data, size_t len);
+ bool SendPacket(bool rtcp, talk_base::Buffer* packet);
+ void HandlePacket(bool rtcp, talk_base::Buffer* packet);
// Setting the send codec based on the remote description.
void OnSessionState(BaseSession* session, BaseSession::State state);
@@ -313,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)
@@ -368,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_;
@@ -405,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();
@@ -440,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 --git a/third_party/libjingle/source/talk/session/phone/channelmanager.cc b/third_party/libjingle/source/talk/session/phone/channelmanager.cc
index 901a20a..d8c97cd 100644
--- a/third_party/libjingle/source/talk/session/phone/channelmanager.cc
+++ b/third_party/libjingle/source/talk/session/phone/channelmanager.cc
@@ -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::MessageData {
};
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::Thread* worker_thread)
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,16 +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_)) {
- // TODO: Consider resetting to the default cam here.
- 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_);
@@ -478,43 +494,17 @@ bool ChannelManager::GetVideoOptions(std::string* cam_name) {
}
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_) {
-#ifdef OSX
- Device sg_device;
- ret = device_manager_->QtKitToSgDevice(device.name, &sg_device);
- if (ret) {
- device = sg_device;
- } else {
- LOG(LS_ERROR) << "Unable to find SG Component for qtkit device "
- << device.name;
- }
-#endif
- if (ret) {
- VideoOptions options(&device);
- ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result);
- }
+ bool ret = true;
+ if (initialized_) {
+ VideoOptions options(&device);
+ ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result);
}
// If everything worked, retain the name of the selected camera.
@@ -638,10 +628,10 @@ bool ChannelManager::Send(uint32 id, talk_base::MessageData* data) {
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) {
@@ -728,8 +718,9 @@ void ChannelManager::OnMessage(talk_base::Message* message) {
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 --git a/third_party/libjingle/source/talk/session/phone/channelmanager.h b/third_party/libjingle/source/talk/session/phone/channelmanager.h
index c5ff45a..dfcfffe 100644
--- a/third_party/libjingle/source/talk/session/phone/channelmanager.h
+++ b/third_party/libjingle/source/talk/session/phone/channelmanager.h
@@ -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::MessageHandler,
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::MessageHandler,
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 --git a/third_party/libjingle/source/talk/session/phone/cryptoparams.h b/third_party/libjingle/source/talk/session/phone/cryptoparams.h
index 8891659..15e94a0 100644
--- a/third_party/libjingle/source/talk/session/phone/cryptoparams.h
+++ b/third_party/libjingle/source/talk/session/phone/cryptoparams.h
@@ -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 --git a/third_party/libjingle/source/talk/session/phone/devicemanager.cc b/third_party/libjingle/source/talk/session/phone/devicemanager.cc
index e32ed63..cb97301 100644
--- a/third_party/libjingle/source/talk/session/phone/devicemanager.cc
+++ b/third_party/libjingle/source/talk/session/phone/devicemanager.cc
@@ -43,46 +43,78 @@
#include <CoreAudio/CoreAudio.h>
#include <QuickTime/QuickTime.h>
#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"
+#include "talk/base/physicalsocketserver.h"
#include "talk/base/stream.h"
+#include "talk/session/phone/libudevsymboltable.h"
#include "talk/session/phone/v4llookup.h"
+#include "talk/sound/platformsoundsystem.h"
+#include "talk/sound/platformsoundsystemfactory.h"
+#include "talk/sound/sounddevicelocator.h"
+#include "talk/sound/soundsysteminterface.h"
#endif
#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.
const std::string DeviceManager::kDefaultDeviceName;
-#if WIN32
+#ifdef WIN32
class DeviceWatcher : public talk_base::Win32Window {
public:
explicit DeviceWatcher(DeviceManager* dm);
bool Start();
void Stop();
+
private:
HDEVNOTIFY Register(REFGUID guid);
void Unregister(HDEVNOTIFY notify);
virtual bool OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT& result);
+
DeviceManager* manager_;
HDEVNOTIFY audio_notify_;
HDEVNOTIFY video_notify_;
};
-#else
-// TODO: Implement this for other platforms.
+#elif defined(LINUX)
+class DeviceWatcher : private talk_base::Dispatcher {
+ public:
+ explicit DeviceWatcher(DeviceManager* dm);
+ bool Start();
+ void Stop();
+
+ private:
+ virtual uint32 GetRequestedEvents();
+ virtual void OnPreEvent(uint32 ff);
+ virtual void OnEvent(uint32 ff, int err);
+ virtual int GetDescriptor();
+ virtual bool IsDescriptorClosed();
+
+ DeviceManager* manager_;
+ LibUDevSymbolTable libudev_;
+ struct udev* udev_;
+ struct udev_monitor* udev_monitor_;
+ bool registered_;
+};
+#define LATE(sym) LATESYM_GET(LibUDevSymbolTable, &libudev_, sym)
+#elif defined(OSX)
+class DeviceWatcher {
+ public:
+ explicit DeviceWatcher(DeviceManager* dm);
+ bool Start();
+ void Stop();
+ private:
+ 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) {}
@@ -91,7 +123,7 @@ class DeviceWatcher {
};
#endif
-#ifndef LINUX
+#if !defined(LINUX) && !defined(IOS)
static bool ShouldDeviceBeIgnored(const std::string& device_name);
#endif
#ifndef OSX
@@ -107,21 +139,22 @@ static bool GetWaveDevices(bool input, std::vector<Device>* devs);
#elif OSX
static const int kVideoDeviceOpenAttempts = 3;
static const UInt32 kAudioDeviceNameLength = 64;
-// Obj-C function defined in devicemanager-mac.mm
+// Obj-C functions defined in devicemanager-mac.mm
+extern void* CreateDeviceWatcherCallback(DeviceManager* dm);
+extern void ReleaseDeviceWatcherCallback(void* impl);
extern bool GetQTKitVideoDevices(std::vector<Device>* out);
static bool GetAudioDeviceIDs(bool inputs, std::vector<AudioDeviceID>* out);
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)
+#ifdef LINUX
+ , sound_system_(new PlatformSoundSystemFactory())
#endif
{
}
@@ -135,6 +168,16 @@ DeviceManager::~DeviceManager() {
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;
}
@@ -146,6 +189,12 @@ bool DeviceManager::Init() {
void DeviceManager::Terminate() {
if (initialized_) {
watcher_->Stop();
+#if defined(WIN32)
+ if (need_couninitialize_) {
+ CoUninitialize();
+ need_couninitialize_ = false;
+ }
+#endif
initialized_ = false;
}
}
@@ -202,86 +251,6 @@ bool DeviceManager::GetVideoCaptureDevices(std::vector<Device>* devices) {
#endif
}
-#ifdef OSX
-bool DeviceManager::QtKitToSgDevice(const std::string& qtkit_name,
- Device* out) {
- out->name.clear();
-
- ComponentDescription only_vdig;
- memset(&only_vdig, 0, sizeof(only_vdig));
- only_vdig.componentType = videoDigitizerComponentType;
- only_vdig.componentSubType = kAnyComponentSubType;
- only_vdig.componentManufacturer = kAnyComponentManufacturer;
-
- // Enumerate components (drivers).
- Component component = 0;
- while ((component = FindNextComponent(component, &only_vdig)) &&
- out->name.empty()) {
- // Get the name of the component and see if we want to open it.
- Handle name_handle = NewHandle(0);
- GetComponentInfo(component, NULL, name_handle, NULL, NULL);
- Ptr name_ptr = *name_handle;
- std::string comp_name(name_ptr + 1, static_cast<size_t>(*name_ptr));
- DisposeHandle(name_handle);
-
- if (!ShouldDeviceBeIgnored(comp_name)) {
- // Try to open the component.
- // DV Video will fail with err=-9408 (deviceCantMeetRequest)
- // IIDC FireWire Video and USB Video Class Video will fail with err=704
- // if no cameras are present, or there is contention for the camera.
- // We can't tell the scenarios apart, so we will retry a few times if
- // we get a 704 to make sure we detect the cam if one is really there.
- int attempts = 0;
- ComponentInstance vdig;
- OSErr err;
- do {
- err = OpenAComponent(component, &vdig);
- ++attempts;
- } while (!vdig && err == 704 && attempts < kVideoDeviceOpenAttempts);
-
- if (vdig) {
- // We were able to open the component.
- LOG(LS_INFO) << "Opened component \"" << comp_name
- << "\", tries=" << attempts;
-
- // Enumerate cameras on the component.
- // Note, that due to QT strangeness VDGetNumberOfInputs really returns
- // the number of inputs minus one. If no inputs are available -1 is
- // returned.
- short num_inputs; // NOLINT
- VideoDigitizerError err = VDGetNumberOfInputs(vdig, &num_inputs);
- if (err == 0 && num_inputs >= 0) {
- LOG(LS_INFO) << "Found " << num_inputs + 1 << " webcams attached.";
- Str255 pname;
- for (int i = 0; i <= num_inputs; ++i) {
- err = VDGetInputName(vdig, i, pname);
- if (err == 0) {
- // The format for camera ids is <component>:<camera index>.
- char id_buf[256];
- talk_base::sprintfn(id_buf, ARRAY_SIZE(id_buf), "%s:%d",
- comp_name.c_str(), i);
- std::string name(reinterpret_cast<const char*>(pname + 1),
- static_cast<size_t>(*pname)), id(id_buf);
- LOG(LS_INFO) << " Webcam " << i << ": " << name;
- if (name == qtkit_name) {
- out->name = name;
- out->id = id;
- break;
- }
- }
- }
- }
- CloseComponent(vdig);
- } else {
- LOG(LS_INFO) << "Failed to open component \"" << comp_name
- << "\", err=" << err;
- }
- }
- }
- return !out->name.empty();
-}
-#endif
-
bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
bool ret = false;
#if WIN32
@@ -310,6 +279,28 @@ bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) {
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) {
@@ -338,7 +329,8 @@ bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name,
bool DeviceManager::GetAudioDevicesByPlatform(bool input,
std::vector<Device>* devs) {
devs->clear();
-#if defined(USE_TALK_SOUND)
+
+#if defined(LINUX)
if (!sound_system_.get()) {
return false;
}
@@ -384,51 +376,6 @@ bool DeviceManager::GetAudioDevicesByPlatform(bool input,
}
return ret;
-#elif defined(LINUX)
- int card = -1, dev = -1;
- snd_ctl_t *handle = NULL;
- snd_pcm_info_t *pcminfo = NULL;
-
- snd_pcm_info_malloc(&pcminfo);
-
- while (true) {
- if (snd_card_next(&card) != 0 || card < 0)
- break;
-
- char *card_name;
- if (snd_card_get_name(card, &card_name) != 0)
- continue;
-
- char card_string[7];
- snprintf(card_string, sizeof(card_string), "hw:%d", card);
- if (snd_ctl_open(&handle, card_string, 0) != 0)
- continue;
-
- while (true) {
- if (snd_ctl_pcm_next_device(handle, &dev) < 0 || dev < 0)
- break;
- snd_pcm_info_set_device(pcminfo, dev);
- snd_pcm_info_set_subdevice(pcminfo, 0);
- snd_pcm_info_set_stream(pcminfo, input ? SND_PCM_STREAM_CAPTURE :
- SND_PCM_STREAM_PLAYBACK);
- if (snd_ctl_pcm_info(handle, pcminfo) != 0)
- continue;
-
- char name[128];
- talk_base::sprintfn(name, sizeof(name), "%s (%s)", card_name,
- snd_pcm_info_get_name(pcminfo));
- // TODO: We might want to identify devices with something
- // more specific than just their card number (e.g., the PCM names that
- // aplay -L prints out).
- devs->push_back(Device(name, card));
-
- LOG(LS_INFO) << "Found device: id = " << card << ", name = "
- << name;
- }
- snd_ctl_close(handle);
- }
- snd_pcm_info_free(pcminfo);
- return true;
#else
return false;
#endif
@@ -436,20 +383,7 @@ bool DeviceManager::GetAudioDevicesByPlatform(bool input,
#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) {
@@ -738,6 +672,24 @@ static bool GetAudioDeviceName(AudioDeviceID id,
return true;
}
+DeviceWatcher::DeviceWatcher(DeviceManager* manager)
+ : manager_(manager), impl_(NULL) {
+}
+
+bool DeviceWatcher::Start() {
+ if (!impl_) {
+ impl_ = CreateDeviceWatcherCallback(manager_);
+ }
+ return impl_ != NULL;
+}
+
+void DeviceWatcher::Stop() {
+ if (impl_) {
+ ReleaseDeviceWatcherCallback(impl_);
+ impl_ = NULL;
+ }
+}
+
#elif defined(LINUX)
static const std::string kVideoMetaPathK2_4("/proc/video/dev/");
static const std::string kVideoMetaPathK2_6("/sys/class/video4linux/");
@@ -900,11 +852,117 @@ static bool GetVideoDevices(std::vector<Device>* devices) {
ScanV4L2Devices(devices);
return true;
}
+
+DeviceWatcher::DeviceWatcher(DeviceManager* dm)
+ : manager_(dm), udev_(NULL), udev_monitor_(NULL), registered_(false) {}
+
+bool DeviceWatcher::Start() {
+ // We deliberately return true in the failure paths here because libudev is
+ // not a critical component of a Linux system so it may not be present/usable,
+ // and we don't want to halt DeviceManager initialization in such a case.
+ if (!libudev_.Load()) {
+ LOG(LS_WARNING) << "libudev not present/usable; DeviceWatcher disabled";
+ return true;
+ }
+ udev_ = LATE(udev_new)();
+ if (!udev_) {
+ LOG_ERR(LS_ERROR) << "udev_new()";
+ return true;
+ }
+ // The second argument here is the event source. It can be either "kernel" or
+ // "udev", but "udev" is the only correct choice. Apps listen on udev and the
+ // udev daemon in turn listens on the kernel.
+ udev_monitor_ = LATE(udev_monitor_new_from_netlink)(udev_, "udev");
+ if (!udev_monitor_) {
+ LOG_ERR(LS_ERROR) << "udev_monitor_new_from_netlink()";
+ return true;
+ }
+ // We only listen for changes in the video devices. Audio devices are more or
+ // less unimportant because receiving device change notifications really only
+ // matters for broadcasting updated send/recv capabilities based on whether
+ // there is at least one device available, and almost all computers have at
+ // least one audio device. Also, PulseAudio device notifications don't come
+ // from the udev daemon, they come from the PulseAudio daemon, so we'd only
+ // want to listen for audio device changes from udev if using ALSA. For
+ // simplicity, we don't bother with any audio stuff at all.
+ if (LATE(udev_monitor_filter_add_match_subsystem_devtype)(udev_monitor_,
+ "video4linux",
+ NULL) < 0) {
+ LOG_ERR(LS_ERROR) << "udev_monitor_filter_add_match_subsystem_devtype()";
+ return true;
+ }
+ if (LATE(udev_monitor_enable_receiving)(udev_monitor_) < 0) {
+ LOG_ERR(LS_ERROR) << "udev_monitor_enable_receiving()";
+ return true;
+ }
+ static_cast<talk_base::PhysicalSocketServer*>(
+ talk_base::Thread::Current()->socketserver())->Add(this);
+ registered_ = true;
+ return true;
+}
+
+void DeviceWatcher::Stop() {
+ if (registered_) {
+ static_cast<talk_base::PhysicalSocketServer*>(
+ talk_base::Thread::Current()->socketserver())->Remove(this);
+ registered_ = false;
+ }
+ if (udev_monitor_) {
+ LATE(udev_monitor_unref)(udev_monitor_);
+ udev_monitor_ = NULL;
+ }
+ if (udev_) {
+ LATE(udev_unref)(udev_);
+ udev_ = NULL;
+ }
+ libudev_.Unload();
+}
+
+uint32 DeviceWatcher::GetRequestedEvents() {
+ return talk_base::DE_READ;
+}
+
+void DeviceWatcher::OnPreEvent(uint32 ff) {
+ // Nothing to do.
+}
+
+void DeviceWatcher::OnEvent(uint32 ff, int err) {
+ udev_device* device = LATE(udev_monitor_receive_device)(udev_monitor_);
+ if (!device) {
+ // Probably the socket connection to the udev daemon was terminated (perhaps
+ // the daemon crashed or is being restarted?).
+ LOG_ERR(LS_WARNING) << "udev_monitor_receive_device()";
+ // Stop listening to avoid potential livelock (an fd with EOF in it is
+ // always considered readable).
+ static_cast<talk_base::PhysicalSocketServer*>(
+ talk_base::Thread::Current()->socketserver())->Remove(this);
+ registered_ = false;
+ return;
+ }
+ // Else we read the device successfully.
+
+ // Since we already have our own filesystem-based device enumeration code, we
+ // simply re-enumerate rather than inspecting the device event.
+ LATE(udev_device_unref)(device);
+ manager_->OnDevicesChange();
+}
+
+int DeviceWatcher::GetDescriptor() {
+ return LATE(udev_monitor_get_fd)(udev_monitor_);
+}
+
+bool DeviceWatcher::IsDescriptorClosed() {
+ // If it is closed then we will just get an error in
+ // udev_monitor_receive_device and unregister, so we don't need to check for
+ // it separately.
+ return false;
+}
+
#endif
// 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/third_party/libjingle/source/talk/session/phone/devicemanager.h b/third_party/libjingle/source/talk/session/phone/devicemanager.h
index 594e9bd..cd41f6f 100644
--- a/third_party/libjingle/source/talk/session/phone/devicemanager.h
+++ b/third_party/libjingle/source/talk/session/phone/devicemanager.h
@@ -33,7 +33,7 @@
#include "talk/base/sigslot.h"
#include "talk/base/stringencode.h"
-#ifdef USE_TALK_SOUND
+#ifdef LINUX
#include "talk/sound/soundsystemfactory.h"
#endif
@@ -59,11 +59,7 @@ struct Device {
// 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,10 +78,7 @@ class DeviceManager {
bool GetAudioOutputDevice(const std::string& name, Device* out);
virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
- virtual bool GetDefaultVideoCaptureDevice(Device* device);
-#ifdef OSX
- virtual bool QtKitToSgDevice(const std::string& qtkit_name, Device* out);
-#endif
+ bool GetVideoCaptureDevice(const std::string& name, Device* out);
sigslot::signal0<> SignalDevicesChange;
@@ -96,12 +89,17 @@ class DeviceManager {
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
+#ifdef LINUX
SoundSystemHandle sound_system_;
#endif
};
diff --git a/third_party/libjingle/source/talk/session/phone/devicemanager_mac.mm b/third_party/libjingle/source/talk/session/phone/devicemanager_mac.mm
index 1a14e95..3537ed9 100644
--- a/third_party/libjingle/source/talk/session/phone/devicemanager_mac.mm
+++ b/third_party/libjingle/source/talk/session/phone/devicemanager_mac.mm
@@ -31,8 +31,48 @@
#include "talk/base/logging.h"
+@interface DeviceWatcherImpl : NSObject {
+@private
+ cricket::DeviceManager* manager_;
+}
+- (id)init:(cricket::DeviceManager*) dm;
+- (void)onDevicesChanged:(NSNotification *)notification;
+@end
+
+@implementation DeviceWatcherImpl
+- (id)init:(cricket::DeviceManager*) dm {
+ if ((self = [super init])) {
+ manager_ = dm;
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(onDevicesChanged:)
+ name:QTCaptureDeviceWasConnectedNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(onDevicesChanged:)
+ name:QTCaptureDeviceWasDisconnectedNotification
+ object:nil];
+ }
+ return self;
+}
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+- (void)onDevicesChanged:(NSNotification *)notification {
+ manager_->OnDevicesChange();
+}
+@end
+
namespace cricket {
+void* CreateDeviceWatcherCallback(DeviceManager* dm) {
+ return [[DeviceWatcherImpl alloc] init:dm];
+}
+void ReleaseDeviceWatcherCallback(void* watcher) {
+ DeviceWatcherImpl* watcher_impl = static_cast<DeviceWatcherImpl*>(watcher);
+ [watcher_impl release];
+}
+
bool GetQTKitVideoDevices(std::vector<Device>* devices) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
@@ -44,11 +84,12 @@ bool GetQTKitVideoDevices(std::vector<Device>* devices) {
QTCaptureDevice* qt_capture_device = [qt_capture_devices objectAtIndex:i];
static const NSString* kFormat = @"localizedDisplayName: \"%@\", "
- "modelUniqueID: \"%@\", isConnected: %d, isOpen: %d, "
+ "modelUniqueID: \"%@\", uniqueID \"%@\", isConnected: %d, isOpen: %d, "
"isInUseByAnotherApplication: %d";
NSString* info = [NSString stringWithFormat:kFormat,
[qt_capture_device localizedDisplayName],
[qt_capture_device modelUniqueID],
+ [qt_capture_device uniqueID],
[qt_capture_device isConnected],
[qt_capture_device isOpen],
[qt_capture_device isInUseByAnotherApplication]];
@@ -57,7 +98,7 @@ bool GetQTKitVideoDevices(std::vector<Device>* devices) {
std::string name([[qt_capture_device localizedDisplayName]
cStringUsingEncoding:NSUTF8StringEncoding]);
devices->push_back(Device(name,
- [[qt_capture_device modelUniqueID]
+ [[qt_capture_device uniqueID]
cStringUsingEncoding:NSUTF8StringEncoding]));
}
diff --git a/third_party/libjingle/source/talk/session/phone/filemediaengine.cc b/third_party/libjingle/source/talk/session/phone/filemediaengine.cc
index 4929933..49d92b6 100644
--- a/third_party/libjingle/source/talk/session/phone/filemediaengine.cc
+++ b/third_party/libjingle/source/talk/session/phone/filemediaengine.cc
@@ -25,6 +25,9 @@
#include "talk/session/phone/filemediaengine.h"
+#include <climits>
+
+#include "talk/base/buffer.h"
#include "talk/base/event.h"
#include "talk/base/logging.h"
#include "talk/base/pathutils.h"
@@ -81,12 +84,15 @@ class RtpSenderReceiver
// Called by media channel. Context: media channel thread.
bool SetSend(bool send);
- void OnPacketReceived(const void* data, int len);
+ void OnPacketReceived(talk_base::Buffer* packet);
// Override virtual method of parent MessageHandler. Context: Worker Thread.
virtual void OnMessage(talk_base::Message* pmsg);
private:
+ // Read the next RTP dump packet, whose RTP SSRC is the same as first_ssrc_.
+ // Return true if successful.
+ bool ReadNextPacket(RtpDumpPacket* packet);
// Send a RTP packet to the network. The input parameter data points to the
// start of the RTP packet and len is the packet size. Return true if the sent
// size is equal to len.
@@ -99,8 +105,10 @@ class RtpSenderReceiver
talk_base::scoped_ptr<RtpDumpWriter> rtp_dump_writer_;
// RTP dump packet read from the input stream.
RtpDumpPacket rtp_dump_packet_;
+ uint32 start_send_time_;
bool sending_;
bool first_packet_;
+ uint32 first_ssrc_;
DISALLOW_COPY_AND_ASSIGN(RtpSenderReceiver);
};
@@ -136,13 +144,14 @@ bool RtpSenderReceiver::SetSend(bool send) {
sending_ = send;
if (!was_sending && sending_) {
PostDelayed(0, this); // Wake up the send thread.
+ start_send_time_ = talk_base::Time();
}
return true;
}
-void RtpSenderReceiver::OnPacketReceived(const void* data, int len) {
+void RtpSenderReceiver::OnPacketReceived(talk_base::Buffer* packet) {
if (rtp_dump_writer_.get()) {
- rtp_dump_writer_->WriteRtpPacket(data, len);
+ rtp_dump_writer_->WriteRtpPacket(packet->data(), packet->length());
}
}
@@ -153,32 +162,45 @@ void RtpSenderReceiver::OnMessage(talk_base::Message* pmsg) {
return;
}
- uint32 prev_elapsed_time = 0xFFFFFFFF;
if (!first_packet_) {
- prev_elapsed_time = rtp_dump_packet_.elapsed_time;
+ // Send the previously read packet.
SendRtpPacket(&rtp_dump_packet_.data[0], rtp_dump_packet_.data.size());
- } else {
- first_packet_ = false;
}
- // Read a dump packet and wait for the elapsed time.
- if (talk_base::SR_SUCCESS ==
- rtp_dump_reader_->ReadPacket(&rtp_dump_packet_)) {
- int waiting_time_ms = rtp_dump_packet_.elapsed_time > prev_elapsed_time ?
- rtp_dump_packet_.elapsed_time - prev_elapsed_time : 0;
- PostDelayed(waiting_time_ms, this);
+ if (ReadNextPacket(&rtp_dump_packet_)) {
+ int wait = talk_base::TimeUntil(
+ start_send_time_ + rtp_dump_packet_.elapsed_time);
+ wait = talk_base::_max(0, wait);
+ PostDelayed(wait, this);
} else {
Quit();
}
}
+bool RtpSenderReceiver::ReadNextPacket(RtpDumpPacket* packet) {
+ while (talk_base::SR_SUCCESS == rtp_dump_reader_->ReadPacket(packet)) {
+ uint32 ssrc;
+ if (!packet->GetRtpSsrc(&ssrc)) {
+ return false;
+ }
+ if (first_packet_) {
+ first_packet_ = false;
+ first_ssrc_ = ssrc;
+ }
+ if (ssrc == first_ssrc_) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool RtpSenderReceiver::SendRtpPacket(const void* data, size_t len) {
if (!media_channel_ || !media_channel_->network_interface()) {
return false;
}
- return media_channel_->network_interface()->SendPacket(data, len) ==
- static_cast<int>(len);
+ talk_base::Buffer packet(data, len, kMaxRtpPacketLen);
+ return media_channel_->network_interface()->SendPacket(&packet);
}
///////////////////////////////////////////////////////////////////////////
@@ -200,8 +222,8 @@ bool FileVoiceChannel::SetSend(SendFlags flag) {
return rtp_sender_receiver_->SetSend(flag != SEND_NOTHING);
}
-void FileVoiceChannel::OnPacketReceived(const void* data, int len) {
- rtp_sender_receiver_->OnPacketReceived(data, len);
+void FileVoiceChannel::OnPacketReceived(talk_base::Buffer* packet) {
+ rtp_sender_receiver_->OnPacketReceived(packet);
}
///////////////////////////////////////////////////////////////////////////
@@ -223,8 +245,8 @@ bool FileVideoChannel::SetSend(bool send) {
return rtp_sender_receiver_->SetSend(send);
}
-void FileVideoChannel::OnPacketReceived(const void* data, int len) {
- rtp_sender_receiver_->OnPacketReceived(data, len);
+void FileVideoChannel::OnPacketReceived(talk_base::Buffer* packet) {
+ rtp_sender_receiver_->OnPacketReceived(packet);
}
} // namespace cricket
diff --git a/third_party/libjingle/source/talk/session/phone/filemediaengine.h b/third_party/libjingle/source/talk/session/phone/filemediaengine.h
index cc6788c..2276772 100644
--- a/third_party/libjingle/source/talk/session/phone/filemediaengine.h
+++ b/third_party/libjingle/source/talk/session/phone/filemediaengine.h
@@ -144,8 +144,8 @@ class FileVoiceChannel : public VoiceMediaChannel {
virtual bool GetStats(VoiceMediaInfo* info) { return true; }
// Implement pure virtual methods of MediaChannel.
- virtual void OnPacketReceived(const void* data, int len);
- virtual void OnRtcpReceived(const void* data, int len) {}
+ virtual void OnPacketReceived(talk_base::Buffer* packet);
+ virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
virtual void SetSendSsrc(uint32 id) {} // TODO: change RTP packet?
virtual bool SetRtcpCName(const std::string& cname) { return true; }
virtual bool Mute(bool on) { return false; }
@@ -179,8 +179,8 @@ class FileVideoChannel : public VideoMediaChannel {
virtual bool RequestIntraFrame() { return false; }
// Implement pure virtual methods of MediaChannel.
- virtual void OnPacketReceived(const void* data, int len);
- virtual void OnRtcpReceived(const void* data, int len) {}
+ virtual void OnPacketReceived(talk_base::Buffer* packet);
+ virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
virtual void SetSendSsrc(uint32 id) {} // TODO: change RTP packet?
virtual bool SetRtcpCName(const std::string& cname) { return true; }
virtual bool Mute(bool on) { return false; }
diff --git a/third_party/libjingle/source/talk/session/phone/mediachannel.h b/third_party/libjingle/source/talk/session/phone/mediachannel.h
index 01bd8b5..bb17db2 100644
--- a/third_party/libjingle/source/talk/session/phone/mediachannel.h
+++ b/third_party/libjingle/source/talk/session/phone/mediachannel.h
@@ -38,12 +38,20 @@
// TODO: re-evaluate this include
#include "talk/session/phone/audiomonitor.h"
+namespace talk_base {
+class Buffer;
+}
+
namespace flute {
- class MagicCamVideoRenderer;
+class MagicCamVideoRenderer;
}
namespace cricket {
+const size_t kMinRtpPacketLen = 12;
+const size_t kMinRtcpPacketLen = 4;
+const size_t kMaxRtpPacketLen = 2048;
+
enum VoiceMediaChannelOptions {
OPT_CONFERENCE = 0x10000, // tune the audio stream for conference mode
OPT_ENERGYLEVEL = 0x20000, // include the energy level in RTP packets, as
@@ -53,6 +61,8 @@ enum VoiceMediaChannelOptions {
};
enum VideoMediaChannelOptions {
+ OPT_INTERPOLATE = 0x10000 // Increase the output framerate by 2x by
+ // interpolating frames
};
class MediaChannel : public sigslot::has_slots<> {
@@ -60,8 +70,8 @@ class MediaChannel : public sigslot::has_slots<> {
class NetworkInterface {
public:
enum SocketType { ST_RTP, ST_RTCP };
- virtual int SendPacket(const void *data, size_t len) = 0;
- virtual int SendRtcp(const void *data, size_t len) = 0;
+ virtual bool SendPacket(talk_base::Buffer* packet) = 0;
+ virtual bool SendRtcp(talk_base::Buffer* packet) = 0;
virtual int SetOption(SocketType type, talk_base::Socket::Option opt,
int option) = 0;
virtual ~NetworkInterface() {}
@@ -77,9 +87,9 @@ class MediaChannel : public sigslot::has_slots<> {
}
// Called when a RTP packet is received.
- virtual void OnPacketReceived(const void *data, int len) = 0;
+ virtual void OnPacketReceived(talk_base::Buffer* packet) = 0;
// Called when a RTCP packet is received.
- virtual void OnRtcpReceived(const void *data, int len) = 0;
+ virtual void OnRtcpReceived(talk_base::Buffer* packet) = 0;
// Sets the SSRC to be used for outgoing data.
virtual void SetSendSsrc(uint32 id) = 0;
// Set the CNAME of RTCP
@@ -101,28 +111,100 @@ enum SendFlags {
SEND_MICROPHONE
};
-struct MediaInfo {
- int fraction_lost;
- int cum_lost;
- int ext_max;
- int jitter;
- int RTT;
- int bytesSent;
- int packetsSent;
- int bytesReceived;
- int packetsReceived;
+struct VoiceSenderInfo {
+ uint32 ssrc;
+ int bytes_sent;
+ int packets_sent;
+ int packets_lost;
+ float fraction_lost;
+ int ext_seqnum;
+ int rtt_ms;
+ int jitter_ms;
+ int audio_level;
+};
+
+struct VoiceReceiverInfo {
+ uint32 ssrc;
+ int bytes_rcvd;
+ int packets_rcvd;
+ int packets_lost;
+ float fraction_lost;
+ int ext_seqnum;
+ int jitter_ms;
+ int audio_level;
};
-struct VoiceMediaInfo : MediaInfo {
+struct VideoSenderInfo {
+ uint32 ssrc;
+ int bytes_sent;
+ int packets_sent;
+ int packets_cached;
+ int packets_lost;
+ float fraction_lost;
+ int firs_rcvd;
+ int nacks_rcvd;
+ int rtt_ms;
+ int frame_width;
+ int frame_height;
+ int framerate_input;
+ int framerate_sent;
};
-struct VideoMediaInfo : MediaInfo {
- int receive_framerate;
- int send_framerate;
+struct VideoReceiverInfo {
+ uint32 ssrc;
+ int bytes_rcvd;
+ // vector<int> layer_bytes_rcvd;
+ int packets_rcvd;
+ int packets_lost;
+ int packets_concealed;
+ float fraction_lost;
+ int firs_sent;
+ int nacks_sent;
+ int frame_width;
+ int frame_height;
+ int framerate_rcvd;
+ int framerate_decoded;
+ int framerate_output;
+};
+
+struct VoiceMediaInfo {
+ void Clear() {
+ senders.clear();
+ receivers.clear();
+ }
+ std::vector<VoiceSenderInfo> senders;
+ std::vector<VoiceReceiverInfo> receivers;
+};
+
+struct VideoMediaInfo {
+ void Clear() {
+ senders.clear();
+ receivers.clear();
+ }
+ std::vector<VideoSenderInfo> senders;
+ std::vector<VideoReceiverInfo> receivers;
};
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.
@@ -149,6 +231,16 @@ class VoiceMediaChannel : public MediaChannel {
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.
@@ -195,7 +287,7 @@ class VideoFrame {
// nothing is written.
virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const = 0;
- // Converts the I420 data to RGB of a certain type such as BGRA and RGBA.
+ // Converts the I420 data to RGB of a certain type such as ARGB and ABGR.
// Returns the frame's actual size, regardless of whether it was written or
// not (like snprintf). Parameters size and pitch_rgb are in units of bytes.
// If there is insufficient space, nothing is written.
@@ -326,6 +418,18 @@ class NullVideoRenderer : public VideoRenderer {
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.
@@ -351,6 +455,7 @@ class VideoMediaChannel : public MediaChannel {
// Reuqest each of the remote senders to send an intra frame.
virtual bool RequestIntraFrame() = 0;
+ sigslot::signal2<uint32, Error> SignalMediaError;
protected:
VideoRenderer *renderer_;
diff --git a/third_party/libjingle/source/talk/session/phone/mediaengine.cc b/third_party/libjingle/source/talk/session/phone/mediaengine.cc
index 66eb18e..42b0954 100644
--- a/third_party/libjingle/source/talk/session/phone/mediaengine.cc
+++ b/third_party/libjingle/source/talk/session/phone/mediaengine.cc
@@ -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 --git a/third_party/libjingle/source/talk/session/phone/mediaengine.h b/third_party/libjingle/source/talk/session/phone/mediaengine.h
index c42e8ef..234a668 100644
--- a/third_party/libjingle/source/talk/session/phone/mediaengine.h
+++ b/third_party/libjingle/source/talk/session/phone/mediaengine.h
@@ -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 MediaEngine {
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 --git a/third_party/libjingle/source/talk/session/phone/mediamonitor.h b/third_party/libjingle/source/talk/session/phone/mediamonitor.h
index 9eda2aa..6b964aa 100644
--- a/third_party/libjingle/source/talk/session/phone/mediamonitor.h
+++ b/third_party/libjingle/source/talk/session/phone/mediamonitor.h
@@ -74,10 +74,8 @@ class MediaMonitorT : public MediaMonitor {
protected:
// These routines assume the crit_ lock is held by the calling thread.
virtual void GetStats() {
- media_info_.packetsReceived = -1;
- if (!media_channel_->GetStats(&media_info_)) {
- media_info_.packetsReceived = -1;
- }
+ media_info_.Clear();
+ media_channel_->GetStats(&media_info_);
}
virtual void Update() {
MI stats(media_info_);
diff --git a/third_party/libjingle/source/talk/session/phone/mediasessionclient.cc b/third_party/libjingle/source/talk/session/phone/mediasessionclient.cc
index f16b531..c862cd5 100644
--- a/third_party/libjingle/source/talk/session/phone/mediasessionclient.cc
+++ b/third_party/libjingle/source/talk/session/phone/mediasessionclient.cc
@@ -562,7 +562,7 @@ bool ParseGingleAudioContent(const buzz::XmlElement* content_elem,
audio->AddCodec(AudioCodec(0, "PCMU", 8000, 64000, 1, 0));
}
- ParseGingleSsrc(content_elem, QN_GINGLE_VIDEO_SRCID, audio);
+ ParseGingleSsrc(content_elem, QN_GINGLE_AUDIO_SRCID, audio);
if (!ParseGingleEncryption(content_elem, QN_GINGLE_AUDIO_CRYPTO_USAGE,
audio, error)) {
diff --git a/third_party/libjingle/source/talk/session/phone/rtpdump.cc b/third_party/libjingle/source/talk/session/phone/rtpdump.cc
index bd67cad..37d664b 100644
--- a/third_party/libjingle/source/talk/session/phone/rtpdump.cc
+++ b/third_party/libjingle/source/talk/session/phone/rtpdump.cc
@@ -30,6 +30,7 @@
#include <string>
#include "talk/base/bytebuffer.h"
+#include "talk/base/byteorder.h"
#include "talk/base/logging.h"
#include "talk/base/time.h"
@@ -55,13 +56,35 @@ void RtpDumpFileHeader::WriteToByteBuffer(talk_base::ByteBuffer* buf) {
}
// RTP packet format (http://www.networksorcery.com/enp/protocol/rtp.htm).
-static const int kRtpSeqNumOffset = 2;
-static const int kRtpSeqNumAndTimestampSize = 6;
+static const size_t kMinimumRtpHeaderSize = 12;
static const uint32 kDefaultTimeIncrease = 30;
bool RtpDumpPacket::IsValidRtpPacket() const {
- return !is_rtcp &&
- data.size() >= kRtpSeqNumOffset + kRtpSeqNumAndTimestampSize;
+ return !is_rtcp && data.size() >= kMinimumRtpHeaderSize;
+}
+
+bool RtpDumpPacket::GetRtpSeqNum(uint16* seq_num) const {
+ if (!seq_num || !IsValidRtpPacket()) {
+ return false;
+ }
+ *seq_num = talk_base::GetBE16(&data[2]);
+ return true;
+}
+
+bool RtpDumpPacket::GetRtpTimestamp(uint32* ts) const {
+ if (!ts || !IsValidRtpPacket()) {
+ return false;
+ }
+ *ts = talk_base::GetBE32(&data[4]);
+ return true;
+}
+
+bool RtpDumpPacket::GetRtpSsrc(uint32* ssrc) const {
+ if (!ssrc || !IsValidRtpPacket()) {
+ return false;
+ }
+ *ssrc = talk_base::GetBE32(&data[8]);
+ return true;
}
///////////////////////////////////////////////////////////////////////////
@@ -197,12 +220,11 @@ talk_base::StreamResult RtpDumpLoopReader::ReadPacket(RtpDumpPacket* packet) {
void RtpDumpLoopReader::UpdateStreamStatistics(const RtpDumpPacket& packet) {
// Get the RTP sequence number and timestamp of the dump packet.
uint16 rtp_seq_num = 0;
+ packet.GetRtpSeqNum(&rtp_seq_num);
uint32 rtp_timestamp = 0;
- if (packet.IsValidRtpPacket()) {
- ReadRtpSeqNumAndTimestamp(packet, &rtp_seq_num, &rtp_timestamp);
- }
+ packet.GetRtpTimestamp(&rtp_timestamp);
- // Get the timestamps and sequence number for the first dump packet.
+ // Set the timestamps and sequence number for the first dump packet.
if (0 == packet_count_++) {
first_elapsed_time_ = packet.elapsed_time;
first_rtp_seq_num_ = rtp_seq_num;
@@ -240,9 +262,10 @@ void RtpDumpLoopReader::UpdateDumpPacket(RtpDumpPacket* packet) {
if (packet->IsValidRtpPacket()) {
// Get the old RTP sequence number and timestamp.
- uint16 sequence;
- uint32 timestamp;
- ReadRtpSeqNumAndTimestamp(*packet, &sequence, &timestamp);
+ uint16 sequence = 0;
+ packet->GetRtpSeqNum(&sequence);
+ uint32 timestamp = 0;
+ packet->GetRtpTimestamp(&timestamp);
// Increase the RTP sequence number and timestamp.
sequence += loop_count_ * rtp_seq_num_increase_;
timestamp += loop_count_ * rtp_timestamp_increase_;
@@ -250,29 +273,27 @@ void RtpDumpLoopReader::UpdateDumpPacket(RtpDumpPacket* packet) {
talk_base::ByteBuffer buffer;
buffer.WriteUInt16(sequence);
buffer.WriteUInt32(timestamp);
- memcpy(&packet->data[0] + kRtpSeqNumOffset, buffer.Data(), buffer.Length());
+ memcpy(&packet->data[2], buffer.Data(), buffer.Length());
}
}
-void RtpDumpLoopReader::ReadRtpSeqNumAndTimestamp(
- const RtpDumpPacket& packet, uint16* sequence, uint32* timestamp) {
- talk_base::ByteBuffer buffer(
- reinterpret_cast<const char*>(&packet.data[0] + kRtpSeqNumOffset),
- kRtpSeqNumAndTimestampSize);
- buffer.ReadUInt16(sequence);
- buffer.ReadUInt32(timestamp);
-}
-
///////////////////////////////////////////////////////////////////////////
// Implementation of RtpDumpWriter.
///////////////////////////////////////////////////////////////////////////
+
+RtpDumpWriter::RtpDumpWriter(talk_base::StreamInterface* stream)
+ : stream_(stream),
+ file_header_written_(false),
+ start_time_ms_(talk_base::Time()) {
+ }
+
uint32 RtpDumpWriter::GetElapsedTime() const {
return talk_base::TimeSince(start_time_ms_);
}
talk_base::StreamResult RtpDumpWriter::WritePacket(
const void* data, size_t data_len, uint32 elapsed, bool rtcp) {
- if (!data || 0 == data_len) return talk_base::SR_ERROR;
+ if (!stream_ || !data || 0 == data_len) return talk_base::SR_ERROR;
talk_base::StreamResult res = talk_base::SR_SUCCESS;
// Write the file header if it has not been written yet.
diff --git a/third_party/libjingle/source/talk/session/phone/rtpdump.h b/third_party/libjingle/source/talk/session/phone/rtpdump.h
index 66275e6..f87b922 100644
--- a/third_party/libjingle/source/talk/session/phone/rtpdump.h
+++ b/third_party/libjingle/source/talk/session/phone/rtpdump.h
@@ -71,9 +71,12 @@ struct RtpDumpPacket {
memcpy(&data[0], d, s);
}
- // Check if the dumped packet is a valid RTP packet with the sequence number
- // and timestamp.
bool IsValidRtpPacket() const;
+ // Get the sequence number, timestampe, and SSRC of the RTP packet. Return
+ // true and set the output parameter if successful.
+ bool GetRtpSeqNum(uint16* seq_num) const;
+ bool GetRtpTimestamp(uint32* ts) const;
+ bool GetRtpSsrc(uint32* ssrc) const;
static const size_t kHeaderLength = 8;
uint32 elapsed_time; // Milliseconds since the start of recording.
@@ -121,10 +124,6 @@ class RtpDumpLoopReader : public RtpDumpReader {
virtual talk_base::StreamResult ReadPacket(RtpDumpPacket* packet);
private:
- // Read the sequence number and timestamp from the RTP dump packet.
- static void ReadRtpSeqNumAndTimestamp(const RtpDumpPacket& packet,
- uint16* seq_num, uint32* timestamp);
-
// During the first loop, update the statistics, including packet count, frame
// count, timestamps, and sequence number, of the input stream.
void UpdateStreamStatistics(const RtpDumpPacket& packet);
@@ -164,11 +163,8 @@ class RtpDumpLoopReader : public RtpDumpReader {
class RtpDumpWriter {
public:
- explicit RtpDumpWriter(talk_base::StreamInterface* stream)
- : stream_(stream),
- file_header_written_(false),
- start_time_ms_(0) {
- }
+ explicit RtpDumpWriter(talk_base::StreamInterface* stream);
+
// Write a RTP or RTCP packet. The parameters data points to the packet and
// data_len is its length.
talk_base::StreamResult WriteRtpPacket(const void* data, size_t data_len) {
diff --git a/third_party/libjingle/source/talk/session/phone/srtpfilter.cc b/third_party/libjingle/source/talk/session/phone/srtpfilter.cc
index f8d2dd4..71f1991 100644
--- a/third_party/libjingle/source/talk/session/phone/srtpfilter.cc
+++ b/third_party/libjingle/source/talk/session/phone/srtpfilter.cc
@@ -25,8 +25,22 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#undef HAVE_CONFIG_H // talk's config.h conflicts with the one included by the
- // libsrtp headers. Don't use it.
+// talk's config.h, generated from mac_config_dot_h for OSX, conflicts with the
+// one included by the libsrtp headers. Don't use it. Instead, we keep HAVE_SRTP
+// and LOGGING defined in config.h.
+#undef HAVE_CONFIG_H
+
+#ifdef OSX
+// TODO: For the XCode build, we force SRTP (b/2500074)
+#ifndef HAVE_SRTP
+#define HAVE_SRTP 1
+#endif // HAVE_SRTP
+// If LOGGING is not defined, define it to 1 (b/3245816)
+#ifndef LOGGING
+#define LOGGING 1
+#endif // HAVE_SRTP
+#endif
+
#include "talk/session/phone/srtpfilter.h"
#include <algorithm>
@@ -35,11 +49,6 @@
#include "talk/base/base64.h"
#include "talk/base/logging.h"
-// TODO: For the XCode build, we force SRTP (b/2500074)
-#if defined(OSX) && !defined(HAVE_SRTP)
-#define HAVE_SRTP 1
-#endif
-
// Enable this line to turn on SRTP debugging
// #define SRTP_DEBUG
@@ -113,6 +122,7 @@ bool SrtpFilter::SetAnswer(const std::vector<CryptoParams>& answer_params,
bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
if (!IsActive()) {
+ LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
return false;
}
return send_session_.ProtectRtp(p, in_len, max_len, out_len);
@@ -120,6 +130,7 @@ bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
bool SrtpFilter::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
if (!IsActive()) {
+ LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
return false;
}
return send_session_.ProtectRtcp(p, in_len, max_len, out_len);
@@ -127,6 +138,7 @@ bool SrtpFilter::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
bool SrtpFilter::UnprotectRtp(void* p, int in_len, int* out_len) {
if (!IsActive()) {
+ LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
return false;
}
return recv_session_.UnprotectRtp(p, in_len, out_len);
@@ -134,6 +146,7 @@ bool SrtpFilter::UnprotectRtp(void* p, int in_len, int* out_len) {
bool SrtpFilter::UnprotectRtcp(void* p, int in_len, int* out_len) {
if (!IsActive()) {
+ LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
return false;
}
return recv_session_.UnprotectRtcp(p, in_len, out_len);
@@ -190,6 +203,9 @@ bool SrtpFilter::ApplyParams(const CryptoParams& send_params,
if (ret) {
offer_params_.clear();
state_ = ST_ACTIVE;
+ LOG(LS_INFO) << "SRTP activated with negotiated parameters:"
+ << " send cipher_suite " << send_params.cipher_suite
+ << " recv cipher_suite " << recv_params.cipher_suite;
} else {
LOG(LS_WARNING) << "Failed to apply negotiated SRTP parameters";
}
@@ -199,6 +215,7 @@ bool SrtpFilter::ApplyParams(const CryptoParams& send_params,
bool SrtpFilter::ResetParams() {
offer_params_.clear();
state_ = ST_INIT;
+ LOG(LS_INFO) << "SRTP reset to init state";
return true;
}
@@ -252,11 +269,18 @@ bool SrtpSession::SetRecv(const std::string& cs, const uint8* key, int len) {
}
bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
- if (!session_)
+ if (!session_) {
+ LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session";
return false;
+ }
+
int need_len = in_len + rtp_auth_tag_len_; // NOLINT
- if (max_len < need_len)
+ if (max_len < need_len) {
+ LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length "
+ << max_len << " is less than the needed " << need_len;
return false;
+ }
+
*out_len = in_len;
int err = srtp_protect(session_, p, out_len);
if (err != err_status_ok) {
@@ -267,11 +291,18 @@ bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
}
bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
- if (!session_)
+ if (!session_) {
+ LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session";
return false;
+ }
+
int need_len = in_len + sizeof(uint32) + rtcp_auth_tag_len_; // NOLINT
- if (max_len < need_len)
+ if (max_len < need_len) {
+ LOG(LS_WARNING) << "Failed to protect SRTCP packet: The buffer length "
+ << max_len << " is less than the needed " << need_len;
return false;
+ }
+
*out_len = in_len;
int err = srtp_protect_rtcp(session_, p, out_len);
if (err != err_status_ok) {
@@ -282,8 +313,11 @@ bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
}
bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) {
- if (!session_)
+ if (!session_) {
+ LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session";
return false;
+ }
+
*out_len = in_len;
int err = srtp_unprotect(session_, p, out_len);
if (err != err_status_ok) {
@@ -294,8 +328,11 @@ bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) {
}
bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
- if (!session_)
+ if (!session_) {
+ LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session";
return false;
+ }
+
*out_len = in_len;
int err = srtp_unprotect_rtcp(session_, p, out_len);
if (err != err_status_ok) {
@@ -308,6 +345,8 @@ bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
bool SrtpSession::SetKey(int type, const std::string& cs,
const uint8* key, int len) {
if (session_) {
+ LOG(LS_ERROR) << "Failed to create SRTP session: "
+ << "SRTP session already created";
return false;
}
@@ -325,10 +364,13 @@ bool SrtpSession::SetKey(int type, const std::string& cs,
crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); // rtp is 32,
crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // rtcp still 80
} else {
+ LOG(LS_WARNING) << "Failed to create SRTP session: unsupported"
+ << " cipher_suite " << cs.c_str();
return false;
}
if (!key || len != SRTP_MASTER_KEY_LEN) {
+ LOG(LS_WARNING) << "Failed to create SRTP session: invalid key";
return false;
}
@@ -376,7 +418,23 @@ bool SrtpSession::Init() {
}
void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
- // TODO: Do something about events.
+ switch (ev->event) {
+ case event_ssrc_collision:
+ LOG(LS_INFO) << "SRTP event: SSRC collision";
+ break;
+ case event_key_soft_limit:
+ LOG(LS_INFO) << "SRTP event: reached soft key usage limit";
+ break;
+ case event_key_hard_limit:
+ LOG(LS_INFO) << "SRTP event: reached hard key usage limit";
+ break;
+ case event_packet_index_limit:
+ LOG(LS_INFO) << "SRTP event: reached hard packet limit (2^48 packets)";
+ break;
+ default:
+ LOG(LS_INFO) << "SRTP event: unknown " << ev->event;
+ break;
+ }
}
void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) {
diff --git a/third_party/libjingle/source/talk/session/phone/testdata/video.rtpdump b/third_party/libjingle/source/talk/session/phone/testdata/video.rtpdump
index 3b0139b..7be863e 100644
--- a/third_party/libjingle/source/talk/session/phone/testdata/video.rtpdump
+++ b/third_party/libjingle/source/talk/session/phone/testdata/video.rtpdump
Binary files differ
diff --git a/third_party/libjingle/source/talk/session/phone/testdata/voice.rtpdump b/third_party/libjingle/source/talk/session/phone/testdata/voice.rtpdump
index 5920d1d..8f0ec15 100644
--- a/third_party/libjingle/source/talk/session/phone/testdata/voice.rtpdump
+++ b/third_party/libjingle/source/talk/session/phone/testdata/voice.rtpdump
Binary files differ
diff --git a/third_party/libjingle/source/talk/session/phone/videocommon.h b/third_party/libjingle/source/talk/session/phone/videocommon.h
index 230b1ff..4fb311a 100644
--- a/third_party/libjingle/source/talk/session/phone/videocommon.h
+++ b/third_party/libjingle/source/talk/session/phone/videocommon.h
@@ -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 fourcc) {
// 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 RGBA
- 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 --git a/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc b/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc
index 0448853..b5e6397 100644
--- a/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc
+++ b/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.cc
@@ -198,6 +198,26 @@ void PseudoTcpChannel::OnSessionTerminate(Session* session) {
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 --git a/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.h b/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.h
index fbcb611..e7ff8f0 100644
--- a/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.h
+++ b/third_party/libjingle/source/talk/session/tunnel/pseudotcpchannel.h
@@ -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 --git a/third_party/libjingle/source/talk/site_scons/talk.py b/third_party/libjingle/source/talk/site_scons/talk.py
index b9e93ef..09e4dd9 100644
--- a/third_party/libjingle/source/talk/site_scons/talk.py
+++ b/third_party/libjingle/source/talk/site_scons/talk.py
@@ -185,7 +185,7 @@ def ExpandSconsPath(path):
def AddMediaLibs(env, **kwargs):
- lmi_libdir = '$GOOGLE3/third_party/lmi/files/merged/lib/'
+ lmi_libdir = '$GOOGLE3/../googleclient/third_party/lmi/files/lib/'
if env.Bit('windows'):
if env.get('COVERAGE_ENABLED'):
lmi_libdir += 'win32/c_only'
@@ -194,20 +194,11 @@ def AddMediaLibs(env, **kwargs):
elif env.Bit('mac'):
lmi_libdir += 'macos'
elif env.Bit('linux'):
- lmi_libdir += 'linux/x86'
-
- ipp_libdir = '$GOOGLE3/third_party/Intel_ipp/%s/ia32/lib'
- if env.Bit('windows'):
- ipp_libdir %= 'v_5_2_windows'
- elif env.Bit('mac'):
- ipp_libdir %= 'v_5_3_mac_os_x'
- elif env.Bit('linux'):
- ipp_libdir %= 'v_5_2_linux'
+ lmi_libdir += 'linux/x86'
AddToDict(kwargs, 'libdirs', [
'$MAIN_DIR/third_party/gips/Libraries/',
- ipp_libdir,
lmi_libdir,
])
@@ -220,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', [
@@ -253,14 +244,6 @@ def AddMediaLibs(env, **kwargs):
'LmiUtils',
'LmiVideoCommon',
'LmiXml',
- 'ippsmerged',
- 'ippsemerged',
- 'ippvcmerged',
- 'ippvcemerged',
- 'ippimerged',
- 'ippiemerged',
- 'ippsrmerged',
- 'ippsremerged',
])
if env.Bit('windows'):
@@ -268,32 +251,21 @@ def AddMediaLibs(env, **kwargs):
'dsound',
'd3d9',
'gdi32',
- 'ippcorel',
- 'ippscmerged',
- 'ippscemerged',
'strmiids',
])
- else:
- AddToDict(kwargs, 'libs', [
- 'ippcore',
- 'ippacmerged',
- 'ippacemerged',
- 'ippccmerged',
- 'ippccemerged',
- 'ippchmerged',
- 'ippchemerged',
- 'ippcvmerged',
- 'ippcvemerged',
- 'ippdcmerged',
- 'ippdcemerged',
- 'ippjmerged',
- 'ippjemerged',
- 'ippmmerged',
- 'ippmemerged',
- 'ipprmerged',
- 'ippremerged',
- ])
+ if env.Bit('mac'):
+ AddToDict(kwargs, 'FRAMEWORKS', [
+ 'AudioToolbox',
+ 'AudioUnit',
+ 'Cocoa',
+ 'CoreAudio',
+ 'CoreFoundation',
+ 'IOKit',
+ 'QTKit',
+ 'QuickTime',
+ 'QuartzCore',
+ ])
return kwargs
@@ -387,10 +359,9 @@ def MergeAndFilterByPlatform(env, params):
# only build 32 bit. For 32 bit debian installer a 32 bit host is required.
# ChromeOS (linux) ebuild don't support 64 bit and requires 32 bit build only
# for now.
-# TODO: Detect ChromeOS chroot board for ChromeOS x64 build.
def Allow64BitCompile(env):
- return (env.Bit('linux') and env.Bit('platform_arch_64bit') and
- not env.Bit('linux_chromeos'))
+ return (env.Bit('linux') and env.Bit('platform_arch_64bit')
+ )
def MergeSettingsFromLibraryDependencies(env, params):
if params.has_key('libs'):
@@ -465,9 +436,13 @@ def ExtendComponent(env, component, **kwargs):
'libs' : 'LIBS',
'FRAMEWORKS' : 'FRAMEWORKS',
}
- prepends = {
- 'ccflags' : 'CCFLAGS',
- }
+ prepends = {}
+ if env.Bit('windows'):
+ # MSVC compile flags have precedence at the beginning ...
+ prepends['ccflags'] = 'CCFLAGS'
+ else:
+ # ... while GCC compile flags have precedence at the end
+ appends['ccflags'] = 'CCFLAGS'
if GetEntry(params, 'prepend_includedirs'):
prepends['includedirs'] = 'CPPPATH'
else:
diff --git a/third_party/modp_b64/LICENSE.html b/third_party/modp_b64/LICENSE.html
deleted file mode 100644
index e156351..0000000
--- a/third_party/modp_b64/LICENSE.html
+++ /dev/null
@@ -1,296 +0,0 @@
-
-
-
-
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<!-- ViewVC :: http://www.viewvc.org/ -->
-<head>
-<title>[chrome] Log of /trunk/src/third_party/modp_b64/LICENSE</title>
-<meta name="generator" content="ViewVC 1.0.9" />
-<link rel="stylesheet" href="/viewvc/*docroot*/styles.css" type="text/css" />
-
-</head>
-<body>
-<div class="vc_navheader">
-
-<form method="get" action="/viewvc/">
-
-<table style="padding:0.1em;">
-<tr>
-<td>
-<strong>
-
-<a href="/viewvc/chrome/?pathrev=74924">
-
-[chrome]</a>
-/
-
-<a href="/viewvc/chrome/trunk/?pathrev=74924">
-
-trunk</a>
-/
-
-<a href="/viewvc/chrome/trunk/src/?pathrev=74924">
-
-src</a>
-/
-
-<a href="/viewvc/chrome/trunk/src/third_party/?pathrev=74924">
-
-third_party</a>
-/
-
-<a href="/viewvc/chrome/trunk/src/third_party/modp_b64/?pathrev=74924">
-
-modp_b64</a>
-/
-
-
-
-LICENSE
-
-
-</strong>
-
-</td>
-<td style="text-align:right;">
-
-
-<strong>Repository:</strong>
-<select name="root" onchange="submit()">
-
-
-<option value="*viewroots*">Repository Listing</option>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<optgroup label="Subversion Repositories"><option selected="selected">chrome</option><option>native_client</option></optgroup>
-
-</select>
-<input type="submit" value="Go" />
-
-</td>
-</tr>
-</table>
-
-</form>
-
-</div>
-<div style="float: right; padding: 5px;"><a href="http://www.viewvc.org/"><img src="/viewvc/*docroot*/images/logo.png" alt="ViewVC logotype" width="128" height="48" /></a></div>
-<h1>Log of /trunk/src/third_party/modp_b64/LICENSE</h1>
-
-<p style="margin:0;">
-
-<a href="/viewvc/chrome/trunk/src/third_party/modp_b64/?pathrev=74924"><img src="/viewvc/*docroot*/images/back_small.png" width="16" height="16" alt="Parent Directory" /> Parent Directory</a>
-
-
-
-
-</p>
-
-<hr />
-<table class="auto">
-
-
-
-<tr>
-<td>Links to HEAD:</td>
-<td>
-(<a href="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE?view=markup">view</a>)
-(<a href="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE">download</a>)
-
-(<a href="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE?view=annotate">annotate</a>)
-</td>
-</tr>
-
-
-
-<tr>
-<td>Sticky Revision:</td>
-<td><form method="get" action="/viewvc/chrome" style="display: inline">
-<div style="display: inline">
-<input type="hidden" name="orig_pathrev" value="74924" /><input type="hidden" name="orig_pathtype" value="FILE" /><input type="hidden" name="orig_view" value="log" /><input type="hidden" name="orig_path" value="trunk/src/third_party/modp_b64/LICENSE" /><input type="hidden" name="view" value="redirect_pathrev" />
-
-<input type="text" name="pathrev" value="74924" size="6"/>
-
-<input type="submit" value="Set" />
-</div>
-</form>
-
-<form method="get" action="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE" style="display: inline">
-<div style="display: inline">
-<input type="hidden" name="view" value="log" />
-
-<input type="submit" value="Clear" />
-
-</div>
-</form>
-
-</td>
-</tr>
-</table>
-
-
-
-
-
-
-
-
-
-<div>
-<hr />
-
-<a name="rev44656"></a>
-
-
-Revision <a href="/viewvc/chrome?view=rev&amp;revision=44656"><strong>44656</strong></a> -
-
-(<a href="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE?revision=44656&amp;view=markup&amp;pathrev=74924">view</a>)
-
-(<a href="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE?revision=44656&amp;pathrev=74924">download</a>)
-
-(<a href="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE?annotate=44656&amp;pathrev=74924">annotate</a>)
-
-
-
-- <a href="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE?view=log&amp;r1=44656&amp;pathrev=74924">[select for diffs]</a>
-
-
-
-
-<br />
-
-Added
-
-<em>Thu Apr 15 15:29:44 2010 UTC</em> (13 months, 2 weeks ago) by <em>evan@chromium.org</em>
-
-
-
-
-
-
-
-<br />File length: 1721 byte(s)
-
-
-
-
-
-
-
-
-
-
-<pre class="vc_log">Pass tools/licenses.py for more directories.
-
-We're now down to only 4 dirs that don't pass the license checker.
-They will require separate changes.
-
-Modify the license checker to only print failing dirs.
-
-BUG=39240
-
-Review URL: <a href="http://codereview.chromium.org/1530040">http://codereview.chromium.org/1530040</a></pre>
-</div>
-
-
-
-
-
- <hr />
-<p><a name="diff"></a>
-This form allows you to request diffs between any two revisions of this file.
-For each of the two "sides" of the diff,
-
-enter a numeric revision.
-
-</p>
-<form method="get" action="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE" id="diff_select">
-<table cellpadding="2" cellspacing="0" class="auto">
-<tr>
-<td>&nbsp;</td>
-<td>
-<input type="hidden" name="pathrev" value="74924" /><input type="hidden" name="view" value="diff" />
-Diffs between
-
-<input type="text" size="12" name="r1"
-value="44656" />
-
-and
-
-<input type="text" size="12" name="r2" value="44656" />
-
-</td>
-</tr>
-<tr>
-<td>&nbsp;</td>
-<td>
-Type of Diff should be a
-<select name="diff_format" onchange="submit()">
-<option value="h" selected="selected">Colored Diff</option>
-<option value="l" >Long Colored Diff</option>
-<option value="u" >Unidiff</option>
-<option value="c" >Context Diff</option>
-<option value="s" >Side by Side</option>
-</select>
-<input type="submit" value=" Get Diffs " />
-</td>
-</tr>
-</table>
-</form>
-
-
-<form method="get" action="/viewvc/chrome/trunk/src/third_party/modp_b64/LICENSE">
-<div>
-<hr />
-<a name="logsort"></a>
-<input type="hidden" name="view" value="log" /><input type="hidden" name="pathrev" value="74924" />
-Sort log by:
-<select name="logsort" onchange="submit()">
-<option value="cvs" >Not sorted</option>
-<option value="date" selected="selected">Commit date</option>
-<option value="rev" >Revision</option>
-</select>
-<input type="submit" value=" Sort " />
-</div>
-</form>
-
-
-<hr />
-<table>
-<tr>
-<td><address><a href="mailto:cvs-admin@insert.your.domain.here">No admin address has been configured</a></address></td>
-<td style="text-align: right;"><strong><a href="/viewvc/*docroot*/help_log.html">ViewVC Help</a></strong></td>
-</tr>
-<tr>
-<td>Powered by <a href="http://viewvc.tigris.org/">ViewVC 1.0.9</a></td>
-<td style="text-align: right;">&nbsp;</td>
-</tr>
-</table>
-</body>
-</html>
-
-
diff --git a/third_party/modp_b64/README.chromium b/third_party/modp_b64/README.chromium
index 16588b5..fc30450 100644
--- a/third_party/modp_b64/README.chromium
+++ b/third_party/modp_b64/README.chromium
@@ -1,9 +1,8 @@
Name: modp base64 decoder
-Short Name: stringencoders
-URL: http://code.google.com/p/stringencoders/
-Version: unknown
+URL: http://modp.com/release/base64/
+
+See the header of modp_b64.cc for the license terms.
-Description:
The modp_b64.c file was modified to remove the inclusion of modp's config.h
and to fix compilation errors that occur under VC8. The file was renamed
modp_b64.cc to force it to be compiled as C++ so that the inclusion of
diff --git a/third_party/modp_b64/modp_b64.gyp b/third_party/modp_b64/modp_b64.gyp
index 1c346e0..4ed34f4 100644
--- a/third_party/modp_b64/modp_b64.gyp
+++ b/third_party/modp_b64/modp_b64.gyp
@@ -6,7 +6,7 @@
'targets': [
{
'target_name': 'modp_b64',
- 'type': 'static_library',
+ 'type': '<(library)',
'msvs_guid': '7100F41F-868D-4E99-80A2-AF8E6574749D',
'sources': [
'modp_b64.cc',