goquic

package module
v0.0.0-...-bfa0612 Latest Latest
Warning

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

Go to latest
Published: Mar 16, 2015 License: BSD-3-Clause Imports: 12 Imported by: 0

README

goquic, QUIC support for Go

This is a work-in-progress QUIC implementation for Go. This is based on libquic library, which is in turn based on original QUIC implementation on Chromium.

QUIC is an experimental protocol aimed at reducing web latency over that of TCP. On the surface, QUIC is very similar to TCP+TLS+SPDY implemented on UDP. Because TCP is implement in operating system kernels, and middlebox firmware, making significant changes to TCP is next to impossible. However, since QUIC is built on top of UDP, it suffers from no such limitations.

Key features of QUIC over existing TCP+TLS+SPDY include

  • Dramatically reduced connection establishment time
  • Improved congestion control
  • Multiplexing without head of line blocking
  • Forward error correction
  • Connection migration

Project Status

This library is highly experimental. Although libquic sources are from Chromium (which are tested), the Go bindings are still highly pre-alpha state.

Known issues:

  • Stability/Crash issues when under high concurrency:
    • Double free or memory corruption on packet decryption (BoringSSL code)
    • FATAL:quic_sent_packet_manager.cc(647)] Check failed: packet_retransmitted. No crypto packets found to retransmit.
    • ERROR:quic_sent_packet_manager.cc(667)] No retransmittable packets, so RetransmitOldestPacket failed.
  • No support for read/write streaming. All request/response must fit in memory.
  • Secure QUIC not fully tested. May not support all kinds of certificates.

Things to do:

  • Fix crash issues noted above
  • Read/write streaming support

Preliminary Benchmarks

A very primitive benchmark testing have been done. Testing environments below:

Items Description
Optimization libquic built with -O3 parameters
CPU Intel(R) Core(TM) i7-4930K CPU @ 3.40GHz
Server Code https://github.com/devsisters/gospdyquic/blob/master/example/server.go
Server Parms GOMAXPROCS=12 ./server -port 9090 -n 12
Client Code https://github.com/devsisters/quicbench/blob/master/quicbench.go
Client Parms ./quicbench -u="https://example.com:9090/" -c 200 -r 1000

The server code is modified to create 30B, 1kB, 5kB, 10kB HTTP body payload. Concurrency is 200 and each thread requests 1,000 requests. It is designed to measure ideal throughput of the server. Naturally the throughput goes down when concurrency increases.

Benchmark results:

Payload Size Requests per Second
30B Payload 23832.18 RPS
1kB Payload 21704.84 RPS
5kB Payload 9343.58 RPS
10kB Payload 5312.75 RPS

On 10kB case, calculating the total network throughput is 435Mbps.

How many connections per second can this server process?

./gobench -u="https://example.com:9090/" -c 200 -r 100 -qk=false

Turning off keepalive using qk option results in a pure new QUIC connection per request. The benchmark results are 2905.58 CPS.

Getting Started

Build static library files

Although prebuilt static library files already exists in the repository for convenience, it is always good practice to build library files from source. You should not trust any unverifiable third-party binaries.

To build the library files for your architecture and OS:

./build_libs.sh

This will fetch libquic master and build all the binaries from source. The C/C++ files for Go bindings will be all built too.

Currently Linux and Mac OS X is supprted.

How to build

Due to Go 1.4's cgo restrictions, use an environment variable like below to build your projects. This restriction will be removed from Go 1.5.

CGO_LDFLAGS="-L$GOPATH/src/github.com/devsisters/goquic/lib/$GOOS_$GOARCH"

For example, building gospdyquic example server in Mac:

CGO_LDFLAGS="-L$GOPATH/src/github.com/devsisters/goquic/lib/darwin_amd64" go build $GOPATH/github.com/devsisters/gospdyquic/example/server.go

How to use

This is a very low-level QUIC library intended for socket-like use. To use QUIC as a SPDY transport layer, see gospdyquic for more details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateGoQuicAlarm

