fquic

package module
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2021 License: MIT Imports: 14 Imported by: 0

README

fquic

Go Reference Go Report Card

fquic provides an experimental wrapper for quic-go that simplifies the API and makes it a little friendlier. It attempts to match the interfaces and practices of the standard libraries net package as much as possible.

Documentation

Overview

Package fquic provides a friendly wrapper around quic-go.

Echo server:

func server(address string) {
	lis, err := fquic.Listen("quic-echo-example", address)
	if err != nil {
		log.Fatalf("open listener: %v", err)
	}
	defer lis.Close()

	for {
		c, err := lis.Accept(context.Background())
		if err != nil {
			log.Fatalf("accept connection: %v", err)
		}

		go func() {
			ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
			defer cancel()

			s, err := c.AcceptStream(ctx)
			if err != nil {
				log.Printf("accept stream: %v", err)
				return
			}
			defer s.Close()
			if !s.CanWrite() {
				log.Printf("got read-only stream")
				return
			}

			var buf strings.Builder
			r := io.TeeReader(s, &buf)
			_, err = io.Copy(s, r)
			if err != nil {
				var apperr *quic.ApplicationError
				if errors.As(err, &apperr) {
					log.Printf("disconnect %v: %q", apperr.ErrorCode, apperr.ErrorMessage)
					log.Printf("echoed: %q", buf.String())
					return
				}

				log.Printf("echo error: %v", err)
				return
			}
		}()
	}
}

Echo client:

func client(address string, data []byte) {
	d := fquic.Dialer{
		TLSConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
		Protocol: "quic-echo-example",
	}
	c, err := d.Dial(address)
	if err != nil {
		log.Fatalf("dial: %v", err)
	}
	defer c.Close()

	s, err := c.NewStream(false)
	if err != nil {
		log.Fatalf("open stream: %v", err)
	}
	defer s.Close()

	_, err = s.Write(data)
	if err != nil {
		log.Fatalf("write data: %v", err)
	}

	buf := make([]byte, len(data))
	_, err = io.ReadFull(s, buf)
	if err != nil {
		log.Fatalf("read data: %v", err)
	}

	fmt.Printf("Got echo: %q\n", buf)
}

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrWriteOnly = errors.New("write-only stream")
	ErrReadOnly  = errors.New("read-only stream")
)

These errors are panicked by Stream methods that are called on incorrectly used unidirectional streams.

Functions

func GenerateCert

func GenerateCert() (tls.Certificate, error)

GenerateCert generates a new, self-signed certificate.

Types

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn represents an open QUIC connection.

Note that Conn does not implement net.Conn, as QUIC connections require streams to be opened for actual data transfer.

func Client

func Client(protocol string, conn net.PacketConn, raddr net.Addr, host string) (*Conn, error)

Client connects to the remote address using the provided net.PacketConn. The host parameter is used for SNI. It uses protocol as the NextProtos specification of the TLS configuration.

func Dial

func Dial(protocol, address string) (*Conn, error)

Dial connects to the specified address using protocol as the NextProtos specification of the TLS configuration.

func (*Conn) AcceptStream

func (c *Conn) AcceptStream(ctx context.Context) (*Stream, error)

AcceptStream accepts a stream initiated by the peer in a similar manner to a Listener accepting a connection. Note that the returned stream can be either bidirectional or read-only.

func (*Conn) Close

func (c *Conn) Close() error

Close closes the connection, indicating to the remote end that there were no errors.

func (*Conn) CloseWithError

func (c *Conn) CloseWithError(code uint64, message string) error

CloseWithError closes the connection with provided error code and message. Error codes are application-defined.

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() net.Addr

LocalAddr returns the address of the local end of the connection.

func (*Conn) NewStream

func (c *Conn) NewStream(unidirectional bool) (*Stream, error)

NewStream opens a new stream that can be written to. If unidirectional if false, the peer may also send data.

func (*Conn) ReadDatagram added in v0.1.2

func (c *Conn) ReadDatagram() ([]byte, error)

ReadDatagram reads a datagram packet from the connection, if datagram support is enabled by both the local machine and the peer.

To enable datagram support, set EnableDatagrams to true in the quic.Config via either Dialer or ListenConfig.

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

RemoteAddr returns the address of the remote end of the connection.

func (*Conn) Session

func (c *Conn) Session() quic.Session

Session returns the underlying quic-go Session. Be careful when using this.

func (*Conn) SupportsDatagrams added in v0.1.2

func (c *Conn) SupportsDatagrams() bool

SupportsDatagrams returns true if both ends of the connection have datagram support.

func (*Conn) WriteDatagram added in v0.1.2

func (c *Conn) WriteDatagram(data []byte) error

WriteDatagram writes a datagram packet to the connection, if datagram support is enabled by both the local machine and the peer.

To enable datagram support, set EnableDatagrams to true in the quic.Config via either Dialer or ListenConfig.

type Dialer

type Dialer struct {
	// TLSConfig is the TLS configuration to use when dialing a new
	// connection. If it is a nil, a sane default configuration is used.
	TLSConfig *tls.Config

	// QUICConfig is the quic-go configuration to use when dialing a new
	// connection. If it is nil, a sane default configuration is used.
	QUICConfig *quic.Config

	// Protocol, if non-empty, is used to build the NextProtos
	// specification of TLSConfig. One or the other must be specified.
	// If neither are specified, dialing operations will panic. If both
	// are specified, Protocol will be prepended to the list specified
	// in NextProtos.
	Protocol string
}

