Commit 71865607 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 69d5916b
...@@ -682,7 +682,7 @@ func handshake(ctx context.Context, conn net.Conn, version uint32) (err error) { ...@@ -682,7 +682,7 @@ func handshake(ctx context.Context, conn net.Conn, version uint32) (err error) {
} }
// ---- for convenience: Dial ---- // ---- for convenience: Dial & Listen ----
// Dial connects to address on given network, handshakes and wraps the connection as NodeLink // Dial connects to address on given network, handshakes and wraps the connection as NodeLink
func Dial(ctx context.Context, net xnet.Networker, addr string) (nl *NodeLink, err error) { func Dial(ctx context.Context, net xnet.Networker, addr string) (nl *NodeLink, err error) {
...@@ -694,10 +694,93 @@ func Dial(ctx context.Context, net xnet.Networker, addr string) (nl *NodeLink, e ...@@ -694,10 +694,93 @@ func Dial(ctx context.Context, net xnet.Networker, addr string) (nl *NodeLink, e
return Handshake(ctx, peerConn, LinkClient) return Handshake(ctx, peerConn, LinkClient)
} }
// NOTE there is no Listen with Handshake hooked into Accept because: Handshake // Listen starts listening on laddr for incoming connections and wraps them as NodeLink.
// is blocking operation and thus needs to be run in separate goroutine not to // The listener accepts only those connections that pass handshake.
// block further Accepts. func Listen(net xnet.Networker, laddr string) (*Listener, error) {
rawl, err := net.Listen(laddr)
if err != nil {
return nil, err
}
l := &Listener{
Listener: rawl,
acceptq: make(chan accepted),
closed: make(chan struct{}),
}
go l.run()
return l, nil
}
type Listener struct {
net.Listener
acceptq chan accepted
closed chan struct {}
}
type accepted struct {
link *NodeLink
err error
}
func (l *Listener) Close() error {
err := l.Listener.Close()
close(l.closed)
return err
}
func (l *Listener) run() {
// context that cancels when listener stops
runCtx, runCancel := context.WithCancel(context.Background())
defer runCancel()
for {
// stop on close
select {
case <-l.closed:
return
default:
}
// XXX add backpressure on too much incoming connections without client .Accept
conn, err := l.Listener.Accept()
go l.accept(runCtx, conn, err)
}
}
func (l *Listener) accept(ctx context.Context, conn net.Conn, err error) {
link, err := l.accept1(ctx, conn, err)
select {
case <-l.closed:
case l.acceptq <- accepted{link, err}:
}
}
func (l *Listener) accept1(ctx context.Context, conn net.Conn, err error) (*NodeLink, error) {
if err != nil {
return nil, err
}
link, err := Handshake(ctx, conn, LinkServer)
if err != nil {
return nil, err
}
return link, nil
}
func (l *Listener) Accept() (*NodeLink, error) {
select{
case <-l.closed:
// we know raw listener is already closed - return proper error about it
_, err := l.Listener.Accept()
return nil, err
case a := <-l.acceptq:
return a.link, a.err
}
}
// ---- for convenience: Conn -> NodeLink & local/remote link addresses ---- // ---- for convenience: Conn -> NodeLink & local/remote link addresses ----
......
...@@ -28,8 +28,6 @@ package neo ...@@ -28,8 +28,6 @@ package neo
//go:generate sh -c "go run ../xcommon/tracing/cmd/gotrace/{gotrace,util}.go ." //go:generate sh -c "go run ../xcommon/tracing/cmd/gotrace/{gotrace,util}.go ."
import ( import (
"net"
"lab.nexedi.com/kirr/neo/go/xcommon/xnet" "lab.nexedi.com/kirr/neo/go/xcommon/xnet"
"lab.nexedi.com/kirr/neo/go/zodb" "lab.nexedi.com/kirr/neo/go/zodb"
) )
...@@ -60,9 +58,9 @@ type NodeCommon struct { ...@@ -60,9 +58,9 @@ type NodeCommon struct {
// Listen starts listening at node's listening address. // Listen starts listening at node's listening address.
// If the address is empty one new free is automatically selected. // If the address is empty one new free is automatically selected.
// The node information about where it listens at is appropriately updated. // The node information about where it listens at is appropriately updated.
func (n *NodeCommon) Listen() (net.Listener, error) { func (n *NodeCommon) Listen() (*Listener, error) {
// start listening // start listening
l, err := n.Net.Listen(n.MyInfo.Address.String()) // XXX ugly l, err := Listen(n.Net, n.MyInfo.Address.String()) // XXX ugly
if err != nil { if err != nil {
return nil, err // XXX err ctx return nil, err // XXX err ctx
} }
......
...@@ -25,7 +25,6 @@ package server ...@@ -25,7 +25,6 @@ package server
import ( import (
"context" "context"
"fmt" "fmt"
"net"
"lab.nexedi.com/kirr/neo/go/neo" "lab.nexedi.com/kirr/neo/go/neo"
...@@ -41,10 +40,10 @@ type Server interface { ...@@ -41,10 +40,10 @@ type Server interface {
// Serve runs service on a listener // Serve runs service on a listener
// - accept incoming connection on the listener // - accept incoming connection on the listener
// - for every accepted connection spawn handshake + srv.ServeLink() in separate goroutine. // - for every accepted connection spawn srv.ServeLink() in separate goroutine.
// //
// the listener is closed when Serve returns. // the listener is closed when Serve returns.
func Serve(ctx context.Context, l net.Listener, srv Server) error { func Serve(ctx context.Context, l *neo.Listener, srv Server) error {
fmt.Printf("xxx: serving on %s ...\n", l.Addr()) // XXX 'xxx' -> ? fmt.Printf("xxx: serving on %s ...\n", l.Addr()) // XXX 'xxx' -> ?
// close listener when either cancelling or returning (e.g. due to an error) // close listener when either cancelling or returning (e.g. due to an error)
...@@ -62,46 +61,29 @@ func Serve(ctx context.Context, l net.Listener, srv Server) error { ...@@ -62,46 +61,29 @@ func Serve(ctx context.Context, l net.Listener, srv Server) error {
l.Close() // XXX err l.Close() // XXX err
}() }()
// main Accept -> Handshake -> ServeLink loop // main Accept -> ServeLink loop
for { for {
peerConn, err := l.Accept() link, err := l.Accept()
if err != nil { if err != nil {
// TODO err == closed <-> ctx was cancelled // TODO err == closed <-> ctx was cancelled
// TODO err -> net.Error && .Temporary() -> some throttling // TODO err -> net.Error && .Temporary() -> some throttling
return err return err
} }
go func() { go srv.ServeLink(ctx, link)
link, err := neo.Handshake(ctx, peerConn, neo.LinkServer)
if err != nil {
fmt.Printf("xxx: %s\n", err)
return
}
srv.ServeLink(ctx, link)
}()
} }
} }
/*
// ListenAndServe listens on network address and then calls Serve to handle incoming connections
// XXX unused -> goes away ?
func ListenAndServe(ctx context.Context, net neo.Network, laddr string, srv Server) error {
l, err := net.Listen(laddr)
if err != nil {
return err
}
// TODO set keepalive on l
return Serve(ctx, l, srv)
}
*/
// ---------------------------------------- // ----------------------------------------
// XXX goes away? (we need a func to make sure to recv RequestIdentification
// XXX and pass it to server main logic - whether to accept it or not should be
// XXX programmed there)
//
// IdentifyPeer identifies peer on the link // IdentifyPeer identifies peer on the link
// it expects peer to send RequestIdentification packet and replies with AcceptIdentification if identification passes. // it expects peer to send RequestIdentification packet and replies with AcceptIdentification if identification passes.
// returns information about identified node or error. // returns information about identified node or error.
// XXX recheck identification logic here
func IdentifyPeer(link *neo.NodeLink, myNodeType neo.NodeType) (nodeInfo neo.RequestIdentification, err error) { func IdentifyPeer(link *neo.NodeLink, myNodeType neo.NodeType) (nodeInfo neo.RequestIdentification, err error) {
defer xerr.Contextf(&err, "%s: identify", link) defer xerr.Contextf(&err, "%s: identify", link)
......
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