예제 #1
0
        /// <summary>
        ///   Creates a message and all it's fragments. From a file.
        /// </summary>
        /// <param name="remoteEndPoint">Where to send the message</param>
        /// <param name="file">File to send</param>
        /// <param name="maxFragmentSize">Maximum size of one fragment in bytes</param>
        public static Message CreateFileMessage(IPEndPoint remoteEndPoint, string file, ushort maxFragmentSize)
        {
            // read file bytes
              var fileBytes = File.ReadAllBytes(file);

              // create a sorted list of fragments
              var fragmentList = new SortedList<ushort, byte[]>();

              // add all fragments
              while (fileBytes.Length > 0) {
            // get the fragment bytes
            byte[] bytes;

            // check the remaining size
            if (fileBytes.Length > maxFragmentSize) {
              // take maximum allowed bytes and make a fragment
              bytes = fileBytes.Take(maxFragmentSize).ToArray();

              // shift
              fileBytes = fileBytes.Skip(maxFragmentSize).ToArray();
            }
            else {
              // take whole fragment
              bytes = fileBytes;
              fileBytes = new byte[0];
            }

            // add the fragment to the list
            fragmentList.Add((ushort) fragmentList.Count, bytes);
              }

              // create a message
              var message = new Message((ushort) fragmentList.Count, fragmentList) {
            RemoteEndPoint = remoteEndPoint,
            FileName = Path.GetFileName(file)
              };

              // return the message
              return message;
        }
예제 #2
0
        /// <summary>
        ///   Sends a fragment.
        /// </summary>
        private Task SendFragment(Message message, byte[] fragment, FragmentType type)
        {
            // create a task
              return Task.Run(() => {
            // check the listening state
            if (_listening) {
              // error
              Log.Singleton.LogError("Can't send a fragment while listening");

              // delete message
              lock (message) {
            MessageCenter.Singleton.Messages.Remove(BitConverter.ToUInt16(message.ID, 0));
              }

              // cancel
              return;
            }

            // append CRC checksum
            CRC.GenerateChecksum(ref fragment);

            // need to lock to prevent multiple tasks trying to send simultaneously
            lock (_clientMutex) {
              // check if we want to lose some fragments
              if (Options.LoseFragments) {
            // get a random value
            var random = new Random();
            if ((ushort) random.Next() % 100 < 30) {
              // 30% of fragments will be lost

              // log that
              Log.Singleton.LogMessage($"Purposefully losing a fragment of type <{type}>");

              // exit
              return;
            }
              }

              // check if we want to corrupt some fragments
              if (Options.SendCorrupt) {
            // get a random value
            var random = new Random();
            if ((ushort) random.Next() % 100 < 40) {
              // 40% of fragments will be corrupted

              // log that
              Log.Singleton.LogMessage($"Purposefully corrupting a fragment of type <{type}>");

              // change random bytes
              for (int i = 0, imax = Math.Abs(random.Next() + 2) % 16; i < imax; ++i) {
                fragment[random.Next() % fragment.Length] = (byte) random.Next();
              }
            }
              }

              // create a client
              _client = new UdpClient();

              // bind it
              try {
            _client.Client.Bind(new IPEndPoint(IPAddress.Any, Options.Port));
              }
              catch (SocketException) {
            // nope, can't bind to that port
            Log.Singleton.LogError($"Failed to bind the sending socket to the port <{Options.Port}>");

            // remove client
            _client = null;

            // remove message
            lock (message) {
              MessageCenter.Singleton.Messages.Remove(BitConverter.ToUInt16(message.ID, 0));
            }

            // stop
            return;
              }

              // log
              lock (message) {
            Log.Singleton.LogMessage(
              $"Sending a <{type}> fragment for message <{message.ID[0].ToString("00")}{message.ID[1].ToString("00")}> to <{message.RemoteEndPoint}>");
              }

              // send the fragment
              lock (message) {
            _client.Send(fragment, fragment.Length, message.RemoteEndPoint);
              }

              // close and remove client
              _client.Close();
              _client = null;
            }
              });
        }
