Commit 8acc21e8 authored by Jeromy's avatar Jeromy
Browse files

Vendor in go-peerstream

parent a9de494f
package peerstream_spdystream
import (
"errors"
"net"
"net/http"
smux "QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer"
ss "QmYewWU9ZnQR7Gct9tNZd97i9tGnyCZfNVLM2GGfNEj5jP/spdystream"
)
var ErrUseServe = errors.New("not implemented, use Serve")
// stream implements smux.Stream using a ss.Stream
type stream ss.Stream
func (s *stream) spdyStream() *ss.Stream {
return (*ss.Stream)(s)
}
func (s *stream) Read(buf []byte) (int, error) {
return s.spdyStream().Read(buf)
}
func (s *stream) Write(buf []byte) (int, error) {
return s.spdyStream().Write(buf)
}
func (s *stream) Close() error {
// Reset is spdystream's full bidirectional close.
// We expose bidirectional close as our `Close`.
// To close only half of the connection, and use other
// spdystream options, just get the stream with:
// ssStream := (*ss.Stream)(stream)
return s.spdyStream().Reset()
}
// Conn is a connection to a remote peer.
type conn struct {
sc *ss.Connection
closed chan struct{}
}
func (c *conn) spdyConn() *ss.Connection {
return c.sc
}
func (c *conn) Close() error {
err := c.spdyConn().CloseWait()
if !c.IsClosed() {
close(c.closed)
}
return err
}
func (c *conn) IsClosed() bool {
select {
case <-c.closed:
return true
case <-c.sc.CloseChan():
return true
default:
return false
}
}
// OpenStream creates a new stream.
func (c *conn) OpenStream() (smux.Stream, error) {
s, err := c.spdyConn().CreateStream(http.Header{
":method": []string{"GET"}, // this is here for HTTP/SPDY interop
":path": []string{"/"}, // this is here for HTTP/SPDY interop
}, nil, false)
if err != nil {
return nil, err
}
// wait for a response before writing. for some reason
// spdystream does not make forward progress unless you do this.
s.Wait()
return (*stream)(s), nil
}
// AcceptStream accepts a stream opened by the other side.
func (c *conn) AcceptStream() (smux.Stream, error) {
return nil, ErrUseServe
}
// Serve starts listening for incoming requests and handles them
// using given StreamHandler
func (c *conn) Serve(handler smux.StreamHandler) {
c.spdyConn().Serve(func(s *ss.Stream) {
// Flow control and backpressure of Opening streams is broken.
// I believe that spdystream has one set of workers that both send
// data AND accept new streams (as it's just more data). there
// is a problem where if the new stream handlers want to throttle,
// they also eliminate the ability to read/write data, which makes
// forward-progress impossible. Thus, throttling this function is
// -- at this moment -- not the solution. Either spdystream must
// change, or we must throttle another way. go-peerstream handles
// every new stream in its own goroutine.
err := s.SendReply(http.Header{}, false)
if err != nil {
// this _could_ error out. not sure how to handle this failure.
// don't return, and let the caller handle a broken stream.
// better than _hiding_ an error.
// return
}
go handler((*stream)(s))
})
}
type transport struct{}
// Transport is a go-peerstream transport that constructs
// spdystream-backed connections.
var Transport = transport{}
func (t transport) NewConn(nc net.Conn, isServer bool) (smux.Conn, error) {
sc, err := ss.NewConnection(nc, isServer)
return &conn{sc: sc, closed: make(chan struct{})}, err
}
package peerstream_spdystream
import (
"testing"
test "QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/test"
)
func TestSpdyStreamTransport(t *testing.T) {
test.SubtestAll(t, Transport)
}
package sm_yamux
import (
"io/ioutil"
"net"
"time"
smux "QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer"
yamux "QmT98GixWnJUj3vHfoURNQa5uk8FxxmZVF5nv3AicXp2R1/yamux"
)
// stream implements smux.Stream using a ss.Stream
type stream yamux.Stream
func (s *stream) yamuxStream() *yamux.Stream {
return (*yamux.Stream)(s)
}
func (s *stream) Read(buf []byte) (int, error) {
return s.yamuxStream().Read(buf)
}
func (s *stream) Write(buf []byte) (int, error) {
return s.yamuxStream().Write(buf)
}
func (s *stream) Close() error {
return s.yamuxStream().Close()
}
// Conn is a connection to a remote peer.
type conn yamux.Session
func (c *conn) yamuxSession() *yamux.Session {
return (*yamux.Session)(c)
}
func (c *conn) Close() error {
return c.yamuxSession().Close()
}
func (c *conn) IsClosed() bool {
return c.yamuxSession().IsClosed()
}
// OpenStream creates a new stream.
func (c *conn) OpenStream() (smux.Stream, error) {
s, err := c.yamuxSession().OpenStream()
if err != nil {
return nil, err
}
return (*stream)(s), nil
}
// AcceptStream accepts a stream opened by the other side.
func (c *conn) AcceptStream() (smux.Stream, error) {
s, err := c.yamuxSession().AcceptStream()
return (*stream)(s), err
}
// Serve starts listening for incoming requests and handles them
// using given StreamHandler
func (c *conn) Serve(handler smux.StreamHandler) {
for { // accept loop
s, err := c.AcceptStream()
if err != nil {
return // err always means closed.
}
go handler(s)
}
}
// Transport is a go-peerstream transport that constructs
// yamux-backed connections.
type Transport yamux.Config
// DefaultTransport has default settings for yamux
var DefaultTransport = (*Transport)(&yamux.Config{
AcceptBacklog: 256, // from yamux.DefaultConfig
EnableKeepAlive: true, // from yamux.DefaultConfig
KeepAliveInterval: 30 * time.Second, // from yamux.DefaultConfig
MaxStreamWindowSize: uint32(256 * 1024), // from yamux.DefaultConfig
LogOutput: ioutil.Discard,
})
func (t *Transport) NewConn(nc net.Conn, isServer bool) (smux.Conn, error) {
var s *yamux.Session
var err error
if isServer {
s, err = yamux.Server(nc, t.Config())
} else {
s, err = yamux.Client(nc, t.Config())
}
return (*conn)(s), err
}
func (t *Transport) Config() *yamux.Config {
return (*yamux.Config)(t)
}
package sm_yamux
import (
"testing"
test "QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/test"
)
func TestYamuxTransport(t *testing.T) {
test.SubtestAll(t, DefaultTransport)
}
# Yamux
Yamux (Yet another Multiplexer) is a multiplexing library for Golang.
It relies on an underlying connection to provide reliability
and ordering, such as TCP or Unix domain sockets, and provides
stream-oriented multiplexing. It is inspired by SPDY but is not
interoperable with it.
Yamux features include:
* Bi-directional streams
* Streams can be opened by either client or server
* Useful for NAT traversal
* Server-side push support
* Flow control
* Avoid starvation
* Back-pressure to prevent overwhelming a receiver
* Keep Alives
* Enables persistent connections over a load balancer
* Efficient
* Enables thousands of logical streams with low overhead
## Documentation
For complete documentation, see the associated [Godoc](http://godoc.org/github.com/hashicorp/yamux).
## Specification
The full specification for Yamux is provided in the `spec.md` file.
It can be used as a guide to implementors of interoperable libraries.
## Usage
Using Yamux is remarkably simple:
```go
func client() {
// Get a TCP connection
conn, err := net.Dial(...)
if err != nil {
panic(err)
}
// Setup client side of yamux
session, err := yamux.Client(conn, nil)
if err != nil {
panic(err)
}
// Open a new stream
stream, err := session.Open()
if err != nil {
panic(err)
}
// Stream implements net.Conn
stream.Write([]byte("ping"))
}
func server() {
// Accept a TCP connection
conn, err := listener.Accept()
if err != nil {
panic(err)
}
// Setup server side of yamux
session, err := yamux.Server(conn, nil)
if err != nil {
panic(err)
}
// Accept a stream
stream, err := session.Accept()
if err != nil {
panic(err)
}
// Listen for a message
buf := make([]byte, 4)
stream.Read(buf)
}
```
{
"name": "yamux",
"author": "whyrusleeping",
"version": "1.0.0",
"language": "go",
"gx": {
"dvcsimport": "github.com/hashicorp/yamux"
}
}
\ No newline at end of file
package yamux
// asyncSendErr is used to try an async send of an error
func asyncSendErr(ch chan error, err error) {
if ch == nil {
return
}
select {
case ch <- err:
default:
}
}
// asyncNotify is used to signal a waiting goroutine
func asyncNotify(ch chan struct{}) {
select {
case ch <- struct{}{}:
default:
}
}
// min computes the minimum of two values
func min(a, b uint32) uint32 {
if a < b {
return a
}
return b
}
language: go
go:
- 1.3
- 1.4
- release
- tip
script:
- go test -v ./...
# - go test -race -cpu=5 ./...
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment