source: trunk/CrypPlugins/KeySearcher/P2P/Storage/StorageHelper.cs @ 2442

Last change on this file since 2442 was 2442, checked in by nolte, 11 years ago

Protecting the Tree from Node/Leaf Attacks. Healing-Kit Update

(Will be further modified Wednesday)

File size: 17.7 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Threading;
5using Cryptool.P2P;
6using Cryptool.P2P.Internal;
7using Cryptool.PluginBase;
8using KeySearcher.P2P.Exceptions;
9using KeySearcher.P2P.Presentation;
10using KeySearcher.P2P.Tree;
11
12namespace KeySearcher.P2P.Storage
13{
14    class StorageHelper
15    {
16        private readonly KeySearcher keySearcher;
17        private readonly StatisticsGenerator statisticsGenerator;
18        private readonly StatusContainer statusContainer;
19
20        //VERSIONNUMBER: Important. Set it +1 manually everytime the length of the MemoryStream Changes
21        private const int version = 5;
22        /*
23        -----------------------------Versionnumber Changelog---------------------------------------------
24        |   Version 1: Added the Versionnumber to the Stream (Leafs)
25        |   Version 2: Added the first User Statistics (Avatar,ID,Count) to the Stream
26        |   Version 3: Added version question (in front of results) + more statistic information (hostname,date) to the Stream
27        |   Version 4: Reorganisation of the DHT structure. Update fully working now + features from previous versions available
28        |   Version 5: Extended the key information by the user who found it. (Username,Date,Maschid,Host)
29        -------------------------------------------------------------------------------------------------
30         */
31
32        public StorageHelper(KeySearcher keySearcher, StatisticsGenerator statisticsGenerator, StatusContainer statusContainer)
33        {
34            this.keySearcher = keySearcher;
35            this.statisticsGenerator = statisticsGenerator;
36            this.statusContainer = statusContainer;
37        }
38
39        //-------------------------------------------------------------------------------------------
40        //AFTER CHANGING THE FOLLOWING METHODS INCREASE THE VERSION-NUMBER AT THE TOP OF THIS CLASS!
41        //-------------------------------------------------------------------------------------------
42        internal RequestResult UpdateInDht(NodeBase nodeToUpdate)
43        {
44            var memoryStream = new MemoryStream();
45            var binaryWriter = new BinaryWriter(memoryStream);
46
47            //Append Updater Version
48            binaryWriter.Write('W');
49            binaryWriter.Write(version); 
50
51            if (nodeToUpdate is Node)
52            {
53                UpdateNodeInDht((Node) nodeToUpdate, binaryWriter);
54            } else
55            {
56                UpdateLeafInDht((Leaf) nodeToUpdate, binaryWriter);
57            }
58
59            // Append results
60            binaryWriter.Write(nodeToUpdate.Result.Count);
61            foreach (var valueKey in nodeToUpdate.Result)
62            {
63                binaryWriter.Write(valueKey.key);
64                binaryWriter.Write(valueKey.value);
65                binaryWriter.Write(valueKey.decryption.Length);
66                binaryWriter.Write(valueKey.decryption);
67
68                //--------------------------------------------------------
69                binaryWriter.Write(valueKey.user);
70                var buffertime = valueKey.time.ToBinary();
71                binaryWriter.Write(buffertime);
72                binaryWriter.Write(valueKey.maschid);
73                binaryWriter.Write(valueKey.maschname);
74                //---------------------------------------------------------
75            }                       
76             
77            //Creating a copy of the activity dictionary
78            var copyAct = nodeToUpdate.Activity;
79
80            //Write number of avatarnames
81            binaryWriter.Write(copyAct.Keys.Count);
82            foreach (string avatar in copyAct.Keys)
83            {
84                var maschCopy = copyAct[avatar];
85                //write avatarname
86                binaryWriter.Write(avatar);
87                //write the number of maschines for this avatar
88                binaryWriter.Write(maschCopy.Keys.Count);
89
90                foreach (long maschID in maschCopy.Keys)
91                {
92                    //write the maschines and their patterncount
93                    binaryWriter.Write(maschID);
94                    binaryWriter.Write(maschCopy[maschID].Count); //int 32
95                    binaryWriter.Write(maschCopy[maschID].Hostname); //String
96                    binaryWriter.Write(maschCopy[maschID].Date.ToBinary()); //DateTime
97                }
98            }
99            return StoreWithStatistic(KeyInDht(nodeToUpdate), memoryStream.ToArray());
100        }
101
102        private static void UpdateNodeInDht(Node nodeToUpdate, BinaryWriter binaryWriter)
103        {
104            binaryWriter.Write(nodeToUpdate.LeftChildFinished);
105            binaryWriter.Write(nodeToUpdate.RightChildFinished);
106        }
107
108        private static void UpdateLeafInDht(Leaf nodeToUpdate, BinaryWriter binaryWriter)
109        {
110            binaryWriter.Write('V');
111            binaryWriter.Write(version);
112            var buffer = nodeToUpdate.LastReservationDate.ToBinary();
113            binaryWriter.Write(buffer);
114            binaryWriter.Write(nodeToUpdate.getClientIdentifier());
115        }
116
117        internal RequestResult UpdateFromDht(NodeBase nodeToUpdate, bool forceUpdate = false)
118        {
119                if (!forceUpdate && nodeToUpdate.LastUpdate > DateTime.Now.Subtract(new TimeSpan(0, 0, 5)))
120                {
121                    return new RequestResult {Status = RequestResultType.Success};
122                }
123
124                nodeToUpdate.LastUpdate = DateTime.Now;
125
126                var requestResult = RetrieveWithStatistic(KeyInDht(nodeToUpdate));
127                var nodeBytes = requestResult.Data;
128
129                if (nodeBytes == null)
130                {
131                    return requestResult;
132                }
133
134                var binaryReader = new BinaryReader(new MemoryStream(nodeBytes));
135
136                //oldVersionFlag will be used to garantee further changes in the Stream
137                var oldVersionFlag = CheckNodeVersion(binaryReader);
138
139                try
140                {
141                    if (nodeToUpdate is Node)
142                    {
143                        UpdateNodeFromDht((Node)nodeToUpdate, binaryReader);
144                    }
145                    else
146                    {
147                        UpdateLeafFromDht((Leaf)nodeToUpdate, binaryReader);
148                    }
149                }
150                catch (Exception e)
151                {
152                    // client id not available, use default
153                    keySearcher.GuiLogMessage(e.Message + ": Node causing the failure: " + nodeToUpdate.ToString(), NotificationLevel.Error);
154                    nodeToUpdate.Reset();
155                    throw new InvalidOperationException();
156                }
157
158                // Load results
159                var resultCount = binaryReader.ReadInt32();
160
161                for (var i = 0; i < resultCount; i++)
162                {
163                    try
164                    {
165                        if (oldVersionFlag < 5)
166                        {
167                            var newResult = new KeySearcher.ValueKey
168                                                {
169                                                    key = binaryReader.ReadString(),
170                                                    value = binaryReader.ReadDouble(),
171                                                    decryption = binaryReader.ReadBytes(binaryReader.ReadInt32()),
172                                                    user = "Unknown",
173                                                    time = DateTime.MinValue,
174                                                    maschid = 666,
175                                                    maschname = "Devil"
176                                                };
177                            nodeToUpdate.Result.AddLast(newResult);
178                        }
179                        else
180                        {
181                            var newResult = new KeySearcher.ValueKey
182                                                {
183                                                    key = binaryReader.ReadString(),
184                                                    value = binaryReader.ReadDouble(),
185                                                    decryption = binaryReader.ReadBytes(binaryReader.ReadInt32()),
186                                                    user = binaryReader.ReadString(),
187                                                    time = DateTime.FromBinary(binaryReader.ReadInt64()),
188                                                    maschid = binaryReader.ReadInt64(),
189                                                    maschname = binaryReader.ReadString()
190                                                };
191                            nodeToUpdate.Result.AddLast(newResult);
192                        }
193                    }
194                    catch(Exception e)
195                    {
196                        keySearcher.GuiLogMessage(e.Message + ": Node causing the failure: " + nodeToUpdate.ToString(),NotificationLevel.Error);
197                        nodeToUpdate.Reset();
198                        throw new InvalidOperationException();
199                    }                                       
200                }
201
202                try
203                {
204                    if (binaryReader.BaseStream.Length != binaryReader.BaseStream.Position)
205                    {
206                        //Reading the number of avatarnames
207                        int avatarcount = binaryReader.ReadInt32();
208                        for (int i = 0; i < avatarcount; i++)
209                        {
210                            //Reading the avatarname and the maschine-count for this name
211                            string avatarname = binaryReader.ReadString();
212                            int maschcount = binaryReader.ReadInt32();
213                            var readMaschcount = new Dictionary<long, Information>();
214
215                            for (int j = 0; j < maschcount; j++)
216                            {
217                                //reading the IDs and patterncount
218                                long maschID = binaryReader.ReadInt64();
219                                int count = binaryReader.ReadInt32();
220                                string host = binaryReader.ReadString();
221                                var date = DateTime.FromBinary(binaryReader.ReadInt64());
222                                readMaschcount.Add(maschID, new Information() { Count = count, Hostname = host, Date = date });
223
224                            }
225
226                            if (nodeToUpdate.Activity.ContainsKey(avatarname))
227                            {
228                                nodeToUpdate.Activity[avatarname] = readMaschcount;
229                            }
230                            else
231                            {
232                                nodeToUpdate.Activity.Add(avatarname, readMaschcount);
233                            }
234                        }
235                    }
236
237                }
238                catch (Exception e)
239                {
240                    keySearcher.GuiLogMessage(e.Message + ": Node causing the failure: " + nodeToUpdate.ToString(), NotificationLevel.Error);
241                    nodeToUpdate.Reset();
242                    throw new InvalidOperationException();
243                }
244
245
246                if (resultCount > 0)
247                {
248                    keySearcher.IntegrateNewResults(nodeToUpdate.Result, nodeToUpdate.Activity,
249                                                    nodeToUpdate.DistributedJobIdentifier);
250                    statisticsGenerator.ProcessPatternResults(nodeToUpdate.Result);
251                }
252
253                nodeToUpdate.UpdateCache();
254                return requestResult;
255        }
256
257        private static void UpdateNodeFromDht(Node nodeToUpdate, BinaryReader binaryReader)
258        {
259            nodeToUpdate.LeftChildFinished = binaryReader.ReadBoolean() || nodeToUpdate.LeftChildFinished;
260            nodeToUpdate.RightChildFinished = binaryReader.ReadBoolean() || nodeToUpdate.RightChildFinished;
261        }
262
263        private static void UpdateLeafFromDht(Leaf nodeToUpdate, BinaryReader binaryReader)
264        {
265            var oldVersionFlag = CheckVersion(binaryReader);
266
267            try
268            {   
269                var date = DateTime.FromBinary(binaryReader.ReadInt64());
270                if (date > nodeToUpdate.LastReservationDate)
271                {
272                    nodeToUpdate.LastReservationDate = date;
273                }
274           
275
276                if (binaryReader.BaseStream.Length - binaryReader.BaseStream.Position >= 8)
277                {
278                    nodeToUpdate.setClientIdentifier(binaryReader.ReadInt64());
279                }
280                else
281                {
282                    throw new Exception();
283                }
284            }
285            catch (Exception)
286            {
287                throw new Exception();
288            }
289           
290        }
291
292        internal static string KeyInDht(NodeBase node)
293        {
294            return string.Format("{0}_node_{1}_{2}", node.DistributedJobIdentifier, node.From, node.To);
295        }
296
297        private static int CheckVersion(BinaryReader binaryReader)
298        {           
299            try
300            {
301                //Checking if there's a version in the stream
302                int vers = binaryReader.PeekChar();
303                if (vers == 86) //V infront of a Leaf
304                {
305                    //Reading the char and the versionnumber
306                    char magic = binaryReader.ReadChar();
307                    int versionInUse = binaryReader.ReadInt32();
308                    //Check if a newer Version is in use
309                    if (versionInUse > version)
310                    {
311                        throw new KeySearcherStopException();
312                    }
313                    return versionInUse;
314                }
315                else
316                {
317                    return 0;
318                }
319            }
320            catch(KeySearcherStopException)
321            {
322                throw new KeySearcherStopException();
323            }           
324        }
325
326        private static int CheckNodeVersion(BinaryReader binaryReader)
327        {
328            try
329            {
330                //Checking if there's a version in the stream
331                int vers = binaryReader.PeekChar();
332                if (vers == 87) //W infront of a Node
333                {
334                    //Reading the char and the versionnumber
335                    char magic = binaryReader.ReadChar();
336                    int versionInUse = binaryReader.ReadInt32();
337                    //Check if a newer Version is in use
338                    if (versionInUse > version)
339                    {
340                        throw new KeySearcherStopException();
341                    }
342                    return versionInUse;
343                }
344                else
345                {
346                    return 0;
347                }
348            }
349            catch (KeySearcherStopException)
350            {
351                throw new KeySearcherStopException();
352            }
353        }
354
355        public DateTime StartDate(String ofJobIdentifier)
356        {
357            var key = ofJobIdentifier + "_startdate";
358            var requestResult = RetrieveWithStatistic(key);
359
360            if (requestResult.IsSuccessful() && requestResult.Data != null)
361            {
362                var startTimeUtc = DateTime.SpecifyKind(
363                    DateTime.FromBinary(BitConverter.ToInt64(requestResult.Data, 0)), DateTimeKind.Utc);
364                return startTimeUtc.ToLocalTime();
365            }
366
367            StoreWithStatistic(key, BitConverter.GetBytes((DateTime.UtcNow.ToBinary())));
368            return DateTime.Now;
369        }
370
371        public long SubmitterID(String ofJobIdentifier)
372        {
373            var key = ofJobIdentifier + "_submitterid";
374            var requestResult = RetrieveWithStatistic(key);
375
376            if (requestResult.IsSuccessful() && requestResult.Data != null)
377            {
378                var submitterid = BitConverter.ToInt64(requestResult.Data, 0);
379                return submitterid;
380            }
381
382            StoreWithStatistic(key, BitConverter.GetBytes(Cryptool.PluginBase.Miscellaneous.UniqueIdentifier.GetID()));
383            return Cryptool.PluginBase.Miscellaneous.UniqueIdentifier.GetID();
384        }
385
386        public RequestResult RetrieveWithStatistic(string key)
387        {
388            statusContainer.RetrieveRequests++;
389            statusContainer.TotalDhtRequests++;
390            var requestResult = P2PManager.Retrieve(key);
391
392            if (requestResult.Data != null)
393            {
394                statusContainer.RetrievedBytes += requestResult.Data.Length;
395                statusContainer.TotalBytes += requestResult.Data.Length;
396            }
397
398            return requestResult;
399        }
400
401        public RequestResult RemoveWithStatistic(string key)
402        {
403            statusContainer.RemoveRequests++;
404            statusContainer.TotalDhtRequests++;
405            return P2PManager.Remove(key);
406        }
407
408        public RequestResult StoreWithStatistic(string key, byte[] data)
409        {
410            statusContainer.StoreRequests++;
411            statusContainer.TotalDhtRequests++;
412            var requestResult = P2PManager.Store(key, data);
413
414            if (requestResult.Data != null)
415            {
416                statusContainer.StoredBytes += requestResult.Data.Length;
417                statusContainer.TotalBytes += requestResult.Data.Length;
418            }
419
420            return requestResult;
421        }
422    }
423}
Note: See TracBrowser for help on using the repository browser.