Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Levin Zimmermann
neoppod
Commits
ee71bd1a
Commit
ee71bd1a
authored
Dec 19, 2016
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
a35297b6
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
77 additions
and
39 deletions
+77
-39
t/neo/connection.go
t/neo/connection.go
+42
-19
t/neo/connection_test.go
t/neo/connection_test.go
+35
-20
No files found.
t/neo/connection.go
View file @
ee71bd1a
...
@@ -20,6 +20,8 @@ import (
...
@@ -20,6 +20,8 @@ import (
"net"
"net"
"sync"
"sync"
"unsafe"
"unsafe"
"fmt"
)
)
// NodeLink is a node-node link in NEO
// NodeLink is a node-node link in NEO
...
@@ -50,7 +52,9 @@ type NodeLink struct {
...
@@ -50,7 +52,9 @@ type NodeLink struct {
connTab
map
[
uint32
]
*
Conn
// connId -> Conn associated with connId
connTab
map
[
uint32
]
*
Conn
// connId -> Conn associated with connId
nextConnId
uint32
// next connId to use for Conn initiated by us
nextConnId
uint32
// next connId to use for Conn initiated by us
handleNewConn
func
(
conn
*
Conn
)
// handler for new connections XXX -> ConnHandler (a-la Handler in net/http) ?
serveWg
sync
.
WaitGroup
handleNewConn
func
(
conn
*
Conn
)
// handler for new connections
txreq
chan
txReq
// tx requests from Conns go via here
txreq
chan
txReq
// tx requests from Conns go via here
closed
chan
struct
{}
closed
chan
struct
{}
...
@@ -95,6 +99,10 @@ type ConnRole int
...
@@ -95,6 +99,10 @@ type ConnRole int
const
(
const
(
ConnServer
ConnRole
=
iota
// connection created as server
ConnServer
ConnRole
=
iota
// connection created as server
ConnClient
// connection created as client
ConnClient
// connection created as client
// for testing: do not spawn serveRecv & serveSend
connNoRecvSend
ConnRole
=
1
<<
16
connFlagsMask
ConnRole
=
(
1
<<
32
-
1
)
<<
16
)
)
// Make a new NodeLink from already established net.Conn
// Make a new NodeLink from already established net.Conn
...
@@ -106,7 +114,7 @@ const (
...
@@ -106,7 +114,7 @@ const (
// net.Listen/net.Accept and client role for connections created via net.Dial.
// net.Listen/net.Accept and client role for connections created via net.Dial.
func
NewNodeLink
(
conn
net
.
Conn
,
role
ConnRole
)
*
NodeLink
{
func
NewNodeLink
(
conn
net
.
Conn
,
role
ConnRole
)
*
NodeLink
{
var
nextConnId
uint32
var
nextConnId
uint32
switch
role
{
switch
role
&^
connFlagsMask
{
case
ConnServer
:
case
ConnServer
:
nextConnId
=
0
// all initiated by us connId will be even
nextConnId
=
0
// all initiated by us connId will be even
case
ConnClient
:
case
ConnClient
:
...
@@ -122,8 +130,11 @@ func NewNodeLink(conn net.Conn, role ConnRole) *NodeLink {
...
@@ -122,8 +130,11 @@ func NewNodeLink(conn net.Conn, role ConnRole) *NodeLink {
txreq
:
make
(
chan
txReq
),
txreq
:
make
(
chan
txReq
),
closed
:
make
(
chan
struct
{}),
closed
:
make
(
chan
struct
{}),
}
}
// TODO go nl.serveRecv()
if
role
&
connNoRecvSend
==
0
{
// TODO go nl.serveSend()
nl
.
serveWg
.
Add
(
2
)
go
nl
.
serveRecv
()
go
nl
.
serveSend
()
}
return
&
nl
return
&
nl
}
}
...
@@ -133,17 +144,16 @@ func (nl *NodeLink) Close() error {
...
@@ -133,17 +144,16 @@ func (nl *NodeLink) Close() error {
close
(
nl
.
closed
)
close
(
nl
.
closed
)
err
:=
nl
.
peerLink
.
Close
()
err
:=
nl
.
peerLink
.
Close
()
// TODO wait for serve{Send,Recv} to complete
// wait for serve{Send,Recv} to complete
//nl.wg.Wait()
fmt
.
Printf
(
"%p serveWg.Wait ...
\n
"
,
nl
)
nl
.
serveWg
.
Wait
()
fmt
.
Printf
(
"%p
\t
(wait) -> woken up
\n
"
,
nl
)
// close active Conns
// close active Conns
nl
.
connMu
.
Lock
()
nl
.
connMu
.
Lock
()
defer
nl
.
connMu
.
Unlock
()
defer
nl
.
connMu
.
Unlock
()
for
_
,
conn
:=
range
nl
.
connTab
{
for
_
,
conn
:=
range
nl
.
connTab
{
// FIXME it also wants to lock conntab -> conn.close() ?
conn
.
close
()
println
(
"conn"
,
conn
.
connId
,
" -> closing ..."
)
// XXX only interrupt, not close? Or allow multiple conn.Close() ?
conn
.
close
()
// XXX err -> errv
}
}
nl
.
connTab
=
nil
// clear + mark closed
nl
.
connTab
=
nil
// clear + mark closed
return
err
return
err
...
@@ -233,9 +243,12 @@ func (nl *NodeLink) NewConn() *Conn {
...
@@ -233,9 +243,12 @@ func (nl *NodeLink) NewConn() *Conn {
// serveRecv handles incoming packets routing them to either appropriate
// serveRecv handles incoming packets routing them to either appropriate
// already-established connection or to new serving goroutine.
// already-established connection or to new serving goroutine.
func
(
nl
*
NodeLink
)
serveRecv
()
{
func
(
nl
*
NodeLink
)
serveRecv
()
{
defer
nl
.
serveWg
.
Done
()
for
{
for
{
// receive 1 packet
// receive 1 packet
println
(
nl
,
"serveRecv -> recv..."
)
pkt
,
err
:=
nl
.
recvPkt
()
pkt
,
err
:=
nl
.
recvPkt
()
fmt
.
Printf
(
"%p
\t
(recv) -> %v
\n
"
,
nl
,
err
)
if
err
!=
nil
{
if
err
!=
nil
{
// this might be just error on close - simply stop in such case
// this might be just error on close - simply stop in such case
select
{
select
{
...
@@ -248,13 +261,15 @@ func (nl *NodeLink) serveRecv() {
...
@@ -248,13 +261,15 @@ func (nl *NodeLink) serveRecv() {
// pkt.ConnId -> Conn
// pkt.ConnId -> Conn
connId
:=
ntoh32
(
pkt
.
Header
()
.
ConnId
)
connId
:=
ntoh32
(
pkt
.
Header
()
.
ConnId
)
accept
:=
false
var
handleNewConn
func
(
conn
*
Conn
)
nl
.
connMu
.
Lock
()
nl
.
connMu
.
Lock
()
conn
:=
nl
.
connTab
[
connId
]
conn
:=
nl
.
connTab
[
connId
]
if
conn
==
nil
&&
nl
.
handleNewConn
!=
nil
{
if
conn
==
nil
{
conn
=
nl
.
newConn
(
connId
)
handleNewConn
=
nl
.
handleNewConn
accept
=
true
if
handleNewConn
!=
nil
{
conn
=
nl
.
newConn
(
connId
)
}
}
}
nl
.
connMu
.
Unlock
()
nl
.
connMu
.
Unlock
()
...
@@ -266,10 +281,10 @@ func (nl *NodeLink) serveRecv() {
...
@@ -266,10 +281,10 @@ func (nl *NodeLink) serveRecv() {
// we are accepting new incoming connection - spawn
// we are accepting new incoming connection - spawn
// connection-serving goroutine
// connection-serving goroutine
if
accept
{
if
handleNewConn
!=
nil
{
// TODO avoid spawning goroutine for each new Ask request -
// TODO avoid spawning goroutine for each new Ask request -
// - by keeping pool of read inactive goroutine / conn pool ?
// - by keeping pool of read inactive goroutine / conn pool ?
go
nl
.
handleNewConn
(
conn
)
go
handleNewConn
(
conn
)
}
}
// route packet to serving goroutine handler
// route packet to serving goroutine handler
...
@@ -287,12 +302,17 @@ type txReq struct {
...
@@ -287,12 +302,17 @@ type txReq struct {
// serveSend handles requests to transmit packets from client connections and
// serveSend handles requests to transmit packets from client connections and
// serially executes them over associated node link.
// serially executes them over associated node link.
func
(
nl
*
NodeLink
)
serveSend
()
{
func
(
nl
*
NodeLink
)
serveSend
()
{
defer
nl
.
serveWg
.
Done
()
runloop
:
for
{
for
{
fmt
.
Printf
(
"%p serveSend -> select ...
\n
"
,
nl
)
select
{
select
{
case
<-
nl
.
closed
:
case
<-
nl
.
closed
:
break
fmt
.
Printf
(
"%p
\t
(send) -> closed
\n
"
,
nl
)
break
runloop
case
txreq
:=
<-
nl
.
txreq
:
case
txreq
:=
<-
nl
.
txreq
:
fmt
.
Printf
(
"%p
\t
(send) -> txreq
\n
"
,
nl
)
err
:=
nl
.
sendPkt
(
txreq
.
pkt
)
err
:=
nl
.
sendPkt
(
txreq
.
pkt
)
if
err
!=
nil
{
if
err
!=
nil
{
// XXX also close whole nodeLink since tx framing now can be broken?
// XXX also close whole nodeLink since tx framing now can be broken?
...
@@ -300,12 +320,15 @@ func (nl *NodeLink) serveSend() {
...
@@ -300,12 +320,15 @@ func (nl *NodeLink) serveSend() {
txreq
.
errch
<-
err
txreq
.
errch
<-
err
}
}
}
}
fmt
.
Printf
(
"%p
\t
(send) -> exit
\n
"
,
nl
)
}
}
// XXX move to NodeLink ctor
// XXX move to NodeLink ctor
?
// Set handler for new incoming connections
// Set handler for new incoming connections
func
(
nl
*
NodeLink
)
HandleNewConn
(
h
func
(
*
Conn
))
{
func
(
nl
*
NodeLink
)
HandleNewConn
(
h
func
(
*
Conn
))
{
// XXX locking
nl
.
connMu
.
Lock
()
defer
nl
.
connMu
.
Unlock
()
nl
.
handleNewConn
=
h
// NOTE can change handler at runtime XXX do we need this?
nl
.
handleNewConn
=
h
// NOTE can change handler at runtime XXX do we need this?
}
}
...
...
t/neo/connection_test.go
View file @
ee71bd1a
...
@@ -88,7 +88,7 @@ func xwait(w interface { Wait() error }) {
...
@@ -88,7 +88,7 @@ func xwait(w interface { Wait() error }) {
}
}
// Prepare PktBuf with content
// Prepare PktBuf with content
func
mkpkt
(
connid
uint32
,
msgcode
uint16
,
payload
[]
byte
)
*
PktBuf
{
func
_
mkpkt
(
connid
uint32
,
msgcode
uint16
,
payload
[]
byte
)
*
PktBuf
{
pkt
:=
&
PktBuf
{
make
([]
byte
,
PktHeadLen
+
len
(
payload
))}
pkt
:=
&
PktBuf
{
make
([]
byte
,
PktHeadLen
+
len
(
payload
))}
h
:=
pkt
.
Header
()
h
:=
pkt
.
Header
()
h
.
ConnId
=
hton32
(
connid
)
h
.
ConnId
=
hton32
(
connid
)
...
@@ -98,6 +98,11 @@ func mkpkt(connid uint32, msgcode uint16, payload []byte) *PktBuf {
...
@@ -98,6 +98,11 @@ func mkpkt(connid uint32, msgcode uint16, payload []byte) *PktBuf {
return
pkt
return
pkt
}
}
func
mkpkt
(
msgcode
uint16
,
payload
[]
byte
)
*
PktBuf
{
// in Conn exchange connid is automatically set by Conn.Send
return
_mkpkt
(
0
,
msgcode
,
payload
)
}
// Verify PktBuf is as expected
// Verify PktBuf is as expected
func
xverifyPkt
(
pkt
*
PktBuf
,
connid
uint32
,
msgcode
uint16
,
payload
[]
byte
)
{
func
xverifyPkt
(
pkt
*
PktBuf
,
connid
uint32
,
msgcode
uint16
,
payload
[]
byte
)
{
errv
:=
xerr
.
Errorv
{}
errv
:=
xerr
.
Errorv
{}
...
@@ -126,13 +131,16 @@ func tdelay() {
...
@@ -126,13 +131,16 @@ func tdelay() {
time
.
Sleep
(
1
*
time
.
Millisecond
)
time
.
Sleep
(
1
*
time
.
Millisecond
)
}
}
// create NodeLinks connected via net.Pipe
func
_nodeLinkPipe
(
flags
ConnRole
)
(
nl1
,
nl2
*
NodeLink
)
{
func
nodeLinkPipe
()
(
nl1
,
nl2
*
NodeLink
)
{
node1
,
node2
:=
net
.
Pipe
()
node1
,
node2
:=
net
.
Pipe
()
nl1
=
NewNodeLink
(
node1
,
ConnClient
)
nl1
=
NewNodeLink
(
node1
,
ConnClient
|
flags
)
nl2
=
NewNodeLink
(
node2
,
ConnServer
)
nl2
=
NewNodeLink
(
node2
,
ConnServer
|
flags
)
return
nl1
,
nl2
return
nl1
,
nl2
}
}
// create NodeLinks connected via net.Pipe
func
nodeLinkPipe
()
(
nl1
,
nl2
*
NodeLink
)
{
return
_nodeLinkPipe
(
0
)
}
func
TestNodeLink
(
t
*
testing
.
T
)
{
func
TestNodeLink
(
t
*
testing
.
T
)
{
...
@@ -141,6 +149,7 @@ func TestNodeLink(t *testing.T) {
...
@@ -141,6 +149,7 @@ func TestNodeLink(t *testing.T) {
nl1
,
nl2
:=
nodeLinkPipe
()
nl1
,
nl2
:=
nodeLinkPipe
()
// Close vs recvPkt
// Close vs recvPkt
println
(
"111"
)
wg
:=
WorkGroup
()
wg
:=
WorkGroup
()
wg
.
Gox
(
func
()
{
wg
.
Gox
(
func
()
{
tdelay
()
tdelay
()
...
@@ -153,6 +162,7 @@ func TestNodeLink(t *testing.T) {
...
@@ -153,6 +162,7 @@ func TestNodeLink(t *testing.T) {
xwait
(
wg
)
xwait
(
wg
)
// Close vs sendPkt
// Close vs sendPkt
println
(
"222"
)
wg
=
WorkGroup
()
wg
=
WorkGroup
()
wg
.
Gox
(
func
()
{
wg
.
Gox
(
func
()
{
tdelay
()
tdelay
()
...
@@ -166,12 +176,13 @@ func TestNodeLink(t *testing.T) {
...
@@ -166,12 +176,13 @@ func TestNodeLink(t *testing.T) {
xwait
(
wg
)
xwait
(
wg
)
// check raw exchange works
// check raw exchange works
nl1
,
nl2
=
nodeLinkPipe
()
println
(
"333"
)
nl1
,
nl2
=
_nodeLinkPipe
(
connNoRecvSend
)
wg
,
ctx
:=
WorkGroupCtx
(
context
.
Background
())
wg
,
ctx
:=
WorkGroupCtx
(
context
.
Background
())
wg
.
Gox
(
func
()
{
wg
.
Gox
(
func
()
{
// send ping; wait for pong
// send ping; wait for pong
pkt
:=
mkpkt
(
1
,
2
,
[]
byte
(
"ping"
))
pkt
:=
_
mkpkt
(
1
,
2
,
[]
byte
(
"ping"
))
xsendPkt
(
nl1
,
pkt
)
xsendPkt
(
nl1
,
pkt
)
pkt
=
xrecvPkt
(
nl1
)
pkt
=
xrecvPkt
(
nl1
)
xverifyPkt
(
pkt
,
3
,
4
,
[]
byte
(
"pong"
))
xverifyPkt
(
pkt
,
3
,
4
,
[]
byte
(
"pong"
))
...
@@ -180,7 +191,7 @@ func TestNodeLink(t *testing.T) {
...
@@ -180,7 +191,7 @@ func TestNodeLink(t *testing.T) {
// wait for ping; send pong
// wait for ping; send pong
pkt
=
xrecvPkt
(
nl2
)
pkt
=
xrecvPkt
(
nl2
)
xverifyPkt
(
pkt
,
1
,
2
,
[]
byte
(
"ping"
))
xverifyPkt
(
pkt
,
1
,
2
,
[]
byte
(
"ping"
))
pkt
=
mkpkt
(
3
,
4
,
[]
byte
(
"pong"
))
pkt
=
_
mkpkt
(
3
,
4
,
[]
byte
(
"pong"
))
xsendPkt
(
nl2
,
pkt
)
xsendPkt
(
nl2
,
pkt
)
})
})
...
@@ -196,7 +207,8 @@ func TestNodeLink(t *testing.T) {
...
@@ -196,7 +207,8 @@ func TestNodeLink(t *testing.T) {
xwait
(
wgclose
)
xwait
(
wgclose
)
// test channels on top of nodelink
// Test connections on top of nodelink
println
(
"444"
)
nl1
,
nl2
=
nodeLinkPipe
()
nl1
,
nl2
=
nodeLinkPipe
()
// Close vs Recv
// Close vs Recv
...
@@ -250,19 +262,22 @@ func TestNodeLink(t *testing.T) {
...
@@ -250,19 +262,22 @@ func TestNodeLink(t *testing.T) {
xclose
(
c12
)
xclose
(
c12
)
xclose
(
nl2
)
// for completeness
xclose
(
nl2
)
// for completeness
// Conn accept + exchange
/*
nl1
,
nl2
=
nodeLinkPipe
()
nl2
.
HandleNewConn
(
func
(
c
*
Conn
)
{
nl2
.
HandleNewConn
(
func
(
c
*
Conn
)
{
pkt := xrecv(c) // XXX t.Fatal() must be called from main goroutine -> context.Cancel ?
// TODO raised err -> errch
// change pkt a bit (TODO) and send it back
pkt
:=
xrecv
(
c
)
err = c.Send(pkt) // XXX err
xverifyPkt
(
pkt
,
c
.
connId
,
33
,
[]
byte
(
"ping"
))
c.Close() // XXX err
// change pkt a bit and send it back
xsend
(
c
,
mkpkt
(
34
,
[]
byte
(
"pong"
)))
xclose
(
c
)
})
})
c1.Send(pkt) // XXX err
c1
:=
nl1
.
NewConn
()
pkt2 := c1.Recv() // XXX err
pkt
=
mkpkt
(
33
,
[]
byte
(
"ping"
))
// TODO check pkt2 is pkt1 + small modification
xsend
(
c1
,
pkt
)
pkt2
:=
xrecv
(
c1
)
xverifyPkt
(
pkt2
,
c1
.
connId
,
34
,
[]
byte
(
"pong"
))
// test 2 channels with replies comming in reversed time order
// test 2 channels with replies comming in reversed time order
*/
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment