1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/network/p2p/socket_tcp.h"
6
7 #include <stddef.h>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/sys_byteorder.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "jingle/glue/fake_ssl_client_socket.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/socket/client_socket_factory.h"
18 #include "net/socket/client_socket_handle.h"
19 #include "net/socket/ssl_client_socket.h"
20 #include "net/socket/tcp_client_socket.h"
21 #include "services/network/proxy_resolving_client_socket.h"
22 #include "services/network/proxy_resolving_client_socket_factory.h"
23 #include "services/network/public/cpp/p2p_param_traits.h"
24 #include "third_party/webrtc/media/base/rtp_utils.h"
25 #include "url/gurl.h"
26
27 namespace network {
28 namespace {
29
30 typedef uint16_t PacketLength;
31 const int kPacketHeaderSize = sizeof(PacketLength);
32 const int kTcpReadBufferSize = 4096;
33 const int kPacketLengthOffset = 2;
34 const int kTurnChannelDataHeaderSize = 4;
35 const int kTcpRecvSocketBufferSize = 128 * 1024;
36 const int kTcpSendSocketBufferSize = 128 * 1024;
37
IsTlsClientSocket(P2PSocketType type)38 bool IsTlsClientSocket(P2PSocketType type) {
39 return (type == P2P_SOCKET_STUN_TLS_CLIENT || type == P2P_SOCKET_TLS_CLIENT);
40 }
41
IsPseudoTlsClientSocket(P2PSocketType type)42 bool IsPseudoTlsClientSocket(P2PSocketType type) {
43 return (type == P2P_SOCKET_SSLTCP_CLIENT ||
44 type == P2P_SOCKET_STUN_SSLTCP_CLIENT);
45 }
46
47 } // namespace
48
SendBuffer()49 P2PSocketTcp::SendBuffer::SendBuffer() : rtc_packet_id(-1) {}
SendBuffer(int32_t rtc_packet_id,scoped_refptr<net::DrainableIOBuffer> buffer,const net::NetworkTrafficAnnotationTag traffic_annotation)50 P2PSocketTcp::SendBuffer::SendBuffer(
51 int32_t rtc_packet_id,
52 scoped_refptr<net::DrainableIOBuffer> buffer,
53 const net::NetworkTrafficAnnotationTag traffic_annotation)
54 : rtc_packet_id(rtc_packet_id),
55 buffer(buffer),
56 traffic_annotation(traffic_annotation) {}
57 P2PSocketTcp::SendBuffer::SendBuffer(const SendBuffer& rhs) = default;
58 P2PSocketTcp::SendBuffer::~SendBuffer() = default;
59
P2PSocketTcpBase(Delegate * delegate,mojo::PendingRemote<mojom::P2PSocketClient> client,mojo::PendingReceiver<mojom::P2PSocket> socket,P2PSocketType type,ProxyResolvingClientSocketFactory * proxy_resolving_socket_factory)60 P2PSocketTcpBase::P2PSocketTcpBase(
61 Delegate* delegate,
62 mojo::PendingRemote<mojom::P2PSocketClient> client,
63 mojo::PendingReceiver<mojom::P2PSocket> socket,
64 P2PSocketType type,
65 ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory)
66 : P2PSocket(delegate, std::move(client), std::move(socket), P2PSocket::TCP),
67 type_(type),
68 proxy_resolving_socket_factory_(proxy_resolving_socket_factory) {}
69
70 P2PSocketTcpBase::~P2PSocketTcpBase() = default;
71
InitAccepted(const net::IPEndPoint & remote_address,std::unique_ptr<net::StreamSocket> socket)72 void P2PSocketTcpBase::InitAccepted(const net::IPEndPoint& remote_address,
73 std::unique_ptr<net::StreamSocket> socket) {
74 DCHECK(socket);
75 remote_address_.ip_address = remote_address;
76 // TODO(ronghuawu): Add FakeSSLServerSocket.
77 socket_ = std::move(socket);
78 DoRead();
79 }
80
Init(const net::IPEndPoint & local_address,uint16_t min_port,uint16_t max_port,const P2PHostAndIPEndPoint & remote_address)81 void P2PSocketTcpBase::Init(const net::IPEndPoint& local_address,
82 uint16_t min_port,
83 uint16_t max_port,
84 const P2PHostAndIPEndPoint& remote_address) {
85 DCHECK(!socket_);
86
87 remote_address_ = remote_address;
88
89 net::HostPortPair dest_host_port_pair;
90 // If there is a domain name, let's try it first, it's required by some proxy
91 // to only take hostname for CONNECT. If it has been DNS resolved, the result
92 // is likely cached and shouldn't cause 2nd DNS resolution in the case of
93 // direct connect (i.e. no proxy).
94 if (!remote_address.hostname.empty()) {
95 dest_host_port_pair = net::HostPortPair(remote_address.hostname,
96 remote_address.ip_address.port());
97 } else {
98 DCHECK(!remote_address.ip_address.address().empty());
99 dest_host_port_pair =
100 net::HostPortPair::FromIPEndPoint(remote_address.ip_address);
101 }
102
103 // TODO(mallinath) - We are ignoring local_address altogether. We should
104 // find a way to inject this into ProxyResolvingClientSocket. This could be
105 // a problem on multi-homed host.
106
107 socket_ = proxy_resolving_socket_factory_->CreateSocket(
108 GURL("https://" + dest_host_port_pair.ToString()),
109 IsTlsClientSocket(type_));
110
111 if (IsPseudoTlsClientSocket(type_)) {
112 socket_ =
113 std::make_unique<jingle_glue::FakeSSLClientSocket>(std::move(socket_));
114 }
115
116 int status = socket_->Connect(
117 base::BindOnce(&P2PSocketTcpBase::OnConnected, base::Unretained(this)));
118 if (status != net::ERR_IO_PENDING)
119 OnConnected(status);
120 }
121
OnConnected(int result)122 void P2PSocketTcpBase::OnConnected(int result) {
123 DCHECK_NE(result, net::ERR_IO_PENDING);
124
125 if (result != net::OK) {
126 LOG(WARNING) << "Error from connecting socket, result=" << result;
127 OnError();
128 return;
129 }
130
131 OnOpen();
132 }
133
OnOpen()134 void P2PSocketTcpBase::OnOpen() {
135 // Setting socket send and receive buffer size.
136 if (net::OK != socket_->SetReceiveBufferSize(kTcpRecvSocketBufferSize)) {
137 LOG(WARNING) << "Failed to set socket receive buffer size to "
138 << kTcpRecvSocketBufferSize;
139 }
140
141 if (net::OK != socket_->SetSendBufferSize(kTcpSendSocketBufferSize)) {
142 LOG(WARNING) << "Failed to set socket send buffer size to "
143 << kTcpSendSocketBufferSize;
144 }
145
146 if (!DoSendSocketCreateMsg())
147 return;
148
149 DoRead();
150 }
151
DoSendSocketCreateMsg()152 bool P2PSocketTcpBase::DoSendSocketCreateMsg() {
153 DCHECK(socket_.get());
154
155 net::IPEndPoint local_address;
156 int result = socket_->GetLocalAddress(&local_address);
157 if (result < 0) {
158 LOG(ERROR) << "P2PSocketTcpBase::OnConnected: unable to get local"
159 << " address: " << result;
160 OnError();
161 return false;
162 }
163
164 VLOG(1) << "Local address: " << local_address.ToString();
165
166 net::IPEndPoint remote_address;
167
168 // GetPeerAddress returns ERR_NAME_NOT_RESOLVED if the socket is connected
169 // through a proxy.
170 result = socket_->GetPeerAddress(&remote_address);
171 if (result < 0 && result != net::ERR_NAME_NOT_RESOLVED) {
172 LOG(ERROR) << "P2PSocketTcpBase::OnConnected: unable to get peer"
173 << " address: " << result;
174 OnError();
175 return false;
176 }
177
178 if (!remote_address.address().empty()) {
179 VLOG(1) << "Remote address: " << remote_address.ToString();
180 if (remote_address_.ip_address.address().empty()) {
181 // Save |remote_address| if address is empty.
182 remote_address_.ip_address = remote_address;
183 }
184 } else {
185 VLOG(1) << "Remote address is unknown since connection is proxied";
186 }
187
188 // If we are not doing TLS, we are ready to send data now.
189 // In case of TLS SignalConnect will be sent only after TLS handshake is
190 // successful. So no buffering will be done at socket handlers if any
191 // packets sent before that by the application.
192 client_->SocketCreated(local_address, remote_address);
193 return true;
194 }
195
DoRead()196 void P2PSocketTcpBase::DoRead() {
197 while (true) {
198 if (!read_buffer_.get()) {
199 read_buffer_ = base::MakeRefCounted<net::GrowableIOBuffer>();
200 read_buffer_->SetCapacity(kTcpReadBufferSize);
201 } else if (read_buffer_->RemainingCapacity() < kTcpReadBufferSize) {
202 // Make sure that we always have at least kTcpReadBufferSize of
203 // remaining capacity in the read buffer. Normally all packets
204 // are smaller than kTcpReadBufferSize, so this is not really
205 // required.
206 read_buffer_->SetCapacity(read_buffer_->capacity() + kTcpReadBufferSize -
207 read_buffer_->RemainingCapacity());
208 }
209 const int result = socket_->Read(
210 read_buffer_.get(), read_buffer_->RemainingCapacity(),
211 base::BindOnce(&P2PSocketTcp::OnRead, base::Unretained(this)));
212 if (result == net::ERR_IO_PENDING || !HandleReadResult(result))
213 return;
214 }
215 }
216
OnRead(int result)217 void P2PSocketTcpBase::OnRead(int result) {
218 if (HandleReadResult(result))
219 DoRead();
220 }
221
OnPacket(std::vector<int8_t> data)222 bool P2PSocketTcpBase::OnPacket(std::vector<int8_t> data) {
223 if (!connected_) {
224 P2PSocket::StunMessageType type;
225 bool stun = GetStunPacketType(reinterpret_cast<uint8_t*>(&*data.begin()),
226 data.size(), &type);
227 if (stun && IsRequestOrResponse(type)) {
228 connected_ = true;
229 } else if (!stun || type == STUN_DATA_INDICATION) {
230 LOG(ERROR) << "Received unexpected data packet from "
231 << remote_address_.ip_address.ToString()
232 << " before STUN binding is finished. "
233 << "Terminating connection.";
234 OnError();
235 return false;
236 }
237 }
238
239 if (data.size() == 0) {
240 // https://tools.ietf.org/html/rfc4571#section-2 allows null packets which
241 // are ignored.
242 LOG(WARNING) << "Ignoring empty RTP-over-TCP frame.";
243 return true;
244 }
245
246 client_->DataReceived(
247 remote_address_.ip_address, data,
248 base::TimeTicks() + base::TimeDelta::FromNanoseconds(rtc::TimeNanos()));
249
250 delegate_->DumpPacket(
251 base::make_span(reinterpret_cast<const uint8_t*>(&data[0]), data.size()),
252 true);
253
254 return true;
255 }
256
WriteOrQueue(SendBuffer & send_buffer)257 void P2PSocketTcpBase::WriteOrQueue(SendBuffer& send_buffer) {
258 IncrementTotalSentPackets();
259 if (write_buffer_.buffer.get()) {
260 write_queue_.push(send_buffer);
261 IncrementDelayedPackets();
262 IncrementDelayedBytes(send_buffer.buffer->size());
263 return;
264 }
265
266 write_buffer_ = send_buffer;
267 DoWrite();
268 }
269
DoWrite()270 void P2PSocketTcpBase::DoWrite() {
271 while (!write_pending_ && write_buffer_.buffer.get()) {
272 int result = socket_->Write(
273 write_buffer_.buffer.get(), write_buffer_.buffer->BytesRemaining(),
274 base::BindOnce(&P2PSocketTcp::OnWritten, base::Unretained(this)),
275 net::NetworkTrafficAnnotationTag(write_buffer_.traffic_annotation));
276
277 if (result == net::ERR_IO_PENDING) {
278 write_pending_ = true;
279 } else if (!HandleWriteResult(result)) {
280 break;
281 }
282 }
283 }
284
OnWritten(int result)285 void P2PSocketTcpBase::OnWritten(int result) {
286 DCHECK(write_pending_);
287 DCHECK_NE(result, net::ERR_IO_PENDING);
288
289 write_pending_ = false;
290
291 if (HandleWriteResult(result))
292 DoWrite();
293 }
294
HandleWriteResult(int result)295 bool P2PSocketTcpBase::HandleWriteResult(int result) {
296 DCHECK(write_buffer_.buffer.get());
297
298 if (result < 0) {
299 ReportSocketError(result, "WebRTC.ICE.TcpSocketWriteErrorCode");
300
301 LOG(ERROR) << "Error when sending data in TCP socket: " << result;
302 OnError();
303 return false;
304 }
305
306 write_buffer_.buffer->DidConsume(result);
307 if (write_buffer_.buffer->BytesRemaining() == 0) {
308 int64_t send_time_ms = rtc::TimeMillis();
309 client_->SendComplete(
310 P2PSendPacketMetrics(0, write_buffer_.rtc_packet_id, send_time_ms));
311 if (write_queue_.empty()) {
312 write_buffer_.buffer = nullptr;
313 write_buffer_.rtc_packet_id = -1;
314 } else {
315 write_buffer_ = write_queue_.front();
316 write_queue_.pop();
317 // Update how many bytes are still waiting to be sent.
318 DecrementDelayedBytes(write_buffer_.buffer->size());
319 }
320 }
321 return true;
322 }
323
HandleReadResult(int result)324 bool P2PSocketTcpBase::HandleReadResult(int result) {
325 if (result < 0) {
326 LOG(ERROR) << "Error when reading from TCP socket: " << result;
327 OnError();
328 return false;
329 } else if (result == 0) {
330 LOG(WARNING) << "Remote peer has shutdown TCP socket.";
331 OnError();
332 return false;
333 }
334
335 read_buffer_->set_offset(read_buffer_->offset() + result);
336 char* head = read_buffer_->StartOfBuffer(); // Purely a convenience.
337 int pos = 0;
338 while (pos <= read_buffer_->offset()) {
339 size_t bytes_consumed = 0;
340 if (!ProcessInput(head + pos, read_buffer_->offset() - pos,
341 &bytes_consumed)) {
342 return false;
343 }
344 if (!bytes_consumed)
345 break;
346 pos += bytes_consumed;
347 }
348 // We've consumed all complete packets from the buffer; now move any remaining
349 // bytes to the head of the buffer and set offset to reflect this.
350 if (pos && pos <= read_buffer_->offset()) {
351 memmove(head, head + pos, read_buffer_->offset() - pos);
352 read_buffer_->set_offset(read_buffer_->offset() - pos);
353 }
354
355 return true;
356 }
357
Send(const std::vector<int8_t> & data,const P2PPacketInfo & packet_info,const net::MutableNetworkTrafficAnnotationTag & traffic_annotation)358 void P2PSocketTcpBase::Send(
359 const std::vector<int8_t>& data,
360 const P2PPacketInfo& packet_info,
361 const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
362 // Renderer should use this socket only to send data to |remote_address_|.
363 if (data.size() > kMaximumPacketSize ||
364 !(packet_info.destination == remote_address_.ip_address)) {
365 NOTREACHED();
366 OnError();
367 return;
368 }
369
370 if (!connected_) {
371 P2PSocket::StunMessageType type = P2PSocket::StunMessageType();
372 bool stun = GetStunPacketType(
373 reinterpret_cast<const uint8_t*>(&*data.begin()), data.size(), &type);
374 if (!stun || type == STUN_DATA_INDICATION) {
375 LOG(ERROR) << "Page tried to send a data packet to "
376 << packet_info.destination.ToString()
377 << " before STUN binding is finished.";
378 OnError();
379 return;
380 }
381 }
382
383 DoSend(packet_info.destination, data, packet_info.packet_options,
384 net::NetworkTrafficAnnotationTag(traffic_annotation));
385 }
386
SetOption(P2PSocketOption option,int32_t value)387 void P2PSocketTcpBase::SetOption(P2PSocketOption option, int32_t value) {
388 switch (option) {
389 case P2P_SOCKET_OPT_RCVBUF:
390 socket_->SetReceiveBufferSize(value);
391 break;
392 case P2P_SOCKET_OPT_SNDBUF:
393 socket_->SetSendBufferSize(value);
394 break;
395 case P2P_SOCKET_OPT_DSCP:
396 return; // For TCP sockets DSCP setting is not available.
397 default:
398 NOTREACHED();
399 return;
400 }
401 }
402
P2PSocketTcp(Delegate * delegate,mojo::PendingRemote<mojom::P2PSocketClient> client,mojo::PendingReceiver<mojom::P2PSocket> socket,P2PSocketType type,ProxyResolvingClientSocketFactory * proxy_resolving_socket_factory)403 P2PSocketTcp::P2PSocketTcp(
404 Delegate* delegate,
405 mojo::PendingRemote<mojom::P2PSocketClient> client,
406 mojo::PendingReceiver<mojom::P2PSocket> socket,
407 P2PSocketType type,
408 ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory)
409 : P2PSocketTcpBase(delegate,
410 std::move(client),
411 std::move(socket),
412 type,
413 proxy_resolving_socket_factory) {
414 DCHECK(type == P2P_SOCKET_TCP_CLIENT || type == P2P_SOCKET_SSLTCP_CLIENT ||
415 type == P2P_SOCKET_TLS_CLIENT);
416 }
417
~P2PSocketTcp()418 P2PSocketTcp::~P2PSocketTcp() {}
419
ProcessInput(char * input,int input_len,size_t * bytes_consumed)420 bool P2PSocketTcp::ProcessInput(char* input,
421 int input_len,
422 size_t* bytes_consumed) {
423 *bytes_consumed = 0;
424 if (input_len < kPacketHeaderSize)
425 return true;
426
427 int packet_size = base::NetToHost16(*reinterpret_cast<uint16_t*>(input));
428 if (input_len < packet_size + kPacketHeaderSize)
429 return true;
430
431 char* cur = input + kPacketHeaderSize;
432 *bytes_consumed = kPacketHeaderSize + packet_size;
433
434 return OnPacket(std::vector<int8_t>(cur, cur + packet_size));
435 }
436
DoSend(const net::IPEndPoint & to,const std::vector<int8_t> & data,const rtc::PacketOptions & options,const net::NetworkTrafficAnnotationTag traffic_annotation)437 void P2PSocketTcp::DoSend(
438 const net::IPEndPoint& to,
439 const std::vector<int8_t>& data,
440 const rtc::PacketOptions& options,
441 const net::NetworkTrafficAnnotationTag traffic_annotation) {
442 int size = kPacketHeaderSize + data.size();
443 SendBuffer send_buffer(options.packet_id,
444 base::MakeRefCounted<net::DrainableIOBuffer>(
445 base::MakeRefCounted<net::IOBuffer>(size), size),
446 traffic_annotation);
447 *reinterpret_cast<uint16_t*>(send_buffer.buffer->data()) =
448 base::HostToNet16(data.size());
449 memcpy(send_buffer.buffer->data() + kPacketHeaderSize, &data[0], data.size());
450
451 cricket::ApplyPacketOptions(
452 reinterpret_cast<uint8_t*>(send_buffer.buffer->data()) +
453 kPacketHeaderSize,
454 send_buffer.buffer->BytesRemaining() - kPacketHeaderSize,
455 options.packet_time_params, rtc::TimeMicros());
456
457 WriteOrQueue(send_buffer);
458 }
459
460 // P2PSocketStunTcp
P2PSocketStunTcp(Delegate * delegate,mojo::PendingRemote<mojom::P2PSocketClient> client,mojo::PendingReceiver<mojom::P2PSocket> socket,P2PSocketType type,ProxyResolvingClientSocketFactory * proxy_resolving_socket_factory)461 P2PSocketStunTcp::P2PSocketStunTcp(
462 Delegate* delegate,
463 mojo::PendingRemote<mojom::P2PSocketClient> client,
464 mojo::PendingReceiver<mojom::P2PSocket> socket,
465 P2PSocketType type,
466 ProxyResolvingClientSocketFactory* proxy_resolving_socket_factory)
467 : P2PSocketTcpBase(delegate,
468 std::move(client),
469 std::move(socket),
470 type,
471 proxy_resolving_socket_factory) {
472 DCHECK(type == P2P_SOCKET_STUN_TCP_CLIENT ||
473 type == P2P_SOCKET_STUN_SSLTCP_CLIENT ||
474 type == P2P_SOCKET_STUN_TLS_CLIENT);
475 }
476
~P2PSocketStunTcp()477 P2PSocketStunTcp::~P2PSocketStunTcp() {}
478
ProcessInput(char * input,int input_len,size_t * bytes_consumed)479 bool P2PSocketStunTcp::ProcessInput(char* input,
480 int input_len,
481 size_t* bytes_consumed) {
482 *bytes_consumed = 0;
483 if (input_len < kPacketHeaderSize + kPacketLengthOffset)
484 return true;
485
486 int pad_bytes;
487 int packet_size = GetExpectedPacketSize(
488 reinterpret_cast<const uint8_t*>(input), input_len, &pad_bytes);
489
490 if (input_len < packet_size + pad_bytes)
491 return true;
492
493 // We have a complete packet. Read through it.
494 char* cur = input;
495 *bytes_consumed = packet_size + pad_bytes;
496 return OnPacket(std::vector<int8_t>(cur, cur + packet_size));
497 }
498
DoSend(const net::IPEndPoint & to,const std::vector<int8_t> & data,const rtc::PacketOptions & options,const net::NetworkTrafficAnnotationTag traffic_annotation)499 void P2PSocketStunTcp::DoSend(
500 const net::IPEndPoint& to,
501 const std::vector<int8_t>& data,
502 const rtc::PacketOptions& options,
503 const net::NetworkTrafficAnnotationTag traffic_annotation) {
504 // Each packet is expected to have header (STUN/TURN ChannelData), where
505 // header contains message type and and length of message.
506 if (data.size() < kPacketHeaderSize + kPacketLengthOffset) {
507 NOTREACHED();
508 OnError();
509 return;
510 }
511
512 int pad_bytes;
513 size_t expected_len = GetExpectedPacketSize(
514 reinterpret_cast<const uint8_t*>(&data[0]), data.size(), &pad_bytes);
515
516 // Accepts only complete STUN/TURN packets.
517 if (data.size() != expected_len) {
518 NOTREACHED();
519 OnError();
520 return;
521 }
522
523 // Add any pad bytes to the total size.
524 int size = data.size() + pad_bytes;
525
526 SendBuffer send_buffer(options.packet_id,
527 base::MakeRefCounted<net::DrainableIOBuffer>(
528 base::MakeRefCounted<net::IOBuffer>(size), size),
529 traffic_annotation);
530 memcpy(send_buffer.buffer->data(), &data[0], data.size());
531
532 cricket::ApplyPacketOptions(
533 reinterpret_cast<uint8_t*>(send_buffer.buffer->data()), data.size(),
534 options.packet_time_params, rtc::TimeMicros());
535
536 if (pad_bytes) {
537 char padding[4] = {0};
538 DCHECK_LE(pad_bytes, 4);
539 memcpy(send_buffer.buffer->data() + data.size(), padding, pad_bytes);
540 }
541
542 // WriteOrQueue may free the memory, so dump it first.
543 delegate_->DumpPacket(
544 base::make_span(reinterpret_cast<uint8_t*>(send_buffer.buffer->data()),
545 data.size()),
546 false);
547
548 WriteOrQueue(send_buffer);
549 }
550
GetExpectedPacketSize(const uint8_t * data,int len,int * pad_bytes)551 int P2PSocketStunTcp::GetExpectedPacketSize(const uint8_t* data,
552 int len,
553 int* pad_bytes) {
554 DCHECK_LE(kTurnChannelDataHeaderSize, len);
555 // Both stun and turn had length at offset 2.
556 int packet_size = base::NetToHost16(
557 *reinterpret_cast<const uint16_t*>(data + kPacketLengthOffset));
558
559 // Get packet type (STUN or TURN).
560 uint16_t msg_type =
561 base::NetToHost16(*reinterpret_cast<const uint16_t*>(data));
562
563 *pad_bytes = 0;
564 // Add heder length to packet length.
565 if ((msg_type & 0xC000) == 0) {
566 packet_size += kStunHeaderSize;
567 } else {
568 packet_size += kTurnChannelDataHeaderSize;
569 // Calculate any padding if present.
570 if (packet_size % 4)
571 *pad_bytes = 4 - packet_size % 4;
572 }
573 return packet_size;
574 }
575
576 } // namespace network
577