private byte[] getPreBuffer()
        {
            // get md5 hash
            ChecksumCalc checksum = new ChecksumCalc();

            byte[] md5 = checksum.GetMD5Checksum(filePath);

            FileInfo f = new FileInfo(filePath);

            // Using windows 1252 encoding
            Encoding encoding1252 = Encoding.GetEncoding(1252);

            //byte[] fileName = Encoding.ASCII.GetBytes(f.Name);
            byte[] fileName = encoding1252.GetBytes(f.Name);
            byte[] filenameSizePlusFilename = new byte[fileName.Length + 1];

            // copy byte representing the size of the filename
            // to the beginning of the first packet sent
            int  length  = fileName.Length;
            byte lengthB = (byte)length;

            new byte[] { lengthB }.CopyTo(filenameSizePlusFilename, 0);

            // copies file name in ASCII format from index 1 to length of filename
            Array.Copy(fileName, 0, filenameSizePlusFilename, 1, fileName.Length);

            // get file size and convert to 8 bytes
            long fileSize = f.Length;

            byte[] fileSizeB = BitConverter.GetBytes(fileSize);

            // preBuffer has size:
            // file name +
            // 1 byte for file name size +
            // 8 bytes is the size of the file +
            // 16 bytes is the md5 hash of the file
            byte[] preBuffer = new byte[fileName.Length + 1 + 8 + 16];

            // copy file name size and file name to preBuffer
            filenameSizePlusFilename.CopyTo(preBuffer, 0);

            // copy fileSizeB to end of preBuffer
            Array.Copy(fileSizeB, 0, preBuffer, fileName.Length + 1, 8);

            // copy md5 hash to preBuffer
            Array.Copy(md5, 0, preBuffer, fileName.Length + 1 + 8, 16);

            // format the transfer like this:
            // byte = filename size
            // file name
            // long = file size in bytes, ulong is 64 bit so filesize could be limitless
            // 16 bytes md5 hash of file
            // file content

            return(preBuffer);
        }