예제 #3
0
        /// <summary>
        ///   Sends end fragment for a message.
        /// </summary>
        private void SendEndFragment(Message message, int retries = 0)
        {
            // create a task
              Task.Run(() => {
            // ask for an end fragment
            byte[] fragment;
            lock (message) {
              fragment = Fragmenter.MakeEndFragment(message);
            }

            // send the fragment
            SendFragment(message, fragment, FragmentType.End)

              // listen
              .ContinueWith(task => Listen())

              // handle timeout
              .ContinueWith(task => {
            // check the result
            if (!task.Result.Result) {
              // timeout, check retries
              if (retries < Options.Retries)
                SendEndFragment(message, retries + 1);

              else {
                // message timed out
                lock (message) {
                  MessageCenter.Singleton.Messages.Remove(BitConverter.ToUInt16(message.ID, 0));

                  // log
                  Log.Singleton.LogError(
                    $"Message <{message.ID[0].ToString("00")}{message.ID[1].ToString("00")}> timed out");

                  MessageCenter.Singleton.FireChange(MessageStatus.TimedOut);
                }
              }
            }
              });
              });
        }
예제 #4
0
        /// <summary>
        ///   Send a prepare fragment for a message.
        /// </summary>
        public void SendPrepareFragment(Message message, int retries = 0)
        {
            // create a task
              Task.Run(() => {
            // create a prepare fragment
            byte[] prepareFragment;
            lock (message) {
              prepareFragment = Fragmenter.MakePrepareFragment(message);
            }

            // update status
            lock (message) {
              message.Status = MessageStatus.Handshaking;
            }

            // log that
            lock (message) {
              Log.Singleton.LogMessage(
            $"Message <{message.ID[0].ToString("00")}{message.ID[1].ToString("00")}> is in state <{message.Status}>");

              MessageCenter.Singleton.FireChange(message.Status);
            }

            // go ahead, send it
            SendFragment(message, prepareFragment, FragmentType.Prepare)

              // listen
              .ContinueWith(task => Listen())

              // handle timeout
              .ContinueWith(task => {
            // check the result
            if (!task.Result.Result) {
              // timeout, check retries
              if (retries < Options.Retries)
                SendPrepareFragment(message, retries + 1);

              else {
                // message timed out
                lock (message) {
                  MessageCenter.Singleton.Messages.Remove(BitConverter.ToUInt16(message.ID, 0));

                  // log
                  Log.Singleton.LogError(
                    $"Message <{message.ID[0].ToString("00")}{message.ID[1].ToString("00")}> timed out");

                  MessageCenter.Singleton.FireChange(MessageStatus.TimedOut);
                }
              }
            }
              });
              });
        }
예제 #5
0
        /// <summary>
        ///   Sends a prepared fragment for a message.
        /// </summary>
        public void SendPreparedFragment(Message message)
        {
            // create a task
              Task.Run(() => {
            // ask for a prepared fragment
            byte[] fragment;
            lock (message) {
              fragment = Fragmenter.MakePreparedFragment(message);
            }

            // send the fragment
            SendFragment(message, fragment, FragmentType.Prepared)

              // listen
              .ContinueWith(task => Listen(false));
              });
        }
예제 #6
0
        /// <summary>
        ///   Sends ending okay fragment.
        /// </summary>
        public void SendOkayFragment(Message message)
        {
            // create a task
              Task.Run(() => {
            // ask for an end fragment
            byte[] fragment;
            lock (message) {
              fragment = Fragmenter.MakeOkayFragment(message);
            }

            // send the fragment
            SendFragment(message, fragment, FragmentType.Okay)

              // set status
              .ContinueWith(task => {
            lock (message) {
              message.Status = MessageStatus.Finished;
              Log.Singleton.LogMessage(
                $"Message <{message.ID[0].ToString("00")}{message.ID[1].ToString("00")}> is in state <{message.Status}>");

              MessageCenter.Singleton.FireChange(message.Status);
            }
              });
              });
        }
예제 #7
0
        /// <summary>
        ///   Sends a missing fragment for a message.
        /// </summary>
        public void SendMissingFragment(Message message, List<ushort> missingList)
        {
            // create a task
              Task.Run(() => {
            // ask for a missing fragment
            byte[] fragment;
            lock (message) {
              fragment = Fragmenter.MakeMissingFragment(message, missingList);
            }

            // send the fragment
            SendFragment(message, fragment, FragmentType.Missing)

              // listen
              .ContinueWith(task => Listen(false));
              });
        }
