mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
create Client in main package
This commit is contained in:
parent
6189df2d37
commit
afa71d52f1
3 changed files with 137 additions and 75 deletions
102
client.go
Normal file
102
client.go
Normal file
|
@ -0,0 +1,102 @@
|
|||
package quic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/qerr"
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
)
|
||||
|
||||
// A Client of QUIC
|
||||
type Client struct {
|
||||
addr *net.UDPAddr
|
||||
conn *net.UDPConn
|
||||
|
||||
connectionID protocol.ConnectionID
|
||||
version protocol.VersionNumber
|
||||
|
||||
session *Session
|
||||
}
|
||||
|
||||
// NewClient makes a new client
|
||||
func NewClient(addr *net.UDPAddr) (*Client, error) {
|
||||
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: generate cryptographically secure random ConnectionID
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
connectionID := protocol.ConnectionID(rand.Int63())
|
||||
|
||||
client := &Client{
|
||||
addr: addr,
|
||||
conn: conn,
|
||||
version: protocol.Version36,
|
||||
connectionID: connectionID,
|
||||
}
|
||||
|
||||
streamCallback := func(session *Session, stream utils.Stream) {}
|
||||
|
||||
client.session, err = newClientSession(conn, addr, client.version, client.connectionID, streamCallback, client.closeCallback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Listen listens
|
||||
func (c *Client) Listen() {
|
||||
go c.session.run()
|
||||
|
||||
for {
|
||||
data := getPacketBuffer()
|
||||
data = data[:protocol.MaxPacketSize]
|
||||
|
||||
n, _, err := c.conn.ReadFromUDP(data)
|
||||
utils.Debugf("%d", n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = data[:n]
|
||||
|
||||
err = c.handlePacket(data)
|
||||
if err != nil {
|
||||
utils.Errorf("error handling packet: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handlePacket(packet []byte) error {
|
||||
if protocol.ByteCount(len(packet)) > protocol.MaxPacketSize {
|
||||
return qerr.PacketTooLarge
|
||||
}
|
||||
|
||||
rcvTime := time.Now()
|
||||
|
||||
r := bytes.NewReader(packet)
|
||||
|
||||
hdr, err := ParsePublicHeader(r)
|
||||
if err != nil {
|
||||
return qerr.Error(qerr.InvalidPacketHeader, err.Error())
|
||||
}
|
||||
hdr.Raw = packet[:len(packet)-r.Len()]
|
||||
|
||||
c.session.handlePacket(&receivedPacket{
|
||||
remoteAddr: c.addr,
|
||||
publicHeader: hdr,
|
||||
data: packet[len(packet)-r.Len():],
|
||||
rcvTime: rcvTime,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) closeCallback(id protocol.ConnectionID) {
|
||||
utils.Infof("Connection %x closed.", id)
|
||||
c.conn.Close()
|
||||
}
|
29
client_test.go
Normal file
29
client_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package quic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/qerr"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Client", func() {
|
||||
var client *Client
|
||||
|
||||
BeforeEach(func() {
|
||||
client = &Client{}
|
||||
})
|
||||
|
||||
It("errors on invalid public header", func() {
|
||||
err := client.handlePacket(nil)
|
||||
Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.InvalidPacketHeader))
|
||||
})
|
||||
|
||||
It("errors on large packets", func() {
|
||||
err := client.handlePacket(bytes.Repeat([]byte{'a'}, int(protocol.MaxPacketSize)+1))
|
||||
Expect(err).To(MatchError(qerr.PacketTooLarge))
|
||||
})
|
||||
})
|
|
@ -1,95 +1,26 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
quic "github.com/lucas-clemente/quic-go"
|
||||
"github.com/lucas-clemente/quic-go/crypto"
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/handshake"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addr := "quic.clemente.io:6121"
|
||||
|
||||
conn, err := connect(addr)
|
||||
defer conn.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
utils.SetLogLevel(utils.LogLevelDebug)
|
||||
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
connectionID := protocol.ConnectionID(0x1337 + rand.Int63())
|
||||
packetNumber := protocol.PacketNumber(1)
|
||||
version := protocol.Version34
|
||||
|
||||
ph := quic.PublicHeader{
|
||||
ConnectionID: connectionID,
|
||||
PacketNumber: packetNumber,
|
||||
PacketNumberLen: protocol.PacketNumberLen6,
|
||||
VersionFlag: true,
|
||||
VersionNumber: version,
|
||||
}
|
||||
|
||||
raw := make([]byte, 0, protocol.MaxPacketSize)
|
||||
buffer := bytes.NewBuffer(raw)
|
||||
|
||||
err = ph.Write(buffer, protocol.Version34, protocol.PerspectiveClient)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
payloadStartIndex := buffer.Len()
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
tags := make(map[handshake.Tag][]byte)
|
||||
tags[handshake.TagSNI] = []byte("quic.clemente.io")
|
||||
tags[handshake.TagPDMD] = []byte("X509")
|
||||
tags[handshake.TagPAD] = bytes.Repeat([]byte("F"), 1000)
|
||||
handshake.WriteHandshakeMessage(b, handshake.TagCHLO, tags)
|
||||
|
||||
frame := frames.StreamFrame{
|
||||
StreamID: 1,
|
||||
DataLenPresent: true,
|
||||
Data: b.Bytes(),
|
||||
}
|
||||
|
||||
frame.Write(buffer, version)
|
||||
|
||||
raw = raw[0:buffer.Len()]
|
||||
aead := crypto.NullAEAD{}
|
||||
aead.Seal(raw[payloadStartIndex:payloadStartIndex], raw[payloadStartIndex:], packetNumber, raw[:payloadStartIndex])
|
||||
raw = raw[0 : buffer.Len()+12]
|
||||
|
||||
conn.Write(raw)
|
||||
|
||||
for {
|
||||
data := make([]byte, 1500)
|
||||
n, _, err := conn.ReadFromUDP(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = data[:n]
|
||||
fmt.Printf("Response length: %d\n", n)
|
||||
fmt.Println(data)
|
||||
}
|
||||
}
|
||||
|
||||
func connect(addr string) (*net.UDPConn, error) {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
panic(err)
|
||||
}
|
||||
|
||||
conn, err := net.DialUDP("udp", nil, udpAddr)
|
||||
client, err := quic.NewClient(udpAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
client.Listen()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue