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

Last change on this file since 1458 was 1458, checked in by Paul Lelgemann, 12 years ago
  • Removed unused references and using statement in CrypP2P, PeerToPeer, PeerToPeerBaseProxy

+ Skeleton for P2PEditor

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