Beispiel #1
0
 private void AddDirectory(DirectoryInfo di, DirectoryInfo root)
 {
     foreach (FileInfo fi in di.GetFiles())
     {
         AppManifestFile addThis = new AppManifestFile(Utility.GetRelativePath(root.FullName, fi.FullName), (long)fi.Length);
         if (this._hashFiles)
         {
             using (FileStream fs = File.OpenRead(fi.FullName))
             {
                 string hash = Utility.GetSha1Hash(fs);
                 fs.Close();
                 addThis.sha1_hash = hash;
             }
         }
         this.AddFile(addThis);
     }
     foreach (DirectoryInfo subdir in di.GetDirectories())
     {
         this.AddDirectory(subdir, root);
     }
 }
Beispiel #2
0
        private void doReceive()
        {
            _transfer.State = TransferState.WaitingForManifest;

            TcpListener listener = new TcpListener(IPAddress.Any, _transfer.Port);
            TcpClient   client   = null;

            try
            {
                listener.Start();
                client = listener.AcceptTcpClient(); // blocks until the remote peer connects
                listener.Stop();
            }
            catch (SocketException ex)
            {
                Debug.Write(ex);
                _transfer.StateChangeReason = "Could not connect to peer";
                _transfer.State             = TransferState.Failed;
                if (client != null && client.Connected)
                {
                    client.Close();
                }
                return;
            }

            // wait until the manifest has been received (on main thread, not this one)
            Stopwatch sw = new Stopwatch();

            sw.Start();
            bool abort = false;

            while (true)
            {
                lock (_transfer)  // this will also be accessed by the main thread
                {
                    if (_transfer.Manifest != null && _transfer.Manifest.files.Count > 0)
                    {
                        break;
                    }
                    Debug.WriteLine("Waiting for manifest...");
                    Thread.Sleep(250);

                    if (sw.ElapsedMilliseconds > 30000)
                    {
                        Debug.WriteLine("Timed out after 30 seconds waiting for manifest");
                        _transfer.StateChangeReason = "Timed out after 30 seconds waiting for manifest";
                        _transfer.State             = TransferState.Failed;
                        abort = true;
                        break;
                    }
                }
            }

            if (abort)
            {
                client.Close();
                return;
            }

            _transfer.State = TransferState.InProgress;
            NetworkStream ns = client.GetStream();

            byte[] buf                = new byte[64 * 1024];
            int    fileIndex          = 0;
            int    bytesRead          = 0;
            long   totalBytesExpected = 0;
            long   totalBytesWritten  = 0;

            // get total bytes we expect to receive
            List <AppManifestFile> files = _transfer.Manifest.files;

            foreach (AppManifestFile mf in _transfer.Manifest.files)
            {
                totalBytesExpected += mf.size;
            }
            _transfer.TotalBytes = totalBytesExpected;
            Stopwatch stopwatch = new Stopwatch();

            for (fileIndex = 0; fileIndex < _transfer.Manifest.files.Count; fileIndex++)
            {
                // get info about next file in the manifest
                AppManifestFile currentFile = files[fileIndex];
                string          rootDir     = _transfer.ManifestRoot.FullName;
                string          filePath;
                Utility.EnsureEndsWithSlash(ref rootDir);

                //determine path to save file
                filePath = rootDir + currentFile.path;

                //ensure this is inside Library path (../ may escape it)
                if (filePath.Contains(".." + Path.DirectorySeparatorChar) || filePath.Contains(".." + Path.AltDirectorySeparatorChar) ||
                    !(currentFile.path.StartsWith("." + Path.DirectorySeparatorChar.ToString()) || currentFile.path.StartsWith("." + Path.AltDirectorySeparatorChar)))
                {
                    throw new Exception("Cannot write to a directory outside ManifestRoot. " + filePath + " is outside " + rootDir);
                }

                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists && currentFile.size > 0)
                {
                    try
                    {
                        // create directory if needed
                        Directory.CreateDirectory(fi.DirectoryName);
                    }
                    catch (Exception ex)
                    {
                        Debug.Write(ex);
                        _transfer.StateChangeReason = "Could not create directory " + fi.DirectoryName;
                        _transfer.State             = TransferState.Failed;

                        ns.Close();
                        if (client.Connected)
                        {
                            client.Close();
                        }

                        return;
                    }
                }

                if (currentFile.size == 0 && fi.Exists)
                {
                    // the manifest contains a zero-byte file, this means we should delete the file (if it exists) on our local copy
                    fi.Delete();
                    Debug.WriteLine("Deleted " + fi.FullName);
                    continue;
                }

                // open the file for writing, replacing any existing file with same name
                FileStream fs;
                long       bytesRemaining = currentFile.size;
                try
                {
                    fs = File.Create(filePath);
                }
                catch (Exception ex)
                {
                    Debug.Write(ex);
                    _transfer.StateChangeReason = "Could not create file " + filePath;
                    _transfer.State             = TransferState.Failed;

                    ns.Close();
                    if (client.Connected)
                    {
                        client.Close();
                    }

                    return;
                }

                Debug.WriteLine("Receiving [" + filePath + "]");


                // determine the number of bytes remaining to write to the current file, and read up to that many bytes (or buffer length,
                // whichever is smaller) from the network
                try
                {
                    stopwatch.Start();
                    while (bytesRemaining > 0 && (bytesRead = ns.Read(buf, 0, (int)Utility.Min((long)buf.Length, bytesRemaining))) != 0)
                    {
                        fs.Write(buf, 0, bytesRead);
                        totalBytesWritten          += bytesRead;
                        bytesRemaining             -= bytesRead;
                        _transfer.BytesTransferred += bytesRead;
                        if (stopwatch.ElapsedMilliseconds > 200)
                        {
                            _transfer.FireDataTransferredEvent();
                            stopwatch.Restart();
                        }
                    }
                    stopwatch.Stop();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("Exception while reading data from peer");
                    Debug.WriteLine(ex);

                    _transfer.StateChangeReason = "Error reading data from peer";
                    _transfer.State             = TransferState.Failed;

                    ns.Close();
                    fs.Close();
                    if (client.Connected)
                    {
                        client.Close();
                    }

                    return;
                }

                // this file is done, move on to the next one
                fs.Close();

                if (bytesRead == 0 && bytesRemaining > 0)  // bytesRead can be 0 even while data remains on the stream, if bytesRemaining was also 0
                {
                    break;
                }
            }



            if (totalBytesWritten < totalBytesExpected)
            {
                Debug.WriteLine(String.Format("Expected {0} bytes but only received {1} bytes", totalBytesExpected, totalBytesWritten));
                _transfer.StateChangeReason = String.Format(new FileSizeFormatProvider(), "Peer closed connection after {0:fs} transferred (expected {1:fs})", totalBytesWritten, totalBytesExpected);
                _transfer.State             = TransferState.Failed;
            }
            else
            {
                _transfer.State = TransferState.Complete;
            }

            ns.Close();
            client.Close();
        }
