// DownloadFile retrieves the erasure-coded segments corresponding to a given file from a quorum. // It reconstructs the original file from the segments using erasure.RebuildSector(). func DownloadFile(mr common.MessageRouter, fileHash crypto.Hash, length int, k int, quorum [common.QuorumSize]common.Address) (fileData []byte, err error) { // spawn a separate thread for each segment for i := range quorum { go func() { // send request m := new(common.Message) m.Destination = quorum[i] m.Payload = []byte{0x01} m.Payload = append(m.Payload, fileHash[:]...) mr.SendMessage(m) // wait for response }() } return }
// TestTCPDownloadFile tests the NewTCPServer and DownloadFile functions. // NewTCPServer must properly initialize a TCP server. // UploadFile splits a file into erasure-coded segments and distributes them across a quorum. // k is the number of non-redundant segments. // The file is padded to satisfy the erasure-coding requirements that: // len(fileData) = k*bytesPerSegment, and: // bytesPerSegment % 64 = 0 func UploadFile(mr common.MessageRouter, file *os.File, k int, quorum [common.QuorumSize]common.Address) (bytesPerSegment int, err error) { // read file fileInfo, err := file.Stat() if err != nil { return } if fileInfo.Size() > int64(common.QuorumSize*common.MaxSegmentSize) { err = fmt.Errorf("File exceeds maximum per-quorum size") return } fileData := make([]byte, fileInfo.Size()) _, err = io.ReadFull(file, fileData) if err != nil { return } // calculate EncodeRing parameters, padding file if necessary bytesPerSegment = len(fileData) / k if bytesPerSegment%64 != 0 { bytesPerSegment += 64 - (bytesPerSegment % 64) padding := k*bytesPerSegment - len(fileData) fileData = append(fileData, bytes.Repeat([]byte{0x00}, padding)...) } // create erasure-coded segments segments, err := erasure.EncodeRing(k, bytesPerSegment, fileData) if err != nil { return } // for now we just send segment i to node i // this may need to be randomized for security for i := range quorum { m := new(common.Message) m.Destination = quorum[i] m.Payload = append([]byte{byte(i)}, []byte(segments[i])...) err = mr.SendMessage(m) if err != nil { return } } return }