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

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

o Command line parameter with the workspace file name can be at any position

File size: 17.6 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.Error);
197                this.settings.PeerStatusChanged(P2PPeerSettings.PeerStatus.Error);
198            }
199        }
200
201        public void StopPeer()
202        {
203
204            GuiLogMessage("Peer cannot be stopped, it is running in CrypTool!", NotificationLevel.Info);
205        }
206        #endregion Start and Stop Peer
207
208        public void LogInternalState()
209        {
210            P2PManager.Instance.P2PBase.LogInternalState();
211        }
212    }
213
214
215    public class P2PPeerMaster : IP2PControl
216    {
217        private AutoResetEvent systemJoined;
218        private P2PPeer p2pPeer;
219        private PeerId peerID;
220        private string sPeerName;
221        // used for every encoding stuff
222        private Encoding enc = UTF8Encoding.UTF8;
223
224        public P2PPeerMaster(P2PPeer p2pPeer)
225        {
226            this.p2pPeer = p2pPeer;
227            this.systemJoined = new AutoResetEvent(false);
228
229            P2PManager.Instance.P2PBase.OnSystemJoined += new P2PBase.SystemJoined(p2pBase_OnSystemJoined);
230            P2PManager.Instance.OnPeerMessageReceived += new P2PBase.P2PMessageReceived(p2pPeer_OnPeerMessageReceived);
231            this.OnStatusChanged += new IControlStatusChangedEventHandler(P2PPeerMaster_OnStatusChanged);
232        }
233
234        #region Events and Event-Handling
235       
236        private void p2pBase_OnSystemJoined()
237        {
238            systemJoined.Set();
239        }
240
241        // to forward event from overlay MessageReceived-Event from P2PBase
242        // analyzes the type of message and throws depend upon this anaysis an event
243        public event P2PPayloadMessageReceived OnPayloadMessageReceived;
244        public event P2PSystemMessageReceived OnSystemMessageReceived;
245        private void p2pPeer_OnPeerMessageReceived(PeerId sourceAddr, byte[] data)
246        {
247            switch (GetMessageType(data[0])) //analyses the first byte of data (index, which represents the MessageType)
248            {
249                case P2PMessageIndex.PubSub:
250                    if (data.Length == 2)
251                    {
252                        if(OnSystemMessageReceived != null)
253                            OnSystemMessageReceived(sourceAddr, GetPubSubType(data[1]));
254                    }
255                    else
256                    {
257                        throw (new Exception("Data seems to be from type 'PubSub', but is to long for it... Data: '" + enc.GetString(data) + "'"));
258                    }
259                    break;
260                case P2PMessageIndex.Payload:
261                    if(OnPayloadMessageReceived != null)
262                        OnPayloadMessageReceived(sourceAddr, GetMessagePayload(data));
263                    break;
264                default:
265                    // not implemented. System ignores these messages completely at present
266                    break;
267            }
268        }
269
270        public event IControlStatusChangedEventHandler OnStatusChanged;
271        private void P2PPeerMaster_OnStatusChanged(IControl sender, bool readyForExecution)
272        {
273            if (OnStatusChanged != null)
274                OnStatusChanged(sender, readyForExecution);
275        }
276
277        #endregion
278
279        public bool PeerStarted()
280        {
281            return this.p2pPeer.PeerStarted();
282        }
283
284        /// <summary>
285        /// workaround method. If the PAP functions are used, but the PAP system isn't
286        /// started yet. This could happen because of the plugin hierarchy and
287        /// when a p2p-using plugin uses PAP functions in the PreExecution method,
288        /// this could run into a race condition (peer plugin not computed by the CT-system
289        /// yet, but p2p-using plugin is already executed)
290        /// </summary>
291        /// <returns></returns>
292        private bool SystemJoinedCompletely()
293        {
294            return P2PManager.Instance.P2PConnected();
295        }
296
297        #region IP2PControl Members
298
299        public bool DHTstore(string sKey, byte[] byteValue)
300        {
301            if (P2PManager.Instance.P2PConnected())
302                return P2PManager.Store(sKey, byteValue);
303            return false;
304        }
305
306        public bool DHTstore(string sKey, string sValue)
307        {
308            if (P2PManager.Instance.P2PConnected())
309                return P2PManager.Store(sKey, sValue);
310            return false;
311        }
312
313        public byte[] DHTload(string sKey)
314        {
315            if (P2PManager.Instance.P2PConnected())
316                return P2PManager.Retrieve(sKey);
317            return null;
318        }
319
320        public bool DHTremove(string sKey)
321        {
322            if (P2PManager.Instance.P2PConnected())
323                return P2PManager.Remove(sKey);
324            return false;
325        }
326
327        /// <summary>
328        /// This method only contacts the p2p system, if the peerID wasn't requested before
329        /// </summary>
330        /// <param name="sPeerName">returns the Peer Name</param>
331        /// <returns>returns the Peer ID</returns>
332        public PeerId GetPeerID(out string sPeerName)
333        {
334            if (SystemJoinedCompletely())
335            {
336                if (this.peerID == null)
337                {
338                    this.peerID = P2PManager.Instance.P2PBase.GetPeerID(out this.sPeerName);
339                }
340                sPeerName = this.sPeerName;
341                return this.peerID;
342            }
343            sPeerName = this.sPeerName;
344            return null;
345        }
346
347        public PeerId GetPeerID(byte[] byteId)
348        {
349            return P2PManager.Instance.P2PBase.GetPeerID(byteId);
350        }
351
352        private void SendReadilyMessage(byte[] data, PeerId destinationAddress)
353        {
354            if (SystemJoinedCompletely())
355                P2PManager.Instance.P2PBase.SendToPeer(data, destinationAddress.ToByteArray());
356        }
357
358        // adds the P2PMessageIndex to the given byte-array
359        public void SendToPeer(byte[] data, PeerId destinationAddress)
360        {
361            byte[] newData = GenerateMessage(data, P2PMessageIndex.Payload);
362            SendReadilyMessage(newData, destinationAddress);
363        }
364
365        public void SendToPeer(string sData, PeerId destinationAddress)
366        {
367            byte[] data = GenerateMessage(sData, P2PMessageIndex.Payload);
368            SendReadilyMessage(data, destinationAddress);
369        }
370        public void SendToPeer(PubSubMessageType msgType, PeerId destinationAddress)
371        {
372            byte[] data = GenerateMessage(msgType);
373            SendReadilyMessage(data, destinationAddress);
374        }
375
376        #region Communication protocol
377
378        /// <summary>
379        /// generates a ct2- and p2p-compatible and processable message
380        /// </summary>
381        /// <param name="payload">payload data in bytes</param>
382        /// <param name="msgIndex">type of message (system message, simple payload for a special use case, etc.)</param>
383        /// <returns>the message, which is processable by the ct2/p2p system</returns>
384        private byte[] GenerateMessage(byte[] payload, P2PMessageIndex msgIndex)
385        {
386            // first byte is the index, if it is payload or Publish/Subscriber stuff
387            byte[] retByte = new byte[1 + payload.Length];
388            retByte[0] = (byte)msgIndex;
389            payload.CopyTo(retByte, 1);
390            return retByte;
391        }
392
393        /// <summary>
394        /// generates a ct2- and p2p-compatible and processable message
395        /// </summary>
396        /// <param name="sPayload">payload data as a string</param>
397        /// <param name="msgIndex">type of message (system message, simple payload for a special use case, etc.)</param>
398        /// <returns>the message, which is processable by the ct2/p2p system</returns>
399        private byte[] GenerateMessage(string sPayload, P2PMessageIndex msgIndex)
400        {
401            return GenerateMessage(enc.GetBytes(sPayload), msgIndex);
402        }
403
404        /// <summary>
405        /// generates a ct2- and p2p-compatible and processable message
406        /// </summary>
407        /// <param name="pubSubData">PubSubMessageType</param>
408        /// <returns>the message, which is processable by the ct2/p2p system<</returns>
409        private byte[] GenerateMessage(PubSubMessageType pubSubData)
410        {
411            byte[] bytePubSubData = new byte[] { (byte)pubSubData };
412            return GenerateMessage(bytePubSubData, P2PMessageIndex.PubSub);
413        }
414
415        /// <summary>
416        /// returns the message type, e.g. PubSub or Payload message
417        /// </summary>
418        /// <param name="msgType">the FIRST byte of a raw message, received by the system</param>
419        /// <returns>the message type</returns>
420        private P2PMessageIndex GetMessageType(byte msgType)
421        {
422            try
423            {
424                return (P2PMessageIndex)msgType;
425            }
426            catch (Exception ex)
427            {
428                throw (ex);
429            }
430        }
431
432        /// <summary>
433        /// returns the message type, e.g. PubSub or Payload message (to accelarate this process, only assign first byte of the whole array message)
434        /// </summary>
435        /// <param name="message">the whole message as an byte array</param>
436        /// <returns>the message type</returns>
437        private P2PMessageIndex GetMessageType(byte[] message)
438        {
439            try
440            {
441                return (P2PMessageIndex)message[0];
442            }
443            catch (Exception ex)
444            {
445                throw (ex);
446            }
447        }
448
449        /// <summary>
450        /// returns only the payload part of the message
451        /// </summary>
452        /// <param name="message">the raw message, received by the system, as an byte array (with the first index byte!!!)</param>
453        /// <returns>only the payload part of the message</returns>
454        private byte[] GetMessagePayload(byte[] message)
455        {
456            if (message.Length > 1)
457            {
458                byte[] retMsg = new byte[message.Length - 1];
459                // workaround because CopyTo doesn't work...
460                //for (int i = 0; i < message.Length-1; i++)
461                //{
462                //    retMsg[i] = message[i + 1];
463                //}
464                Buffer.BlockCopy(message, 1, retMsg, 0, retMsg.Length);
465                return retMsg;
466            }
467            return null;
468        }
469
470        #endregion
471
472
473        /// <summary>
474        /// Converts a string to the PubSubMessageType if possible. Otherwise return null.
475        /// </summary>
476        /// <param name="sData">Data</param>
477        /// <returns>PubSubMessageType if possible. Otherwise null.</returns>
478        private PubSubMessageType GetPubSubType(byte data)
479        {
480            // Convert one byte data to PublishSubscribeMessageType-Enum
481            try
482            {
483                return (PubSubMessageType)data;
484            }
485            catch (Exception ex)
486            {
487                throw(ex);
488            }
489        }
490
491        #endregion
492    }
493}
Note: See TracBrowser for help on using the repository browser.