Beispiel #3
0
        public void doSend()
        {
            NetworkStream ns     = null;
            FileStream    fs     = null;
            TcpClient     client = new TcpClient();

            try
            {
                client.Connect(_transfer.Peer.Address, _transfer.Port);
                ns = client.GetStream();

                List <AppManifestFile> files = _transfer.Manifest.files;
                string rootDir = _transfer.ManifestRoot.FullName;
                Utility.EnsureEndsWithSlash(ref rootDir);
                string filePath;
                byte[] buf = new byte[64 * 1024];

                _transfer.State = TransferState.InProgress;

                for (int fileIndex = 0; fileIndex < files.Count; fileIndex++)
                {
                    AppManifestFile currentFile = files[fileIndex];
                    filePath = rootDir + currentFile.path;
                    if (!File.Exists(filePath)) // this entry has put in the manifest to tell the remote peer to delete the file, we dont need to send anything
                    {
                        continue;
                    }
                    fs = File.OpenRead(filePath);

                    Debug.WriteLine("Sending [" + filePath + "]");

                    int bytesRead;


                    while ((bytesRead = fs.Read(buf, 0, buf.Length)) != 0)
                    {
                        ns.Write(buf, 0, bytesRead);
                    }
                    fs.Close();
                }

                _transfer.State = TransferState.Complete;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception while sending data to peer");
                Debug.WriteLine(ex);

                _transfer.StateChangeReason = "Error sending data to peer";
                _transfer.State             = TransferState.Failed;
            }
            finally
            {
                if (ns != null)
                {
                    ns.Close();
                }

                if (fs != null)
                {
                    fs.Close();
                }

                if (client != null && client.Connected)
                {
                    client.Close();
                }
            }
        }
Beispiel #4
0
 private void AddFile(AppManifestFile file)
 {
     files.Add(file);
 }