func CreateGoQuicAlarm(go_quic_alarm_go_wrapper_c unsafe.Pointer, clock_c unsafe.Pointer, task_runner_c unsafe.Pointer) unsafe.Pointer

func CreateGoSession

func CreateGoSession(dispatcher_c unsafe.Pointer, session_c unsafe.Pointer) unsafe.Pointer

func CreateIncomingDataStream

func CreateIncomingDataStream(session_c unsafe.Pointer, stream_id uint32, wrapper_c unsafe.Pointer) unsafe.Pointer

func DataStreamProcessorOnClose

func DataStreamProcessorOnClose(go_data_stream_processor_c unsafe.Pointer, isServer int)

func DataStreamProcessorOnFinRead

func DataStreamProcessorOnFinRead(go_data_stream_processor_c unsafe.Pointer, isServer int)

func DataStreamProcessorProcessData

func DataStreamProcessorProcessData(go_data_stream_processor_c unsafe.Pointer, data unsafe.Pointer, data_len uint32, isServer int) uint32

func DeleteGoSession

func DeleteGoSession(dispatcher_c unsafe.Pointer, go_session_c unsafe.Pointer)

func DeleteIPAddressNumber

func DeleteIPAddressNumber(ipAddr IPAddressNumber)

func DeleteIPEndPoint

func DeleteIPEndPoint(endpoint IPEndPoint)

func DeleteQuicEncryptedPacket

func DeleteQuicEncryptedPacket(packet QuicEncryptedPacket)

func GetProof

func GetProof(dispatcher_c unsafe.Pointer, server_ip_c unsafe.Pointer, hostname_c unsafe.Pointer, hostname_sz_c C.size_t, server_config_c unsafe.Pointer, server_config_sz_c C.size_t, ecdsa_ok_c C.int, out_certs_c ***C.char, out_certs_sz_c *C.int, out_certs_item_sz_c **C.size_t, out_signature_c **C.char, out_signature_sz_c *C.size_t) C.int

func GoQuicAlarmCancelImpl

func GoQuicAlarmCancelImpl(alarm_c unsafe.Pointer)

func GoQuicAlarmDestroy

func GoQuicAlarmDestroy(alarm_c unsafe.Pointer)

func GoQuicAlarmSetImpl

func GoQuicAlarmSetImpl(alarm_c unsafe.Pointer, deadline int64)

func ParseHeaders

func ParseHeaders(reader io.Reader) (http.Header, error)

func SetLogLevel

func SetLogLevel(level int)

func UnregisterQuicClientStreamFromSession

func UnregisterQuicClientStreamFromSession(go_stream_c unsafe.Pointer)

func UnregisterQuicServerStreamFromSession

func UnregisterQuicServerStreamFromSession(go_stream_c unsafe.Pointer)

func WriteToUDP

func WriteToUDP(conn_c unsafe.Pointer, ip_endpoint_c unsafe.Pointer, buffer_c unsafe.Pointer, length_c C.size_t, server_packet_writer_c unsafe.Pointer, task_runner_c unsafe.Pointer, isSynchronous bool)

Types

type AlarmHeap

type AlarmHeap []*HeapItem

func (AlarmHeap) Len

func (ht AlarmHeap) Len() int

func (AlarmHeap) Less

func (ht AlarmHeap) Less(i, j int) bool

func (*AlarmHeap) Pop

func (ht *AlarmHeap) Pop() interface{}

func (*AlarmHeap) Push

func (ht *AlarmHeap) Push(x interface{})

func (AlarmHeap) Swap

func (ht AlarmHeap) Swap(i, j int)

type ClientSessionImpl

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

func (*ClientSessionImpl) CreateIncomingDataStream

func (c *ClientSessionImpl) CreateIncomingDataStream(stream_id uint32) DataStreamProcessor

func (*ClientSessionImpl) CreateOutgoingDataStream

func (c *ClientSessionImpl) CreateOutgoingDataStream() DataStreamProcessor

type ClientStreamImpl

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

func (*ClientStreamImpl) OnClose

func (cs *ClientStreamImpl) OnClose(writer QuicStream)

func (*ClientStreamImpl) OnFinRead

