conn.go (81 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package gmux import ( "crypto/tls" "errors" "io" "net" "sync" ) func newProxyConn(raw net.Conn, r io.Reader, w io.Writer) (_ net.Conn, closed <-chan struct{}) { pc := proxyConn{Conn: raw, closed: make(chan struct{}), r: r, w: w} if raw, ok := raw.(*tls.Conn); ok { return &tlsProxyConn{connectionStater: raw, proxyConn: pc}, pc.closed } return &pc, pc.closed } type tlsProxyConn struct { connectionStater proxyConn } type connectionStater interface { ConnectionState() tls.ConnectionState } func (c *tlsProxyConn) Close() error { c.closeOnce.Do(func() { close(c.closed) }) return c.Conn.Close() } func (c *tlsProxyConn) Read(b []byte) (int, error) { return c.r.Read(b) } func (c *tlsProxyConn) Write(b []byte) (int, error) { return c.w.Write(b) } type proxyConn struct { net.Conn closeOnce sync.Once closed chan struct{} r io.Reader w io.Writer } func (c *proxyConn) Close() error { c.closeOnce.Do(func() { close(c.closed) }) return c.Conn.Close() } func (c *proxyConn) Read(b []byte) (int, error) { return c.r.Read(b) } func (c *proxyConn) Write(b []byte) (int, error) { return c.w.Write(b) } type chanListener struct { closeOnce sync.Once closed chan struct{} conns chan net.Conn } func newChanListener() *chanListener { return &chanListener{conns: make(chan net.Conn), closed: make(chan struct{})} } func (l *chanListener) Addr() net.Addr { return gmuxAddr{} } func (l *chanListener) Close() error { l.closeOnce.Do(func() { close(l.closed) }) return nil } func (l *chanListener) Accept() (net.Conn, error) { select { case <-l.closed: return nil, errors.New("listener closed") case conn := <-l.conns: return conn, nil } } type gmuxAddr struct{} func (gmuxAddr) Network() string { return "gmux" } func (gmuxAddr) String() string { return "gmux" }