]> git.lizzy.rs Git - minetest.git/blobdiff - src/connection.cpp
refactor main.cpp
[minetest.git] / src / connection.cpp
index ee03b2113ffc60959ed87a37fc0c93df6d2bbab4..64ef9a50e42f9638008adeb0f9273190212068f8 100644 (file)
@@ -34,6 +34,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 namespace con
 {
 
+/******************************************************************************/
+/* defines used for debugging and profiling                                   */
+/******************************************************************************/
+#ifdef NDEBUG
+#define LOG(a) a
+#define PROFILE(a)
+#undef DEBUG_CONNECTION_KBPS
+#else
 /* this mutex is used to achieve log message consistency */
 JMutex log_message_mutex;
 #define LOG(a)                                                                 \
@@ -41,15 +49,10 @@ JMutex log_message_mutex;
        JMutexAutoLock loglock(log_message_mutex);                                 \
        a;                                                                         \
        }
-
-/******************************************************************************/
-/* defines used for debugging and profiling                                   */
-/******************************************************************************/
 #define PROFILE(a) a
-//#define PROFILE(a)
-
 //#define DEBUG_CONNECTION_KBPS
 #undef DEBUG_CONNECTION_KBPS
+#endif
 
 
 static inline float CALC_DTIME(unsigned int lasttime, unsigned int curtime) {
@@ -108,10 +111,10 @@ SharedBuffer<u8> makeOriginalPacket(
        u32 packet_size = data.getSize() + header_size;
        SharedBuffer<u8> b(packet_size);
 
-       writeU8(&b[0], TYPE_ORIGINAL);
-
-       memcpy(&b[header_size], *data, data.getSize());
-
+       writeU8(&(b[0]), TYPE_ORIGINAL);
+       if (data.getSize() > 0) {
+               memcpy(&(b[header_size]), *data, data.getSize());
+       }
        return b;
 }
 
@@ -122,7 +125,7 @@ std::list<SharedBuffer<u8> > makeSplitPacket(
 {
        // Chunk packets, containing the TYPE_SPLIT header
        std::list<SharedBuffer<u8> > chunks;
-       
+
        u32 chunk_header_size = 7;
        u32 maximum_data_size = chunksize_max - chunk_header_size;
        u32 start = 0;
@@ -133,12 +136,12 @@ std::list<SharedBuffer<u8> > makeSplitPacket(
                end = start + maximum_data_size - 1;
                if(end > data.getSize() - 1)
                        end = data.getSize() - 1;
-               
+
                u32 payload_size = end - start + 1;
                u32 packet_size = chunk_header_size + payload_size;
 
                SharedBuffer<u8> chunk(packet_size);
-               
+
                writeU8(&chunk[0], TYPE_SPLIT);
                writeU16(&chunk[1], seqnum);
                // [3] u16 chunk_count is written at next stage
@@ -147,7 +150,7 @@ std::list<SharedBuffer<u8> > makeSplitPacket(
 
                chunks.push_back(chunk);
                chunk_count++;
-               
+
                start = end + 1;
                chunk_num++;
        }
@@ -187,9 +190,6 @@ SharedBuffer<u8> makeReliablePacket(
                SharedBuffer<u8> data,
                u16 seqnum)
 {
-       /*dstream<<"BEGIN SharedBuffer<u8> makeReliablePacket()"<<std::endl;
-       dstream<<"data.getSize()="<<data.getSize()<<", data[0]="
-                       <<((unsigned int)data[0]&0xff)<<std::endl;*/
        u32 header_size = 3;
        u32 packet_size = data.getSize() + header_size;
        SharedBuffer<u8> b(packet_size);
@@ -199,9 +199,6 @@ SharedBuffer<u8> makeReliablePacket(
 
        memcpy(&b[header_size], *data, data.getSize());
 
-       /*dstream<<"data.getSize()="<<data.getSize()<<", data[0]="
-                       <<((unsigned int)data[0]&0xff)<<std::endl;*/
-       //dstream<<"END SharedBuffer<u8> makeReliablePacket()"<<std::endl;
        return b;
 }
 
@@ -209,7 +206,7 @@ SharedBuffer<u8> makeReliablePacket(
        ReliablePacketBuffer
 */
 
-ReliablePacketBuffer::ReliablePacketBuffer(): m_list_size(0),writeptr(0) {}
+ReliablePacketBuffer::ReliablePacketBuffer(): m_list_size(0) {}
 
 void ReliablePacketBuffer::print()
 {
@@ -277,10 +274,12 @@ BufferedPacket ReliablePacketBuffer::popFirst()
        m_list.erase(m_list.begin());
        --m_list_size;
 
-       if (m_list_size == 0)
-       { m_oldest_non_answered_ack = 0; }
-       else
-       { m_oldest_non_answered_ack = readU16(&(*m_list.begin()).data[BASE_HEADER_SIZE+1]);     }
+       if (m_list_size == 0) {
+               m_oldest_non_answered_ack = 0;
+       } else {
+               m_oldest_non_answered_ack =
+                               readU16(&(*m_list.begin()).data[BASE_HEADER_SIZE+1]);
+       }
        return p;
 }
 BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
@@ -288,7 +287,8 @@ BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
        JMutexAutoLock listlock(m_list_mutex);
        RPBSearchResult r = findPacket(seqnum);
        if(r == notFound()){
-               LOG(dout_con<<"Sequence number: " << seqnum << " not found in reliable buffer"<<std::endl);
+               LOG(dout_con<<"Sequence number: " << seqnum
+                               << " not found in reliable buffer"<<std::endl);
                throw NotFoundException("seqnum not found in buffer");
        }
        BufferedPacket p = *r;
@@ -366,11 +366,15 @@ void ReliablePacketBuffer::insert(BufferedPacket &p,u16 next_expected)
                        )
                {
                        /* if this happens your maximum transfer window may be to big */
-                       fprintf(stderr, "Duplicated seqnum %d non matching packet detected:\n",seqnum);
+                       fprintf(stderr,
+                                       "Duplicated seqnum %d non matching packet detected:\n",
+                                       seqnum);
                        fprintf(stderr, "Old: seqnum: %05d size: %04d, address: %s\n",
-                                       readU16(&(i->data[BASE_HEADER_SIZE+1])),i->data.getSize(), i->address.serializeString().c_str());
+                                       readU16(&(i->data[BASE_HEADER_SIZE+1])),i->data.getSize(),
+                                       i->address.serializeString().c_str());
                        fprintf(stderr, "New: seqnum: %05d size: %04d, address: %s\n",
-                                       readU16(&(p.data[BASE_HEADER_SIZE+1])),p.data.getSize(), p.address.serializeString().c_str());
+                                       readU16(&(p.data[BASE_HEADER_SIZE+1])),p.data.getSize(),
+                                       p.address.serializeString().c_str());
                        throw IncomingDataCorruption("duplicated packet isn't same as original one");
                }
 
@@ -461,9 +465,9 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
                sp->reliable = reliable;
                m_buf[seqnum] = sp;
        }
-       
+
        IncomingSplitPacket *sp = m_buf[seqnum];
-       
+
        // TODO: These errors should be thrown or something? Dunno.
        if(chunk_count != sp->chunk_count)
                LOG(derr_con<<"Connection: WARNING: chunk_count="<<chunk_count
@@ -479,15 +483,15 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
        // lag and the server re-sends stuff.
        if(sp->chunks.find(chunk_num) != sp->chunks.end())
                return SharedBuffer<u8>();
-       
+
        // Cut chunk data out of packet
        u32 chunkdatasize = p.data.getSize() - headersize;
        SharedBuffer<u8> chunkdata(chunkdatasize);
        memcpy(*chunkdata, &(p.data[headersize]), chunkdatasize);
-       
+
        // Set chunk data in buffer
        sp->chunks[chunk_num] = chunkdata;
-       
+
        // If not all chunks are received, return empty buffer
        if(sp->allReceived() == false)
                return SharedBuffer<u8>();
@@ -499,7 +503,7 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
        {
                totalsize += i->second.getSize();
        }
-       
+
        SharedBuffer<u8> fulldata(totalsize);
 
        // Copy chunks to data buffer
@@ -557,16 +561,22 @@ Channel::Channel() :
                next_outgoing_split_seqnum(SEQNUM_INITIAL),
                current_packet_loss(0),
                current_packet_too_late(0),
+               current_packet_successfull(0),
                packet_loss_counter(0),
                current_bytes_transfered(0),
+               current_bytes_received(0),
                current_bytes_lost(0),
                max_kbps(0.0),
                cur_kbps(0.0),
                avg_kbps(0.0),
+               max_incoming_kbps(0.0),
+               cur_incoming_kbps(0.0),
+               avg_incoming_kbps(0.0),
                max_kbps_lost(0.0),
                cur_kbps_lost(0.0),
                avg_kbps_lost(0.0),
-               bpm_counter(0.0)
+               bpm_counter(0.0),
+               rate_samples(0)
 {
 }
 
@@ -662,6 +672,11 @@ void Channel::UpdateBytesSent(unsigned int bytes, unsigned int packets)
        current_packet_successfull += packets;
 }
 
+void Channel::UpdateBytesReceived(unsigned int bytes) {
+       JMutexAutoLock internal(m_internal_mutex);
+       current_bytes_received += bytes;
+}
+
 void Channel::UpdateBytesLost(unsigned int bytes)
 {
        JMutexAutoLock internal(m_internal_mutex);
@@ -681,7 +696,7 @@ void Channel::UpdatePacketTooLateCounter()
        current_packet_too_late++;
 }
 
-void Channel::UpdateTimers(float dtime)
+void Channel::UpdateTimers(float dtime,bool legacy_peer)
 {
        bpm_counter += dtime;
        packet_loss_counter += dtime;
@@ -702,7 +717,7 @@ void Channel::UpdateTimers(float dtime)
                        packet_too_late = current_packet_too_late;
                        packets_successfull = current_packet_successfull;
 
-                       if (current_bytes_transfered > (window_size*512/2))
+                       if (current_bytes_transfered > (unsigned int) (window_size*512/2))
                        {
                                reasonable_amount_of_data_transmitted = true;
                        }
@@ -711,53 +726,56 @@ void Channel::UpdateTimers(float dtime)
                        current_packet_successfull = 0;
                }
 
-               float successfull_to_lost_ratio = 0.0;
-               bool done = false;
-
-               if (packets_successfull > 0) {
-                       successfull_to_lost_ratio = packet_loss/packets_successfull;
-               }
-               else if (packet_loss > 0)
-               {
-                       window_size = MYMAX(
-                                                                               (window_size - 10),
-                                                                               MIN_RELIABLE_WINDOW_SIZE);
-                       done = true;
-               }
+               /* dynamic window size is only available for non legacy peers */
+               if (!legacy_peer) {
+                       float successfull_to_lost_ratio = 0.0;
+                       bool done = false;
 
-               if (!done)
-               {
-                       if ((successfull_to_lost_ratio < 0.01) &&
-                               (window_size < MAX_RELIABLE_WINDOW_SIZE))
-                       {
-                               /* don't even think about increasing if we didn't even
-                                * use major parts of our window */
-                               if (reasonable_amount_of_data_transmitted)
-                                       window_size = MYMIN(
-                                                                                       (window_size + 100),
-                                                                                       MAX_RELIABLE_WINDOW_SIZE);
-                       }
-                       else if ((successfull_to_lost_ratio < 0.05) &&
-                                       (window_size < MAX_RELIABLE_WINDOW_SIZE))
-                       {
-                               /* don't even think about increasing if we didn't even
-                                * use major parts of our window */
-                               if (reasonable_amount_of_data_transmitted)
-                                       window_size = MYMIN(
-                                                                                       (window_size + 50),
-                                                                                       MAX_RELIABLE_WINDOW_SIZE);
+                       if (packets_successfull > 0) {
+                               successfull_to_lost_ratio = packet_loss/packets_successfull;
                        }
-                       else if (successfull_to_lost_ratio > 0.15)
+                       else if (packet_loss > 0)
                        {
                                window_size = MYMAX(
-                                                                                       (window_size - 100),
-                                                                                       MIN_RELIABLE_WINDOW_SIZE);
+                                               (window_size - 10),
+                                               MIN_RELIABLE_WINDOW_SIZE);
+                               done = true;
                        }
-                       else if (successfull_to_lost_ratio > 0.1)
+
+                       if (!done)
                        {
-                               window_size = MYMAX(
-                                                                                       (window_size - 50),
-                                                                                       MIN_RELIABLE_WINDOW_SIZE);
+                               if ((successfull_to_lost_ratio < 0.01) &&
+                                       (window_size < MAX_RELIABLE_WINDOW_SIZE))
+                               {
+                                       /* don't even think about increasing if we didn't even
+                                        * use major parts of our window */
+                                       if (reasonable_amount_of_data_transmitted)
+                                               window_size = MYMIN(
+                                                               (window_size + 100),
+                                                               MAX_RELIABLE_WINDOW_SIZE);
+                               }
+                               else if ((successfull_to_lost_ratio < 0.05) &&
+                                               (window_size < MAX_RELIABLE_WINDOW_SIZE))
+                               {
+                                       /* don't even think about increasing if we didn't even
+                                        * use major parts of our window */
+                                       if (reasonable_amount_of_data_transmitted)
+                                               window_size = MYMIN(
+                                                               (window_size + 50),
+                                                               MAX_RELIABLE_WINDOW_SIZE);
+                               }
+                               else if (successfull_to_lost_ratio > 0.15)
+                               {
+                                       window_size = MYMAX(
+                                                       (window_size - 100),
+                                                       MIN_RELIABLE_WINDOW_SIZE);
+                               }
+                               else if (successfull_to_lost_ratio > 0.1)
+                               {
+                                       window_size = MYMAX(
+                                                       (window_size - 50),
+                                                       MIN_RELIABLE_WINDOW_SIZE);
+                               }
                        }
                }
        }
@@ -766,11 +784,16 @@ void Channel::UpdateTimers(float dtime)
        {
                {
                        JMutexAutoLock internal(m_internal_mutex);
-                       cur_kbps = (current_bytes_transfered/bpm_counter)/1024;
+                       cur_kbps                 =
+                                       (((float) current_bytes_transfered)/bpm_counter)/1024.0;
                        current_bytes_transfered = 0;
-                       cur_kbps_lost = (current_bytes_lost/bpm_counter)/1024;
-                       current_bytes_lost = 0;
-                       bpm_counter = 0;
+                       cur_kbps_lost            =
+                                       (((float) current_bytes_lost)/bpm_counter)/1024.0;
+                       current_bytes_lost       = 0;
+                       cur_incoming_kbps        =
+                                       (((float) current_bytes_received)/bpm_counter)/1024.0;
+                       current_bytes_received   = 0;
+                       bpm_counter              = 0;
                }
 
                if (cur_kbps > max_kbps)
@@ -783,8 +806,18 @@ void Channel::UpdateTimers(float dtime)
                        max_kbps_lost = cur_kbps_lost;
                }
 
-               avg_kbps = avg_kbps * 0.9 + cur_kbps * 0.1;
-               avg_kbps_lost = avg_kbps_lost * 0.9 + cur_kbps_lost * 0.1;
+               if (cur_incoming_kbps > max_incoming_kbps) {
+                       max_incoming_kbps = cur_incoming_kbps;
+               }
+
+               rate_samples       = MYMIN(rate_samples+1,10);
+               float old_fraction = ((float) (rate_samples-1) )/( (float) rate_samples);
+               avg_kbps           = avg_kbps * old_fraction +
+                               cur_kbps * (1.0 - old_fraction);
+               avg_kbps_lost      = avg_kbps_lost * old_fraction +
+                               cur_kbps_lost * (1.0 - old_fraction);
+               avg_incoming_kbps  = avg_incoming_kbps * old_fraction +
+                               cur_incoming_kbps * (1.0 - old_fraction);
        }
 }
 