A Dialer contains options for connecting to an address. Use of methods on a zero-value Dialer is equivalent to calling the similarly-named top-level functions in this package.

It is safe to call methods on Dialer concurrently, but they should not be called concurrently to modifying fields.

func (*Dialer) Client

func (d *Dialer) Client(conn net.PacketConn, raddr net.Addr, host string) (*Conn, error)

Client connects to the remote address using the provided net.PacketConn. The host parameter is used for SNI.

func (*Dialer) ClientContext

func (d *Dialer) ClientContext(ctx context.Context, conn net.PacketConn, raddr net.Addr, host string) (*Conn, error)

ClientContext connects to the remote address using the provided net.PacketConn and context. The host parameter is used for SNI.

func (*Dialer) Dial

func (d *Dialer) Dial(address string) (*Conn, error)

Dial connects to the specified address.

func (*Dialer) DialContext

func (d *Dialer) DialContext(ctx context.Context, address string) (*Conn, error)

DialContext connects to the specified address using the provided context.

type ListenConfig

type ListenConfig struct {
	TLSConfig  *tls.Config
	QUICConfig *quic.Config
	Protocol   string

	// If TLSConfig contains no certificates, GetCertificate is used to
	// get one as the Listener must have a certificate. If
	// GetCertificate is nil, GenerateCert is used.
	GetCertificate func() (tls.Certificate, error)
}

ListenConfig defines configuration details for a Listener. Undocumented fields behave the same as identically named fields do in Dialer.

func (*ListenConfig) Listen

func (lc *ListenConfig) Listen(address string) (*Listener, error)

Listen listens for incoming connections on the specified address.

func (*ListenConfig) Server

func (lc *ListenConfig) Server(conn net.PacketConn) (*Listener, error)

Server listens for incoming connections using the provided net.PacketConn.

type Listener

type Listener struct {
	// contains filtered or unexported fields
}

Listener listens for incoming connections.

func Listen

func Listen(protocol, address string) (*Listener, error)

Listen creates a Listener that listens for connections on the given local address. It uses protocol as the NextProtos specification of the TLS configuration.

func Server

func Server(protocol string, conn net.PacketConn) (*Listener, error)

Server creates a Listener that listens for connections using the given net.PacketConn. It uses protocol as the NextProtos specification of the TLS configuration.

func (*Listener) Accept

func (lis *Listener) Accept(ctx context.Context) (*Conn, error)

Accept accepts a new connection. Note that because Conn does not implement net.Conn, Listener does not implement net.Listener. For a simple workaround, see the NetListener method.

func (*Listener) Addr

func (lis *Listener) Addr() net.Addr

Addr returns the local address that the Listener is listening on.

func (*Listener) Close

func (lis *Listener) Close() error

Close closes the listener. This will also close all connections that were accepted by this listener.

func (*Listener) Listener

func (lis *Listener) Listener() quic.Listener

Listener returns the underlying quic-go Listener.

func (*Listener) NetListener

func (lis *Listener) NetListener(outgoing, unidirectional bool) net.Listener

NetListener returns a wrapper around the Listener that implements net.Listener. In order to do this, it immediately creates a new Stream after a connection is accepted. If outgoing is false, the stream is expected to be initiated by the remote end, whereas if it is true it is created at the local end of the connection. If outgoing is true, unidirectional specifies the type of stream created, but otherwise it is ignored.

type Stream

type Stream struct {
	// contains filtered or unexported fields
}

A Stream is an open QUIC stream inside of a connection.

A Stream can be bidirectional, read-only, or write-only. Calling read-related methods on a write-only stream and vice versa will result in a panic.

func (*Stream) CanRead

func (s *Stream) CanRead() bool

CanRead returns true if the stream can be read from.

func (*Stream) CanWrite

func (s *Stream) CanWrite() bool

CanWrite returns true if the stream can be written to.

func (*Stream) Close

func (s *Stream) Close() error

Close closes a writable stream. Unlike other direction-dependant methods methods, if this stream is read-only, this is a no-op.

func (*Stream) Conn

func (s *Stream) Conn() *Conn

Conn returns the connection associated with the Stream.

func (*Stream) LocalAddr

func (s *Stream) LocalAddr() net.Addr

func (*Stream) Read

func (s *Stream) Read(buf []byte) (int, error)

func (*Stream) ReceiveStream

func (s *Stream) ReceiveStream() quic.ReceiveStream

ReceiveStream returns the underlying quic-go ReceiveStream, or nil if the stream is write-only.

func (*Stream) RemoteAddr

func (s *Stream) RemoteAddr() net.Addr

func (*Stream) SendStream

func (s *Stream) SendStream() quic.SendStream

SendStream returns the underlying quic-go SendStream, or nil if the stream is read-only.

func (*Stream) SetDeadline

func (s *Stream) SetDeadline(t time.Time) error

SetDeadline implements net.Conn's SetDeadline method. Note that this method only works on bidirectional streams.

TODO: Make this use the available unidirectional method automatically if the stream is unidirectional?

func (*Stream) SetReadDeadline

func (s *Stream) SetReadDeadline(t time.Time) error

func (*Stream) SetWriteDeadline

func (s *Stream) SetWriteDeadline(t time.Time) error

func (*Stream) Stream

func (s *Stream) Stream() quic.Stream

Stream returns the underlying bidirectional quic-go Stream. If the Stream is unidirectional in either direction, this returns nil.

func (*Stream) Write

func (s *Stream) Write(data []byte) (int, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL