/// <summary> /// Initiates a network query for a session /// </summary> /// <param name="TimeoutHandler">The Action that is called when the query times out</param> /// <returns>True if the network query was initiated. Otherwise, false</returns> protected bool QueryNetwork(System.Threading.WaitCallback TimeoutHandler) { ServiceSocket[] peers = service.LivePeers; if (!service.Settings.StandaloneMode && peers.Length > 0) { if (queryTimeout == null) { queryTimeout = DateTime.UtcNow + new TimeSpan(0, 0, 0, 0, service.Settings.NetworkQueryTimeout); } //Log P2P Querying Network Diags.LogQueryingNetwork(Resource); //Create a new guid as the message id Guid msgID = Guid.NewGuid(); //Add new query to Queries Initiated list (with one minute expiry) service.QueriesInitiated.Add(DateTime.UtcNow + new TimeSpan(0, 1, 0), msgID, null); //To get Origin Host: Get the LocalIP of the server IP + Port of peer listening socket //NOTE: Server IP must be valid within this routine because it is discovered in Server.NewLivePeer() and livePeers > 0 string originEndPoint; { string localhost; int? localport; ServerSettings.HostEndPoint.Parse(service.ServerIP, out localhost, out localport); originEndPoint = new ServerSettings.HostEndPoint(localhost, service.Settings.PeerPort).ToString(); } //Broadcast a GetTransferMessage which will call Process() when the session is returned //and processes TimeoutHandler delegate when the broadcast times out GetTransferMessage.Broadcast (originEndPoint ,new List<ServiceSocket>(peers), service, Resource, msgID, service.Settings.MaxForwards, Guid.Empty, queryTimeout.Value, delegate(string key) { Process(); }, //Found delegate simply reprocesses the request delegate (object key) //Timeout delegate calls the time-out handler { Diags.LogNetworkQueryTimeout(Resource); TimeoutHandler(key); } ); return true; } else { return false; } }
/// <summary> /// Called by the SessionDictionary.BeginExport method to complete processing the request, /// if the requested session was found and read /// </summary> /// <param name="Session">The read session</param> /// <param name="StateObject">The state object passed from the SessionDictionary.BeginExport method</param> private void CompleteTransferRequest(ISessionObject Session, object StateObject) { ISessionResponseInfo response = Session.CreateResponseInfo(); //Get the endpoint for the host to connect to string remoteHost; int? remotePort; ServerSettings.HostEndPoint.Parse(Host,out remoteHost,out remotePort); if(!remotePort.HasValue) remotePort = service.Settings.PeerPort; ServerSettings.HostEndPoint endPoint = new ServerSettings.HostEndPoint(remoteHost.Trim(),remotePort.Value); const int sentTransferExpiryTime = 2; // 2 seconds is sufficient for a broadcast to traverse half a reasonable network #region Callback Delegate declarations //SuccessAction Action<AsyncMessageTracker> successAction = delegate(AsyncMessageTracker asyncMsg) { //Add this transfer to list of recently transferred sessions and have it expire in 15 seconds service.SentTransfers.Add(DateTime.UtcNow + new TimeSpan(0, 0, sentTransferExpiryTime), Resource, null); TransferSuccess(asyncMsg); Diags.LogTransferSuccess(Resource); }; //FailedAction Action<AsyncMessageTracker> failureAction = delegate(AsyncMessageTracker asyncMsg) { TransferFailure(asyncMsg); Diags.LogTransferFailed(Resource, string.Empty); }; //AlreadyExistsAction Action<AsyncMessageTracker> alreadyExistsAction = delegate(AsyncMessageTracker asyncMsg) { //Add this transfer to list of recently transferred sessions and have it expire in 15 seconds service.SentTransfers.Add(DateTime.UtcNow + new TimeSpan(0, 0, sentTransferExpiryTime), Resource, null); TransferSuccess(asyncMsg); Diags.LogTransferFailed(Resource, "Resource already exists in remote peer -- deleted local copy"); }; //PeerShuttingDownAction Action<AsyncMessageTracker> peerShuttingDownAction = delegate(AsyncMessageTracker asyncMsg) { TransferFailure(asyncMsg); Diags.LogTransferFailed(Resource, "Peer is shutting down"); }; //TimeoutAction System.Threading.WaitCallback timeoutAction = delegate(object asyncMsg) { //This anonymous method can be called directly from a background thread so make sure it's exception-safe try { TransferFailure((AsyncMessageTracker)asyncMsg); Diags.LogTransferFailed(Resource, "Timed out"); } catch (Exception ex) { Diags.LogApplicationError( "TimeoutAction delegate error in CompleteTransferRequest", ex); } }; //FailedActionForExistingLink Action<AsyncMessageTracker> failureActionForExistingLink = delegate(AsyncMessageTracker asyncMsg) { Diags.LogTransferFailed(Resource, "Existing link, trying again on new link"); //Try again by reconnecting service.TransferSession(endPoint, Resource, response, Session.Data, successAction, failureAction, alreadyExistsAction, peerShuttingDownAction, timeoutAction); }; #endregion service.NewActiveExport(Resource); //create an entry in the exports list for this export //Look for standing link ServiceSocket linkSocket; if(service.TryGetLinkTo(endPoint, out linkSocket)) { //There is a standing link to this peer so send transfer through it AsyncMessageTracker msg = new AsyncMessageTracker(AsyncMessageOperation.SetTransferOperation, Guid.NewGuid(), linkSocket); service.TransferSession(msg, Resource, response, Session.Data, successAction, failureActionForExistingLink, alreadyExistsAction, peerShuttingDownAction, timeoutAction); } else { //Initiate a brand new connection service.TransferSession(endPoint, Resource, response, Session.Data, successAction,failureAction,alreadyExistsAction,peerShuttingDownAction,timeoutAction); } }