TSystems.RELOAD.Transport.MessageTransport.PreJoinProdecure C# (CSharp) Method

PreJoinProdecure() public method

public PreJoinProdecure ( List BootstrapServerList ) : IEnumerator
BootstrapServerList List
return IEnumerator
        public IEnumerator<ITask> PreJoinProdecure(List<BootstrapServer> BootstrapServerList)
        {
            bool attached = false;
            ulong bsTransId = 0;

            if (m_topology.LocalNode.Id == null)
                yield break;

            ReloadMessage reloadSendMsg;
            ReloadMessage reloadRcvMsg = null;

            /* This is the begin of populating the neighbor table
               convert local node to resource id + 1 and sent an attach to it
             */
            Destination dest = new Destination(new ResourceId(
              m_topology.LocalNode.Id + (byte)1));
            Destination last_destination = null;
            Node NextHopNode = null;
            int succSize = m_ReloadConfig.IamClient ? 1 : ReloadGlobals.SUCCESSOR_CACHE_SIZE;
            for (int i = 0; i < succSize; i++)
            {
                //if (last_destination != null && last_destination == dest)
                if (last_destination != null && last_destination.Equals(dest))    // markus: we have to use Equals method
                    break;
                if (m_ReloadConfig.IamClient)
                    reloadSendMsg = create_attach_req(dest, false);
                else
                    reloadSendMsg = create_attach_req(dest, true);

                //we do not know the bootstrap peer's node id so far so we leave that parameter empty Node(null)

                ReloadDialog reloadDialog = null;
                int RetransmissionTime = ReloadGlobals.RetransmissionTime + ReloadGlobals.MaxTimeToSendPacket;

                /* Modification for Clients out of draft, TLS stack will take some time
                 * to initialize, add another 10s waiting */
                if (m_ReloadConfig.IamClient && i == 0)
                    RetransmissionTime += 10000;

                int iRetrans = ReloadGlobals.MaxRetransmissions;

                int iCycleBootstrap = 0;

                while (iRetrans >= 0 &&
                  m_ReloadConfig.State < ReloadConfig.RELOAD_State.Shutdown)
                {
                    /* This is the first bootstrap contacting sequence if NextHopNode 
                     * is still zero, in any other case 
                     * use an attach to the node where we got the last answer from 
                     */
                    if (NextHopNode == null)
                    {
                        /* we could use a foreach loop, but CCR would multitask it, but we
                         * want serialize that here
                        */
                        if (iCycleBootstrap >= BootstrapServerList.Count())
                            iCycleBootstrap = 0;

                        BootstrapServer bss = BootstrapServerList[iCycleBootstrap++];

                        if (attached == true)
                            break;

                        //TKTODO Rejoin of bootstrap server not solved 
                        List<IceCandidate> ics = new List<IceCandidate>();
                        IceCandidate ice = new IceCandidate(new IpAddressPort(
                          AddressType.IPv4_Address, ReloadGlobals.IPAddressFromHost(
                          m_ReloadConfig, bss.Host), (UInt16)bss.Port),
                          Overlay_Link.TLS_TCP_FH_NO_ICE);

                        // markus: change cand_type to bootstrap
                        ice.cand_type = CandType.tcp_bootstrap;

                        ics.Add(ice);

                        NextHopNode = new Node(reloadRcvMsg == null ?
                          null : reloadRcvMsg.OriginatorID, ics);
                    }

                    try
                    {
                        /* use a new ReloadDialog instance for every usage, Monitor requires it                         */
                        reloadDialog = new ReloadDialog(m_ReloadConfig, m_flm, NextHopNode);

                        if (iCycleBootstrap > 0)
                        {
                            // save transaction id from request to bootstrap
                            if (NextHopNode.IceCandidates[0].addr_port.ipaddr.ToString() == BootstrapServerList[iCycleBootstrap - 1].Host &&
                                NextHopNode.IceCandidates[0].addr_port.port == BootstrapServerList[iCycleBootstrap - 1].Port)
                                bsTransId = reloadSendMsg.TransactionID;
                        }
                   
                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_RELOAD,
                          String.Format("{0} ==> {1} Dest={2} TransId={3:x16}",
                          RELOAD_MessageCode.Attach_Request.ToString().PadRight(16, ' '),
                          NextHopNode, dest.ToString(), reloadSendMsg.TransactionID));

                        Arbiter.Activate(m_DispatcherQueue,
                          new IterativeTask<ReloadMessage, ReloadMessageFilter, int>(
                          reloadSendMsg, new ReloadMessageFilter(reloadSendMsg.TransactionID),
                          RetransmissionTime, reloadDialog.Execute));
                    }
                    catch (Exception ex)
                    {
                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR,
                          "PreJoinProcedure: " + ex.Message);
                    }

                    yield return Arbiter.Receive(false, reloadDialog.Done, done => { });

                    if (!reloadDialog.Error && reloadDialog.ReceivedMessage != null)
                    {
                        if (reloadDialog.ReceivedMessage.TransactionID == bsTransId)
                        {

                            if (reloadDialog.ReceivedMessage.forwarding_header.via_list.Count == 1)
                            {
                                BootstrapServer bsServer = BootstrapServerList[iCycleBootstrap - 1];
                                bsServer.NodeId = reloadDialog.ReceivedMessage.forwarding_header.via_list[0].destination_data.node_id;
                                BootstrapServerList.RemoveAt(iCycleBootstrap - 1);
                                BootstrapServerList.Insert(iCycleBootstrap - 1, bsServer);
                                m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_RELOAD, String.Format("Bootstrap ID: {0}", reloadDialog.ReceivedMessage.forwarding_header.via_list[0].destination_data.node_id));
                                //Console.WriteLine("Bootstrap ID: {0}", reloadDialog.ReceivedMessage.forwarding_header.via_list[0].destination_data.node_id);
                            }
                            else if (reloadDialog.ReceivedMessage.forwarding_header.via_list.Count == 2)
                            {
                                BootstrapServer bsServer = BootstrapServerList[iCycleBootstrap - 1];
                                bsServer.NodeId = reloadDialog.ReceivedMessage.forwarding_header.via_list[1].destination_data.node_id;
                                BootstrapServerList.RemoveAt(iCycleBootstrap - 1);
                                BootstrapServerList.Insert(iCycleBootstrap - 1, bsServer);
                                m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_RELOAD, String.Format("Bootstrap ID: {0}", reloadDialog.ReceivedMessage.forwarding_header.via_list[1].destination_data.node_id));
                                //Console.WriteLine("Bootstrap ID: {0}", reloadDialog.ReceivedMessage.forwarding_header.via_list[1].destination_data.node_id);
                            }

                            bsTransId = 0;
                        }

                        break;
                    }




                    /* still bootstrapping, allow cycling trough different bootstraps by
                     * resetting NextHopNode
                     */
                    if (i == 0)
                        NextHopNode = null;

                    /* If a response has not been received when the timer fires, the request
                       is retransmitted with the same transaction identifier. 
                    */
                    --iRetrans;
                    if (iRetrans >= 0)
                    {
                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_WARNING, String.Format("Retrans {0} Attach  {1} TransId={2:x16}", iRetrans, NextHopNode, reloadSendMsg.TransactionID));
                        m_statistics.IncRetransmission();
                    }
                    else
                    {
                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR, String.Format("Failed! Attach {0} TransId={1:x16}", NextHopNode, reloadSendMsg.TransactionID));
                        m_statistics.IncTransmissionError();
                        if (ReloadGlobals.AutoExe)
                        {
                            m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR, "PreJoin: Exit because initial Attach Faild!");
                            m_machine.SendCommand("Exit");
                        }
                    }
                }
                try
                {
                    if (reloadDialog != null && !reloadDialog.Error && reloadDialog.ReceivedMessage != null)
                    {
                        //the SourceNodeID delivered from reloadDialog comes from connection table and is the last hop of the message
                        reloadRcvMsg = reloadDialog.ReceivedMessage;
                        RELOAD_MessageCode msgCode = reloadRcvMsg.reload_message_body.RELOAD_MsgCode;
                        if (reloadRcvMsg != null)
                        {
                            if (msgCode == RELOAD_MessageCode.Attach_Answer)
                            {
                                m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_RELOAD,
                                  String.Format("{0} <== {1} last={2} TransId={3:x16}",
                                  msgCode.ToString().PadRight(16, ' '), reloadRcvMsg.OriginatorID,
                                  reloadRcvMsg.LastHopNodeId, reloadRcvMsg.TransactionID));

                                AttachReqAns answ = (AttachReqAns)reloadRcvMsg.reload_message_body;

                                if (answ != null)
                                {
                                    m_ReloadConfig.State = ReloadConfig.RELOAD_State.PreJoin;
                                    m_machine.StateUpdates(ReloadConfig.RELOAD_State.PreJoin);

                                    /*  An Attach in and of itself does not result in updating the routing
                                     *  table of either node.
                                     *  Note: We use the routing table here only for storing ice candidates 
                                     *  for later use, we will not update successor or predecessor list
                                     */
                                    NextHopNode = new Node(reloadRcvMsg.OriginatorID, answ.ice_candidates);
                                    /*  An Attach in and of itself does not result in updating the routing
                                     *  table of either node.
                                     *  Note: We use the routing table here only for storing ice candidates 
                                     *  for later use, we will not update successor or predecessor list
                                     */
                                    m_topology.routing_table.AddNode(NextHopNode);
                                    m_topology.routing_table.SetNodeState(NextHopNode.Id,
                                      NodeState.attached);

                                    if (CheckAndSetAdmittingPeer(NextHopNode) &&
                                      NextHopNode.Id != reloadRcvMsg.LastHopNodeId)
                                        // Send ping to establish a physical connection
                                        Arbiter.Activate(m_DispatcherQueue,
                                          new IterativeTask<Destination, PingOption>(new Destination(
                                          NextHopNode.Id), PingOption.direct, SendPing));

                                    if (m_ReloadConfig.IamClient)
                                    {
                                        m_ReloadConfig.LastJoinedTime = DateTime2.Now;
                                        TimeSpan joiningTime = m_ReloadConfig.LastJoinedTime - m_ReloadConfig.StartJoinMobile;
                                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_MEASURE,
                                          "Join:" + joiningTime.TotalSeconds.ToString());
                                    }

                                    attached = true;
                                }
                            }
                            else if (msgCode == RELOAD_MessageCode.Error)
                            {
                                if (dest.type == DestinationType.node)
                                {
                                    ErrorResponse error = (ErrorResponse)reloadRcvMsg.reload_message_body;

                                    if (error != null)
                                    {
                                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR,
                                          String.Format("Prejoin: Got Error {0} from {1} deleting {2}",
                                            error.ErrorMsg,
                                            reloadRcvMsg.OriginatorID,
                                            dest.destination_data.node_id));

                                        m_topology.routing_table.Leave(dest.destination_data.node_id);
                                    }
                                }
                            }
                        }
                        else
                        {
                            m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR, "PreJoinProcedure: reloadRcvMsg == null!!");
                        }

                        last_destination = dest;
                        dest = new Destination(new ResourceId(reloadRcvMsg.OriginatorID) + (byte)1);
                    }
                    else
                        break;
                }
                catch (Exception ex)
                {
                    m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR, "PreJoinProcedure: " + ex.Message);
                }
            } // End Successor Search

            // FingerTable enrichment
            if (!m_ReloadConfig.IamClient)
            {
                List<FTEntry> fingers = m_topology.routing_table.AttachFingers();
                Port<bool> attachNextPort = null;
                Boolean attachNext = true;
                /* JP SHOULD send Attach requests to initiate connections to each of
                 * the peers in the neighbor table as well as to the desired finger
                 * table entries.
                 */
                foreach (FTEntry finger in fingers)
                {
                    attachNextPort = new Port<bool>();
                    Arbiter.Activate(m_DispatcherQueue,
                      new IterativeTask<FTEntry, Port<bool>>(
                      finger, attachNextPort, AttachFinger));
                    /* Wait for finger attach */
                    yield return Arbiter.Receive(false, attachNextPort, next =>
                    {
                        attachNext = next;
                    });
                    if (!attachNext)
                        break;

                }
            }
            /* see base -18 p.106
            /* 4.  JP MUST enter all the peers it has contacted into its routing
            /*     table.
             */
            m_topology.routing_table.Conn2Route();

            /* Once JP has a reasonable set of connections it is ready to take its 
             * place in the DHT.  It does this by sending a Join to AP.
             */
            if (m_ReloadConfig.AdmittingPeer != null)
                if (!m_ReloadConfig.IamClient)
                {
                    m_ReloadConfig.State = ReloadConfig.RELOAD_State.Joining;
                    m_machine.StateUpdates(ReloadConfig.RELOAD_State.Joining);

                    m_topology.routing_table.SetWaitForJoinAnsw(
                      m_ReloadConfig.AdmittingPeer.Id, true);

                    reloadSendMsg = create_join_req(
                      new Destination(m_ReloadConfig.AdmittingPeer.Id));
                    ReloadDialog reloadDialog = null;

                    int RetransmissionTime = ReloadGlobals.RetransmissionTime + ReloadGlobals.MaxTimeToSendPacket;
                    int iRetrans = ReloadGlobals.MaxRetransmissions;

                    while (iRetrans >= 0 && m_ReloadConfig.State < ReloadConfig.RELOAD_State.Shutdown)
                    {
                        reloadDialog = new ReloadDialog(m_ReloadConfig, m_flm, m_ReloadConfig.AdmittingPeer);

                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_RELOAD, String.Format("{0} ==> {1} TransId={2:x16}", RELOAD_MessageCode.Join_Request.ToString().PadRight(16, ' '), m_ReloadConfig.AdmittingPeer, reloadSendMsg.TransactionID));

                        Arbiter.Activate(m_DispatcherQueue, new IterativeTask<ReloadMessage, ReloadMessageFilter, int>(reloadSendMsg, new ReloadMessageFilter(reloadSendMsg.TransactionID), RetransmissionTime, reloadDialog.Execute));
                        yield return Arbiter.Receive(false, reloadDialog.Done, done => { });

                        if (!reloadDialog.Error && reloadDialog.ReceivedMessage != null)
                            break;

                        /* If a response has not been received when the timer fires, the request
                           is retransmitted with the same transaction identifier. 
                        */
                        --iRetrans;
                        if (iRetrans >= 0)
                        {
                            m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_WARNING, String.Format("Retrans {0} Join  {1} TransId={2:x16}", iRetrans, m_ReloadConfig.AdmittingPeer, reloadSendMsg.TransactionID));
                            m_statistics.IncRetransmission();
                        }
                        else
                        {
                            m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR, String.Format("Failed! Join {0} TransId={1:x16}", m_ReloadConfig.AdmittingPeer, reloadSendMsg.TransactionID));
                            m_statistics.IncTransmissionError();
                        }
                    }

                    try
                    {
                        if (!reloadDialog.Error)
                        {
                            reloadRcvMsg = reloadDialog.ReceivedMessage;
                            RELOAD_MessageCode msgCode = reloadRcvMsg.reload_message_body.RELOAD_MsgCode;
                            if (reloadRcvMsg != null)
                            {
                                if (msgCode == RELOAD_MessageCode.Join_Answer)
                                {
                                    m_topology.routing_table.SetWaitForJoinAnsw(reloadRcvMsg.OriginatorID, false);

                                    m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_RELOAD,
                                      String.Format("{0} <== {1} TransId={2:x16}",
                                      msgCode.ToString().PadRight(16, ' '), reloadRcvMsg.OriginatorID,
                                      reloadRcvMsg.TransactionID));

                                    NodeState nodestate = m_topology.routing_table.GetNodeState(reloadRcvMsg.OriginatorID);

                                    if (nodestate == NodeState.updates_received)
                                    {
                                        /* we previously received an update from admitting peer (maybe 
                                         * race condition), now joining is complete in any other case 
                                         * wait for updates to come from this node */
                                        m_ReloadConfig.State = ReloadConfig.RELOAD_State.Joined;
                                        m_machine.StateUpdates(ReloadConfig.RELOAD_State.Joined);
                                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_RELOAD, String.Format("Joining completed"));
                                        m_ReloadConfig.LastJoinedTime = DateTime.Now;
                                        TimeSpan joiningTime = m_ReloadConfig.LastJoinedTime - m_ReloadConfig.StartJoining;
                                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_MEASURE, String.Format("Join:{0}", joiningTime.TotalSeconds.ToString()));

                                        m_topology.routing_table.SendUpdateToAllNeighbors();
                                    }
                                    else
                                    {
                                        m_ReloadConfig.LastJoinedTime = DateTime.Now;
                                        TimeSpan joiningTime = m_ReloadConfig.LastJoinedTime - m_ReloadConfig.StartTime;
                                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_MEASURE, String.Format("Join:{0}", joiningTime.TotalSeconds.ToString()));

                                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_WARNING,
                                          String.Format("Prejoin: nodestate != update_recv at Node {0}", m_machine.ReloadConfig.ListenPort));
                                    }
                                    //m_topology.routing_table.SendUpdatesToAllFingers();
                                }
                            }
                            else
                            {
                                m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR, "PreJoinProcedure: reloadRcvMsg == null!!");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_ERROR, "PreJoinProcedure: " + ex.Message);
                    }
                }
                else
                {
                    if (m_ReloadConfig.SipUri == "")
                        m_ReloadConfig.SipUri = String.Format("{0}@{1}", ReloadGlobals.HostName,
                            m_ReloadConfig.OverlayName);

                    if (m_ReloadConfig.SipUri != null && m_ReloadConfig.SipUri != "")
                    {
                        // explictite SIP registration as minimal config for RELOAD clients

                        IUsage sipRegistration = m_machine.UsageManager.CreateUsage(Usage_Code_Point.SIP_REGISTRATION,
                                                                         2,
                                                                         m_ReloadConfig.SipUri);
                        sipRegistration.ResourceName = m_ReloadConfig.SipUri;
                        List<StoreKindData> clientRegistrationList = new List<StoreKindData>();
                        StoreKindData sipKindData = new StoreKindData(sipRegistration.KindId,
                                                                      0, new StoredData(sipRegistration.Encapsulate(true)));
                        clientRegistrationList.Add(sipKindData);
                        Arbiter.Activate(m_DispatcherQueue, new IterativeTask<string, List<StoreKindData>>(m_ReloadConfig.SipUri, clientRegistrationList, Store));
                    }
                }
            else
            {
                m_ReloadConfig.Logger(ReloadGlobals.TRACEFLAGS.T_MEASURE,
                  String.Format("PreJoinPredure => Node {0} has no admitting peer = {1}!",
                  m_machine.ReloadConfig.ListenPort, m_ReloadConfig.AdmittingPeer));
                if (ReloadGlobals.AutoExe)
                {
                    m_machine.SendCommand("Exit");
                }
            }
        } // End PreJoin