int IMessageController.PullFromPeer(DataHeader header)
 {
     if (this.IsAlive)
     {
         return(CastTargetController.PullFromPeer(header));
     }
     else
     {
         return(0);
     }
 }
        /// <summary>
        /// Removes a previous request based on its contentLocation and old version requested.
        /// </summary>
        /// <param name="request"></param>
        /// <returns>true if the request is removed, false otherwise</returns>
        public bool RemoveOldRequest(DataHeader request)
        {
            lock (this.receiveEntries)
            {

                if (receiveEntries.ContainsKey(request.key))
                {
                    DataHeader h = receiveEntries[request.key];
                    ETagCompare result = ETag.CompareETags(h.GetETag(), request.GetETag());
                    if (result == ETagCompare.SecondIsNewer || result == ETagCompare.Conflict)
                    {
                        // another version of the tag arrived, pull this request and have the new data requested
                        this.receiveEntries.Remove(request.key);
                        return true;
                    }
                }
            }

            // this request is the newest
            return false;
        }
        private void WriteSimpleGetRequest(MemoryStream stream, DataHeader request)
        {
            StreamWriter writer = new StreamWriter(stream, Encoding.ASCII);
            writer.NewLine = NEWLINE;

            writer.WriteLine("{0} {1} HTTP/1.1" , GET, request.key);
            writer.WriteLine("P2P-Sender-List: " + GetStringOf(request.sentFrom));
            writer.WriteLine(SPECIAL_HEADER + ": " + this.local_uid);
            writer.WriteLine();
            writer.Flush();
        }
 /// <summary>
 /// Adds a request to get data from the remote side.
 /// Call RemoveOldRequest() before this method.
 /// </summary>
 /// <param name="h"></param>
 public void AddRequest(DataHeader h)
 {
     lock (this.receiveEntries)
     {
         this.receiveEntries.Add(h.key, h);
     }
     lock(this.sendQueue)
     {
         this.sendQueue.Enqueue(h.key);
     }
 }
        /// <summary>
        /// Reads data using only header information. Can be used by ReadDictionary
        /// so it handles deleted content too.
        /// </summary>
        /// <param name="contentLocation">Location of the data item without /proxy</param>
        /// <param name="contentType">GetMime()</param>
        /// <param name="eTag">Version number</param>
        /// <param name="addEntryToSender">These are entries that the sender does not know about</param>
        /// <param name="getEntryFromSender">This function fills in a list of entries that need to be requested from the sender</param>
        private ResponseAction ReadDataStub(string contentLocation, string contentType, string eTag, 
            List<int> sentFromList, out DataHeader getEntryFromSender, out SendMemoryToPeer addEntryToSender)
        {
            ResponseAction success = ResponseAction.DoNotForward;
            ETag tag = ReadETag(eTag);

            DataEntry get = null;
            getEntryFromSender = null;
            addEntryToSender = null;

            // create a stub of the item
            DataEntry create = new DataEntry(contentLocation, tag, sentFromList);
            create.subscribed = keysToListen.IsSubscribed(contentLocation);
            create.SetMime(contentType);

            // manually erase the value (TODO, don't erase the value)
            // always default to singleton because we assume that a GET is required to complete the request
            if (create.type != Data.ValueType.Removed)
                create.value = DataMissing.Singleton;

            this.dataLock.EnterUpgradeableReadLock();
            try
            {
                if (this.data.ContainsKey(contentLocation))
                {
                    // update the version number of the stub
                    get = this.data[contentLocation];
                }
                else
                {
                    this.dataLock.EnterWriteLock();
                    try
                    {
                        this.data.Add(contentLocation, create);
                    }
                    finally { this.dataLock.ExitWriteLock(); }

                    if (create.subscribed && DataMissing.IsSingleton(create.value))
                    {
                        // we'll have to wait for the data to arrive on the wire
                        // actually get the data
                        getEntryFromSender = new DataHeader(contentLocation, tag, sentFromList);
                        success = ResponseAction.DoNotForward;
                    }
                    else
                    {
                        success = ResponseAction.ForwardToSuccessor;
                    }

                }
            }

            finally
            {
                this.dataLock.ExitUpgradeableReadLock();
            }

            if (get != null)
            {
                lock (get)
                {
                    if (create.subscribed)
                    {
                        ETagCompare compareResult = ETag.CompareETags(tag, get.GetETag());

                        if (compareResult == ETagCompare.FirstIsNewer ||
                            compareResult == ETagCompare.Same || compareResult == ETagCompare.Conflict)
                        {
                            getEntryFromSender = new DataHeader(create.key, create.GetETag(), sentFromList);
                            success = ResponseAction.DoNotForward;
                        }
                        else //if (compareResult == ETagCompare.SecondIsNewer )
                        {
                            // i know about something newer than the sender, tell the sender
                            //SendMemoryToPeer mem = new SendMemoryToPeer(get.key,sentFromList);
                            //ResponseHeadStub(HEAD, get.key, GetListOfThisLocalID(), 0, get.GetMime(), get.GetETag(), get.IsEmpty, mem.MemBuffer, false);
                            //addEntryToSender = mem;

                            // well, predecessor already been handled above, so we only need to tell
                            // the others
                            success = ResponseAction.ForwardToAll;
                        }
                    }
                    else
                    {
                        // not subscribed
                        // just record the fact that there is newer data on the wire; cannot resolve conflicts without being a subscriber
                        ETagCompare compareResult = ETag.CompareETags(create.GetETag(), get.GetETag());
                        if (compareResult == ETagCompare.FirstIsNewer || compareResult == ETagCompare.Same || compareResult == ETagCompare.Conflict)
                        {
                            get.lastOwnerID = create.lastOwnerID;
                            get.lastOwnerRevision = create.lastOwnerRevision;
                            get.value = DataMissing.Singleton;

                            if (compareResult != ETagCompare.Same)
                            {
                                get.senderPath = create.senderPath;

                                success = ResponseAction.ForwardToSuccessor;
                            }
                            else
                                success = ResponseAction.DoNotForward;
                        }
                        else // if (compareResult == ETagCompare.SecondIsNewer )
                        {
                            //// i know about something newer than the sender
                            //SendMemoryToPeer mem = new SendMemoryToPeer(get.key,sentFromList);
                            //ResponseHeadStub(HEAD, get.key, GetListOfThisLocalID(), 0, get.GetMime(), get.GetETag(), get.IsEmpty, mem.MemBuffer, false);
                            //addEntryToSender = mem;

                            // tell the others too (already told predecessor above)
                            success = ResponseAction.ForwardToAll;
                        }
                    }
                }
            }

            return success;
        }
        private void HandleReadPush(string contentLocation, string contentType, string eTag, List<int> senders, int lastSender, List<int> responsePath)
        {
            ETag tag = ReadETag(eTag);

            if (contentLocation == DATA_NAMESPACE)
            {
                //// tell others that a new dictionary entered
                //// add to wire to send out
                //SendMemory sendMsg = new SendMemory(senders);
                //ResponseDictionary(verb, sendMsg.MemBuffer, senders, false);
                //controller.BroadcastToWire(sendMsg);

                // don't forward message because the GET method call will do it

                // let me update my model first by
                // requesting to pull data from the other side
                // before sending out a HEAD
                DataHeader hdr = new DataHeader(contentLocation, tag, lastSender);
                controller.PullFromPeer(hdr);

            }
            else
            {
                if (contentLocation.StartsWith(PROXY_PREFIX + "/"))
                {
                    // this is a pushed message from a proxy request
                    // so I should subscribe to the key

                    contentLocation = contentLocation.Substring(PROXYPREFIX_REMOVE);
                    throw new NotImplementedException();
                }

                DataHeader getEntryFromSender;
                SendMemoryToPeer addEntryToSender;

                ResponseAction action = ReadDataStub(contentLocation, contentType, eTag, new List<int>(senders), out getEntryFromSender, out addEntryToSender);

                if (action == ResponseAction.ForwardToAll)
                {
                    senders.Clear();
                }

                if (action != ResponseAction.DoNotForward)
                {
                    // forward a HEAD message (because we didn't do it when we got a 200/HEAD notification)
                    DataEntry get = P2PDictionary.GetEntry(this.data, this.dataLock, contentLocation);
                    System.Diagnostics.Debug.Assert(get != null);

                    senders.Add(this.local_uid);
                    SendBroadcastMemory sendMsg = new SendBroadcastMemory(contentLocation, senders);
                    WriteMethodPush(contentLocation, senders, responsePath, 0, get.GetMime(), get.GetETag(), get.IsDeleted, false, sendMsg.MemBuffer);
                    controller.BroadcastToWire(sendMsg);
                }

                if (getEntryFromSender != null)
                {
                    // and get data from the caller
                    controller.PullFromPeer(getEntryFromSender);
                }

                if (addEntryToSender != null)
                {
                    // send any updates to the peer
                    controller.SendToPeer(addEntryToSender);
                }
            }
        }
 int IMessageController.PullFromPeer(DataHeader header)
 {
     if (this.IsAlive)
         return CastTargetController.PullFromPeer(header);
     else
         return 0;
 }