#include "llarp/iwp/transit_message.hpp" #include "llarp/endian.h" #include "llarp/iwp/frame_state.hpp" #include "llarp/iwp/sendbuf.hpp" #include "llarp/time.h" void transit_message::clear() { frags.clear(); lastfrag.clear(); } // calculate acked bitmask uint32_t transit_message::get_bitmask() const { uint32_t bitmask = 0; uint8_t idx = 0; while(idx < 32) { bitmask |= (status.test(idx) ? (1 << idx) : 0); ++idx; } return bitmask; } // outbound transit_message::transit_message(llarp_buffer_t buf, const byte_t *hash, uint64_t id, uint16_t mtu) { started = llarp_time_now_ms(); put_message(buf, hash, id, mtu); } // inbound transit_message::transit_message(const xmit &x) : msginfo(x) { started = llarp_time_now_ms(); byte_t fragidx = 0; uint16_t fragsize = x.fragsize(); while(fragidx < x.numfrags()) { frags[fragidx].resize(fragsize); ++fragidx; } status.reset(); } /// ack packets based off a bitmask void transit_message::ack(uint32_t bitmask) { uint8_t idx = 0; while(idx < 32) { if(bitmask & (1 << idx)) { status.set(idx); } ++idx; } lastAck = llarp_time_now_ms(); } bool transit_message::should_send_ack(llarp_time_t now) const { if(msginfo.numfrags() == 0) return true; if(now < started) return false; if(status.count() == 0) return true; return now - lastRetransmit > 200; } bool transit_message::should_resend_xmit(llarp_time_t now) const { if(now < started) return false; return lastAck == 0 && now - started > 1000; } bool transit_message::should_resend_frags(llarp_time_t now) const { if(now < started) return false; return lastAck > 0 && now - lastAck > 500 && !completed(); } bool transit_message::completed() const { for(byte_t idx = 0; idx < msginfo.numfrags(); ++idx) { if(!status.test(idx)) return false; } return true; } // template < typename T > void transit_message::generate_xmit(sendqueue_t &queue, byte_t flags) { uint16_t sz = lastfrag.size() + sizeof(msginfo.buffer); auto pkt = new sendbuf_t(sz + 6); auto body_ptr = init_sendbuf(pkt, eXMIT, sz, flags); memcpy(body_ptr, msginfo.buffer, sizeof(msginfo.buffer)); body_ptr += sizeof(msginfo.buffer); memcpy(body_ptr, lastfrag.data(), lastfrag.size()); queue.Put(pkt); } // template < typename T > void transit_message::retransmit_frags(sendqueue_t &queue, byte_t flags) { auto msgid = msginfo.msgid(); auto fragsize = msginfo.fragsize(); for(auto &frag : frags) { if(status.test(frag.first)) continue; uint16_t sz = 9 + fragsize; auto pkt = new sendbuf_t(sz + 6); auto body_ptr = init_sendbuf(pkt, eFRAG, sz, flags); htobe64buf(body_ptr, msgid); body_ptr[8] = frag.first; memcpy(body_ptr + 9, frag.second.data(), fragsize); queue.Put(pkt); } lastRetransmit = llarp_time_now_ms(); } bool transit_message::reassemble(std::vector< byte_t > &buffer) { auto total = msginfo.totalsize(); buffer.resize(total); auto fragsz = msginfo.fragsize(); auto ptr = &buffer[0]; for(byte_t idx = 0; idx < msginfo.numfrags(); ++idx) { if(!status.test(idx)) return false; memcpy(ptr, frags[idx].data(), fragsz); ptr += fragsz; } memcpy(ptr, lastfrag.data(), lastfrag.size()); return true; } void transit_message::put_message(llarp_buffer_t buf, const byte_t *hash, uint64_t id, uint16_t mtu) { status.reset(); uint8_t fragid = 0; uint16_t fragsize = mtu; size_t left = buf.sz; while(left > fragsize) { auto &frag = frags[fragid]; frag.resize(fragsize); memcpy(frag.data(), buf.cur, fragsize); buf.cur += fragsize; fragid++; left -= fragsize; } uint16_t lastfrag = buf.sz - (buf.cur - buf.base); // set info for xmit msginfo.set_info(hash, id, fragsize, lastfrag, fragid); put_lastfrag(buf.cur, lastfrag); } void transit_message::put_lastfrag(byte_t *buf, size_t sz) { lastfrag.resize(sz); memcpy(lastfrag.data(), buf, sz); } bool transit_message::put_frag(byte_t fragno, byte_t *buf) { auto itr = frags.find(fragno); if(itr == frags.end()) return false; memcpy(itr->second.data(), buf, msginfo.fragsize()); status.set(fragno); return true; }