// downloadSector retrieves a Ring from the quorum it is stored on. // It reconstructs the original Sector from the Ring. func downloadSector(hash crypto.Hash) (sec *common.Sector, err error) { // look up Sector in SectorDB rh := SectorDB[hash] if rh == nil { err = fmt.Errorf("Sector not found in database") return } // send requests to each member of the quorum var segs []common.Segment for i := range rh.Hosts { var seg common.Segment sendErr := router.SendMessage(&common.Message{ Dest: rh.Hosts[i], Proc: "Server.DownloadSegment", Args: rh.SegHashes[i], Resp: &seg, }) if sendErr == nil { segs = append(segs, seg) } else { fmt.Println(sendErr) } } // rebuild file sec, err = erasure.RebuildSector(segs, rh.Params) return }
func (dh *downloadHandler) HandleMessage(payload []byte) { // first byte is the segment index dh.indices = append(dh.indices, uint8(payload[0])) dh.segments = append(dh.segments, string(payload[1:])) // if enough segments have been collected, reconstruct the data if len(dh.segments) == dh.k { dh.data, _ = erasure.RebuildSector(dh.k, dh.b, dh.segments, dh.indices) dh.done <- true } }
// TestRPCUploadSector tests the NewRPCServer and uploadFile functions. // NewRPCServer must properly initialize a RPC server. // uploadSector must succesfully distribute a Sector among a quorum. // The uploaded Sector must be successfully reconstructed. func TestRPCuploadSector(t *testing.T) { SectorDB = make(map[crypto.Hash]*common.RingHeader) // create RPCServer var err error router, err = network.NewRPCServer(9985) if err != nil { t.Fatal("Failed to initialize RPCServer:", err) } defer router.Close() // create quorum var q [common.QuorumSize]common.Address var shs [common.QuorumSize]Server for i := 0; i < common.QuorumSize; i++ { q[i] = common.Address{0, "localhost", 9000 + i} qrpc, err := network.NewRPCServer(9000 + i) defer qrpc.Close() if err != nil { t.Fatal("Failed to initialize RPCServer:", err) } q[i].ID = qrpc.RegisterHandler(&shs[i]) } // create sector secData, err := crypto.RandomByteSlice(70000) if err != nil { t.Fatal("Could not generate test data:", err) } sec, err := common.NewSector(secData) if err != nil { t.Fatal("Failed to create sector:", err) } // add sector to database k := common.QuorumSize / 2 SectorDB[sec.Hash] = &common.RingHeader{ Hosts: q, Params: sec.CalculateParams(k), } // upload sector to quorum err = uploadSector(sec) if err != nil { t.Fatal("Failed to upload file:", err) } // rebuild file from first k segments var newRing []common.Segment for i := 0; i < k; i++ { newRing = append(newRing, shs[i].seg) } sec, err = erasure.RebuildSector(newRing, SectorDB[sec.Hash].Params) if err != nil { t.Fatal("Failed to rebuild file:", err) } // check hash rebuiltHash, err := crypto.CalculateHash(sec.Data) if err != nil { t.Fatal("Failed to calculate hash:", err) } if sec.Hash != rebuiltHash { t.Fatal("Failed to recover file: hashes do not match") } }
// TestTCPUploadFile tests the NewTCPServer and UploadFile functions. // NewTCPServer must properly initialize a TCP server. // UploadFile must succesfully distribute a file among a quorum. // The uploaded file must be successfully reconstructed. func TestTCPUploadFile(t *testing.T) { // create TCPServer tcp, err := network.NewTCPServer(9988) if err != nil { t.Fatal("Failed to initialize TCPServer:", err) } defer tcp.Close() // create quorum var q [common.QuorumSize]common.Address var uhs [common.QuorumSize]uploadHandler for i := 0; i < common.QuorumSize; i++ { q[i] = common.Address{0, "localhost", 9000 + i} qtcp, err := network.NewTCPServer(9000 + i) defer qtcp.Close() if err != nil { t.Fatal("Failed to initialize TCPServer:", err) } uhs[i].done = make(chan bool, 1) q[i].Id = qtcp.AddMessageHandler(&uhs[i]).Id } // create file file, err := os.Create("InputFile") if err != nil { t.Fatal("Failed to create file \"InputFile\"") } defer file.Close() defer os.Remove("InputFile") fileData, err := crypto.RandomByteSlice(70000) if err != nil { t.Fatal("Could not generate test data:", err) } err = ioutil.WriteFile("InputFile", fileData, 0644) if err != nil { t.Fatal("Failed to write to file InputFile:", err) } // calculate hash origHash, err := crypto.CalculateHash(fileData) if err != nil { t.Fatal("Failed to calculate hash:", err) } // upload file to quorum k := 50 b, err := UploadFile(tcp, file, k, q) if err != nil { t.Fatal("Failed to upload file:", err) } // wait for all participants to complete for i := range uhs { <-uhs[i].done } // rebuild file from first k segments segments := make([]string, k) indices := make([]uint8, k) for i := 0; i < k; i++ { segments[i] = string(uhs[i].data) indices[i] = uint8(uhs[i].index) } rebuiltData, err := erasure.RebuildSector(k, b, segments, indices) if err != nil { t.Fatal("Failed to rebuild file:", err) } // remove padding rebuiltData = rebuiltData[:len(fileData)] // check hash rebuiltHash, err := crypto.CalculateHash(rebuiltData) if err != nil { t.Fatal("Failed to calculate hash:", err) } if origHash != rebuiltHash { t.Fatal("Failed to recover file: hashes do not match") } }