fix nagle implementation in uTP

This commit is contained in:
Arvid Norberg
2012-06-25 06:27:37 +00:00
parent c691205ff7
commit e51e953cb9
2 changed files with 222 additions and 85 deletions

View File

@@ -1,3 +1,5 @@
* fix nagle implementation in uTP
* minor uTP tweaks * minor uTP tweaks
* fix end-game mode issue when some files are selected to not be downloaded * fix end-game mode issue when some files are selected to not be downloaded
* improve uTP slow start * improve uTP slow start

View File

@@ -136,6 +136,9 @@ struct packet
// the last time this packet was sent // the last time this packet was sent
ptime send_time; ptime send_time;
// the number of bytes actually allocated in 'buf'
boost::uint16_t allocated;
// the size of the buffer 'buf' points to // the size of the buffer 'buf' points to
boost::uint16_t size; boost::uint16_t size;
@@ -157,7 +160,7 @@ struct packet
bool mtu_probe:1; bool mtu_probe:1;
// the actual packet buffer // the actual packet buffer
char buf[]; boost::uint8_t buf[];
}; };
// since the uTP socket state may be needed after the // since the uTP socket state may be needed after the
@@ -214,6 +217,7 @@ struct utp_socket_impl
, void* userdata, utp_socket_manager* sm) , void* userdata, utp_socket_manager* sm)
: m_sm(sm) : m_sm(sm)
, m_userdata(userdata) , m_userdata(userdata)
, m_nagle_packet(NULL)
, m_read_handler(0) , m_read_handler(0)
, m_write_handler(0) , m_write_handler(0)
, m_connect_handler(0) , m_connect_handler(0)
@@ -271,7 +275,7 @@ struct utp_socket_impl
void tick(ptime const& now); void tick(ptime const& now);
void init_mtu(int link_mtu, int utp_mtu); void init_mtu(int link_mtu, int utp_mtu);
bool incoming_packet(char const* buf, int size bool incoming_packet(boost::uint8_t const* buf, int size
, udp::endpoint const& ep, ptime receive_time); , udp::endpoint const& ep, ptime receive_time);
bool should_delete() const; bool should_delete() const;
tcp::endpoint remote_endpoint(error_code& ec) const tcp::endpoint remote_endpoint(error_code& ec) const
@@ -291,17 +295,18 @@ struct utp_socket_impl
void send_fin(); void send_fin();
void defer_ack(); void defer_ack();
void remove_sack_header(packet* p);
bool send_pkt(bool ack); bool send_pkt(bool ack);
bool resend_packet(packet* p, bool fast_resend = false); bool resend_packet(packet* p, bool fast_resend = false);
void send_reset(utp_header* ph); void send_reset(utp_header* ph);
void parse_sack(boost::uint16_t packet_ack, char const* ptr, int size, int* acked_bytes void parse_sack(boost::uint16_t packet_ack, boost::uint8_t const* ptr, int size, int* acked_bytes
, ptime const now, boost::uint32_t& min_rtt); , ptime const now, boost::uint32_t& min_rtt);
void write_payload(char* ptr, int size); void write_payload(boost::uint8_t* ptr, int size);
void maybe_inc_acked_seq_nr(); void maybe_inc_acked_seq_nr();
void ack_packet(packet* p, ptime const& receive_time void ack_packet(packet* p, ptime const& receive_time
, boost::uint32_t& min_rtt, boost::uint16_t seq_nr); , boost::uint32_t& min_rtt, boost::uint16_t seq_nr);
void write_sack(char* buf, int size) const; void write_sack(boost::uint8_t* buf, int size) const;
void incoming(char const* buf, int size, packet* p, ptime now); void incoming(boost::uint8_t const* buf, int size, packet* p, ptime now);
void do_ledbat(int acked_bytes, int delay, int in_flight, ptime const now); void do_ledbat(int acked_bytes, int delay, int in_flight, ptime const now);
int packet_timeout() const; int packet_timeout() const;
bool test_socket_state(); bool test_socket_state();
@@ -309,7 +314,7 @@ struct utp_socket_impl
void maybe_trigger_send_callback(ptime now); void maybe_trigger_send_callback(ptime now);
bool cancel_handlers(error_code const& ec, bool kill); bool cancel_handlers(error_code const& ec, bool kill);
bool consume_incoming_data( bool consume_incoming_data(
utp_header const* ph, char const* ptr, int payload_size, ptime now); utp_header const* ph, boost::uint8_t const* ptr, int payload_size, ptime now);
void update_mtu_limits(); void update_mtu_limits();
void experienced_loss(int seq_nr); void experienced_loss(int seq_nr);
@@ -350,6 +355,11 @@ struct utp_socket_impl
// buffers. Buffers that empty are erased from the vector. // buffers. Buffers that empty are erased from the vector.
std::vector<iovec_t> m_write_buffer; std::vector<iovec_t> m_write_buffer;
// if this is non NULL, it's a packet. This packet was held off because
// of NAGLE. We couldn't send it immediately. It's left
// here to accrue more bytes before we send it.
packet* m_nagle_packet;
// the user provided read buffer. If this has a size greater // the user provided read buffer. If this has a size greater
// than 0, we'll always prefer using it over putting received // than 0, we'll always prefer using it over putting received
// data in the m_receive_buffer. As data is stored in the // data in the m_receive_buffer. As data is stored in the
@@ -651,7 +661,7 @@ void utp_init_mtu(utp_socket_impl* s, int link_mtu, int utp_mtu)
bool utp_incoming_packet(utp_socket_impl* s, char const* p bool utp_incoming_packet(utp_socket_impl* s, char const* p
, int size, udp::endpoint const& ep, ptime receive_time) , int size, udp::endpoint const& ep, ptime receive_time)
{ {
return s->incoming_packet(p, size, ep, receive_time); return s->incoming_packet((boost::uint8_t const*)p, size, ep, receive_time);
} }
bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id) bool utp_match(utp_socket_impl* s, udp::endpoint const& ep, boost::uint16_t id)
@@ -1321,7 +1331,7 @@ std::size_t utp_socket_impl::available() const
return m_receive_buffer_size; return m_receive_buffer_size;
} }
void utp_socket_impl::parse_sack(boost::uint16_t packet_ack, char const* ptr void utp_socket_impl::parse_sack(boost::uint16_t packet_ack, boost::uint8_t const* ptr
, int size, int* acked_bytes, ptime const now, boost::uint32_t& min_rtt) , int size, int* acked_bytes, ptime const now, boost::uint32_t& min_rtt)
{ {
if (size == 0) return; if (size == 0) return;
@@ -1332,7 +1342,7 @@ void utp_socket_impl::parse_sack(boost::uint16_t packet_ack, char const* ptr
#if TORRENT_VERBOSE_UTP_LOG #if TORRENT_VERBOSE_UTP_LOG
std::string bitmask; std::string bitmask;
bitmask.reserve(size); bitmask.reserve(size);
for (char const* b = ptr, *end = ptr + size; b != end; ++b) for (boost::uint8_t const* b = ptr, *end = ptr + size; b != end; ++b)
{ {
unsigned char bitfield = unsigned(*b); unsigned char bitfield = unsigned(*b);
unsigned char mask = 1; unsigned char mask = 1;
@@ -1355,7 +1365,7 @@ void utp_socket_impl::parse_sack(boost::uint16_t packet_ack, char const* ptr
int last_ack = packet_ack; int last_ack = packet_ack;
// for each byte // for each byte
for (char const* end = ptr + size; ptr != end; ++ptr) for (boost::uint8_t const* end = ptr + size; ptr != end; ++ptr)
{ {
unsigned char bitfield = unsigned(*ptr); unsigned char bitfield = unsigned(*ptr);
unsigned char mask = 1; unsigned char mask = 1;
@@ -1420,7 +1430,7 @@ void utp_socket_impl::parse_sack(boost::uint16_t packet_ack, char const* ptr
// copies data from the write buffer into the packet // copies data from the write buffer into the packet
// pointed to by ptr // pointed to by ptr
void utp_socket_impl::write_payload(char* ptr, int size) void utp_socket_impl::write_payload(boost::uint8_t* ptr, int size)
{ {
#ifdef TORRENT_DEBUG #ifdef TORRENT_DEBUG
int write_buffer_size = 0; int write_buffer_size = 0;
@@ -1487,6 +1497,28 @@ void utp_socket_impl::defer_ack()
m_sm->defer_ack(this); m_sm->defer_ack(this);
} }
void utp_socket_impl::remove_sack_header(packet* p)
{
// remove the sack header
boost::uint8_t* ptr = p->buf + sizeof(utp_header);
utp_header* h = (utp_header*)p->buf;
TORRENT_ASSERT(h->extension == 1);
h->extension = ptr[0];
int sack_size = ptr[1];
TORRENT_ASSERT(h->extension == 0);
UTP_LOGV("%8p: removing SACK header, %d bytes\n"
, this, sack_size + 2);
TORRENT_ASSERT(p->size >= p->header_size + sack_size + 2);
TORRENT_ASSERT(p->header_size >= sizeof(utp_header) + sack_size + 2);
memmove(ptr, ptr + sack_size + 2, p->size - p->header_size);
p->header_size -= sack_size + 2;
p->size -= sack_size + 2;
}
// sends a packet, pulls data from the write buffer (if there's any) // sends a packet, pulls data from the write buffer (if there's any)
// if ack is true, we need to send a packet regardless of if there's // if ack is true, we need to send a packet regardless of if there's
// any data. Returns true if we could send more data (i.e. call // any data. Returns true if we could send more data (i.e. call
@@ -1522,8 +1554,6 @@ bool utp_socket_impl::send_pkt(bool ack)
m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK; m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK;
} }
bool ret = false;
int sack = 0; int sack = 0;
if (m_inbuf.size()) if (m_inbuf.size())
{ {
@@ -1536,10 +1566,7 @@ bool utp_socket_impl::send_pkt(bool ack)
int header_size = sizeof(utp_header) + (sack ? sack + 2 : 0); int header_size = sizeof(utp_header) + (sack ? sack + 2 : 0);
int payload_size = m_write_buffer_size; int payload_size = m_write_buffer_size;
if (m_mtu - header_size < payload_size) if (m_mtu - header_size < payload_size)
{
payload_size = m_mtu - header_size; payload_size = m_mtu - header_size;
ret = true; // there's more data to send
}
// if we have one MSS worth of data, make sure it fits in our // if we have one MSS worth of data, make sure it fits in our
// congestion window and the advertized receive window from // congestion window and the advertized receive window from
@@ -1556,49 +1583,42 @@ bool utp_socket_impl::send_pkt(bool ack)
m_last_cwnd_hit = time_now_hires(); m_last_cwnd_hit = time_now_hires();
m_cwnd_full = true; m_cwnd_full = true;
// there's no more space in the cwnd, no need to
// try to send more right now
ret = false;
UTP_LOGV("%8p: no space in window send_buffer_size:%d cwnd:%d " UTP_LOGV("%8p: no space in window send_buffer_size:%d cwnd:%d "
"ret:%d adv_wnd:%d in-flight:%d mtu:%d\n" "adv_wnd:%d in-flight:%d mtu:%d\n"
, this, m_write_buffer_size, int(m_cwnd >> 16) , this, m_write_buffer_size, int(m_cwnd >> 16)
, ret, m_adv_wnd, m_bytes_in_flight, m_mtu); , m_adv_wnd, m_bytes_in_flight, m_mtu);
if (!ack)
{
#if TORRENT_UTP_LOG
UTP_LOGV("%8p: skipping send seq_nr:%d ack_nr:%d "
"id:%d target:%s header_size:%d error:%s send_buffer_size:%d cwnd:%d "
"adv_wnd:%d in-flight:%d mtu:%d\n"
, this, int(m_seq_nr), int(m_ack_nr)
, m_send_id, print_endpoint(udp::endpoint(m_remote_address, m_port)).c_str()
, header_size, m_error.message().c_str(), m_write_buffer_size, int(m_cwnd >> 16)
, m_adv_wnd, m_bytes_in_flight, m_mtu);
#endif
return false;
}
} }
// if we don't have any data to send, or can't send any data // if we don't have any data to send, or can't send any data
// and we don't have any data to ack, don't send a packet // and we don't have any data to ack, don't send a packet
if (payload_size == 0 && !ack) if (payload_size == 0 && !ack && !m_nagle_packet)
{ {
#if TORRENT_UTP_LOG #if TORRENT_UTP_LOG
UTP_LOGV("%8p: skipping send seq_nr:%d ack_nr:%d " UTP_LOGV("%8p: skipping send (no payload and no ack) seq_nr:%d ack_nr:%d "
"id:%d target:%s header_size:%d error:%s send_buffer_size:%d cwnd:%d " "id:%d target:%s header_size:%d error:%s send_buffer_size:%d cwnd:%d "
"ret:%d adv_wnd:%d in-flight:%d mtu:%d\n" "adv_wnd:%d in-flight:%d mtu:%d\n"
, this, int(m_seq_nr), int(m_ack_nr) , this, int(m_seq_nr), int(m_ack_nr)
, m_send_id, print_endpoint(udp::endpoint(m_remote_address, m_port)).c_str() , m_send_id, print_endpoint(udp::endpoint(m_remote_address, m_port)).c_str()
, header_size, m_error.message().c_str(), m_write_buffer_size, int(m_cwnd >> 16) , header_size, m_error.message().c_str(), m_write_buffer_size, int(m_cwnd >> 16)
, int(ret), m_adv_wnd, m_bytes_in_flight, m_mtu); , m_adv_wnd, m_bytes_in_flight, m_mtu);
#endif #endif
return false; return false;
} }
if (((m_seq_nr - m_acked_seq_nr) & ACK_MASK) > 1
&& payload_size < m_mtu - header_size
&& !ack
&& m_nagle)
{
// this is nagle. If we don't have a full packet
// worth of payload to send AND we have at least
// one outstanding packet, hold off. Once the
// outstanding packet is acked, we'll send this
// payload
UTP_LOGV("%8p: NAGLE not enough payload send_buffer_size:%d cwnd:%d "
"ret:%d adv_wnd:%d in-flight:%d mtu:%d\n"
, this, m_write_buffer_size, int(m_cwnd >> 16)
, ret, m_adv_wnd, m_bytes_in_flight, m_mtu);
return false;
}
int packet_size = header_size + payload_size; int packet_size = header_size + payload_size;
// MTU DISCOVERY // MTU DISCOVERY
@@ -1611,31 +1631,104 @@ bool utp_socket_impl::send_pkt(bool ack)
m_mtu_seq = m_seq_nr; m_mtu_seq = m_seq_nr;
} }
packet* p; packet* p = NULL;
// we only need a heap allocation if we have payload and boost::uint8_t* ptr = NULL;
// need to keep the packet around (in the outbuf) utp_header* h = NULL;
if (payload_size) p = (packet*)malloc(sizeof(packet) + packet_size);
else p = (packet*)TORRENT_ALLOCA(char, sizeof(packet) + packet_size);
p->size = packet_size; // payload size being zero means we're just sending
p->header_size = packet_size - payload_size; // and ack. We should not pick up the nagle packet
p->num_transmissions = 1; if (!m_nagle_packet || (payload_size == 0 && ack))
p->need_resend = false; {
p->mtu_probe = use_as_probe; // we only need a heap allocation if we have payload and
char* ptr = p->buf; // need to keep the packet around (in the outbuf)
utp_header* h = (utp_header*)ptr; #ifdef TORRENT_DEBUG
ptr += sizeof(utp_header); bool stack_alloced = false;
#endif
if (payload_size)
{
p = (packet*)malloc(sizeof(packet) + m_mtu);
p->allocated = m_mtu;
}
else
{
#ifdef TORRENT_DEBUG
stack_alloced = true;
#endif
TORRENT_ASSERT(ack);
p = (packet*)TORRENT_ALLOCA(char, sizeof(packet) + packet_size);
UTP_LOGV("%8p: allocating %d bytes on the stack\n", this, packet_size);
p->allocated = packet_size;
}
h->type_ver = ((payload_size ? ST_DATA : ST_STATE) << 4) | 1; p->size = packet_size;
h->extension = sack ? 1 : 0; p->header_size = packet_size - payload_size;
h->connection_id = m_send_id; p->num_transmissions = 0;
h->timestamp_difference_microseconds = m_reply_micro; p->need_resend = false;
h->wnd_size = m_in_buf_size - m_buffered_incoming_bytes - m_receive_buffer_size; p->mtu_probe = use_as_probe;
// seq_nr is ignored for ST_STATE packets, so it doesn't ptr = p->buf;
// matter that we say this is a sequence number we haven't h = (utp_header*)ptr;
// actually sent yet ptr += sizeof(utp_header);
h->seq_nr = m_seq_nr;
h->ack_nr = m_ack_nr; h->extension = sack ? 1 : 0;
h->connection_id = m_send_id;
// seq_nr is ignored for ST_STATE packets, so it doesn't
// matter that we say this is a sequence number we haven't
// actually sent yet
h->seq_nr = m_seq_nr;
h->type_ver = ((payload_size ? ST_DATA : ST_STATE) << 4) | 1;
write_payload(p->buf + p->header_size, payload_size);
}
else
{
// pick up the nagle packet and keep adding bytes to it
p = m_nagle_packet;
ptr = p->buf + sizeof(utp_header);
h = (utp_header*)p->buf;
// if the packet has a selective ack header, we'll need
// to update it
if (h->extension == 1)
{
sack = ptr[1];
if (m_inbuf.size() == 0 && h->ack_nr != m_ack_nr)
{
// we need to remove the sack header
remove_sack_header(p);
sack = 0;
}
}
else
sack = 0;
int size_left = p->allocated - p->size;
TORRENT_ASSERT(size_left > 0);
size_left = (std::min)(size_left, m_write_buffer_size);
write_payload(p->buf + p->size, size_left);
p->size += size_left;
UTP_LOGV("%8p: NAGLE appending %d bytes to nagle packet. new size: %d allocated: %d\n"
, this, size_left, p->size, p->allocated);
// did we fill up the whole mtu?
// if we didn't, we may still send it if there's
// no bytes in flight
if (m_bytes_in_flight > 0
&& p->size < p->allocated
&& !ack
&& m_nagle)
{
return false;
}
// clear the nagle packet pointer and fall through
// sending p
m_nagle_packet = NULL;
packet_size = p->size;
payload_size = p->size - p->header_size;
}
if (sack) if (sack)
{ {
@@ -1643,11 +1736,34 @@ bool utp_socket_impl::send_pkt(bool ack)
*ptr++ = sack; // bytes for SACK bitfield *ptr++ = sack; // bytes for SACK bitfield
write_sack(ptr, sack); write_sack(ptr, sack);
ptr += sack; ptr += sack;
TORRENT_ASSERT(ptr <= p->buf + p->header_size);
} }
write_payload(ptr, payload_size); if (m_bytes_in_flight > 0
&& payload_size < m_mtu - header_size
&& !ack
&& m_nagle)
{
// this is nagle. If we don't have a full packet
// worth of payload to send AND we have at least
// one outstanding packet, hold off. Once the
// outstanding packet is acked, we'll send this
// payload
UTP_LOGV("%8p: NAGLE not enough payload send_buffer_size:%d cwnd:%d "
"adv_wnd:%d in-flight:%d mtu:%d\n"
, this, m_write_buffer_size, int(m_cwnd >> 16)
, m_adv_wnd, m_bytes_in_flight, m_mtu);
TORRENT_ASSERT(m_nagle_packet == NULL);
m_nagle_packet = p;
return false;
}
h->timestamp_difference_microseconds = m_reply_micro;
h->wnd_size = m_in_buf_size - m_buffered_incoming_bytes - m_receive_buffer_size;
h->ack_nr = m_ack_nr;
// fill in the timestamp as late as possible // fill in the timestamp as late as possible
++p->num_transmissions;
ptime now = time_now_hires(); ptime now = time_now_hires();
p->send_time = now; p->send_time = now;
h->timestamp_microseconds = boost::uint32_t(total_microseconds(now - min_time())); h->timestamp_microseconds = boost::uint32_t(total_microseconds(now - min_time()));
@@ -1671,7 +1787,7 @@ bool utp_socket_impl::send_pkt(bool ack)
// if ((rand() % 100) > 0) // if ((rand() % 100) > 0)
#endif #endif
m_sm->send_packet(udp::endpoint(m_remote_address, m_port) m_sm->send_packet(udp::endpoint(m_remote_address, m_port)
, (char const*)h, packet_size, ec , (char const*)h, p->size, ec
, use_as_probe ? utp_socket_manager::dont_fragment : 0); , use_as_probe ? utp_socket_manager::dont_fragment : 0);
++m_out_packets; ++m_out_packets;
@@ -1711,18 +1827,18 @@ bool utp_socket_impl::send_pkt(bool ack)
} }
m_seq_nr = (m_seq_nr + 1) & ACK_MASK; m_seq_nr = (m_seq_nr + 1) & ACK_MASK;
TORRENT_ASSERT(payload_size >= 0); TORRENT_ASSERT(payload_size >= 0);
m_bytes_in_flight += payload_size; m_bytes_in_flight += p->size - p->header_size;
} }
return ret; return m_write_buffer_size > 0 && !m_cwnd_full;
} }
// size is in bytes // size is in bytes
void utp_socket_impl::write_sack(char* buf, int size) const void utp_socket_impl::write_sack(boost::uint8_t* buf, int size) const
{ {
TORRENT_ASSERT(m_inbuf.size()); TORRENT_ASSERT(m_inbuf.size());
int ack_nr = (m_ack_nr + 2) & ACK_MASK; int ack_nr = (m_ack_nr + 2) & ACK_MASK;
char* end = buf + size; boost::uint8_t* end = buf + size;
for (; buf != end; ++buf) for (; buf != end; ++buf)
{ {
@@ -1778,14 +1894,27 @@ bool utp_socket_impl::resend_packet(packet* p, bool fast_resend)
h->timestamp_difference_microseconds = m_reply_micro; h->timestamp_difference_microseconds = m_reply_micro;
p->send_time = time_now_hires(); p->send_time = time_now_hires();
h->timestamp_microseconds = boost::uint32_t(total_microseconds(p->send_time - min_time())); h->timestamp_microseconds = boost::uint32_t(total_microseconds(p->send_time - min_time()));
if (h->extension == 0)
// if the packet has a selective ack header, we'll need
// to update it
if (h->extension == 1 && h->ack_nr != m_ack_nr)
{ {
// if extension != 0, there might be a SACK in the header boost::uint8_t* ptr = p->buf + sizeof(utp_header);
// and we can't update the ack field (since the SACK bits int sack_size = ptr[1];
// depend on it). If it's zero however, we can update it. if (m_inbuf.size())
h->ack_nr = m_ack_nr; {
// update the sack header
write_sack(ptr + 2, sack_size);
TORRENT_ASSERT(ptr + sack_size + 2 <= p->buf + p->header_size);
}
else
{
remove_sack_header(p);
}
} }
h->ack_nr = m_ack_nr;
error_code ec; error_code ec;
m_sm->send_packet(udp::endpoint(m_remote_address, m_port) m_sm->send_packet(udp::endpoint(m_remote_address, m_port)
, (char const*)p->buf, p->size, ec); , (char const*)p->buf, p->size, ec);
@@ -1909,7 +2038,7 @@ void utp_socket_impl::ack_packet(packet* p, ptime const& receive_time
free(p); free(p);
} }
void utp_socket_impl::incoming(char const* buf, int size, packet* p, ptime now) void utp_socket_impl::incoming(boost::uint8_t const* buf, int size, packet* p, ptime now)
{ {
while (!m_read_buffer.empty()) while (!m_read_buffer.empty())
{ {
@@ -1928,7 +2057,7 @@ void utp_socket_impl::incoming(char const* buf, int size, packet* p, ptime now)
UTP_LOGV("%8p: setting read timeout to 100 ms from now\n", this); UTP_LOGV("%8p: setting read timeout to 100 ms from now\n", this);
} }
m_read += to_copy; m_read += to_copy;
target->buf = ((char*)target->buf) + to_copy; target->buf = ((boost::uint8_t*)target->buf) + to_copy;
target->len -= to_copy; target->len -= to_copy;
buf += to_copy; buf += to_copy;
UTP_LOGV("%8p: copied %d bytes into user receive buffer\n", this, to_copy); UTP_LOGV("%8p: copied %d bytes into user receive buffer\n", this, to_copy);
@@ -1987,7 +2116,7 @@ bool utp_socket_impl::cancel_handlers(error_code const& ec, bool kill)
} }
bool utp_socket_impl::consume_incoming_data( bool utp_socket_impl::consume_incoming_data(
utp_header const* ph, char const* ptr, int payload_size utp_header const* ph, boost::uint8_t const* ptr, int payload_size
, ptime now) , ptime now)
{ {
if (ph->get_type() != ST_DATA) return false; if (ph->get_type() != ST_DATA) return false;
@@ -2136,7 +2265,7 @@ void utp_socket_impl::init_mtu(int link_mtu, int utp_mtu)
} }
// return false if this is an invalid packet // return false if this is an invalid packet
bool utp_socket_impl::incoming_packet(char const* buf, int size bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
, udp::endpoint const& ep, ptime receive_time) , udp::endpoint const& ep, ptime receive_time)
{ {
utp_header* ph = (utp_header*)buf; utp_header* ph = (utp_header*)buf;
@@ -2351,7 +2480,7 @@ bool utp_socket_impl::incoming_packet(char const* buf, int size
} }
// look for extended headers // look for extended headers
char const* ptr = buf; boost::uint8_t const* ptr = buf;
ptr += sizeof(utp_header); ptr += sizeof(utp_header);
unsigned int extension = ph->extension; unsigned int extension = ph->extension;
@@ -2364,8 +2493,14 @@ bool utp_socket_impl::incoming_packet(char const* buf, int size
UTP_LOGV("%8p: invalid extension header\n", this); UTP_LOGV("%8p: invalid extension header\n", this);
return true; return true;
} }
int next_extension = unsigned(*ptr++); int next_extension = *ptr++;
int len = unsigned(*ptr++); int len = *ptr++;
if (len < 0)
{
UTP_LOGV("%8p: invalid extension length:%d packet:%d\n"
, this, len, int(ptr - buf));
return true;
}
if (ptr - buf + len > size_t(size)) if (ptr - buf + len > size_t(size))
{ {
UTP_LOGV("%8p: invalid extension header size:%d packet:%d\n" UTP_LOGV("%8p: invalid extension header size:%d packet:%d\n"