Example #1
0
        /**
         * When we get a reply ack, we can remove the item from our cache,
         * we know the other guy got our reply
         */
        protected void HandleReplyAck(ReqrepType rt, int idnum,
                                      MemBlock err_data, ISender ret_path)
        {
            RequestKey rk = new RequestKey(idnum, ret_path);

            lock ( _sync ) {
                /**
                 * This is not completely safe, but probably fine.  Consider the
                 * case where:
                 * A -(req)-> B
                 * A timeout but B does get the req
                 * A <-(rep)- B
                 * A -(req)-> B (these cross in flight)
                 * A -(repack)-> B
                 *
                 * but then the repack passes the req retransmission (out of order
                 * delivery)
                 *
                 * This is unlikely, but we could improve it.
                 * @todo improve the reply caching algorithm
                 */
                ReplyState rs = (ReplyState)_reply_cache[rk];
                if (rs != null)
                {
                    ReleaseReplyState(rs);
                }
            }
        }
Example #2
0
        /** Forget all state associated with this ReplyState
         * Not synchronized!  You have to hold the lock!
         */
        protected void ReleaseReplyState(ReplyState rs)
        {
            _reply_cache.Remove(rs.RequestKey);
            ReplyState tmp_rs;

            _reply_id_table.TryTake(rs.LocalID, out tmp_rs);
        }
Example #3
0
        // Methods /////

        /** Create a ReplyState for a new Request
         * Note, this is not synchronized, you must hold the lock when calling!
         */
        protected ReplyState GenerateReplyState(PType prefix, RequestKey rk)
        {
            var rs = new ReplyState(_prefix, rk);

            _reply_cache[rk] = rs;
            rs.LocalID       = _reply_id_table.GenerateID(rs);
            return(rs);
        }
Example #4
0
 public Reply(Topic topic, String subject, String content, ReplyState state) : base(subject, content, null)
 {
     if (topic == null)
     {
         throw new ArgumentNullException(nameof(topic));
     }
     this.TopicId = topic.Id;
     this.State   = state;
 }
Example #5
0
 public Reply(Reply reply, String subject, String content, ReplyState state) : base(subject, content, null)
 {
     if (reply == null)
     {
         throw new ArgumentNullException(nameof(reply));
     }
     this.ReplyToId = reply.Id;
     this.TopicId   = reply.TopicId;
     this.State     = state;
 }
Example #6
0
        protected void HandleRequest(ReqrepType rt, int idnum,
                                     MemBlock rest, ISender retpath)
        {
            /**
             * Lets see if we have been asked this question before
             */
            ReplyState rs     = null;
            bool       resend = false;

#if REQREP_DEBUG
            Console.Error.WriteLine("[ReqrepManager: {0}] Receiving request id: {1}, from: {2}",
                                    _info, idnum, retpath);
#endif
            RequestKey rk = new RequestKey(idnum, retpath);
            lock ( _sync ) {
                rs = (ReplyState)_reply_cache[rk];
                if (rs == null)
                {
                    rs = GenerateReplyState(_prefix, rk);
                }
                else
                {
                    resend = true;
                }
            }
            if (resend)
            {
                //This is an old request:
                rs.Resend();
            }
            else
            {
                //This is a new request:
                try {
                    _sub.Handle(rest, rs);
                }
                catch {
                    lock ( _sync ) {
                        ReleaseReplyState(rs);
                    }
                    //This didn't work out:
                    try {
                        MemBlock err_data = MemBlock.Reference(
                            new byte[] { (byte)ReqrepError.HandlerFailure });
                        ICopyable reply = MakeRequest(ReqrepType.Error, idnum, err_data);
                        retpath.Send(reply);
                    }
                    catch {
                        //If this fails, we may think about logging.
                        //The return path could fail, that's the only obvious exception
                        ///@todo log exception
                    }
                }
            }
        }
Example #7
0
 /** Forget all state associated with this ReplyState
  * Not synchronized!  You have to hold the lock!
  */
 protected void ReleaseReplyState(ReplyState rs) {
   _reply_cache.Remove(rs.RequestKey);
   ReplyState tmp_rs;
   _reply_id_table.TryTake(rs.LocalID, out tmp_rs);
 }
Example #8
0
   // Methods /////

   /** Create a ReplyState for a new Request
    * Note, this is not synchronized, you must hold the lock when calling!
    */
   protected ReplyState GenerateReplyState(PType prefix, RequestKey rk) {
     var rs = new ReplyState(_prefix, rk);
     _reply_cache[rk] = rs;
     rs.LocalID = _reply_id_table.GenerateID(rs);
     return rs;
   }
