1 /* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/p2p/base/pseudotcp.h" 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 33 #include <set> 34 35 #include "talk/base/basictypes.h" 36 #include "talk/base/bytebuffer.h" 37 #include "talk/base/byteorder.h" 38 #include "talk/base/common.h" 39 #include "talk/base/logging.h" 40 #include "talk/base/scoped_ptr.h" 41 #include "talk/base/socket.h" 42 #include "talk/base/stringutils.h" 43 #include "talk/base/timeutils.h" 44 45 // The following logging is for detailed (packet-level) analysis only. 46 #define _DBG_NONE 0 47 #define _DBG_NORMAL 1 48 #define _DBG_VERBOSE 2 49 #define _DEBUGMSG _DBG_NONE 50 51 namespace cricket { 52 53 ////////////////////////////////////////////////////////////////////// 54 // Network Constants 55 ////////////////////////////////////////////////////////////////////// 56 57 // Standard MTUs 58 const uint16 PACKET_MAXIMUMS[] = { 59 65535, // Theoretical maximum, Hyperchannel 60 32000, // Nothing 61 17914, // 16Mb IBM Token Ring 62 8166, // IEEE 802.4 63 //4464, // IEEE 802.5 (4Mb max) 64 4352, // FDDI 65 //2048, // Wideband Network 66 2002, // IEEE 802.5 (4Mb recommended) 67 //1536, // Expermental Ethernet Networks 68 //1500, // Ethernet, Point-to-Point (default) 69 1492, // IEEE 802.3 70 1006, // SLIP, ARPANET 71 //576, // X.25 Networks 72 //544, // DEC IP Portal 73 //512, // NETBIOS 74 508, // IEEE 802/Source-Rt Bridge, ARCNET 75 296, // Point-to-Point (low delay) 76 //68, // Official minimum 77 0, // End of list marker 78 }; 79 80 const uint32 MAX_PACKET = 65535; 81 // Note: we removed lowest level because packet overhead was larger! 82 const uint32 MIN_PACKET = 296; 83 84 const uint32 IP_HEADER_SIZE = 20; // (+ up to 40 bytes of options?) 85 const uint32 UDP_HEADER_SIZE = 8; 86 // TODO: Make JINGLE_HEADER_SIZE transparent to this code? 87 const uint32 JINGLE_HEADER_SIZE = 64; // when relay framing is in use 88 89 // Default size for receive and send buffer. 90 const uint32 DEFAULT_RCV_BUF_SIZE = 60 * 1024; 91 const uint32 DEFAULT_SND_BUF_SIZE = 90 * 1024; 92 93 ////////////////////////////////////////////////////////////////////// 94 // Global Constants and Functions 95 ////////////////////////////////////////////////////////////////////// 96 // 97 // 0 1 2 3 98 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 99 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 100 // 0 | Conversation Number | 101 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 102 // 4 | Sequence Number | 103 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 104 // 8 | Acknowledgment Number | 105 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 106 // | | |U|A|P|R|S|F| | 107 // 12 | Control | |R|C|S|S|Y|I| Window | 108 // | | |G|K|H|T|N|N| | 109 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 110 // 16 | Timestamp sending | 111 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 112 // 20 | Timestamp receiving | 113 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 114 // 24 | data | 115 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 116 // 117 ////////////////////////////////////////////////////////////////////// 118 119 #define PSEUDO_KEEPALIVE 0 120 121 const uint32 HEADER_SIZE = 24; 122 const uint32 PACKET_OVERHEAD = HEADER_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE + JINGLE_HEADER_SIZE; 123 124 const uint32 MIN_RTO = 250; // 250 ms (RFC1122, Sec 4.2.3.1 "fractions of a second") 125 const uint32 DEF_RTO = 3000; // 3 seconds (RFC1122, Sec 4.2.3.1) 126 const uint32 MAX_RTO = 60000; // 60 seconds 127 const uint32 DEF_ACK_DELAY = 100; // 100 milliseconds 128 129 const uint8 FLAG_CTL = 0x02; 130 const uint8 FLAG_RST = 0x04; 131 132 const uint8 CTL_CONNECT = 0; 133 134 // TCP options. 135 const uint8 TCP_OPT_EOL = 0; // End of list. 136 const uint8 TCP_OPT_NOOP = 1; // No-op. 137 const uint8 TCP_OPT_MSS = 2; // Maximum segment size. 138 const uint8 TCP_OPT_WND_SCALE = 3; // Window scale factor. 139 140 const long DEFAULT_TIMEOUT = 4000; // If there are no pending clocks, wake up every 4 seconds 141 const long CLOSED_TIMEOUT = 60 * 1000; // If the connection is closed, once per minute 142 143 #if PSEUDO_KEEPALIVE 144 // !?! Rethink these times 145 const uint32 IDLE_PING = 20 * 1000; // 20 seconds (note: WinXP SP2 firewall udp timeout is 90 seconds) 146 const uint32 IDLE_TIMEOUT = 90 * 1000; // 90 seconds; 147 #endif // PSEUDO_KEEPALIVE 148 149 ////////////////////////////////////////////////////////////////////// 150 // Helper Functions 151 ////////////////////////////////////////////////////////////////////// 152 153 inline void long_to_bytes(uint32 val, void* buf) { 154 *static_cast<uint32*>(buf) = talk_base::HostToNetwork32(val); 155 } 156 157 inline void short_to_bytes(uint16 val, void* buf) { 158 *static_cast<uint16*>(buf) = talk_base::HostToNetwork16(val); 159 } 160 161 inline uint32 bytes_to_long(const void* buf) { 162 return talk_base::NetworkToHost32(*static_cast<const uint32*>(buf)); 163 } 164 165 inline uint16 bytes_to_short(const void* buf) { 166 return talk_base::NetworkToHost16(*static_cast<const uint16*>(buf)); 167 } 168 169 uint32 bound(uint32 lower, uint32 middle, uint32 upper) { 170 return talk_base::_min(talk_base::_max(lower, middle), upper); 171 } 172 173 ////////////////////////////////////////////////////////////////////// 174 // Debugging Statistics 175 ////////////////////////////////////////////////////////////////////// 176 177 #if 0 // Not used yet 178 179 enum Stat { 180 S_SENT_PACKET, // All packet sends 181 S_RESENT_PACKET, // All packet sends that are retransmits 182 S_RECV_PACKET, // All packet receives 183 S_RECV_NEW, // All packet receives that are too new 184 S_RECV_OLD, // All packet receives that are too old 185 S_NUM_STATS 186 }; 187 188 const char* const STAT_NAMES[S_NUM_STATS] = { 189 "snt", 190 "snt-r", 191 "rcv" 192 "rcv-n", 193 "rcv-o" 194 }; 195 196 int g_stats[S_NUM_STATS]; 197 inline void Incr(Stat s) { ++g_stats[s]; } 198 void ReportStats() { 199 char buffer[256]; 200 size_t len = 0; 201 for (int i = 0; i < S_NUM_STATS; ++i) { 202 len += talk_base::sprintfn(buffer, ARRAY_SIZE(buffer), "%s%s:%d", 203 (i == 0) ? "" : ",", STAT_NAMES[i], g_stats[i]); 204 g_stats[i] = 0; 205 } 206 LOG(LS_INFO) << "Stats[" << buffer << "]"; 207 } 208 209 #endif 210 211 ////////////////////////////////////////////////////////////////////// 212 // PseudoTcp 213 ////////////////////////////////////////////////////////////////////// 214 215 uint32 PseudoTcp::Now() { 216 #if 0 // Use this to synchronize timers with logging timestamps (easier debug) 217 return talk_base::TimeSince(StartTime()); 218 #else 219 return talk_base::Time(); 220 #endif 221 } 222 223 PseudoTcp::PseudoTcp(IPseudoTcpNotify* notify, uint32 conv) 224 : m_notify(notify), 225 m_shutdown(SD_NONE), 226 m_error(0), 227 m_rbuf_len(DEFAULT_RCV_BUF_SIZE), 228 m_rbuf(m_rbuf_len), 229 m_sbuf_len(DEFAULT_SND_BUF_SIZE), 230 m_sbuf(m_sbuf_len) { 231 232 // Sanity check on buffer sizes (needed for OnTcpWriteable notification logic) 233 ASSERT(m_rbuf_len + MIN_PACKET < m_sbuf_len); 234 235 uint32 now = Now(); 236 237 m_state = TCP_LISTEN; 238 m_conv = conv; 239 m_rcv_wnd = m_rbuf_len; 240 m_rwnd_scale = m_swnd_scale = 0; 241 m_snd_nxt = 0; 242 m_snd_wnd = 1; 243 m_snd_una = m_rcv_nxt = 0; 244 m_bReadEnable = true; 245 m_bWriteEnable = false; 246 m_t_ack = 0; 247 248 m_msslevel = 0; 249 m_largest = 0; 250 ASSERT(MIN_PACKET > PACKET_OVERHEAD); 251 m_mss = MIN_PACKET - PACKET_OVERHEAD; 252 m_mtu_advise = MAX_PACKET; 253 254 m_rto_base = 0; 255 256 m_cwnd = 2 * m_mss; 257 m_ssthresh = m_rbuf_len; 258 m_lastrecv = m_lastsend = m_lasttraffic = now; 259 m_bOutgoing = false; 260 261 m_dup_acks = 0; 262 m_recover = 0; 263 264 m_ts_recent = m_ts_lastack = 0; 265 266 m_rx_rto = DEF_RTO; 267 m_rx_srtt = m_rx_rttvar = 0; 268 269 m_use_nagling = true; 270 m_ack_delay = DEF_ACK_DELAY; 271 m_support_wnd_scale = true; 272 } 273 274 PseudoTcp::~PseudoTcp() { 275 } 276 277 int PseudoTcp::Connect() { 278 if (m_state != TCP_LISTEN) { 279 m_error = EINVAL; 280 return -1; 281 } 282 283 m_state = TCP_SYN_SENT; 284 LOG(LS_INFO) << "State: TCP_SYN_SENT"; 285 286 queueConnectMessage(); 287 attemptSend(); 288 289 return 0; 290 } 291 292 void PseudoTcp::NotifyMTU(uint16 mtu) { 293 m_mtu_advise = mtu; 294 if (m_state == TCP_ESTABLISHED) { 295 adjustMTU(); 296 } 297 } 298 299 void PseudoTcp::NotifyClock(uint32 now) { 300 if (m_state == TCP_CLOSED) 301 return; 302 303 // Check if it's time to retransmit a segment 304 if (m_rto_base && (talk_base::TimeDiff(m_rto_base + m_rx_rto, now) <= 0)) { 305 if (m_slist.empty()) { 306 ASSERT(false); 307 } else { 308 // Note: (m_slist.front().xmit == 0)) { 309 // retransmit segments 310 #if _DEBUGMSG >= _DBG_NORMAL 311 LOG(LS_INFO) << "timeout retransmit (rto: " << m_rx_rto 312 << ") (rto_base: " << m_rto_base 313 << ") (now: " << now 314 << ") (dup_acks: " << static_cast<unsigned>(m_dup_acks) 315 << ")"; 316 #endif // _DEBUGMSG 317 if (!transmit(m_slist.begin(), now)) { 318 closedown(ECONNABORTED); 319 return; 320 } 321 322 uint32 nInFlight = m_snd_nxt - m_snd_una; 323 m_ssthresh = talk_base::_max(nInFlight / 2, 2 * m_mss); 324 //LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << " nInFlight: " << nInFlight << " m_mss: " << m_mss; 325 m_cwnd = m_mss; 326 327 // Back off retransmit timer. Note: the limit is lower when connecting. 328 uint32 rto_limit = (m_state < TCP_ESTABLISHED) ? DEF_RTO : MAX_RTO; 329 m_rx_rto = talk_base::_min(rto_limit, m_rx_rto * 2); 330 m_rto_base = now; 331 } 332 } 333 334 // Check if it's time to probe closed windows 335 if ((m_snd_wnd == 0) 336 && (talk_base::TimeDiff(m_lastsend + m_rx_rto, now) <= 0)) { 337 if (talk_base::TimeDiff(now, m_lastrecv) >= 15000) { 338 closedown(ECONNABORTED); 339 return; 340 } 341 342 // probe the window 343 packet(m_snd_nxt - 1, 0, 0, 0); 344 m_lastsend = now; 345 346 // back off retransmit timer 347 m_rx_rto = talk_base::_min(MAX_RTO, m_rx_rto * 2); 348 } 349 350 // Check if it's time to send delayed acks 351 if (m_t_ack && (talk_base::TimeDiff(m_t_ack + m_ack_delay, now) <= 0)) { 352 packet(m_snd_nxt, 0, 0, 0); 353 } 354 355 #if PSEUDO_KEEPALIVE 356 // Check for idle timeout 357 if ((m_state == TCP_ESTABLISHED) && (TimeDiff(m_lastrecv + IDLE_TIMEOUT, now) <= 0)) { 358 closedown(ECONNABORTED); 359 return; 360 } 361 362 // Check for ping timeout (to keep udp mapping open) 363 if ((m_state == TCP_ESTABLISHED) && (TimeDiff(m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3/2 : IDLE_PING), now) <= 0)) { 364 packet(m_snd_nxt, 0, 0, 0); 365 } 366 #endif // PSEUDO_KEEPALIVE 367 } 368 369 bool PseudoTcp::NotifyPacket(const char* buffer, size_t len) { 370 if (len > MAX_PACKET) { 371 LOG_F(WARNING) << "packet too large"; 372 return false; 373 } 374 return parse(reinterpret_cast<const uint8 *>(buffer), uint32(len)); 375 } 376 377 bool PseudoTcp::GetNextClock(uint32 now, long& timeout) { 378 return clock_check(now, timeout); 379 } 380 381 void PseudoTcp::GetOption(Option opt, int* value) { 382 if (opt == OPT_NODELAY) { 383 *value = m_use_nagling ? 0 : 1; 384 } else if (opt == OPT_ACKDELAY) { 385 *value = m_ack_delay; 386 } else if (opt == OPT_SNDBUF) { 387 *value = m_sbuf_len; 388 } else if (opt == OPT_RCVBUF) { 389 *value = m_rbuf_len; 390 } else { 391 ASSERT(false); 392 } 393 } 394 void PseudoTcp::SetOption(Option opt, int value) { 395 if (opt == OPT_NODELAY) { 396 m_use_nagling = value == 0; 397 } else if (opt == OPT_ACKDELAY) { 398 m_ack_delay = value; 399 } else if (opt == OPT_SNDBUF) { 400 ASSERT(m_state == TCP_LISTEN); 401 resizeSendBuffer(value); 402 } else if (opt == OPT_RCVBUF) { 403 ASSERT(m_state == TCP_LISTEN); 404 resizeReceiveBuffer(value); 405 } else { 406 ASSERT(false); 407 } 408 } 409 410 uint32 PseudoTcp::GetCongestionWindow() const { 411 return m_cwnd; 412 } 413 414 uint32 PseudoTcp::GetBytesInFlight() const { 415 return m_snd_nxt - m_snd_una; 416 } 417 418 uint32 PseudoTcp::GetBytesBufferedNotSent() const { 419 size_t buffered_bytes = 0; 420 m_sbuf.GetBuffered(&buffered_bytes); 421 return static_cast<uint32>(m_snd_una + buffered_bytes - m_snd_nxt); 422 } 423 424 uint32 PseudoTcp::GetRoundTripTimeEstimateMs() const { 425 return m_rx_srtt; 426 } 427 428 // 429 // IPStream Implementation 430 // 431 432 int PseudoTcp::Recv(char* buffer, size_t len) { 433 if (m_state != TCP_ESTABLISHED) { 434 m_error = ENOTCONN; 435 return SOCKET_ERROR; 436 } 437 438 size_t read = 0; 439 talk_base::StreamResult result = m_rbuf.Read(buffer, len, &read, NULL); 440 441 // If there's no data in |m_rbuf|. 442 if (result == talk_base::SR_BLOCK) { 443 m_bReadEnable = true; 444 m_error = EWOULDBLOCK; 445 return SOCKET_ERROR; 446 } 447 ASSERT(result == talk_base::SR_SUCCESS); 448 449 size_t available_space = 0; 450 m_rbuf.GetWriteRemaining(&available_space); 451 452 if (uint32(available_space) - m_rcv_wnd >= 453 talk_base::_min<uint32>(m_rbuf_len / 2, m_mss)) { 454 // TODO(jbeda): !?! Not sure about this was closed business 455 bool bWasClosed = (m_rcv_wnd == 0); 456 m_rcv_wnd = static_cast<uint32>(available_space); 457 458 if (bWasClosed) { 459 attemptSend(sfImmediateAck); 460 } 461 } 462 463 return static_cast<int>(read); 464 } 465 466 int PseudoTcp::Send(const char* buffer, size_t len) { 467 if (m_state != TCP_ESTABLISHED) { 468 m_error = ENOTCONN; 469 return SOCKET_ERROR; 470 } 471 472 size_t available_space = 0; 473 m_sbuf.GetWriteRemaining(&available_space); 474 475 if (!available_space) { 476 m_bWriteEnable = true; 477 m_error = EWOULDBLOCK; 478 return SOCKET_ERROR; 479 } 480 481 int written = queue(buffer, uint32(len), false); 482 attemptSend(); 483 return written; 484 } 485 486 void PseudoTcp::Close(bool force) { 487 LOG_F(LS_VERBOSE) << "(" << (force ? "true" : "false") << ")"; 488 m_shutdown = force ? SD_FORCEFUL : SD_GRACEFUL; 489 } 490 491 int PseudoTcp::GetError() { 492 return m_error; 493 } 494 495 // 496 // Internal Implementation 497 // 498 499 uint32 PseudoTcp::queue(const char* data, uint32 len, bool bCtrl) { 500 size_t available_space = 0; 501 m_sbuf.GetWriteRemaining(&available_space); 502 503 if (len > static_cast<uint32>(available_space)) { 504 ASSERT(!bCtrl); 505 len = static_cast<uint32>(available_space); 506 } 507 508 // We can concatenate data if the last segment is the same type 509 // (control v. regular data), and has not been transmitted yet 510 if (!m_slist.empty() && (m_slist.back().bCtrl == bCtrl) && 511 (m_slist.back().xmit == 0)) { 512 m_slist.back().len += len; 513 } else { 514 size_t snd_buffered = 0; 515 m_sbuf.GetBuffered(&snd_buffered); 516 SSegment sseg(static_cast<uint32>(m_snd_una + snd_buffered), len, bCtrl); 517 m_slist.push_back(sseg); 518 } 519 520 size_t written = 0; 521 m_sbuf.Write(data, len, &written, NULL); 522 return static_cast<uint32>(written); 523 } 524 525 IPseudoTcpNotify::WriteResult PseudoTcp::packet(uint32 seq, uint8 flags, 526 uint32 offset, uint32 len) { 527 ASSERT(HEADER_SIZE + len <= MAX_PACKET); 528 529 uint32 now = Now(); 530 531 talk_base::scoped_ptr<uint8[]> buffer(new uint8[MAX_PACKET]); 532 long_to_bytes(m_conv, buffer.get()); 533 long_to_bytes(seq, buffer.get() + 4); 534 long_to_bytes(m_rcv_nxt, buffer.get() + 8); 535 buffer[12] = 0; 536 buffer[13] = flags; 537 short_to_bytes( 538 static_cast<uint16>(m_rcv_wnd >> m_rwnd_scale), buffer.get() + 14); 539 540 // Timestamp computations 541 long_to_bytes(now, buffer.get() + 16); 542 long_to_bytes(m_ts_recent, buffer.get() + 20); 543 m_ts_lastack = m_rcv_nxt; 544 545 if (len) { 546 size_t bytes_read = 0; 547 talk_base::StreamResult result = m_sbuf.ReadOffset( 548 buffer.get() + HEADER_SIZE, len, offset, &bytes_read); 549 UNUSED(result); 550 ASSERT(result == talk_base::SR_SUCCESS); 551 ASSERT(static_cast<uint32>(bytes_read) == len); 552 } 553 554 #if _DEBUGMSG >= _DBG_VERBOSE 555 LOG(LS_INFO) << "<-- <CONV=" << m_conv 556 << "><FLG=" << static_cast<unsigned>(flags) 557 << "><SEQ=" << seq << ":" << seq + len 558 << "><ACK=" << m_rcv_nxt 559 << "><WND=" << m_rcv_wnd 560 << "><TS=" << (now % 10000) 561 << "><TSR=" << (m_ts_recent % 10000) 562 << "><LEN=" << len << ">"; 563 #endif // _DEBUGMSG 564 565 IPseudoTcpNotify::WriteResult wres = m_notify->TcpWritePacket( 566 this, reinterpret_cast<char *>(buffer.get()), len + HEADER_SIZE); 567 // Note: When len is 0, this is an ACK packet. We don't read the return value for those, 568 // and thus we won't retry. So go ahead and treat the packet as a success (basically simulate 569 // as if it were dropped), which will prevent our timers from being messed up. 570 if ((wres != IPseudoTcpNotify::WR_SUCCESS) && (0 != len)) 571 return wres; 572 573 m_t_ack = 0; 574 if (len > 0) { 575 m_lastsend = now; 576 } 577 m_lasttraffic = now; 578 m_bOutgoing = true; 579 580 return IPseudoTcpNotify::WR_SUCCESS; 581 } 582 583 bool PseudoTcp::parse(const uint8* buffer, uint32 size) { 584 if (size < 12) 585 return false; 586 587 Segment seg; 588 seg.conv = bytes_to_long(buffer); 589 seg.seq = bytes_to_long(buffer + 4); 590 seg.ack = bytes_to_long(buffer + 8); 591 seg.flags = buffer[13]; 592 seg.wnd = bytes_to_short(buffer + 14); 593 594 seg.tsval = bytes_to_long(buffer + 16); 595 seg.tsecr = bytes_to_long(buffer + 20); 596 597 seg.data = reinterpret_cast<const char *>(buffer) + HEADER_SIZE; 598 seg.len = size - HEADER_SIZE; 599 600 #if _DEBUGMSG >= _DBG_VERBOSE 601 LOG(LS_INFO) << "--> <CONV=" << seg.conv 602 << "><FLG=" << static_cast<unsigned>(seg.flags) 603 << "><SEQ=" << seg.seq << ":" << seg.seq + seg.len 604 << "><ACK=" << seg.ack 605 << "><WND=" << seg.wnd 606 << "><TS=" << (seg.tsval % 10000) 607 << "><TSR=" << (seg.tsecr % 10000) 608 << "><LEN=" << seg.len << ">"; 609 #endif // _DEBUGMSG 610 611 return process(seg); 612 } 613 614 bool PseudoTcp::clock_check(uint32 now, long& nTimeout) { 615 if (m_shutdown == SD_FORCEFUL) 616 return false; 617 618 size_t snd_buffered = 0; 619 m_sbuf.GetBuffered(&snd_buffered); 620 if ((m_shutdown == SD_GRACEFUL) 621 && ((m_state != TCP_ESTABLISHED) 622 || ((snd_buffered == 0) && (m_t_ack == 0)))) { 623 return false; 624 } 625 626 if (m_state == TCP_CLOSED) { 627 nTimeout = CLOSED_TIMEOUT; 628 return true; 629 } 630 631 nTimeout = DEFAULT_TIMEOUT; 632 633 if (m_t_ack) { 634 nTimeout = talk_base::_min<int32>(nTimeout, 635 talk_base::TimeDiff(m_t_ack + m_ack_delay, now)); 636 } 637 if (m_rto_base) { 638 nTimeout = talk_base::_min<int32>(nTimeout, 639 talk_base::TimeDiff(m_rto_base + m_rx_rto, now)); 640 } 641 if (m_snd_wnd == 0) { 642 nTimeout = talk_base::_min<int32>(nTimeout, talk_base::TimeDiff(m_lastsend + m_rx_rto, now)); 643 } 644 #if PSEUDO_KEEPALIVE 645 if (m_state == TCP_ESTABLISHED) { 646 nTimeout = talk_base::_min<int32>(nTimeout, 647 talk_base::TimeDiff(m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3/2 : IDLE_PING), now)); 648 } 649 #endif // PSEUDO_KEEPALIVE 650 return true; 651 } 652 653 bool PseudoTcp::process(Segment& seg) { 654 // If this is the wrong conversation, send a reset!?! (with the correct conversation?) 655 if (seg.conv != m_conv) { 656 //if ((seg.flags & FLAG_RST) == 0) { 657 // packet(tcb, seg.ack, 0, FLAG_RST, 0, 0); 658 //} 659 LOG_F(LS_ERROR) << "wrong conversation"; 660 return false; 661 } 662 663 uint32 now = Now(); 664 m_lasttraffic = m_lastrecv = now; 665 m_bOutgoing = false; 666 667 if (m_state == TCP_CLOSED) { 668 // !?! send reset? 669 LOG_F(LS_ERROR) << "closed"; 670 return false; 671 } 672 673 // Check if this is a reset segment 674 if (seg.flags & FLAG_RST) { 675 closedown(ECONNRESET); 676 return false; 677 } 678 679 // Check for control data 680 bool bConnect = false; 681 if (seg.flags & FLAG_CTL) { 682 if (seg.len == 0) { 683 LOG_F(LS_ERROR) << "Missing control code"; 684 return false; 685 } else if (seg.data[0] == CTL_CONNECT) { 686 bConnect = true; 687 688 // TCP options are in the remainder of the payload after CTL_CONNECT. 689 parseOptions(&seg.data[1], seg.len - 1); 690 691 if (m_state == TCP_LISTEN) { 692 m_state = TCP_SYN_RECEIVED; 693 LOG(LS_INFO) << "State: TCP_SYN_RECEIVED"; 694 //m_notify->associate(addr); 695 queueConnectMessage(); 696 } else if (m_state == TCP_SYN_SENT) { 697 m_state = TCP_ESTABLISHED; 698 LOG(LS_INFO) << "State: TCP_ESTABLISHED"; 699 adjustMTU(); 700 if (m_notify) { 701 m_notify->OnTcpOpen(this); 702 } 703 //notify(evOpen); 704 } 705 } else { 706 LOG_F(LS_WARNING) << "Unknown control code: " << seg.data[0]; 707 return false; 708 } 709 } 710 711 // Update timestamp 712 if ((seg.seq <= m_ts_lastack) && (m_ts_lastack < seg.seq + seg.len)) { 713 m_ts_recent = seg.tsval; 714 } 715 716 // Check if this is a valuable ack 717 if ((seg.ack > m_snd_una) && (seg.ack <= m_snd_nxt)) { 718 // Calculate round-trip time 719 if (seg.tsecr) { 720 int32 rtt = talk_base::TimeDiff(now, seg.tsecr); 721 if (rtt >= 0) { 722 if (m_rx_srtt == 0) { 723 m_rx_srtt = rtt; 724 m_rx_rttvar = rtt / 2; 725 } else { 726 uint32 unsigned_rtt = static_cast<uint32>(rtt); 727 uint32 abs_err = unsigned_rtt > m_rx_srtt ? unsigned_rtt - m_rx_srtt 728 : m_rx_srtt - unsigned_rtt; 729 m_rx_rttvar = (3 * m_rx_rttvar + abs_err) / 4; 730 m_rx_srtt = (7 * m_rx_srtt + rtt) / 8; 731 } 732 m_rx_rto = bound(MIN_RTO, m_rx_srtt + 733 talk_base::_max<uint32>(1, 4 * m_rx_rttvar), MAX_RTO); 734 #if _DEBUGMSG >= _DBG_VERBOSE 735 LOG(LS_INFO) << "rtt: " << rtt 736 << " srtt: " << m_rx_srtt 737 << " rto: " << m_rx_rto; 738 #endif // _DEBUGMSG 739 } else { 740 ASSERT(false); 741 } 742 } 743 744 m_snd_wnd = static_cast<uint32>(seg.wnd) << m_swnd_scale; 745 746 uint32 nAcked = seg.ack - m_snd_una; 747 m_snd_una = seg.ack; 748 749 m_rto_base = (m_snd_una == m_snd_nxt) ? 0 : now; 750 751 m_sbuf.ConsumeReadData(nAcked); 752 753 for (uint32 nFree = nAcked; nFree > 0; ) { 754 ASSERT(!m_slist.empty()); 755 if (nFree < m_slist.front().len) { 756 m_slist.front().len -= nFree; 757 nFree = 0; 758 } else { 759 if (m_slist.front().len > m_largest) { 760 m_largest = m_slist.front().len; 761 } 762 nFree -= m_slist.front().len; 763 m_slist.pop_front(); 764 } 765 } 766 767 if (m_dup_acks >= 3) { 768 if (m_snd_una >= m_recover) { // NewReno 769 uint32 nInFlight = m_snd_nxt - m_snd_una; 770 m_cwnd = talk_base::_min(m_ssthresh, nInFlight + m_mss); // (Fast Retransmit) 771 #if _DEBUGMSG >= _DBG_NORMAL 772 LOG(LS_INFO) << "exit recovery"; 773 #endif // _DEBUGMSG 774 m_dup_acks = 0; 775 } else { 776 #if _DEBUGMSG >= _DBG_NORMAL 777 LOG(LS_INFO) << "recovery retransmit"; 778 #endif // _DEBUGMSG 779 if (!transmit(m_slist.begin(), now)) { 780 closedown(ECONNABORTED); 781 return false; 782 } 783 m_cwnd += m_mss - talk_base::_min(nAcked, m_cwnd); 784 } 785 } else { 786 m_dup_acks = 0; 787 // Slow start, congestion avoidance 788 if (m_cwnd < m_ssthresh) { 789 m_cwnd += m_mss; 790 } else { 791 m_cwnd += talk_base::_max<uint32>(1, m_mss * m_mss / m_cwnd); 792 } 793 } 794 } else if (seg.ack == m_snd_una) { 795 // !?! Note, tcp says don't do this... but otherwise how does a closed window become open? 796 m_snd_wnd = static_cast<uint32>(seg.wnd) << m_swnd_scale; 797 798 // Check duplicate acks 799 if (seg.len > 0) { 800 // it's a dup ack, but with a data payload, so don't modify m_dup_acks 801 } else if (m_snd_una != m_snd_nxt) { 802 m_dup_acks += 1; 803 if (m_dup_acks == 3) { // (Fast Retransmit) 804 #if _DEBUGMSG >= _DBG_NORMAL 805 LOG(LS_INFO) << "enter recovery"; 806 LOG(LS_INFO) << "recovery retransmit"; 807 #endif // _DEBUGMSG 808 if (!transmit(m_slist.begin(), now)) { 809 closedown(ECONNABORTED); 810 return false; 811 } 812 m_recover = m_snd_nxt; 813 uint32 nInFlight = m_snd_nxt - m_snd_una; 814 m_ssthresh = talk_base::_max(nInFlight / 2, 2 * m_mss); 815 //LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << " nInFlight: " << nInFlight << " m_mss: " << m_mss; 816 m_cwnd = m_ssthresh + 3 * m_mss; 817 } else if (m_dup_acks > 3) { 818 m_cwnd += m_mss; 819 } 820 } else { 821 m_dup_acks = 0; 822 } 823 } 824 825 // !?! A bit hacky 826 if ((m_state == TCP_SYN_RECEIVED) && !bConnect) { 827 m_state = TCP_ESTABLISHED; 828 LOG(LS_INFO) << "State: TCP_ESTABLISHED"; 829 adjustMTU(); 830 if (m_notify) { 831 m_notify->OnTcpOpen(this); 832 } 833 //notify(evOpen); 834 } 835 836 // If we make room in the send queue, notify the user 837 // The goal it to make sure we always have at least enough data to fill the 838 // window. We'd like to notify the app when we are halfway to that point. 839 const uint32 kIdealRefillSize = (m_sbuf_len + m_rbuf_len) / 2; 840 size_t snd_buffered = 0; 841 m_sbuf.GetBuffered(&snd_buffered); 842 if (m_bWriteEnable && static_cast<uint32>(snd_buffered) < kIdealRefillSize) { 843 m_bWriteEnable = false; 844 if (m_notify) { 845 m_notify->OnTcpWriteable(this); 846 } 847 //notify(evWrite); 848 } 849 850 // Conditions were acks must be sent: 851 // 1) Segment is too old (they missed an ACK) (immediately) 852 // 2) Segment is too new (we missed a segment) (immediately) 853 // 3) Segment has data (so we need to ACK!) (delayed) 854 // ... so the only time we don't need to ACK, is an empty segment that points to rcv_nxt! 855 856 SendFlags sflags = sfNone; 857 if (seg.seq != m_rcv_nxt) { 858 sflags = sfImmediateAck; // (Fast Recovery) 859 } else if (seg.len != 0) { 860 if (m_ack_delay == 0) { 861 sflags = sfImmediateAck; 862 } else { 863 sflags = sfDelayedAck; 864 } 865 } 866 #if _DEBUGMSG >= _DBG_NORMAL 867 if (sflags == sfImmediateAck) { 868 if (seg.seq > m_rcv_nxt) { 869 LOG_F(LS_INFO) << "too new"; 870 } else if (seg.seq + seg.len <= m_rcv_nxt) { 871 LOG_F(LS_INFO) << "too old"; 872 } 873 } 874 #endif // _DEBUGMSG 875 876 // Adjust the incoming segment to fit our receive buffer 877 if (seg.seq < m_rcv_nxt) { 878 uint32 nAdjust = m_rcv_nxt - seg.seq; 879 if (nAdjust < seg.len) { 880 seg.seq += nAdjust; 881 seg.data += nAdjust; 882 seg.len -= nAdjust; 883 } else { 884 seg.len = 0; 885 } 886 } 887 888 size_t available_space = 0; 889 m_rbuf.GetWriteRemaining(&available_space); 890 891 if ((seg.seq + seg.len - m_rcv_nxt) > static_cast<uint32>(available_space)) { 892 uint32 nAdjust = seg.seq + seg.len - m_rcv_nxt - static_cast<uint32>(available_space); 893 if (nAdjust < seg.len) { 894 seg.len -= nAdjust; 895 } else { 896 seg.len = 0; 897 } 898 } 899 900 bool bIgnoreData = (seg.flags & FLAG_CTL) || (m_shutdown != SD_NONE); 901 bool bNewData = false; 902 903 if (seg.len > 0) { 904 if (bIgnoreData) { 905 if (seg.seq == m_rcv_nxt) { 906 m_rcv_nxt += seg.len; 907 } 908 } else { 909 uint32 nOffset = seg.seq - m_rcv_nxt; 910 911 talk_base::StreamResult result = m_rbuf.WriteOffset(seg.data, seg.len, 912 nOffset, NULL); 913 ASSERT(result == talk_base::SR_SUCCESS); 914 UNUSED(result); 915 916 if (seg.seq == m_rcv_nxt) { 917 m_rbuf.ConsumeWriteBuffer(seg.len); 918 m_rcv_nxt += seg.len; 919 m_rcv_wnd -= seg.len; 920 bNewData = true; 921 922 RList::iterator it = m_rlist.begin(); 923 while ((it != m_rlist.end()) && (it->seq <= m_rcv_nxt)) { 924 if (it->seq + it->len > m_rcv_nxt) { 925 sflags = sfImmediateAck; // (Fast Recovery) 926 uint32 nAdjust = (it->seq + it->len) - m_rcv_nxt; 927 #if _DEBUGMSG >= _DBG_NORMAL 928 LOG(LS_INFO) << "Recovered " << nAdjust << " bytes (" << m_rcv_nxt << " -> " << m_rcv_nxt + nAdjust << ")"; 929 #endif // _DEBUGMSG 930 m_rbuf.ConsumeWriteBuffer(nAdjust); 931 m_rcv_nxt += nAdjust; 932 m_rcv_wnd -= nAdjust; 933 } 934 it = m_rlist.erase(it); 935 } 936 } else { 937 #if _DEBUGMSG >= _DBG_NORMAL 938 LOG(LS_INFO) << "Saving " << seg.len << " bytes (" << seg.seq << " -> " << seg.seq + seg.len << ")"; 939 #endif // _DEBUGMSG 940 RSegment rseg; 941 rseg.seq = seg.seq; 942 rseg.len = seg.len; 943 RList::iterator it = m_rlist.begin(); 944 while ((it != m_rlist.end()) && (it->seq < rseg.seq)) { 945 ++it; 946 } 947 m_rlist.insert(it, rseg); 948 } 949 } 950 } 951 952 attemptSend(sflags); 953 954 // If we have new data, notify the user 955 if (bNewData && m_bReadEnable) { 956 m_bReadEnable = false; 957 if (m_notify) { 958 m_notify->OnTcpReadable(this); 959 } 960 //notify(evRead); 961 } 962 963 return true; 964 } 965 966 bool PseudoTcp::transmit(const SList::iterator& seg, uint32 now) { 967 if (seg->xmit >= ((m_state == TCP_ESTABLISHED) ? 15 : 30)) { 968 LOG_F(LS_VERBOSE) << "too many retransmits"; 969 return false; 970 } 971 972 uint32 nTransmit = talk_base::_min(seg->len, m_mss); 973 974 while (true) { 975 uint32 seq = seg->seq; 976 uint8 flags = (seg->bCtrl ? FLAG_CTL : 0); 977 IPseudoTcpNotify::WriteResult wres = packet(seq, 978 flags, 979 seg->seq - m_snd_una, 980 nTransmit); 981 982 if (wres == IPseudoTcpNotify::WR_SUCCESS) 983 break; 984 985 if (wres == IPseudoTcpNotify::WR_FAIL) { 986 LOG_F(LS_VERBOSE) << "packet failed"; 987 return false; 988 } 989 990 ASSERT(wres == IPseudoTcpNotify::WR_TOO_LARGE); 991 992 while (true) { 993 if (PACKET_MAXIMUMS[m_msslevel + 1] == 0) { 994 LOG_F(LS_VERBOSE) << "MTU too small"; 995 return false; 996 } 997 // !?! We need to break up all outstanding and pending packets and then retransmit!?! 998 999 m_mss = PACKET_MAXIMUMS[++m_msslevel] - PACKET_OVERHEAD; 1000 m_cwnd = 2 * m_mss; // I added this... haven't researched actual formula 1001 if (m_mss < nTransmit) { 1002 nTransmit = m_mss; 1003 break; 1004 } 1005 } 1006 #if _DEBUGMSG >= _DBG_NORMAL 1007 LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes"; 1008 #endif // _DEBUGMSG 1009 } 1010 1011 if (nTransmit < seg->len) { 1012 LOG_F(LS_VERBOSE) << "mss reduced to " << m_mss; 1013 1014 SSegment subseg(seg->seq + nTransmit, seg->len - nTransmit, seg->bCtrl); 1015 //subseg.tstamp = seg->tstamp; 1016 subseg.xmit = seg->xmit; 1017 seg->len = nTransmit; 1018 1019 SList::iterator next = seg; 1020 m_slist.insert(++next, subseg); 1021 } 1022 1023 if (seg->xmit == 0) { 1024 m_snd_nxt += seg->len; 1025 } 1026 seg->xmit += 1; 1027 //seg->tstamp = now; 1028 if (m_rto_base == 0) { 1029 m_rto_base = now; 1030 } 1031 1032 return true; 1033 } 1034 1035 void PseudoTcp::attemptSend(SendFlags sflags) { 1036 uint32 now = Now(); 1037 1038 if (talk_base::TimeDiff(now, m_lastsend) > static_cast<long>(m_rx_rto)) { 1039 m_cwnd = m_mss; 1040 } 1041 1042 #if _DEBUGMSG 1043 bool bFirst = true; 1044 UNUSED(bFirst); 1045 #endif // _DEBUGMSG 1046 1047 while (true) { 1048 uint32 cwnd = m_cwnd; 1049 if ((m_dup_acks == 1) || (m_dup_acks == 2)) { // Limited Transmit 1050 cwnd += m_dup_acks * m_mss; 1051 } 1052 uint32 nWindow = talk_base::_min(m_snd_wnd, cwnd); 1053 uint32 nInFlight = m_snd_nxt - m_snd_una; 1054 uint32 nUseable = (nInFlight < nWindow) ? (nWindow - nInFlight) : 0; 1055 1056 size_t snd_buffered = 0; 1057 m_sbuf.GetBuffered(&snd_buffered); 1058 uint32 nAvailable = 1059 talk_base::_min(static_cast<uint32>(snd_buffered) - nInFlight, m_mss); 1060 1061 if (nAvailable > nUseable) { 1062 if (nUseable * 4 < nWindow) { 1063 // RFC 813 - avoid SWS 1064 nAvailable = 0; 1065 } else { 1066 nAvailable = nUseable; 1067 } 1068 } 1069 1070 #if _DEBUGMSG >= _DBG_VERBOSE 1071 if (bFirst) { 1072 size_t available_space = 0; 1073 m_sbuf.GetWriteRemaining(&available_space); 1074 1075 bFirst = false; 1076 LOG(LS_INFO) << "[cwnd: " << m_cwnd 1077 << " nWindow: " << nWindow 1078 << " nInFlight: " << nInFlight 1079 << " nAvailable: " << nAvailable 1080 << " nQueued: " << snd_buffered 1081 << " nEmpty: " << available_space 1082 << " ssthresh: " << m_ssthresh << "]"; 1083 } 1084 #endif // _DEBUGMSG 1085 1086 if (nAvailable == 0) { 1087 if (sflags == sfNone) 1088 return; 1089 1090 // If this is an immediate ack, or the second delayed ack 1091 if ((sflags == sfImmediateAck) || m_t_ack) { 1092 packet(m_snd_nxt, 0, 0, 0); 1093 } else { 1094 m_t_ack = Now(); 1095 } 1096 return; 1097 } 1098 1099 // Nagle's algorithm. 1100 // If there is data already in-flight, and we haven't a full segment of 1101 // data ready to send then hold off until we get more to send, or the 1102 // in-flight data is acknowledged. 1103 if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable < m_mss)) { 1104 return; 1105 } 1106 1107 // Find the next segment to transmit 1108 SList::iterator it = m_slist.begin(); 1109 while (it->xmit > 0) { 1110 ++it; 1111 ASSERT(it != m_slist.end()); 1112 } 1113 SList::iterator seg = it; 1114 1115 // If the segment is too large, break it into two 1116 if (seg->len > nAvailable) { 1117 SSegment subseg(seg->seq + nAvailable, seg->len - nAvailable, seg->bCtrl); 1118 seg->len = nAvailable; 1119 m_slist.insert(++it, subseg); 1120 } 1121 1122 if (!transmit(seg, now)) { 1123 LOG_F(LS_VERBOSE) << "transmit failed"; 1124 // TODO: consider closing socket 1125 return; 1126 } 1127 1128 sflags = sfNone; 1129 } 1130 } 1131 1132 void 1133 PseudoTcp::closedown(uint32 err) { 1134 LOG(LS_INFO) << "State: TCP_CLOSED"; 1135 m_state = TCP_CLOSED; 1136 if (m_notify) { 1137 m_notify->OnTcpClosed(this, err); 1138 } 1139 //notify(evClose, err); 1140 } 1141 1142 void 1143 PseudoTcp::adjustMTU() { 1144 // Determine our current mss level, so that we can adjust appropriately later 1145 for (m_msslevel = 0; PACKET_MAXIMUMS[m_msslevel + 1] > 0; ++m_msslevel) { 1146 if (static_cast<uint16>(PACKET_MAXIMUMS[m_msslevel]) <= m_mtu_advise) { 1147 break; 1148 } 1149 } 1150 m_mss = m_mtu_advise - PACKET_OVERHEAD; 1151 // !?! Should we reset m_largest here? 1152 #if _DEBUGMSG >= _DBG_NORMAL 1153 LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes"; 1154 #endif // _DEBUGMSG 1155 // Enforce minimums on ssthresh and cwnd 1156 m_ssthresh = talk_base::_max(m_ssthresh, 2 * m_mss); 1157 m_cwnd = talk_base::_max(m_cwnd, m_mss); 1158 } 1159 1160 bool 1161 PseudoTcp::isReceiveBufferFull() const { 1162 size_t available_space = 0; 1163 m_rbuf.GetWriteRemaining(&available_space); 1164 return !available_space; 1165 } 1166 1167 void 1168 PseudoTcp::disableWindowScale() { 1169 m_support_wnd_scale = false; 1170 } 1171 1172 void 1173 PseudoTcp::queueConnectMessage() { 1174 talk_base::ByteBuffer buf(talk_base::ByteBuffer::ORDER_NETWORK); 1175 1176 buf.WriteUInt8(CTL_CONNECT); 1177 if (m_support_wnd_scale) { 1178 buf.WriteUInt8(TCP_OPT_WND_SCALE); 1179 buf.WriteUInt8(1); 1180 buf.WriteUInt8(m_rwnd_scale); 1181 } 1182 m_snd_wnd = static_cast<uint32>(buf.Length()); 1183 queue(buf.Data(), static_cast<uint32>(buf.Length()), true); 1184 } 1185 1186 void 1187 PseudoTcp::parseOptions(const char* data, uint32 len) { 1188 std::set<uint8> options_specified; 1189 1190 // See http://www.freesoft.org/CIE/Course/Section4/8.htm for 1191 // parsing the options list. 1192 talk_base::ByteBuffer buf(data, len); 1193 while (buf.Length()) { 1194 uint8 kind = TCP_OPT_EOL; 1195 buf.ReadUInt8(&kind); 1196 1197 if (kind == TCP_OPT_EOL) { 1198 // End of option list. 1199 break; 1200 } else if (kind == TCP_OPT_NOOP) { 1201 // No op. 1202 continue; 1203 } 1204 1205 // Length of this option. 1206 ASSERT(len != 0); 1207 UNUSED(len); 1208 uint8 opt_len = 0; 1209 buf.ReadUInt8(&opt_len); 1210 1211 // Content of this option. 1212 if (opt_len <= buf.Length()) { 1213 applyOption(kind, buf.Data(), opt_len); 1214 buf.Consume(opt_len); 1215 } else { 1216 LOG(LS_ERROR) << "Invalid option length received."; 1217 return; 1218 } 1219 options_specified.insert(kind); 1220 } 1221 1222 if (options_specified.find(TCP_OPT_WND_SCALE) == options_specified.end()) { 1223 LOG(LS_WARNING) << "Peer doesn't support window scaling"; 1224 1225 if (m_rwnd_scale > 0) { 1226 // Peer doesn't support TCP options and window scaling. 1227 // Revert receive buffer size to default value. 1228 resizeReceiveBuffer(DEFAULT_RCV_BUF_SIZE); 1229 m_swnd_scale = 0; 1230 } 1231 } 1232 } 1233 1234 void 1235 PseudoTcp::applyOption(char kind, const char* data, uint32 len) { 1236 if (kind == TCP_OPT_MSS) { 1237 LOG(LS_WARNING) << "Peer specified MSS option which is not supported."; 1238 // TODO: Implement. 1239 } else if (kind == TCP_OPT_WND_SCALE) { 1240 // Window scale factor. 1241 // http://www.ietf.org/rfc/rfc1323.txt 1242 if (len != 1) { 1243 LOG_F(WARNING) << "Invalid window scale option received."; 1244 return; 1245 } 1246 applyWindowScaleOption(data[0]); 1247 } 1248 } 1249 1250 void 1251 PseudoTcp::applyWindowScaleOption(uint8 scale_factor) { 1252 m_swnd_scale = scale_factor; 1253 } 1254 1255 void 1256 PseudoTcp::resizeSendBuffer(uint32 new_size) { 1257 m_sbuf_len = new_size; 1258 m_sbuf.SetCapacity(new_size); 1259 } 1260 1261 void 1262 PseudoTcp::resizeReceiveBuffer(uint32 new_size) { 1263 uint8 scale_factor = 0; 1264 1265 // Determine the scale factor such that the scaled window size can fit 1266 // in a 16-bit unsigned integer. 1267 while (new_size > 0xFFFF) { 1268 ++scale_factor; 1269 new_size >>= 1; 1270 } 1271 1272 // Determine the proper size of the buffer. 1273 new_size <<= scale_factor; 1274 bool result = m_rbuf.SetCapacity(new_size); 1275 1276 // Make sure the new buffer is large enough to contain data in the old 1277 // buffer. This should always be true because this method is called either 1278 // before connection is established or when peers are exchanging connect 1279 // messages. 1280 ASSERT(result); 1281 UNUSED(result); 1282 m_rbuf_len = new_size; 1283 m_rwnd_scale = scale_factor; 1284 m_ssthresh = new_size; 1285 1286 size_t available_space = 0; 1287 m_rbuf.GetWriteRemaining(&available_space); 1288 m_rcv_wnd = static_cast<uint32>(available_space); 1289 } 1290 1291 } // namespace cricket 1292