Example #1
0
// Make takes a message as a byte slice, along with the expected loss rate and
// target reliability and produces the packets for that message. The packets are
// returned as a slice of byte-slices.
func (p *Packeter) Make(msg []byte, loss, reliability float64) [][]byte {
	l := uint32(len(msg) + 4)
	msk := uint32(255)
	lb := []byte{
		byte(l & msk),
		byte((l >> 8) & msk),
		byte((l >> 16) & msk),
		byte((l >> 24) & msk),
	}
	msg = append(lb, msg...)

	dataShards, parityShards := findRedundancy(len(msg), Packetlength, loss, reliability)
	if parityShards < 1 {
		// reedsolomon.Encoder cannot have 0 parity shards
		// at some point I want to change this so it doesn't use reedsolomon in this
		// case
		parityShards = 1
	}
	shards := dataShards + parityShards

	var data [][]byte
	if enc, e := reedsolomon.New(dataShards, parityShards); err.Warn(e) {
		if data, e = enc.Split(msg); err.Warn(e) {
			err.Warn(enc.Encode(data))
		}
	} else {
		return nil
	}

	idArr := make([]byte, 4)
	rand.Read(idArr)
	id := uint32(idArr[0]) + uint32(idArr[1])<<8 + uint32(idArr[2])<<16 + uint32(idArr[3])<<24

	pk := Packet{}
	pks := make([][]byte, shards)

	pk.MessageId = id
	pk.ParityShards = uint32(parityShards)
	for i := 0; i < shards; i++ {
		pk.PacketId = uint32(i<<16) + uint32(shards)
		pk.Data = data[i]
		if d, e := proto.Marshal(&pk); err.Log(e) {
			pks[i] = d
		} else {
			return nil
		}
	}
	return pks
}
Example #2
0
// Receive collects packets. When exactly enough packets have been recovered to
// reconstruct the message, the message is returned as a byte slice. Otherwise
// nil is returned. Receive can continue to collect packets after the message
// has been constructed for reliability statistics.
func (p Packeter) Receive(b []byte) []byte {
	var pk Packet
	if err.Log(proto.Unmarshal(b, &pk)) {
		return nil
	}
	mid, pid, dataShards, parityShards := pk.MetaData()
	clctr, ok := p[mid]
	if !ok {
		clctr = &collector{
			data:      make([][]byte, dataShards+parityShards),
			collected: make(map[uint32]bool),
			complete:  false,
		}
		p[mid] = clctr
	}
	clctr.collected[pid] = true
	if clctr.complete {
		return nil
	}
	clctr.data[pid] = pk.Data
	if uint32(len(clctr.collected)) >= dataShards {
		clctr.complete = true
		if enc, e := reedsolomon.New(int(dataShards), int(parityShards)); err.Warn(e) {
			if err.Log(enc.Reconstruct(clctr.data)) {

				//maybe should take out as an arg
				ln := int(clctr.data[0][0]) + int(clctr.data[0][1])<<8 + int(clctr.data[0][2])<<16 + int(clctr.data[0][2])<<24
				var out bytes.Buffer
				err.Warn(enc.Join(&out, clctr.data, ln))
				clctr.data = nil

				return out.Bytes()[4:]
			}
		}
	}
	return nil
}