internal static string GetString(this Message.MsgType msgType) { switch (msgType) { case Message.MsgType.KeepAlive: return("KeepAlive"); case Message.MsgType.ClientHello: return("ClientHello"); case Message.MsgType.ProtoUnsup: return("ProtoUnsup"); case Message.MsgType.ServerHelloDone: return("ServerHelloDone"); case Message.MsgType.ServerHello: return("ServerHello"); case Message.MsgType.ClientHelloDone: return("ClientHelloDone"); case Message.MsgType.EntryAssign: return("EntryAssign"); case Message.MsgType.EntryUpdate: return("EntryUpdate"); case Message.MsgType.FlagsUpdate: return("FlagsUpdate"); case Message.MsgType.EntryDelete: return("EntryDelete"); case Message.MsgType.ClearEntries: return("ClearEntries"); case Message.MsgType.ExecuteRpc: return("ExecuteRpc"); case Message.MsgType.RpcResponse: return("RpcResponse"); default: return("Unknown"); } }
public void QueueOutgoing(Message msg) { lock (m_pendingMutex) { //Merge with previouse Message.MsgType type = msg.Type; switch (type) { case Message.MsgType.EntryAssign: case Message.MsgType.EntryUpdate: { // don't do this for unassigned id's int id = (int)msg.Id; if (id == 0xffff) { m_pendingOutgoing.Add(msg); break; } if (id < m_pendingUpdate.Count && m_pendingUpdate[id].First != 0) { var oldmsg = m_pendingOutgoing[m_pendingUpdate[id].First - 1]; if (oldmsg != null && oldmsg.Is(Message.MsgType.EntryAssign) && msg.Is(Message.MsgType.EntryUpdate)) { // need to update assignement m_pendingOutgoing[m_pendingUpdate[id].First] = Message.EntryAssign(oldmsg.Str, (uint)id, msg.SeqNumUid, msg.Val, (EntryFlags)oldmsg.Flags); } else { // new but remember it m_pendingOutgoing[m_pendingUpdate[id].First] = msg; } } else { // new but don't remember it int pos = m_pendingOutgoing.Count; m_pendingOutgoing.Add(msg); if (id >= m_pendingUpdate.Count) { ResizePendingUpdate(id + 1); } m_pendingUpdate[id].SetFirst(pos + 1); } break; } case Message.MsgType.EntryDelete: { //Don't do this for unnasigned uid's int id = (int)msg.Id; if (id == 0xffff) { m_pendingOutgoing.Add(msg); break; } if (id < m_pendingUpdate.Count) { if (m_pendingUpdate[id].First != 0) { m_pendingOutgoing[m_pendingUpdate[id].First - 1] = new Message(); m_pendingUpdate[id].SetFirst(0); } if (m_pendingUpdate[id].Second != 0) { m_pendingOutgoing[m_pendingUpdate[id].Second - 1] = new Message(); m_pendingUpdate[id].SetSecond(0); } } //Add deletion m_pendingOutgoing.Add(msg); break; } case Message.MsgType.FlagsUpdate: { //Don't do this for unassigned uids int id = (int)msg.Id; if (id == 0xffff) { m_pendingOutgoing.Add(msg); break; } if (id < m_pendingUpdate.Count && m_pendingUpdate[id].Second != 0) { //Overwrite the previous one for this uid m_pendingOutgoing[m_pendingUpdate[id].Second - 1] = msg; } else { int pos = m_pendingOutgoing.Count; m_pendingOutgoing.Add(msg); if (id > m_pendingUpdate.Count) { ResizePendingUpdate(id + 1); } m_pendingUpdate[id].SetSecond(pos + 1); } break; } case Message.MsgType.ClearEntries: { //Knock out all previous assignes/updates for (int i = 0; i < m_pendingOutgoing.Count; i++) { var message = m_pendingOutgoing[i]; if (message == null) { continue; } var t = message.Type; if (t == Message.MsgType.EntryAssign || t == Message.MsgType.EntryUpdate || t == Message.MsgType.FlagsUpdate || t == Message.MsgType.EntryDelete || t == Message.MsgType.ClearEntries) { m_pendingOutgoing[i] = new Message(); } } m_pendingUpdate.Clear(); m_pendingOutgoing.Add(msg); break; } default: m_pendingOutgoing.Add(msg); break; } } }
public void ProcessIncoming(Message msg, NetworkConnection conn, WeakReference <NetworkConnection> connWeak) { IDisposable monitor = null; try { monitor = m_monitor.Enter(); IDisposable monitorToUnlock; Message.MsgType type = msg.Type; SequenceNumber seqNum; Entry entry; uint id; switch (type) { case KeepAlive: break; // ignore case ClientHello: case ProtoUnsup: case ServerHelloDone: case ServerHello: case ClientHelloDone: // shouldn't get these, but ignore if we do break; case EntryAssign: { id = msg.Id; string name = msg.Str; bool mayNeedUpdate = false; if (m_server) { if (id == 0xffff) { if (m_entries.ContainsKey(name)) { return; } id = (uint)m_idMap.Count; entry = new Entry(name) { Value = msg.Val, Flags = (EntryFlags)msg.Flags, Id = id }; m_entries[name] = entry; m_idMap.Add(entry); if (entry.IsPersistent()) { m_persistentDirty = true; } m_notifier.NotifyEntry(name, entry.Value, NotifyFlags.NotifyNew); if (m_queueOutgoing != null) { var queueOutgoing = m_queueOutgoing; var outMsg = Message.EntryAssign(name, id, entry.SeqNum.Value, msg.Val, (EntryFlags)msg.Flags); monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); queueOutgoing(outMsg, null, null); } return; } if (id >= m_idMap.Count || m_idMap[(int)id] == null) { monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); Debug("server: received assignment to unknown entry"); return; } entry = m_idMap[(int)id]; } else { if (id == 0xffff) { monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); Debug("client: received entry assignment request?"); return; } if (id >= m_idMap.Count) { ResizeIdMap(id + 1); } entry = m_idMap[(int)id]; if (entry == null) { Entry newEntry; if (!m_entries.ContainsKey(name)) { //Entry didn't exist at all. newEntry = new Entry(name) { Value = msg.Val, Flags = (EntryFlags)msg.Flags, Id = id }; m_idMap[(int)id] = newEntry; m_entries[name] = newEntry; m_notifier.NotifyEntry(name, newEntry.Value, NotifyFlags.NotifyNew); return; } else { newEntry = m_entries[name]; } mayNeedUpdate = true; entry = newEntry; entry.Id = id; m_idMap[(int)id] = entry; if ((EntryFlags)msg.Flags != entry.Flags) { var queueOutgoing = m_queueOutgoing; var outmsg = Message.FlagsUpdate(id, entry.Flags); monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); queueOutgoing(outmsg, null, null); Interlocked.Exchange(ref monitor, m_monitor.Enter()); } } } seqNum = new SequenceNumber(msg.SeqNumUid); if (seqNum < entry.SeqNum) { if (mayNeedUpdate) { var queueOutgoing = m_queueOutgoing; var outmsg = Message.EntryUpdate(entry.Id, entry.SeqNum.Value, entry.Value); monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); queueOutgoing(outmsg, null, null); } return; } //Sanity check. Name should match id if (msg.Str != entry.Name) { monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); Debug("entry assignment for same id with different name?"); return; } NotifyFlags notifyFlags = NotifyFlags.NotifyUpdate; if (!mayNeedUpdate && conn.ProtoRev >= 0x0300) { if ((entry.Flags & EntryFlags.Persistent) != ((EntryFlags)msg.Flags & EntryFlags.Persistent)) { m_persistentDirty = true; } if (entry.Flags != (EntryFlags)msg.Flags) { notifyFlags |= NotifyFlags.NotifyFlagsChanged; } entry.Flags = (EntryFlags)msg.Flags; } if (entry.IsPersistent() && entry.Value != msg.Val) { m_persistentDirty = true; } entry.Value = msg.Val; entry.SeqNum = seqNum; m_notifier.NotifyEntry(name, entry.Value, notifyFlags); if (m_server && m_queueOutgoing != null) { var queueOutgoing = m_queueOutgoing; var outmsg = Message.EntryAssign(entry.Name, id, msg.SeqNumUid, msg.Val, entry.Flags); monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); queueOutgoing(outmsg, null, conn); } break; } case EntryUpdate: id = msg.Id; if (id >= m_idMap.Count || m_idMap[(int)id] == null) { monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); Debug("received update to unknown entyr"); return; } entry = m_idMap[(int)id]; seqNum = new SequenceNumber(msg.SeqNumUid); if (seqNum <= entry.SeqNum) { return; } entry.Value = msg.Val; entry.SeqNum = seqNum; if (entry.IsPersistent()) { m_persistentDirty = true; } m_notifier.NotifyEntry(entry.Name, entry.Value, NotifyFlags.NotifyUpdate); if (m_server && m_queueOutgoing != null) { var queueOutgoing = m_queueOutgoing; monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); queueOutgoing(msg, null, conn); } break; case FlagsUpdate: { id = msg.Id; if (id >= m_idMap.Count || m_idMap[(int)id] == null) { monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); Debug("reeived flags update to unknown entry"); return; } entry = m_idMap[(int)id]; if (entry.Flags == (EntryFlags)msg.Flags) { return; } if ((entry.Flags & EntryFlags.Persistent) != ((EntryFlags)msg.Flags & EntryFlags.Persistent)) { m_persistentDirty = true; } entry.Flags = (EntryFlags)msg.Flags; m_notifier.NotifyEntry(entry.Name, entry.Value, NotifyFlags.NotifyFlagsChanged); if (m_server && m_queueOutgoing != null) { var queueOutgoing = m_queueOutgoing; monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); queueOutgoing(msg, null, conn); } break; } case EntryDelete: { id = msg.Id; if (id >= m_idMap.Count || m_idMap[(int)id] == null) { monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); Debug("received delete to unknown entry"); return; } entry = m_idMap[(int)id]; if (entry.IsPersistent()) { m_persistentDirty = true; } m_idMap[(int)id] = null; if (m_entries.TryGetValue(entry.Name, out entry)) { m_entries.Remove(entry.Name); m_notifier.NotifyEntry(entry.Name, entry.Value, NotifyFlags.NotifyDelete); } if (m_server && m_queueOutgoing != null) { var queueOutgoing = m_queueOutgoing; monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); queueOutgoing(msg, null, conn); } break; } case ClearEntries: { DeleteAllEntriesImpl(); if (m_server && m_queueOutgoing != null) { var queueOutgoing = m_queueOutgoing; monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); queueOutgoing(msg, null, conn); } break; } case ExecuteRpc: if (!m_server) { return; } id = msg.Id; if (id >= m_idMap.Count || m_idMap[(int)id] == null) { monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); Debug("received RPC call to unknown entry"); return; } entry = m_idMap[(int)id]; if (!entry.Value.IsRpc()) { monitorToUnlock = Interlocked.Exchange(ref monitor, null); monitorToUnlock.Dispose(); Debug("received RPC call to non-RPC entry"); return; } m_rpcServer.ProcessRpc(entry.Name, msg, entry.RpcCallback, conn.Uid, message => { NetworkConnection c; connWeak.TryGetTarget(out c); if (c != null && !c.Disposed) { c.QueueOutgoing(message); } }); break; case RpcResponse: if (m_server) { return; } if (!msg.Val.IsRpc()) { return; //Not an RPC message } m_rpcResults.Add(new ImmutablePair <uint, uint>(msg.Id, msg.SeqNumUid), msg.Val.GetRpc()); m_monitor.PulseAll(); break; } } finally { monitor?.Dispose(); } }