func (cs *ClientStreamImpl) OnFinRead(writer QuicStream)

func (*ClientStreamImpl) ProcessData

func (cs *ClientStreamImpl) ProcessData(writer QuicStream, buffer []byte) int

type Conn

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

func Dial

func Dial(network, address string) (c *Conn, err error)

func (*Conn) Close

func (c *Conn) Close() (err error)

func (*Conn) Connect

func (c *Conn) Connect() bool

func (*Conn) CreateStream

func (c *Conn) CreateStream() *Stream

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) (err error)

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) (err error)

func (*Conn) SetWriteDeadline

func (c *Conn) SetWriteDeadline(t time.Time) (err error)

func (*Conn) Socket

func (c *Conn) Socket() *net.UDPConn

type DataStreamCreator

type DataStreamCreator interface {
	CreateIncomingDataStream(streamId uint32) DataStreamProcessor
	CreateOutgoingDataStream() DataStreamProcessor
}

(For QuicServerSession)

type DataStreamProcessor

type DataStreamProcessor interface {
	ProcessData(writer QuicStream, buffer []byte) int
	// Called when there's nothing to read. Called on server XXX(serialx): Not called on client
	OnFinRead(writer QuicStream)
	// Called when the connection is closed. Called on client XXX(serialx): Not called on server
	OnClose(writer QuicStream)
}

(For QuicSpdyServerStream)

type GoQuicAlarm

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

func (*GoQuicAlarm) CancelImpl

func (alarm *GoQuicAlarm) CancelImpl()

func (*GoQuicAlarm) Destroy

func (alarm *GoQuicAlarm) Destroy()

Called by C++ side when the C++ wrapper object is destoryed

func (*GoQuicAlarm) Now

func (alarm *GoQuicAlarm) Now() int64

func (*GoQuicAlarm) OnAlarm

func (alarm *GoQuicAlarm) OnAlarm()

func (*GoQuicAlarm) SetImpl

func (alarm *GoQuicAlarm) SetImpl()

type HeapItem

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

type IPAddressNumber

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

func CreateIPAddressNumber

func CreateIPAddressNumber(ip net.IP) IPAddressNumber

type IPEndPoint

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

func CreateIPEndPoint

func CreateIPEndPoint(udpAddr *net.UDPAddr) IPEndPoint

func CreateIPEndPointC

func CreateIPEndPointC(ipAddr IPAddressNumber, port uint16) IPEndPoint

func (*IPEndPoint) UDPAddr

func (endpoint *IPEndPoint) UDPAddr() *net.UDPAddr

type ProofSource

type ProofSource interface {
	GetProof(addr *net.UDPAddr, hostname []byte, serverConfig []byte, ecdsaOk bool) (outCerts [][]byte, outSignature []byte)
}

type QuicClient

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

TODO(hodduc) multi-stream support ?

func CreateQuicClient

func CreateQuicClient(addr *net.UDPAddr, conn QuicConn, createQuicClientSession func() DataStreamCreator, taskRunner *TaskRunner) (qc *QuicClient, err error)

func (*QuicClient) Close

func (qc *QuicClient) Close() (err error)

func (*QuicClient) CreateReliableQuicStream

func (qc *QuicClient) CreateReliableQuicStream() *QuicClientStream

func (*QuicClient) EncryptionBeingEstablished

func (qc *QuicClient) EncryptionBeingEstablished() bool

func (*QuicClient) IsConnected

func (qc *QuicClient) IsConnected() bool

func (*QuicClient) ProcessPacket

func (qc *QuicClient) ProcessPacket(self_address *net.UDPAddr, peer_address *net.UDPAddr, buffer []byte)

func (*QuicClient) SendConnectionClosePacket

func (qc *QuicClient) SendConnectionClosePacket()

func (*QuicClient) StartConnect

func (qc *QuicClient) StartConnect()

type QuicClientSession

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

func (*QuicClientSession) NumActiveRequests

func (s *QuicClientSession) NumActiveRequests() int

type QuicClientStream

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

func (*QuicClientStream) CloseReadSide

func (stream *QuicClientStream) CloseReadSide()

