/* * Copyright (c) 2010-2013 BitTorrent, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include // for UINT_MAX #include #include "utp_types.h" #include "utp_packedsockaddr.h" #include "utp_internal.h" #include "utp_hash.h" #define TIMEOUT_CHECK_INTERVAL 500 // number of bytes to increase max window size by, per RTT. This is // scaled down linearly proportional to off_target. i.e. if all packets // in one window have 0 delay, window size will increase by this number. // Typically it's less. TCP increases one MSS per RTT, which is 1500 #define MAX_CWND_INCREASE_BYTES_PER_RTT 3000 #define CUR_DELAY_SIZE 3 // experiments suggest that a clock skew of 10 ms per 325 seconds // is not impossible. Reset delay_base every 13 minutes. The clock // skew is dealt with by observing the delay base in the other // direction, and adjusting our own upwards if the opposite direction // delay base keeps going down #define DELAY_BASE_HISTORY 13 #define MAX_WINDOW_DECAY 100 // ms #define REORDER_BUFFER_SIZE 32 #define REORDER_BUFFER_MAX_SIZE 1024 #define OUTGOING_BUFFER_MAX_SIZE 1024 #define PACKET_SIZE 1435 // this is the minimum max_window value. It can never drop below this #define MIN_WINDOW_SIZE 10 // if we receive 4 or more duplicate acks, we resend the packet // that hasn't been acked yet #define DUPLICATE_ACKS_BEFORE_RESEND 3 // Allow a reception window of at least 3 ack_nrs behind seq_nr // A non-SYN packet with an ack_nr difference greater than this is // considered suspicious and ignored #define ACK_NR_ALLOWED_WINDOW DUPLICATE_ACKS_BEFORE_RESEND #define RST_INFO_TIMEOUT 10000 #define RST_INFO_LIMIT 1000 // 29 seconds determined from measuring many home NAT devices #define KEEPALIVE_INTERVAL 29000 #define SEQ_NR_MASK 0xFFFF #define ACK_NR_MASK 0xFFFF #define TIMESTAMP_MASK 0xFFFFFFFF #define DIV_ROUND_UP(num, denom) ((num + denom - 1) / denom) // The totals are derived from the following data: // 45: IPv6 address including embedded IPv4 address // 11: Scope Id // 2: Brackets around IPv6 address when port is present // 6: Port (including colon) // 1: Terminating null byte char addrbuf[65]; #define addrfmt(x, s) x.fmt(s, sizeof(s)) #if(defined(__SVR4) && defined(__sun)) #pragma pack(1) #else #pragma pack(push, 1) #endif // these packet sizes are including the uTP header wich // is either 20 or 23 bytes depending on version #define PACKET_SIZE_EMPTY_BUCKET 0 #define PACKET_SIZE_EMPTY 23 #define PACKET_SIZE_SMALL_BUCKET 1 #define PACKET_SIZE_SMALL 373 #define PACKET_SIZE_MID_BUCKET 2 #define PACKET_SIZE_MID 723 #define PACKET_SIZE_BIG_BUCKET 3 #define PACKET_SIZE_BIG 1400 #define PACKET_SIZE_HUGE_BUCKET 4 struct PACKED_ATTRIBUTE PacketFormatV1 { // packet_type (4 high bits) // protocol version (4 low bits) byte ver_type; byte version() const { return ver_type & 0xf; } byte type() const { return ver_type >> 4; } void set_version(byte v) { ver_type = (ver_type & 0xf0) | (v & 0xf); } void set_type(byte t) { ver_type = (ver_type & 0xf) | (t << 4); } // Type of the first extension header byte ext; // connection ID uint16_big connid; uint32_big tv_usec; uint32_big reply_micro; // receive window size in bytes uint32_big windowsize; // Sequence number uint16_big seq_nr; // Acknowledgment number uint16_big ack_nr; }; struct PACKED_ATTRIBUTE PacketFormatAckV1 { PacketFormatV1 pf; byte ext_next; byte ext_len; byte acks[4]; }; #if(defined(__SVR4) && defined(__sun)) #pragma pack(0) #else #pragma pack(pop) #endif enum { ST_DATA = 0, // Data packet. ST_FIN = 1, // Finalize the connection. This is the last packet. ST_STATE = 2, // State packet. Used to transmit an ACK with no data. ST_RESET = 3, // Terminate connection forcefully. ST_SYN = 4, // Connect SYN ST_NUM_STATES, // used for bounds checking }; enum CONN_STATE { CS_UNINITIALIZED = 0, CS_IDLE, CS_SYN_SENT, CS_SYN_RECV, CS_CONNECTED, CS_CONNECTED_FULL, CS_RESET, CS_DESTROY }; #if UTP_DEBUG_LOGGING static const cstr flagnames[] = {"ST_DATA", "ST_FIN", "ST_STATE", "ST_RESET", "ST_SYN"}; static const cstr statenames[] = { "UNINITIALIZED", "IDLE", "SYN_SENT", "SYN_RECV", "CONNECTED", "CONNECTED_FULL", "DESTROY_DELAY", "RESET", "DESTROY"}; #endif struct OutgoingPacket { size_t length; size_t payload; uint64 time_sent; // microseconds uint transmissions : 31; bool need_resend : 1; byte data[1]; }; struct SizableCircularBuffer { // This is the mask. Since it's always a power of 2, adding 1 to this value // will return the size. size_t mask; // This is the elements that the circular buffer points to void **elements; void * get(size_t i) const { assert(elements); return elements ? elements[i & mask] : NULL; } void put(size_t i, void *data) { assert(elements); elements[i & mask] = data; } void grow(size_t item, size_t index); void ensure_size(size_t item, size_t index) { if(index > mask) grow(item, index); } size_t size() { return mask + 1; } }; // Item contains the element we want to make space for // index is the index in the list. void SizableCircularBuffer::grow(size_t item, size_t index) { // Figure out the new size. size_t size = mask + 1; do size *= 2; while(index >= size); // Allocate the new buffer void **buf = (void **)calloc(size, sizeof(void *)); size--; // Copy elements from the old buffer to the new buffer for(size_t i = 0; i <= mask; i++) { buf[(item - index + i) & size] = get(item - index + i); } // Swap to the newly allocated buffer mask = size; free(elements); elements = buf; } // compare if lhs is less than rhs, taking wrapping // into account. if lhs is close to UINT_MAX and rhs // is close to 0, lhs is assumed to have wrapped and // considered smaller bool wrapping_compare_less(uint32 lhs, uint32 rhs, uint32 mask) { // distance walking from lhs to rhs, downwards const uint32 dist_down = (lhs - rhs) & mask; // distance walking from lhs to rhs, upwards const uint32 dist_up = (rhs - lhs) & mask; // if the distance walking up is shorter, lhs // is less than rhs. If the distance walking down // is shorter, then rhs is less than lhs return dist_up < dist_down; } struct DelayHist { uint32 delay_base; // this is the history of delay samples, // normalized by using the delay_base. These // values are always greater than 0 and measures // the queuing delay in microseconds uint32 cur_delay_hist[CUR_DELAY_SIZE]; size_t cur_delay_idx; // this is the history of delay_base. It's // a number that doesn't have an absolute meaning // only relative. It doesn't make sense to initialize // it to anything other than values relative to // what's been seen in the real world. uint32 delay_base_hist[DELAY_BASE_HISTORY]; size_t delay_base_idx; // the time when we last stepped the delay_base_idx uint64 delay_base_time; bool delay_base_initialized; void clear(uint64 current_ms) { delay_base_initialized = false; delay_base = 0; cur_delay_idx = 0; delay_base_idx = 0; delay_base_time = current_ms; for(size_t i = 0; i < CUR_DELAY_SIZE; i++) { cur_delay_hist[i] = 0; } for(size_t i = 0; i < DELAY_BASE_HISTORY; i++) { delay_base_hist[i] = 0; } } void shift(const uint32 offset) { // the offset should never be "negative" // assert(offset < 0x10000000); // increase all of our base delays by this amount // this is used to take clock skew into account // by observing the other side's changes in its base_delay for(size_t i = 0; i < DELAY_BASE_HISTORY; i++) { delay_base_hist[i] += offset; } delay_base += offset; } void add_sample(const uint32 sample, uint64 current_ms) { // The two clocks (in the two peers) are assumed not to // progress at the exact same rate. They are assumed to be // drifting, which causes the delay samples to contain // a systematic error, either they are under- // estimated or over-estimated. This is why we update the // delay_base every two minutes, to adjust for this. // This means the values will keep drifting and eventually wrap. // We can cross the wrapping boundry in two directions, either // going up, crossing the highest value, or going down, crossing 0. // if the delay_base is close to the max value and sample actually // wrapped on the other end we would see something like this: // delay_base = 0xffffff00, sample = 0x00000400 // sample - delay_base = 0x500 which is the correct difference // if the delay_base is instead close to 0, and we got an even lower // sample (that will eventually update the delay_base), we may see // something like this: // delay_base = 0x00000400, sample = 0xffffff00 // sample - delay_base = 0xfffffb00 // this needs to be interpreted as a negative number and the actual // recorded delay should be 0. // It is important that all arithmetic that assume wrapping // is done with unsigned intergers. Signed integers are not guaranteed // to wrap the way unsigned integers do. At least GCC takes advantage // of this relaxed rule and won't necessarily wrap signed ints. // remove the clock offset and propagation delay. // delay base is min of the sample and the current // delay base. This min-operation is subject to wrapping // and care needs to be taken to correctly choose the // true minimum. // specifically the problem case is when delay_base is very small // and sample is very large (because it wrapped past zero), sample // needs to be considered the smaller if(!delay_base_initialized) { // delay_base being 0 suggests that we haven't initialized // it or its history with any real measurements yet. Initialize // everything with this sample. for(size_t i = 0; i < DELAY_BASE_HISTORY; i++) { // if we don't have a value, set it to the current sample delay_base_hist[i] = sample; continue; } delay_base = sample; delay_base_initialized = true; } if(wrapping_compare_less(sample, delay_base_hist[delay_base_idx], TIMESTAMP_MASK)) { // sample is smaller than the current delay_base_hist entry // update it delay_base_hist[delay_base_idx] = sample; } // is sample lower than delay_base? If so, update delay_base if(wrapping_compare_less(sample, delay_base, TIMESTAMP_MASK)) { // sample is smaller than the current delay_base // update it delay_base = sample; } // this operation may wrap, and is supposed to const uint32 delay = sample - delay_base; // sanity check. If this is triggered, something fishy is going on // it means the measured sample was greater than 32 seconds! // assert(delay < 0x2000000); cur_delay_hist[cur_delay_idx] = delay; cur_delay_idx = (cur_delay_idx + 1) % CUR_DELAY_SIZE; // once every minute if(current_ms - delay_base_time > 60 * 1000) { delay_base_time = current_ms; delay_base_idx = (delay_base_idx + 1) % DELAY_BASE_HISTORY; // clear up the new delay base history spot by initializing // it to the current sample, then update it delay_base_hist[delay_base_idx] = sample; delay_base = delay_base_hist[0]; // Assign the lowest delay in the last 2 minutes to delay_base for(size_t i = 0; i < DELAY_BASE_HISTORY; i++) { if(wrapping_compare_less(delay_base_hist[i], delay_base, TIMESTAMP_MASK)) delay_base = delay_base_hist[i]; } } } uint32 get_value() { uint32 value = UINT_MAX; for(size_t i = 0; i < CUR_DELAY_SIZE; i++) { value = min< uint32 >(cur_delay_hist[i], value); } // value could be UINT_MAX if we have no samples yet... return value; } }; struct UTPSocket { ~UTPSocket(); PackedSockAddr addr; utp_context *ctx; int ida; // for ack socket list uint16 retransmit_count; uint16 reorder_count; byte duplicate_ack; // the number of packets in the send queue. Packets that haven't // yet been sent count as well as packets marked as needing resend // the oldest un-acked packet in the send queue is seq_nr - cur_window_packets uint16 cur_window_packets; // how much of the window is used, number of bytes in-flight // packets that have not yet been sent do not count, packets // that are marked as needing to be re-sent (due to a timeout) // don't count either size_t cur_window; // maximum window size, in bytes size_t max_window; // UTP_SNDBUF setting, in bytes size_t opt_sndbuf; // UTP_RCVBUF setting, in bytes size_t opt_rcvbuf; // this is the target delay, in microseconds // for this socket. defaults to 100000. size_t target_delay; // Is a FIN packet in the reassembly buffer? bool got_fin : 1; // Have we reached the FIN? bool got_fin_reached : 1; // Have we sent our FIN? bool fin_sent : 1; // Has our fin been ACKed? bool fin_sent_acked : 1; // Reading is disabled bool read_shutdown : 1; // User called utp_close() bool close_requested : 1; // Timeout procedure bool fast_timeout : 1; // max receive window for other end, in bytes size_t max_window_user; CONN_STATE state; // TickCount when we last decayed window (wraps) int64 last_rwin_decay; // the sequence number of the FIN packet. This field is only set // when we have received a FIN, and the flag field has the FIN flag set. // it is used to know when it is safe to destroy the socket, we must have // received all packets up to this sequence number first. uint16 eof_pkt; // All sequence numbers up to including this have been properly received // by us uint16 ack_nr; // This is the sequence number for the next packet to be sent. uint16 seq_nr; uint16 timeout_seq_nr; // This is the sequence number of the next packet we're allowed to // do a fast resend with. This makes sure we only do a fast-resend // once per packet. We can resend the packet with this sequence number // or any later packet (with a higher sequence number). uint16 fast_resend_seq_nr; uint32 reply_micro; uint64 last_got_packet; uint64 last_sent_packet; uint64 last_measured_delay; // timestamp of the last time the cwnd was full // this is used to prevent the congestion window // from growing when we're not sending at capacity mutable uint64 last_maxed_out_window; void *userdata; // Round trip time uint rtt; // Round trip time variance uint rtt_var; // Round trip timeout uint rto; DelayHist rtt_hist; uint retransmit_timeout; // The RTO timer will timeout here. uint64 rto_timeout; // When the window size is set to zero, start this timer. It will send a new // packet every 30secs. uint64 zerowindow_time; uint32 conn_seed; // Connection ID for packets I receive uint32 conn_id_recv; // Connection ID for packets I send uint32 conn_id_send; // Last rcv window we advertised, in bytes size_t last_rcv_win; DelayHist our_hist; DelayHist their_hist; // extension bytes from SYN packet byte extensions[8]; // MTU Discovery // time when we should restart the MTU discovery uint64 mtu_discover_time; // ceiling and floor of binary search. last is the mtu size // we're currently using uint32 mtu_ceiling, mtu_floor, mtu_last; // we only ever have a single probe in flight at any given time. // this is the sequence number of that probe, and the size of // that packet uint32 mtu_probe_seq, mtu_probe_size; // this is the average delay samples, as compared to the initial // sample. It's averaged over 5 seconds int32 average_delay; // this is the sum of all the delay samples // we've made recently. The important distinction // of these samples is that they are all made compared // to the initial sample, this is to deal with // wrapping in a simple way. int64 current_delay_sum; // number of sample ins current_delay_sum int current_delay_samples; // initialized to 0, set to the first raw delay sample // each sample that's added to current_delay_sum // is subtracted from the value first, to make it // a delay relative to this sample uint32 average_delay_base; // the next time we should add an average delay // sample into average_delay_hist uint64 average_sample_time; // the estimated clock drift between our computer // and the endpoint computer. The unit is microseconds // per 5 seconds int32 clock_drift; // just used for logging int32 clock_drift_raw; SizableCircularBuffer inbuf, outbuf; #ifdef _DEBUG // Public per-socket statistics, returned by utp_get_stats() utp_socket_stats _stats; #endif // true if we're in slow-start (exponential growth) phase bool slow_start; // the slow-start threshold, in bytes size_t ssthresh; void log(int level, char const *fmt, ...) { va_list va; char buf[4096], buf2[4096]; // don't bother with vsnprintf() etc calls if we're not going to log. if(!ctx->would_log(level)) { return; } va_start(va, fmt); vsnprintf(buf, 4096, fmt, va); va_end(va); buf[4095] = '\0'; snprintf(buf2, 4096, "%p %s %06u %s", this, addrfmt(addr, addrbuf), conn_id_recv, buf); buf2[4095] = '\0'; ctx->log_unchecked(this, buf2); } void schedule_ack(); // called every time mtu_floor or mtu_ceiling are adjusted void mtu_search_update(); void mtu_reset(); // Calculates the current receive window size_t get_rcv_window() { // Trim window down according to what's already in buffer. const size_t numbuf = utp_call_get_read_buffer_size(this->ctx, this); assert((int)numbuf >= 0); return opt_rcvbuf > numbuf ? opt_rcvbuf - numbuf : 0; } // Test if we're ready to decay max_window // XXX this breaks when spaced by > INT_MAX/2, which is 49 // days; the failure mode in that case is we do an extra decay // or fail to do one when we really shouldn't. bool can_decay_win(int64 msec) const { return (msec - last_rwin_decay) >= MAX_WINDOW_DECAY; } // If we can, decay max window, returns true if we actually did so void maybe_decay_win(uint64 current_ms) { if(can_decay_win(current_ms)) { // TCP uses 0.5 max_window = (size_t)(max_window * .5); last_rwin_decay = current_ms; if(max_window < MIN_WINDOW_SIZE) max_window = MIN_WINDOW_SIZE; slow_start = false; ssthresh = max_window; } } size_t get_header_size() const { return sizeof(PacketFormatV1); } size_t get_udp_mtu() { socklen_t len; SOCKADDR_STORAGE sa = addr.get_sockaddr_storage(&len); return utp_call_get_udp_mtu(this->ctx, this, (const struct sockaddr *)&sa, len); } size_t get_udp_overhead() { socklen_t len; SOCKADDR_STORAGE sa = addr.get_sockaddr_storage(&len); return utp_call_get_udp_overhead(this->ctx, this, (const struct sockaddr *)&sa, len); } size_t get_overhead() { return get_udp_overhead() + get_header_size(); } void send_data(byte *b, size_t length, bandwidth_type_t type, uint32 flags = 0); void send_ack(bool synack = false); void send_keep_alive(); static void send_rst(utp_context *ctx, const PackedSockAddr &addr, uint32 conn_id_send, uint16 ack_nr, uint16 seq_nr); void send_packet(OutgoingPacket *pkt); bool is_full(int bytes = -1); bool flush_packets(); void write_outgoing_packet(size_t payload, uint flags, struct utp_iovec *iovec, size_t num_iovecs); #ifdef _DEBUG void check_invariant(); #endif void check_timeouts(); int ack_packet(uint16 seq); size_t selective_ack_bytes(uint base, const byte *mask, byte len, int64 &min_rtt); void selective_ack(uint base, const byte *mask, byte len); void apply_ccontrol(size_t bytes_acked, uint32 actual_delay, int64 min_rtt); size_t get_packet_size() const; }; void removeSocketFromAckList(UTPSocket *conn) { if(conn->ida >= 0) { UTPSocket *last = conn->ctx->ack_sockets[conn->ctx->ack_sockets.GetCount() - 1]; assert(last->ida < (int)(conn->ctx->ack_sockets.GetCount())); assert(conn->ctx->ack_sockets[last->ida] == last); last->ida = conn->ida; conn->ctx->ack_sockets[conn->ida] = last; conn->ida = -1; // Decrease the count conn->ctx->ack_sockets.SetCount(conn->ctx->ack_sockets.GetCount() - 1); } } static void utp_register_sent_packet(utp_context *ctx, size_t length) { if(length <= PACKET_SIZE_MID) { if(length <= PACKET_SIZE_EMPTY) { ctx->context_stats._nraw_send[PACKET_SIZE_EMPTY_BUCKET]++; } else if(length <= PACKET_SIZE_SMALL) { ctx->context_stats._nraw_send[PACKET_SIZE_SMALL_BUCKET]++; } else ctx->context_stats._nraw_send[PACKET_SIZE_MID_BUCKET]++; } else { if(length <= PACKET_SIZE_BIG) { ctx->context_stats._nraw_send[PACKET_SIZE_BIG_BUCKET]++; } else ctx->context_stats._nraw_send[PACKET_SIZE_HUGE_BUCKET]++; } } void send_to_addr(utp_context *ctx, const byte *p, size_t len, const PackedSockAddr &addr, int flags = 0) { socklen_t tolen; SOCKADDR_STORAGE to = addr.get_sockaddr_storage(&tolen); utp_register_sent_packet(ctx, len); utp_call_sendto(ctx, NULL, p, len, (const struct sockaddr *)&to, tolen, flags); } void UTPSocket::schedule_ack() { if(ida == -1) { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "schedule_ack"); #endif ida = ctx->ack_sockets.Append(this); } else { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "schedule_ack: already in list"); #endif } } void UTPSocket::send_data(byte *b, size_t length, bandwidth_type_t type, uint32 flags) { // time stamp this packet with local time, the stamp goes into // the header of every packet at the 8th byte for 8 bytes : // two integers, check packet.h for more uint64 time = utp_call_get_microseconds(ctx, this); PacketFormatV1 *b1 = (PacketFormatV1 *)b; b1->tv_usec = (uint32)time; b1->reply_micro = reply_micro; last_sent_packet = ctx->current_ms; #ifdef _DEBUG _stats.nbytes_xmit += length; ++_stats.nxmit; #endif if(ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS]) { size_t n; if(type == payload_bandwidth) { // if this packet carries payload, just // count the header as overhead type = header_overhead; n = get_overhead(); } else { n = length + get_udp_overhead(); } utp_call_on_overhead_statistics(ctx, this, true, n, type); } #if UTP_DEBUG_LOGGING int flags2 = b1->type(); uint16 seq_nr = b1->seq_nr; uint16 ack_nr = b1->ack_nr; log(UTP_LOG_DEBUG, "send %s len:%u id:%u timestamp:" I64u " reply_micro:%u flags:%s seq_nr:%u ack_nr:%u", addrfmt(addr, addrbuf), (uint)length, conn_id_send, time, reply_micro, flagnames[flags2], seq_nr, ack_nr); #endif send_to_addr(ctx, b, length, addr, flags); removeSocketFromAckList(this); } void UTPSocket::send_ack(bool synack) { PacketFormatAckV1 pfa; zeromem(&pfa); size_t len; last_rcv_win = get_rcv_window(); pfa.pf.set_version(1); pfa.pf.set_type(ST_STATE); pfa.pf.ext = 0; pfa.pf.connid = conn_id_send; pfa.pf.ack_nr = ack_nr; pfa.pf.seq_nr = seq_nr; pfa.pf.windowsize = (uint32)last_rcv_win; len = sizeof(PacketFormatV1); // we never need to send EACK for connections // that are shutting down if(reorder_count != 0 && !got_fin_reached) { // if reorder count > 0, send an EACK. // reorder count should always be 0 // for synacks, so this should not be // as synack assert(!synack); (void)synack; pfa.pf.ext = 1; pfa.ext_next = 0; pfa.ext_len = 4; uint m = 0; // reorder count should only be non-zero // if the packet ack_nr + 1 has not yet // been received assert(inbuf.get(ack_nr + 1) == NULL); size_t window = min< size_t >(14 + 16, inbuf.size()); // Generate bit mask of segments received. for(size_t i = 0; i < window; i++) { if(inbuf.get(ack_nr + i + 2) != NULL) { m |= 1 << i; #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "EACK packet [%u]", ack_nr + i + 2); #endif } } pfa.acks[0] = (byte)m; pfa.acks[1] = (byte)(m >> 8); pfa.acks[2] = (byte)(m >> 16); pfa.acks[3] = (byte)(m >> 24); len += 4 + 2; #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "Sending EACK %u [%u] bits:[%032b]", ack_nr, conn_id_send, m); #endif } else { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "Sending ACK %u [%u]", ack_nr, conn_id_send); #endif } send_data((byte *)&pfa, len, ack_overhead); removeSocketFromAckList(this); } void UTPSocket::send_keep_alive() { ack_nr--; #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "Sending KeepAlive ACK %u [%u]", ack_nr, conn_id_send); #endif send_ack(); ack_nr++; } void UTPSocket::send_rst(utp_context *ctx, const PackedSockAddr &addr, uint32 conn_id_send, uint16 ack_nr, uint16 seq_nr) { PacketFormatV1 pf1; zeromem(&pf1); size_t len; pf1.set_version(1); pf1.set_type(ST_RESET); pf1.ext = 0; pf1.connid = conn_id_send; pf1.ack_nr = ack_nr; pf1.seq_nr = seq_nr; pf1.windowsize = 0; len = sizeof(PacketFormatV1); // LOG_DEBUG("%s: Sending RST id:%u seq_nr:%u ack_nr:%u", addrfmt(addr, // addrbuf), conn_id_send, seq_nr, ack_nr); LOG_DEBUG("send %s len:%u // id:%u", addrfmt(addr, addrbuf), (uint)len, conn_id_send); send_to_addr(ctx, (const byte *)&pf1, len, addr); } void UTPSocket::send_packet(OutgoingPacket *pkt) { // only count against the quota the first time we // send the packet. Don't enforce quota when closing // a socket. Only enforce the quota when we're sending // at slow rates (max window < packet size) // size_t max_send = min(max_window, opt_sndbuf, max_window_user); time_t cur_time = utp_call_get_milliseconds(this->ctx, this); if(pkt->transmissions == 0 || pkt->need_resend) { cur_window += pkt->payload; } pkt->need_resend = false; PacketFormatV1 *p1 = (PacketFormatV1 *)pkt->data; p1->ack_nr = ack_nr; pkt->time_sent = utp_call_get_microseconds(this->ctx, this); // socklen_t salen; // SOCKADDR_STORAGE sa = addr.get_sockaddr_storage(&salen); bool use_as_mtu_probe = false; // TODO: this is subject to nasty wrapping issues! Below as well if(mtu_discover_time < (uint64)cur_time) { // it's time to reset our MTU assupmtions // and trigger a new search mtu_reset(); } // don't use packets that are larger then mtu_ceiling // as probes, since they were probably used as probes // already and failed, now we need it to fragment // just to get it through // if seq_nr == 1, the probe would end up being 0 // which is a magic number representing no-probe // that why we don't send a probe for a packet with // sequence number 0 if(mtu_floor < mtu_ceiling && pkt->length > mtu_floor && pkt->length <= mtu_ceiling && mtu_probe_seq == 0 && seq_nr != 1 && pkt->transmissions == 0) { // we've already incremented seq_nr // for this packet mtu_probe_seq = (seq_nr - 1) & ACK_NR_MASK; mtu_probe_size = pkt->length; assert(pkt->length >= mtu_floor); assert(pkt->length <= mtu_ceiling); use_as_mtu_probe = true; log(UTP_LOG_MTU, "MTU [PROBE] floor:%d ceiling:%d current:%d", mtu_floor, mtu_ceiling, mtu_probe_size); } pkt->transmissions++; send_data( (byte *)pkt->data, pkt->length, (state == CS_SYN_SENT) ? connect_overhead : (pkt->transmissions == 1) ? payload_bandwidth : retransmit_overhead, use_as_mtu_probe ? UTP_UDP_DONTFRAG : 0); } bool UTPSocket::is_full(int bytes) { size_t packet_size = get_packet_size(); if(bytes < 0) bytes = packet_size; else if(bytes > (int)packet_size) bytes = (int)packet_size; size_t max_send = min(max_window, opt_sndbuf, max_window_user); // subtract one to save space for the FIN packet if(cur_window_packets >= OUTGOING_BUFFER_MAX_SIZE - 1) { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "is_full:false cur_window_packets:%d MAX:%d", cur_window_packets, OUTGOING_BUFFER_MAX_SIZE - 1); #endif last_maxed_out_window = ctx->current_ms; return true; } #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "is_full:%s. cur_window:%u pkt:%u max:%u cur_window_packets:%u " "max_window:%u", (cur_window + bytes > max_send) ? "true" : "false", cur_window, bytes, max_send, cur_window_packets, max_window); #endif if(cur_window + bytes > max_send) { last_maxed_out_window = ctx->current_ms; return true; } return false; } bool UTPSocket::flush_packets() { size_t packet_size = get_packet_size(); // send packets that are waiting on the pacer to be sent // i has to be an unsigned 16 bit counter to wrap correctly // signed types are not guaranteed to wrap the way you expect for(uint16 i = seq_nr - cur_window_packets; i != seq_nr; ++i) { OutgoingPacket *pkt = (OutgoingPacket *)outbuf.get(i); if(pkt == 0 || (pkt->transmissions > 0 && pkt->need_resend == false)) continue; // have we run out of quota? if(is_full()) return true; // Nagle check // don't send the last packet if we have one packet in-flight // and the current packet is still smaller than packet_size. if(i != ((seq_nr - 1) & ACK_NR_MASK) || cur_window_packets == 1 || pkt->payload >= packet_size) { send_packet(pkt); } } return false; } // @payload: number of bytes to send // @flags: either ST_DATA, or ST_FIN // @iovec: base address of iovec array // @num_iovecs: number of iovecs in array void UTPSocket::write_outgoing_packet(size_t payload, uint flags, struct utp_iovec *iovec, size_t num_iovecs) { // Setup initial timeout timer if(cur_window_packets == 0) { retransmit_timeout = rto; rto_timeout = ctx->current_ms + retransmit_timeout; assert(cur_window == 0); } size_t packet_size = get_packet_size(); do { assert(cur_window_packets < OUTGOING_BUFFER_MAX_SIZE); assert(flags == ST_DATA || flags == ST_FIN); size_t added = 0; OutgoingPacket *pkt = NULL; if(cur_window_packets > 0) { pkt = (OutgoingPacket *)outbuf.get(seq_nr - 1); } const size_t header_size = get_header_size(); bool append = true; // if there's any room left in the last packet in the window // and it hasn't been sent yet, fill that frame first if(payload && pkt && !pkt->transmissions && pkt->payload < packet_size) { // Use the previous unsent packet added = min(payload + pkt->payload, max< size_t >(packet_size, pkt->payload)) - pkt->payload; pkt = (OutgoingPacket *)realloc( pkt, (sizeof(OutgoingPacket) - 1) + header_size + pkt->payload + added); outbuf.put(seq_nr - 1, pkt); append = false; assert(!pkt->need_resend); } else { // Create the packet to send. added = payload; pkt = (OutgoingPacket *)malloc((sizeof(OutgoingPacket) - 1) + header_size + added); pkt->payload = 0; pkt->transmissions = 0; pkt->need_resend = false; } if(added) { assert(flags == ST_DATA); // Fill it with data from the upper layer. unsigned char *p = pkt->data + header_size + pkt->payload; size_t needed = added; /* while (needed) { *p = *(char*)iovec[0].iov_base; p++; iovec[0].iov_base = (char *)iovec[0].iov_base + 1; needed--; } */ for(size_t i = 0; i < num_iovecs && needed; i++) { if(iovec[i].iov_len == 0) continue; size_t num = min< size_t >(needed, iovec[i].iov_len); memcpy(p, iovec[i].iov_base, num); p += num; iovec[i].iov_len -= num; iovec[i].iov_base = (byte *)iovec[i].iov_base + num; // iovec[i].iov_base += num, but without void* pointers needed -= num; } assert(needed == 0); } pkt->payload += added; pkt->length = header_size + pkt->payload; last_rcv_win = get_rcv_window(); PacketFormatV1 *p1 = (PacketFormatV1 *)pkt->data; // p1->ver_type; needs to be set!! p1->set_version(1); p1->set_type(flags); p1->ext = 0; p1->connid = conn_id_send; p1->windowsize = (uint32)last_rcv_win; p1->ack_nr = ack_nr; if(append) { // Remember the message in the outgoing queue. outbuf.ensure_size(seq_nr, cur_window_packets); outbuf.put(seq_nr, pkt); p1->seq_nr = seq_nr; seq_nr++; cur_window_packets++; } payload -= added; } while(payload); flush_packets(); } #ifdef _DEBUG void UTPSocket::check_invariant() { if(reorder_count > 0) { assert(inbuf.get(ack_nr + 1) == NULL); } size_t outstanding_bytes = 0; for(int i = 0; i < cur_window_packets; ++i) { OutgoingPacket *pkt = (OutgoingPacket *)outbuf.get(seq_nr - i - 1); if(pkt == 0 || pkt->transmissions == 0 || pkt->need_resend) continue; outstanding_bytes += pkt->payload; } assert(outstanding_bytes == cur_window); } #endif void UTPSocket::check_timeouts() { #ifdef _DEBUG check_invariant(); #endif // this invariant should always be true assert(cur_window_packets == 0 || outbuf.get(seq_nr - cur_window_packets)); #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "CheckTimeouts timeout:%d max_window:%u cur_window:%u " "state:%s cur_window_packets:%u", (int)(rto_timeout - ctx->current_ms), (uint)max_window, (uint)cur_window, statenames[state], cur_window_packets); #endif if(state != CS_DESTROY) flush_packets(); switch(state) { case CS_SYN_SENT: case CS_SYN_RECV: case CS_CONNECTED_FULL: case CS_CONNECTED: { // Reset max window... if((int)(ctx->current_ms - zerowindow_time) >= 0 && max_window_user == 0) { max_window_user = PACKET_SIZE; } if((int)(ctx->current_ms - rto_timeout) >= 0 && rto_timeout > 0) { bool ignore_loss = false; if(cur_window_packets == 1 && ((seq_nr - 1) & ACK_NR_MASK) == mtu_probe_seq && mtu_probe_seq != 0) { // we only had a single outstanding packet that timed out, and it was // the probe mtu_ceiling = mtu_probe_size - 1; mtu_search_update(); // this packet was most likely dropped because the packet size being // too big and not because congestion. To accelerate the binary search // for the MTU, resend immediately and don't reset the window size ignore_loss = true; log(UTP_LOG_MTU, "MTU [PROBE-TIMEOUT] floor:%d ceiling:%d current:%d", mtu_floor, mtu_ceiling, mtu_last); } // we dropepd the probe, clear these fields to // allow us to send a new one mtu_probe_seq = mtu_probe_size = 0; log(UTP_LOG_MTU, "MTU [TIMEOUT]"); /* OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(seq_nr - cur_window_packets); // If there were a lot of retransmissions, force recomputation of round trip time if (pkt->transmissions >= 4) rtt = 0; */ // Increase RTO const uint new_timeout = ignore_loss ? retransmit_timeout : retransmit_timeout * 2; // They initiated the connection but failed to respond before the rto. // A malicious client can also spoof the destination address of a ST_SYN // bringing us to this state. Kill the connection and do not notify the // upper layer if(state == CS_SYN_RECV) { state = CS_DESTROY; utp_call_on_error(ctx, this, UTP_ETIMEDOUT); return; } // We initiated the connection but the other side failed to respond // before the rto if(retransmit_count >= 4 || (state == CS_SYN_SENT && retransmit_count >= 2)) { // 4 consecutive transmissions have timed out. Kill it. If we // haven't even connected yet, give up after only 2 consecutive // failed transmissions. if(close_requested) state = CS_DESTROY; else state = CS_RESET; utp_call_on_error(ctx, this, UTP_ETIMEDOUT); return; } retransmit_timeout = new_timeout; rto_timeout = ctx->current_ms + new_timeout; if(!ignore_loss) { // On Timeout duplicate_ack = 0; int packet_size = get_packet_size(); if((cur_window_packets == 0) && ((int)max_window > packet_size)) { // we don't have any packets in-flight, even though // we could. This implies that the connection is just // idling. No need to be aggressive about resetting the // congestion window. Just let it decay by a 3:rd. // don't set it any lower than the packet size though max_window = max(max_window * 2 / 3, size_t(packet_size)); } else { // our delay was so high that our congestion window // was shrunk below one packet, preventing us from // sending anything for one time-out period. Now, reset // the congestion window to fit one packet, to start over // again max_window = packet_size; slow_start = true; } } // every packet should be considered lost for(int i = 0; i < cur_window_packets; ++i) { OutgoingPacket *pkt = (OutgoingPacket *)outbuf.get(seq_nr - i - 1); if(pkt == 0 || pkt->transmissions == 0 || pkt->need_resend) continue; pkt->need_resend = true; assert(cur_window >= pkt->payload); cur_window -= pkt->payload; } if(cur_window_packets > 0) { retransmit_count++; // used in parse_log.py log(UTP_LOG_NORMAL, "Packet timeout. Resend. seq_nr:%u. timeout:%u " "max_window:%u cur_window_packets:%d", seq_nr - cur_window_packets, retransmit_timeout, (uint)max_window, int(cur_window_packets)); fast_timeout = true; timeout_seq_nr = seq_nr; OutgoingPacket *pkt = (OutgoingPacket *)outbuf.get(seq_nr - cur_window_packets); assert(pkt); // Re-send the packet. send_packet(pkt); } } // Mark the socket as writable. If the cwnd has grown, or if the number of // bytes in-flight is lower than cwnd, we need to make the socket writable // again in case it isn't if(state == CS_CONNECTED_FULL && !is_full()) { state = CS_CONNECTED; #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "Socket writable. max_window:%u cur_window:%u packet_size:%u", (uint)max_window, (uint)cur_window, (uint)get_packet_size()); #endif utp_call_on_state_change(this->ctx, this, UTP_STATE_WRITABLE); } if(state >= CS_CONNECTED && !fin_sent) { if((int)(ctx->current_ms - last_sent_packet) >= KEEPALIVE_INTERVAL) { send_keep_alive(); } } break; } // prevent warning case CS_UNINITIALIZED: case CS_IDLE: case CS_RESET: case CS_DESTROY: break; } } // this should be called every time we change mtu_floor or mtu_ceiling void UTPSocket::mtu_search_update() { assert(mtu_floor <= mtu_ceiling); // binary search mtu_last = (mtu_floor + mtu_ceiling) / 2; // enable a new probe to be sent mtu_probe_seq = mtu_probe_size = 0; // if the floor and ceiling are close enough, consider the // MTU binary search complete. We set the current value // to floor since that's the only size we know can go through // also set the ceiling to floor to terminate the searching if(mtu_ceiling - mtu_floor <= 16) { mtu_last = mtu_floor; log(UTP_LOG_MTU, "MTU [DONE] floor:%d ceiling:%d current:%d", mtu_floor, mtu_ceiling, mtu_last); mtu_ceiling = mtu_floor; assert(mtu_floor <= mtu_ceiling); // Do another search in 30 minutes mtu_discover_time = utp_call_get_milliseconds(this->ctx, this) + 30 * 60 * 1000; } } void UTPSocket::mtu_reset() { mtu_ceiling = get_udp_mtu(); // Less would not pass TCP... mtu_floor = 576; log(UTP_LOG_MTU, "MTU [RESET] floor:%d ceiling:%d current:%d", mtu_floor, mtu_ceiling, mtu_last); assert(mtu_floor <= mtu_ceiling); mtu_discover_time = utp_call_get_milliseconds(this->ctx, this) + 30 * 60 * 1000; } // returns: // 0: the packet was acked. // 1: it means that the packet had already been acked // 2: the packet has not been sent yet int UTPSocket::ack_packet(uint16 seq) { OutgoingPacket *pkt = (OutgoingPacket *)outbuf.get(seq); // the packet has already been acked (or not sent) if(pkt == NULL) { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "got ack for:%u (already acked, or never sent)", seq); #endif return 1; } // can't ack packets that haven't been sent yet! if(pkt->transmissions == 0) { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "got ack for:%u (never sent, pkt_size:%u need_resend:%u)", seq, (uint)pkt->payload, pkt->need_resend); #endif return 2; } #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "got ack for:%u (pkt_size:%u need_resend:%u)", seq, (uint)pkt->payload, pkt->need_resend); #endif outbuf.put(seq, NULL); // if we never re-sent the packet, update the RTT estimate if(pkt->transmissions == 1) { // Estimate the round trip time. const uint32 ertt = (uint32)( (utp_call_get_microseconds(this->ctx, this) - pkt->time_sent) / 1000); if(rtt == 0) { // First round trip time sample rtt = ertt; rtt_var = ertt / 2; // sanity check. rtt should never be more than 6 seconds // assert(rtt < 6000); } else { // Compute new round trip times const int delta = (int)rtt - ertt; rtt_var = rtt_var + (int)(abs(delta) - rtt_var) / 4; rtt = rtt - rtt / 8 + ertt / 8; // sanity check. rtt should never be more than 6 seconds // assert(rtt < 6000); rtt_hist.add_sample(ertt, ctx->current_ms); } rto = max< uint >(rtt + rtt_var * 4, 1000); #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "rtt:%u avg:%u var:%u rto:%u", ertt, rtt, rtt_var, rto); #endif } retransmit_timeout = rto; rto_timeout = ctx->current_ms + rto; // if need_resend is set, this packet has already // been considered timed-out, and is not included in // the cur_window anymore if(!pkt->need_resend) { assert(cur_window >= pkt->payload); cur_window -= pkt->payload; } free(pkt); retransmit_count = 0; return 0; } // count the number of bytes that were acked by the EACK header size_t UTPSocket::selective_ack_bytes(uint base, const byte *mask, byte len, int64 &min_rtt) { if(cur_window_packets == 0) return 0; size_t acked_bytes = 0; int bits = len * 8; uint64 now = utp_call_get_microseconds(this->ctx, this); do { uint v = base + bits; // ignore bits that haven't been sent yet // see comment in UTPSocket::selective_ack if(((seq_nr - v - 1) & ACK_NR_MASK) >= (uint16)(cur_window_packets - 1)) continue; // ignore bits that represents packets we haven't sent yet // or packets that have already been acked OutgoingPacket *pkt = (OutgoingPacket *)outbuf.get(v); if(!pkt || pkt->transmissions == 0) continue; // Count the number of segments that were successfully received past it. if(bits >= 0 && mask[bits >> 3] & (1 << (bits & 7))) { assert((int)(pkt->payload) >= 0); acked_bytes += pkt->payload; if(pkt->time_sent < now) min_rtt = min< int64 >(min_rtt, now - pkt->time_sent); else min_rtt = min< int64 >(min_rtt, 50000); continue; } } while(--bits >= -1); return acked_bytes; } enum { MAX_EACK = 128 }; void UTPSocket::selective_ack(uint base, const byte *mask, byte len) { if(cur_window_packets == 0) return; // the range is inclusive [0, 31] bits int bits = len * 8 - 1; int count = 0; // resends is a stack of sequence numbers we need to resend. Since we // iterate in reverse over the acked packets, at the end, the top packets // are the ones we want to resend int resends[MAX_EACK]; int nr = 0; #if UTP_DEBUG_LOGGING char bitmask[1024] = {0}; int counter = bits; for(int i = 0; i <= bits; ++i) { bool bit_set = counter >= 0 && mask[counter >> 3] & (1 << (counter & 7)); bitmask[i] = bit_set ? '1' : '0'; --counter; } log(UTP_LOG_DEBUG, "Got EACK [%s] base:%u", bitmask, base); #endif do { // we're iterating over the bits from higher sequence numbers // to lower (kind of in reverse order, wich might not be very // intuitive) uint v = base + bits; // ignore bits that haven't been sent yet // and bits that fall below the ACKed sequence number // this can happen if an EACK message gets // reordered and arrives after a packet that ACKs up past // the base for thie EACK message // this is essentially the same as: // if v >= seq_nr || v <= seq_nr - cur_window_packets // but it takes wrapping into account // if v == seq_nr the -1 will make it wrap. if v > seq_nr // it will also wrap (since it will fall further below 0) // and be > cur_window_packets. // if v == seq_nr - cur_window_packets, the result will be // seq_nr - (seq_nr - cur_window_packets) - 1 // == seq_nr - seq_nr + cur_window_packets - 1 // == cur_window_packets - 1 which will be caught by the // test. If v < seq_nr - cur_window_packets the result will grow // fall furhter outside of the cur_window_packets range. // sequence number space: // // rejected < accepted > rejected // <============+--------------+============> // ^ ^ // | | // (seq_nr-wnd) seq_nr if(((seq_nr - v - 1) & ACK_NR_MASK) >= (uint16)(cur_window_packets - 1)) continue; // this counts as a duplicate ack, even though we might have // received an ack for this packet previously (in another EACK // message for instance) bool bit_set = bits >= 0 && mask[bits >> 3] & (1 << (bits & 7)); // if this packet is acked, it counts towards the duplicate ack counter if(bit_set) count++; // ignore bits that represents packets we haven't sent yet // or packets that have already been acked OutgoingPacket *pkt = (OutgoingPacket *)outbuf.get(v); if(!pkt || pkt->transmissions == 0) { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "skipping %u. pkt:%08x transmissions:%u %s", v, pkt, pkt ? pkt->transmissions : 0, pkt ? "(not sent yet?)" : "(already acked?)"); #endif continue; } // Count the number of segments that were successfully received past it. if(bit_set) { // the selective ack should never ACK the packet we're waiting for to // decrement cur_window_packets assert((v & outbuf.mask) != ((seq_nr - cur_window_packets) & outbuf.mask)); ack_packet(v); continue; } // Resend segments // if count is less than our re-send limit, we haven't seen enough // acked packets in front of this one to warrant a re-send. // if count == 0, we're still going through the tail of zeroes if(((v - fast_resend_seq_nr) & ACK_NR_MASK) <= OUTGOING_BUFFER_MAX_SIZE && count >= DUPLICATE_ACKS_BEFORE_RESEND) { // resends is a stack, and we're mostly interested in the top of it // if we're full, just throw away the lower half if(nr >= MAX_EACK - 2) { memmove(resends, &resends[MAX_EACK / 2], MAX_EACK / 2 * sizeof(resends[0])); nr -= MAX_EACK / 2; } resends[nr++] = v; #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "no ack for %u", v); #endif } else { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "not resending %u count:%d dup_ack:%u fast_resend_seq_nr:%u", v, count, duplicate_ack, fast_resend_seq_nr); #endif } } while(--bits >= -1); if(((base - 1 - fast_resend_seq_nr) & ACK_NR_MASK) <= OUTGOING_BUFFER_MAX_SIZE && count >= DUPLICATE_ACKS_BEFORE_RESEND) { // if we get enough duplicate acks to start // resending, the first packet we should resend // is base-1 resends[nr++] = (base - 1) & ACK_NR_MASK; #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "no ack for %u", (base - 1) & ACK_NR_MASK); #endif } else { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "not resending %u count:%d dup_ack:%u fast_resend_seq_nr:%u", base - 1, count, duplicate_ack, fast_resend_seq_nr); #endif } bool back_off = false; int i = 0; while(nr > 0) { uint v = resends[--nr]; // don't consider the tail of 0:es to be lost packets // only unacked packets with acked packets after should // be considered lost OutgoingPacket *pkt = (OutgoingPacket *)outbuf.get(v); // this may be an old (re-ordered) packet, and some of the // packets in here may have been acked already. In which // case they will not be in the send queue anymore if(!pkt) continue; // used in parse_log.py log(UTP_LOG_NORMAL, "Packet %u lost. Resending", v); // On Loss back_off = true; #ifdef _DEBUG ++_stats.rexmit; #endif send_packet(pkt); fast_resend_seq_nr = (v + 1) & ACK_NR_MASK; // Re-send max 4 packets. if(++i >= 4) break; } if(back_off) maybe_decay_win(ctx->current_ms); duplicate_ack = count; } void UTPSocket::apply_ccontrol(size_t bytes_acked, uint32 actual_delay, int64 min_rtt) { // the delay can never be greater than the rtt. The min_rtt // variable is the RTT in microseconds assert(min_rtt >= 0); int32 our_delay = min< uint32 >(our_hist.get_value(), uint32(min_rtt)); assert(our_delay != INT_MAX); assert(our_delay >= 0); utp_call_on_delay_sample(this->ctx, this, our_delay / 1000); // This test the connection under heavy load from foreground // traffic. Pretend that our delays are very high to force the // connection to use sub-packet size window sizes // our_delay *= 4; // target is microseconds int target = target_delay; if(target <= 0) target = 100000; // this is here to compensate for very large clock drift that affects // the congestion controller into giving certain endpoints an unfair // share of the bandwidth. We have an estimate of the clock drift // (clock_drift). The unit of this is microseconds per 5 seconds. // empirically, a reasonable cut-off appears to be about 200000 // (which is pretty high). The main purpose is to compensate for // people trying to "cheat" uTP by making their clock run slower, // and this definitely catches that without any risk of false positives // if clock_drift < -200000 start applying a penalty delay proportional // to how far beoynd -200000 the clock drift is int32 penalty = 0; if(clock_drift < -200000) { penalty = (-clock_drift - 200000) / 7; our_delay += penalty; } double off_target = target - our_delay; // this is the same as: // // (min(off_target, target) / target) * (bytes_acked / max_window) * // MAX_CWND_INCREASE_BYTES_PER_RTT // // so, it's scaling the max increase by the fraction of the window this ack // represents, and the fraction of the target delay the current delay // represents. The min() around off_target protects against crazy values of // our_delay, which may happen when th timestamps wraps, or by just having a // malicious peer sending garbage. This caps the increase of the window size // to MAX_CWND_INCREASE_BYTES_PER_RTT per rtt. as for large negative numbers, // this direction is already capped at the min packet size further down the // min around the bytes_acked protects against the case where the window size // was recently shrunk and the number of acked bytes exceeds that. This is // considered no more than one full window, in order to keep the gain within // sane boundries. assert(bytes_acked > 0); double window_factor = (double)min(bytes_acked, max_window) / (double)max(max_window, bytes_acked); double delay_factor = off_target / target; double scaled_gain = MAX_CWND_INCREASE_BYTES_PER_RTT * window_factor * delay_factor; // since MAX_CWND_INCREASE_BYTES_PER_RTT is a cap on how much the window size // (max_window) may increase per RTT, we may not increase the window size more // than that proportional to the number of bytes that were acked, so that once // one window has been acked (one rtt) the increase limit is not exceeded the // +1. is to allow for floating point imprecision assert(scaled_gain <= 1. + MAX_CWND_INCREASE_BYTES_PER_RTT * (double)min(bytes_acked, max_window) / (double)max(max_window, bytes_acked)); if(scaled_gain > 0 && ctx->current_ms - last_maxed_out_window > 1000) { // if it was more than 1 second since we tried to send a packet // and stopped because we hit the max window, we're most likely rate // limited (which prevents us from ever hitting the window size) // if this is the case, we cannot let the max_window grow indefinitely scaled_gain = 0; } size_t ledbat_cwnd = (max_window + scaled_gain < MIN_WINDOW_SIZE) ? MIN_WINDOW_SIZE : (size_t)(max_window + scaled_gain); if(slow_start) { size_t ss_cwnd = (size_t)(max_window + window_factor * get_packet_size()); if(ss_cwnd > ssthresh) { slow_start = false; } else if(our_delay > target * 0.9) { // even if we're a little under the target delay, we conservatively // discontinue the slow start phase slow_start = false; ssthresh = max_window; } else { max_window = max(ss_cwnd, ledbat_cwnd); } } else { max_window = ledbat_cwnd; } // make sure that the congestion window is below max // make sure that we don't shrink our window too small max_window = clamp< size_t >(max_window, MIN_WINDOW_SIZE, opt_sndbuf); // used in parse_log.py log(UTP_LOG_NORMAL, "actual_delay:%u our_delay:%d their_delay:%u off_target:%d max_window:%u " "delay_base:%u delay_sum:%d target_delay:%d acked_bytes:%u cur_window:%u " "scaled_gain:%f rtt:%u rate:%u wnduser:%u rto:%u timeout:%d " "get_microseconds:" I64u " " "cur_window_packets:%u packet_size:%u their_delay_base:%u " "their_actual_delay:%u " "average_delay:%d clock_drift:%d clock_drift_raw:%d delay_penalty:%d " "current_delay_sum:" I64u "current_delay_samples:%d average_delay_base:%d " "last_maxed_out_window:" I64u " opt_sndbuf:%d " "current_ms:" I64u "", actual_delay, our_delay / 1000, their_hist.get_value() / 1000, int(off_target / 1000), uint(max_window), uint32(our_hist.delay_base), int((our_delay + their_hist.get_value()) / 1000), int(target / 1000), uint(bytes_acked), (uint)(cur_window - bytes_acked), (float)(scaled_gain), rtt, (uint)(max_window * 1000 / (rtt_hist.delay_base ? rtt_hist.delay_base : 50)), (uint)max_window_user, rto, (int)(rto_timeout - ctx->current_ms), utp_call_get_microseconds(this->ctx, this), cur_window_packets, (uint)get_packet_size(), their_hist.delay_base, their_hist.delay_base + their_hist.get_value(), average_delay, clock_drift, clock_drift_raw, penalty / 1000, current_delay_sum, current_delay_samples, average_delay_base, uint64(last_maxed_out_window), int(opt_sndbuf), uint64(ctx->current_ms)); } static void utp_register_recv_packet(UTPSocket *conn, size_t len) { #ifdef _DEBUG ++conn->_stats.nrecv; conn->_stats.nbytes_recv += len; #endif if(len <= PACKET_SIZE_MID) { if(len <= PACKET_SIZE_EMPTY) { conn->ctx->context_stats._nraw_recv[PACKET_SIZE_EMPTY_BUCKET]++; } else if(len <= PACKET_SIZE_SMALL) { conn->ctx->context_stats._nraw_recv[PACKET_SIZE_SMALL_BUCKET]++; } else conn->ctx->context_stats._nraw_recv[PACKET_SIZE_MID_BUCKET]++; } else { if(len <= PACKET_SIZE_BIG) { conn->ctx->context_stats._nraw_recv[PACKET_SIZE_BIG_BUCKET]++; } else conn->ctx->context_stats._nraw_recv[PACKET_SIZE_HUGE_BUCKET]++; } } // returns the max number of bytes of payload the uTP // connection is allowed to send size_t UTPSocket::get_packet_size() const { int header_size = sizeof(PacketFormatV1); size_t mtu = mtu_last ? mtu_last : mtu_ceiling; return mtu - header_size; } // Process an incoming packet // syn is true if this is the first packet received. It will cut off parsing // as soon as the header is done size_t utp_process_incoming(UTPSocket *conn, const byte *packet, size_t len, bool syn = false) { utp_register_recv_packet(conn, len); conn->ctx->current_ms = utp_call_get_milliseconds(conn->ctx, conn); const PacketFormatV1 *pf1 = (PacketFormatV1 *)packet; const byte *packet_end = packet + len; uint16 pk_seq_nr = pf1->seq_nr; uint16 pk_ack_nr = pf1->ack_nr; uint8 pk_flags = pf1->type(); if(pk_flags >= ST_NUM_STATES) return 0; #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Got %s. seq_nr:%u ack_nr:%u state:%s timestamp:" I64u " reply_micro:%u", flagnames[pk_flags], pk_seq_nr, pk_ack_nr, statenames[conn->state], uint64(pf1->tv_usec), (uint32)(pf1->reply_micro)); #endif // mark receipt time uint64 time = utp_call_get_microseconds(conn->ctx, conn); // window packets size is used to calculate a minimum // permissible range for received acks. connections with acks falling // out of this range are dropped const uint16 curr_window = max< uint16 >( conn->cur_window_packets + ACK_NR_ALLOWED_WINDOW, ACK_NR_ALLOWED_WINDOW); // ignore packets whose ack_nr is invalid. This would imply a spoofed address // or a malicious attempt to attach the uTP implementation. // acking a packet that hasn't been sent yet! // SYN packets have an exception, since there are no previous packets if((pk_flags != ST_SYN || conn->state != CS_SYN_RECV) && (wrapping_compare_less(conn->seq_nr - 1, pk_ack_nr, ACK_NR_MASK) || wrapping_compare_less(pk_ack_nr, conn->seq_nr - 1 - curr_window, ACK_NR_MASK))) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Invalid ack_nr: %u. our seq_nr: %u last unacked: %u", pk_ack_nr, conn->seq_nr, (conn->seq_nr - conn->cur_window_packets) & ACK_NR_MASK); #endif return 0; } // RSTs are handled earlier, since the connid matches the send id not the recv // id assert(pk_flags != ST_RESET); // TODO: maybe send a ST_RESET if we're in CS_RESET? const byte *selack_ptr = NULL; // Unpack UTP packet options // Data pointer const byte *data = (const byte *)pf1 + conn->get_header_size(); if(conn->get_header_size() > len) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Invalid packet size (less than header size)"); #endif return 0; } // Skip the extension headers uint extension = pf1->ext; if(extension != 0) { do { // Verify that the packet is valid. data += 2; if((int)(packet_end - data) < 0 || (int)(packet_end - data) < data[-1]) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Invalid len of extensions"); #endif return 0; } switch(extension) { case 1: // Selective Acknowledgment selack_ptr = data; break; case 2: // extension bits if(data[-1] != 8) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Invalid len of extension bits header"); #endif return 0; } memcpy(conn->extensions, data, 8); #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "got extension bits:%02x%02x%02x%02x%02x%02x%02x%02x", conn->extensions[0], conn->extensions[1], conn->extensions[2], conn->extensions[3], conn->extensions[4], conn->extensions[5], conn->extensions[6], conn->extensions[7]); #endif } extension = data[-2]; data += data[-1]; } while(extension); } if(conn->state == CS_SYN_SENT) { // if this is a syn-ack, initialize our ack_nr // to match the sequence number we got from // the other end conn->ack_nr = (pk_seq_nr - 1) & SEQ_NR_MASK; } conn->last_got_packet = conn->ctx->current_ms; if(syn) { return 0; } // seqnr is the number of packets past the expected // packet this is. ack_nr is the last acked, seq_nr is the // current. Subtracring 1 makes 0 mean "this is the next // expected packet". const uint seqnr = (pk_seq_nr - conn->ack_nr - 1) & SEQ_NR_MASK; // Getting an invalid sequence number? if(seqnr >= REORDER_BUFFER_MAX_SIZE) { if(seqnr >= (SEQ_NR_MASK + 1) - REORDER_BUFFER_MAX_SIZE && pk_flags != ST_STATE) { conn->schedule_ack(); } #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, " Got old Packet/Ack (%u/%u)=%u", pk_seq_nr, conn->ack_nr, seqnr); #endif return 0; } // Process acknowledgment // acks is the number of packets that was acked int acks = (pk_ack_nr - (conn->seq_nr - 1 - conn->cur_window_packets)) & ACK_NR_MASK; // this happens when we receive an old ack nr if(acks > conn->cur_window_packets) acks = 0; // if we get the same ack_nr as in the last packet // increase the duplicate_ack counter, otherwise reset // it to 0. // It's important to only count ACKs in ST_STATE packets. Any other // packet (primarily ST_DATA) is likely to have been sent because of the // other end having new outgoing data, not in response to incoming data. // For instance, if we're receiving a steady stream of payload with no // outgoing data, and we suddently have a few bytes of payload to send (say, // a bittorrent HAVE message), we're very likely to see 3 duplicate ACKs // immediately after sending our payload packet. This effectively disables // the fast-resend on duplicate-ack logic for bi-directional connections // (except in the case of a selective ACK). This is in line with BSD4.4 TCP // implementation. if(conn->cur_window_packets > 0) { if(pk_ack_nr == ((conn->seq_nr - conn->cur_window_packets - 1) & ACK_NR_MASK) && conn->cur_window_packets > 0 && pk_flags == ST_STATE) { ++conn->duplicate_ack; if(conn->duplicate_ack == DUPLICATE_ACKS_BEFORE_RESEND && conn->mtu_probe_seq) { // It's likely that the probe was rejected due to its size, but we // haven't got an ICMP report back yet if(pk_ack_nr == ((conn->mtu_probe_seq - 1) & ACK_NR_MASK)) { conn->mtu_ceiling = conn->mtu_probe_size - 1; conn->mtu_search_update(); conn->log(UTP_LOG_MTU, "MTU [DUPACK] floor:%d ceiling:%d current:%d", conn->mtu_floor, conn->mtu_ceiling, conn->mtu_last); } else { // A non-probe was blocked before our probe. // Can't conclude much, send a new probe conn->mtu_probe_seq = conn->mtu_probe_size = 0; } } } else { conn->duplicate_ack = 0; } // TODO: if duplicate_ack == DUPLICATE_ACK_BEFORE_RESEND // and fast_resend_seq_nr <= ack_nr + 1 // resend ack_nr + 1 // also call maybe_decay_win() } // figure out how many bytes were acked size_t acked_bytes = 0; // the minimum rtt of all acks // this is the upper limit on the delay we get back // from the other peer. Our delay cannot exceed // the rtt of the packet. If it does, clamp it. // this is done in apply_ledbat_ccontrol() int64 min_rtt = INT64_MAX; uint64 now = utp_call_get_microseconds(conn->ctx, conn); for(int i = 0; i < acks; ++i) { int seq = (conn->seq_nr - conn->cur_window_packets + i) & ACK_NR_MASK; OutgoingPacket *pkt = (OutgoingPacket *)conn->outbuf.get(seq); if(pkt == 0 || pkt->transmissions == 0) continue; assert((int)(pkt->payload) >= 0); acked_bytes += pkt->payload; if(conn->mtu_probe_seq && seq == static_cast< int >(conn->mtu_probe_seq)) { conn->mtu_floor = conn->mtu_probe_size; conn->mtu_search_update(); conn->log(UTP_LOG_MTU, "MTU [ACK] floor:%d ceiling:%d current:%d", conn->mtu_floor, conn->mtu_ceiling, conn->mtu_last); } // in case our clock is not monotonic if(pkt->time_sent < now) min_rtt = min< int64 >(min_rtt, now - pkt->time_sent); else min_rtt = min< int64 >(min_rtt, 50000); } // count bytes acked by EACK if(selack_ptr != NULL) { acked_bytes += conn->selective_ack_bytes( (pk_ack_nr + 2) & ACK_NR_MASK, selack_ptr, selack_ptr[-1], min_rtt); } #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "acks:%d acked_bytes:%u seq_nr:%d cur_window:%u " "cur_window_packets:%u relative_seqnr:%u max_window:%u min_rtt:%u " "rtt:%u", acks, (uint)acked_bytes, conn->seq_nr, (uint)conn->cur_window, conn->cur_window_packets, seqnr, (uint)conn->max_window, (uint)(min_rtt / 1000), conn->rtt); #endif uint64 p = pf1->tv_usec; conn->last_measured_delay = conn->ctx->current_ms; // get delay in both directions // record the delay to report back const uint32 their_delay = (uint32)(p == 0 ? 0 : time - p); conn->reply_micro = their_delay; uint32 prev_delay_base = conn->their_hist.delay_base; if(their_delay != 0) conn->their_hist.add_sample(their_delay, conn->ctx->current_ms); // if their new delay base is less than their previous one // we should shift our delay base in the other direction in order // to take the clock skew into account if(prev_delay_base != 0 && wrapping_compare_less(conn->their_hist.delay_base, prev_delay_base, TIMESTAMP_MASK)) { // never adjust more than 10 milliseconds if(prev_delay_base - conn->their_hist.delay_base <= 10000) { conn->our_hist.shift(prev_delay_base - conn->their_hist.delay_base); } } const uint32 actual_delay = (uint32(pf1->reply_micro) == INT_MAX ? 0 : uint32(pf1->reply_micro)); // if the actual delay is 0, it means the other end // hasn't received a sample from us yet, and doesn't // know what it is. We can't update out history unless // we have a true measured sample if(actual_delay != 0) { conn->our_hist.add_sample(actual_delay, conn->ctx->current_ms); // this is keeping an average of the delay samples // we've recevied within the last 5 seconds. We sum // all the samples and increase the count in order to // calculate the average every 5 seconds. The samples // are based off of the average_delay_base to deal with // wrapping counters. if(conn->average_delay_base == 0) conn->average_delay_base = actual_delay; int64 average_delay_sample = 0; // distance walking from lhs to rhs, downwards const uint32 dist_down = conn->average_delay_base - actual_delay; // distance walking from lhs to rhs, upwards const uint32 dist_up = actual_delay - conn->average_delay_base; if(dist_down > dist_up) { // assert(dist_up < INT_MAX / 4); // average_delay_base < actual_delay, we should end up // with a positive sample average_delay_sample = dist_up; } else { // assert(-int64(dist_down) < INT_MAX / 4); // average_delay_base >= actual_delay, we should end up // with a negative sample average_delay_sample = -int64(dist_down); } conn->current_delay_sum += average_delay_sample; ++conn->current_delay_samples; if(conn->ctx->current_ms > conn->average_sample_time) { int32 prev_average_delay = conn->average_delay; assert(conn->current_delay_sum / conn->current_delay_samples < INT_MAX); assert(conn->current_delay_sum / conn->current_delay_samples > -INT_MAX); // write the new average conn->average_delay = (int32)(conn->current_delay_sum / conn->current_delay_samples); // each slot represents 5 seconds conn->average_sample_time += 5000; conn->current_delay_sum = 0; conn->current_delay_samples = 0; // this makes things very confusing when logging the average delay //#if !g_log_utp // normalize the average samples // since we're only interested in the slope // of the curve formed by the average delay samples, // we can cancel out the actual offset to make sure // we won't have problems with wrapping. int min_sample = min(prev_average_delay, conn->average_delay); int max_sample = max(prev_average_delay, conn->average_delay); // normalize around zero. Try to keep the min <= 0 and max >= 0 int adjust = 0; if(min_sample > 0) { // adjust all samples (and the baseline) down by min_sample adjust = -min_sample; } else if(max_sample < 0) { // adjust all samples (and the baseline) up by -max_sample adjust = -max_sample; } if(adjust) { conn->average_delay_base -= adjust; conn->average_delay += adjust; prev_average_delay += adjust; } //#endif // update the clock drift estimate // the unit is microseconds per 5 seconds // what we're doing is just calculating the average of the // difference between each slot. Since each slot is 5 seconds // and the timestamps unit are microseconds, we'll end up with // the average slope across our history. If there is a consistent // trend, it will show up in this value // int64 slope = 0; int32 drift = conn->average_delay - prev_average_delay; // clock_drift is a rolling average conn->clock_drift = (int64(conn->clock_drift) * 7 + drift) / 8; conn->clock_drift_raw = drift; } } // if our new delay base is less than our previous one // we should shift the other end's delay base in the other // direction in order to take the clock skew into account // This is commented out because it creates bad interactions // with our adjustment in the other direction. We don't really // need our estimates of the other peer to be very accurate // anyway. The problem with shifting here is that we're more // likely shift it back later because of a low latency. This // second shift back would cause us to shift our delay base // which then get's into a death spiral of shifting delay bases /* if (prev_delay_base != 0 && wrapping_compare_less(conn->our_hist.delay_base, prev_delay_base)) { // never adjust more than 10 milliseconds if (prev_delay_base - conn->our_hist.delay_base <= 10000) { conn->their_hist.Shift(prev_delay_base - conn->our_hist.delay_base); } } */ // if the delay estimate exceeds the RTT, adjust the base_delay to // compensate assert(min_rtt >= 0); if(int64(conn->our_hist.get_value()) > min_rtt) { conn->our_hist.shift((uint32)(conn->our_hist.get_value() - min_rtt)); } // only apply the congestion controller on acks // if we don't have a delay measurement, there's // no point in invoking the congestion control if(actual_delay != 0 && acked_bytes >= 1) conn->apply_ccontrol(acked_bytes, actual_delay, min_rtt); // sanity check, the other end should never ack packets // past the point we've sent if(acks <= conn->cur_window_packets) { conn->max_window_user = pf1->windowsize; // If max user window is set to 0, then we startup a timer // That will reset it to 1 after 15 seconds. if(conn->max_window_user == 0) // Reset max_window_user to 1 every 15 seconds. conn->zerowindow_time = conn->ctx->current_ms + 15000; // Respond to connect message // Switch to CONNECTED state. // If this is an ack and we're in still handshaking // transition over to the connected state. // Incoming connection completion if(pk_flags == ST_DATA && conn->state == CS_SYN_RECV) { conn->state = CS_CONNECTED; } // Outgoing connection completion if(pk_flags == ST_STATE && conn->state == CS_SYN_SENT) { conn->state = CS_CONNECTED; // If the user has defined the ON_CONNECT callback, use that to // notify the user that the socket is now connected. If ON_CONNECT // has not been defined, notify the user via ON_STATE_CHANGE. if(conn->ctx->callbacks[UTP_ON_CONNECT]) utp_call_on_connect(conn->ctx, conn); else utp_call_on_state_change(conn->ctx, conn, UTP_STATE_CONNECT); // We've sent a fin, and everything was ACKed (including the FIN). // cur_window_packets == acks means that this packet acked all // the remaining packets that were in-flight. } else if(conn->fin_sent && conn->cur_window_packets == acks) { conn->fin_sent_acked = true; if(conn->close_requested) { conn->state = CS_DESTROY; } } // Update fast resend counter if(wrapping_compare_less(conn->fast_resend_seq_nr, (pk_ack_nr + 1) & ACK_NR_MASK, ACK_NR_MASK)) conn->fast_resend_seq_nr = (pk_ack_nr + 1) & ACK_NR_MASK; #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "fast_resend_seq_nr:%u", conn->fast_resend_seq_nr); #endif for(int i = 0; i < acks; ++i) { int ack_status = conn->ack_packet(conn->seq_nr - conn->cur_window_packets); // if ack_status is 0, the packet was acked. // if acl_stauts is 1, it means that the packet had already been acked // if it's 2, the packet has not been sent yet // We need to break this loop in the latter case. This could potentially // happen if we get an ack_nr that does not exceed what we have stuffed // into the outgoing buffer, but does exceed what we have sent if(ack_status == 2) { #ifdef _DEBUG OutgoingPacket *pkt = (OutgoingPacket *)conn->outbuf.get( conn->seq_nr - conn->cur_window_packets); assert(pkt->transmissions == 0); #endif break; } conn->cur_window_packets--; #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "decementing cur_window_packets:%u", conn->cur_window_packets); #endif } #ifdef _DEBUG if(conn->cur_window_packets == 0) assert(conn->cur_window == 0); #endif // packets in front of this may have been acked by a // selective ack (EACK). Keep decreasing the window packet size // until we hit a packet that is still waiting to be acked // in the send queue // this is especially likely to happen when the other end // has the EACK send bug older versions of uTP had while(conn->cur_window_packets > 0 && !conn->outbuf.get(conn->seq_nr - conn->cur_window_packets)) { conn->cur_window_packets--; #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "decementing cur_window_packets:%u", conn->cur_window_packets); #endif } #ifdef _DEBUG if(conn->cur_window_packets == 0) assert(conn->cur_window == 0); #endif // this invariant should always be true assert(conn->cur_window_packets == 0 || conn->outbuf.get(conn->seq_nr - conn->cur_window_packets)); // flush Nagle if(conn->cur_window_packets == 1) { OutgoingPacket *pkt = (OutgoingPacket *)conn->outbuf.get(conn->seq_nr - 1); // do we still have quota? if(pkt->transmissions == 0) { conn->send_packet(pkt); } } // Fast timeout-retry if(conn->fast_timeout) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Fast timeout %u,%u,%u?", (uint)conn->cur_window, conn->seq_nr - conn->timeout_seq_nr, conn->timeout_seq_nr); #endif // if the fast_resend_seq_nr is not pointing to the oldest outstanding // packet, it suggests that we've already resent the packet that timed // out, and we should leave the fast-timeout mode. if(((conn->seq_nr - conn->cur_window_packets) & ACK_NR_MASK) != conn->fast_resend_seq_nr) { conn->fast_timeout = false; } else { // resend the oldest packet and increment fast_resend_seq_nr // to not allow another fast resend on it again OutgoingPacket *pkt = (OutgoingPacket *)conn->outbuf.get( conn->seq_nr - conn->cur_window_packets); if(pkt && pkt->transmissions > 0) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Packet %u fast timeout-retry.", conn->seq_nr - conn->cur_window_packets); #endif #ifdef _DEBUG ++conn->_stats.fastrexmit; #endif conn->fast_resend_seq_nr++; conn->send_packet(pkt); } } } } // Process selective acknowledgent if(selack_ptr != NULL) { conn->selective_ack(pk_ack_nr + 2, selack_ptr, selack_ptr[-1]); } // this invariant should always be true assert(conn->cur_window_packets == 0 || conn->outbuf.get(conn->seq_nr - conn->cur_window_packets)); #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "acks:%d acked_bytes:%u seq_nr:%u cur_window:%u " "cur_window_packets:%u ", acks, (uint)acked_bytes, conn->seq_nr, (uint)conn->cur_window, conn->cur_window_packets); #endif // In case the ack dropped the current window below // the max_window size, Mark the socket as writable if(conn->state == CS_CONNECTED_FULL && !conn->is_full()) { conn->state = CS_CONNECTED; #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Socket writable. max_window:%u cur_window:%u packet_size:%u", (uint)conn->max_window, (uint)conn->cur_window, (uint)conn->get_packet_size()); #endif utp_call_on_state_change(conn->ctx, conn, UTP_STATE_WRITABLE); } if(pk_flags == ST_STATE) { // This is a state packet only. return 0; } // The connection is not in a state that can accept data? if(conn->state != CS_CONNECTED && conn->state != CS_CONNECTED_FULL) { return 0; } // Is this a finalize packet? if(pk_flags == ST_FIN && !conn->got_fin) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Got FIN eof_pkt:%u", pk_seq_nr); #endif conn->got_fin = true; conn->eof_pkt = pk_seq_nr; // at this point, it is possible for the // other end to have sent packets with // sequence numbers higher than seq_nr. // if this is the case, our reorder_count // is out of sync. This case is dealt with // when we re-order and hit the eof_pkt. // we'll just ignore any packets with // sequence numbers past this } // Getting an in-order packet? if(seqnr == 0) { size_t count = packet_end - data; if(count > 0 && !conn->read_shutdown) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Got Data len:%u (rb:%u)", (uint)count, (uint)utp_call_get_read_buffer_size(conn->ctx, conn)); #endif // Post bytes to the upper layer utp_call_on_read(conn->ctx, conn, data, count); } conn->ack_nr++; // Check if the next packet has been received too, but waiting // in the reorder buffer. for(;;) { if(!conn->got_fin_reached && conn->got_fin && conn->eof_pkt == conn->ack_nr) { conn->got_fin_reached = true; conn->rto_timeout = conn->ctx->current_ms + min< uint >(conn->rto * 3, 60); #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Posting EOF"); #endif utp_call_on_state_change(conn->ctx, conn, UTP_STATE_EOF); // if the other end wants to close, ack conn->send_ack(); // reorder_count is not necessarily 0 at this point. // even though it is most of the time, the other end // may have sent packets with higher sequence numbers // than what later end up being eof_pkt // since we have received all packets up to eof_pkt // just ignore the ones after it. conn->reorder_count = 0; } // Quick get-out in case there is nothing to reorder if(conn->reorder_count == 0) break; // Check if there are additional buffers in the reorder buffers // that need delivery. byte *p = (byte *)conn->inbuf.get(conn->ack_nr + 1); if(p == NULL) break; conn->inbuf.put(conn->ack_nr + 1, NULL); count = *(uint *)p; if(count > 0 && !conn->read_shutdown) { // Pass the bytes to the upper layer utp_call_on_read(conn->ctx, conn, p + sizeof(uint), count); } conn->ack_nr++; // Free the element from the reorder buffer free(p); assert(conn->reorder_count > 0); conn->reorder_count--; } conn->schedule_ack(); } else { // Getting an out of order packet. // The packet needs to be remembered and rearranged later. // if we have received a FIN packet, and the EOF-sequence number // is lower than the sequence number of the packet we just received // something is wrong. if(conn->got_fin && pk_seq_nr > conn->eof_pkt) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Got an invalid packet sequence number, past EOF " "reorder_count:%u len:%u (rb:%u)", conn->reorder_count, (uint)(packet_end - data), (uint)utp_call_get_read_buffer_size(conn->ctx, conn)); #endif return 0; } // if the sequence number is entirely off the expected // one, just drop it. We can't allocate buffer space in // the inbuf entirely based on untrusted input if(seqnr > 0x3ff) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "0x%08x: Got an invalid packet sequence number, too far off " "reorder_count:%u len:%u (rb:%u)", conn->reorder_count, (uint)(packet_end - data), (uint)utp_call_get_read_buffer_size(conn->ctx, conn)); #endif return 0; } // we need to grow the circle buffer before we // check if the packet is already in here, so that // we don't end up looking at an older packet (since // the indices wraps around). conn->inbuf.ensure_size(pk_seq_nr + 1, seqnr + 1); // Has this packet already been received? (i.e. a duplicate) // If that is the case, just discard it. if(conn->inbuf.get(pk_seq_nr) != NULL) { #ifdef _DEBUG ++conn->_stats.nduprecv; #endif return 0; } // Allocate memory to fit the packet that needs to re-ordered byte *mem = (byte *)malloc((packet_end - data) + sizeof(uint)); *(uint *)mem = (uint)(packet_end - data); memcpy(mem + sizeof(uint), data, packet_end - data); // Insert into reorder buffer and increment the count // of # of packets to be reordered. // we add one to seqnr in order to leave the last // entry empty, that way the assert in send_ack // is valid. we have to add one to seqnr too, in order // to make the circular buffer grow around the correct // point (which is conn->ack_nr + 1). assert(conn->inbuf.get(pk_seq_nr) == NULL); assert((pk_seq_nr & conn->inbuf.mask) != ((conn->ack_nr + 1) & conn->inbuf.mask)); conn->inbuf.put(pk_seq_nr, mem); conn->reorder_count++; #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "0x%08x: Got out of order data reorder_count:%u len:%u (rb:%u)", conn->reorder_count, (uint)(packet_end - data), (uint)utp_call_get_read_buffer_size(conn->ctx, conn)); #endif conn->schedule_ack(); } return (size_t)(packet_end - data); } inline byte UTP_Version(PacketFormatV1 const *pf) { return (pf->type() < ST_NUM_STATES && pf->ext < 3 ? pf->version() : 0); } UTPSocket::~UTPSocket() { #if UTP_DEBUG_LOGGING log(UTP_LOG_DEBUG, "Killing socket"); #endif utp_call_on_state_change(ctx, this, UTP_STATE_DESTROYING); if(ctx->last_utp_socket == this) { ctx->last_utp_socket = NULL; } // Remove object from the global hash table UTPSocketKeyData *kd = ctx->utp_sockets->Delete(UTPSocketKey(addr, conn_id_recv)); assert(kd); (void)kd; // remove the socket from ack_sockets if it was there also removeSocketFromAckList(this); // Free all memory occupied by the socket object. for(size_t i = 0; i <= inbuf.mask; i++) { free(inbuf.elements[i]); } for(size_t i = 0; i <= outbuf.mask; i++) { free(outbuf.elements[i]); } // TODO: The circular buffer should have a destructor free(inbuf.elements); free(outbuf.elements); } void UTP_FreeAll(struct UTPSocketHT *utp_sockets) { utp_hash_iterator_t it; UTPSocketKeyData *keyData; while((keyData = utp_sockets->Iterate(it))) { delete keyData->socket; } } void utp_initialize_socket(utp_socket *conn, const struct sockaddr *addr, socklen_t addrlen, bool need_seed_gen, uint32 conn_seed, uint32 conn_id_recv, uint32 conn_id_send) { PackedSockAddr psaddr = PackedSockAddr((const SOCKADDR_STORAGE *)addr, addrlen); if(need_seed_gen) { do { conn_seed = utp_call_get_random(conn->ctx, conn); // we identify v1 and higher by setting the first two bytes to 0x0001 conn_seed &= 0xffff; } while(conn->ctx->utp_sockets->Lookup(UTPSocketKey(psaddr, conn_seed))); conn_id_recv += conn_seed; conn_id_send += conn_seed; } conn->state = CS_IDLE; conn->conn_seed = conn_seed; conn->conn_id_recv = conn_id_recv; conn->conn_id_send = conn_id_send; conn->addr = psaddr; conn->ctx->current_ms = utp_call_get_milliseconds(conn->ctx, NULL); conn->last_got_packet = conn->ctx->current_ms; conn->last_sent_packet = conn->ctx->current_ms; conn->last_measured_delay = conn->ctx->current_ms + 0x70000000; conn->average_sample_time = conn->ctx->current_ms + 5000; conn->last_rwin_decay = conn->ctx->current_ms - MAX_WINDOW_DECAY; conn->our_hist.clear(conn->ctx->current_ms); conn->their_hist.clear(conn->ctx->current_ms); conn->rtt_hist.clear(conn->ctx->current_ms); // initialize MTU floor and ceiling conn->mtu_reset(); conn->mtu_last = conn->mtu_ceiling; conn->ctx->utp_sockets->Add(UTPSocketKey(conn->addr, conn->conn_id_recv)) ->socket = conn; // we need to fit one packet in the window when we start the connection conn->max_window = conn->get_packet_size(); #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "UTP socket initialized"); #endif } utp_socket * utp_create_socket(utp_context *ctx) { assert(ctx); if(!ctx) return NULL; UTPSocket *conn = new UTPSocket; // TODO: UTPSocket should have a constructor conn->state = CS_UNINITIALIZED; conn->ctx = ctx; conn->userdata = NULL; conn->reorder_count = 0; conn->duplicate_ack = 0; conn->timeout_seq_nr = 0; conn->last_rcv_win = 0; conn->got_fin = false; conn->got_fin_reached = false; conn->fin_sent = false; conn->fin_sent_acked = false; conn->read_shutdown = false; conn->close_requested = false; conn->fast_timeout = false; conn->rtt = 0; conn->retransmit_timeout = 0; conn->rto_timeout = 0; conn->zerowindow_time = 0; conn->average_delay = 0; conn->current_delay_samples = 0; conn->cur_window = 0; conn->eof_pkt = 0; conn->last_maxed_out_window = 0; conn->mtu_probe_seq = 0; conn->mtu_probe_size = 0; conn->current_delay_sum = 0; conn->average_delay_base = 0; conn->retransmit_count = 0; conn->rto = 3000; conn->rtt_var = 800; conn->seq_nr = 1; conn->ack_nr = 0; conn->max_window_user = 255 * PACKET_SIZE; conn->cur_window_packets = 0; conn->fast_resend_seq_nr = conn->seq_nr; conn->target_delay = ctx->target_delay; conn->reply_micro = 0; conn->opt_sndbuf = ctx->opt_sndbuf; conn->opt_rcvbuf = ctx->opt_rcvbuf; conn->slow_start = true; conn->ssthresh = conn->opt_sndbuf; conn->clock_drift = 0; conn->clock_drift_raw = 0; conn->outbuf.mask = 15; conn->inbuf.mask = 15; conn->outbuf.elements = (void **)calloc(16, sizeof(void *)); conn->inbuf.elements = (void **)calloc(16, sizeof(void *)); conn->ida = -1; // set the index of every new socket in ack_sockets to // -1, which also means it is not in ack_sockets yet memset(conn->extensions, 0, sizeof(conn->extensions)); #ifdef _DEBUG memset(&conn->_stats, 0, sizeof(utp_socket_stats)); #endif return conn; } int utp_context_set_option(utp_context *ctx, int opt, int val) { assert(ctx); if(!ctx) return -1; switch(opt) { case UTP_LOG_NORMAL: ctx->log_normal = val ? true : false; return 0; case UTP_LOG_MTU: ctx->log_mtu = val ? true : false; return 0; case UTP_LOG_DEBUG: ctx->log_debug = val ? true : false; return 0; case UTP_TARGET_DELAY: ctx->target_delay = val; return 0; case UTP_SNDBUF: assert(val >= 1); ctx->opt_sndbuf = val; return 0; case UTP_RCVBUF: assert(val >= 1); ctx->opt_rcvbuf = val; return 0; } return -1; } int utp_context_get_option(utp_context *ctx, int opt) { assert(ctx); if(!ctx) return -1; switch(opt) { case UTP_LOG_NORMAL: return ctx->log_normal ? 1 : 0; case UTP_LOG_MTU: return ctx->log_mtu ? 1 : 0; case UTP_LOG_DEBUG: return ctx->log_debug ? 1 : 0; case UTP_TARGET_DELAY: return ctx->target_delay; case UTP_SNDBUF: return ctx->opt_sndbuf; case UTP_RCVBUF: return ctx->opt_rcvbuf; } return -1; } int utp_setsockopt(UTPSocket *conn, int opt, int val) { assert(conn); if(!conn) return -1; switch(opt) { case UTP_SNDBUF: assert(val >= 1); conn->opt_sndbuf = val; return 0; case UTP_RCVBUF: assert(val >= 1); conn->opt_rcvbuf = val; return 0; case UTP_TARGET_DELAY: conn->target_delay = val; return 0; } return -1; } int utp_getsockopt(UTPSocket *conn, int opt) { assert(conn); if(!conn) return -1; switch(opt) { case UTP_SNDBUF: return conn->opt_sndbuf; case UTP_RCVBUF: return conn->opt_rcvbuf; case UTP_TARGET_DELAY: return conn->target_delay; } return -1; } // Try to connect to a specified host. int utp_connect(utp_socket *conn, const struct sockaddr *to, socklen_t tolen) { assert(conn); if(!conn) return -1; assert(conn->state == CS_UNINITIALIZED); if(conn->state != CS_UNINITIALIZED) { conn->state = CS_DESTROY; return -1; } utp_initialize_socket(conn, to, tolen, true, 0, 0, 1); assert(conn->cur_window_packets == 0); assert(conn->outbuf.get(conn->seq_nr) == NULL); assert(sizeof(PacketFormatV1) == 20); conn->state = CS_SYN_SENT; conn->ctx->current_ms = utp_call_get_milliseconds(conn->ctx, conn); // Create and send a connect message // used in parse_log.py conn->log(UTP_LOG_NORMAL, "UTP_Connect conn_seed:%u packet_size:%u (B) " "target_delay:%u (ms) delay_history:%u " "delay_base_history:%u (minutes)", conn->conn_seed, PACKET_SIZE, static_cast< unsigned int >(conn->target_delay / 1000), CUR_DELAY_SIZE, DELAY_BASE_HISTORY); // Setup initial timeout timer. conn->retransmit_timeout = 3000; conn->rto_timeout = conn->ctx->current_ms + conn->retransmit_timeout; conn->last_rcv_win = conn->get_rcv_window(); // if you need compatibiltiy with 1.8.1, use this. it increases attackability // though. // conn->seq_nr = 1; conn->seq_nr = utp_call_get_random(conn->ctx, conn); // Create the connect packet. const size_t header_size = sizeof(PacketFormatV1); OutgoingPacket *pkt = (OutgoingPacket *)malloc(sizeof(OutgoingPacket) - 1 + header_size); PacketFormatV1 *p1 = (PacketFormatV1 *)pkt->data; memset(p1, 0, header_size); // SYN packets are special, and have the receive ID in the connid field, // instead of conn_id_send. p1->set_version(1); p1->set_type(ST_SYN); p1->ext = 0; p1->connid = conn->conn_id_recv; p1->windowsize = (uint32)conn->last_rcv_win; p1->seq_nr = conn->seq_nr; pkt->transmissions = 0; pkt->length = header_size; pkt->payload = 0; /* #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Sending connect %s [%u].", addrfmt(conn->addr, addrbuf), conn_seed); #endif */ // Remember the message in the outgoing queue. conn->outbuf.ensure_size(conn->seq_nr, conn->cur_window_packets); conn->outbuf.put(conn->seq_nr, pkt); conn->seq_nr++; conn->cur_window_packets++; #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "incrementing cur_window_packets:%u", conn->cur_window_packets); #endif conn->send_packet(pkt); return 0; } // Returns 1 if the UDP payload was recognized as a UTP packet, or 0 if it was // not int utp_process_udp(utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen) { assert(ctx); if(!ctx) return 0; assert(buffer); if(!buffer) return 0; assert(to); if(!to) return 0; const PackedSockAddr addr((const SOCKADDR_STORAGE *)to, tolen); if(len < sizeof(PacketFormatV1)) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv %s len:%u too small", addrfmt(addr, addrbuf), (uint)len); #endif return 0; } const PacketFormatV1 *pf1 = (PacketFormatV1 *)buffer; const byte version = UTP_Version(pf1); const uint32 id = uint32(pf1->connid); if(version != 1) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv %s len:%u version:%u unsupported version", addrfmt(addr, addrbuf), (uint)len, version); #endif return 0; } #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv %s len:%u id:%u", addrfmt(addr, addrbuf), (uint)len, id); ctx->log(UTP_LOG_DEBUG, NULL, "recv id:%u seq_nr:%u ack_nr:%u", id, (uint)pf1->seq_nr, (uint)pf1->ack_nr); #endif const byte flags = pf1->type(); if(flags == ST_RESET) { // id is either our recv id or our send id // if it's our send id, and we initiated the connection, our recv id is id + // 1 if it's our send id, and we did not initiate the connection, our recv // id is id - 1 we have to check every case UTPSocketKeyData *keyData; if((keyData = ctx->utp_sockets->Lookup(UTPSocketKey(addr, id))) || ((keyData = ctx->utp_sockets->Lookup(UTPSocketKey(addr, id + 1))) && keyData->socket->conn_id_send == id) || ((keyData = ctx->utp_sockets->Lookup(UTPSocketKey(addr, id - 1))) && keyData->socket->conn_id_send == id)) { UTPSocket *conn = keyData->socket; #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv RST for existing connection"); #endif if(conn->close_requested) conn->state = CS_DESTROY; else conn->state = CS_RESET; utp_call_on_overhead_statistics(conn->ctx, conn, false, len + conn->get_udp_overhead(), close_overhead); const int err = (conn->state == CS_SYN_SENT) ? UTP_ECONNREFUSED : UTP_ECONNRESET; utp_call_on_error(conn->ctx, conn, err); } else { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv RST for unknown connection"); #endif } return 1; } else if(flags != ST_SYN) { UTPSocket *conn = NULL; if(ctx->last_utp_socket && ctx->last_utp_socket->addr == addr && ctx->last_utp_socket->conn_id_recv == id) { conn = ctx->last_utp_socket; } else { UTPSocketKeyData *keyData = ctx->utp_sockets->Lookup(UTPSocketKey(addr, id)); if(keyData) { conn = keyData->socket; ctx->last_utp_socket = conn; } } if(conn) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv processing"); #endif const size_t read = utp_process_incoming(conn, buffer, len); utp_call_on_overhead_statistics(conn->ctx, conn, false, (len - read) + conn->get_udp_overhead(), header_overhead); return 1; } } // We have not found a matching utp_socket, and this isn't a SYN. Reject it. const uint32 seq_nr = pf1->seq_nr; if(flags != ST_SYN) { ctx->current_ms = utp_call_get_milliseconds(ctx, NULL); for(size_t i = 0; i < ctx->rst_info.GetCount(); i++) { if((ctx->rst_info[i].connid == id) && (ctx->rst_info[i].addr == addr) && (ctx->rst_info[i].ack_nr == seq_nr)) { ctx->rst_info[i].timestamp = ctx->current_ms; #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv not sending RST to non-SYN (stored)"); #endif return 1; } } if(ctx->rst_info.GetCount() > RST_INFO_LIMIT) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv not sending RST to non-SYN (limit at %u stored)", (uint)ctx->rst_info.GetCount()); #endif return 1; } #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv send RST to non-SYN (%u stored)", (uint)ctx->rst_info.GetCount()); #endif RST_Info &r = ctx->rst_info.Append(); r.addr = addr; r.connid = id; r.ack_nr = seq_nr; r.timestamp = ctx->current_ms; UTPSocket::send_rst(ctx, addr, id, seq_nr, utp_call_get_random(ctx, NULL)); return 1; } if(ctx->callbacks[UTP_ON_ACCEPT]) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "Incoming connection from %s", addrfmt(addr, addrbuf)); #endif UTPSocketKeyData *keyData = ctx->utp_sockets->Lookup(UTPSocketKey(addr, id + 1)); if(keyData) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "rejected incoming connection, connection already exists"); #endif return 1; } /* if(ctx->utp_sockets->GetCount() > 3000) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "rejected incoming connection, too many uTP sockets %d", ctx->utp_sockets->GetCount()); #endif return 1; } */ // true means yes, block connection. false means no, don't block. if(utp_call_on_firewall(ctx, to, tolen)) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "rejected incoming connection, firewall callback returned true"); #endif return 1; } // Create a new UTP socket to handle this new connection UTPSocket *conn = utp_create_socket(ctx); utp_initialize_socket(conn, to, tolen, false, id, id + 1, id); conn->ack_nr = seq_nr; conn->seq_nr = utp_call_get_random(ctx, NULL); conn->fast_resend_seq_nr = conn->seq_nr; conn->state = CS_SYN_RECV; const size_t read = utp_process_incoming(conn, buffer, len, true); #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "recv send connect ACK"); #endif conn->send_ack(true); utp_call_on_accept(ctx, conn, to, tolen); // we report overhead after on_accept(), because the callbacks are setup now utp_call_on_overhead_statistics(conn->ctx, conn, false, (len - read) + conn->get_udp_overhead(), header_overhead); // SYN utp_call_on_overhead_statistics(conn->ctx, conn, true, conn->get_overhead(), ack_overhead); // SYNACK } else { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "rejected incoming connection, UTP_ON_ACCEPT callback not set"); #endif } return 1; } // Called by utp_process_icmp_fragmentation() and utp_process_icmp_error() below static UTPSocket * parse_icmp_payload(utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen) { assert(ctx); if(!ctx) return NULL; assert(buffer); if(!buffer) return NULL; assert(to); if(!to) return NULL; const PackedSockAddr addr((const SOCKADDR_STORAGE *)to, tolen); // ICMP packets are only required to quote the first 8 bytes of the layer4 // payload. The UDP payload is 8 bytes, and the UTP header is another 20 // bytes. So, in order to find the entire UTP header, we need the ICMP // packet to quote 28 bytes. if(len < sizeof(PacketFormatV1)) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "Ignoring ICMP from %s: runt length %d", addrfmt(addr, addrbuf), len); #endif return NULL; } const PacketFormatV1 *pf = (PacketFormatV1 *)buffer; const byte version = UTP_Version(pf); const uint32 id = uint32(pf->connid); if(version != 1) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "Ignoring ICMP from %s: not UTP version 1", addrfmt(addr, addrbuf)); #endif return NULL; } UTPSocketKeyData *keyData; if((keyData = ctx->utp_sockets->Lookup(UTPSocketKey(addr, id))) || ((keyData = ctx->utp_sockets->Lookup(UTPSocketKey(addr, id + 1))) && keyData->socket->conn_id_send == id) || ((keyData = ctx->utp_sockets->Lookup(UTPSocketKey(addr, id - 1))) && keyData->socket->conn_id_send == id)) { return keyData->socket; } #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "Ignoring ICMP from %s: No matching connection found for id %u", addrfmt(addr, addrbuf), id); #endif return NULL; } // Should be called when an ICMP Type 3, Code 4 packet (fragmentation needed) is // received, to adjust the MTU // // Returns 1 if the UDP payload (delivered in the ICMP packet) was recognized as // a UTP packet, or 0 if it was not // // @ctx: utp_context // @buf: Contents of the original UDP payload, which the ICMP packet quoted. // *Not* the ICMP packet itself. // @len: buffer length // @to: destination address of the original UDP pakcet // @tolen: address length // @next_hop_mtu: int utp_process_icmp_fragmentation(utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen, uint16 next_hop_mtu) { UTPSocket *conn = parse_icmp_payload(ctx, buffer, len, to, tolen); if(!conn) return 0; // Constrain the next_hop_mtu to sane values. It might not be initialized or // sent properly if(next_hop_mtu >= 576 && next_hop_mtu < 0x2000) { conn->mtu_ceiling = min< uint32 >(next_hop_mtu, conn->mtu_ceiling); conn->mtu_search_update(); // this is something of a speecial case, where we don't set mtu_last // to the value in between the floor and the ceiling. We can update the // floor, because there might be more network segments after the one // that sent this ICMP with smaller MTUs. But we want to test this // MTU size first. If the next probe gets through, mtu_floor is updated conn->mtu_last = conn->mtu_ceiling; } else { // Otherwise, binary search. At this point we don't actually know // what size the packet that failed was, and apparently we can't // trust the next hop mtu either. It seems reasonably conservative // to just lower the ceiling. This should not happen on working networks // anyway. conn->mtu_ceiling = (conn->mtu_floor + conn->mtu_ceiling) / 2; conn->mtu_search_update(); } conn->log(UTP_LOG_MTU, "MTU [ICMP] floor:%d ceiling:%d current:%d", conn->mtu_floor, conn->mtu_ceiling, conn->mtu_last); return 1; } // Should be called when an ICMP message is received that should tear down the // connection. // // Returns 1 if the UDP payload (delivered in the ICMP packet) was recognized as // a UTP packet, or 0 if it was not // // @ctx: utp_context // @buf: Contents of the original UDP payload, which the ICMP packet quoted. // *Not* the ICMP packet itself. // @len: buffer length // @to: destination address of the original UDP pakcet // @tolen: address length int utp_process_icmp_error(utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen) { UTPSocket *conn = parse_icmp_payload(ctx, buffer, len, to, tolen); if(!conn) return 0; const int err = (conn->state == CS_SYN_SENT) ? UTP_ECONNREFUSED : UTP_ECONNRESET; const PackedSockAddr addr((const SOCKADDR_STORAGE *)to, tolen); switch(conn->state) { // Don't pass on errors for idle/closed connections case CS_IDLE: #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "ICMP from %s in state CS_IDLE, ignoring", addrfmt(addr, addrbuf)); #endif return 1; default: if(conn->close_requested) { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "ICMP from %s after close, setting state to CS_DESTROY and " "causing error %d", addrfmt(addr, addrbuf), err); #endif conn->state = CS_DESTROY; } else { #if UTP_DEBUG_LOGGING ctx->log(UTP_LOG_DEBUG, NULL, "ICMP from %s, setting state to CS_RESET and causing error %d", addrfmt(addr, addrbuf), err); #endif conn->state = CS_RESET; } break; } utp_call_on_error(conn->ctx, conn, err); return 1; } // Write bytes to the UTP socket. Returns the number of bytes written. // 0 indicates the socket is no longer writable, -1 indicates an error ssize_t utp_writev(utp_socket *conn, struct utp_iovec *iovec_input, size_t num_iovecs) { static utp_iovec iovec[UTP_IOV_MAX]; assert(conn); if(!conn) return -1; assert(iovec_input); if(!iovec_input) return -1; assert(num_iovecs); if(!num_iovecs) return -1; if(num_iovecs > UTP_IOV_MAX) num_iovecs = UTP_IOV_MAX; memcpy(iovec, iovec_input, sizeof(struct utp_iovec) * num_iovecs); size_t bytes = 0; size_t sent = 0; for(size_t i = 0; i < num_iovecs; i++) bytes += iovec[i].iov_len; #if UTP_DEBUG_LOGGING size_t param = bytes; #endif if(conn->state != CS_CONNECTED) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "UTP_Write %u bytes = false (not CS_CONNECTED)", (uint)bytes); #endif return 0; } if(conn->fin_sent) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "UTP_Write %u bytes = false (fin_sent already)", (uint)bytes); #endif return 0; } conn->ctx->current_ms = utp_call_get_milliseconds(conn->ctx, conn); // don't send unless it will all fit in the window size_t packet_size = conn->get_packet_size(); size_t num_to_send = min< size_t >(bytes, packet_size); while(!conn->is_full(num_to_send)) { // Send an outgoing packet. // Also add it to the outgoing of packets that have been sent but not ACKed. bytes -= num_to_send; sent += num_to_send; #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Sending packet. seq_nr:%u ack_nr:%u wnd:%u/%u/%u rcv_win:%u " "size:%u cur_window_packets:%u", conn->seq_nr, conn->ack_nr, (uint)(conn->cur_window + num_to_send), (uint)conn->max_window, (uint)conn->max_window_user, (uint)conn->last_rcv_win, num_to_send, conn->cur_window_packets); #endif conn->write_outgoing_packet(num_to_send, ST_DATA, iovec, num_iovecs); num_to_send = min< size_t >(bytes, packet_size); if(num_to_send == 0) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "UTP_Write %u bytes = true", (uint)param); #endif return sent; } } bool full = conn->is_full(); if(full) { // mark the socket as not being writable. conn->state = CS_CONNECTED_FULL; } #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "UTP_Write %u bytes = %s", (uint)bytes, full ? "false" : "true"); #endif // returns whether or not the socket is still writable // if the congestion window is not full, we can still write to it // return !full; return sent; } void utp_read_drained(utp_socket *conn) { assert(conn); if(!conn) return; assert(conn->state != CS_UNINITIALIZED); if(conn->state == CS_UNINITIALIZED) return; const size_t rcvwin = conn->get_rcv_window(); if(rcvwin > conn->last_rcv_win) { // If last window was 0 send ACK immediately, otherwise should set timer if(conn->last_rcv_win == 0) { conn->send_ack(); } else { conn->ctx->current_ms = utp_call_get_milliseconds(conn->ctx, conn); conn->schedule_ack(); } } } // Should be called each time the UDP socket is drained void utp_issue_deferred_acks(utp_context *ctx) { assert(ctx); if(!ctx) return; for(size_t i = 0; i < ctx->ack_sockets.GetCount(); i++) { UTPSocket *conn = ctx->ack_sockets[i]; conn->send_ack(); i--; } } // Should be called every 500ms void utp_check_timeouts(utp_context *ctx) { assert(ctx); if(!ctx) return; ctx->current_ms = utp_call_get_milliseconds(ctx, NULL); if(ctx->current_ms - ctx->last_check < TIMEOUT_CHECK_INTERVAL) return; ctx->last_check = ctx->current_ms; for(size_t i = 0; i < ctx->rst_info.GetCount(); i++) { if((int)(ctx->current_ms - ctx->rst_info[i].timestamp) >= RST_INFO_TIMEOUT) { ctx->rst_info.MoveUpLast(i); i--; } } if(ctx->rst_info.GetCount() != ctx->rst_info.GetAlloc()) { ctx->rst_info.Compact(); } utp_hash_iterator_t it; UTPSocketKeyData *keyData; while((keyData = ctx->utp_sockets->Iterate(it))) { UTPSocket *conn = keyData->socket; conn->check_timeouts(); // Check if the object was deleted if(conn->state == CS_DESTROY) { #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "Destroying"); #endif delete conn; } } } int utp_getpeername(utp_socket *conn, struct sockaddr *addr, socklen_t *addrlen) { assert(addr); if(!addr) return -1; assert(addrlen); if(!addrlen) return -1; assert(conn); if(!conn) return -1; assert(conn->state != CS_UNINITIALIZED); if(conn->state == CS_UNINITIALIZED) return -1; socklen_t len; const SOCKADDR_STORAGE sa = conn->addr.get_sockaddr_storage(&len); *addrlen = min(len, *addrlen); memcpy(addr, &sa, *addrlen); return 0; } int utp_get_delays(UTPSocket *conn, uint32 *ours, uint32 *theirs, uint32 *age) { assert(conn); if(!conn) return -1; assert(conn->state != CS_UNINITIALIZED); if(conn->state == CS_UNINITIALIZED) { if(ours) *ours = 0; if(theirs) *theirs = 0; if(age) *age = 0; return -1; } if(ours) *ours = conn->our_hist.get_value(); if(theirs) *theirs = conn->their_hist.get_value(); if(age) *age = (uint32)(conn->ctx->current_ms - conn->last_measured_delay); return 0; } // Close the UTP socket. // It is not valid for the upper layer to refer to socket after it is closed. // Data will keep to try being delivered after the close. void utp_close(UTPSocket *conn) { assert(conn); if(!conn) return; assert(conn->state != CS_UNINITIALIZED && conn->state != CS_DESTROY); #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "UTP_Close in state:%s", statenames[conn->state]); #endif switch(conn->state) { case CS_CONNECTED: case CS_CONNECTED_FULL: conn->read_shutdown = true; conn->close_requested = true; if(!conn->fin_sent) { conn->fin_sent = true; conn->write_outgoing_packet(0, ST_FIN, NULL, 0); } else if(conn->fin_sent_acked) { conn->state = CS_DESTROY; } break; case CS_SYN_SENT: conn->rto_timeout = utp_call_get_milliseconds(conn->ctx, conn) + min< uint >(conn->rto * 2, 60); // fall through case CS_SYN_RECV: // fall through default: conn->state = CS_DESTROY; break; } #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "UTP_Close end in state:%s", statenames[conn->state]); #endif } void utp_shutdown(UTPSocket *conn, int how) { assert(conn); if(!conn) return; assert(conn->state != CS_UNINITIALIZED && conn->state != CS_DESTROY); #if UTP_DEBUG_LOGGING conn->log(UTP_LOG_DEBUG, "UTP_shutdown(%d) in state:%s", how, statenames[conn->state]); #endif if(how != SHUT_WR) { conn->read_shutdown = true; } if(how != SHUT_RD) { switch(conn->state) { case CS_CONNECTED: case CS_CONNECTED_FULL: if(!conn->fin_sent) { conn->fin_sent = true; conn->write_outgoing_packet(0, ST_FIN, NULL, 0); } break; case CS_SYN_SENT: conn->rto_timeout = utp_call_get_milliseconds(conn->ctx, conn) + min< uint >(conn->rto * 2, 60); default: break; } } } utp_context * utp_get_context(utp_socket *socket) { assert(socket); return socket ? socket->ctx : NULL; } void * utp_set_userdata(utp_socket *socket, void *userdata) { assert(socket); if(socket) socket->userdata = userdata; return socket ? socket->userdata : NULL; } void * utp_get_userdata(utp_socket *socket) { assert(socket); return socket ? socket->userdata : NULL; } void struct_utp_context::log(int level, utp_socket *socket, char const *fmt, ...) { if(!would_log(level)) { return; } va_list va; va_start(va, fmt); log_unchecked(socket, fmt, va); va_end(va); } void struct_utp_context::log_unchecked(utp_socket *socket, char const *fmt, ...) { va_list va; char buf[4096]; va_start(va, fmt); vsnprintf(buf, 4096, fmt, va); buf[4095] = '\0'; va_end(va); utp_call_log(this, socket, (const byte *)buf); } inline bool struct_utp_context::would_log(int level) { if(level == UTP_LOG_NORMAL) return log_normal; if(level == UTP_LOG_MTU) return log_mtu; if(level == UTP_LOG_DEBUG) return log_debug; return true; } utp_socket_stats * utp_get_stats(utp_socket *socket) { #ifdef _DEBUG assert(socket); if(!socket) return NULL; socket->_stats.mtu_guess = socket->mtu_last ? socket->mtu_last : socket->mtu_ceiling; return &socket->_stats; #else (void)socket; return NULL; #endif }