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

Last change on this file since 1200 was 1200, checked in by Arno Wacker, 12 years ago

P2PBase:

  • Update current p2p-dlls (Release/Debug)
  • Adjusted P2PBase for small interface changes in peers@play

P2PPeer:

  • Changed Log internal state to be clickable during Run-mode
File size: 29.5 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            switch (linkManagerType)
169            {
170                case P2PLinkManagerType.Snal:
171                    LogToMonitor("Init LinkMgr: Using NAT Traversal stuff");
172                    // NAT-Traversal stuff needs a different Snal-Version
173                    this.linkmanager = new PeersAtPlay.P2PLink.SnalNG.Snal(new STAScheduler("crypt"));
174
175                    ((PeersAtPlay.P2PLink.SnalNG.Snal)this.linkmanager).Settings.ConnectInternal = true;
176                    ((PeersAtPlay.P2PLink.SnalNG.Snal)this.linkmanager).Settings.LocalReceivingPort = 0;
177                    ((PeersAtPlay.P2PLink.SnalNG.Snal)this.linkmanager).Settings.UseLocalAddressDetection = false;
178                    break;
179                default:
180                    throw (new NotImplementedException());
181            }
182            switch (bsType)
183            {
184                case P2PBootstrapperType.LocalMachineBootstrapper:
185                    //LocalMachineBootstrapper = only local connection (runs only on one machine)
186                    this.bootstrapper = new LocalMachineBootstrapper();
187                    break;
188                case P2PBootstrapperType.IrcBootstrapper:
189                    // setup nat traversal stuff
190                    LogToMonitor("Init Bootstrapper: Using NAT Traversal stuff");
191                    PeersAtPlay.P2POverlay.Bootstrapper.IrcBootstrapper.Settings.DelaySymmetricResponse = true;
192                    PeersAtPlay.P2POverlay.Bootstrapper.IrcBootstrapper.Settings.IncludeSymmetricInResponse = false;
193                    PeersAtPlay.P2POverlay.Bootstrapper.IrcBootstrapper.Settings.SymmetricResponseDelay = 6000;
194
195                    this.bootstrapper = new IrcBootstrapper();
196                    break;
197                default:
198                    throw (new NotImplementedException());
199            }
200            switch (overlayType)
201            {
202                case P2POverlayType.FullMeshOverlay:
203                    // changing overlay example: this.overlay = new ChordOverlay();
204                    this.overlay = new FullMeshOverlay();
205                    break;
206                default:
207                    throw (new NotImplementedException());
208            }
209            switch (dhtType)
210            {
211                case P2PDHTType.FullMeshDHT:
212                    this.dht = new FullMeshDHT();
213                    break;
214                default:
215                    throw (new NotImplementedException());
216            }
217            #endregion
218
219            this.overlay.MessageReceived += new EventHandler<OverlayMessageEventArgs>(overlay_MessageReceived);
220            this.dht.SystemJoined += new EventHandler(OnDHT_SystemJoined);
221            this.dht.SystemLeft += new EventHandler<SystemLeftEventArgs>(OnDHT_SystemLeft);
222
223            this.dht.Initialize(sUserName, "", sWorldName, this.overlay, this.bootstrapper, this.linkmanager, null);
224        }
225
226        /// <summary>
227        /// Starts the P2P System. When the given P2P world doesn't exist yet,
228        /// inclusive creating the and bootstrapping to the P2P network.
229        /// In either case joining the P2P world.
230        /// This synchronized method returns true not before the peer has
231        /// successfully joined the network (this may take one or two minutes).
232        /// </summary>
233        /// <returns>True, if the peer has completely joined the p2p network</returns>
234        public bool SynchStart()
235        {
236            //Start != system joined
237            //Only starts the system asynchronous, the possible callback is useless,
238            //because it's invoked before the peer completly joined the P2P system
239            this.dht.BeginStart(null);
240            //Wait for event SystemJoined. When it's invoked, the peer completly joined the P2P system
241            this.systemJoined.WaitOne();
242            return true;
243        }
244
245        /// <summary>
246        /// Disjoins the peer from the system. The P2P system survive while one peer is still in the network.
247        /// </summary>
248        /// <returns>True, if the peer has completely disjoined the p2p network</returns>
249        public bool SynchStop()
250        {
251            if (this.dht != null)
252            {
253                this.dht.BeginStop(null);
254                //don't stop anything else, because BOOM
255
256                //wait till systemLeft Event is invoked
257                this.systemLeft.WaitOne();
258            }
259            return true;
260        }
261
262        /// <summary>
263        /// Asynchronously starting the peer. When the given P2P world doesn't
264        /// exist yet, inclusive creating the and bootstrapping to the P2P network.
265        /// In either case joining the P2P world. To ensure that peer has successfully
266        /// joined the p2p world, catch the event OnSystemJoined.
267        /// </summary>
268        public void AsynchStart()
269        {
270            // no callback usefull, because starting and joining isn't the same
271            // everything else is done by the EventHandler OnDHT_SystemJoined
272            this.dht.BeginStart(null);
273        }
274
275        /// <summary>
276        /// Asynchronously disjoining the actual peer of the p2p system. To ensure
277        /// disjoining, catch the event OnDHT_SystemLeft.
278        /// </summary>
279        public void AsynchStop()
280        {
281            if (this.dht != null)
282            {
283                // no callback usefull.
284                // Everything else is done by the EventHandler OnDHT_SystemLeft
285                this.dht.BeginStop(null);
286            }
287        }
288
289        #endregion
290
291        /// <summary>
292        /// Get PeerName of the actual peer
293        /// </summary>
294        /// <param name="sPeerName">out: additional peer information UserName on LinkManager</param>
295        /// <returns>PeerID as a String</returns>
296        public PeerId GetPeerID(out string sPeerName)
297        {
298            sPeerName = this.linkmanager.UserName;
299            return new PeerId(this.overlay.LocalAddress);
300        }
301
302        /// <summary>
303        /// Construct PeerId object for a specific byte[] id
304        /// </summary>
305        /// <param name="byteId">overlay address as byte array</param>
306        /// <returns>corresponding PeerId for given byte[] id</returns>
307        public PeerId GetPeerID(byte[] byteId)
308        {
309            LogToMonitor("GetPeerID: Converting byte[] to PeerId-Object");
310            return new PeerId(this.overlay.GetAddress(byteId));
311        }
312
313        // overlay.LocalAddress = Overlay-Peer-Address/Names
314        public void SendToPeer(byte[] data, byte[] destinationPeer)
315        {
316            // get stack size of the pap use-data and add own use data (for optimizing Stack size)
317            int realStackSize = this.overlay.GetHeaderSize() + data.Length;
318            ByteStack stackData = new ByteStack(realStackSize);
319
320            stackData.Push(data);
321
322            OverlayAddress destinationAddr = this.overlay.GetAddress(destinationPeer);
323            OverlayMessage overlayMsg = new OverlayMessage(MessageReceiverType.P2PBase,
324                this.overlay.LocalAddress, destinationAddr, stackData);
325            this.overlay.Send(overlayMsg);
326        }
327
328        private void overlay_MessageReceived(object sender, OverlayMessageEventArgs e)
329        {
330            if (OnP2PMessageReceived != null)
331            {
332                PeerId pid = new PeerId(e.Message.Source);
333                /* You have to fire this event asynchronous, because the main
334                 * thread will be stopped in this wrapper class for synchronizing
335                 * the asynchronous stuff (AutoResetEvent) --> so this could run
336                 * into a deadlock, when you fire this event synchronous (normal Invoke)
337                 * ATTENTION: This could change the invocation order!!! In my case
338                              no problem, but maybe in future cases... */
339                OnP2PMessageReceived.BeginInvoke(pid, e.Message.Data.PopBytes(e.Message.Data.CurrentStackSize),null,null);
340                //OnP2PMessageReceived(pid, e.Message.Data.PopUTF8String());
341            }
342        }
343
344        #region Event Handling (System Joined, Left and Message Received)
345
346        private void OnDHT_SystemJoined(object sender, EventArgs e)
347        {
348            if (OnSystemJoined != null)
349                OnSystemJoined();
350            this.systemJoined.Set();
351            Started = true;
352        }
353
354        private void OnDHT_SystemLeft(object sender, SystemLeftEventArgs e)
355        {
356            if (OnSystemLeft != null)
357                OnSystemLeft();
358            // as an experiment
359            this.dht = null;
360            this.systemLeft.Set();
361            Started = false;
362
363            LogToMonitor("OnDHT_SystemLeft has nulled the dht and setted the systemLeft Waithandle");
364        }
365
366        #endregion
367
368        /* Attention: The asynchronous methods are not tested at the moment */
369        #region Asynchronous Methods incl. Callbacks
370
371        /// <summary>
372        /// Asynchronously retrieving a key from the DHT. To get value, catch
373        /// event OnDhtLoad_Completed.
374        /// </summary>
375        /// <param name="sKey">Existing key in DHT</param>
376        public void AsynchRetrieve(string sKey)
377        {
378            Guid g = this.dht.Retrieve(OnAsynchRetrieve_Completed, sKey);
379        }
380        private void OnAsynchRetrieve_Completed(RetrieveResult rr)
381        {
382            if (OnDhtLoad_Completed != null)
383            {
384                OnDhtLoad_Completed(rr.Data);
385            }
386        }
387
388        /// <summary>
389        /// Asynchronously storing a Key-Value-Pair in the DHT. To ensure that
390        /// storing is completed, catch event OnDhtStore_Completed.
391        /// </summary>
392        /// <param name="sKey"></param>
393        /// <param name="sValue"></param>
394        public void AsynchStore(string sKey, string sValue)
395        {
396            //this.dht.Store(OnAsynchStore_Completed, sKey, UTF8Encoding.UTF8.GetBytes(sValue), IGNORE_DHT_VERSIONING_SYSTEM);
397            this.dht.Store(OnAsynchStore_Completed, sKey, UTF8Encoding.UTF8.GetBytes(sValue));
398        }
399
400        private void OnAsynchStore_Completed(StoreResult sr)
401        {
402            if (OnDhtStore_Completed != null)
403            {
404                if (sr.Status == OperationStatus.Success)
405                    OnDhtStore_Completed(true);
406                else
407                    OnDhtStore_Completed(false);
408            }
409               
410        }
411
412        /// <summary>
413        /// Asynchronously removing an existing key out of the DHT. To ensure
414        /// that removing is completed, catch event OnDhtRemove_Completed.
415        /// </summary>
416        /// <param name="sKey"></param>
417        public void AsynchRemove(string sKey)
418        {
419            //this.dht.Remove(OnAsynchRemove_Completed, sKey, IGNORE_DHT_VERSIONING_SYSTEM);
420            this.dht.Remove(OnAsynchRemove_Completed, sKey);
421        }
422        private void OnAsynchRemove_Completed(RemoveResult rr)
423        {
424            if (OnDhtRemove_Completed != null)
425            {
426                if(rr.Status == OperationStatus.Success)
427                    OnDhtRemove_Completed(true);
428                else
429                    OnDhtRemove_Completed(false);
430            }
431        }
432
433        #endregion
434
435        #region Synchronous Methods incl. Callbacks
436
437        #region SynchStore incl.Callback and SecondTrialCallback
438
439        /// <summary>
440        /// Stores a value in the DHT at the given key
441        /// </summary>
442        /// <param name="sKey">Key of DHT Entry</param>
443        /// <param name="byteData">Value of DHT Entry</param>
444        /// <returns>True, when storing is completed!</returns>
445        public bool SynchStore(string sKey, byte[] byteData)
446        {
447            LogToMonitor("Begin: SynchStore. Key: " + sKey + ", Data: " + Encoding.UTF8.GetString(byteData));
448            AutoResetEvent are = new AutoResetEvent(false);
449            // this method returns always a GUID to distinguish between asynchronous actions
450            Guid g = this.dht.Store(OnSynchStoreCompleted, sKey, byteData);
451
452            ResponseWait rw = new ResponseWait() { WaitHandle = are, key=sKey , value = byteData };
453
454            waitDict.Add(g, rw);
455            //blocking till response
456            are.WaitOne();
457
458            LogToMonitor("End: SynchStore. Key: " + sKey + ". Success: " + rw.success.ToString());
459
460            return rw.success;
461        }
462
463        /// <summary>
464        /// Stores a value in the DHT at the given key
465        /// </summary>
466        /// <param name="sKey">Key of DHT Entry</param>
467        /// <param name="sValue">Value of DHT Entry</param>
468        /// <returns>True, when storing is completed!</returns>
469        public bool SynchStore(string sKey, string sData)
470        {
471            return SynchStore(sKey, UTF8Encoding.UTF8.GetBytes(sData));
472        }
473        /// <summary>
474        /// Callback for a the synchronized store method
475        /// </summary>
476        /// <param name="rr"></param>
477        private void OnSynchStoreCompleted(StoreResult sr)
478        {
479            ResponseWait rw;
480            if (this.waitDict.TryGetValue(sr.Guid, out rw))
481            {
482                // if Status == Error, than the version of the value is out of date.
483                // There is a versioning system in the DHT. So you must retrieve the
484                // key and than store the new value
485                if (sr.Status == OperationStatus.Failure)
486                {
487                    byte[] byteTemp = this.SynchRetrieve(rw.key);
488
489                    // Only try a second time. When it's still not possible, abort storing
490                    AutoResetEvent are = new AutoResetEvent(false);
491                    Guid g = this.dht.Store(OnSecondTrialStoring, rw.key, rw.value);
492                    ResponseWait rw2 = new ResponseWait() { WaitHandle = are, key = rw.key, value = rw.value };
493
494                    waitDict.Add(g, rw2);
495                    // blocking till response
496                    are.WaitOne();
497                    rw.success = rw2.success;
498                    rw.Message = rw2.Message;
499                }
500                else
501                {
502                    rw.Message = UTF8Encoding.UTF8.GetBytes(sr.Status.ToString());
503                    if (sr.Status == OperationStatus.KeyNotFound)
504                        rw.success = false;
505                    else
506                        rw.success = true;
507                }
508            }
509            //unblock WaitHandle in the synchronous method
510            rw.WaitHandle.Set();
511            // don't know if this accelerates the system...
512            this.waitDict.Remove(sr.Guid);
513        }
514
515        private void OnSecondTrialStoring(StoreResult sr)
516        {
517            ResponseWait rw;
518            if (this.waitDict.TryGetValue(sr.Guid, out rw))
519            {
520                if (sr.Status == OperationStatus.Failure)
521                {
522                    //Abort storing, because it's already the second trial
523                    rw.Message = UTF8Encoding.UTF8.GetBytes("Storing also not possible on second trial.");
524                    rw.success = false;
525                }
526                else
527                {
528                    //works the second trial, so it was the versioning system
529                    rw.success = true;
530                }
531            }
532            //unblock WaitHandle in the synchronous method
533            rw.WaitHandle.Set();
534            // don't know if this accelerates the system...
535            this.waitDict.Remove(sr.Guid);
536        }
537
538        #endregion
539
540        /// <summary>
541        /// Get the value of the given DHT Key or null, if it doesn't exist.
542        /// For synchronous environments use the Synch* methods.
543        /// </summary>
544        /// <param name="sKey">Key of DHT Entry</param>
545        /// <returns>Value of DHT Entry</returns>
546        public byte[] SynchRetrieve(string sKey)
547        {
548            LogToMonitor("ThreadId (P2PBase SynchRetrieve): " + Thread.CurrentThread.ManagedThreadId.ToString());
549
550            AutoResetEvent are = new AutoResetEvent(false);
551            // this method returns always a GUID to distinguish between asynchronous actions
552
553            LogToMonitor("Begin: SynchRetrieve. Key: " + sKey);
554             
555            Guid g = this.dht.Retrieve(OnSynchRetrieveCompleted, sKey);
556           
557            ResponseWait rw = new ResponseWait() {WaitHandle = are };
558           
559            waitDict.Add(g,rw  );
560            // blocking till response
561            are.WaitOne();
562
563            LogToMonitor("End: SynchRetrieve. Key: " + sKey + ". Success: " + rw.success.ToString());
564
565            //Rückgabe der Daten
566            return rw.Message;
567        }
568
569        /// <summary>
570        /// Callback for a the synchronized retrieval method
571        /// </summary>
572        /// <param name="rr"></param>
573        private void OnSynchRetrieveCompleted(RetrieveResult rr)
574        {
575            LogToMonitor(rr.Guid.ToString());
576           
577            ResponseWait rw;
578
579            LogToMonitor("ThreadId (P2PBase retrieve callback): " + Thread.CurrentThread.ManagedThreadId.ToString());
580
581            if (this.waitDict.TryGetValue(rr.Guid, out rw))
582            {
583                // successful as long as no error occured
584                rw.success = true;
585                if (rr.Status == OperationStatus.Failure)
586                {
587                    rw.Message = null;
588                    rw.success = false;
589                }
590                else if (rr.Status == OperationStatus.KeyNotFound)
591                    rw.Message = null;
592                else
593                    rw.Message = rr.Data;
594
595                //unblock WaitHandle in the synchronous method
596                rw.WaitHandle.Set();
597                // don't know if this accelerates the system...
598                this.waitDict.Remove(rr.Guid);
599            }
600        }
601        /// <summary>
602        /// Removes a key/value pair out of the DHT
603        /// </summary>
604        /// <param name="sKey">Key of the DHT Entry</param>
605        /// <returns>True, when removing is completed!</returns>
606        public bool SynchRemove(string sKey)
607        {
608            LogToMonitor("Begin SynchRemove. Key: " + sKey);
609
610            AutoResetEvent are = new AutoResetEvent(false);
611            // this method returns always a GUID to distinguish between asynchronous actions
612            Guid g = this.dht.Remove(OnSynchRemoveCompleted, sKey);
613            //Guid g = this.dht.Remove(OnSynchRemoveCompleted, sKey, IGNORE_DHT_VERSIONING_SYSTEM);
614
615            ResponseWait rw = new ResponseWait() { WaitHandle = are };
616
617            waitDict.Add(g, rw);
618            // blocking till response
619            are.WaitOne();
620
621            LogToMonitor("Ended SynchRemove. Key: " + sKey + ". Success: " + rw.success.ToString());
622
623            return rw.success;
624        }
625
626        /// <summary>
627        /// Callback for a the synchronized remove method
628        /// </summary>
629        /// <param name="rr"></param>
630        private void OnSynchRemoveCompleted(RemoveResult rr)
631        {
632            ResponseWait rw;
633            if (this.waitDict.TryGetValue(rr.Guid, out rw))
634            {
635                rw.Message = UTF8Encoding.UTF8.GetBytes(rr.Status.ToString());
636
637                if (rr.Status == OperationStatus.Failure || rr.Status == OperationStatus.KeyNotFound)
638                    rw.success = false;
639                else
640                    rw.success = true;
641
642                //unblock WaitHandle in the synchronous method
643                rw.WaitHandle.Set();
644                // don't know if this accelerates the system...
645                this.waitDict.Remove(rr.Guid);
646            }
647        }
648
649        #endregion
650
651        /// <summary>
652        /// To log the internal state in the Monitoring Software of P@play
653        /// </summary>
654        public void LogInternalState()
655        {
656            if (this.dht != null)
657            {
658                this.dht.LogInternalState();
659            }
660        }
661
662        public void LogToMonitor(string sTextToLog)
663        {
664            if(AllowLoggingToMonitor)
665                Log.Debug(sTextToLog);
666        }
667
668    }
669
670    public class PeerId
671    {
672        private readonly string stringId;
673        private readonly byte[] byteId;
674
675        private const uint OFFSET_BASIS = 2166136261;
676        private const uint PRIME = 16777619; // 2^24 + 2^8 + 0x93
677        private readonly int hashCode;
678
679        public PeerId(OverlayAddress oAddress)
680        {
681            if (oAddress != null)
682            {
683                this.stringId = oAddress.ToString();
684                this.byteId = oAddress.ToByteArray();
685
686                // FNV-1 hashing
687                uint fnvHash = OFFSET_BASIS;
688                foreach (byte b in byteId)
689                {
690                    fnvHash = (fnvHash * PRIME) ^ b;
691                }
692                hashCode = (int)fnvHash;
693            }
694        }
695
696        /// <summary>
697        /// Returns true when the byteId content is identical
698        /// </summary>
699        /// <param name="right"></param>
700        /// <returns></returns>
701        public override bool Equals(object right)
702        {
703            /* standard checks for reference types */
704
705            if (right == null)
706                return false;
707
708            if (object.ReferenceEquals(this, right))
709                return true;
710
711            if (this.GetType() != right.GetType())
712                return false;
713
714            // actual content comparison
715            return this == (PeerId)right;
716        }
717
718        public static bool operator ==(PeerId left, PeerId right)
719        {
720            // because it's possible that one parameter is null, catch this exception
721            /* Begin add - Christian Arnold, 2009.12.16, must cast the parameters, otherwise --> recursion */
722            if ((object)left == (object)right)
723                return true;
724
725            if ((object)left == null || (object)right == null)
726                return false;
727            /* End add */
728
729            if (left.hashCode != right.hashCode)
730                return false;
731
732            if (left.byteId.Length != right.byteId.Length)
733                return false;
734
735            for (int i = 0; i < left.byteId.Length; i++)
736            {
737                // uneven pattern content
738                if (left.byteId[i] != right.byteId[i])
739                    return false;
740            }
741
742            return true;
743        }
744
745        public static bool operator !=(PeerId left, PeerId right)
746        {
747            return !(left == right);
748        }
749
750        public override int GetHashCode()
751        {
752            return hashCode;
753        }
754
755        public override string ToString()
756        {
757            return this.stringId;
758        }
759
760        public byte[] ToByteArray()
761        {
762            return this.byteId;
763        }
764    }
765}
Note: See TracBrowser for help on using the repository browser.