#include #include "lan_clipboard.h" #include using namespace ks;using namespace ks::lan; int checks{}; void check(bool b,const char *s){if(!b)throw std::runtime_error(s);++checks;} int main(){try{ const std::string aid(32,'a'),bid(32,'b'),cid(32,'c'),key(64,'d'); ClipboardExchange a(aid),b(bid),c(cid); a.peerSession(bid,b.session());a.peerSession(cid,c.session());b.peerSession(aid,a.session());c.peerSession(aid,a.session()); Json trusted{{bid,{{"key",key}}},{cid,{{"key",key}}}},back{{aid,{{"key",key}}}}; Bytes payload(13000);for(size_t i=0;i(i); a.queue({bid,cid},payload,"editor.exe",1); std::deque> packets,acks;Json firstPacket;int sent=0; auto output=[&](const std::string &to,const Json &p){check(p.dump().size()<=2048,"datagram fits discovery bound");if(firstPacket.is_null())firstPacket=p;packets.push_back({to,p});}; auto ack=[&](const std::string &,const Json &p){acks.push_back({p.at("id"),p});}; for(uint64_t now=10;now<10000;now+=20){ a.poll(trusted,now,output); while(!packets.empty()){ auto [to,p]=std::move(packets.front());packets.pop_front();if(++sent%7==0)continue; auto &receiver=to==bid?b:c; receiver.receive(aid,key,p,now,123,ack); receiver.receive(aid,key,p,now,123,ack); // duplicate datagrams do not duplicate history } while(!acks.empty()){ auto [from,p]=std::move(acks.front());acks.pop_front();if(++sent%11==0)continue; a.receive(from,key,p,now,123,output); } } check(b.deliveries.size()==1&&c.deliveries.size()==1,"all paired instances receive exactly once despite loss/duplicates"); check(b.deliveries[0].bytes==payload&&c.deliveries[0].bytes==payload,"binary clipboard survives retransmission"); check(b.deliveries[0].sequence==123&&b.deliveries[0].app=="editor.exe","capture sequence and origin retained"); b.receive(aid,key,firstPacket,10000,123,ack); check(acks.empty(),"authenticated old packet replay is ignored"); ClipboardExchange restarted(bid);restarted.peerSession(aid,a.session()); restarted.receive(aid,key,firstPacket,10001,123,ack); check(restarted.deliveries.empty()&&acks.empty(),"old datagrams rejected after recipient restart"); auto damaged=firstPacket;damaged["number"]=1000000;auto data=damaged["data"].get();data[0]=data[0]=='0'?'1':'0';damaged["data"]=data; bool rejected=false;try{b.receive(aid,key,damaged,10002,123,ack);}catch(...){rejected=true;} check(rejected,"modified ciphertext rejected"); a.queue({bid},Bytes{1,2,3},"second",10003); a.peerSession(bid,restarted.session()); for(uint64_t now=10004;now<11000;now+=20){ a.poll(trusted,now,output); while(!packets.empty()){auto p=std::move(packets.front().second);packets.pop_front();restarted.receive(aid,key,p,now,456,ack);} while(!acks.empty()){auto p=std::move(acks.front().second);acks.pop_front();a.receive(bid,key,p,now,456,output);} } check(restarted.deliveries.size()==1&&restarted.deliveries[0].bytes==Bytes({1,2,3}),"clipboard works after peer restart"); bool limited=false;try{a.queue({bid},Bytes(32*1024*1024+1),"large",12000);}catch(...){limited=true;} check(limited,"oversized clipboard bounded"); { WSADATA startup{};check(WSAStartup(MAKEWORD(2,2),&startup)==0,"UDP benchmark starts"); SOCKET sa=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP),sb=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); struct Cleanup {SOCKET a,b;~Cleanup(){closesocket(a);closesocket(b);WSACleanup();}} cleanup{sa,sb}; sockaddr_in aa{},ab{};aa.sin_family=ab.sin_family=AF_INET;aa.sin_addr.s_addr=ab.sin_addr.s_addr=htonl(INADDR_LOOPBACK); check(bind(sa,reinterpret_cast(&aa),sizeof(aa))==0&&bind(sb,reinterpret_cast(&ab),sizeof(ab))==0,"UDP benchmark binds"); int length=sizeof(aa);getsockname(sa,reinterpret_cast(&aa),&length);length=sizeof(ab);getsockname(sb,reinterpret_cast(&ab),&length); for(auto socket:{sa,sb}){u_long nonblock=1;ioctlsocket(socket,FIONBIO,&nonblock);int buffer=1024*1024;setsockopt(socket,SOL_SOCKET,SO_RCVBUF,reinterpret_cast(&buffer),sizeof(buffer));} ClipboardExchange sender(aid),receiver(bid);sender.peerSession(bid,receiver.session());receiver.peerSession(aid,sender.session()); Bytes large(2*1024*1024);uint32_t random=123;for(auto &v:large){random=random*1664525+1013904223;v=static_cast(random>>24);} auto started=GetTickCount64();sender.queue({bid},large,"benchmark",started); auto send=[&](SOCKET socket,const sockaddr_in &address,const Json &p){auto data=p.dump();if(sendto(socket,data.data(),int(data.size()),0,reinterpret_cast(&address),sizeof(address))!=int(data.size()))throw std::runtime_error("UDP benchmark send failed");}; while(receiver.deliveries.empty()&&GetTickCount64()-started<15000){ auto now=GetTickCount64();sender.poll(trusted,now,[&](const auto &,const Json &p){send(sa,ab,p);}); bool progressed=false; for(int n=0;n<64;++n){char buffer[2048];auto size=recv(sb,buffer,sizeof(buffer),0);if(size<=0)break;progressed=true; receiver.receive(aid,key,Json::parse(buffer,buffer+size),now,123,[&](const auto &,const Json &p){send(sb,aa,p);});} for(int n=0;n<64;++n){char buffer[2048];auto size=recv(sa,buffer,sizeof(buffer),0);if(size<=0)break;progressed=true; sender.receive(bid,key,Json::parse(buffer,buffer+size),now,123,[&](const auto &,const Json &p){send(sa,ab,p);});} if(!progressed)Sleep(1); } check(receiver.deliveries.size()==1&&receiver.deliveries[0].bytes==large,"2 MiB crosses actual encrypted UDP sockets intact"); std::cout<<"2 MiB encrypted UDP loopback: "<<(GetTickCount64()-started)<<" ms\n"; } std::cout<