protected override void XAttachPipe(Pipe pipe, bool icanhasall) { Debug.Assert(pipe != null); // ZMQ_PAIR socket can only be connected to a single peer. // The socket rejects any further connection requests. if (m_pipe == null) m_pipe = pipe; else pipe.Terminate (false); }
// Activates pipe that have previously reached high watermark. public void Activated(Pipe pipe) { // Move the pipe from passive to eligible state. Utils.Swap (m_pipes, m_pipes.IndexOf (pipe), m_eligible); m_eligible++; // If there's no message being sent at the moment, move it to // the active state. if (!m_more) { Utils.Swap (m_pipes, m_eligible - 1, m_active); m_active++; } }
public Stream(Ctx parent, int threadId, int sid) : base(parent, threadId, sid) { m_prefetched = false; m_identitySent = false; m_currentOut = null; m_moreOut = false; m_nextPeerId = Utils.GenerateRandom(); m_options.SocketType = ZmqSocketType.Stream; m_fq = new FQ(); m_prefetchedId = new Msg(); m_prefetchedMsg = new Msg(); m_outpipes = new Dictionary<Blob, Outpipe>(); m_options.RawSocket = true; }
protected void SendActivateWrite(Pipe destination, long msgsRead) { Command cmd = new Command(destination, CommandType.ActivateWrite, msgsRead); SendCommand (cmd); }
protected virtual void ProcessBind(Pipe pipe) { throw new NotSupportedException(); }
protected override void XTerminated(Pipe pipe) { // Remove the pipe from the trie. If there are topics that nobody // is interested in anymore, send corresponding unsubscriptions // upstream. m_subscriptions.RemoveHelper(pipe, s_SendUnsubscription, this); m_dist.Terminated(pipe); }
protected override void XAttachPipe(Pipe pipe, bool icanhasall) { Debug.Assert(pipe != null); m_dist.Attach(pipe); // If icanhasall_ is specified, the caller would like to subscribe // to all data on this pipe, implicitly. if (icanhasall) m_subscriptions.Add(null, pipe); // The pipe is active when attached. Let's read the subscriptions from // it, if any. XReadActivated(pipe); }
protected override void XAttachPipe(Pipe pipe, bool icanhasall) { Debug.Assert(pipe != null); lb.Attach (pipe); }
public SessionBase(IOThread ioThread, bool connect, SocketBase socket, Options options, Address addr) : base(ioThread, options) { m_ioObject = new IOObject(ioThread); m_connect = connect; m_pipe = null; m_incompleteIn = false; m_pending = false; m_engine = null; m_socket = socket; m_ioThread = ioThread; m_hasLingerTimer = false; m_identitySent = false; m_identityReceived = false; m_addr = addr; if (options.RawSocket) { m_identitySent = true; m_identityReceived = true; } m_terminatingPipes = new HashSet<Pipe>(); }
/// <summary> <see cref="PipePair"/> uses this function to let us know about the peer pipe object. </summary> /// <param name="peer">The peer to be assigned.</param> private void SetPeer(Pipe peer) { // Peer can be set once only. Debug.Assert(peer != null); m_peer = peer; }
public Outpipe(Pipe pipe, bool active) { Pipe = pipe; Active = active; }
private bool IdentifyPeer(Pipe pipe) { Blob identity; if (m_options.RawSocket) { // Always assign identity for raw-socket byte[] buf = new byte[5]; buf[0] = 0; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, buf, 1, 4); identity = new Blob(buf, buf.Length); } else { // Pick up handshake cases and also case where next identity is set Msg msg = new Msg(); msg.InitEmpty(); bool ok = pipe.Read(ref msg); if (!ok) { return(false); } if (msg.Size == 0) { // Fall back on the auto-generation byte[] buf = new byte[5]; buf[0] = 0; byte[] result = BitConverter.GetBytes(m_nextPeerId++); Buffer.BlockCopy(result, 0, buf, 1, 4); identity = new Blob(buf, buf.Length); msg.Close(); } else { identity = new Blob(msg.Data, msg.Size); // Ignore peers with duplicate ID. if (m_outpipes.ContainsKey(identity)) { msg.Close(); return(false); } msg.Close(); } } pipe.Identity = identity; // Add the record into output pipes lookup table Outpipe outpipe = new Outpipe(pipe, true); m_outpipes.Add(identity, outpipe); return(true); }
protected override bool XRecv(SendReceiveOptions flags, ref Msg msg) { if (m_prefetched) { if (!m_identitySent) { msg.Move(ref m_prefetchedId); m_identitySent = true; } else { msg.Move(ref m_prefetchedMsg); m_prefetched = false; } m_moreIn = msg.HasMore; return(true); } Pipe[] pipe = new Pipe[1]; bool isMessageAvailable = m_fq.RecvPipe(pipe, ref msg); // It's possible that we receive peer's identity. That happens // after reconnection. The current implementation assumes that // the peer always uses the same identity. // TODO: handle the situation when the peer changes its identity. while (isMessageAvailable && msg.IsIdentity) { isMessageAvailable = m_fq.RecvPipe(pipe, ref msg); } if (!isMessageAvailable) { return(false); } Debug.Assert(pipe[0] != null); // If we are in the middle of reading a message, just return the next part. if (m_moreIn) { m_moreIn = msg.HasMore; } else { // We are at the beginning of a message. // Keep the message part we have in the prefetch buffer // and return the ID of the peer instead. m_prefetchedMsg.Move(ref msg); m_prefetched = true; Blob identity = pipe[0].Identity; msg.InitPool(identity.Size); msg.Put(identity.Data, 0, identity.Size); msg.SetFlags(MsgFlags.More); m_identitySent = true; } return(true); }
protected override bool XSend(ref Msg msg, SendReceiveOptions flags) { // If this is the first part of the message it's the ID of the // peer to send the message to. if (!m_moreOut) { Debug.Assert(m_currentOut == null); // If we have malformed message (prefix with no subsequent message) // then just silently ignore it. // TODO: The connections should be killed instead. if (msg.HasMore) { m_moreOut = true; // Find the pipe associated with the identity stored in the prefix. // If there's no such pipe just silently ignore the message, unless // mandatory is set. Blob identity = new Blob(msg.Data, msg.Size); Outpipe op; if (m_outpipes.TryGetValue(identity, out op)) { m_currentOut = op.Pipe; if (!m_currentOut.CheckWrite()) { op.Active = false; m_currentOut = null; if (m_mandatory) { m_moreOut = false; return(false); } } } else if (m_mandatory) { m_moreOut = false; throw NetMQException.Create(ErrorCode.EHOSTUNREACH); } } // Detach the message from the data buffer. msg.Close(); msg.InitEmpty(); return(true); } if (m_options.RawSocket) { msg.ResetFlags(MsgFlags.More); } // Check whether this is the last part of the message. m_moreOut = msg.HasMore; // Push the message into the pipe. If there's no out pipe, just drop it. if (m_currentOut != null) { // Close the remote connection if user has asked to do so // by sending zero length message. // Pending messages in the pipe will be dropped (on receiving term- ack) if (m_rawSocket && msg.Size == 0) { m_currentOut.Terminate(false); msg.Close(); msg.InitEmpty(); m_currentOut = null; return(true); } bool ok = m_currentOut.Write(ref msg); if (!ok) { m_currentOut = null; } else if (!m_moreOut) { m_currentOut.Flush(); m_currentOut = null; } } else { msg.Close(); } // Detach the message from the data buffer. msg.InitEmpty(); return(true); }
protected void SendBind(Own destination, Pipe pipe, bool incSeqnum) { if (incSeqnum) destination.IncSeqnum (); Command cmd = new Command(destination, CommandType.Bind, pipe); SendCommand (cmd); }
protected void SendPipeTermAck(Pipe destination) { Command cmd = new Command(destination, CommandType.PipeTermAck); SendCommand (cmd); }
// Removes the pipe from the distributor object. public void Terminated(Pipe pipe) { // Remove the pipe from the list; adjust number of matching, active and/or // eligible pipes accordingly. if (m_pipes.IndexOf (pipe) < m_matching) m_matching--; if (m_pipes.IndexOf (pipe) < m_active) m_active--; if (m_pipes.IndexOf (pipe) < m_eligible) m_eligible--; m_pipes.Remove(pipe); }
protected override void XReadActivated(Pipe pipe) { m_fq.Activated(pipe); }
// Write the message to the pipe. Make the pipe inactive if writing // fails. In such a case false is returned. private bool Write(Pipe pipe, Msg msg) { if (!pipe.Write (msg)) { Utils.Swap(m_pipes, m_pipes.IndexOf (pipe), m_matching - 1); m_matching--; Utils.Swap(m_pipes, m_pipes.IndexOf (pipe), m_active - 1); m_active--; Utils.Swap(m_pipes, m_active, m_eligible - 1); m_eligible--; return false; } if (!msg.HasMore) pipe.Flush (); return true; }
protected override void XReadActivated(Pipe pipe) { m_fq.Activated (pipe); }
// Adds the pipe to the distributor object. public void Attach(Pipe pipe) { // If we are in the middle of sending a message, we'll add new pipe // into the list of eligible pipes. Otherwise we add it to the list // of active pipes. if (m_more) { m_pipes.Add (pipe); //pipes.swap (eligible, pipes.size () - 1); Utils.Swap(m_pipes, m_eligible, m_pipes.Count - 1); m_eligible++; } else { m_pipes.Add (pipe); //pipes.swap (active, pipes.size () - 1); Utils.Swap(m_pipes, m_active, m_pipes.Count - 1); m_active++; m_eligible++; } }
protected override void XTerminated(Pipe pipe) { lb.Terminated (pipe); }
// To be used once only, when creating the session. public void AttachPipe(Pipe pipe) { Debug.Assert(!IsTerminating); Debug.Assert(m_pipe == null); Debug.Assert(pipe != null); m_pipe = pipe; m_pipe.SetEventSink(this); }
protected override void XReadActivated(Pipe pipe) { // There are some subscriptions waiting. Let's process them. Msg sub; while ((sub = pipe.Read()) != null) { // Apply the subscription to the trie. byte[] data = sub.Data; int size = sub.Size; if (size > 0 && (data[0] == 0 || data[0] == 1)) { bool unique; if (data[0] == 0) unique = m_subscriptions.Remove(data, 1, pipe); else unique = m_subscriptions.Add(data, 1, pipe); // If the subscription is not a duplicate, store it so that it can be // passed to used on next recv call. if (m_options.SocketType == ZmqSocketType.Xpub && (unique || m_verbose)) m_pending.Enqueue(new Blob(sub.Data)); } } }
public void Hiccuped(Pipe pipe) { // Hiccups are always sent from session to socket, not the other // way round. throw new NotSupportedException("Must Override"); }
protected override void XWriteActivated(Pipe pipe) { m_dist.Activated(pipe); }
public void ReadActivated(Pipe pipe) { // Skip activating if we're detaching this pipe if (m_pipe != pipe) { Debug.Assert(m_terminatingPipes.Contains(pipe)); return; } if (m_engine != null) m_engine.ActivateOut(); else m_pipe.CheckRead(); }
protected void SendActivateRead(Pipe destination) { Command cmd = new Command(destination, CommandType.ActivateRead); SendCommand (cmd); }
public void Terminated(Pipe pipe) { // Drop the reference to the deallocated pipe. Debug.Assert(m_pipe == pipe || m_terminatingPipes.Contains(pipe)); if (m_pipe == pipe) // If this is our current pipe, remove it m_pipe = null; else // Remove the pipe from the detached pipes set m_terminatingPipes.Remove(pipe); if (!IsTerminating && m_options.RawSocket) { if (m_engine != null) { m_engine.Terminate(); m_engine = null; } Terminate(); } // If we are waiting for pending messages to be sent, at this point // we are sure that there will be no more messages and we can proceed // with termination safely. if (m_pending && m_pipe == null && m_terminatingPipes.Count == 0) ProceedWithTerm(); }
protected void SendBind(Own destination, Pipe pipe) { SendBind(destination, pipe, true); }
public void WriteActivated(Pipe pipe) { // Skip activating if we're detaching this pipe if (m_pipe != pipe) { Debug.Assert(m_terminatingPipes.Contains(pipe)); return; } if (m_engine != null) m_engine.ActivateIn(); }
protected void SendHiccup(Pipe destination, Object pipe) { Command cmd = new Command(destination, CommandType.Hiccup, pipe); SendCommand (cmd); }
protected override void ProcessAttach(IEngine engine) { Debug.Assert(engine != null); // Create the pipe if it does not exist yet. if (m_pipe == null && !IsTerminating) { ZObject[] parents = { this, m_socket }; int[] hwms = { m_options.ReceiveHighWatermark, m_options.SendHighWatermark }; bool[] delays = { m_options.DelayOnClose, m_options.DelayOnDisconnect }; Pipe[] pipes = Pipe.PipePair(parents, hwms, delays); // Plug the local end of the pipe. pipes[0].SetEventSink(this); // Remember the local end of the pipe. Debug.Assert(m_pipe == null); m_pipe = pipes[0]; // Ask socket to plug into the remote end of the pipe. SendBind(m_socket, pipes[1]); } // Plug in the engine. Debug.Assert(m_engine == null); m_engine = engine; m_engine.Plug(m_ioThread, this); }
protected override void XTerminated(Pipe pipe) { if (pipe == m_pipe) m_pipe = null; }
private void Detached() { // Transient session self-destructs after peer disconnects. if (!m_connect) { Terminate(); return; } // For delayed connect situations, terminate the pipe // and reestablish later on if (m_pipe != null && m_options.DelayAttachOnConnect && m_addr.Protocol != Address.PgmProtocol && m_addr.Protocol != Address.EpgmProtocol) { m_pipe.Hiccup(); m_pipe.Terminate(false); m_terminatingPipes.Add(m_pipe); m_pipe = null; } Reset(); // Reconnect. if (m_options.ReconnectIvl != -1) StartConnecting(true); // For subscriber sockets we hiccup the inbound pipe, which will cause // the socket object to resend all the subscriptions. if (m_pipe != null && (m_options.SocketType == ZmqSocketType.Sub || m_options.SocketType == ZmqSocketType.Xsub)) m_pipe.Hiccup(); }
protected override void XReadActivated(Pipe pipe) { // There's just one pipe. No lists of active and inactive pipes. // There's nothing to do here. }