Example #9
0
   protected void HandleRequest(ReqrepType rt, int idnum,
                                MemBlock rest, ISender retpath)
   {
     /**
      * Lets see if we have been asked this question before
      */
     ReplyState rs = null;
     bool resend = false;
#if REQREP_DEBUG
	 Console.Error.WriteLine("[ReqrepManager: {0}] Receiving request id: {1}, from: {2}", 
			     _info, idnum, retpath);
#endif
     RequestKey rk = new RequestKey(idnum, retpath);
     lock( _sync ) {
       rs = (ReplyState)_reply_cache[rk];
       if( rs == null ) {
         rs = new ReplyState(rk);
	 //Add the new reply state before we drop the lock
         _reply_cache[rk] = rs;
       }
       else {
         resend = true;
       }
     }
     if( resend ) {
       //This is an old request:
       rs.Resend();
     }
     else {
       //This is a new request:
       try {
         _sub.Handle(rest, rs);
       }
       catch {
         lock( _sync ) {
           _reply_cache.Remove( rs.RequestKey );
         }
         //This didn't work out:
         try {
           MemBlock err_data = MemBlock.Reference(
                        new byte[]{ (byte) ReqrepError.HandlerFailure } );
           ICopyable reply = MakeRequest(ReqrepType.Error, idnum, err_data);
           retpath.Send(reply);
         }
         catch {
           //If this fails, we may think about logging.
           //The return path could fail, that's the only obvious exception
           ///@todo log exception
         }
       }
     }
   }
Example #10
0
        /**
         * This method listens for the HeartBeatEvent from the
         * node and checks for timeouts.
         */
        public void TimeoutChecker(object o, EventArgs args)
        {
            DateTime  now            = DateTime.UtcNow;
            TimeSpan  interval       = now - _last_check;
            ArrayList timeout_hands  = null;
            ArrayList to_resend      = null;
            ArrayList to_ack         = null;
            ArrayList reps_to_resend = null;

            if (interval > _edge_reqtimeout || interval > _nonedge_reqtimeout)
            {
                //Here is a list of all the handlers for the requests that timed out
                lock ( _sync ) {
                    _last_check = now;
                    foreach (RequestState reqs in _req_state_table)
                    {
                        if (reqs.IsTimeToAct(now))
                        {
                            //We need to act:
                            if (reqs.IsTimedOut)
                            {
                                //We have timed out.
                                if (timeout_hands == null)
                                {
                                    timeout_hands = new ArrayList();
                                }
                                timeout_hands.Add(reqs);
                            }
                            else if (reqs.NeedToResend)
                            {
                                ///@todo improve the logic of resending to be less wasteful
                                if (to_resend == null)
                                {
                                    to_resend = new ArrayList();
                                }
                                to_resend.Add(reqs);
                            }
                        }
                    }
                    //Clean up the req_state_table:
                    if (timeout_hands != null)
                    {
                        RequestState tmprs;
                        foreach (RequestState reqs in timeout_hands)
                        {
                            _req_state_table.TryTake(reqs.RequestID, out tmprs);
                        }
                    }
                    //Look for any Replies it might be time to clean:
                    foreach (DictionaryEntry de in _reply_cache)
                    {
                        ReplyState reps = (ReplyState)de.Value;
                        TimeSpan   reptimeout;
                        if (reps.ReturnPath is Edge)
                        {
                            reptimeout = _edge_reqtimeout;
                        }
                        else
                        {
                            reptimeout = _nonedge_reqtimeout;
                        }
                        if (reps.HaveSent)
                        {
                            /*
                             * See if we need to resend our reply
                             */
                            if (now - reps.RepDate > reptimeout)
                            {
                                //We have already sent and we've kept it for a while...
                                if (reps.IncrementRepTimeouts() <= _MAX_RESENDS)
                                {
                                    if (reps.HaveSentAck)
                                    {
                                        /*
                                         * If we sent an ack, we must keep sending the reply, until
                                         * we get a reply ack
                                         */
                                        if (reps_to_resend == null)
                                        {
                                            reps_to_resend = new ArrayList();
                                        }
                                        reps_to_resend.Add(reps);
                                    }
                                }
                                else
                                {
                                    /*
                                     * This reply has timed out:
                                     */
                                    ReleaseReplyState(reps);
                                }
                            }
                        }
                        else if (false == reps.HaveSentAck)
                        {
                            //This one is taking a long time to answer, just ack it:
                            if (to_ack == null)
                            {
                                to_ack = new ArrayList();
                            }
                            to_ack.Add(reps);
                        }
                    }
                }
            }
            else
            {
                //At each heartbeat check to see if we need send request acks:
                lock (_sync) {
                    foreach (DictionaryEntry de in _reply_cache)
                    {
                        ReplyState reps = (ReplyState)de.Value;
                        if ((false == reps.HaveSentAck) && (false == reps.HaveSent))
                        {
                            //This one is taking a long time to answer, just ack it:
                            if (to_ack == null)
                            {
                                to_ack = new ArrayList();
                            }
                            to_ack.Add(reps);
                        }
                    }
                }
            }

            /*
             * It is important not to hold the lock while we call
             * functions that could result in this object being
             * accessed.
             *
             * We have released the lock, now we can send the packets:
             */
            if (to_resend != null)
            {
                foreach (RequestState req in to_resend)
                {
                    try {
                        req.Send();
                    }
                    catch (SendException sx) {
                        if (sx.IsTransient)
                        {
                            /*
                             * Just ignore it and wait until later
                             */
                            //This send didn't work, but maybe it will next time, who knows...
                            req.ReplyHandler.HandleError(this, req.RequestID, ReqrepError.Send,
                                                         null, req.UserState);
                        }
                        else
                        {
                            /*
                             * This is a permanent failure, we don't have a way to denote
                             * permanent failures currently, so let's just pass it on as a
                             * Timeout (which is a kind of permanent failure).
                             */
                            StopRequest(req.RequestID, req.ReplyHandler);
                            req.ReplyHandler.HandleError(this, req.RequestID, ReqrepError.Timeout,
                                                         null, req.UserState);
                        }
                    }
                    catch {
                        //This send didn't work, but maybe it will next time, who knows...
                        req.ReplyHandler.HandleError(this, req.RequestID, ReqrepError.Send,
                                                     null, req.UserState);
                    }
                }
            }

            /*
             * Once we have released the lock, tell the handlers
             * about the timeout that have occured
             */
            if (timeout_hands != null)
            {
                foreach (RequestState reqs in timeout_hands)
                {
                    reqs.ReplyHandler.HandleError(this, reqs.RequestID, ReqrepError.Timeout,
                                                  null, reqs.UserState);
                }
            }

            /*
             * Send acks for those that have been waiting for a long time
             */
            if (to_ack != null)
            {
                foreach (ReplyState reps in to_ack)
                {
                    try {
                        reps.SendAck();
                    }
                    catch (Exception) {
                        ///@todo, log this exception.
                    }
                }
            }

            /*
             * Resend replies for unacked replies
             */
            if (reps_to_resend != null)
            {
                foreach (ReplyState reps in reps_to_resend)
                {
                    reps.Resend();
                }
            }
        }
