From db0614fc08985f09157d6641e89ee3916b9d2d58 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Sat, 21 Oct 2017 17:33:08 +0300 Subject: [PATCH] fixes to network and client ids; it should work with more than two peers now ;-) --- wootnet.d | 232 ++++++++++++++++++++++++++------------------------------------ 1 file changed, 97 insertions(+), 135 deletions(-) diff --git a/wootnet.d b/wootnet.d index c7de336..1733fbb 100644 --- a/wootnet.d +++ b/wootnet.d @@ -20,6 +20,8 @@ // 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. +// +// WARNING! crypto here is TOTALLY INVALID! don't do it like that! module wootnet; //version = woot_net_chatty; @@ -31,7 +33,6 @@ import core.time; import std.conv : to; import std.digest.sha; import std.socket; -import std.uuid; import iv.chachasimple; import iv.cmdcon; @@ -54,19 +55,26 @@ version(Windows) { // ////////////////////////////////////////////////////////////////////////// // +public string toString() (in auto ref sockaddr_in it) { + import std.format : format; + return + "%u.%u.%u.%u:%u".format( + it.sin_addr.s_addr&0xff, (it.sin_addr.s_addr>>8)&0xff, (it.sin_addr.s_addr>>16)&0xff, (it.sin_addr.s_addr>>24)&0xff, + ntohs(it.sin_port)); +} + + +// ////////////////////////////////////////////////////////////////////////// // align(1) struct WootNetOp { align(1): public: - string toString () const { - import std.format : format; - string cs; - if (ch <= 32 || ch >= 127) cs = "0x%u".format(cast(uint)ch); else cs = "'%c'".format(cast(char)ch); - return "WootNetOp(%s,%s,id=%s,prev=%s,next=%s)".format(opType, cs, id, prev, next); - } + string toString () const { return op.toString; } pure nothrow @safe @nogc: public: ubyte[ChaCha20.IVSize] nonce; + WStrOp op; + /* WStrOp.OpType opType = WStrOp.OpType.None; UUID id; // the id assigned at creation-time that this character keeps forever uint opid; @@ -75,26 +83,26 @@ public: // these are the ids of the chars that must go somewhere before and somewhere after this character respectively UUID prev, next; uint popid, nopid; + */ } // ////////////////////////////////////////////////////////////////////////// // // we will use UUIDs to identify clients in the network, -// but will convert UUIDs to uints for internal operations /* * WOOT network packet: * uint pktseq; - * 16 bytes: client id (self for send, remote for recv) - * ubyte operation (0: hello; 1: insert; 2: delete; 3: ping; 4: pong; 5: ack) + * 4 bytes: client id (self for send, remote for recv) + * ubyte operation (see PktType) * hello: * insert: * 4 bytes: dchar - * 20 bytes: char id (UUID, opid) - * 20 bytes: prev id (UUID, opid) - * 20 bytes: next id (UUID, opid) + * 8 bytes: char id (UUID, opid) + * 8 bytes: prev id (UUID, opid) + * 8 bytes: next id (UUID, opid) * delete: - * 20 bytes: char id (UUID, opid) + * 8 bytes: char id (UUID, opid) * ping: * uint pingid * pong: @@ -102,7 +110,6 @@ public: * ack: * pktseq is used as acked packet id * peer: - * 16 bytes: client id (self for send, remote for recv) * uint ip * ushort port */ @@ -143,13 +150,14 @@ private: foreach (ubyte b; dp[0..T.sizeof]) data.unsafeArrayAppend(b); } + /* void put(T:UUID) (in auto ref T v) { foreach (ubyte b; v.data[]) data.unsafeArrayAppend(b); } + */ } static struct Peer { - UUID uuid; uint cid; // client id [1..] Packet[] queue; // send queue sockaddr_in addr; @@ -169,9 +177,10 @@ private: int sk = -1; uint pktseq; Peer[] mPeers; - uint[UUID] uuid2peerMap; uint[uint] cid2peerMap; - uint mNextCId = 2; + public uint mMyCId; + public sockaddr_in myaddr; + static struct HelloQueue { sockaddr_in addr; @@ -191,7 +200,7 @@ private: if (!hq.pkt.valid) { initPacket(hq.pkt); // generate packet - hq.pkt.put(mPeers[0].uuid); + hq.pkt.put(mMyCId); hq.pkt.put(cast(ubyte)PktType.Hello); //hq.pkt.put(mPort); encodePacket(hq.pkt); @@ -239,7 +248,6 @@ private: // encrypt packet auto cyph = ChaCha20(mKey, pkt.data[0..ChaCha20.IVSize]); cyph.processBuf(pkt.data[ChaCha20.IVSize..$]); - } void initPacket (ref Packet pkt) { @@ -250,28 +258,24 @@ private: Packet encodePacketOp (in ref WootNetOp op) { Packet pkt; - if (op.opType == WStrOp.OpType.None || op.opType < WStrOp.OpType.min || op.opType > WStrOp.OpType.max) return pkt; + if (op.op.opType == WStrOp.OpType.None || op.op.opType < WStrOp.OpType.min || op.op.opType > WStrOp.OpType.max) return pkt; initPacket(pkt); // generate packet - pkt.put(mPeers[0].uuid); + pkt.put(mMyCId); - final switch (op.opType) { + final switch (op.op.opType) { case WStrOp.OpType.Insert: pkt.put(cast(ubyte)PktType.Insert); - pkt.put(cast(uint)op.ch); - pkt.put(op.id); - pkt.put(op.opid); - pkt.put(op.prev); - pkt.put(op.popid); - pkt.put(op.next); - pkt.put(op.nopid); + pkt.put(cast(uint)op.op.ch.ch); + pkt.put(op.op.ch.id.uid); + pkt.put(op.op.ch.prev.uid); + pkt.put(op.op.ch.next.uid); break; case WStrOp.OpType.Delete: pkt.put(cast(ubyte)PktType.Delete); - pkt.put(op.id); - pkt.put(op.opid); + pkt.put(op.op.ch.id.uid); break; case WStrOp.OpType.None: assert(0); } @@ -287,7 +291,7 @@ private: initPacket(pkt); // generate packet - pkt.put(mPeers[0].uuid); + pkt.put(mMyCId); pkt.put(cast(ubyte)PktType.Peer); pkt.put(peer.addr.sin_addr.s_addr); pkt.put(peer.addr.sin_port); @@ -304,7 +308,7 @@ private: pkt.setup(seqn, true); // generate packet - pkt.put(mPeers[0].uuid); + pkt.put(mMyCId); pkt.put(cast(ubyte)PktType.Ack); encodePacket(pkt); @@ -317,7 +321,7 @@ private: initPacket(pkt); // generate packet - pkt.put(mPeers[0].uuid); + pkt.put(mMyCId); pkt.put(cast(ubyte)PktType.Ping); encodePacket(pkt); @@ -341,84 +345,62 @@ private: } private: - static bool isEmpty() (in auto ref UUID uuid) nothrow @trusted @nogc { - foreach (immutable b; uuid.data[]) if (b != 0) return false; - return true; - } - - static UUID emptyUUID () nothrow @trusted @nogc { - UUID res; - res.data[] = 0; - return res; - } - - Peer* newPeer() (in auto ref UUID uuid) { - if (auto pip = uuid in uuid2peerMap) return &mPeers[*pip]; - mPeers.unsafeArrayAppend(Peer(uuid, mNextCId++)); - uuid2peerMap[uuid] = cast(uint)(mPeers.length-1); - cid2peerMap[mPeers[$-1].cid] = cast(uint)(mPeers.length-1); + Peer* newPeer() (uint peercid) { + if (peercid == 0) return null; + if (peercid == mMyCId) return null; + if (auto pip = peercid in cid2peerMap) return &mPeers[*pip]; + mPeers.unsafeArrayAppend(Peer(peercid)); + cid2peerMap[peercid] = cast(uint)(mPeers.length-1); mPeers[$-1].lastActivity = MonoTime.currTime; return &mPeers[$-1]; } - int findPeerIdx() (in auto ref UUID uuid) { - if (auto pip = uuid in uuid2peerMap) return cast(int)(*pip); - return -1; - } - - Peer* findPeer() (in auto ref UUID uuid) { - if (auto pip = uuid in uuid2peerMap) return &mPeers[*pip]; + Peer* findPeer() (uint peercid) { + if (auto pip = peercid in cid2peerMap) return &mPeers[*pip]; return null; } - bool setUUIDbyCId (out UUID uuid, uint cid) nothrow @trusted @nogc { - if (cid == 0) { uuid = emptyUUID(); return true; } - if (auto pp = cid in cid2peerMap) { uuid = mPeers[*pp].uuid; return true; } - uuid = emptyUUID(); - return false; - } - - void setCIdbyUUID() (out uint cid, in auto ref UUID uuid) nothrow @trusted { - if (isEmpty(uuid)) { cid = 0; return; } - if (auto pp = uuid in uuid2peerMap) { cid = mPeers[*pp].cid; return; } - // new peer - auto np = newPeer(uuid); - cid = np.cid; + Peer* findPeerByAddr() (in auto ref sockaddr_in addr) { + foreach (immutable idx, ref peer; mPeers) { + if (!peer.netvalid) continue; + if (peer.addr.sin_port != addr.sin_port) continue; + if (peer.addr.sin_addr.s_addr != addr.sin_addr.s_addr) continue; + return &mPeers[idx]; + } + return null; } public: this (const(char)[] akey, ushort aport) { + import core.stdc.string : memset; + memset(&myaddr, 0, myaddr.sizeof); + // init crypto key mKey = sha256Of(akey); prng.seed(getUlongSeed, getUlongSeed); // add initial peer - mPeers.unsafeArrayAppend(Peer()); - mPeers[0].uuid = randomUUID(); - mPeers[0].cid = 1; - uuid2peerMap[mPeers[0].uuid] = 0; - cid2peerMap[mPeers[0].cid] = 0; + foreach (ref ubyte b; (cast(ubyte*)&mMyCId)[0..mMyCId.sizeof]) { + b = cast(ubyte)prng.front; + prng.popFront(); + } // prepare socket - { - import core.stdc.string : memset; - sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sk < -1) throw new Exception("cannot create socket"); - sockaddr_in me = void; - memset(&me, 0, me.sizeof); - me.sin_family = AF_INET; - me.sin_port = htons(aport); - me.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(sk, cast(sockaddr*)&me, me.sizeof) == -1) { - closeSocket(); - throw new Exception("cannot bind socket"); - } + sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sk < -1) throw new Exception("cannot create socket"); + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(aport); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(sk, cast(sockaddr*)&myaddr, myaddr.sizeof) == -1) { + closeSocket(); + throw new Exception("cannot bind socket"); } } ~this () { closeSocket(); } final private void closeSocket () nothrow @trusted @nogc { + import core.stdc.string : memset; if (sk >= 0) { version(Windows) { } else { @@ -427,6 +409,7 @@ public: } sk = -1; } + memset(&myaddr, 0, myaddr.sizeof); } void addPeer (const(char)[] host, const(char)[] port) { @@ -453,27 +436,18 @@ public: private final Packet createOpPacket() (in auto ref WStrOp op) { if (op.empty) return Packet(); WootNetOp netop; - netop.opType = op.opType; - if (!setUUIDbyCId(netop.id, op.ch.id.cid)) throw new Exception("unknown CID"); - netop.opid = op.ch.id.opid; - if (op.isIns) { - netop.ch = op.ch.ch; - if (!setUUIDbyCId(netop.prev, op.ch.prev.cid)) throw new Exception("unknown CID"); - netop.popid = op.ch.prev.opid; - if (!setUUIDbyCId(netop.next, op.ch.next.cid)) throw new Exception("unknown CID"); - netop.nopid = op.ch.next.opid; - } + netop.op = op; return encodePacketOp(netop); } final void queue (const(WStrOp)[] ops...) { - if (mPeers.length == 1) return; + if (mPeers.length == 0) return; foreach (const ref op; ops[]) { if (op.empty) continue; auto pk = createOpPacket(op); if (!pk.valid) continue; // don't send to ourself - foreach (ref peer; mPeers[1..$]) { + foreach (ref peer; mPeers[]) { if (!peer.netvalid) continue; peer.queue.unsafeArrayAppend(pk); } @@ -509,7 +483,7 @@ public: } } else if (xsend >= 0 && xsend < mPeers.length && mPeers[xsend].queue.length && mPeers[xsend].netvalid) { auto peer = &mPeers[xsend]; - version(woot_net_chatty) conwriteln("sending packet to peer ", peer.uuid); + version(woot_net_chatty) conwriteln("sending packet to peer ", peer.cid); aout = peer.addr; int cnum = 0; while (cnum < peer.queue.length) { @@ -526,6 +500,7 @@ public: } } if (pktpos > 0) { + version(woot_net_chatty) conwriteln("NET: sending packet to ", aout.toString); if (sendto(sk, pkt.ptr, pktpos, MSG_NOSIGNAL, cast(sockaddr*)&aout, aout.sizeof) != pktpos) return; } } @@ -533,13 +508,13 @@ public: final void checkTimeouts () { auto ct = MonoTime.currTime; - foreach (ref peer; mPeers[1..$]) { + foreach (ref peer; mPeers[]) { if (!peer.netvalid) continue; // pinged? if (peer.pingSent) { if ((ct-peer.lastActivity).total!"msecs" > 1000) { // this peer is dead - conwriteln("NET: disconnected ", peer.uuid); + conwriteln("NET: disconnected ", peer.cid); peer.markDead(); } continue; @@ -581,6 +556,8 @@ public: if (rd < 0) return; gotPacketFrom(it); // clear hellos + version(woot_net_chatty) conwriteln("NET: packet from ", it.toString); + int ccpktpos = 0; datagram: while (ccpktpos < rd && rd-ccpktpos >= ChaCha20.IVSize) { ubyte[MTU] xdata = void; @@ -592,7 +569,7 @@ public: auto data = xdata[ChaCha20.IVSize..rd]; cyph.processBuf(data[]); - if (data.length < 4+16+1) break; + if (data.length < 4+4+1) break; T get(T) () if (__traits(isIntegral, T)) { if (data.length < T.sizeof) throw new Exception("invalid packed received"); @@ -602,18 +579,9 @@ public: return res; } - UUID getUUID () { - if (data.length < UUID.data.length) throw new Exception("invalid packed received"); - UUID res; - ccpktpos += cast(int)UUID.data.length; - res.data[] = data[0..UUID.data.length]; - data = data[UUID.data.length..$]; - return res; - } - try { uint rseq = get!uint; - UUID ruuid = getUUID; + uint ruuid = get!uint; ubyte opcode = get!ubyte; if (opcode < PktType.min || opcode > PktType.max) break; // alas @@ -621,9 +589,10 @@ public: auto peer = findPeer(ruuid); if (peer is null) { // new peer - version(woot_net_chatty) conwriteln("NET: new peer comes: ", ruuid.toString); + version(woot_net_chatty) conwriteln("NET: new peer comes: ", ruuid); peer = newPeer(ruuid); - version(woot_net_chatty) conwriteln(" ", peer.uuid, " : ", (peer.uuid == ruuid)); + if (peer is null) break; // oops + version(woot_net_chatty) conwriteln(" ", peer.cid, " : ", (peer.cid == ruuid)); } version(woot_net_chatty) conprintfln("NET: msg from %u.%u.%u.%u:%u", @@ -644,8 +613,8 @@ public: // ack this packet peerAck(*peer, rseq); // send all known peers to it - foreach (ref pr; mPeers[1..$]) { - if (pr.uuid != peer.uuid) { + foreach (ref pr; mPeers[]) { + if (pr.cid != peer.cid) { auto pk = encodePacketPeer(pr); if (pk.valid) peer.queue.unsafeArrayAppend(pk); } @@ -677,14 +646,11 @@ public: // char dchar ch = cast(dchar)get!uint; // char id - setCIdbyUUID(xid, getUUID); - auto chid = WCharId(xid, get!uint); + auto chid = WCharId(get!ulong); // prev id - setCIdbyUUID(xid, getUUID); - auto previd = WCharId(xid, get!uint); + auto previd = WCharId(get!ulong); // next id - setCIdbyUUID(xid, getUUID); - auto nextid = WCharId(xid, get!uint); + auto nextid = WCharId(get!ulong); auto wc = WChar(chid, ch, previd, nextid); cb(WStrOp(WStrOp.OpType.Insert, wc)); break; @@ -693,8 +659,7 @@ public: // ack this packet peerAck(*peer, rseq); // char id - setCIdbyUUID(xid, getUUID); - auto chid = WCharId(xid, get!uint); + auto chid = WCharId(get!ulong); auto wc = WChar(chid, 0); cb(WStrOp(WStrOp.OpType.Delete, wc)); break; @@ -727,15 +692,13 @@ public: case PktType.Peer: // ack this packet peerAck(*peer, rseq); - auto pid = getUUID; it.sin_family = AF_INET; it.sin_addr.s_addr = get!uint; it.sin_port = get!ushort; - version(woot_net_chatty) conwriteln("NET: PEER ", pid); - peer = findPeer(pid); - if (peer is null) peer = newPeer(ruuid); - peer.addr = it; - peer.netvalid = true; + if (it.sin_port == myaddr.sin_port && it.sin_addr.s_addr == myaddr.sin_addr.s_addr) break; + version(woot_net_chatty) conwriteln("NET: PEER ", it.toString); + peer = findPeerByAddr(it); + if (peer is null) addPeer(it); break; default: throw new Exception("invalid packed received"); } @@ -748,8 +711,7 @@ public: } public: - final @property uint mycid () { return mPeers[0].cid; } - final @property UUID myuuid () { return mPeers[0].uuid; } + final @property uint mycid () const pure nothrow @safe @nogc { pragma(inline, true); return mMyCId; } } -- 2.11.4.GIT