source: trunk/CrypP2P/Internal/P2PBase.cs @ 1374

Last change on this file since 1374 was 1374, checked in by Paul Lelgemann, 12 years ago

+ Added P2P connection to CrypP2P based on PeerToPeerBase plugin (using default settings)
+ Added MD5Collider to CoreDeveloper solution

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