source: trunk/CrypPlugins/PeerToPeerBaseProxy/P2PPeer.cs @ 1438

Last change on this file since 1438 was 1438, checked in by Paul Lelgemann, 12 years ago
  • Removed unused configuration options of PeerToPeerProxy
File size: 17.8 KB
Line 
1/*
2   Copyright 2010 Paul Lelgemann, University of Duisburg-Essen
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections.Generic;
19using System.Linq;
20using System.Text;
21using System.Threading;
22using Cryptool.PluginBase.Control;
23using Cryptool.PluginBase;
24using Cryptool.PluginBase.Miscellaneous;
25using System.ComponentModel;
26using Cryptool.PluginBase.IO;
27using Cryptool.Plugins.PeerToPeer.Internal;
28using Cryptool.P2P;
29using Cryptool.P2P.Internal;
30
31namespace Cryptool.Plugins.PeerToPeerProxy
32{
33    [Author("Paul Lelgemann", "lelgemann@cryptool.org", "Uni Duisburg-Essen", "http://www.uni-due.de")]
34    [PluginInfo(false, "P2P_Peer_Proxy", "Creates a new Peer. Uses the CrypTool2 built-in P2P network and can be used as a replacement for P2P_Peer.", "", "PeerToPeerBaseProxy/icons/peer_inactive.png", "PeerToPeerBaseProxy/icons/peer_connecting.png", "PeerToPeerBaseProxy/icons/peer_online.png", "PeerToPeerBaseProxy/icons/peer_error.png")]
35    public class P2PPeer : IIOMisc
36    {
37        // to forward event from overlay/dht MessageReceived-Event from P2PBase
38        public event P2PBase.P2PMessageReceived OnPeerMessageReceived;
39
40        #region Variables
41
42        private P2PPeerSettings settings;
43        private IP2PControl p2pSlave;
44
45        #endregion
46
47        #region Standard functionality
48
49        public P2PPeer()
50        {
51            this.settings = new P2PPeerSettings(this);
52            this.settings.TaskPaneAttributeChanged += new TaskPaneAttributeChangedHandler(settings_TaskPaneAttributeChanged);
53            this.settings.OnPluginStatusChanged += new StatusChangedEventHandler(settings_OnPluginStatusChanged);
54        }
55
56        public event StatusChangedEventHandler OnPluginStatusChanged;
57        private void settings_OnPluginStatusChanged(IPlugin sender, StatusEventArgs args)
58        {
59            if (OnPluginStatusChanged != null)
60                OnPluginStatusChanged(this, args);
61        }
62
63        // to forward event from overlay/dht MessageReceived-Event from P2PBase
64        private void p2pBase_OnP2PMessageReceived(PeerId sourceAddr, byte[] data)
65        {
66            if (OnPeerMessageReceived != null)
67                OnPeerMessageReceived(sourceAddr, data);
68        }
69
70        void settings_TaskPaneAttributeChanged(ISettings settings, TaskPaneAttributeChangedEventArgs args)
71        {
72            //throw new NotImplementedException();
73        }
74
75        public ISettings Settings
76        {
77            set { this.settings = (P2PPeerSettings)value; }
78            get { return this.settings; }
79        }
80
81        public System.Windows.Controls.UserControl Presentation
82        {
83            get { return null; }
84        }
85
86        public System.Windows.Controls.UserControl QuickWatchPresentation
87        {
88            get { return null; }
89        }
90
91        public void PreExecution()
92        {
93            StartPeer();
94        }
95
96        public void Execute()
97        {
98            // TODO: For future use copy functionality to Execute instead of PreExecute
99            //       so we don't need the workaround anymore!!!
100            // StartPeer();
101        }
102
103        public void PostExecution()
104        {
105        }
106
107        public void Pause()
108        {
109        }
110
111        public void Stop()
112        {
113        }
114
115        public void Initialize()
116        {
117        }
118
119        public void Dispose()
120        {
121            StopPeer();
122        }
123
124        #endregion
125
126        #region IPlugin Members
127
128        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
129
130        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
131
132        #endregion
133
134        #region INotifyPropertyChanged Members
135
136        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
137
138        public void OnPropertyChanged(string name)
139        {
140            EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
141        }
142
143        public event PluginProgressChangedEventHandler OnPluginProcessChanged;
144
145        private void ProgressChanged(double value, double max)
146        {
147            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
148        }
149
150        private void GuiLogMessage(string p, NotificationLevel notificationLevel)
151        {
152            // for evaluation issues only
153            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p + "(" + DebugToFile.GetTimeStamp() + ")", this, notificationLevel));
154            //EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p, this, notificationLevel));
155        }
156
157        #endregion
158
159        #region In and Output
160
161        [PropertyInfo(Direction.ControlSlave, "Master Peer", "One peer to rule them all", "", true, false, DisplayLevel.Beginner, QuickWatchFormat.Text, null)]
162        public IP2PControl P2PControlSlave
163        {
164            get
165            {
166                if (this.p2pSlave == null)
167                    // to commit the settings of the plugin to the IControl
168                    this.p2pSlave = new P2PPeerMaster(this);
169                return this.p2pSlave;
170            }
171        }
172
173        #endregion
174
175        #region Start and Stop Peer
176        /// <summary>
177        /// Status flag for starting and stopping peer only once.
178        /// </summary>
179        public bool PeerStarted()
180        {
181            return P2PManager.Instance.P2PConnected();
182        }
183
184        public void StartPeer()
185        {
186            this.settings.PeerStatusChanged(P2PPeerSettings.PeerStatus.Connecting);
187            P2PManager.Instance.P2PBase.OnP2PMessageReceived += new P2PBase.P2PMessageReceived(p2pBase_OnP2PMessageReceived);
188
189            if (P2PManager.Instance.P2PConnected())
190            {
191                GuiLogMessage("P2P connected.", NotificationLevel.Info);
192                this.settings.PeerStatusChanged(P2PPeerSettings.PeerStatus.Online);
193            }
194            else
195            {
196                GuiLogMessage("P2P network must be configured and connecting using the world button.", NotificationLevel.Warning);
197                this.settings.PeerStatusChanged(P2PPeerSettings.PeerStatus.Error);
198
199                // TODO use appropriate exception / abort procedure
200                throw new ApplicationException("P2P unavailable.");
201            }
202        }
203
204        public void StopPeer()
205        {
206
207            GuiLogMessage("Peer cannot be stopped, it is running in CrypTool!", NotificationLevel.Info);
208        }
209        #endregion Start and Stop Peer
210
211        public void LogInternalState()
212        {
213            P2PManager.Instance.P2PBase.LogInternalState();
214        }
215    }
216
217
218    public class P2PPeerMaster : IP2PControl
219    {
220        private AutoResetEvent systemJoined;
221        private P2PPeer p2pPeer;
222        private PeerId peerID;
223        private string sPeerName;
224        // used for every encoding stuff
225        private Encoding enc = UTF8Encoding.UTF8;
226
227        public P2PPeerMaster(P2PPeer p2pPeer)
228        {
229            this.p2pPeer = p2pPeer;
230            this.systemJoined = new AutoResetEvent(false);
231
232            P2PManager.Instance.P2PBase.OnSystemJoined += new P2PBase.SystemJoined(p2pBase_OnSystemJoined);
233            P2PManager.Instance.OnPeerMessageReceived += new P2PBase.P2PMessageReceived(p2pPeer_OnPeerMessageReceived);
234            this.OnStatusChanged += new IControlStatusChangedEventHandler(P2PPeerMaster_OnStatusChanged);
235        }
236
237        #region Events and Event-Handling
238       
239        private void p2pBase_OnSystemJoined()
240        {
241            systemJoined.Set();
242        }
243
244        // to forward event from overlay MessageReceived-Event from P2PBase
245        // analyzes the type of message and throws depend upon this anaysis an event
246        public event P2PPayloadMessageReceived OnPayloadMessageReceived;
247        public event P2PSystemMessageReceived OnSystemMessageReceived;
248        private void p2pPeer_OnPeerMessageReceived(PeerId sourceAddr, byte[] data)
249        {
250            switch (GetMessageType(data[0])) //analyses the first byte of data (index, which represents the MessageType)
251            {
252                case P2PMessageIndex.PubSub:
253                    if (data.Length == 2)
254                    {
255                        if(OnSystemMessageReceived != null)
256                            OnSystemMessageReceived(sourceAddr, GetPubSubType(data[1]));
257                    }
258                    else
259                    {
260                        throw (new Exception("Data seems to be from type 'PubSub', but is to long for it... Data: '" + enc.GetString(data) + "'"));
261                    }
262                    break;
263                case P2PMessageIndex.Payload:
264                    if(OnPayloadMessageReceived != null)
265                        OnPayloadMessageReceived(sourceAddr, GetMessagePayload(data));
266                    break;
267                default:
268                    // not implemented. System ignores these messages completely at present
269                    break;
270            }
271        }
272
273        public event IControlStatusChangedEventHandler OnStatusChanged;
274        private void P2PPeerMaster_OnStatusChanged(IControl sender, bool readyForExecution)
275        {
276            if (OnStatusChanged != null)
277                OnStatusChanged(sender, readyForExecution);
278        }
279
280        #endregion
281
282        public bool PeerStarted()
283        {
284            return this.p2pPeer.PeerStarted();
285        }
286
287        /// <summary>
288        /// workaround method. If the PAP functions are used, but the PAP system isn't
289        /// started yet. This could happen because of the plugin hierarchy and
290        /// when a p2p-using plugin uses PAP functions in the PreExecution method,
291        /// this could run into a race condition (peer plugin not computed by the CT-system
292        /// yet, but p2p-using plugin is already executed)
293        /// </summary>
294        /// <returns></returns>
295        private bool SystemJoinedCompletely()
296        {
297            return P2PManager.Instance.P2PConnected();
298        }
299
300        #region IP2PControl Members
301
302        public bool DHTstore(string sKey, byte[] byteValue)
303        {
304            if (P2PManager.Instance.P2PConnected())
305                return P2PManager.Store(sKey, byteValue);
306            return false;
307        }
308
309        public bool DHTstore(string sKey, string sValue)
310        {
311            if (P2PManager.Instance.P2PConnected())
312                return P2PManager.Store(sKey, sValue);
313            return false;
314        }
315
316        public byte[] DHTload(string sKey)
317        {
318            if (P2PManager.Instance.P2PConnected())
319                return P2PManager.Retrieve(sKey);
320            return null;
321        }
322
323        public bool DHTremove(string sKey)
324        {
325            if (P2PManager.Instance.P2PConnected())
326                return P2PManager.Remove(sKey);
327            return false;
328        }
329
330        /// <summary>
331        /// This method only contacts the p2p system, if the peerID wasn't requested before
332        /// </summary>
333        /// <param name="sPeerName">returns the Peer Name</param>
334        /// <returns>returns the Peer ID</returns>
335        public PeerId GetPeerID(out string sPeerName)
336        {
337            if (SystemJoinedCompletely())
338            {
339                if (this.peerID == null)
340                {
341                    this.peerID = P2PManager.Instance.P2PBase.GetPeerID(out this.sPeerName);
342                }
343                sPeerName = this.sPeerName;
344                return this.peerID;
345            }
346            sPeerName = this.sPeerName;
347            return null;
348        }
349
350        public PeerId GetPeerID(byte[] byteId)
351        {
352            return P2PManager.Instance.P2PBase.GetPeerID(byteId);
353        }
354
355        private void SendReadilyMessage(byte[] data, PeerId destinationAddress)
356        {
357            if (SystemJoinedCompletely())
358                P2PManager.Instance.P2PBase.SendToPeer(data, destinationAddress.ToByteArray());
359        }
360
361        // adds the P2PMessageIndex to the given byte-array
362        public void SendToPeer(byte[] data, PeerId destinationAddress)
363        {
364            byte[] newData = GenerateMessage(data, P2PMessageIndex.Payload);
365            SendReadilyMessage(newData, destinationAddress);
366        }
367
368        public void SendToPeer(string sData, PeerId destinationAddress)
369        {
370            byte[] data = GenerateMessage(sData, P2PMessageIndex.Payload);
371            SendReadilyMessage(data, destinationAddress);
372        }
373        public void SendToPeer(PubSubMessageType msgType, PeerId destinationAddress)
374        {
375            byte[] data = GenerateMessage(msgType);
376            SendReadilyMessage(data, destinationAddress);
377        }
378
379        #region Communication protocol
380
381        /// <summary>
382        /// generates a ct2- and p2p-compatible and processable message
383        /// </summary>
384        /// <param name="payload">payload data in bytes</param>
385        /// <param name="msgIndex">type of message (system message, simple payload for a special use case, etc.)</param>
386        /// <returns>the message, which is processable by the ct2/p2p system</returns>
387        private byte[] GenerateMessage(byte[] payload, P2PMessageIndex msgIndex)
388        {
389            // first byte is the index, if it is payload or Publish/Subscriber stuff
390            byte[] retByte = new byte[1 + payload.Length];
391            retByte[0] = (byte)msgIndex;
392            payload.CopyTo(retByte, 1);
393            return retByte;
394        }
395
396        /// <summary>
397        /// generates a ct2- and p2p-compatible and processable message
398        /// </summary>
399        /// <param name="sPayload">payload data as a string</param>
400        /// <param name="msgIndex">type of message (system message, simple payload for a special use case, etc.)</param>
401        /// <returns>the message, which is processable by the ct2/p2p system</returns>
402        private byte[] GenerateMessage(string sPayload, P2PMessageIndex msgIndex)
403        {
404            return GenerateMessage(enc.GetBytes(sPayload), msgIndex);
405        }
406
407        /// <summary>
408        /// generates a ct2- and p2p-compatible and processable message
409        /// </summary>
410        /// <param name="pubSubData">PubSubMessageType</param>
411        /// <returns>the message, which is processable by the ct2/p2p system<</returns>
412        private byte[] GenerateMessage(PubSubMessageType pubSubData)
413        {
414            byte[] bytePubSubData = new byte[] { (byte)pubSubData };
415            return GenerateMessage(bytePubSubData, P2PMessageIndex.PubSub);
416        }
417
418        /// <summary>
419        /// returns the message type, e.g. PubSub or Payload message
420        /// </summary>
421        /// <param name="msgType">the FIRST byte of a raw message, received by the system</param>
422        /// <returns>the message type</returns>
423        private P2PMessageIndex GetMessageType(byte msgType)
424        {
425            try
426            {
427                return (P2PMessageIndex)msgType;
428            }
429            catch (Exception ex)
430            {
431                throw (ex);
432            }
433        }
434
435        /// <summary>
436        /// returns the message type, e.g. PubSub or Payload message (to accelarate this process, only assign first byte of the whole array message)
437        /// </summary>
438        /// <param name="message">the whole message as an byte array</param>
439        /// <returns>the message type</returns>
440        private P2PMessageIndex GetMessageType(byte[] message)
441        {
442            try
443            {
444                return (P2PMessageIndex)message[0];
445            }
446            catch (Exception ex)
447            {
448                throw (ex);
449            }
450        }
451
452        /// <summary>
453        /// returns only the payload part of the message
454        /// </summary>
455        /// <param name="message">the raw message, received by the system, as an byte array (with the first index byte!!!)</param>
456        /// <returns>only the payload part of the message</returns>
457        private byte[] GetMessagePayload(byte[] message)
458        {
459            if (message.Length > 1)
460            {
461                byte[] retMsg = new byte[message.Length - 1];
462                // workaround because CopyTo doesn't work...
463                //for (int i = 0; i < message.Length-1; i++)
464                //{
465                //    retMsg[i] = message[i + 1];
466                //}
467                Buffer.BlockCopy(message, 1, retMsg, 0, retMsg.Length);
468                return retMsg;
469            }
470            return null;
471        }
472
473        #endregion
474
475
476        /// <summary>
477        /// Converts a string to the PubSubMessageType if possible. Otherwise return null.
478        /// </summary>
479        /// <param name="sData">Data</param>
480        /// <returns>PubSubMessageType if possible. Otherwise null.</returns>
481        private PubSubMessageType GetPubSubType(byte data)
482        {
483            // Convert one byte data to PublishSubscribeMessageType-Enum
484            try
485            {
486                return (PubSubMessageType)data;
487            }
488            catch (Exception ex)
489            {
490                throw(ex);
491            }
492        }
493
494        #endregion
495    }
496}
Note: See TracBrowser for help on using the repository browser.