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