Example #11
0
        public RpcReplyMessage(byte[] recieved)
        {
            Type = MessageType.REPLY;
            int pos = sizeof(int);

            state = (ReplyState)NetUtils.ToIntFromBigEndian(recieved, sizeof(int));
            pos  += sizeof(int);
            switch (state)
            {
            case ReplyState.MSG_ACCEPTED:
                #region Accepted
                ServerVerifier = new Authentication(recieved, pos);
                pos           += ServerVerifier.Size;
                if (ServerVerifier.Flavor == AuthFlavor.AUTH_NONE)
                {
                    acceptState = (ReplyAcceptState)NetUtils.ToIntFromBigEndian(recieved, pos);
                    pos        += sizeof(int);
                    switch (acceptState)
                    {
                    case ReplyAcceptState.SUCCESS:
                        Result = new byte[recieved.Length - pos];
                        Buffer.BlockCopy(recieved, pos, Result, 0, recieved.Length - pos);
                        break;

                    case ReplyAcceptState.PROG_MISMATCH:
                        PROGvLow  = (uint)NetUtils.ToIntFromBigEndian(recieved, pos);
                        pos      += sizeof(int);
                        PROGvHigh = (uint)NetUtils.ToIntFromBigEndian(recieved, pos);
                        break;

                    case ReplyAcceptState.PROG_UNAVAIL:
                    case ReplyAcceptState.PROC_UNAVAIL:
                    case ReplyAcceptState.GARBAGE_ARGS:
                    case ReplyAcceptState.SYSTEM_ERR:
                        break;

                    default:
                        throw new ArgumentException("RpcReplyMessage. Wrong Accept State.");
                    }
                }
                else
                {
                    throw new ArgumentException("RPCv2. Library not support authentication.");
                }
                #endregion
                break;

            case ReplyState.MSG_DENIED:
                #region Denied
                rejectState = (ReplyRejectState)NetUtils.ToIntFromBigEndian(recieved, pos);
                pos        += sizeof(int);
                switch (rejectState)
                {
                case ReplyRejectState.RPC_MISMATCH:
                    RPCvLow  = (uint)NetUtils.ToIntFromBigEndian(recieved, pos);
                    pos     += sizeof(int);
                    RPCvHigh = (uint)NetUtils.ToIntFromBigEndian(recieved, pos);
                    break;

                case ReplyRejectState.AUTH_ERROR:
                    authState = (AuthenticationState)NetUtils.ToIntFromBigEndian(recieved, pos);
                    break;

                default:
                    throw new ArgumentException("RpcReplyMessage. Wrong Reject State.");
                }
                #endregion
                break;

            default:
                throw new ArgumentException("RpcReplyMessage. Wrong Message Status.");
            }
        }