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); }
public void startSending() { try { // Create a TCP socket. sendingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //sendingSocket.SendBufferSize = 8192; sendingSocket.SendBufferSize = 32768; //sendingSocket.SendBufferSize = 65536; // Don't allow another socket to bind to this port. // Should perhaps consider this one //listener.ExclusiveAddressUse = true; // Connect the socket to the remote endpoint. sendingSocket.Connect(endPoint); // TODO: // look at SocketFlags http://msdn.microsoft.com/en-us/library/system.net.sockets.socketflags%28v=vs.110%29.aspx // get md5 hash ChecksumCalc checksum = new ChecksumCalc(); byte[] md5 = checksum.GetMD5Checksum(filePath); FileInfo f = new FileInfo(filePath); // TODO: // fix error with files like xyzæøå.txt // Replace ASIC2 with Windows 1252 encoding //Encoding encoding = Encoding.GetEncoding(1252); byte[] fileName = Encoding.ASCII.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 // sends size of filename (0-255) + filename // plus file size and md5 hash of file // and then disconnect after file has been queued for transmission sendingSocket.BeginSendFile(filePath, preBuffer, null, TransmitFileOptions.Disconnect, new AsyncCallback(FileSendCallback), sendingSocket); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { // this method starts a new AsyncCallback(ReadCallback) // and this method is ReadCallback so it works as a recursive method //handler.BeginReceive(tempState.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), tempState); //Thread.CurrentThread.Interrupt(); } }
public void ReadCallback(IAsyncResult ar) { //int fileNameLen = 1; //String content = String.Empty; StateObject tempState = (StateObject)ar.AsyncState; Socket handler = tempState.workSocket; int bytesRead = handler.EndReceive(ar); if (bytesRead <= 0) { return; } 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 // if file already exist (conflict) // 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: // double check that file path is correct // 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)); string savePathAndFileName = receivePath + "\\" + fileName; // 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 handler.BeginReceive(tempState.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), tempState); //Thread.CurrentThread.Interrupt(); } }
public void sendFileInfo(string filePath) { // check if file exists if (File.Exists(filePath) == false) { return; } // 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 // byte indicating what type of packet it is byte[] commandByte = new byte[] { 9 }; // byte array with port byte[] listenPortByteArray = BitConverter.GetBytes(listenPort); // Creating buffer to send byte[] sendBuffer = combineBytes(commandByte, listenPortByteArray, preBuffer); // Sending UPD packet socket.SendTo(sendBuffer, endPoint); Console.WriteLine("\nUDP Responder"); Console.WriteLine(String.Format("Sending file info to {0}, file: \"{1}\"", endPoint.ToString(), f.Name)); }