mirror of
https://github.com/openp2p-cn/openp2p.git
synced 2025-10-05 08:37:04 +08:00
151 lines
4.3 KiB
Go
151 lines
4.3 KiB
Go
package openp2p
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
var ErrDeadlineExceeded error = &DeadlineExceededError{}
|
|
|
|
// DeadlineExceededError is returned for an expired deadline.
|
|
type DeadlineExceededError struct{}
|
|
|
|
// Implement the net.Error interface.
|
|
// The string is "i/o timeout" because that is what was returned
|
|
// by earlier Go versions. Changing it may break programs that
|
|
// match on error strings.
|
|
func (e *DeadlineExceededError) Error() string { return "i/o timeout" }
|
|
func (e *DeadlineExceededError) Timeout() bool { return true }
|
|
func (e *DeadlineExceededError) Temporary() bool { return true }
|
|
|
|
// implement io.Writer
|
|
type overlayConn struct {
|
|
tunnel *P2PTunnel
|
|
connTCP net.Conn
|
|
id uint64
|
|
rtid uint64
|
|
running bool
|
|
isClient bool
|
|
appID uint64
|
|
appKey uint64
|
|
appKeyBytes []byte
|
|
// for udp
|
|
connUDP *net.UDPConn
|
|
remoteAddr net.Addr
|
|
udpRelayData chan []byte
|
|
lastReadUDPTs time.Time
|
|
}
|
|
|
|
func (oConn *overlayConn) run() {
|
|
gLog.Printf(LvDEBUG, "%d overlayConn run start", oConn.id)
|
|
defer gLog.Printf(LvDEBUG, "%d overlayConn run end", oConn.id)
|
|
oConn.running = true
|
|
oConn.lastReadUDPTs = time.Now()
|
|
buffer := make([]byte, ReadBuffLen+PaddingSize)
|
|
readBuf := buffer[:ReadBuffLen]
|
|
encryptData := make([]byte, ReadBuffLen+PaddingSize) // 16 bytes for padding
|
|
tunnelHead := new(bytes.Buffer)
|
|
relayHead := new(bytes.Buffer)
|
|
binary.Write(relayHead, binary.LittleEndian, oConn.rtid)
|
|
binary.Write(tunnelHead, binary.LittleEndian, oConn.id)
|
|
for oConn.running && oConn.tunnel.isRuning() {
|
|
buff, dataLen, err := oConn.Read(readBuf)
|
|
if err != nil {
|
|
if ne, ok := err.(net.Error); ok && ne.Timeout() {
|
|
continue
|
|
}
|
|
// overlay tcp connection normal close, debug log
|
|
gLog.Printf(LvDEBUG, "overlayConn %d read error:%s,close it", oConn.id, err)
|
|
break
|
|
}
|
|
payload := buff[:dataLen]
|
|
if oConn.appKey != 0 {
|
|
payload, _ = encryptBytes(oConn.appKeyBytes, encryptData, buffer[:dataLen], dataLen)
|
|
}
|
|
writeBytes := append(tunnelHead.Bytes(), payload...)
|
|
if oConn.rtid == 0 {
|
|
oConn.tunnel.conn.WriteBytes(MsgP2P, MsgOverlayData, writeBytes)
|
|
gLog.Printf(LvDEBUG, "write overlay data to %d:%d bodylen=%d", oConn.rtid, oConn.id, len(writeBytes))
|
|
} else {
|
|
// write raley data
|
|
all := append(relayHead.Bytes(), encodeHeader(MsgP2P, MsgOverlayData, uint32(len(writeBytes)))...)
|
|
all = append(all, writeBytes...)
|
|
oConn.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, all)
|
|
gLog.Printf(LvDEBUG, "write relay data to %d:%d bodylen=%d", oConn.rtid, oConn.id, len(writeBytes))
|
|
}
|
|
}
|
|
if oConn.connTCP != nil {
|
|
oConn.connTCP.Close()
|
|
}
|
|
if oConn.connUDP != nil {
|
|
oConn.connUDP.Close()
|
|
}
|
|
oConn.tunnel.overlayConns.Delete(oConn.id)
|
|
// notify peer disconnect
|
|
if oConn.isClient {
|
|
req := OverlayDisconnectReq{ID: oConn.id}
|
|
if oConn.rtid == 0 {
|
|
oConn.tunnel.conn.WriteMessage(MsgP2P, MsgOverlayDisconnectReq, &req)
|
|
} else {
|
|
// write relay data
|
|
msg, _ := newMessage(MsgP2P, MsgOverlayDisconnectReq, &req)
|
|
msgWithHead := append(relayHead.Bytes(), msg...)
|
|
oConn.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, msgWithHead)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (oConn *overlayConn) Read(reuseBuff []byte) (buff []byte, n int, err error) {
|
|
if oConn.connUDP != nil {
|
|
if time.Now().After(oConn.lastReadUDPTs.Add(time.Minute * 5)) {
|
|
err = errors.New("udp close")
|
|
return
|
|
}
|
|
if oConn.remoteAddr != nil { // as server
|
|
select {
|
|
case buff = <-oConn.udpRelayData:
|
|
n = len(buff)
|
|
oConn.lastReadUDPTs = time.Now()
|
|
case <-time.After(time.Second * 10):
|
|
err = ErrDeadlineExceeded
|
|
}
|
|
} else { // as client
|
|
oConn.connUDP.SetReadDeadline(time.Now().Add(5 * time.Second))
|
|
n, _, err = oConn.connUDP.ReadFrom(reuseBuff)
|
|
if err == nil {
|
|
oConn.lastReadUDPTs = time.Now()
|
|
}
|
|
buff = reuseBuff
|
|
}
|
|
return
|
|
}
|
|
oConn.connTCP.SetReadDeadline(time.Now().Add(time.Second * 5))
|
|
n, err = oConn.connTCP.Read(reuseBuff)
|
|
buff = reuseBuff
|
|
return
|
|
}
|
|
|
|
// calling by p2pTunnel
|
|
func (oConn *overlayConn) Write(buff []byte) (n int, err error) {
|
|
// add mutex when multi-thread calling
|
|
if oConn.connUDP != nil {
|
|
if oConn.remoteAddr == nil {
|
|
n, err = oConn.connUDP.Write(buff)
|
|
} else {
|
|
n, err = oConn.connUDP.WriteTo(buff, oConn.remoteAddr)
|
|
}
|
|
if err != nil {
|
|
oConn.running = false
|
|
}
|
|
return
|
|
}
|
|
n, err = oConn.connTCP.Write(buff)
|
|
if err != nil {
|
|
oConn.running = false
|
|
}
|
|
return
|
|
}
|