func (*QuicClientStream) UserStream

func (stream *QuicClientStream) UserStream() DataStreamProcessor

func (*QuicClientStream) WriteHeader

func (stream *QuicClientStream) WriteHeader(header http.Header, is_body_empty bool)

func (*QuicClientStream) WriteOrBufferData

func (stream *QuicClientStream) WriteOrBufferData(body []byte, fin bool)

type QuicConn

type QuicConn interface {
	Close() error
	SetDeadline(t time.Time) error
	SetReadDeadline(t time.Time) error
	SetWriteDeadline(t time.Time) error
	Socket() *net.UDPConn
}

type QuicDispatcher

type QuicDispatcher struct {
	TaskRunner *TaskRunner
	// contains filtered or unexported fields
}

func CreateQuicDispatcher

func CreateQuicDispatcher(conn *net.UDPConn, createQuicServerSession func() DataStreamCreator, taskRunner *TaskRunner, proofSource ProofSource, isSecure bool) *QuicDispatcher

func (*QuicDispatcher) ProcessPacket

func (d *QuicDispatcher) ProcessPacket(self_address *net.UDPAddr, peer_address *net.UDPAddr, buffer []byte)

type QuicEncryptedPacket

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

func CreateQuicEncryptedPacket

func CreateQuicEncryptedPacket(buffer []byte) QuicEncryptedPacket

Note that the buffer is NOT copied. So it is the callers responsibility to retain the buffer until it is processed by QuicConnection

type QuicServerSession

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

type QuicSpdyServerStream

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

func (*QuicSpdyServerStream) CloseReadSide

func (writer *QuicSpdyServerStream) CloseReadSide()

func (*QuicSpdyServerStream) UserStream

func (writer *QuicSpdyServerStream) UserStream() DataStreamProcessor

func (*QuicSpdyServerStream) WriteHeader

func (writer *QuicSpdyServerStream) WriteHeader(header http.Header, is_body_empty bool)

func (*QuicSpdyServerStream) WriteOrBufferData

func (writer *QuicSpdyServerStream) WriteOrBufferData(body []byte, fin bool)

type QuicStream

type QuicStream interface {
	UserStream() DataStreamProcessor
	WriteHeader(header http.Header, is_body_empty bool)
	WriteOrBufferData(body []byte, fin bool)
	CloseReadSide()
}

type Stream

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

func (*Stream) FinWrite

func (s *Stream) FinWrite() error

func (*Stream) Read

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

func (*Stream) ReadHeader

func (s *Stream) ReadHeader() (http.Header, error)

func (*Stream) Write

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

func (*Stream) WriteHeader

func (s *Stream) WriteHeader(header http.Header, isBodyEmpty bool)

type TaskRunner

type TaskRunner struct {
	WriteChan chan *WriteCallback
	// contains filtered or unexported fields
}

This TaskRunner is NOT THREAD SAFE (and NEED NOT TO BE) so be careful All heap operations and callback operations should be called in a mainloop, not seperated goroutine

func CreateTaskRunner

func CreateTaskRunner(writeCh chan *WriteCallback) *TaskRunner

func (*TaskRunner) CallWriteCallback

func (t *TaskRunner) CallWriteCallback(server_packet_writer_c unsafe.Pointer, rv int)

func (*TaskRunner) CancelAlarm

func (t *TaskRunner) CancelAlarm(alarm *GoQuicAlarm)

func (*TaskRunner) DoTasks

func (t *TaskRunner) DoTasks()

func (*TaskRunner) RegisterAlarm

func (t *TaskRunner) RegisterAlarm(alarm *GoQuicAlarm)

func (*TaskRunner) RunAlarm

func (t *TaskRunner) RunAlarm(alarm *GoQuicAlarm)

func (*TaskRunner) UnregisterAlarm

func (t *TaskRunner) UnregisterAlarm(alarm *GoQuicAlarm)

func (*TaskRunner) WaitTimer

func (t *TaskRunner) WaitTimer() <-chan time.Time

type WriteCallback

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

func (*WriteCallback) Callback

func (cb *WriteCallback) Callback()

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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