@@ -795,8 +828,7 @@ void Channel::UpdateTimers(float dtime)
 
 PeerHelper::PeerHelper() :
        m_peer(0)
-{
-}
+{}
 
 PeerHelper::PeerHelper(Peer* peer) :
        m_peer(peer)
@@ -876,9 +908,8 @@ void Peer::DecUseCount()
        delete this;
 }
 
-void Peer::RTTStatistics(float rtt,
-                                               std::string profiler_id,
-                                               unsigned int num_samples) {
+void Peer::RTTStatistics(float rtt, std::string profiler_id,
+               unsigned int num_samples) {
 
        if (m_last_rtt > 0) {
                /* set min max values */
@@ -949,10 +980,12 @@ void Peer::Drop()
        }
 
        PROFILE(std::stringstream peerIdentifier1);
-       PROFILE(peerIdentifier1 << "runTimeouts[" << m_connection->getDesc() << ";" << id << ";RELIABLE]");
+       PROFILE(peerIdentifier1 << "runTimeouts[" << m_connection->getDesc()
+                       << ";" << id << ";RELIABLE]");
        PROFILE(g_profiler->remove(peerIdentifier1.str()));
        PROFILE(std::stringstream peerIdentifier2);
-       PROFILE(peerIdentifier2 << "sendPackets[" << m_connection->getDesc() << ";" << id << ";RELIABLE]");
+       PROFILE(peerIdentifier2 << "sendPackets[" << m_connection->getDesc()
+                       << ";" << id << ";RELIABLE]");
        PROFILE(ScopeProfiler peerprofiler(g_profiler, peerIdentifier2.str(), SPT_AVG));
 
        delete this;
@@ -960,18 +993,15 @@ void Peer::Drop()
 
 UDPPeer::UDPPeer(u16 a_id, Address a_address, Connection* connection) :
        Peer(a_address,a_id,connection),
+       m_pending_disconnect(false),
        resend_timeout(0.5),
        m_legacy_peer(true)
 {
 }
 
-UDPPeer::~UDPPeer()
-{
-}
-
 bool UDPPeer::getAddress(MTProtocols type,Address& toset)
 {
-       if ((type == UDP) || (type == MINETEST_RELIABLE_UDP) || (type == PRIMARY))
+       if ((type == MTP_UDP) || (type == MTP_MINETEST_RELIABLE_UDP) || (type == MTP_PRIMARY))
        {
                toset = address;
                return true;
@@ -980,6 +1010,15 @@ bool UDPPeer::getAddress(MTProtocols type,Address& toset)
        return false;
 }
 
+void UDPPeer::setNonLegacyPeer()
+{
+       m_legacy_peer = false;
+       for(unsigned int i=0; i< CHANNEL_COUNT; i++)
+       {
+               channels->setWindowSize(g_settings->getU16("max_packets_per_iteration"));
+       }
+}
+
 void UDPPeer::reportRTT(float rtt)
 {
        if (rtt < 0.0) {
@@ -1014,6 +1053,9 @@ bool UDPPeer::Ping(float dtime,SharedBuffer<u8>& data)
 void UDPPeer::PutReliableSendCommand(ConnectionCommand &c,
                unsigned int max_packet_size)
 {
+       if (m_pending_disconnect)
+               return;
+
        if ( channels[c.channelnum].queued_commands.empty() &&
                        /* don't queue more packets then window size */
                        (channels[c.channelnum].queued_reliables.size()
@@ -1040,6 +1082,9 @@ bool UDPPeer::processReliableSendCommand(
                                ConnectionCommand &c,
                                unsigned int max_packet_size)
 {
+       if (m_pending_disconnect)
+               return true;
+
        u32 chunksize_max = max_packet_size
                                                        - BASE_HEADER_SIZE
                                                        - RELIABLE_HEADER_SIZE;
@@ -1121,10 +1166,14 @@ bool UDPPeer::processReliableSendCommand(
                        assert(successfully_put_back_sequence_number);
                }
                LOG(dout_con<<m_connection->getDesc()
-                               << " Windowsize exceeded on reliable sending " << c.data.getSize() << " bytes"
-                               << std::endl << "\t\tinitial_sequence_number: " << initial_sequence_number
-                               << std::endl << "\t\tgot at most            : " << packets_available << " packets"
-                               << std::endl << "\t\tpackets queued         : " << channels[c.channelnum].outgoing_reliables_sent.size()
+                               << " Windowsize exceeded on reliable sending "
+                               << c.data.getSize() << " bytes"
+                               << std::endl << "\t\tinitial_sequence_number: "
+                               << initial_sequence_number
+                               << std::endl << "\t\tgot at most            : "
+                               << packets_available << " packets"
+                               << std::endl << "\t\tpackets queued         : "
+                               << channels[c.channelnum].outgoing_reliables_sent.size()
                                << std::endl);
                return false;
        }
@@ -1151,11 +1200,12 @@ void UDPPeer::RunCommandQueues(
                                if (!processReliableSendCommand(c,max_packet_size)) {
                                        LOG(dout_con<<m_connection->getDesc()
                                                        << " Failed to queue packets for peer_id: " << c.peer_id
-                                                       << ", delaying sending of " << c.data.getSize() << " bytes" << std::endl);
+                                                       << ", delaying sending of " << c.data.getSize()
+                                                       << " bytes" << std::endl);
                                        channels[i].queued_commands.push_front(c);
                                }
                        }
-                       catch (ItemNotFoundException e) {
+                       catch (ItemNotFoundException &e) {
                                // intentionally empty
                        }
                }
@@ -1212,6 +1262,8 @@ void * ConnectionSendThread::Thread()
        PROFILE(std::stringstream ThreadIdentifier);
        PROFILE(ThreadIdentifier << "ConnectionSend: [" << m_connection->getDesc() << "]");
 
+       porting::setThreadName("ConnectionSend");
+
        /* if stop is requested don't stop immediately but try to send all        */
        /* packets first */
        while(!StopRequested() || packetsQueued()) {
@@ -1248,7 +1300,7 @@ void * ConnectionSendThread::Thread()
                /* send non reliable packets */
                sendPackets(dtime);
 
-               END_DEBUG_EXCEPTION_HANDLER(derr_con);
+               END_DEBUG_EXCEPTION_HANDLER(errorstream);
        }
 
        PROFILE(g_profiler->remove(ThreadIdentifier.str()));
@@ -1310,7 +1362,8 @@ void ConnectionSendThread::runTimeouts(float dtime)
                        continue;
 
                PROFILE(std::stringstream peerIdentifier);
-               PROFILE(peerIdentifier << "runTimeouts[" << m_connection->getDesc() << ";" << *j << ";RELIABLE]");
+               PROFILE(peerIdentifier << "runTimeouts[" << m_connection->getDesc()
+                               << ";" << *j << ";RELIABLE]");
                PROFILE(ScopeProfiler peerprofiler(g_profiler, peerIdentifier.str(), SPT_AVG));
 
                SharedBuffer<u8> data(2); // data for sending ping, required here because of goto
@@ -1320,11 +1373,11 @@ void ConnectionSendThread::runTimeouts(float dtime)
                */
                if(peer->isTimedOut(m_timeout))
                {
-                       LOG(derr_con<<m_connection->getDesc()
+                       infostream<<m_connection->getDesc()
                                        <<"RunTimeouts(): Peer "<<peer->id
                                        <<" has timed out."
                                        <<" (source=peer->timeout_counter)"
-                                       <<std::endl);
+                                       <<std::endl;
                        // Add peer to the list
                        timeouted_peers.push_back(peer->id);
                        // Don't bother going through the buffers of this one
@@ -1357,35 +1410,35 @@ void ConnectionSendThread::runTimeouts(float dtime)
                                                        (m_max_data_packets_per_iteration/numpeers));
 
                        channel->UpdatePacketLossCounter(timed_outs.size());
+                       g_profiler->graphAdd("packets_lost", timed_outs.size());
 
                        m_iteration_packets_avaialble -= timed_outs.size();
 
-                       for(std::list<BufferedPacket>::iterator j = timed_outs.begin();
-                               j != timed_outs.end(); ++j)
+                       for(std::list<BufferedPacket>::iterator k = timed_outs.begin();
+                               k != timed_outs.end(); ++k)
                        {
-                               u16 peer_id = readPeerId(*(j->data));
-                               u8 channelnum  = readChannel(*(j->data));
-                               u16 seqnum  = readU16(&(j->data[BASE_HEADER_SIZE+1]));
+                               u16 peer_id = readPeerId(*(k->data));
+                               u8 channelnum  = readChannel(*(k->data));
+                               u16 seqnum  = readU16(&(k->data[BASE_HEADER_SIZE+1]));
 
-                               channel->UpdateBytesLost(j->data.getSize());
+                               channel->UpdateBytesLost(k->data.getSize());
+                               k->resend_count++;
 
                                LOG(derr_con<<m_connection->getDesc()
                                                <<"RE-SENDING timed-out RELIABLE to "
-                                               << j->address.serializeString()
+                                               << k->address.serializeString()
                                                << "(t/o="<<resend_timeout<<"): "
                                                <<"from_peer_id="<<peer_id
                                                <<", channel="<<((int)channelnum&0xff)
                                                <<", seqnum="<<seqnum
                                                <<std::endl);
 
-                               rawSend(*j);
+                               rawSend(*k);
 
                                // do not handle rtt here as we can't decide if this packet was
                                // lost or really takes more time to transmit
                        }
-
-                       if (!dynamic_cast<UDPPeer*>(&peer)->getLegacyPeer())
-                               channel->UpdateTimers(dtime);
+                       channel->UpdateTimers(dtime,dynamic_cast<UDPPeer*>(&peer)->getLegacyPeer());
                }
 
                /* send ping if necessary */
@@ -1419,9 +1472,11 @@ void ConnectionSendThread::runTimeouts(float dtime)
 void ConnectionSendThread::rawSend(const BufferedPacket &packet)
 {
        try{
-               m_connection->m_udpSocket.Send(packet.address, *packet.data, packet.data.getSize());
+               m_connection->m_udpSocket.Send(packet.address, *packet.data,
+                               packet.data.getSize());
                LOG(dout_con <<m_connection->getDesc()
-                               << " rawSend: " << packet.data.getSize() << " bytes sent" << std::endl);
+                               << " rawSend: " << packet.data.getSize()
+                               << " bytes sent" << std::endl);
        } catch(SendFailedException &e){
                LOG(derr_con<<m_connection->getDesc()
                                <<"Connection::rawSend(): SendFailedException: "
@@ -1435,7 +1490,8 @@ void ConnectionSendThread::sendAsPacketReliable(BufferedPacket& p, Channel* chan
                p.absolute_send_time = porting::getTimeMs();
                // Buffer the packet
                channel->outgoing_reliables_sent.insert(p,
-                       (channel->readOutgoingSequenceNumber() - MAX_RELIABLE_WINDOW_SIZE) % (MAX_RELIABLE_WINDOW_SIZE+1));
+                       (channel->readOutgoingSequenceNumber() - MAX_RELIABLE_WINDOW_SIZE)
+                       % (MAX_RELIABLE_WINDOW_SIZE+1));
        }
        catch(AlreadyExistsException &e)
        {
@@ -1455,7 +1511,8 @@ bool ConnectionSendThread::rawSendAsPacket(u16 peer_id, u8 channelnum,
        PeerHelper peer = m_connection->getPeerNoEx(peer_id);
        if(!peer) {
                LOG(dout_con<<m_connection->getDesc()
-                               <<" INFO: dropped packet for non existent peer_id: " << peer_id << std::endl);
+                               <<" INFO: dropped packet for non existent peer_id: "
+                               << peer_id << std::endl);
                assert(reliable && "trying to send raw packet reliable but no peer found!");
                return false;
        }
@@ -1464,14 +1521,15 @@ bool ConnectionSendThread::rawSendAsPacket(u16 peer_id, u8 channelnum,
        if(reliable)
        {
                bool have_sequence_number_for_raw_packet = true;
-               u16 seqnum = channel->getOutgoingSequenceNumber(have_sequence_number_for_raw_packet);
+               u16 seqnum =
+                               channel->getOutgoingSequenceNumber(have_sequence_number_for_raw_packet);
 
                if (!have_sequence_number_for_raw_packet)
                        return false;
 
                SharedBuffer<u8> reliable = makeReliablePacket(data, seqnum);
                Address peer_address;
-               peer->getAddress(MINETEST_RELIABLE_UDP,peer_address);
+               peer->getAddress(MTP_MINETEST_RELIABLE_UDP, peer_address);
 
                // Add base headers and make a packet
                BufferedPacket p = con::makePacket(peer_address, reliable,
@@ -1501,7 +1559,7 @@ bool ConnectionSendThread::rawSendAsPacket(u16 peer_id, u8 channelnum,
        {
                Address peer_address;
 
-               if (peer->getAddress(UDP,peer_address))
+               if (peer->getAddress(MTP_UDP, peer_address))
                {
                        // Add base headers and make a packet
                        BufferedPacket p = con::makePacket(peer_address, data,
@@ -1530,21 +1588,25 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
 
        switch(c.type){
        case CONNCMD_NONE:
-               LOG(dout_con<<m_connection->getDesc()<<"UDP processing reliable CONNCMD_NONE"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<"UDP processing reliable CONNCMD_NONE"<<std::endl);
                return;
 
        case CONNCMD_SEND:
-               LOG(dout_con<<m_connection->getDesc()<<"UDP processing reliable CONNCMD_SEND"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<"UDP processing reliable CONNCMD_SEND"<<std::endl);
                sendReliable(c);
                return;
 
        case CONNCMD_SEND_TO_ALL:
-               LOG(dout_con<<m_connection->getDesc()<<"UDP processing CONNCMD_SEND_TO_ALL"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<"UDP processing CONNCMD_SEND_TO_ALL"<<std::endl);
                sendToAllReliable(c);
                return;
 
        case CONCMD_CREATE_PEER:
-               LOG(dout_con<<m_connection->getDesc()<<"UDP processing reliable CONCMD_CREATE_PEER"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<"UDP processing reliable CONCMD_CREATE_PEER"<<std::endl);
                if (!rawSendAsPacket(c.peer_id,c.channelnum,c.data,c.reliable))
                {
                        /* put to queue if we couldn't send it immediately */
@@ -1553,7 +1615,8 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
                return;
 
        case CONCMD_DISABLE_LEGACY:
-               LOG(dout_con<<m_connection->getDesc()<<"UDP processing reliable CONCMD_DISABLE_LEGACY"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<"UDP processing reliable CONCMD_DISABLE_LEGACY"<<std::endl);
                if (!rawSendAsPacket(c.peer_id,c.channelnum,c.data,c.reliable))
                {
                        /* put to queue if we couldn't send it immediately */
@@ -1564,11 +1627,11 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
        case CONNCMD_SERVE:
        case CONNCMD_CONNECT:
        case CONNCMD_DISCONNECT:
-       case CONNCMD_DELETE_PEER:
        case CONCMD_ACK:
                assert("Got command that shouldn't be reliable as reliable command" == 0);
        default:
-               LOG(dout_con<<m_connection->getDesc()<<" Invalid reliable command type: " << c.type <<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" Invalid reliable command type: " << c.type <<std::endl);
        }
 }
 
@@ -1579,53 +1642,59 @@ void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c)
 
        switch(c.type){
        case CONNCMD_NONE:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_NONE"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" UDP processing CONNCMD_NONE"<<std::endl);
                return;
        case CONNCMD_SERVE:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SERVE port="
-                               <<c.port<<std::endl);
-               serve(c.port);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" UDP processing CONNCMD_SERVE port="
+                               <<c.address.serializeString()<<std::endl);
+               serve(c.address);
                return;
        case CONNCMD_CONNECT:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_CONNECT"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" UDP processing CONNCMD_CONNECT"<<std::endl);
                connect(c.address);
                return;
        case CONNCMD_DISCONNECT:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_DISCONNECT"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" UDP processing CONNCMD_DISCONNECT"<<std::endl);
                disconnect();
                return;
        case CONNCMD_DISCONNECT_PEER:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_DISCONNECT_PEER"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" UDP processing CONNCMD_DISCONNECT_PEER"<<std::endl);
                disconnect_peer(c.peer_id);
                return;
        case CONNCMD_SEND:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SEND"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" UDP processing CONNCMD_SEND"<<std::endl);
                send(c.peer_id, c.channelnum, c.data);
                return;
        case CONNCMD_SEND_TO_ALL:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SEND_TO_ALL"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" UDP processing CONNCMD_SEND_TO_ALL"<<std::endl);
                sendToAll(c.channelnum, c.data);
                return;
-       case CONNCMD_DELETE_PEER:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_DELETE_PEER"<<std::endl);
-               m_connection->deletePeer(c.peer_id, false);
-               return;
        case CONCMD_ACK:
-               LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONCMD_ACK"<<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" UDP processing CONCMD_ACK"<<std::endl);
                sendAsPacket(c.peer_id,c.channelnum,c.data,true);
                return;
        case CONCMD_CREATE_PEER:
                assert("Got command that should be reliable as unreliable command" == 0);
        default:
-               LOG(dout_con<<m_connection->getDesc()<<" Invalid command type: " << c.type <<std::endl);
+               LOG(dout_con<<m_connection->getDesc()
+                               <<" Invalid command type: " << c.type <<std::endl);
        }
 }
 
-void ConnectionSendThread::serve(u16 port)
+void ConnectionSendThread::serve(Address bind_address)
 {
-       LOG(dout_con<<m_connection->getDesc()<<"UDP serving at port "<<port<<std::endl);
+       LOG(dout_con<<m_connection->getDesc()
+                       <<"UDP serving at port " << bind_address.serializeString() <<std::endl);
        try{
-               m_connection->m_udpSocket.Bind(port);
+               m_connection->m_udpSocket.Bind(bind_address);
                m_connection->SetPeerID(PEER_ID_SERVER);
        }
        catch(SocketException &e){
@@ -1648,7 +1717,14 @@ void ConnectionSendThread::connect(Address address)
        e.peerAdded(peer->id, peer->address);
        m_connection->putEvent(e);
 
-       m_connection->m_udpSocket.Bind(0);
+       Address bind_addr;
+
+       if (address.isIPv6())
+               bind_addr.setAddress((IPv6AddressBytes*) NULL);
+       else
+               bind_addr.setAddress(0,0,0,0);
+
+       m_connection->m_udpSocket.Bind(bind_addr);
 
        // Send a dummy packet to server with peer_id = PEER_ID_INEXISTENT
        m_connection->SetPeerID(PEER_ID_INEXISTENT);
@@ -1686,6 +1762,18 @@ void ConnectionSendThread::disconnect_peer(u16 peer_id)
        writeU8(&data[0], TYPE_CONTROL);
        writeU8(&data[1], CONTROLTYPE_DISCO);
        sendAsPacket(peer_id, 0,data,false);
+
+       PeerHelper peer = m_connection->getPeerNoEx(peer_id);
+
+       if (!peer)
+               return;
+
+       if (dynamic_cast<UDPPeer*>(&peer) == 0)
+       {
+               return;
+       }
+
+       dynamic_cast<UDPPeer*>(&peer)->m_pending_disconnect = true;
 }
 
 void ConnectionSendThread::send(u16 peer_id, u8 channelnum,
@@ -1694,7 +1782,8 @@ void ConnectionSendThread::send(u16 peer_id, u8 channelnum,
        assert(channelnum < CHANNEL_COUNT);
 
        PeerHelper peer = m_connection->getPeerNoEx(peer_id);
-       if(!peer) {
+       if(!peer)
+       {
                LOG(dout_con<<m_connection->getDesc()<<" peer: peer_id="<<peer_id
                                << ">>>NOT<<< found on sending packet"
                                << ", channel " << (channelnum % 0xFF)
@@ -1764,6 +1853,8 @@ void ConnectionSendThread::sendToAllReliable(ConnectionCommand &c)
 void ConnectionSendThread::sendPackets(float dtime)
 {
        std::list<u16> peerIds = m_connection->getPeerIDs();
+       std::list<u16> pendingDisconnect;
+       std::map<u16,bool> pending_unreliable;
 
        for(std::list<u16>::iterator
                        j = peerIds.begin();
@@ -1782,6 +1873,11 @@ void ConnectionSendThread::sendPackets(float dtime)
                        continue;
                }
 
+               if (dynamic_cast<UDPPeer*>(&peer)->m_pending_disconnect)
+               {
+                       pendingDisconnect.push_back(*j);
+               }
+
                PROFILE(std::stringstream peerIdentifier);
                PROFILE(peerIdentifier << "sendPackets[" << m_connection->getDesc() << ";" << *j << ";RELIABLE]");
                PROFILE(ScopeProfiler peerprofiler(g_profiler, peerIdentifier.str(), SPT_AVG));
@@ -1843,8 +1939,9 @@ void ConnectionSendThread::sendPackets(float dtime)
                                << m_outgoing_queue.size() << " pkts)" << std::endl);
        }
 
+       unsigned int initial_queuesize = m_outgoing_queue.size();
        /* send non reliable packets*/
-       for(unsigned int i=0;i < m_outgoing_queue.size();i++) {
+       for(unsigned int i=0;i < initial_queuesize;i++) {
                OutgoingPacket packet = m_outgoing_queue.pop_front();
 
                assert(!packet.reliable &&
@@ -1876,6 +1973,17 @@ void ConnectionSendThread::sendPackets(float dtime)
                }
                else {
                        m_outgoing_queue.push_back(packet);
+                       pending_unreliable[packet.peer_id] = true;
+               }
+       }
+
+       for(std::list<u16>::iterator
+                               k = pendingDisconnect.begin();
+                               k != pendingDisconnect.end(); ++k)
+       {
+               if (!pending_unreliable[*k])
+               {
+                       m_connection->deletePeer(*k,false);
                }
        }
 }
@@ -1888,9 +1996,8 @@ void ConnectionSendThread::sendAsPacket(u16 peer_id, u8 channelnum,
 }
 
 ConnectionReceiveThread::ConnectionReceiveThread(Connection* parent,
-                                                                                               unsigned int max_packet_size) :
-       m_connection(parent),
-       m_max_packet_size(max_packet_size)
+               unsigned int max_packet_size) :
+       m_connection(parent)
 {
 }
 
@@ -1905,6 +2012,8 @@ void * ConnectionReceiveThread::Thread()
        PROFILE(std::stringstream ThreadIdentifier);
        PROFILE(ThreadIdentifier << "ConnectionReceive: [" << m_connection->getDesc() << "]");
 
+       porting::setThreadName("ConnectionReceive");
+
 #ifdef DEBUG_CONNECTION_KBPS
        u32 curtime = porting::getTimeMs();
        u32 lasttime = curtime;
@@ -1976,7 +2085,7 @@ void * ConnectionReceiveThread::Thread()
                        }
                }
 #endif
-               END_DEBUG_EXCEPTION_HANDLER(derr_con);
+               END_DEBUG_EXCEPTION_HANDLER(errorstream);
        }
        PROFILE(g_profiler->remove(ThreadIdentifier.str()));
        return NULL;
@@ -1985,13 +2094,12 @@ void * ConnectionReceiveThread::Thread()
 // Receive packets from the network and buffers and create ConnectionEvents
 void ConnectionReceiveThread::receive()
 {
-       /* now reorder reliables */
-       u32 datasize = m_max_packet_size * 2;  // Double it just to be safe
-       // TODO: We can not know how many layers of header there are.
-       // For now, just assume there are no other than the base headers.
-       u32 packet_maxsize = datasize + BASE_HEADER_SIZE;
+       // use IPv6 minimum allowed MTU as receive buffer size as this is
+       // theoretical reliable upper boundary of a udp packet for all IPv6 enabled
+       // infrastructure
+       unsigned int packet_maxsize = 1500;
        SharedBuffer<u8> packetdata(packet_maxsize);
-       
+
        bool packet_queued = true;
 
        unsigned int loop_count = 0;
@@ -2018,7 +2126,7 @@ void ConnectionReceiveThread::receive()
                                                m_connection->putEvent(e);
                                        }
                                }
-                               catch(ProcessedSilentlyException e) {
+                               catch(ProcessedSilentlyException &e) {
                                        /* try reading again */
                                }
                        }
@@ -2035,18 +2143,21 @@ void ConnectionReceiveThread::receive()
                        LOG(derr_con<<m_connection->getDesc()
                                        <<"Receive(): Invalid incoming packet, "
                                        <<"size: " << received_size
-                                       <<", protocol: " << readU32(&packetdata[0]) <<std::endl);
+                                       <<", protocol: "
+                                       << ((received_size >= 4) ? readU32(&packetdata[0]) : -1)
+                                       << std::endl);
+                       continue;
                }
 
                u16 peer_id          = readPeerId(*packetdata);
                u8 channelnum        = readChannel(*packetdata);
-               
+
                if(channelnum > CHANNEL_COUNT-1){
                        LOG(derr_con<<m_connection->getDesc()
                                        <<"Receive(): Invalid channel "<<channelnum<<std::endl);
                        throw InvalidIncomingDataException("Channel doesn't exist");
                }
-               
+
                /* preserve original peer_id for later usage */
                u16 packet_peer_id   = peer_id;
 
@@ -2059,7 +2170,7 @@ void ConnectionReceiveThread::receive()
                /* The peer was not found in our lists. Add it. */
                if(peer_id == PEER_ID_INEXISTENT)
                {
-                       peer_id = m_connection->createPeer(sender,MINETEST_RELIABLE_UDP,0);
+                       peer_id = m_connection->createPeer(sender, MTP_MINETEST_RELIABLE_UDP, 0);
                }
 
                PeerHelper peer = m_connection->getPeerNoEx(peer_id);
@@ -2075,7 +2186,7 @@ void ConnectionReceiveThread::receive()
 
                Address peer_address;
 
-               if (peer->getAddress(UDP,peer_address)) {
+               if (peer->getAddress(MTP_UDP, peer_address)) {
                        if (peer_address != sender) {
                                LOG(derr_con<<m_connection->getDesc()
                                                <<m_connection->getDesc()
@@ -2096,7 +2207,7 @@ void ConnectionReceiveThread::receive()
                        }
                }
 
-               
+
                /* mark peer as seen with id */
                if (!(packet_peer_id == PEER_ID_INEXISTENT))
                        peer->setSentWithID();
@@ -2109,24 +2220,28 @@ void ConnectionReceiveThread::receive()
                {
                        channel = &(dynamic_cast<UDPPeer*>(&peer)->channels[channelnum]);
                }
-               
+
+               if (channel != 0) {
+                       channel->UpdateBytesReceived(received_size);
+               }
+
                // Throw the received packet to channel->processPacket()
 
                // Make a new SharedBuffer from the data without the base headers
                SharedBuffer<u8> strippeddata(received_size - BASE_HEADER_SIZE);
                memcpy(*strippeddata, &packetdata[BASE_HEADER_SIZE],
                                strippeddata.getSize());
-               
+
                try{
                        // Process it (the result is some data with no headers made by us)
                        SharedBuffer<u8> resultdata = processPacket
                                        (channel, strippeddata, peer_id, channelnum, false);
-                       
+
                        LOG(dout_con<<m_connection->getDesc()
                                        <<" ProcessPacket from peer_id: " << peer_id
-                                       << ",channel: " << channelnum << ", returned "
+                                       << ",channel: " << (channelnum & 0xFF) << ", returned "
                                        << resultdata.getSize() << " bytes" <<std::endl);
-                       
+
                        ConnectionEvent e;
                        e.dataReceived(peer_id, resultdata);
                        m_connection->putEvent(e);
@@ -2170,8 +2285,8 @@ bool ConnectionReceiveThread::getFromBuffers(u16 &peer_id, SharedBuffer<u8> &dst
        return false;
 }
 
-bool ConnectionReceiveThread::checkIncomingBuffers(Channel *channel, u16 &peer_id,
-               SharedBuffer<u8> &dst)
+bool ConnectionReceiveThread::checkIncomingBuffers(Channel *channel,
+               u16 &peer_id, SharedBuffer<u8> &dst)
 {
        u16 firstseqnum = 0;
        if (channel->incoming_reliables.getFirstSeqnum(firstseqnum))
@@ -2205,22 +2320,26 @@ bool ConnectionReceiveThread::checkIncomingBuffers(Channel *channel, u16 &peer_i
 }
 
 SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
-               SharedBuffer<u8> packetdata, u16 peer_id,
-               u8 channelnum, bool reliable)
+               SharedBuffer<u8> packetdata, u16 peer_id, u8 channelnum, bool reliable)
 {
-       PeerHelper peer = m_connection->getPeer(peer_id);
+       PeerHelper peer = m_connection->getPeerNoEx(peer_id);
+
+       if (!peer) {
+               errorstream << "Peer not found (possible timeout)" << std::endl;
+               throw ProcessedSilentlyException("Peer not found (possible timeout)");
+       }
 
        if(packetdata.getSize() < 1)
                throw InvalidIncomingDataException("packetdata.getSize() < 1");
 
-       u8 type = readU8(&packetdata[0]);
+       u8 type = readU8(&(packetdata[0]));
 
        if(type == TYPE_CONTROL)
        {
                if(packetdata.getSize() < 2)
                        throw InvalidIncomingDataException("packetdata.getSize() < 2");
 
-               u8 controltype = readU8(&packetdata[1]);
+               u8 controltype = readU8(&(packetdata[1]));
 
                if( (controltype == CONTROLTYPE_ACK)
                                && (peer_id <= MAX_UDP_PEERS))
@@ -2239,27 +2358,37 @@ SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
                        try{
                                BufferedPacket p =
                                                channel->outgoing_reliables_sent.popSeqnum(seqnum);
-                               // Get round trip time
-                               unsigned int current_time = porting::getTimeMs();
 
-                               if (current_time > p.absolute_send_time)
-                               {
-                                       float rtt = (current_time - p.absolute_send_time) / 1000.0;
+                               // only calculate rtt from straight sent packets
+                               if (p.resend_count == 0) {
+                                       // Get round trip time
+                                       unsigned int current_time = porting::getTimeMs();
 
-                                       // Let peer calculate stuff according to it
-                                       // (avg_rtt and resend_timeout)
-                                       dynamic_cast<UDPPeer*>(&peer)->reportRTT(rtt);
-                               }
-                               else if (p.totaltime > 0)
-                               {
-                                       float rtt = p.totaltime;
+                                       // a overflow is quite unlikely but as it'd result in major
+                                       // rtt miscalculation we handle it here
+                                       if (current_time > p.absolute_send_time)
+                                       {
+                                               float rtt = (current_time - p.absolute_send_time) / 1000.0;
+
+                                               // Let peer calculate stuff according to it
+                                               // (avg_rtt and resend_timeout)
+                                               dynamic_cast<UDPPeer*>(&peer)->reportRTT(rtt);
+                                       }
+                                       else if (p.totaltime > 0)
+                                       {
+                                               float rtt = p.totaltime;
 
-                                       // Let peer calculate stuff according to it
-                                       // (avg_rtt and resend_timeout)
-                                       dynamic_cast<UDPPeer*>(&peer)->reportRTT(rtt);
+                                               // Let peer calculate stuff according to it
+                                               // (avg_rtt and resend_timeout)
+                                               dynamic_cast<UDPPeer*>(&peer)->reportRTT(rtt);
+                                       }
                                }
                                //put bytes for max bandwidth calculation
                                channel->UpdateBytesSent(p.data.getSize(),1);
+                               if (channel->outgoing_reliables_sent.size() == 0)
+                               {
+                                       m_connection->TriggerSend();
+                               }
                        }
                        catch(NotFoundException &e){
                                LOG(derr_con<<m_connection->getDesc()
@@ -2341,22 +2470,22 @@ SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
        }
        else if(type == TYPE_ORIGINAL)
        {
-               if(packetdata.getSize() < ORIGINAL_HEADER_SIZE)
+               if(packetdata.getSize() <= ORIGINAL_HEADER_SIZE)
                        throw InvalidIncomingDataException
-                                       ("packetdata.getSize() < ORIGINAL_HEADER_SIZE");
+                                       ("packetdata.getSize() <= ORIGINAL_HEADER_SIZE");
                LOG(dout_con<<m_connection->getDesc()
                                <<"RETURNING TYPE_ORIGINAL to user"
                                <<std::endl);
                // Get the inside packet out and return it
                SharedBuffer<u8> payload(packetdata.getSize() - ORIGINAL_HEADER_SIZE);
-               memcpy(*payload, &packetdata[ORIGINAL_HEADER_SIZE], payload.getSize());
+               memcpy(*payload, &(packetdata[ORIGINAL_HEADER_SIZE]), payload.getSize());
                return payload;
        }
        else if(type == TYPE_SPLIT)
        {
                Address peer_address;
 
-               if (peer->getAddress(UDP,peer_address)) {
+               if (peer->getAddress(MTP_UDP, peer_address)) {
 
                        // We have to create a packet again for buffering
                        // This isn't actually too bad an idea.
@@ -2428,7 +2557,8 @@ SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
 
                                // we already have this packet so this one was on wire at least
                                // the current timeout
-                               dynamic_cast<UDPPeer*>(&peer)->reportRTT(dynamic_cast<UDPPeer*>(&peer)->getResendTimeout());
+                               // we don't know how long this packet was on wire don't do silly guessing
+                               // dynamic_cast<UDPPeer*>(&peer)->reportRTT(dynamic_cast<UDPPeer*>(&peer)->getResendTimeout());
 
                                throw ProcessedSilentlyException("Retransmitting ack for old packet");
                        }
@@ -2439,7 +2569,7 @@ SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
                        Address peer_address;
 
                        // this is a reliable packet so we have a udp address for sure
-                       peer->getAddress(MINETEST_RELIABLE_UDP,peer_address);
+                       peer->getAddress(MTP_MINETEST_RELIABLE_UDP, peer_address);
                        // This one comes later, buffer it.
                        // Actually we have to make a packet to buffer one.
                        // Well, we have all the ingredients, so just do it.
@@ -2521,7 +2651,7 @@ SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
 */
 
 Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
-               bool ipv6):
+               bool ipv6) :
        m_udpSocket(ipv6),
        m_command_queue(),
        m_event_queue(),
@@ -2532,7 +2662,8 @@ Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
        m_info_mutex(),
        m_bc_peerhandler(0),
        m_bc_receive_timeout(0),
-       m_shutting_down(false)
+       m_shutting_down(false),
+       m_next_remote_peer_id(2)
 {
        m_udpSocket.setTimeoutMs(5);
 
@@ -2541,7 +2672,7 @@ Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
 }
 
 Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
-               bool ipv6, PeerHandler *peerhandler):
+               bool ipv6, PeerHandler *peerhandler) :
        m_udpSocket(ipv6),
        m_command_queue(),
        m_event_queue(),
@@ -2552,7 +2683,8 @@ Connection::Connection(u32 protocol_id, u32 max_packet_size, float timeout,
        m_info_mutex(),
        m_bc_peerhandler(peerhandler),
        m_bc_receive_timeout(0),
-       m_shutting_down(false)
+       m_shutting_down(false),
+       m_next_remote_peer_id(2)
 
 {
        m_udpSocket.setTimeoutMs(5);
@@ -2639,10 +2771,10 @@ u16 Connection::lookupPeer(Address& sender)
 
                Address tocheck;
 
-               if ((peer->getAddress(MINETEST_RELIABLE_UDP,tocheck)) && (tocheck == sender))
+               if ((peer->getAddress(MTP_MINETEST_RELIABLE_UDP, tocheck)) && (tocheck == sender))
                        return peer->id;
 
-               if ((peer->getAddress(UDP,tocheck)) && (tocheck == sender))
+               if ((peer->getAddress(MTP_UDP, tocheck)) && (tocheck == sender))
                        return peer->id;
        }
 
@@ -2676,7 +2808,7 @@ bool Connection::deletePeer(u16 peer_id, bool timeout)
 
        Address peer_address;
        //any peer has a primary address this never fails!
-       peer->getAddress(PRIMARY,peer_address);
+       peer->getAddress(MTP_PRIMARY, peer_address);
        // Create event
        ConnectionEvent e;
        e.peerRemoved(peer_id, timeout, peer_address);
@@ -2719,10 +2851,10 @@ void Connection::putCommand(ConnectionCommand &c)
        }
 }
 
-void Connection::Serve(unsigned short port)
+void Connection::Serve(Address bind_addr)
 {
        ConnectionCommand c;
-       c.serve(port);
+       c.serve(bind_addr);
        putCommand(c);
 }
 
@@ -2739,11 +2871,11 @@ bool Connection::Connected()
 
        if(m_peers.size() != 1)
                return false;
-               
+
        std::map<u16, Peer*>::iterator node = m_peers.find(PEER_ID_SERVER);
        if(node == m_peers.end())
                return false;
-       
+
        if(m_peer_id == PEER_ID_INEXISTENT)
                return false;
 
@@ -2808,11 +2940,6 @@ void Connection::Send(u16 peer_id, u8 channelnum,
        putCommand(c);
 }
 
-void Connection::RunTimeouts(float dtime)
-{
-       // No-op
-}
-
 Address Connection::GetPeerAddress(u16 peer_id)
 {
        PeerHelper peer = getPeerNoEx(peer_id);
@@ -2820,15 +2947,52 @@ Address Connection::GetPeerAddress(u16 peer_id)
        if (!peer)
                throw PeerNotFoundException("No address for peer found!");
        Address peer_address;
-       peer->getAddress(PRIMARY,peer_address);
+       peer->getAddress(MTP_PRIMARY, peer_address);
        return peer_address;
 }
 
-float Connection::GetPeerAvgRTT(u16 peer_id)
+float Connection::getPeerStat(u16 peer_id, rtt_stat_type type)
 {
        PeerHelper peer = getPeerNoEx(peer_id);
        if (!peer) return -1;
-       return peer->getStat(AVG_RTT);
+       return peer->getStat(type);
+}
+
+float Connection::getLocalStat(rate_stat_type type)
+{
+       PeerHelper peer = getPeerNoEx(PEER_ID_SERVER);
+
+       if (!peer) {
+               assert("Connection::getLocalStat we couldn't get our own peer? are you serious???" == 0);
+       }
+
+       float retval = 0.0;
+
+       for (u16 j=0; j<CHANNEL_COUNT; j++) {
+               switch(type) {
+                       case CUR_DL_RATE:
+                               retval += dynamic_cast<UDPPeer*>(&peer)->channels[j].getCurrentDownloadRateKB();
+                               break;
+                       case AVG_DL_RATE:
+                               retval += dynamic_cast<UDPPeer*>(&peer)->channels[j].getAvgDownloadRateKB();
+                               break;
+                       case CUR_INC_RATE:
+                               retval += dynamic_cast<UDPPeer*>(&peer)->channels[j].getCurrentIncomingRateKB();
+                               break;
+                       case AVG_INC_RATE:
+                               retval += dynamic_cast<UDPPeer*>(&peer)->channels[j].getAvgIncomingRateKB();
+                               break;
+                       case AVG_LOSS_RATE:
+                               retval += dynamic_cast<UDPPeer*>(&peer)->channels[j].getAvgLossRateKB();
+                               break;
+                       case CUR_LOSS_RATE:
+                               retval += dynamic_cast<UDPPeer*>(&peer)->channels[j].getCurrentLossRateKB();
+                               break;
+               default:
+                       assert("Connection::getLocalStat Invalid stat type" == 0);
+               }
+       }
+       return retval;
 }
 
 u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
@@ -2836,46 +3000,43 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
        // Somebody wants to make a new connection
 
        // Get a unique peer id (2 or higher)
-       u16 peer_id_new = 2;
+       u16 peer_id_new = m_next_remote_peer_id;
        u16 overflow =  MAX_UDP_PEERS;
 
        /*
                Find an unused peer id
        */
-       bool out_of_ids = false;
-       for(;;)
        {
-               // Check if exists
-               if(m_peers.find(peer_id_new) == m_peers.end())
-                       break;
-               // Check for overflow
-               if(peer_id_new == overflow){
-                       out_of_ids = true;
-                       break;
+       JMutexAutoLock lock(m_peers_mutex);
+               bool out_of_ids = false;
+               for(;;)
+               {
+                       // Check if exists
+                       if(m_peers.find(peer_id_new) == m_peers.end())
+                               break;
+                       // Check for overflow
+                       if(peer_id_new == overflow){
+                               out_of_ids = true;
+                               break;
+                       }
+                       peer_id_new++;
+               }
+               if(out_of_ids){
+                       errorstream<<getDesc()<<" ran out of peer ids"<<std::endl;
+                       return PEER_ID_INEXISTENT;
                }
-               peer_id_new++;
-       }
-       if(out_of_ids){
-               errorstream<<getDesc()<<" ran out of peer ids"<<std::endl;
-               return PEER_ID_INEXISTENT;
-       }
-
-       LOG(dout_con<<getDesc()
-                       <<"createPeer(): giving peer_id="<<peer_id_new<<std::endl);
 
-       // Create a peer
-       Peer *peer = 0;
+               // Create a peer
+               Peer *peer = 0;
+               peer = new UDPPeer(peer_id_new, sender, this);
 
-       peer = new UDPPeer(peer_id_new, sender, this);
+               m_peers[peer->id] = peer;
+       }
 
-       m_peers_mutex.Lock();
-       m_peers[peer->id] = peer;
-       m_peers_mutex.Unlock();
+       m_next_remote_peer_id = (peer_id_new +1) % MAX_UDP_PEERS;
 
-       // Create peer addition event
-       ConnectionEvent e;
-       e.peerAdded(peer_id_new, sender);
-       putEvent(e);
+       LOG(dout_con<<getDesc()
+                       <<"createPeer(): giving peer_id="<<peer_id_new<<std::endl);
 
        ConnectionCommand cmd;
        SharedBuffer<u8> reply(4);
@@ -2885,17 +3046,15 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
        cmd.createPeer(peer_id_new,reply);
        this->putCommand(cmd);
 
+       // Create peer addition event
+       ConnectionEvent e;
+       e.peerAdded(peer_id_new, sender);
+       putEvent(e);
+
        // We're now talking to a valid peer_id
        return peer_id_new;
 }
 
-void Connection::DeletePeer(u16 peer_id)
-{
-       ConnectionCommand c;
-       c.deletePeer(peer_id);
-       putCommand(c);
-}
-
 void Connection::PrintInfo(std::ostream &out)
 {
        m_info_mutex.Lock();
@@ -2910,11 +3069,19 @@ void Connection::PrintInfo()
 
 const std::string Connection::getDesc()
 {
-       return std::string("con(")+itos(m_udpSocket.GetHandle())+"/"+itos(m_peer_id)+")";
+       return std::string("con(")+
+                       itos(m_udpSocket.GetHandle())+"/"+itos(m_peer_id)+")";
 }
 
-void Connection::sendAck(u16 peer_id, u8 channelnum, u16 seqnum) {
+void Connection::DisconnectPeer(u16 peer_id)
+{
+       ConnectionCommand discon;
+       discon.disconnect_peer(peer_id);
+       putCommand(discon);
+}
 
+void Connection::sendAck(u16 peer_id, u8 channelnum, u16 seqnum)
+{
        assert(channelnum < CHANNEL_COUNT);
 
        LOG(dout_con<<getDesc()
@@ -2964,4 +3131,3 @@ std::list<u16> Connection::getPeerIDs()
 }
 
 } // namespace
-