diff --git a/talk/app/webrtc/java/jni/peerconnection_jni.cc b/talk/app/webrtc/java/jni/peerconnection_jni.cc index 6b7e8c1357..12ac8c6d9c 100644 --- a/talk/app/webrtc/java/jni/peerconnection_jni.cc +++ b/talk/app/webrtc/java/jni/peerconnection_jni.cc @@ -581,7 +581,7 @@ class DataChannelObserverWrapper : public DataChannelObserver { void OnMessage(const DataBuffer& buffer) override { ScopedLocalRefFrame local_ref_frame(jni()); jobject byte_buffer = jni()->NewDirectByteBuffer( - const_cast(buffer.data.data()), buffer.data.size()); + const_cast(buffer.data.data()), buffer.data.size()); jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_, byte_buffer, buffer.binary); jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer); diff --git a/talk/app/webrtc/objc/RTCDataChannel.mm b/talk/app/webrtc/objc/RTCDataChannel.mm index 239695ac70..94d22d2595 100644 --- a/talk/app/webrtc/objc/RTCDataChannel.mm +++ b/talk/app/webrtc/objc/RTCDataChannel.mm @@ -141,7 +141,8 @@ std::string StdStringFromNSString(NSString* nsString) { - (instancetype)initWithData:(NSData*)data isBinary:(BOOL)isBinary { NSAssert(data, @"data cannot be nil"); if (self = [super init]) { - rtc::Buffer buffer([data bytes], [data length]); + rtc::Buffer buffer(reinterpret_cast([data bytes]), + [data length]); _dataBuffer.reset(new webrtc::DataBuffer(buffer, isBinary)); } return self; diff --git a/talk/app/webrtc/sctputils.cc b/talk/app/webrtc/sctputils.cc index 8aa902f84e..21174c3e48 100644 --- a/talk/app/webrtc/sctputils.cc +++ b/talk/app/webrtc/sctputils.cc @@ -54,8 +54,7 @@ bool ParseDataChannelOpenMessage(const rtc::Buffer& payload, // Format defined at // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04 - rtc::ByteBuffer buffer(payload.data(), payload.size()); - + rtc::ByteBuffer buffer(payload); uint8 message_type; if (!buffer.ReadUInt8(&message_type)) { LOG(LS_WARNING) << "Could not read OPEN message type."; @@ -126,8 +125,7 @@ bool ParseDataChannelOpenMessage(const rtc::Buffer& payload, } bool ParseDataChannelOpenAckMessage(const rtc::Buffer& payload) { - rtc::ByteBuffer buffer(payload.data(), payload.size()); - + rtc::ByteBuffer buffer(payload); uint8 message_type; if (!buffer.ReadUInt8(&message_type)) { LOG(LS_WARNING) << "Could not read OPEN_ACK message type."; diff --git a/talk/app/webrtc/test/mockpeerconnectionobservers.h b/talk/app/webrtc/test/mockpeerconnectionobservers.h index 40e9001dba..f31b16c744 100644 --- a/talk/app/webrtc/test/mockpeerconnectionobservers.h +++ b/talk/app/webrtc/test/mockpeerconnectionobservers.h @@ -100,7 +100,7 @@ class MockDataChannelObserver : public webrtc::DataChannelObserver { virtual void OnStateChange() { state_ = channel_->state(); } virtual void OnMessage(const DataBuffer& buffer) { - last_message_.assign(buffer.data.data(), buffer.data.size()); + last_message_.assign(buffer.data.data(), buffer.data.size()); ++received_message_count_; } diff --git a/talk/media/base/fakemediaengine.h b/talk/media/base/fakemediaengine.h index 9dffff26b8..7deaed735f 100644 --- a/talk/media/base/fakemediaengine.h +++ b/talk/media/base/fakemediaengine.h @@ -73,11 +73,13 @@ template class RtpHelper : public Base { if (!sending_) { return false; } - rtc::Buffer packet(data, len, kMaxRtpPacketLen); + rtc::Buffer packet(reinterpret_cast(data), len, + kMaxRtpPacketLen); return Base::SendPacket(&packet); } bool SendRtcp(const void* data, int len) { - rtc::Buffer packet(data, len, kMaxRtpPacketLen); + rtc::Buffer packet(reinterpret_cast(data), len, + kMaxRtpPacketLen); return Base::SendRtcp(&packet); } @@ -193,11 +195,11 @@ template class RtpHelper : public Base { void set_playout(bool playout) { playout_ = playout; } virtual void OnPacketReceived(rtc::Buffer* packet, const rtc::PacketTime& packet_time) { - rtp_packets_.push_back(std::string(packet->data(), packet->size())); + rtp_packets_.push_back(std::string(packet->data(), packet->size())); } virtual void OnRtcpReceived(rtc::Buffer* packet, const rtc::PacketTime& packet_time) { - rtcp_packets_.push_back(std::string(packet->data(), packet->size())); + rtcp_packets_.push_back(std::string(packet->data(), packet->size())); } virtual void OnReadyToSend(bool ready) { ready_to_send_ = ready; @@ -686,7 +688,7 @@ class FakeDataMediaChannel : public RtpHelper { return false; } else { last_sent_data_params_ = params; - last_sent_data_ = std::string(payload.data(), payload.size()); + last_sent_data_ = std::string(payload.data(), payload.size()); return true; } } diff --git a/talk/media/base/filemediaengine.cc b/talk/media/base/filemediaengine.cc index 1c26568993..0fc8d5610b 100644 --- a/talk/media/base/filemediaengine.cc +++ b/talk/media/base/filemediaengine.cc @@ -276,7 +276,8 @@ bool RtpSenderReceiver::SendRtpPacket(const void* data, size_t len) { if (!media_channel_) return false; - rtc::Buffer packet(data, len, kMaxRtpPacketLen); + rtc::Buffer packet(reinterpret_cast(data), len, + kMaxRtpPacketLen); return media_channel_->SendPacket(&packet); } diff --git a/talk/media/base/rtpdataengine.cc b/talk/media/base/rtpdataengine.cc index 923b25476f..8cc4dac458 100644 --- a/talk/media/base/rtpdataengine.cc +++ b/talk/media/base/rtpdataengine.cc @@ -231,7 +231,8 @@ void RtpDataMediaChannel::OnPacketReceived( // << packet->length() << "."; return; } - const char* data = packet->data() + header_length + sizeof(kReservedSpace); + const char* data = + packet->data() + header_length + sizeof(kReservedSpace); size_t data_len = packet->size() - header_length - sizeof(kReservedSpace); if (!receiving_) { @@ -337,14 +338,12 @@ bool RtpDataMediaChannel::SendData( rtp_clock_by_send_ssrc_[header.ssrc]->Tick( now, &header.seq_num, &header.timestamp); - rtc::Buffer packet; - packet.SetCapacity(packet_len); - packet.SetSize(kMinRtpPacketLen); + rtc::Buffer packet(kMinRtpPacketLen, packet_len); if (!SetRtpHeader(packet.data(), packet.size(), header)) { return false; } - packet.AppendData(&kReservedSpace, sizeof(kReservedSpace)); - packet.AppendData(payload.data(), payload.size()); + packet.AppendData(kReservedSpace); + packet.AppendData(payload); LOG(LS_VERBOSE) << "Sent RTP data packet: " << " stream=" << found_stream->id << " ssrc=" << header.ssrc diff --git a/talk/media/base/rtpdataengine_unittest.cc b/talk/media/base/rtpdataengine_unittest.cc index 0cd1b2a1bd..3682320433 100644 --- a/talk/media/base/rtpdataengine_unittest.cc +++ b/talk/media/base/rtpdataengine_unittest.cc @@ -144,7 +144,7 @@ class RtpDataMediaChannelTest : public testing::Test { rtc::scoped_ptr packet( iface_->GetRtpPacket(index)); if (packet->size() > 12) { - return std::string(packet->data() + 12, packet->size() - 12); + return std::string(packet->data() + 12, packet->size() - 12); } else { return ""; } diff --git a/talk/media/base/videoengine_unittest.h b/talk/media/base/videoengine_unittest.h index 1c759f4ec1..90db020abe 100644 --- a/talk/media/base/videoengine_unittest.h +++ b/talk/media/base/videoengine_unittest.h @@ -670,7 +670,7 @@ class VideoMediaChannelTest : public testing::Test, static bool ParseRtpPacket(const rtc::Buffer* p, bool* x, int* pt, int* seqnum, uint32* tstamp, uint32* ssrc, std::string* payload) { - rtc::ByteBuffer buf(p->data(), p->size()); + rtc::ByteBuffer buf(*p); uint8 u08 = 0; uint16 u16 = 0; uint32 u32 = 0; @@ -730,7 +730,7 @@ class VideoMediaChannelTest : public testing::Test, int count = 0; for (int i = start_index; i < stop_index; ++i) { rtc::scoped_ptr p(GetRtcpPacket(i)); - rtc::ByteBuffer buf(p->data(), p->size()); + rtc::ByteBuffer buf(*p); size_t total_len = 0; // The packet may be a compound RTCP packet. while (total_len < p->size()) { diff --git a/talk/media/sctp/sctpdataengine.cc b/talk/media/sctp/sctpdataengine.cc index d801035b02..5312d86d5c 100644 --- a/talk/media/sctp/sctpdataengine.cc +++ b/talk/media/sctp/sctpdataengine.cc @@ -186,8 +186,8 @@ static int OnSctpOutboundPacket(void* addr, void* data, size_t length, << "; tos: " << std::hex << static_cast(tos) << "; set_df: " << std::hex << static_cast(set_df); // Note: We have to copy the data; the caller will delete it. - OutboundPacketMessage* msg = - new OutboundPacketMessage(new rtc::Buffer(data, length)); + auto* msg = new OutboundPacketMessage( + new rtc::Buffer(reinterpret_cast(data), length)); channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg); return 0; } @@ -214,7 +214,7 @@ static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr, << " on an SCTP packet. Dropping."; } else { SctpInboundPacket* packet = new SctpInboundPacket; - packet->buffer.SetData(data, length); + packet->buffer.SetData(reinterpret_cast(data), length); packet->params.ssrc = rcv.rcv_sid; packet->params.seq_num = rcv.rcv_ssn; packet->params.timestamp = rcv.rcv_tsn; @@ -630,7 +630,7 @@ void SctpDataMediaChannel::OnDataFromSctpToChannel( << " on stream " << params.ssrc; // Reports all received messages to upper layers, no matter whether the sid // is known. - SignalDataReceived(params, buffer->data(), buffer->size()); + SignalDataReceived(params, buffer->data(), buffer->size()); } else { LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): " << "Not receiving packet with sid=" << params.ssrc diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc index 24b6bb64f4..090ad75e23 100644 --- a/talk/media/webrtc/webrtcvideoengine.cc +++ b/talk/media/webrtc/webrtcvideoengine.cc @@ -4123,14 +4123,16 @@ void WebRtcVideoMediaChannel::OnMessage(rtc::Message* msg) { int WebRtcVideoMediaChannel::SendPacket(int channel, const void* data, size_t len) { - rtc::Buffer packet(data, len, kMaxRtpPacketLen); + rtc::Buffer packet(reinterpret_cast(data), len, + kMaxRtpPacketLen); return MediaChannel::SendPacket(&packet) ? static_cast(len) : -1; } int WebRtcVideoMediaChannel::SendRTCPPacket(int channel, const void* data, size_t len) { - rtc::Buffer packet(data, len, kMaxRtpPacketLen); + rtc::Buffer packet(reinterpret_cast(data), len, + kMaxRtpPacketLen); return MediaChannel::SendRtcp(&packet) ? static_cast(len) : -1; } diff --git a/talk/media/webrtc/webrtcvoiceengine.h b/talk/media/webrtc/webrtcvoiceengine.h index ffbace5f0d..56665de7ba 100644 --- a/talk/media/webrtc/webrtcvoiceengine.h +++ b/talk/media/webrtc/webrtcvoiceengine.h @@ -313,12 +313,14 @@ class WebRtcMediaChannel : public T, public webrtc::Transport { protected: // implements Transport interface int SendPacket(int channel, const void* data, size_t len) override { - rtc::Buffer packet(data, len, kMaxRtpPacketLen); + rtc::Buffer packet(reinterpret_cast(data), len, + kMaxRtpPacketLen); return T::SendPacket(&packet) ? static_cast(len) : -1; } int SendRTCPPacket(int channel, const void* data, size_t len) override { - rtc::Buffer packet(data, len, kMaxRtpPacketLen); + rtc::Buffer packet(reinterpret_cast(data), len, + kMaxRtpPacketLen); return T::SendRtcp(&packet) ? static_cast(len) : -1; } diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc index 789502377c..f0e450328a 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc @@ -168,7 +168,7 @@ class WebRtcVoiceEngineTestFake : public testing::Test { EXPECT_EQ(0, voe_.GetLocalSSRC(default_channel_num, default_send_ssrc)); } void DeliverPacket(const void* data, int len) { - rtc::Buffer packet(data, len); + rtc::Buffer packet(reinterpret_cast(data), len); channel_->OnPacketReceived(&packet, rtc::PacketTime()); } virtual void TearDown() { diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc index 0750537eab..ab6cb2e8e4 100644 --- a/talk/session/media/channel.cc +++ b/talk/session/media/channel.cc @@ -478,7 +478,7 @@ bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet, // 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); + data->packet = packet->Pass(); data->dscp = dscp; worker_thread_->Post(this, message_id, data); return true; @@ -512,7 +512,7 @@ bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet, // Protect if needed. if (srtp_filter_.IsActive()) { bool res; - char* data = packet->data(); + uint8_t* data = packet->data(); int len = static_cast(packet->size()); if (!rtcp) { // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done @@ -584,7 +584,7 @@ bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet, // Bon voyage. int ret = - channel->SendPacket(packet->data(), packet->size(), options, + channel->SendPacket(packet->data(), packet->size(), options, (secure() && secure_dtls()) ? PF_SRTP_BYPASS : 0); if (ret != static_cast(packet->size())) { if (channel->GetError() == EWOULDBLOCK) { @@ -606,7 +606,7 @@ bool BaseChannel::WantsPacket(bool rtcp, rtc::Buffer* packet) { } // Bundle filter handles both rtp and rtcp packets. - return bundle_filter_.DemuxPacket(packet->data(), packet->size(), rtcp); + return bundle_filter_.DemuxPacket(packet->data(), packet->size(), rtcp); } void BaseChannel::HandlePacket(bool rtcp, rtc::Buffer* packet, @@ -630,7 +630,7 @@ void BaseChannel::HandlePacket(bool rtcp, rtc::Buffer* packet, // Unprotect the packet, if needed. if (srtp_filter_.IsActive()) { - char* data = packet->data(); + char* data = packet->data(); int len = static_cast(packet->size()); bool res; if (!rtcp) { diff --git a/talk/session/media/srtpfilter.cc b/talk/session/media/srtpfilter.cc index a49b037734..dc93dd463d 100644 --- a/talk/session/media/srtpfilter.cc +++ b/talk/session/media/srtpfilter.cc @@ -36,6 +36,7 @@ #include "talk/media/base/rtputils.h" #include "webrtc/base/base64.h" #include "webrtc/base/byteorder.h" +#include "webrtc/base/common.h" #include "webrtc/base/logging.h" #include "webrtc/base/stringencode.h" #include "webrtc/base/timeutils.h" diff --git a/webrtc/base/BUILD.gn b/webrtc/base/BUILD.gn index 5201a69bef..9168d162c3 100644 --- a/webrtc/base/BUILD.gn +++ b/webrtc/base/BUILD.gn @@ -103,6 +103,8 @@ static_library("rtc_base_approved") { public_configs = [ "..:common_inherited_config" ] sources = [ + "buffer.cc", + "buffer.h", "checks.cc", "checks.h", "event.cc", @@ -177,8 +179,6 @@ static_library("rtc_base") { "base64.cc", "base64.h", "basicdefs.h", - "buffer.cc", - "buffer.h", "bytebuffer.cc", "bytebuffer.h", "byteorder.h", diff --git a/webrtc/base/base.gyp b/webrtc/base/base.gyp index 0c1ecfa4f0..c767a9a8cd 100644 --- a/webrtc/base/base.gyp +++ b/webrtc/base/base.gyp @@ -29,6 +29,8 @@ 'target_name': 'rtc_base_approved', 'type': 'static_library', 'sources': [ + 'buffer.cc', + 'buffer.h', 'checks.cc', 'checks.h', 'event.cc', @@ -100,8 +102,6 @@ 'basictypes.h', 'bind.h', 'bind.h.pump', - 'buffer.cc', - 'buffer.h', 'bytebuffer.cc', 'bytebuffer.h', 'byteorder.h', diff --git a/webrtc/base/buffer.cc b/webrtc/base/buffer.cc index 227a3b25b8..90e687bbb6 100644 --- a/webrtc/base/buffer.cc +++ b/webrtc/base/buffer.cc @@ -10,28 +10,34 @@ #include "webrtc/base/buffer.h" +#include + namespace rtc { -Buffer::Buffer() { - Construct(NULL, 0, 0); +Buffer::Buffer() : size_(0), capacity_(0), data_(nullptr) { + assert(IsConsistent()); } -Buffer::Buffer(size_t size) : Buffer() { - SetSize(size); +Buffer::Buffer(const Buffer& buf) : Buffer(buf.data(), buf.size()) { } -Buffer::Buffer(const void* data, size_t size) { - Construct(data, size, size); +Buffer::Buffer(Buffer&& buf) + : size_(buf.size()), capacity_(buf.capacity()), data_(buf.data_.Pass()) { + assert(IsConsistent()); + buf.OnMovedFrom(); } -Buffer::Buffer(const void* data, size_t size, size_t capacity) { - Construct(data, size, capacity); +Buffer::Buffer(size_t size) : Buffer(size, size) { } -Buffer::Buffer(const Buffer& buf) { - Construct(buf.data(), buf.size(), buf.size()); +Buffer::Buffer(size_t size, size_t capacity) + : size_(size), + capacity_(std::max(size, capacity)), + data_(new uint8_t[capacity_]) { + assert(IsConsistent()); } +// Note: The destructor works even if the buffer has been moved from. Buffer::~Buffer() = default; }; // namespace rtc diff --git a/webrtc/base/buffer.h b/webrtc/base/buffer.h index c7fb959942..5880f50c94 100644 --- a/webrtc/base/buffer.h +++ b/webrtc/base/buffer.h @@ -11,83 +11,215 @@ #ifndef WEBRTC_BASE_BUFFER_H_ #define WEBRTC_BASE_BUFFER_H_ -#include - -#include "webrtc/base/common.h" +#include // std::swap (pre-C++11) +#include +#include +#include // std::swap (C++11 and later) #include "webrtc/base/scoped_ptr.h" namespace rtc { +namespace internal { + +// (Internal; please don't use outside this file.) ByteType::t is int if T +// is uint8_t, int8_t, or char; otherwise, it's a compilation error. Use like +// this: +// +// template ::t = 0> +// void foo(T* x); +// +// to let foo be defined only for byte-sized integers. +template +struct ByteType { + private: + static int F(uint8_t*); + static int F(int8_t*); + static int F(char*); + + public: + using t = decltype(F(static_cast(nullptr))); +}; + +} // namespace internal + // Basic buffer class, can be grown and shrunk dynamically. // Unlike std::string/vector, does not initialize data when expanding capacity. -class Buffer { +class Buffer final { public: - Buffer(); + Buffer(); // An empty buffer. + Buffer(const Buffer& buf); // Copy size and contents of an existing buffer. + Buffer(Buffer&& buf); // Move contents from an existing buffer. + + // Construct a buffer with the specified number of uninitialized bytes. explicit Buffer(size_t size); - Buffer(const void* data, size_t size); - Buffer(const void* data, size_t size, size_t capacity); - Buffer(const Buffer& buf); + Buffer(size_t size, size_t capacity); + + // Construct a buffer and copy the specified number of bytes into it. The + // source array may be (const) uint8_t*, int8_t*, or char*. + template ::t = 0> + Buffer(const T* data, size_t size) + : Buffer(data, size, size) {} + template ::t = 0> + Buffer(const T* data, size_t size, size_t capacity) + : Buffer(size, capacity) { + std::memcpy(data_.get(), data, size); + } + + // Construct a buffer from the contents of an array. + template ::t = 0> + Buffer(const T(&array)[N]) + : Buffer(array, N) {} + ~Buffer(); - const char* data() const { return data_.get(); } - char* data() { return data_.get(); } - size_t size() const { return size_; } - size_t capacity() const { return capacity_; } + // Get a pointer to the data. Just .data() will give you a (const) char*, + // but you may also use .data() and .data(). + // TODO(kwiberg): Change default to uint8_t + template ::t = 0> + const T* data() const { + assert(IsConsistent()); + return reinterpret_cast(data_.get()); + } + template ::t = 0> + T* data() { + assert(IsConsistent()); + return reinterpret_cast(data_.get()); + } + + size_t size() const { + assert(IsConsistent()); + return size_; + } + size_t capacity() const { + assert(IsConsistent()); + return capacity_; + } Buffer& operator=(const Buffer& buf) { - if (&buf != this) { - Construct(buf.data(), buf.size(), buf.size()); - } + if (&buf != this) + SetData(buf.data(), buf.size()); return *this; } - bool operator==(const Buffer& buf) const { - return (size_ == buf.size() && memcmp(data_.get(), buf.data(), size_) == 0); - } - bool operator!=(const Buffer& buf) const { - return !operator==(buf); + Buffer& operator=(Buffer&& buf) { + assert(IsConsistent()); + assert(buf.IsConsistent()); + size_ = buf.size_; + capacity_ = buf.capacity_; + data_ = buf.data_.Pass(); + buf.OnMovedFrom(); + return *this; } - void SetData(const void* data, size_t size) { - ASSERT(data != NULL || size == 0); - SetSize(size); - memcpy(data_.get(), data, size); + bool operator==(const Buffer& buf) const { + assert(IsConsistent()); + return size_ == buf.size() && memcmp(data_.get(), buf.data(), size_) == 0; } - void AppendData(const void* data, size_t size) { - ASSERT(data != NULL || size == 0); - size_t old_size = size_; - SetSize(size_ + size); - memcpy(data_.get() + old_size, data, size); + + bool operator!=(const Buffer& buf) const { return !(*this == buf); } + + // Replace the contents of the buffer. Accepts the same types as the + // constructors. + template ::t = 0> + void SetData(const T* data, size_t size) { + assert(IsConsistent()); + size_ = 0; + AppendData(data, size); } + template ::t = 0> + void SetData(const T(&array)[N]) { + SetData(array, N); + } + void SetData(const Buffer& buf) { SetData(buf.data(), buf.size()); } + + // Append data to the buffer. Accepts the same types as the constructors. + template ::t = 0> + void AppendData(const T* data, size_t size) { + assert(IsConsistent()); + const size_t new_size = size_ + size; + EnsureCapacity(new_size); + std::memcpy(data_.get() + size_, data, size); + size_ = new_size; + assert(IsConsistent()); + } + template ::t = 0> + void AppendData(const T(&array)[N]) { + AppendData(array, N); + } + void AppendData(const Buffer& buf) { AppendData(buf.data(), buf.size()); } + + // Sets the size of the buffer. If the new size is smaller than the old, the + // buffer contents will be kept but truncated; if the new size is greater, + // the existing contents will be kept and the new space will be + // uninitialized. void SetSize(size_t size) { - SetCapacity(size); + EnsureCapacity(size); size_ = size; } - void SetCapacity(size_t capacity) { - if (capacity > capacity_) { - rtc::scoped_ptr data(new char[capacity]); - memcpy(data.get(), data_.get(), size_); - data_.swap(data); - capacity_ = capacity; - } + + // Ensure that the buffer size can be increased to at least capacity without + // further reallocation. (Of course, this operation might need to reallocate + // the buffer.) + void EnsureCapacity(size_t capacity) { + assert(IsConsistent()); + if (capacity <= capacity_) + return; + scoped_ptr new_data(new uint8_t[capacity]); + std::memcpy(new_data.get(), data_.get(), size_); + data_ = new_data.Pass(); + capacity_ = capacity; + assert(IsConsistent()); } - void TransferTo(Buffer* buf) { - ASSERT(buf != NULL); - buf->data_.reset(data_.release()); - buf->size_ = size_; - buf->capacity_ = capacity_; - Construct(NULL, 0, 0); + // We can't call std::move(b), so call b.Pass() instead to do the same job. + Buffer&& Pass() { + assert(IsConsistent()); + return static_cast(*this); } - protected: - void Construct(const void* data, size_t size, size_t capacity) { - data_.reset(new char[capacity_ = capacity]); - SetData(data, size); + // Resets the buffer to zero size and capacity. Works even if the buffer has + // been moved from. + void Clear() { + data_.reset(); + size_ = 0; + capacity_ = 0; + assert(IsConsistent()); + } + + // Swaps two buffers. Also works for buffers that have been moved from. + friend void swap(Buffer& a, Buffer& b) { + using std::swap; + swap(a.size_, b.size_); + swap(a.capacity_, b.capacity_); + swap(a.data_, b.data_); + } + + private: + // Precondition for all methods except Clear and the destructor. + // Postcondition for all methods except move construction and move + // assignment, which leave the moved-from object in a possibly inconsistent + // state. + bool IsConsistent() const { + return (data_ || capacity_ == 0) && capacity_ >= size_; + } + + // Called when *this has been moved from. Conceptually it's a no-op, but we + // can mutate the state slightly to help subsequent sanity checks catch bugs. + void OnMovedFrom() { +#ifdef NDEBUG + // Make *this consistent and empty. Shouldn't be necessary, but better safe + // than sorry. + size_ = 0; + capacity_ = 0; +#else + // Ensure that *this is always inconsistent, to provoke bugs. + size_ = 1; + capacity_ = 0; +#endif } - scoped_ptr data_; size_t size_; size_t capacity_; + scoped_ptr data_; }; } // namespace rtc diff --git a/webrtc/base/buffer_unittest.cc b/webrtc/base/buffer_unittest.cc index 632ca81240..963209c94b 100644 --- a/webrtc/base/buffer_unittest.cc +++ b/webrtc/base/buffer_unittest.cc @@ -11,47 +11,65 @@ #include "webrtc/base/buffer.h" #include "webrtc/base/gunit.h" +#include // std::swap (pre-C++11) +#include // std::swap (C++11 and later) + namespace rtc { -static const char kTestData[] = { - 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF -}; +namespace { -TEST(BufferTest, TestConstructDefault) { - Buffer buf; - EXPECT_EQ(0U, buf.size()); - EXPECT_EQ(0U, buf.capacity()); - EXPECT_EQ(Buffer(), buf); +// clang-format off +const uint8_t kTestData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; +// clang-format on + +void TestBuf(const Buffer& b1, size_t size, size_t capacity) { + EXPECT_EQ(b1.size(), size); + EXPECT_EQ(b1.capacity(), capacity); } -TEST(BufferTest, TestConstructEmptyWithCapacity) { - Buffer buf(NULL, 0, 256U); - EXPECT_EQ(0U, buf.size()); - EXPECT_EQ(256U, buf.capacity()); - EXPECT_EQ(Buffer(), buf); +} // namespace + +TEST(BufferTest, TestConstructEmpty) { + TestBuf(Buffer(), 0, 0); + TestBuf(Buffer(Buffer()), 0, 0); + TestBuf(Buffer(0), 0, 0); + + // We can't use a literal 0 for the first argument, because C++ will allow + // that to be considered a null pointer, which makes the call ambiguous. + TestBuf(Buffer(0 + 0, 10), 0, 10); + + TestBuf(Buffer(kTestData, 0), 0, 0); + TestBuf(Buffer(kTestData, 0, 20), 0, 20); } TEST(BufferTest, TestConstructData) { - Buffer buf(kTestData, sizeof(kTestData)); - EXPECT_EQ(sizeof(kTestData), buf.size()); - EXPECT_EQ(sizeof(kTestData), buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData))); - EXPECT_EQ(Buffer(kTestData, sizeof(kTestData)), buf); + Buffer buf(kTestData, 7); + EXPECT_EQ(buf.size(), 7u); + EXPECT_EQ(buf.capacity(), 7u); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 7)); } TEST(BufferTest, TestConstructDataWithCapacity) { - Buffer buf(kTestData, sizeof(kTestData), 256U); - EXPECT_EQ(sizeof(kTestData), buf.size()); - EXPECT_EQ(256U, buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData))); - EXPECT_EQ(Buffer(kTestData, sizeof(kTestData)), buf); + Buffer buf(kTestData, 7, 14); + EXPECT_EQ(buf.size(), 7u); + EXPECT_EQ(buf.capacity(), 14u); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 7)); +} + +TEST(BufferTest, TestConstructArray) { + Buffer buf(kTestData); + EXPECT_EQ(buf.size(), 16u); + EXPECT_EQ(buf.capacity(), 16u); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 16)); } TEST(BufferTest, TestConstructCopy) { - Buffer buf1(kTestData, sizeof(kTestData), 256), buf2(buf1); - EXPECT_EQ(sizeof(kTestData), buf2.size()); - EXPECT_EQ(sizeof(kTestData), buf2.capacity()); // capacity isn't copied - EXPECT_EQ(0, memcmp(buf2.data(), kTestData, sizeof(kTestData))); + Buffer buf1(kTestData), buf2(buf1); + EXPECT_EQ(buf2.size(), 16u); + EXPECT_EQ(buf2.capacity(), 16u); + EXPECT_EQ(0, memcmp(buf2.data(), kTestData, 16)); + EXPECT_NE(buf1.data(), buf2.data()); EXPECT_EQ(buf1, buf2); } @@ -59,85 +77,104 @@ TEST(BufferTest, TestAssign) { Buffer buf1, buf2(kTestData, sizeof(kTestData), 256); EXPECT_NE(buf1, buf2); buf1 = buf2; - EXPECT_EQ(sizeof(kTestData), buf1.size()); - EXPECT_EQ(sizeof(kTestData), buf1.capacity()); // capacity isn't copied - EXPECT_EQ(0, memcmp(buf1.data(), kTestData, sizeof(kTestData))); EXPECT_EQ(buf1, buf2); + EXPECT_NE(buf1.data(), buf2.data()); } TEST(BufferTest, TestSetData) { - Buffer buf; - buf.SetData(kTestData, sizeof(kTestData)); - EXPECT_EQ(sizeof(kTestData), buf.size()); - EXPECT_EQ(sizeof(kTestData), buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData))); + Buffer buf(kTestData + 4, 7); + buf.SetData(kTestData, 9); + EXPECT_EQ(buf.size(), 9u); + EXPECT_EQ(buf.capacity(), 9u); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 9)); } TEST(BufferTest, TestAppendData) { - Buffer buf(kTestData, sizeof(kTestData)); - buf.AppendData(kTestData, sizeof(kTestData)); - EXPECT_EQ(2 * sizeof(kTestData), buf.size()); - EXPECT_EQ(2 * sizeof(kTestData), buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData))); - EXPECT_EQ(0, memcmp(buf.data() + sizeof(kTestData), - kTestData, sizeof(kTestData))); + Buffer buf(kTestData + 4, 3); + buf.AppendData(kTestData + 10, 2); + const int8_t exp[] = {0x4, 0x5, 0x6, 0xa, 0xb}; + EXPECT_EQ(buf, Buffer(exp)); } TEST(BufferTest, TestSetSizeSmaller) { Buffer buf; - buf.SetData(kTestData, sizeof(kTestData)); - buf.SetSize(sizeof(kTestData) / 2); - EXPECT_EQ(sizeof(kTestData) / 2, buf.size()); - EXPECT_EQ(sizeof(kTestData), buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData) / 2)); + buf.SetData(kTestData, 15); + buf.SetSize(10); + EXPECT_EQ(buf.size(), 10u); + EXPECT_EQ(buf.capacity(), 15u); // Hasn't shrunk. + EXPECT_EQ(buf, Buffer(kTestData, 10)); } TEST(BufferTest, TestSetSizeLarger) { Buffer buf; - buf.SetData(kTestData, sizeof(kTestData)); - buf.SetSize(sizeof(kTestData) * 2); - EXPECT_EQ(sizeof(kTestData) * 2, buf.size()); - EXPECT_EQ(sizeof(kTestData) * 2, buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData))); + buf.SetData(kTestData, 15); + EXPECT_EQ(buf.size(), 15u); + EXPECT_EQ(buf.capacity(), 15u); + buf.SetSize(20); + EXPECT_EQ(buf.size(), 20u); + EXPECT_EQ(buf.capacity(), 20u); // Has grown. + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 15)); } -TEST(BufferTest, TestSetCapacitySmaller) { - Buffer buf; - buf.SetData(kTestData, sizeof(kTestData)); - buf.SetCapacity(sizeof(kTestData) / 2); // should be ignored - EXPECT_EQ(sizeof(kTestData), buf.size()); - EXPECT_EQ(sizeof(kTestData), buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData))); +TEST(BufferTest, TestEnsureCapacitySmaller) { + Buffer buf(kTestData); + const char* data = buf.data(); + buf.EnsureCapacity(4); + EXPECT_EQ(buf.capacity(), 16u); // Hasn't shrunk. + EXPECT_EQ(buf.data(), data); // No reallocation. + EXPECT_EQ(buf, Buffer(kTestData)); } -TEST(BufferTest, TestSetCapacityLarger) { - Buffer buf(kTestData, sizeof(kTestData)); - buf.SetCapacity(sizeof(kTestData) * 2); - EXPECT_EQ(sizeof(kTestData), buf.size()); - EXPECT_EQ(sizeof(kTestData) * 2, buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData))); +TEST(BufferTest, TestEnsureCapacityLarger) { + Buffer buf(kTestData, 5); + buf.EnsureCapacity(10); + const int8_t* data = buf.data(); + EXPECT_EQ(buf.capacity(), 10u); + buf.AppendData(kTestData + 5, 5); + EXPECT_EQ(buf.data(), data); // No reallocation. + EXPECT_EQ(buf, Buffer(kTestData, 10)); } -TEST(BufferTest, TestSetCapacityThenSetSize) { - Buffer buf(kTestData, sizeof(kTestData)); - buf.SetCapacity(sizeof(kTestData) * 4); - memcpy(buf.data() + sizeof(kTestData), kTestData, sizeof(kTestData)); - buf.SetSize(sizeof(kTestData) * 2); - EXPECT_EQ(sizeof(kTestData) * 2, buf.size()); - EXPECT_EQ(sizeof(kTestData) * 4, buf.capacity()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData))); - EXPECT_EQ(0, memcmp(buf.data() + sizeof(kTestData), - kTestData, sizeof(kTestData))); +TEST(BufferTest, TestMoveConstruct) { + Buffer buf1(kTestData, 3, 40); + const uint8_t* data = buf1.data(); + Buffer buf2(buf1.Pass()); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 40u); + EXPECT_EQ(buf2.data(), data); + buf1.Clear(); + EXPECT_EQ(buf1.size(), 0u); + EXPECT_EQ(buf1.capacity(), 0u); + EXPECT_EQ(buf1.data(), nullptr); } -TEST(BufferTest, TestTransfer) { - Buffer buf1(kTestData, sizeof(kTestData), 256U), buf2; - buf1.TransferTo(&buf2); - EXPECT_EQ(0U, buf1.size()); - EXPECT_EQ(0U, buf1.capacity()); - EXPECT_EQ(sizeof(kTestData), buf2.size()); - EXPECT_EQ(256U, buf2.capacity()); // capacity does transfer - EXPECT_EQ(0, memcmp(buf2.data(), kTestData, sizeof(kTestData))); +TEST(BufferTest, TestMoveAssign) { + Buffer buf1(kTestData, 3, 40); + const uint8_t* data = buf1.data(); + Buffer buf2(kTestData); + buf2 = buf1.Pass(); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 40u); + EXPECT_EQ(buf2.data(), data); + buf1.Clear(); + EXPECT_EQ(buf1.size(), 0u); + EXPECT_EQ(buf1.capacity(), 0u); + EXPECT_EQ(buf1.data(), nullptr); +} + +TEST(BufferTest, TestSwap) { + Buffer buf1(kTestData, 3); + Buffer buf2(kTestData, 6, 40); + uint8_t* data1 = buf1.data(); + uint8_t* data2 = buf2.data(); + using std::swap; + swap(buf1, buf2); + EXPECT_EQ(buf1.size(), 6u); + EXPECT_EQ(buf1.capacity(), 40u); + EXPECT_EQ(buf1.data(), data2); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 3u); + EXPECT_EQ(buf2.data(), data1); } } // namespace rtc diff --git a/webrtc/base/bytebuffer.cc b/webrtc/base/bytebuffer.cc index d2aa4cfd6f..4b6a1d8d62 100644 --- a/webrtc/base/bytebuffer.cc +++ b/webrtc/base/bytebuffer.cc @@ -42,6 +42,10 @@ ByteBuffer::ByteBuffer(const char* bytes) { Construct(bytes, strlen(bytes), ORDER_NETWORK); } +ByteBuffer::ByteBuffer(const Buffer& buf) { + Construct(buf.data(), buf.size(), ORDER_NETWORK); +} + void ByteBuffer::Construct(const char* bytes, size_t len, ByteOrder byte_order) { version_ = 0; diff --git a/webrtc/base/bytebuffer.h b/webrtc/base/bytebuffer.h index 1934f418e5..c4632f50b7 100644 --- a/webrtc/base/bytebuffer.h +++ b/webrtc/base/bytebuffer.h @@ -14,6 +14,7 @@ #include #include "webrtc/base/basictypes.h" +#include "webrtc/base/buffer.h" #include "webrtc/base/constructormagic.h" namespace rtc { @@ -35,6 +36,8 @@ class ByteBuffer { // Initializes buffer from a zero-terminated string. explicit ByteBuffer(const char* bytes); + explicit ByteBuffer(const Buffer& buf); + ~ByteBuffer(); const char* Data() const { return bytes_ + start_; } diff --git a/webrtc/base/fakesslidentity.h b/webrtc/base/fakesslidentity.h index 71a42d545b..7926580e7b 100644 --- a/webrtc/base/fakesslidentity.h +++ b/webrtc/base/fakesslidentity.h @@ -14,6 +14,7 @@ #include #include +#include "webrtc/base/common.h" #include "webrtc/base/messagedigest.h" #include "webrtc/base/sslidentity.h" diff --git a/webrtc/base/opensslidentity.cc b/webrtc/base/opensslidentity.cc index 39ae22a463..7aa99467fc 100644 --- a/webrtc/base/opensslidentity.cc +++ b/webrtc/base/opensslidentity.cc @@ -285,7 +285,7 @@ std::string OpenSSLCertificate::ToPEMString() const { void OpenSSLCertificate::ToDER(Buffer* der_buffer) const { // In case of failure, make sure to leave the buffer empty. - der_buffer->SetData(NULL, 0); + der_buffer->SetSize(0); // Calculates the DER representation of the certificate, from scratch. BIO* bio = BIO_new(BIO_s_mem()); diff --git a/webrtc/base/scoped_ptr.h b/webrtc/base/scoped_ptr.h index 36ca3269e9..02fa15d745 100644 --- a/webrtc/base/scoped_ptr.h +++ b/webrtc/base/scoped_ptr.h @@ -598,13 +598,13 @@ class scoped_ptr { template bool operator!=(scoped_ptr const& p2) const; }; -} // namespace rtc - template void swap(rtc::scoped_ptr& p1, rtc::scoped_ptr& p2) { p1.swap(p2); } +} // namespace rtc + template bool operator==(T* p1, const rtc::scoped_ptr& p2) { return p1 == p2.get(); diff --git a/webrtc/base/sslfingerprint.cc b/webrtc/base/sslfingerprint.cc index d45e7a068b..a6101810b7 100644 --- a/webrtc/base/sslfingerprint.cc +++ b/webrtc/base/sslfingerprint.cc @@ -79,7 +79,7 @@ bool SSLFingerprint::operator==(const SSLFingerprint& other) const { std::string SSLFingerprint::GetRfc4572Fingerprint() const { std::string fingerprint = - rtc::hex_encode_with_delimiter(digest.data(), digest.size(), ':'); + rtc::hex_encode_with_delimiter(digest.data(), digest.size(), ':'); std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(), ::toupper); return fingerprint; diff --git a/webrtc/base/sslfingerprint.h b/webrtc/base/sslfingerprint.h index a63b3dd875..355c6bae6d 100644 --- a/webrtc/base/sslfingerprint.h +++ b/webrtc/base/sslfingerprint.h @@ -13,6 +13,7 @@ #include +#include "webrtc/base/basictypes.h" #include "webrtc/base/buffer.h" #include "webrtc/base/sslidentity.h" diff --git a/webrtc/base/stream.cc b/webrtc/base/stream.cc index 0fdb1fcd83..5e9dc04a28 100644 --- a/webrtc/base/stream.cc +++ b/webrtc/base/stream.cc @@ -755,7 +755,7 @@ StreamResult AsyncWriteStream::Write(const void* data, size_t data_len, { CritScope cs(&crit_buffer_); previous_buffer_length = buffer_.size(); - buffer_.AppendData(data, data_len); + buffer_.AppendData(reinterpret_cast(data), data_len); } if (previous_buffer_length == 0) { @@ -790,7 +790,8 @@ void AsyncWriteStream::ClearBufferAndWrite() { Buffer to_write; { CritScope cs_buffer(&crit_buffer_); - buffer_.TransferTo(&to_write); + to_write = buffer_.Pass(); + buffer_.Clear(); } if (to_write.size() > 0) { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index 8a85fbe361..07fc5e347d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -79,8 +79,9 @@ class LoopbackTransportTest : public webrtc::Transport { } int SendPacket(int channel, const void *data, size_t len) override { packets_sent_++; - rtc::Buffer* buffer = new rtc::Buffer(data, len); - last_sent_packet_ = reinterpret_cast(buffer->data()); + rtc::Buffer* buffer = + new rtc::Buffer(reinterpret_cast(data), len); + last_sent_packet_ = buffer->data(); last_sent_packet_len_ = len; total_bytes_sent_ += len; sent_packets_.push_back(buffer); diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc index 6c853c14f7..438840827b 100644 --- a/webrtc/p2p/base/dtlstransportchannel.cc +++ b/webrtc/p2p/base/dtlstransportchannel.cc @@ -209,7 +209,7 @@ bool DtlsTransportChannelWrapper::SetRemoteFingerprint( } // At this point we know we are doing DTLS - remote_fingerprint_value.TransferTo(&remote_fingerprint_value_); + remote_fingerprint_value_ = remote_fingerprint_value.Pass(); remote_fingerprint_algorithm_ = digest_alg; if (!SetupDtls()) { diff --git a/webrtc/p2p/base/fakesession.h b/webrtc/p2p/base/fakesession.h index 5d07d2558f..a197885ecd 100644 --- a/webrtc/p2p/base/fakesession.h +++ b/webrtc/p2p/base/fakesession.h @@ -213,8 +213,8 @@ class FakeTransportChannel : public TransportChannelImpl, virtual void OnMessage(rtc::Message* msg) { PacketMessageData* data = static_cast( msg->pdata); - dest_->SignalReadPacket(dest_, data->packet.data(), data->packet.size(), - rtc::CreatePacketTime(0), 0); + dest_->SignalReadPacket(dest_, data->packet.data(), + data->packet.size(), rtc::CreatePacketTime(0), 0); delete data; } diff --git a/webrtc/p2p/base/transportdescription.cc b/webrtc/p2p/base/transportdescription.cc index 01c6a8f071..52033ec9c3 100644 --- a/webrtc/p2p/base/transportdescription.cc +++ b/webrtc/p2p/base/transportdescription.cc @@ -10,8 +10,9 @@ #include "webrtc/p2p/base/transportdescription.h" -#include "webrtc/p2p/base/constants.h" +#include "webrtc/base/basicdefs.h" #include "webrtc/base/stringutils.h" +#include "webrtc/p2p/base/constants.h" namespace cricket {