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
1
Issues
1
List
Boards
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
neoppod
Commits
b370f152
Commit
b370f152
authored
Jun 02, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
6a360785
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
78 additions
and
57 deletions
+78
-57
go/xcommon/pipenet/pipenet.go
go/xcommon/pipenet/pipenet.go
+78
-57
No files found.
go/xcommon/pipenet/pipenet.go
View file @
b370f152
...
...
@@ -25,14 +25,19 @@ package pipenet
import
(
"errors"
"fmt"
"net"
"strconv"
"strings"
"sync"
)
const
NetPrefix
=
"pipe"
// pipenet package works only with "pipe*" networks
var
errBadNetwork
=
errors
.
New
(
"pipenet: invalid network"
)
var
errBadAddress
=
errors
.
New
(
"pipenet: invalid address"
)
var
errNetNotFound
=
errors
.
New
(
"no such network"
)
//var errBadNetwork = errors.New("invalid network")
var
errBadAddress
=
errors
.
New
(
"invalid address"
)
var
errNetClosed
=
errors
.
New
(
"network connection closed"
)
var
errAddrAlreadyUsed
=
errors
.
New
(
"address already in use"
)
var
errConnRefused
=
errors
.
New
(
"connection refused"
)
...
...
@@ -47,25 +52,25 @@ type Network struct {
Name
string
mu
sync
.
Mutex
pipev
[]
pipe
// port -> listener + net.Pipe (?)
// listenv []chan dialReq
// listener[port] is waiting here if != nil
pipev
[]
*
pipe
// port -> listener + net.Pipe (?)
// listenv []chan dialReq
// listener[port] is waiting here if != nil
}
// pipe represents one pipenet connection
// pipe represents one pipenet connection
XXX naming
// it can be either already connected (2 endpoints) or only listening (1 endpoint) XXX
type
pipe
struct
{
// TODO
listener
*
listener
// listener is waiting here if != nil
}
// Addr represents address of a pipe endpoint
type
Addr
struct
{
network
*
Network
network
string
// full network name, e.g. "pipe"
addr
string
// XXX -> port ? + including c/s ?
}
var
_
net
.
Addr
=
(
*
Addr
)(
nil
)
func
(
a
*
Addr
)
Network
()
string
{
return
a
.
network
.
netname
()
}
func
(
a
*
Addr
)
Network
()
string
{
return
a
.
network
}
func
(
a
*
Addr
)
String
()
string
{
return
a
.
addr
}
// XXX Network() + ":" + a.addr ?
func
(
n
*
Network
)
netname
()
string
{
return
NetPrefix
+
n
.
Name
}
...
...
@@ -75,7 +80,7 @@ func (n *Network) netname() string { return NetPrefix + n.Name }
func
(
n
*
Network
)
Listen
(
laddr
string
)
(
net
.
Listener
,
error
)
{
lerr
:=
func
(
err
error
)
error
{
return
&
net
.
OpError
{
Op
:
"listen"
,
Net
:
n
.
netname
(),
Addr
:
laddr
,
Err
:
err
}
return
&
net
.
OpError
{
Op
:
"listen"
,
Net
:
n
.
netname
(),
Addr
:
&
Addr
{
n
.
netname
(),
laddr
}
,
Err
:
err
}
}
// laddr must be empty or int >= 0
...
...
@@ -83,59 +88,66 @@ func (n *Network) Listen(laddr string) (net.Listener, error) {
if
laddr
!=
""
{
port
,
err
:=
strconv
.
Atoi
(
laddr
)
if
err
!=
nil
||
port
<
0
{
return
lerr
(
errBadAddress
)
return
nil
,
lerr
(
errBadAddress
)
}
}
n
.
mu
.
Lock
()
defer
n
.
m
.
Unlock
()
defer
n
.
m
u
.
Unlock
()
// find first free port if it was not specified
if
port
<
0
{
for
port
=
0
;
port
<
len
(
n
.
listen
v
);
port
++
{
if
n
.
listen
v
[
port
]
==
nil
{
for
port
=
0
;
port
<
len
(
n
.
pipe
v
);
port
++
{
if
n
.
pipe
v
[
port
]
==
nil
{
break
}
}
// if all busy it exits with port == len(n.
listen
v)
// if all busy it exits with port == len(n.
pipe
v)
}
// grow if needed
for
port
>=
len
(
n
.
listen
v
)
{
n
.
listenv
=
append
(
n
.
listen
v
,
nil
)
for
port
>=
len
(
n
.
pipe
v
)
{
n
.
pipev
=
append
(
n
.
pipe
v
,
nil
)
}
if
n
.
listen
v
[
port
]
!=
nil
{
return
lerr
(
errAddrAlreadyUsed
)
if
n
.
pipe
v
[
port
]
!=
nil
{
return
nil
,
lerr
(
errAddrAlreadyUsed
)
}
l
:=
listener
{
...
}
n
.
listenv
[
port
]
=
l
...
l
:=
&
listener
{
network
:
n
,
port
:
port
,
dialq
:
make
(
chan
chan
connected
),
acceptq
:
make
(
chan
chan
connected
),
down
:
make
(
chan
struct
{}),
}
n
.
pipev
[
port
]
=
&
pipe
{
listener
:
l
}
return
&
l
return
l
,
ni
l
}
// listener implements net.Listener for piped network
type
listener
struct
{
network
*
Network
// XXX needed ?
port
int
// port we are listening on
network
*
Network
// XXX needed ?
port
int
// port we are listening on XXX needed ?
dialq
chan
chan
dialResp
// Dial requests to our port go here
acceptq
chan
chan
acceptResp
// Accept requests go here
down
chan
struct
{}
// Close -> down=ready
downOnce
sync
.
Once
// so Close several times is ok
dialq
chan
chan
connected
// Dial requests to our port go here
acceptq
chan
chan
connected
// Accept requests go here
down
chan
struct
{}
// Close -> down=ready
downOnce
sync
.
Once
// so Close several times is ok
}
var
_
net
.
Listener
=
(
*
listener
)
nil
var
_
net
.
Listener
=
(
*
listener
)
(
nil
)
func
(
l
*
listener
)
Addr
()
Addr
{
return
&
Addr
{
net
:
l
.
net
,
addr
:
fmt
.
Sprintf
(
"%d"
,
l
.
port
}
// NOTE no c/s XXX -> +l ?
func
(
l
*
listener
)
Addr
()
net
.
Addr
{
return
&
Addr
{
net
work
:
l
.
network
.
netname
(),
addr
:
fmt
.
Sprintf
(
"%d"
,
l
.
port
)
}
// NOTE no c/s XXX -> +l ?
}
func
(
l
*
listener
)
Close
()
error
{
l
.
downOnce
.
Do
(
func
()
{
close
(
l
.
down
)
})
return
nil
}
// connected is response from listener to Dial and Accept
...
...
@@ -147,8 +159,8 @@ type connected struct {
func
(
l
*
listener
)
Accept
()
(
net
.
Conn
,
error
)
{
ch
:=
make
(
chan
connected
)
select
{
case
l
.
down
return
...
"... closed"
// XXX
case
<-
l
.
down
:
return
nil
,
&
net
.
OpError
{
Op
:
"accept"
,
Net
:
l
.
network
.
netname
(),
Addr
:
l
.
Addr
(),
Err
:
errNetClosed
}
case
l
.
acceptq
<-
ch
:
resp
:=
<-
ch
...
...
@@ -156,33 +168,34 @@ func (l *listener) Accept() (net.Conn, error) {
}
}
func
(
n
*
Network
)
Dial
(
network
,
addr
string
)
(
net
.
Conn
,
error
)
{
func
(
n
*
Network
)
Dial
(
addr
string
)
(
net
.
Conn
,
error
)
{
derr
:=
func
(
err
error
)
error
{
return
&
net
.
OpError
{
Op
:
"dial"
,
Net
:
n
etwork
,
Addr
:
addr
,
Err
:
err
}
return
&
net
.
OpError
{
Op
:
"dial"
,
Net
:
n
.
netname
(),
Addr
:
&
Addr
{
n
.
netname
(),
addr
}
,
Err
:
err
}
}
port
,
err
:=
strconv
.
Atoi
(
addr
)
if
err
!=
nil
||
port
<
0
{
return
derr
(
errBadAddress
)
return
nil
,
derr
(
errBadAddress
)
}
n
.
mu
.
Lock
()
defer
n
.
mu
.
Unlock
()
// XXX ok to defer here?
if
port
>=
len
(
n
.
listen
v
)
{
return
derr
(
errConnRefused
)
// XXX merge with vvv
if
port
>=
len
(
n
.
pipe
v
)
{
return
nil
,
derr
(
errConnRefused
)
// XXX merge with vvv
}
l
:=
n
.
listen
v
[
port
]
if
l
==
nil
{
return
derr
(
errConnRefused
)
// XXX merge with ^^^
p
:=
n
.
pipe
v
[
port
]
if
p
==
nil
||
p
.
listener
==
nil
{
return
nil
,
derr
(
errConnRefused
)
// XXX merge with ^^^
}
l
:=
p
.
listener
// NOTE listener is not locking n.mu -> it is ok to send/receive under mu
ch
:=
make
(
chan
dialResp
)
ch
:=
make
(
chan
connected
)
select
{
case
l
.
down
:
return
derr
(
errConnRefused
)
case
<-
l
.
down
:
return
nil
,
derr
(
errConnRefused
)
case
l
.
dialq
<-
ch
:
resp
:=
<-
ch
...
...
@@ -210,7 +223,7 @@ func New(name string) *Network {
_
,
already
:=
networks
[
name
]
if
already
{
panic
(
fmt
.
Errorf
(
"pipenet %v already registered"
,
name
)
panic
(
fmt
.
Errorf
(
"pipenet %v already registered"
,
name
)
)
}
n
:=
&
Network
{
Name
:
name
}
...
...
@@ -219,31 +232,39 @@ func New(name string) *Network {
}
// lookupNet lookups Network by name
// returns nil, if not found
func
lookupNet
(
name
string
)
*
Network
{
func
lookupNet
(
name
string
)
(
*
Network
,
error
)
{
if
!
strings
.
HasPrefix
(
NetPrefix
,
name
)
{
return
nil
,
errBadNetwork
}
netMu
.
Lock
()
defer
netMu
.
Unlock
()
return
networks
[
name
]
n
:=
networks
[
strings
.
TrimPrefix
(
NetPrefix
,
name
)]
if
n
==
nil
{
return
nil
,
errNetNotFound
}
return
n
,
nil
}
// Dial dials addr on a pipenet
// network should be
valid registered pipe network name
// network should be
full valid registered pipe network name, e.g. "pipe"
func
Dial
(
network
,
addr
string
)
(
net
.
Conn
,
error
)
{
n
:=
lookupNet
(
network
)
if
n
=
=
nil
{
return
nil
,
&
net
.
OpError
{
Op
:
"dial"
,
Net
:
NetPrefix
+
network
,
Addr
:
addr
,
Err
:
err
}
n
,
err
:=
lookupNet
(
network
)
if
err
!
=
nil
{
return
nil
,
&
net
.
OpError
{
Op
:
"dial"
,
Net
:
network
,
Addr
:
&
Addr
{
network
,
addr
}
,
Err
:
err
}
}
return
n
.
Dial
(
addr
)
}
// XXX text
func
Listen
(
network
,
laddr
string
)
(
net
.
Listen
,
error
)
{
n
:=
lookupNet
(
network
)
if
n
==
nil
{
return
nil
,
&
net
.
OpError
{
Op
:
"listen"
,
Net
:
NetPrefix
+
network
,
Addr
:
addr
,
Err
:
err
}
// Listen starts listening on a pipenet address
// network should be full valid registered pipe network name, e.g. "pipe"
func
Listen
(
network
,
laddr
string
)
(
net
.
Listener
,
error
)
{
n
,
err
:=
lookupNet
(
network
)
if
err
!=
nil
{
return
nil
,
&
net
.
OpError
{
Op
:
"listen"
,
Net
:
network
,
Addr
:
&
Addr
{
network
,
laddr
},
Err
:
err
}
}
return
n
.
Listen
(
netw
,
laddr
)
return
n
.
Listen
(
laddr
)
}
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