You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
2.9 KiB
117 lines
2.9 KiB
7 years ago
|
package p2p
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"bytes"
|
||
|
"encoding/binary"
|
||
7 years ago
|
"io"
|
||
|
"log"
|
||
|
"net"
|
||
6 years ago
|
"time"
|
||
7 years ago
|
)
|
||
|
|
||
|
/*
|
||
|
P2p Message data structure:
|
||
|
|
||
|
---- message start -----
|
||
6 years ago
|
1 byte - p2p type
|
||
|
0x00: unicast (no need to forward)
|
||
|
0x01: broadcast (may need to forward to other neighbors)
|
||
|
4 bytes - message content size n in number of bytes
|
||
|
content (n bytes) - actual message content
|
||
7 years ago
|
---- message end -----
|
||
|
|
||
6 years ago
|
|
||
7 years ago
|
*/
|
||
7 years ago
|
|
||
6 years ago
|
// Read the message type and content size, and return the actual content.
|
||
|
func ReadMessageContent(conn net.Conn) ([]byte, error) {
|
||
7 years ago
|
var (
|
||
6 years ago
|
contentBuf = bytes.NewBuffer([]byte{})
|
||
7 years ago
|
r = bufio.NewReader(conn)
|
||
7 years ago
|
)
|
||
|
|
||
6 years ago
|
timeoutDuration := 1 * time.Second
|
||
|
conn.SetReadDeadline(time.Now().Add(timeoutDuration))
|
||
|
|
||
6 years ago
|
//// Read 1 byte for message type
|
||
6 years ago
|
_, err := r.ReadByte()
|
||
|
switch err {
|
||
|
case io.EOF:
|
||
|
log.Printf("Error reading the p2p message type field: %s", err)
|
||
6 years ago
|
return contentBuf.Bytes(), err
|
||
6 years ago
|
case nil:
|
||
|
//log.Printf("Received p2p message type: %x\n", msgType)
|
||
|
default:
|
||
|
log.Printf("Error reading the p2p message type field: %s", err)
|
||
6 years ago
|
return contentBuf.Bytes(), err
|
||
7 years ago
|
}
|
||
|
// TODO: check on msgType and take actions accordingly
|
||
|
|
||
7 years ago
|
//// Read 4 bytes for message size
|
||
7 years ago
|
fourBytes := make([]byte, 4)
|
||
|
n, err := r.Read(fourBytes)
|
||
7 years ago
|
if err != nil {
|
||
6 years ago
|
log.Printf("Error reading the p2p message size field")
|
||
6 years ago
|
return contentBuf.Bytes(), err
|
||
7 years ago
|
} else if n < len(fourBytes) {
|
||
6 years ago
|
log.Printf("Failed reading the p2p message size field: only read %d bytes", n)
|
||
6 years ago
|
return contentBuf.Bytes(), err
|
||
7 years ago
|
}
|
||
|
|
||
6 years ago
|
//log.Print(fourBytes)
|
||
6 years ago
|
// Number of bytes for the message content
|
||
7 years ago
|
bytesToRead := binary.BigEndian.Uint32(fourBytes)
|
||
6 years ago
|
//log.Printf("The content size is %d bytes.", bytesToRead)
|
||
7 years ago
|
|
||
6 years ago
|
//// Read the content in chunk of 1024 bytes
|
||
7 years ago
|
tmpBuf := make([]byte, 1024)
|
||
|
ILOOP:
|
||
|
for {
|
||
6 years ago
|
timeoutDuration := 1 * time.Second
|
||
|
conn.SetReadDeadline(time.Now().Add(timeoutDuration))
|
||
7 years ago
|
if bytesToRead < 1024 {
|
||
|
// Read the last number of bytes less than 1024
|
||
|
tmpBuf = make([]byte, bytesToRead)
|
||
|
}
|
||
|
n, err := r.Read(tmpBuf)
|
||
6 years ago
|
contentBuf.Write(tmpBuf[:n])
|
||
7 years ago
|
|
||
|
switch err {
|
||
|
case io.EOF:
|
||
|
// TODO: should we return error here, or just ignore it?
|
||
|
log.Printf("EOF reached while reading p2p message")
|
||
|
break ILOOP
|
||
|
case nil:
|
||
|
bytesToRead -= uint32(n) // TODO: think about avoid the casting in every loop
|
||
|
if bytesToRead <= 0 {
|
||
|
break ILOOP
|
||
|
}
|
||
|
default:
|
||
|
log.Printf("Error reading p2p message")
|
||
|
return []byte{}, err
|
||
|
}
|
||
|
}
|
||
6 years ago
|
return contentBuf.Bytes(), nil
|
||
7 years ago
|
}
|
||
6 years ago
|
|
||
|
func CreateMessage(msgType byte, data []byte) []byte {
|
||
|
buffer := bytes.NewBuffer([]byte{})
|
||
|
|
||
|
buffer.WriteByte(msgType)
|
||
|
|
||
|
fourBytes := make([]byte, 4)
|
||
|
binary.BigEndian.PutUint32(fourBytes, uint32(len(data)))
|
||
|
buffer.Write(fourBytes)
|
||
|
|
||
|
buffer.Write(data)
|
||
|
return buffer.Bytes()
|
||
|
}
|
||
|
|
||
|
func SendMessageContent(conn net.Conn, data []byte) {
|
||
|
msgToSend := CreateMessage(byte(1), data)
|
||
|
w := bufio.NewWriter(conn)
|
||
|
w.Write(msgToSend)
|
||
|
w.Flush()
|
||
|
}
|