예제 #8
0
        /// <summary>
        ///   Sends only missing parts of a message.
        /// </summary>
        public void SendDataFragments(Message message, List<ushort> missingList)
        {
            // create a task
              Task.Run(() => {
            // set state
            lock (message) {
              message.Status = MessageStatus.Transmitting;
            }

            // log that
            lock (message) {
              Log.Singleton.LogMessage(
            $"Message <{message.ID[0].ToString("00")}{message.ID[1].ToString("00")}> is in state <{message.Status}>");

              MessageCenter.Singleton.FireChange(message.Status);
            }

            // send missing data fragments
            var sendTasks = new List<Task>();
            lock (message) {
              foreach (var missingNumber in missingList) {
            // request a data fragment
            var fragment = Fragmenter.MakeDataFragment(message, missingNumber);

            // send it
            var task = SendFragment(message, fragment, FragmentType.Data);
            sendTasks.Add(task);

            task.ContinueWith(t => {
              lock (message) {
                // update progress
                MessageCenter.Singleton.FireProgress(missingNumber, message.PartCount);

                // increment data counter
                message.DataCounter++;
              }
            });
              }
            }

            // TODO: Handle keep-alive fragments

            Task.WhenAll(sendTasks).ContinueWith(task => {
              // set state
              lock (message) {
            message.Status = MessageStatus.Ending;
              }

              // log that
              lock (message) {
            Log.Singleton.LogMessage(
              $"Message <{message.ID[0].ToString("00")}{message.ID[1].ToString("00")}> is in state <{message.Status}>");

            MessageCenter.Singleton.FireChange(message.Status);
              }

              // send end fragment
              SendEndFragment(message);
            });
              });
        }
예제 #9
0
        /// <summary>
        ///   Creates a message and all it's fragments.
        /// </summary>
        /// <param name="remoteEndPoint">Where to send the message</param>
        /// <param name="messageString">String to send</param>
        /// <param name="maxFragmentSize">Maximum size of one fragment in bytes</param>
        public static Message CreateMessage(IPEndPoint remoteEndPoint, string messageString, ushort maxFragmentSize)
        {
            // convert message string to bytes
              var messageStringBytes = Encoding.ASCII.GetBytes(messageString);

              // create a sorted list of fragments
              var fragmentList = new SortedList<ushort, byte[]>();

              // add all fragments
              while (messageStringBytes.Length > 0) {
            // get the fragment bytes
            byte[] bytes;

            // check the remaining size
            if (messageStringBytes.Length > maxFragmentSize) {
              // take maximum allowed bytes and make a fragment
              bytes = messageStringBytes.Take(maxFragmentSize).ToArray();

              // shift
              messageStringBytes = messageStringBytes.Skip(maxFragmentSize).ToArray();
            }
            else {
              // take whole fragment
              bytes = messageStringBytes;
              messageStringBytes = new byte[0];
            }

            // add the fragment to the list
            fragmentList.Add((ushort) fragmentList.Count, bytes);
              }

              // create a message
              var message = new Message((ushort) fragmentList.Count, fragmentList) {
            RemoteEndPoint = remoteEndPoint,
            Text = messageString
              };

              // return the message
              return message;
        }
예제 #10
0
        /// <summary>
        ///   Makes a prepare fragment.
        /// </summary>
        public static byte[] MakePrepareFragment(Message message)
        {
            // the resulting array of bytes
              var data = new List<byte>();

              // add the type
              data.Add((byte) FragmentType.Prepare);

              // add the id
              data.AddRange(message.ID);

              // add fragment count
              data.AddRange(BitConverter.GetBytes(message.PartCount));

              // add name
              data.AddRange(Encoding.ASCII.GetBytes(Options.Name));

              // return data
              return data.ToArray();
        }
예제 #11
0
        /// <summary>
        ///   Makes an okay fragment.
        /// </summary>
        public static byte[] MakeOkayFragment(Message message)
        {
            // the resulting array of bytes
              var data = new List<byte>();

              // add the type
              data.Add((byte) FragmentType.Okay);

              // add the id
              data.AddRange(message.ID);

              // return data
              return data.ToArray();
        }
예제 #12
0
        /// <summary>
        ///   Makes a missing fragment.
        /// </summary>
        public static byte[] MakeMissingFragment(Message message, List<ushort> missingList)
        {
            // the resulting array of bytes
              var data = new List<byte>();

              // add the type
              data.Add((byte) FragmentType.Missing);

              // add the id
              data.AddRange(message.ID);

              // add missing fragments
              foreach (var missingFragment in missingList) {
            data.AddRange(BitConverter.GetBytes(missingFragment));
              }

              // return data
              return data.ToArray();
        }
예제 #13
0
        /// <summary>
        ///   Makes a data fragment for a fragment of a message.
        /// </summary>
        public static byte[] MakeDataFragment(Message message, ushort number)
        {
            // the resulting array of bytes
              var data = new List<byte>();

              // add the type
              data.Add((byte) FragmentType.Data);

              // add the id
              data.AddRange(message.ID);

              // add the fragment number
              data.AddRange(BitConverter.GetBytes(number));

              // add data
              data.AddRange(message.PartList[number]);

              // return data
              return data.ToArray();
        }