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");
            }
        }
Exemplo n.º 2
0
        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;
                }
            }
        }
Exemplo n.º 3
0
        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();
            }
        }