source: trunk/CrypPlugins/PeerToPeerBase/PeerToPeerBase.cs @ 1261

Last change on this file since 1261 was 1261, checked in by Matthäus Wander, 12 years ago
  • new pap dlls, should fix thread stuck after shutdown (thanks Seb)
  • underlying interface change for configuring Snal settings
File size: 29.8 KB
Line 
1/* Copyright 2009 Team CrypTool (Christian Arnold), Uni Duisburg-Essen
2
3   Licensed under the Apache License, Version 2.0 (the "License");
4   you may not use this file except in compliance with the License.
5   You may obtain a copy of the License at
6
7       http://www.apache.org/licenses/LICENSE-2.0
8
9   Unless required by applicable law or agreed to in writing, software
10   distributed under the License is distributed on an "AS IS" BASIS,
11   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   See the License for the specific language governing permissions and
13   limitations under the License.
14*/
15
16using System;
17using System.Collections.Generic;
18using System.Linq;
19using System.Text;
20using PeersAtPlay.P2PStorage.DHT;
21using PeersAtPlay.P2PStorage.FullMeshDHT;
22using PeersAtPlay.P2POverlay.Bootstrapper;
23using PeersAtPlay.P2POverlay;
24using PeersAtPlay.P2POverlay.Bootstrapper.LocalMachineBootstrapper;
25using PeersAtPlay.P2POverlay.FullMeshOverlay;
26using PeersAtPlay.P2PLink;
27using PeersAtPlay.P2POverlay.Bootstrapper.IrcBootstrapper;
28using System.Threading;
29using Cryptool.PluginBase.Control;
30using System.ComponentModel;
31using PeersAtPlay;
32using PeersAtPlay.Util.Logging;
33using Gears4Net;
34
35/* TODO:
36 * - Catch errors, which can occur when using the DHT (network-based errors)
37 */
38
39/* - Synchronous functions successfully tested (store, retrieve)
40 * - The DHT has an integrated versioning system. When a peer wants
41 *   to store data in an entry, which already holds data, the version
42 *   number will be compared with the peers' version number. If the
43 *   peer hasn't read/write the entry the last time, the storing instruction
44 *   will be rejected. You must first read the actual data and than you can
45 *   store your data in this entry...
46 *
47 * INFO:
48 * - Have considered the DHT-own versioning system in the SynchStore method.
49 *   If this versioning system will be abolished, the SynchStore method must
50 *   be change!
51 * - Everything switched to SnalNG, SimpleSnal isn't used anymore, because
52 *   certification stuff runs now
53 *
54 * TODO:
55 * - Delete UseNatTraversal-Flag and insert CertificateCheck and CertificateSetup
56 * - Testing asynchronous methods incl. EventHandlers
57 */
58namespace Cryptool.Plugins.PeerToPeer
59{
60    /* Advantages of this wrapper class:
61     * - The PeerAtPlay-Libraries are only referenced in this project
62     *   --> so they're easy to update
63     * - PeerAtPlay only works with asynchronous methods, so this class
64     *   "synchronizes" this methods.
65     * - The PeerToPeer-Layers are unimportant for CT2-Developers, so this
66     *   issue is obfuscated by this wrapper class
67     */
68    /// <summary>
69    /// Wrapper class to integrate peer@play environment into CrypTool.
70    /// This class synchronizes asynchronous methods for easier usage in CT2. For future
71    /// </summary>
72    public class P2PBase
73    {
74        #region Delegates and Events for asynchronous p2p functions
75
76        public delegate void SystemJoined();
77        public event SystemJoined OnSystemJoined;
78
79        public delegate void SystemLeft();
80        public event SystemLeft OnSystemLeft;
81
82        public delegate void P2PMessageReceived(PeerId sourceAddr, byte[] data);
83        public event P2PMessageReceived OnP2PMessageReceived;
84
85        /// <summary>
86        /// returns true if key-value-pair is successfully stored in the DHT
87        /// </summary>
88        /// <param name="result"></param>
89        public delegate void DHTStoreCompleted(bool result);
90        public event DHTStoreCompleted OnDhtStore_Completed;
91
92        public delegate void DHTLoadCompleted(byte[] loadedData);
93        public event DHTLoadCompleted OnDhtLoad_Completed;
94
95        /// <summary>
96        /// returns true if key was found and removed successfully from the DHT
97        /// </summary>
98        /// <param name="result"></param>
99        public delegate void DHTRemoveCompleted(bool result);
100        public event DHTRemoveCompleted OnDhtRemove_Completed;
101
102        #endregion
103
104        #region Variables
105
106        private bool allowLoggingToMonitor;
107        /// <summary>
108        /// If true, all kinds of actions will be logged in the PeersAtPlay LogMonitor.
109        /// </summary>
110        public bool AllowLoggingToMonitor
111        {
112            get { return this.allowLoggingToMonitor; }
113            set { this.allowLoggingToMonitor = value; }
114        }
115
116        private const bool ALLOW_LOGGING_TO_MONITOR = true;
117
118        private bool started = false;
119        /// <summary>
120        /// True if system was successfully joined, false if system is COMPLETELY left
121        /// </summary>
122        public bool Started
123        {
124            get { return this.started; }
125            private set { this.started = value; } 
126        }
127
128        private IDHT dht;
129        private IP2PLinkManager linkmanager;
130        private IBootstrapper bootstrapper;
131        private P2POverlay overlay;
132        private AutoResetEvent systemJoined;
133        private AutoResetEvent systemLeft;
134
135        /// <summary>
136        /// Dictionary for synchronizing asynchronous DHT retrieves.
137        /// Cryptool doesn't offers an asynchronous environment, so this workaround is necessary
138        /// </summary>
139        private Dictionary<Guid, ResponseWait> waitDict;
140
141        #endregion
142
143        public P2PBase()
144        {
145            this.waitDict = new Dictionary<Guid, ResponseWait>();
146            this.systemJoined = new AutoResetEvent(false);
147            this.systemLeft = new AutoResetEvent(false);
148        }
149
150        #region Basic P2P Methods (Init, Start, Stop) - synch and asynch
151
152        /// <summary>
153        /// Initializing is the first step to build a new or access an existing p2p network
154        /// </summary>
155        /// <param name="sUserName">Choose an individual name for the user</param>
156        /// <param name="sWorldName">fundamental: two peers are only in the SAME
157        /// P2P system, when they initialized the SAME WORLD!</param>
158        /// <param name="bolUseNatTraversal">When you want to use NAT-Traversal #
159        /// (tunneling the P2P connection through NATs and Firewalls), you have to
160        /// set this flag to true</param>
161        /// <param name="linkManagerType"></param>
162        /// <param name="bsType"></param>
163        /// <param name="overlayType"></param>
164        /// <param name="dhtType"></param>
165        public void Initialize(string sUserName, string sWorldName, P2PLinkManagerType linkManagerType, P2PBootstrapperType bsType, P2POverlayType overlayType, P2PDHTType dhtType)
166        {
167            #region Setting LinkManager, Bootstrapper, Overlay and DHT to the specified types
168
169            Scheduler scheduler = new STAScheduler("pap");
170
171            switch (linkManagerType)
172            {
173                case P2PLinkManagerType.Snal:
174                    LogToMonitor("Init LinkMgr: Using NAT Traversal stuff");
175                    // NAT-Traversal stuff needs a different Snal-Version
176                    this.linkmanager = new PeersAtPlay.P2PLink.SnalNG.Snal(scheduler);
177
178                    PeersAtPlay.P2PLink.SnalNG.Settings settings = new PeersAtPlay.P2PLink.SnalNG.Settings();
179                    settings.LoadDefaults();
180                    settings.ConnectInternal = true;
181                    settings.LocalReceivingPort = 0;
182                    settings.UseLocalAddressDetection = false;
183                    settings.AutoReconnect = false;
184                    settings.NoDelay = false;
185                    settings.ReuseAddress = false;
186                    settings.UseNetworkMonitorServer = true;
187
188                    this.linkmanager.Settings = settings;
189
190                    break;
191                default:
192                    throw (new NotImplementedException());
193            }
194            switch (bsType)
195            {
196                case P2PBootstrapperType.LocalMachineBootstrapper:
197                    //LocalMachineBootstrapper = only local connection (runs only on one machine)
198                    this.bootstrapper = new LocalMachineBootstrapper();
199                    break;
200                case P2PBootstrapperType.IrcBootstrapper:
201                    // setup nat traversal stuff
202                    LogToMonitor("Init Bootstrapper: Using NAT Traversal stuff");
203                    PeersAtPlay.P2POverlay.Bootstrapper.IrcBootstrapper.Settings.DelaySymmetricResponse = true;
204                    PeersAtPlay.P2POverlay.Bootstrapper.IrcBootstrapper.Settings.IncludeSymmetricInResponse = false;
205                    PeersAtPlay.P2POverlay.Bootstrapper.IrcBootstrapper.Settings.SymmetricResponseDelay = 6000;
206
207                    this.bootstrapper = new IrcBootstrapper(scheduler);
208                    break;
209                default:
210                    throw (new NotImplementedException());
211            }
212            switch (overlayType)
213            {
214                case P2POverlayType.FullMeshOverlay:
215                    // changing overlay example: this.overlay = new ChordOverlay();
216                    this.overlay = new FullMeshOverlay(scheduler);
217                    break;
218                default:
219                    throw (new NotImplementedException());
220            }
221            switch (dhtType)
222            {
223                case P2PDHTType.FullMeshDHT:
224                    this.dht = new FullMeshDHT(scheduler);
225                    break;
226                default:
227                    throw (new NotImplementedException());
228            }
229            #endregion
230
231            this.overlay.MessageReceived += new EventHandler<OverlayMessageEventArgs>(overlay_MessageReceived);
232            this.dht.SystemJoined += new EventHandler(OnDHT_SystemJoined);
233            this.dht.SystemLeft += new EventHandler<SystemLeftEventArgs>(OnDHT_SystemLeft);
234
235            this.dht.Initialize(sUserName, "", sWorldName, this.overlay, this.bootstrapper, this.linkmanager, null);
236        }
237
238        /// <summary>
239        /// Starts the P2P System. When the given P2P world doesn't exist yet,
240        /// inclusive creating the and bootstrapping to the P2P network.
241        /// In either case joining the P2P world.
242        /// This synchronized method returns true not before the peer has
243        /// successfully joined the network (this may take one or two minutes).
244        /// </summary>
245        /// <returns>True, if the peer has completely joined the p2p network</returns>
246        public bool SynchStart()
247        {
248            //Start != system joined
249            //Only starts the system asynchronous, the possible callback is useless,
250            //because it's invoked before the peer completly joined the P2P system
251            this.dht.BeginStart(null);
252            //Wait for event SystemJoined. When it's invoked, the peer completly joined the P2P system
253            this.systemJoined.WaitOne();
254            return true;
255        }
256
257        /// <summary>
258        /// Disjoins the peer from the system. The P2P system survive while one peer is still in the network.
259        /// </summary>
260        /// <returns>True, if the peer has completely disjoined the p2p network</returns>
261        public bool SynchStop()
262        {
263            if (this.dht != null)
264            {
265                this.dht.BeginStop(null);
266                //don't stop anything else, because BOOM
267
268                //wait till systemLeft Event is invoked
269                this.systemLeft.WaitOne();
270            }
271            return true;
272        }
273
274        /// <summary>
275        /// Asynchronously starting the peer. When the given P2P world doesn't
276        /// exist yet, inclusive creating the and bootstrapping to the P2P network.
277        /// In either case joining the P2P world. To ensure that peer has successfully
278        /// joined the p2p world, catch the event OnSystemJoined.
279        /// </summary>
280        public void AsynchStart()
281        {
282            // no callback usefull, because starting and joining isn't the same
283            // everything else is done by the EventHandler OnDHT_SystemJoined
284            this.dht.BeginStart(null);
285        }
286
287        /// <summary>
288        /// Asynchronously disjoining the actual peer of the p2p system. To ensure
289        /// disjoining, catch the event OnDHT_SystemLeft.
290        /// </summary>
291        public void AsynchStop()
292        {
293            if (this.dht != null)
294            {
295                // no callback usefull.
296                // Everything else is done by the EventHandler OnDHT_SystemLeft
297                this.dht.BeginStop(null);
298            }
299        }
300
301        #endregion
302
303        /// <summary>
304        /// Get PeerName of the actual peer
305        /// </summary>
306        /// <param name="sPeerName">out: additional peer information UserName on LinkManager</param>
307        /// <returns>PeerID as a String</returns>
308        public PeerId GetPeerID(out string sPeerName)
309        {
310            sPeerName = this.linkmanager.UserName;
311            return new PeerId(this.overlay.LocalAddress);
312        }
313
314        /// <summary>
315        /// Construct PeerId object for a specific byte[] id
316        /// </summary>
317        /// <param name="byteId">overlay address as byte array</param>
318        /// <returns>corresponding PeerId for given byte[] id</returns>
319        public PeerId GetPeerID(byte[] byteId)
320        {
321            LogToMonitor("GetPeerID: Converting byte[] to PeerId-Object");
322            return new PeerId(this.overlay.GetAddress(byteId));
323        }
324
325        // overlay.LocalAddress = Overlay-Peer-Address/Names
326        public void SendToPeer(byte[] data, byte[] destinationPeer)
327        {
328            // get stack size of the pap use-data and add own use data (for optimizing Stack size)
329            int realStackSize = this.overlay.GetHeaderSize() + data.Length;
330            ByteStack stackData = new ByteStack(realStackSize);
331
332            stackData.Push(data);
333
334            OverlayAddress destinationAddr = this.overlay.GetAddress(destinationPeer);
335            OverlayMessage overlayMsg = new OverlayMessage(MessageReceiverType.P2PBase,
336                this.overlay.LocalAddress, destinationAddr, stackData);
337            this.overlay.Send(overlayMsg);
338        }
339
340        private void overlay_MessageReceived(object sender, OverlayMessageEventArgs e)
341        {
342            if (OnP2PMessageReceived != null)
343            {
344                PeerId pid = new PeerId(e.Message.Source);
345                /* You have to fire this event asynchronous, because the main
346                 * thread will be stopped in this wrapper class for synchronizing
347                 * the asynchronous stuff (AutoResetEvent) --> so this could run
348                 * into a deadlock, when you fire this event synchronous (normal Invoke)
349                 * ATTENTION: This could change the invocation order!!! In my case
350                              no problem, but maybe in future cases... */
351                OnP2PMessageReceived.BeginInvoke(pid, e.Message.Data.PopBytes(e.Message.Data.CurrentStackSize),null,null);
352                //OnP2PMessageReceived(pid, e.Message.Data.PopUTF8String());
353            }
354        }
355
356        #region Event Handling (System Joined, Left and Message Received)
357
358        private void OnDHT_SystemJoined(object sender, EventArgs e)
359        {
360            if (OnSystemJoined != null)
361                OnSystemJoined();
362            this.systemJoined.Set();
363            Started = true;
364        }
365
366        private void OnDHT_SystemLeft(object sender, SystemLeftEventArgs e)
367        {
368            if (OnSystemLeft != null)
369                OnSystemLeft();
370            // as an experiment
371            this.dht = null;
372            this.systemLeft.Set();
373            Started = false;
374
375            LogToMonitor("OnDHT_SystemLeft has nulled the dht and setted the systemLeft Waithandle");
376        }
377
378        #endregion
379
380        /* Attention: The asynchronous methods are not tested at the moment */
381        #region Asynchronous Methods incl. Callbacks
382
383        /// <summary>
384        /// Asynchronously retrieving a key from the DHT. To get value, catch
385        /// event OnDhtLoad_Completed.
386        /// </summary>
387        /// <param name="sKey">Existing key in DHT</param>
388        public void AsynchRetrieve(string sKey)
389        {
390            Guid g = this.dht.Retrieve(OnAsynchRetrieve_Completed, sKey);
391        }
392        private void OnAsynchRetrieve_Completed(RetrieveResult rr)
393        {
394            if (OnDhtLoad_Completed != null)
395            {
396                OnDhtLoad_Completed(rr.Data);
397            }
398        }
399
400        /// <summary>
401        /// Asynchronously storing a Key-Value-Pair in the DHT. To ensure that
402        /// storing is completed, catch event OnDhtStore_Completed.
403        /// </summary>
404        /// <param name="sKey"></param>
405        /// <param name="sValue"></param>
406        public void AsynchStore(string sKey, string sValue)
407        {
408            //this.dht.Store(OnAsynchStore_Completed, sKey, UTF8Encoding.UTF8.GetBytes(sValue), IGNORE_DHT_VERSIONING_SYSTEM);
409            this.dht.Store(OnAsynchStore_Completed, sKey, UTF8Encoding.UTF8.GetBytes(sValue));
410        }
411
412        private void OnAsynchStore_Completed(StoreResult sr)
413        {
414            if (OnDhtStore_Completed != null)
415            {
416                if (sr.Status == OperationStatus.Success)
417                    OnDhtStore_Completed(true);
418                else
419                    OnDhtStore_Completed(false);
420            }
421               
422        }
423
424        /// <summary>
425        /// Asynchronously removing an existing key out of the DHT. To ensure
426        /// that removing is completed, catch event OnDhtRemove_Completed.
427        /// </summary>
428        /// <param name="sKey"></param>
429        public void AsynchRemove(string sKey)
430        {
431            //this.dht.Remove(OnAsynchRemove_Completed, sKey, IGNORE_DHT_VERSIONING_SYSTEM);
432            this.dht.Remove(OnAsynchRemove_Completed, sKey);
433        }
434        private void OnAsynchRemove_Completed(RemoveResult rr)
435        {
436            if (OnDhtRemove_Completed != null)
437            {
438                if(rr.Status == OperationStatus.Success)
439                    OnDhtRemove_Completed(true);
440                else
441                    OnDhtRemove_Completed(false);
442            }
443        }
444
445        #endregion
446
447        #region Synchronous Methods incl. Callbacks
448
449        #region SynchStore incl.Callback and SecondTrialCallback
450
451        /// <summary>
452        /// Stores a value in the DHT at the given key
453        /// </summary>
454        /// <param name="sKey">Key of DHT Entry</param>
455        /// <param name="byteData">Value of DHT Entry</param>
456        /// <returns>True, when storing is completed!</returns>
457        public bool SynchStore(string sKey, byte[] byteData)
458        {
459            LogToMonitor("Begin: SynchStore. Key: " + sKey + ", Data: " + Encoding.UTF8.GetString(byteData));
460            AutoResetEvent are = new AutoResetEvent(false);
461            // this method returns always a GUID to distinguish between asynchronous actions
462            Guid g = this.dht.Store(OnSynchStoreCompleted, sKey, byteData);
463
464            ResponseWait rw = new ResponseWait() { WaitHandle = are, key=sKey , value = byteData };
465
466            waitDict.Add(g, rw);
467            //blocking till response
468            are.WaitOne();
469
470            LogToMonitor("End: SynchStore. Key: " + sKey + ". Success: " + rw.success.ToString());
471
472            return rw.success;
473        }
474
475        /// <summary>
476        /// Stores a value in the DHT at the given key
477        /// </summary>
478        /// <param name="sKey">Key of DHT Entry</param>
479        /// <param name="sValue">Value of DHT Entry</param>
480        /// <returns>True, when storing is completed!</returns>
481        public bool SynchStore(string sKey, string sData)
482        {
483            return SynchStore(sKey, UTF8Encoding.UTF8.GetBytes(sData));
484        }
485        /// <summary>
486        /// Callback for a the synchronized store method
487        /// </summary>
488        /// <param name="rr"></param>
489        private void OnSynchStoreCompleted(StoreResult sr)
490        {
491            ResponseWait rw;
492            if (this.waitDict.TryGetValue(sr.Guid, out rw))
493            {
494                // if Status == Error, than the version of the value is out of date.
495                // There is a versioning system in the DHT. So you must retrieve the
496                // key and than store the new value
497                if (sr.Status == OperationStatus.Failure)
498                {
499                    byte[] byteTemp = this.SynchRetrieve(rw.key);
500
501                    // Only try a second time. When it's still not possible, abort storing
502                    AutoResetEvent are = new AutoResetEvent(false);
503                    Guid g = this.dht.Store(OnSecondTrialStoring, rw.key, rw.value);
504                    ResponseWait rw2 = new ResponseWait() { WaitHandle = are, key = rw.key, value = rw.value };
505
506                    waitDict.Add(g, rw2);
507                    // blocking till response
508                    are.WaitOne();
509                    rw.success = rw2.success;
510                    rw.Message = rw2.Message;
511                }
512                else
513                {
514                    rw.Message = UTF8Encoding.UTF8.GetBytes(sr.Status.ToString());
515                    if (sr.Status == OperationStatus.KeyNotFound)
516                        rw.success = false;
517                    else
518                        rw.success = true;
519                }
520            }
521            //unblock WaitHandle in the synchronous method
522            rw.WaitHandle.Set();
523            // don't know if this accelerates the system...
524            this.waitDict.Remove(sr.Guid);
525        }
526
527        private void OnSecondTrialStoring(StoreResult sr)
528        {
529            ResponseWait rw;
530            if (this.waitDict.TryGetValue(sr.Guid, out rw))
531            {
532                if (sr.Status == OperationStatus.Failure)
533                {
534                    //Abort storing, because it's already the second trial
535                    rw.Message = UTF8Encoding.UTF8.GetBytes("Storing also not possible on second trial.");
536                    rw.success = false;
537                }
538                else
539                {
540                    //works the second trial, so it was the versioning system
541                    rw.success = true;
542                }
543            }
544            //unblock WaitHandle in the synchronous method
545            rw.WaitHandle.Set();
546            // don't know if this accelerates the system...
547            this.waitDict.Remove(sr.Guid);
548        }
549
550        #endregion
551
552        /// <summary>
553        /// Get the value of the given DHT Key or null, if it doesn't exist.
554        /// For synchronous environments use the Synch* methods.
555        /// </summary>
556        /// <param name="sKey">Key of DHT Entry</param>
557        /// <returns>Value of DHT Entry</returns>
558        public byte[] SynchRetrieve(string sKey)
559        {
560            LogToMonitor("ThreadId (P2PBase SynchRetrieve): " + Thread.CurrentThread.ManagedThreadId.ToString());
561
562            AutoResetEvent are = new AutoResetEvent(false);
563            // this method returns always a GUID to distinguish between asynchronous actions
564
565            LogToMonitor("Begin: SynchRetrieve. Key: " + sKey);
566             
567            Guid g = this.dht.Retrieve(OnSynchRetrieveCompleted, sKey);
568           
569            ResponseWait rw = new ResponseWait() {WaitHandle = are };
570           
571            waitDict.Add(g,rw  );
572            // blocking till response
573            are.WaitOne();
574
575            LogToMonitor("End: SynchRetrieve. Key: " + sKey + ". Success: " + rw.success.ToString());
576
577            //Rückgabe der Daten
578            return rw.Message;
579        }
580
581        /// <summary>
582        /// Callback for a the synchronized retrieval method
583        /// </summary>
584        /// <param name="rr"></param>
585        private void OnSynchRetrieveCompleted(RetrieveResult rr)
586        {
587            LogToMonitor(rr.Guid.ToString());
588           
589            ResponseWait rw;
590
591            LogToMonitor("ThreadId (P2PBase retrieve callback): " + Thread.CurrentThread.ManagedThreadId.ToString());
592
593            if (this.waitDict.TryGetValue(rr.Guid, out rw))
594            {
595                // successful as long as no error occured
596                rw.success = true;
597                if (rr.Status == OperationStatus.Failure)
598                {
599                    rw.Message = null;
600                    rw.success = false;
601                }
602                else if (rr.Status == OperationStatus.KeyNotFound)
603                    rw.Message = null;
604                else
605                    rw.Message = rr.Data;
606
607                //unblock WaitHandle in the synchronous method
608                rw.WaitHandle.Set();
609                // don't know if this accelerates the system...
610                this.waitDict.Remove(rr.Guid);
611            }
612        }
613        /// <summary>
614        /// Removes a key/value pair out of the DHT
615        /// </summary>
616        /// <param name="sKey">Key of the DHT Entry</param>
617        /// <returns>True, when removing is completed!</returns>
618        public bool SynchRemove(string sKey)
619        {
620            LogToMonitor("Begin SynchRemove. Key: " + sKey);
621
622            AutoResetEvent are = new AutoResetEvent(false);
623            // this method returns always a GUID to distinguish between asynchronous actions
624            Guid g = this.dht.Remove(OnSynchRemoveCompleted, sKey);
625            //Guid g = this.dht.Remove(OnSynchRemoveCompleted, sKey, IGNORE_DHT_VERSIONING_SYSTEM);
626
627            ResponseWait rw = new ResponseWait() { WaitHandle = are };
628
629            waitDict.Add(g, rw);
630            // blocking till response
631            are.WaitOne();
632
633            LogToMonitor("Ended SynchRemove. Key: " + sKey + ". Success: " + rw.success.ToString());
634
635            return rw.success;
636        }
637
638        /// <summary>
639        /// Callback for a the synchronized remove method
640        /// </summary>
641        /// <param name="rr"></param>
642        private void OnSynchRemoveCompleted(RemoveResult rr)
643        {
644            ResponseWait rw;
645            if (this.waitDict.TryGetValue(rr.Guid, out rw))
646            {
647                rw.Message = UTF8Encoding.UTF8.GetBytes(rr.Status.ToString());
648
649                if (rr.Status == OperationStatus.Failure || rr.Status == OperationStatus.KeyNotFound)
650                    rw.success = false;
651                else
652                    rw.success = true;
653
654                //unblock WaitHandle in the synchronous method
655                rw.WaitHandle.Set();
656                // don't know if this accelerates the system...
657                this.waitDict.Remove(rr.Guid);
658            }
659        }
660
661        #endregion
662
663        /// <summary>
664        /// To log the internal state in the Monitoring Software of P@play
665        /// </summary>
666        public void LogInternalState()
667        {
668            if (this.dht != null)
669            {
670                this.dht.LogInternalState();
671            }
672        }
673
674        public void LogToMonitor(string sTextToLog)
675        {
676            if(AllowLoggingToMonitor)
677                Log.Debug(sTextToLog);
678        }
679
680    }
681
682    public class PeerId
683    {
684        private readonly string stringId;
685        private readonly byte[] byteId;
686
687        private const uint OFFSET_BASIS = 2166136261;
688        private const uint PRIME = 16777619; // 2^24 + 2^8 + 0x93
689        private readonly int hashCode;
690
691        public PeerId(OverlayAddress oAddress)
692        {
693            if (oAddress != null)
694            {
695                this.stringId = oAddress.ToString();
696                this.byteId = oAddress.ToByteArray();
697
698                // FNV-1 hashing
699                uint fnvHash = OFFSET_BASIS;
700                foreach (byte b in byteId)
701                {
702                    fnvHash = (fnvHash * PRIME) ^ b;
703                }
704                hashCode = (int)fnvHash;
705            }
706        }
707
708        /// <summary>
709        /// Returns true when the byteId content is identical
710        /// </summary>
711        /// <param name="right"></param>
712        /// <returns></returns>
713        public override bool Equals(object right)
714        {
715            /* standard checks for reference types */
716
717            if (right == null)
718                return false;
719
720            if (object.ReferenceEquals(this, right))
721                return true;
722
723            if (this.GetType() != right.GetType())
724                return false;
725
726            // actual content comparison
727            return this == (PeerId)right;
728        }
729
730        public static bool operator ==(PeerId left, PeerId right)
731        {
732            // because it's possible that one parameter is null, catch this exception
733            /* Begin add - Christian Arnold, 2009.12.16, must cast the parameters, otherwise --> recursion */
734            if ((object)left == (object)right)
735                return true;
736
737            if ((object)left == null || (object)right == null)
738                return false;
739            /* End add */
740
741            if (left.hashCode != right.hashCode)
742                return false;
743
744            if (left.byteId.Length != right.byteId.Length)
745                return false;
746
747            for (int i = 0; i < left.byteId.Length; i++)
748            {
749                // uneven pattern content
750                if (left.byteId[i] != right.byteId[i])
751                    return false;
752            }
753
754            return true;
755        }
756
757        public static bool operator !=(PeerId left, PeerId right)
758        {
759            return !(left == right);
760        }
761
762        public override int GetHashCode()
763        {
764            return hashCode;
765        }
766
767        public override string ToString()
768        {
769            return this.stringId;
770        }
771
772        public byte[] ToByteArray()
773        {
774            return this.byteId;
775        }
776    }
777}
Note: See TracBrowser for help on using the repository browser.