Example #2
0
        public void ReadCallback(IAsyncResult ar)
        {
            StateObject tempState = (StateObject)ar.AsyncState;
            Socket      handler   = tempState.workSocket;

            // handle connection problems
            int bytesRead = 0;

            try
            {
                bytesRead = handler.EndReceive(ar);
            }
            catch (SocketException socketError)
            {
                Console.WriteLine("Socket error while transfering: " + socketError.Message);
                Console.WriteLine("Reseting connection...");
                resetConnection();
            }
            catch (Exception error)
            {
                Console.WriteLine("Error while transfering: " + error.Message);
                return;
            }

            if (bytesRead <= 0)
            {
                return;
            }

            // add to counter
            counter.AddBytes((uint)bytesRead);

            if (isFirstPacket)
            {
                try
                {
                    // gets the first byte
                    byte[] firstByte = new byte[1];
                    firstByte = tempState.buffer.Take(1).ToArray();

                    // first byte has a value 0 - 255
                    fileNameLength = Convert.ToInt32(firstByte[0]);

                    // a fileName cannot be more then 255 characters because a byte cannot have have a higher value...
                    if (fileNameLength > 255)
                    {
                        // filename is not valid...
                        // this should not happen, should somehow at least validate the first packet to ensure
                        // it contain the right information...
                        return;
                        //fileNameLength = 255;
                    }

                    // TODO:
                    // check if fileName is valid

                    // Windows 1252 encoding
                    Encoding encoding1252 = Encoding.GetEncoding(1252);
                    fileName = encoding1252.GetString(tempState.buffer, 1, fileNameLength);

                    // after the file name comes the size of the file
                    // should be a long
                    // that is 64 bit = 8 byte
                    byte[] fileSizeB = tempState.buffer.Skip(1 + fileNameLength).Take(8).ToArray();
                    fileSize = BitConverter.ToInt64(fileSizeB, 0);

                    // get md5 hash
                    // md5 hash is 16 bytes = 128 bit
                    md5 = tempState.buffer.Skip(1 + fileNameLength + 8).Take(16).ToArray();

                    // set total to be received
                    totalBytesToBeReceived = fileNameLength + fileSize + 9 + 16;

                    // TODO:
                    // get FileInfo object

                    // TODO:
                    // start download counter, datetime, total filesize to download etc
                    // get MD5 hash or other hash of file
                    // make sure all meta data and other stuff is actually sent
                    // calculate hash of when file has been received and written to a file here
                    // close socket and stop thread when entire file has been written

                    // start timer that will execute an event every 1 sec
                    // that shows mb/s kb/s etc
                    timer = new System.Timers.Timer()
                    {
                        Interval = 1000, Enabled = true
                    };
                    timer.Elapsed += timer_Elapsed;
                    timer.Start();
                }
                catch (InvalidCastException castError)
                {
                    // was not able to find file size
                    Console.WriteLine(castError.Message);
                    return;
                }
                catch (Exception error)
                {
                    Console.WriteLine(error.Message);
                    return;
                }
            }

            BinaryWriter writer = null;

            try
            {
                // TODO:
                // only open file while it is not in use
                // wait until file is ready to be written to

                if (isFirstPacket)
                {
                    // old way
                    //writer = new BinaryWriter(File.Open(savePathAndFileName, FileMode.Append));

                    // TODO:
                    // check that file name and path is correct

                    string savePathAndFileName = receivePath + "\\" + fileName;

                    // check if file already exist
                    // if it does, simply append to the file
                    if (File.Exists(savePathAndFileName))
                    {
                        // TODO:
                        // check if md5 hash of existing file is correct
                        // if so, stop transfer

                        // TODO:
                        // if md5 hash is not the same, check file size of existing file
                        // if its bigger than it's supposed too, remove it
                        // if not, start appending to the file


                        Console.WriteLine("File already exist, appending to file...");
                        fileWriter = new ParallelFileWriter(savePathAndFileName, 200, true);
                    }
                    else
                    {
                        // creates a thread pool using BlockingCollection
                        // this will allow a queue of max 200 threads waiting to write to the file
                        // if more than 200 threads are created, they are blocked and wait until the '
                        // queue is free
                        fileWriter = new ParallelFileWriter(savePathAndFileName, 200);
                    }

                    // the first packet contain information that should not be written to the file itself so
                    // if first packet then increase the index to size of fileName + one byte
                    // since we increase the index, we need to reduce the count by the same amount

                    // + 1 byte for size of fileName byte
                    // + 8 bytes for 64 bit long with file size
                    // + 16 bytes for md5 hash
                    // shift = 9 bytes + fileName
                    int shift = fileNameLength + 9 + 16;
                    //writer.Write(tempState.buffer, shift, bytesRead - shift);

                    byte[] data = new byte[bytesRead - shift];
                    Array.Copy(tempState.buffer, shift, data, 0, bytesRead - shift);

                    fileWriter.Write(data);

                    isFirstPacket = false;

                    // set fileName, but do not trigger event
                    FileTransferEvents.filename = fileName;
                }
                else
                {
                    byte[] data = new byte[bytesRead];
                    Array.Copy(tempState.buffer, 0, data, 0, bytesRead);

                    fileWriter.Write(data);

                    //writer.Write(tempState.buffer, 0, bytesRead);
                }

                // add to written files
                totalBytesReceived += bytesRead;

                // check if all bytes has been read and transfer is complete
                if (totalBytesReceived == totalBytesToBeReceived)
                {
                    // trigger file received event
                    FileTransferEvents.FileReceived = fileName;

                    // get file location
                    string savePathAndFileName = receivePath + "\\" + fileName;

                    // reset connection
                    // set everything back to default and wait for new file
                    resetConnection();

                    // close file writer so we can access file again
                    if (writer != null)
                    {
                        writer.Close();
                    }

                    // complete writing tasks and threads
                    fileWriter.Dispose();

                    Console.WriteLine("Calculating md5 hash of received file...");

                    // get md5 hash
                    ChecksumCalc checksum         = new ChecksumCalc();
                    byte[]       md5AfterTransfer = checksum.GetMD5Checksum(savePathAndFileName);

                    // check if md5 received is identical to md5 calculated after transfer
                    bool isIdentical = checksum.checkIfHashisIdentical(md5, md5AfterTransfer);

                    if (isIdentical)
                    {
                        // the hash received before the file transfer is identical to the
                        // hash calculated with the new file
                        Console.WriteLine("SUCCESS: md5 hash match the md5 of received file");
                    }
                    else
                    {
                        // delete file?
                        Console.WriteLine("ERROR: File is corrupt, md5 hash does NOT match the md5 of the file received");
                    }
                }
            }
            catch (Exception error)
            {
                Console.WriteLine(error.Message);
                Thread.Sleep(30);
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                }

                // triggers event with long of bytes written
                //FileTransferEvents.BytesReceived = written;

                // this method starts a new  AsyncCallback(ReadCallback)
                // and this method is ReadCallback so it works as a recursive method
                try
                {
                    handler.BeginReceive(tempState.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), tempState);
                }
                catch (SocketException socketError)
                {
                    Console.WriteLine("Socket error while transfering: " + socketError.Message);
                    Console.WriteLine("Reseting connection...");
                    resetConnection();
                }
                catch (Exception error)
                {
                    Console.WriteLine("Error while transfering: " + error.Message);
                }
            }
        }