Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
09d0d55f
Commit
09d0d55f
authored
Jun 09, 2015
by
Bas van Kervel
Committed by
Bas van Kervel
Jun 11, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added debug API
parent
faab931c
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
980 additions
and
712 deletions
+980
-712
api.go
rpc/api/api.go
+2
-1
debug.go
rpc/api/debug.go
+169
-0
debug_args.go
rpc/api/debug_args.go
+47
-0
debug_js.go
rpc/api/debug_js.go
+48
-0
utils.go
rpc/api/utils.go
+4
-0
ipc_unix.go
rpc/comms/ipc_unix.go
+5
-5
ipc_windows.go
rpc/comms/ipc_windows.go
+696
-699
jeth.go
rpc/jeth.go
+4
-3
types.go
rpc/shared/types.go
+5
-4
No files found.
rpc/api/api.go
View file @
09d0d55f
...
@@ -4,9 +4,10 @@ import "github.com/ethereum/go-ethereum/rpc/shared"
...
@@ -4,9 +4,10 @@ import "github.com/ethereum/go-ethereum/rpc/shared"
const
(
const
(
// List with all API's which are offered over the IPC interface by default
// List with all API's which are offered over the IPC interface by default
DefaultIpcApis
=
"eth,miner,net,web3"
DefaultIpcApis
=
"
debug,
eth,miner,net,web3"
EthApiName
=
"eth"
EthApiName
=
"eth"
DebugApiName
=
"debug"
MergedApiName
=
"merged"
MergedApiName
=
"merged"
MinerApiName
=
"miner"
MinerApiName
=
"miner"
NetApiName
=
"net"
NetApiName
=
"net"
...
...
rpc/api/debug.go
0 → 100644
View file @
09d0d55f
package
api
import
(
"fmt"
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared"
"github.com/ethereum/go-ethereum/xeth"
)
const
(
DebugVersion
=
"1.0.0"
)
var
(
// mapping between methods and handlers
DebugMapping
=
map
[
string
]
debughandler
{
"debug_dumpBlock"
:
(
*
DebugApi
)
.
DumpBlock
,
"debug_getBlockRlp"
:
(
*
DebugApi
)
.
GetBlockRlp
,
"debug_printBlock"
:
(
*
DebugApi
)
.
PrintBlock
,
"debug_processBlock"
:
(
*
DebugApi
)
.
ProcessBlock
,
"debug_seedHash"
:
(
*
DebugApi
)
.
SeedHash
,
"debug_setHead"
:
(
*
DebugApi
)
.
SetHead
,
}
)
// debug callback handler
type
debughandler
func
(
*
DebugApi
,
*
shared
.
Request
)
(
interface
{},
error
)
// admin api provider
type
DebugApi
struct
{
xeth
*
xeth
.
XEth
ethereum
*
eth
.
Ethereum
methods
map
[
string
]
debughandler
codec
codec
.
ApiCoder
}
// create a new debug api instance
func
NewDebugApi
(
xeth
*
xeth
.
XEth
,
ethereum
*
eth
.
Ethereum
,
coder
codec
.
Codec
)
*
DebugApi
{
return
&
DebugApi
{
xeth
:
xeth
,
ethereum
:
ethereum
,
methods
:
DebugMapping
,
codec
:
coder
.
New
(
nil
),
}
}
// collection with supported methods
func
(
self
*
DebugApi
)
Methods
()
[]
string
{
methods
:=
make
([]
string
,
len
(
self
.
methods
))
i
:=
0
for
k
:=
range
self
.
methods
{
methods
[
i
]
=
k
i
++
}
return
methods
}
// Execute given request
func
(
self
*
DebugApi
)
Execute
(
req
*
shared
.
Request
)
(
interface
{},
error
)
{
if
callback
,
ok
:=
self
.
methods
[
req
.
Method
];
ok
{
return
callback
(
self
,
req
)
}
return
nil
,
&
shared
.
NotImplementedError
{
req
.
Method
}
}
func
(
self
*
DebugApi
)
Name
()
string
{
return
DebugApiName
}
func
(
self
*
DebugApi
)
PrintBlock
(
req
*
shared
.
Request
)
(
interface
{},
error
)
{
args
:=
new
(
BlockNumArg
)
if
err
:=
self
.
codec
.
Decode
(
req
.
Params
,
&
args
);
err
!=
nil
{
return
nil
,
shared
.
NewDecodeParamError
(
err
.
Error
())
}
block
:=
self
.
xeth
.
EthBlockByNumber
(
args
.
BlockNumber
)
return
fmt
.
Sprintf
(
"%s"
,
block
),
nil
}
func
(
self
*
DebugApi
)
DumpBlock
(
req
*
shared
.
Request
)
(
interface
{},
error
)
{
args
:=
new
(
BlockNumArg
)
if
err
:=
self
.
codec
.
Decode
(
req
.
Params
,
&
args
);
err
!=
nil
{
return
nil
,
shared
.
NewDecodeParamError
(
err
.
Error
())
}
block
:=
self
.
xeth
.
EthBlockByNumber
(
args
.
BlockNumber
)
if
block
==
nil
{
return
nil
,
fmt
.
Errorf
(
"block #%d not found"
,
args
.
BlockNumber
)
}
stateDb
:=
state
.
New
(
block
.
Root
(),
self
.
ethereum
.
StateDb
())
if
stateDb
==
nil
{
return
nil
,
nil
}
return
stateDb
.
Dump
(),
nil
}
func
(
self
*
DebugApi
)
GetBlockRlp
(
req
*
shared
.
Request
)
(
interface
{},
error
)
{
args
:=
new
(
BlockNumArg
)
if
err
:=
self
.
codec
.
Decode
(
req
.
Params
,
&
args
);
err
!=
nil
{
return
nil
,
shared
.
NewDecodeParamError
(
err
.
Error
())
}
block
:=
self
.
xeth
.
EthBlockByNumber
(
args
.
BlockNumber
)
if
block
==
nil
{
return
nil
,
fmt
.
Errorf
(
"block #%d not found"
,
args
.
BlockNumber
)
}
encoded
,
err
:=
rlp
.
EncodeToBytes
(
block
)
return
fmt
.
Sprintf
(
"%x"
,
encoded
),
err
}
func
(
self
*
DebugApi
)
SetHead
(
req
*
shared
.
Request
)
(
interface
{},
error
)
{
args
:=
new
(
BlockNumArg
)
if
err
:=
self
.
codec
.
Decode
(
req
.
Params
,
&
args
);
err
!=
nil
{
return
nil
,
shared
.
NewDecodeParamError
(
err
.
Error
())
}
block
:=
self
.
xeth
.
EthBlockByNumber
(
args
.
BlockNumber
)
if
block
==
nil
{
return
nil
,
fmt
.
Errorf
(
"block #%d not found"
,
args
.
BlockNumber
)
}
self
.
ethereum
.
ChainManager
()
.
SetHead
(
block
)
return
nil
,
nil
}
func
(
self
*
DebugApi
)
ProcessBlock
(
req
*
shared
.
Request
)
(
interface
{},
error
)
{
args
:=
new
(
BlockNumArg
)
if
err
:=
self
.
codec
.
Decode
(
req
.
Params
,
&
args
);
err
!=
nil
{
return
nil
,
shared
.
NewDecodeParamError
(
err
.
Error
())
}
block
:=
self
.
xeth
.
EthBlockByNumber
(
args
.
BlockNumber
)
if
block
==
nil
{
return
nil
,
fmt
.
Errorf
(
"block #%d not found"
,
args
.
BlockNumber
)
}
old
:=
vm
.
Debug
defer
func
()
{
vm
.
Debug
=
old
}()
vm
.
Debug
=
true
_
,
err
:=
self
.
ethereum
.
BlockProcessor
()
.
RetryProcess
(
block
)
if
err
==
nil
{
return
true
,
nil
}
return
false
,
err
}
func
(
self
*
DebugApi
)
SeedHash
(
req
*
shared
.
Request
)
(
interface
{},
error
)
{
args
:=
new
(
BlockNumArg
)
if
err
:=
self
.
codec
.
Decode
(
req
.
Params
,
&
args
);
err
!=
nil
{
return
nil
,
shared
.
NewDecodeParamError
(
err
.
Error
())
}
if
hash
,
err
:=
ethash
.
GetSeedHash
(
uint64
(
args
.
BlockNumber
));
err
==
nil
{
return
fmt
.
Sprintf
(
"0x%x"
,
hash
),
nil
}
else
{
return
nil
,
err
}
}
rpc/api/debug_args.go
0 → 100644
View file @
09d0d55f
package
api
import
(
"encoding/json"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/rpc/shared"
)
type
WaitForBlockArgs
struct
{
MinHeight
int
Timeout
int
// in seconds
}
func
(
args
*
WaitForBlockArgs
)
UnmarshalJSON
(
b
[]
byte
)
(
err
error
)
{
var
obj
[]
interface
{}
if
err
:=
json
.
Unmarshal
(
b
,
&
obj
);
err
!=
nil
{
return
shared
.
NewDecodeParamError
(
err
.
Error
())
}
if
len
(
obj
)
>
2
{
return
fmt
.
Errorf
(
"waitForArgs needs 0, 1, 2 arguments"
)
}
// default values when not provided
args
.
MinHeight
=
-
1
args
.
Timeout
=
-
1
if
len
(
obj
)
>=
1
{
var
minHeight
*
big
.
Int
if
minHeight
,
err
=
numString
(
obj
[
0
]);
err
!=
nil
{
return
err
}
args
.
MinHeight
=
int
(
minHeight
.
Int64
())
}
if
len
(
obj
)
>=
2
{
timeout
,
err
:=
numString
(
obj
[
1
])
if
err
!=
nil
{
return
err
}
args
.
Timeout
=
int
(
timeout
.
Int64
())
}
return
nil
}
rpc/api/debug_js.go
0 → 100644
View file @
09d0d55f
package
api
const
Debug_JS
=
`
web3.extend({
property: 'debug',
methods:
[
new web3.extend.Method({
name: 'printBlock',
call: 'debug_printBlock',
params: 1,
inputFormatter: [web3.extend.formatters.formatInputInt],
outputFormatter: web3.extend.formatters.formatOutputString
}),
new web3.extend.Method({
name: 'getBlockRlp',
call: 'debug_getBlockRlp',
params: 1,
inputFormatter: [web3.extend.formatters.formatInputInt],
outputFormatter: web3.extend.formatters.formatOutputString
}),
new web3.extend.Method({
name: 'setHead',
call: 'debug_setHead',
params: 1,
inputFormatter: [web3.extend.formatters.formatInputInt],
outputFormatter: web3.extend.formatters.formatOutputBool
}),
new web3.extend.Method({
name: 'processBlock',
call: 'debug_processBlock',
params: 1,
inputFormatter: [web3.extend.formatters.formatInputInt],
outputFormatter: function(obj) { return obj; }
}),
new web3.extend.Method({
name: 'seedHash',
call: 'debug_seedHash',
params: 1,
inputFormatter: [web3.extend.formatters.formatInputInt],
outputFormatter: web3.extend.formatters.formatOutputString
})
],
properties:
[
]
});
`
rpc/api/utils.go
View file @
09d0d55f
...
@@ -21,6 +21,8 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
...
@@ -21,6 +21,8 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
for
i
,
name
:=
range
names
{
for
i
,
name
:=
range
names
{
switch
strings
.
ToLower
(
strings
.
TrimSpace
(
name
))
{
switch
strings
.
ToLower
(
strings
.
TrimSpace
(
name
))
{
case
DebugApiName
:
apis
[
i
]
=
NewDebugApi
(
xeth
,
eth
,
codec
)
case
EthApiName
:
case
EthApiName
:
apis
[
i
]
=
NewEthApi
(
xeth
,
codec
)
apis
[
i
]
=
NewEthApi
(
xeth
,
codec
)
case
MinerApiName
:
case
MinerApiName
:
...
@@ -39,6 +41,8 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
...
@@ -39,6 +41,8 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
func
Javascript
(
name
string
)
string
{
func
Javascript
(
name
string
)
string
{
switch
strings
.
ToLower
(
strings
.
TrimSpace
(
name
))
{
switch
strings
.
ToLower
(
strings
.
TrimSpace
(
name
))
{
case
DebugApiName
:
return
Debug_JS
case
MinerApiName
:
case
MinerApiName
:
return
Miner_JS
return
Miner_JS
case
NetApiName
:
case
NetApiName
:
...
...
rpc/comms/ipc_unix.go
View file @
09d0d55f
...
@@ -3,9 +3,9 @@
...
@@ -3,9 +3,9 @@
package
comms
package
comms
import
(
import
(
"io"
"io"
"net"
"net"
"os"
"os"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/logger/glog"
...
@@ -70,8 +70,8 @@ func startIpc(cfg IpcConfig, codec codec.Codec, api api.EthereumApi) error {
...
@@ -70,8 +70,8 @@ func startIpc(cfg IpcConfig, codec codec.Codec, api api.EthereumApi) error {
os
.
Remove
(
cfg
.
Endpoint
)
os
.
Remove
(
cfg
.
Endpoint
)
}()
}()
glog
.
V
(
logger
.
Info
)
.
Infof
(
"IPC service started (%s)
\n
"
,
cfg
.
Endpoint
)
glog
.
V
(
logger
.
Info
)
.
Infof
(
"IPC service started (%s)
\n
"
,
cfg
.
Endpoint
)
return
nil
return
nil
}
}
rpc/comms/ipc_windows.go
View file @
09d0d55f
// +build windows
// +build windows
package
comms
package
comms
import
(
import
(
"fmt"
"fmt"
"io"
"io"
"net"
"net"
"os"
"os"
"sync"
"sync"
"syscall"
"syscall"
"time"
"time"
"unsafe"
"unsafe"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared"
"github.com/ethereum/go-ethereum/rpc/shared"
)
)
var
(
var
(
modkernel32
=
syscall
.
NewLazyDLL
(
"kernel32.dll"
)
modkernel32
=
syscall
.
NewLazyDLL
(
"kernel32.dll"
)
procCreateNamedPipeW
=
modkernel32
.
NewProc
(
"CreateNamedPipeW"
)
procCreateNamedPipeW
=
modkernel32
.
NewProc
(
"CreateNamedPipeW"
)
procConnectNamedPipe
=
modkernel32
.
NewProc
(
"ConnectNamedPipe"
)
procConnectNamedPipe
=
modkernel32
.
NewProc
(
"ConnectNamedPipe"
)
procDisconnectNamedPipe
=
modkernel32
.
NewProc
(
"DisconnectNamedPipe"
)
procDisconnectNamedPipe
=
modkernel32
.
NewProc
(
"DisconnectNamedPipe"
)
procWaitNamedPipeW
=
modkernel32
.
NewProc
(
"WaitNamedPipeW"
)
procWaitNamedPipeW
=
modkernel32
.
NewProc
(
"WaitNamedPipeW"
)
procCreateEventW
=
modkernel32
.
NewProc
(
"CreateEventW"
)
procCreateEventW
=
modkernel32
.
NewProc
(
"CreateEventW"
)
procGetOverlappedResult
=
modkernel32
.
NewProc
(
"GetOverlappedResult"
)
procGetOverlappedResult
=
modkernel32
.
NewProc
(
"GetOverlappedResult"
)
procCancelIoEx
=
modkernel32
.
NewProc
(
"CancelIoEx"
)
procCancelIoEx
=
modkernel32
.
NewProc
(
"CancelIoEx"
)
)
)
func
createNamedPipe
(
name
*
uint16
,
openMode
uint32
,
pipeMode
uint32
,
maxInstances
uint32
,
outBufSize
uint32
,
inBufSize
uint32
,
defaultTimeout
uint32
,
sa
*
syscall
.
SecurityAttributes
)
(
handle
syscall
.
Handle
,
err
error
)
{
func
createNamedPipe
(
name
*
uint16
,
openMode
uint32
,
pipeMode
uint32
,
maxInstances
uint32
,
outBufSize
uint32
,
inBufSize
uint32
,
defaultTimeout
uint32
,
sa
*
syscall
.
SecurityAttributes
)
(
handle
syscall
.
Handle
,
err
error
)
{
r0
,
_
,
e1
:=
syscall
.
Syscall9
(
procCreateNamedPipeW
.
Addr
(),
8
,
uintptr
(
unsafe
.
Pointer
(
name
)),
uintptr
(
openMode
),
uintptr
(
pipeMode
),
uintptr
(
maxInstances
),
uintptr
(
outBufSize
),
uintptr
(
inBufSize
),
uintptr
(
defaultTimeout
),
uintptr
(
unsafe
.
Pointer
(
sa
)),
0
)
r0
,
_
,
e1
:=
syscall
.
Syscall9
(
procCreateNamedPipeW
.
Addr
(),
8
,
uintptr
(
unsafe
.
Pointer
(
name
)),
uintptr
(
openMode
),
uintptr
(
pipeMode
),
uintptr
(
maxInstances
),
uintptr
(
outBufSize
),
uintptr
(
inBufSize
),
uintptr
(
defaultTimeout
),
uintptr
(
unsafe
.
Pointer
(
sa
)),
0
)
handle
=
syscall
.
Handle
(
r0
)
handle
=
syscall
.
Handle
(
r0
)
if
handle
==
syscall
.
InvalidHandle
{
if
handle
==
syscall
.
InvalidHandle
{
if
e1
!=
0
{
if
e1
!=
0
{
err
=
error
(
e1
)
err
=
error
(
e1
)
}
else
{
}
else
{
err
=
syscall
.
EINVAL
err
=
syscall
.
EINVAL
}
}
}
}
return
return
}
}
func
cancelIoEx
(
handle
syscall
.
Handle
,
overlapped
*
syscall
.
Overlapped
)
(
err
error
)
{
func
cancelIoEx
(
handle
syscall
.
Handle
,
overlapped
*
syscall
.
Overlapped
)
(
err
error
)
{
r1
,
_
,
e1
:=
syscall
.
Syscall
(
procCancelIoEx
.
Addr
(),
2
,
uintptr
(
handle
),
uintptr
(
unsafe
.
Pointer
(
overlapped
)),
0
)
r1
,
_
,
e1
:=
syscall
.
Syscall
(
procCancelIoEx
.
Addr
(),
2
,
uintptr
(
handle
),
uintptr
(
unsafe
.
Pointer
(
overlapped
)),
0
)
if
r1
==
0
{
if
r1
==
0
{
if
e1
!=
0
{
if
e1
!=
0
{
err
=
error
(
e1
)
err
=
error
(
e1
)
}
else
{
}
else
{
err
=
syscall
.
EINVAL
err
=
syscall
.
EINVAL
}
}
}
}
return
return
}
}
func
connectNamedPipe
(
handle
syscall
.
Handle
,
overlapped
*
syscall
.
Overlapped
)
(
err
error
)
{
func
connectNamedPipe
(
handle
syscall
.
Handle
,
overlapped
*
syscall
.
Overlapped
)
(
err
error
)
{
r1
,
_
,
e1
:=
syscall
.
Syscall
(
procConnectNamedPipe
.
Addr
(),
2
,
uintptr
(
handle
),
uintptr
(
unsafe
.
Pointer
(
overlapped
)),
0
)
r1
,
_
,
e1
:=
syscall
.
Syscall
(
procConnectNamedPipe
.
Addr
(),
2
,
uintptr
(
handle
),
uintptr
(
unsafe
.
Pointer
(
overlapped
)),
0
)
if
r1
==
0
{
if
r1
==
0
{
if
e1
!=
0
{
if
e1
!=
0
{
err
=
error
(
e1
)
err
=
error
(
e1
)
}
else
{
}
else
{
err
=
syscall
.
EINVAL
err
=
syscall
.
EINVAL
}
}
}
}
return
return
}
}
func
disconnectNamedPipe
(
handle
syscall
.
Handle
)
(
err
error
)
{
func
disconnectNamedPipe
(
handle
syscall
.
Handle
)
(
err
error
)
{
r1
,
_
,
e1
:=
syscall
.
Syscall
(
procDisconnectNamedPipe
.
Addr
(),
1
,
uintptr
(
handle
),
0
,
0
)
r1
,
_
,
e1
:=
syscall
.
Syscall
(
procDisconnectNamedPipe
.
Addr
(),
1
,
uintptr
(
handle
),
0
,
0
)
if
r1
==
0
{
if
r1
==
0
{
if
e1
!=
0
{
if
e1
!=
0
{
err
=
error
(
e1
)
err
=
error
(
e1
)
}
else
{
}
else
{
err
=
syscall
.
EINVAL
err
=
syscall
.
EINVAL
}
}
}
}
return
return
}
}
func
waitNamedPipe
(
name
*
uint16
,
timeout
uint32
)
(
err
error
)
{
func
waitNamedPipe
(
name
*
uint16
,
timeout
uint32
)
(
err
error
)
{
r1
,
_
,
e1
:=
syscall
.
Syscall
(
procWaitNamedPipeW
.
Addr
(),
2
,
uintptr
(
unsafe
.
Pointer
(
name
)),
uintptr
(
timeout
),
0
)
r1
,
_
,
e1
:=
syscall
.
Syscall
(
procWaitNamedPipeW
.
Addr
(),
2
,
uintptr
(
unsafe
.
Pointer
(
name
)),
uintptr
(
timeout
),
0
)
if
r1
==
0
{
if
r1
==
0
{
if
e1
!=
0
{
if
e1
!=
0
{
err
=
error
(
e1
)
err
=
error
(
e1
)
}
else
{
}
else
{
err
=
syscall
.
EINVAL
err
=
syscall
.
EINVAL
}
}
}
}
return
return
}
}
func
createEvent
(
sa
*
syscall
.
SecurityAttributes
,
manualReset
bool
,
initialState
bool
,
name
*
uint16
)
(
handle
syscall
.
Handle
,
err
error
)
{
func
createEvent
(
sa
*
syscall
.
SecurityAttributes
,
manualReset
bool
,
initialState
bool
,
name
*
uint16
)
(
handle
syscall
.
Handle
,
err
error
)
{
var
_p0
uint32
var
_p0
uint32
if
manualReset
{
if
manualReset
{
_p0
=
1
_p0
=
1
}
else
{
}
else
{
_p0
=
0
_p0
=
0
}
}
var
_p1
uint32
var
_p1
uint32
if
initialState
{
if
initialState
{
_p1
=
1
_p1
=
1
}
else
{
}
else
{
_p1
=
0
_p1
=
0
}
}
r0
,
_
,
e1
:=
syscall
.
Syscall6
(
procCreateEventW
.
Addr
(),
4
,
uintptr
(
unsafe
.
Pointer
(
sa
)),
uintptr
(
_p0
),
uintptr
(
_p1
),
uintptr
(
unsafe
.
Pointer
(
name
)),
0
,
0
)
r0
,
_
,
e1
:=
syscall
.
Syscall6
(
procCreateEventW
.
Addr
(),
4
,
uintptr
(
unsafe
.
Pointer
(
sa
)),
uintptr
(
_p0
),
uintptr
(
_p1
),
uintptr
(
unsafe
.
Pointer
(
name
)),
0
,
0
)
handle
=
syscall
.
Handle
(
r0
)
handle
=
syscall
.
Handle
(
r0
)
if
handle
==
syscall
.
InvalidHandle
{
if
handle
==
syscall
.
InvalidHandle
{
if
e1
!=
0
{
if
e1
!=
0
{
err
=
error
(
e1
)
err
=
error
(
e1
)
}
else
{
}
else
{
err
=
syscall
.
EINVAL
err
=
syscall
.
EINVAL
}
}
}
}
return
return
}
}
func
getOverlappedResult
(
handle
syscall
.
Handle
,
overlapped
*
syscall
.
Overlapped
,
transferred
*
uint32
,
wait
bool
)
(
err
error
)
{
func
getOverlappedResult
(
handle
syscall
.
Handle
,
overlapped
*
syscall
.
Overlapped
,
transferred
*
uint32
,
wait
bool
)
(
err
error
)
{
var
_p0
uint32
var
_p0
uint32
if
wait
{
if
wait
{
_p0
=
1
_p0
=
1
}
else
{
}
else
{
_p0
=
0
_p0
=
0
}
}
r1
,
_
,
e1
:=
syscall
.
Syscall6
(
procGetOverlappedResult
.
Addr
(),
4
,
uintptr
(
handle
),
uintptr
(
unsafe
.
Pointer
(
overlapped
)),
uintptr
(
unsafe
.
Pointer
(
transferred
)),
uintptr
(
_p0
),
0
,
0
)
r1
,
_
,
e1
:=
syscall
.
Syscall6
(
procGetOverlappedResult
.
Addr
(),
4
,
uintptr
(
handle
),
uintptr
(
unsafe
.
Pointer
(
overlapped
)),
uintptr
(
unsafe
.
Pointer
(
transferred
)),
uintptr
(
_p0
),
0
,
0
)
if
r1
==
0
{
if
r1
==
0
{
if
e1
!=
0
{
if
e1
!=
0
{
err
=
error
(
e1
)
err
=
error
(
e1
)
}
else
{
}
else
{
err
=
syscall
.
EINVAL
err
=
syscall
.
EINVAL
}
}
}
}
return
return
}
}
const
(
const
(
// openMode
// openMode
pipe_access_duplex
=
0x3
pipe_access_duplex
=
0x3
pipe_access_inbound
=
0x1
pipe_access_inbound
=
0x1
pipe_access_outbound
=
0x2
pipe_access_outbound
=
0x2
// openMode write flags
// openMode write flags
file_flag_first_pipe_instance
=
0x00080000
file_flag_first_pipe_instance
=
0x00080000
file_flag_write_through
=
0x80000000
file_flag_write_through
=
0x80000000
file_flag_overlapped
=
0x40000000
file_flag_overlapped
=
0x40000000
// openMode ACL flags
// openMode ACL flags
write_dac
=
0x00040000
write_dac
=
0x00040000
write_owner
=
0x00080000
write_owner
=
0x00080000
access_system_security
=
0x01000000
access_system_security
=
0x01000000
// pipeMode
// pipeMode
pipe_type_byte
=
0x0
pipe_type_byte
=
0x0
pipe_type_message
=
0x4
pipe_type_message
=
0x4
// pipeMode read mode flags
// pipeMode read mode flags
pipe_readmode_byte
=
0x0
pipe_readmode_byte
=
0x0
pipe_readmode_message
=
0x2
pipe_readmode_message
=
0x2
// pipeMode wait mode flags
// pipeMode wait mode flags
pipe_wait
=
0x0
pipe_wait
=
0x0
pipe_nowait
=
0x1
pipe_nowait
=
0x1
// pipeMode remote-client mode flags
// pipeMode remote-client mode flags
pipe_accept_remote_clients
=
0x0
pipe_accept_remote_clients
=
0x0
pipe_reject_remote_clients
=
0x8
pipe_reject_remote_clients
=
0x8
pipe_unlimited_instances
=
255
pipe_unlimited_instances
=
255
nmpwait_wait_forever
=
0xFFFFFFFF
nmpwait_wait_forever
=
0xFFFFFFFF
// the two not-an-errors below occur if a client connects to the pipe between
// the two not-an-errors below occur if a client connects to the pipe between
// the server's CreateNamedPipe and ConnectNamedPipe calls.
// the server's CreateNamedPipe and ConnectNamedPipe calls.
error_no_data
syscall
.
Errno
=
0xE8
error_no_data
syscall
.
Errno
=
0xE8
error_pipe_connected
syscall
.
Errno
=
0x217
error_pipe_connected
syscall
.
Errno
=
0x217
error_pipe_busy
syscall
.
Errno
=
0xE7
error_pipe_busy
syscall
.
Errno
=
0xE7
error_sem_timeout
syscall
.
Errno
=
0x79
error_sem_timeout
syscall
.
Errno
=
0x79
error_bad_pathname
syscall
.
Errno
=
0xA1
error_bad_pathname
syscall
.
Errno
=
0xA1
error_invalid_name
syscall
.
Errno
=
0x7B
error_invalid_name
syscall
.
Errno
=
0x7B
error_io_incomplete
syscall
.
Errno
=
0x3e4
error_io_incomplete
syscall
.
Errno
=
0x3e4
)
)
var
_
net
.
Conn
=
(
*
PipeConn
)(
nil
)
var
_
net
.
Conn
=
(
*
PipeConn
)(
nil
)
var
_
net
.
Listener
=
(
*
PipeListener
)(
nil
)
var
_
net
.
Listener
=
(
*
PipeListener
)(
nil
)
// ErrClosed is the error returned by PipeListener.Accept when Close is called
// ErrClosed is the error returned by PipeListener.Accept when Close is called
// on the PipeListener.
// on the PipeListener.
var
ErrClosed
=
PipeError
{
"Pipe has been closed."
,
false
}
var
ErrClosed
=
PipeError
{
"Pipe has been closed."
,
false
}
// PipeError is an error related to a call to a pipe
// PipeError is an error related to a call to a pipe
type
PipeError
struct
{
type
PipeError
struct
{
msg
string
msg
string
timeout
bool
timeout
bool
}
}
// Error implements the error interface
// Error implements the error interface
func
(
e
PipeError
)
Error
()
string
{
func
(
e
PipeError
)
Error
()
string
{
return
e
.
msg
return
e
.
msg
}
}
// Timeout implements net.AddrError.Timeout()
// Timeout implements net.AddrError.Timeout()
func
(
e
PipeError
)
Timeout
()
bool
{
func
(
e
PipeError
)
Timeout
()
bool
{
return
e
.
timeout
return
e
.
timeout
}
}
// Temporary implements net.AddrError.Temporary()
// Temporary implements net.AddrError.Temporary()
func
(
e
PipeError
)
Temporary
()
bool
{
func
(
e
PipeError
)
Temporary
()
bool
{
return
false
return
false
}
}
// Dial connects to a named pipe with the given address. If the specified pipe is not available,
// Dial connects to a named pipe with the given address. If the specified pipe is not available,
// it will wait indefinitely for the pipe to become available.
// it will wait indefinitely for the pipe to become available.
//
//
// The address must be of the form \\.\\pipe\<name> for local pipes and \\<computer>\pipe\<name>
// The address must be of the form \\.\\pipe\<name> for local pipes and \\<computer>\pipe\<name>
// for remote pipes.
// for remote pipes.
//
//
// Dial will return a PipeError if you pass in a badly formatted pipe name.
// Dial will return a PipeError if you pass in a badly formatted pipe name.
//
//
// Examples:
// Examples:
// // local pipe
// // local pipe
// conn, err := Dial(`\\.\pipe\mypipename`)
// conn, err := Dial(`\\.\pipe\mypipename`)
//
//
// // remote pipe
// // remote pipe
// conn, err := Dial(`\\othercomp\pipe\mypipename`)
// conn, err := Dial(`\\othercomp\pipe\mypipename`)
func
Dial
(
address
string
)
(
*
PipeConn
,
error
)
{
func
Dial
(
address
string
)
(
*
PipeConn
,
error
)
{
for
{
for
{
conn
,
err
:=
dial
(
address
,
nmpwait_wait_forever
)
conn
,
err
:=
dial
(
address
,
nmpwait_wait_forever
)
if
err
==
nil
{
if
err
==
nil
{
return
conn
,
nil
return
conn
,
nil
}
}
if
isPipeNotReady
(
err
)
{
if
isPipeNotReady
(
err
)
{
<-
time
.
After
(
100
*
time
.
Millisecond
)
<-
time
.
After
(
100
*
time
.
Millisecond
)
continue
continue
}
}
return
nil
,
err
return
nil
,
err
}
}
}
}
// DialTimeout acts like Dial, but will time out after the duration of timeout
// DialTimeout acts like Dial, but will time out after the duration of timeout
func
DialTimeout
(
address
string
,
timeout
time
.
Duration
)
(
*
PipeConn
,
error
)
{
func
DialTimeout
(
address
string
,
timeout
time
.
Duration
)
(
*
PipeConn
,
error
)
{
deadline
:=
time
.
Now
()
.
Add
(
timeout
)
deadline
:=
time
.
Now
()
.
Add
(
timeout
)
now
:=
time
.
Now
()
now
:=
time
.
Now
()
for
now
.
Before
(
deadline
)
{
for
now
.
Before
(
deadline
)
{
millis
:=
uint32
(
deadline
.
Sub
(
now
)
/
time
.
Millisecond
)
millis
:=
uint32
(
deadline
.
Sub
(
now
)
/
time
.
Millisecond
)
conn
,
err
:=
dial
(
address
,
millis
)
conn
,
err
:=
dial
(
address
,
millis
)
if
err
==
nil
{
if
err
==
nil
{
return
conn
,
nil
return
conn
,
nil
}
}
if
err
==
error_sem_timeout
{
if
err
==
error_sem_timeout
{
// This is WaitNamedPipe's timeout error, so we know we're done
// This is WaitNamedPipe's timeout error, so we know we're done
return
nil
,
PipeError
{
fmt
.
Sprintf
(
return
nil
,
PipeError
{
fmt
.
Sprintf
(
"Timed out waiting for pipe '%s' to come available"
,
address
),
true
}
"Timed out waiting for pipe '%s' to come available"
,
address
),
true
}
}
}
if
isPipeNotReady
(
err
)
{
if
isPipeNotReady
(
err
)
{
left
:=
deadline
.
Sub
(
time
.
Now
())
left
:=
deadline
.
Sub
(
time
.
Now
())
retry
:=
100
*
time
.
Millisecond
retry
:=
100
*
time
.
Millisecond
if
left
>
retry
{
if
left
>
retry
{
<-
time
.
After
(
retry
)
<-
time
.
After
(
retry
)
}
else
{
}
else
{
<-
time
.
After
(
left
-
time
.
Millisecond
)
<-
time
.
After
(
left
-
time
.
Millisecond
)
}
}
now
=
time
.
Now
()
now
=
time
.
Now
()
continue
continue
}
}
return
nil
,
err
return
nil
,
err
}
}
return
nil
,
PipeError
{
fmt
.
Sprintf
(
return
nil
,
PipeError
{
fmt
.
Sprintf
(
"Timed out waiting for pipe '%s' to come available"
,
address
),
true
}
"Timed out waiting for pipe '%s' to come available"
,
address
),
true
}
}
}
// isPipeNotReady checks the error to see if it indicates the pipe is not ready
// isPipeNotReady checks the error to see if it indicates the pipe is not ready
func
isPipeNotReady
(
err
error
)
bool
{
func
isPipeNotReady
(
err
error
)
bool
{
// Pipe Busy means another client just grabbed the open pipe end,
// Pipe Busy means another client just grabbed the open pipe end,
// and the server hasn't made a new one yet.
// and the server hasn't made a new one yet.
// File Not Found means the server hasn't created the pipe yet.
// File Not Found means the server hasn't created the pipe yet.
// Neither is a fatal error.
// Neither is a fatal error.
return
err
==
syscall
.
ERROR_FILE_NOT_FOUND
||
err
==
error_pipe_busy
return
err
==
syscall
.
ERROR_FILE_NOT_FOUND
||
err
==
error_pipe_busy
}
}
// newOverlapped creates a structure used to track asynchronous
// newOverlapped creates a structure used to track asynchronous
// I/O requests that have been issued.
// I/O requests that have been issued.
func
newOverlapped
()
(
*
syscall
.
Overlapped
,
error
)
{
func
newOverlapped
()
(
*
syscall
.
Overlapped
,
error
)
{
event
,
err
:=
createEvent
(
nil
,
true
,
true
,
nil
)
event
,
err
:=
createEvent
(
nil
,
true
,
true
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
&
syscall
.
Overlapped
{
HEvent
:
event
},
nil
return
&
syscall
.
Overlapped
{
HEvent
:
event
},
nil
}
}
// waitForCompletion waits for an asynchronous I/O request referred to by overlapped to complete.
// waitForCompletion waits for an asynchronous I/O request referred to by overlapped to complete.
// This function returns the number of bytes transferred by the operation and an error code if
// This function returns the number of bytes transferred by the operation and an error code if
// applicable (nil otherwise).
// applicable (nil otherwise).
func
waitForCompletion
(
handle
syscall
.
Handle
,
overlapped
*
syscall
.
Overlapped
)
(
uint32
,
error
)
{
func
waitForCompletion
(
handle
syscall
.
Handle
,
overlapped
*
syscall
.
Overlapped
)
(
uint32
,
error
)
{
_
,
err
:=
syscall
.
WaitForSingleObject
(
overlapped
.
HEvent
,
syscall
.
INFINITE
)
_
,
err
:=
syscall
.
WaitForSingleObject
(
overlapped
.
HEvent
,
syscall
.
INFINITE
)
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
err
return
0
,
err
}
}
var
transferred
uint32
var
transferred
uint32
err
=
getOverlappedResult
(
handle
,
overlapped
,
&
transferred
,
true
)
err
=
getOverlappedResult
(
handle
,
overlapped
,
&
transferred
,
true
)
return
transferred
,
err
return
transferred
,
err
}
}
// dial is a helper to initiate a connection to a named pipe that has been started by a server.
// dial is a helper to initiate a connection to a named pipe that has been started by a server.
// The timeout is only enforced if the pipe server has already created the pipe, otherwise
// The timeout is only enforced if the pipe server has already created the pipe, otherwise
// this function will return immediately.
// this function will return immediately.
func
dial
(
address
string
,
timeout
uint32
)
(
*
PipeConn
,
error
)
{
func
dial
(
address
string
,
timeout
uint32
)
(
*
PipeConn
,
error
)
{
name
,
err
:=
syscall
.
UTF16PtrFromString
(
string
(
address
))
name
,
err
:=
syscall
.
UTF16PtrFromString
(
string
(
address
))
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
// If at least one instance of the pipe has been created, this function
// If at least one instance of the pipe has been created, this function
// will wait timeout milliseconds for it to become available.
// will wait timeout milliseconds for it to become available.
// It will return immediately regardless of timeout, if no instances
// It will return immediately regardless of timeout, if no instances
// of the named pipe have been created yet.
// of the named pipe have been created yet.
// If this returns with no error, there is a pipe available.
// If this returns with no error, there is a pipe available.
if
err
:=
waitNamedPipe
(
name
,
timeout
);
err
!=
nil
{
if
err
:=
waitNamedPipe
(
name
,
timeout
);
err
!=
nil
{
if
err
==
error_bad_pathname
{
if
err
==
error_bad_pathname
{
// badly formatted pipe name
// badly formatted pipe name
return
nil
,
badAddr
(
address
)
return
nil
,
badAddr
(
address
)
}
}
return
nil
,
err
return
nil
,
err
}
}
pathp
,
err
:=
syscall
.
UTF16PtrFromString
(
address
)
pathp
,
err
:=
syscall
.
UTF16PtrFromString
(
address
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
handle
,
err
:=
syscall
.
CreateFile
(
pathp
,
syscall
.
GENERIC_READ
|
syscall
.
GENERIC_WRITE
,
handle
,
err
:=
syscall
.
CreateFile
(
pathp
,
syscall
.
GENERIC_READ
|
syscall
.
GENERIC_WRITE
,
uint32
(
syscall
.
FILE_SHARE_READ
|
syscall
.
FILE_SHARE_WRITE
),
nil
,
syscall
.
OPEN_EXISTING
,
uint32
(
syscall
.
FILE_SHARE_READ
|
syscall
.
FILE_SHARE_WRITE
),
nil
,
syscall
.
OPEN_EXISTING
,
syscall
.
FILE_FLAG_OVERLAPPED
,
0
)
syscall
.
FILE_FLAG_OVERLAPPED
,
0
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
&
PipeConn
{
handle
:
handle
,
addr
:
PipeAddr
(
address
)},
nil
return
&
PipeConn
{
handle
:
handle
,
addr
:
PipeAddr
(
address
)},
nil
}
}
// Listen returns a new PipeListener that will listen on a pipe with the given
// Listen returns a new PipeListener that will listen on a pipe with the given
// address. The address must be of the form \\.\pipe\<name>
// address. The address must be of the form \\.\pipe\<name>
//
//
// Listen will return a PipeError for an incorrectly formatted pipe name.
// Listen will return a PipeError for an incorrectly formatted pipe name.
func
Listen
(
address
string
)
(
*
PipeListener
,
error
)
{
func
Listen
(
address
string
)
(
*
PipeListener
,
error
)
{
handle
,
err
:=
createPipe
(
address
,
true
)
handle
,
err
:=
createPipe
(
address
,
true
)
if
err
==
error_invalid_name
{
if
err
==
error_invalid_name
{
return
nil
,
badAddr
(
address
)
return
nil
,
badAddr
(
address
)
}
}
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
&
PipeListener
{
return
&
PipeListener
{
addr
:
PipeAddr
(
address
),
addr
:
PipeAddr
(
address
),
handle
:
handle
,
handle
:
handle
,
},
nil
},
nil
}
}
// PipeListener is a named pipe listener. Clients should typically
// PipeListener is a named pipe listener. Clients should typically
// use variables of type net.Listener instead of assuming named pipe.
// use variables of type net.Listener instead of assuming named pipe.
type
PipeListener
struct
{
type
PipeListener
struct
{
addr
PipeAddr
addr
PipeAddr
handle
syscall
.
Handle
handle
syscall
.
Handle
closed
bool
closed
bool
// acceptHandle contains the current handle waiting for
// acceptHandle contains the current handle waiting for
// an incoming connection or nil.
// an incoming connection or nil.
acceptHandle
syscall
.
Handle
acceptHandle
syscall
.
Handle
// acceptOverlapped is set before waiting on a connection.
// acceptOverlapped is set before waiting on a connection.
// If not waiting, it is nil.
// If not waiting, it is nil.
acceptOverlapped
*
syscall
.
Overlapped
acceptOverlapped
*
syscall
.
Overlapped
// acceptMutex protects the handle and overlapped structure.
// acceptMutex protects the handle and overlapped structure.
acceptMutex
sync
.
Mutex
acceptMutex
sync
.
Mutex
}
}
// Accept implements the Accept method in the net.Listener interface; it
// Accept implements the Accept method in the net.Listener interface; it
// waits for the next call and returns a generic net.Conn.
// waits for the next call and returns a generic net.Conn.
func
(
l
*
PipeListener
)
Accept
()
(
net
.
Conn
,
error
)
{
func
(
l
*
PipeListener
)
Accept
()
(
net
.
Conn
,
error
)
{
c
,
err
:=
l
.
AcceptPipe
()
c
,
err
:=
l
.
AcceptPipe
()
for
err
==
error_no_data
{
for
err
==
error_no_data
{
// Ignore clients that connect and immediately disconnect.
// Ignore clients that connect and immediately disconnect.
c
,
err
=
l
.
AcceptPipe
()
c
,
err
=
l
.
AcceptPipe
()
}
}
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
c
,
nil
return
c
,
nil
}
}
// AcceptPipe accepts the next incoming call and returns the new connection.
// AcceptPipe accepts the next incoming call and returns the new connection.
// It might return an error if a client connected and immediately cancelled
// It might return an error if a client connected and immediately cancelled
// the connection.
// the connection.
func
(
l
*
PipeListener
)
AcceptPipe
()
(
*
PipeConn
,
error
)
{
func
(
l
*
PipeListener
)
AcceptPipe
()
(
*
PipeConn
,
error
)
{
if
l
==
nil
||
l
.
addr
==
""
||
l
.
closed
{
if
l
==
nil
||
l
.
addr
==
""
||
l
.
closed
{
return
nil
,
syscall
.
EINVAL
return
nil
,
syscall
.
EINVAL
}
}
// the first time we call accept, the handle will have been created by the Listen
// the first time we call accept, the handle will have been created by the Listen
// call. This is to prevent race conditions where the client thinks the server
// call. This is to prevent race conditions where the client thinks the server
// isn't listening because it hasn't actually called create yet. After the first time, we'll
// isn't listening because it hasn't actually called create yet. After the first time, we'll
// have to create a new handle each time
// have to create a new handle each time
handle
:=
l
.
handle
handle
:=
l
.
handle
if
handle
==
0
{
if
handle
==
0
{
var
err
error
var
err
error
handle
,
err
=
createPipe
(
string
(
l
.
addr
),
false
)
handle
,
err
=
createPipe
(
string
(
l
.
addr
),
false
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
}
else
{
}
else
{
l
.
handle
=
0
l
.
handle
=
0
}
}
overlapped
,
err
:=
newOverlapped
()
overlapped
,
err
:=
newOverlapped
()
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
defer
syscall
.
CloseHandle
(
overlapped
.
HEvent
)
defer
syscall
.
CloseHandle
(
overlapped
.
HEvent
)
if
err
:=
connectNamedPipe
(
handle
,
overlapped
);
err
!=
nil
&&
err
!=
error_pipe_connected
{
if
err
:=
connectNamedPipe
(
handle
,
overlapped
);
err
!=
nil
&&
err
!=
error_pipe_connected
{
if
err
==
error_io_incomplete
||
err
==
syscall
.
ERROR_IO_PENDING
{
if
err
==
error_io_incomplete
||
err
==
syscall
.
ERROR_IO_PENDING
{
l
.
acceptMutex
.
Lock
()
l
.
acceptMutex
.
Lock
()
l
.
acceptOverlapped
=
overlapped
l
.
acceptOverlapped
=
overlapped
l
.
acceptHandle
=
handle
l
.
acceptHandle
=
handle
l
.
acceptMutex
.
Unlock
()
l
.
acceptMutex
.
Unlock
()
defer
func
()
{
defer
func
()
{
l
.
acceptMutex
.
Lock
()
l
.
acceptMutex
.
Lock
()
l
.
acceptOverlapped
=
nil
l
.
acceptOverlapped
=
nil
l
.
acceptHandle
=
0
l
.
acceptHandle
=
0
l
.
acceptMutex
.
Unlock
()
l
.
acceptMutex
.
Unlock
()
}()
}()
_
,
err
=
waitForCompletion
(
handle
,
overlapped
)
_
,
err
=
waitForCompletion
(
handle
,
overlapped
)
}
}
if
err
==
syscall
.
ERROR_OPERATION_ABORTED
{
if
err
==
syscall
.
ERROR_OPERATION_ABORTED
{
// Return error compatible to net.Listener.Accept() in case the
// Return error compatible to net.Listener.Accept() in case the
// listener was closed.
// listener was closed.
return
nil
,
ErrClosed
return
nil
,
ErrClosed
}
}
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
}
}
return
&
PipeConn
{
handle
:
handle
,
addr
:
l
.
addr
},
nil
return
&
PipeConn
{
handle
:
handle
,
addr
:
l
.
addr
},
nil
}
}
// Close stops listening on the address.
// Close stops listening on the address.
// Already Accepted connections are not closed.
// Already Accepted connections are not closed.
func
(
l
*
PipeListener
)
Close
()
error
{
func
(
l
*
PipeListener
)
Close
()
error
{
if
l
.
closed
{
if
l
.
closed
{
return
nil
return
nil
}
}
l
.
closed
=
true
l
.
closed
=
true
if
l
.
handle
!=
0
{
if
l
.
handle
!=
0
{
err
:=
disconnectNamedPipe
(
l
.
handle
)
err
:=
disconnectNamedPipe
(
l
.
handle
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
err
=
syscall
.
CloseHandle
(
l
.
handle
)
err
=
syscall
.
CloseHandle
(
l
.
handle
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
l
.
handle
=
0
l
.
handle
=
0
}
}
l
.
acceptMutex
.
Lock
()
l
.
acceptMutex
.
Lock
()
defer
l
.
acceptMutex
.
Unlock
()
defer
l
.
acceptMutex
.
Unlock
()
if
l
.
acceptOverlapped
!=
nil
&&
l
.
acceptHandle
!=
0
{
if
l
.
acceptOverlapped
!=
nil
&&
l
.
acceptHandle
!=
0
{
// Cancel the pending IO. This call does not block, so it is safe
// Cancel the pending IO. This call does not block, so it is safe
// to hold onto the mutex above.
// to hold onto the mutex above.
if
err
:=
cancelIoEx
(
l
.
acceptHandle
,
l
.
acceptOverlapped
);
err
!=
nil
{
if
err
:=
cancelIoEx
(
l
.
acceptHandle
,
l
.
acceptOverlapped
);
err
!=
nil
{
return
err
return
err
}
}
err
:=
syscall
.
CloseHandle
(
l
.
acceptOverlapped
.
HEvent
)
err
:=
syscall
.
CloseHandle
(
l
.
acceptOverlapped
.
HEvent
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
l
.
acceptOverlapped
.
HEvent
=
0
l
.
acceptOverlapped
.
HEvent
=
0
err
=
syscall
.
CloseHandle
(
l
.
acceptHandle
)
err
=
syscall
.
CloseHandle
(
l
.
acceptHandle
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
l
.
acceptHandle
=
0
l
.
acceptHandle
=
0
}
}
return
nil
return
nil
}
}
// Addr returns the listener's network address, a PipeAddr.
// Addr returns the listener's network address, a PipeAddr.
func
(
l
*
PipeListener
)
Addr
()
net
.
Addr
{
return
l
.
addr
}
func
(
l
*
PipeListener
)
Addr
()
net
.
Addr
{
return
l
.
addr
}
// PipeConn is the implementation of the net.Conn interface for named pipe connections.
// PipeConn is the implementation of the net.Conn interface for named pipe connections.
type
PipeConn
struct
{
type
PipeConn
struct
{
handle
syscall
.
Handle
handle
syscall
.
Handle
addr
PipeAddr
addr
PipeAddr
// these aren't actually used yet
// these aren't actually used yet
readDeadline
*
time
.
Time
readDeadline
*
time
.
Time
writeDeadline
*
time
.
Time
writeDeadline
*
time
.
Time
}
}
type
iodata
struct
{
type
iodata
struct
{
n
uint32
n
uint32
err
error
err
error
}
}
// completeRequest looks at iodata to see if a request is pending. If so, it waits for it to either complete or to
// completeRequest looks at iodata to see if a request is pending. If so, it waits for it to either complete or to
// abort due to hitting the specified deadline. Deadline may be set to nil to wait forever. If no request is pending,
// abort due to hitting the specified deadline. Deadline may be set to nil to wait forever. If no request is pending,
// the content of iodata is returned.
// the content of iodata is returned.
func
(
c
*
PipeConn
)
completeRequest
(
data
iodata
,
deadline
*
time
.
Time
,
overlapped
*
syscall
.
Overlapped
)
(
int
,
error
)
{
func
(
c
*
PipeConn
)
completeRequest
(
data
iodata
,
deadline
*
time
.
Time
,
overlapped
*
syscall
.
Overlapped
)
(
int
,
error
)
{
if
data
.
err
==
error_io_incomplete
||
data
.
err
==
syscall
.
ERROR_IO_PENDING
{
if
data
.
err
==
error_io_incomplete
||
data
.
err
==
syscall
.
ERROR_IO_PENDING
{
var
timer
<-
chan
time
.
Time
var
timer
<-
chan
time
.
Time
if
deadline
!=
nil
{
if
deadline
!=
nil
{
if
timeDiff
:=
deadline
.
Sub
(
time
.
Now
());
timeDiff
>
0
{
if
timeDiff
:=
deadline
.
Sub
(
time
.
Now
());
timeDiff
>
0
{
timer
=
time
.
After
(
timeDiff
)
timer
=
time
.
After
(
timeDiff
)
}
}
}
}
done
:=
make
(
chan
iodata
)
done
:=
make
(
chan
iodata
)
go
func
()
{
go
func
()
{
n
,
err
:=
waitForCompletion
(
c
.
handle
,
overlapped
)
n
,
err
:=
waitForCompletion
(
c
.
handle
,
overlapped
)
done
<-
iodata
{
n
,
err
}
done
<-
iodata
{
n
,
err
}
}()
}()
select
{
select
{
case
data
=
<-
done
:
case
data
=
<-
done
:
case
<-
timer
:
case
<-
timer
:
syscall
.
CancelIoEx
(
c
.
handle
,
overlapped
)
syscall
.
CancelIoEx
(
c
.
handle
,
overlapped
)
data
=
iodata
{
0
,
timeout
(
c
.
addr
.
String
())}
data
=
iodata
{
0
,
timeout
(
c
.
addr
.
String
())}
}
}
}
}
// Windows will produce ERROR_BROKEN_PIPE upon closing
// Windows will produce ERROR_BROKEN_PIPE upon closing
// a handle on the other end of a connection. Go RPC
// a handle on the other end of a connection. Go RPC
// expects an io.EOF error in this case.
// expects an io.EOF error in this case.
if
data
.
err
==
syscall
.
ERROR_BROKEN_PIPE
{
if
data
.
err
==
syscall
.
ERROR_BROKEN_PIPE
{
data
.
err
=
io
.
EOF
data
.
err
=
io
.
EOF
}
}
return
int
(
data
.
n
),
data
.
err
return
int
(
data
.
n
),
data
.
err
}
}
// Read implements the net.Conn Read method.
// Read implements the net.Conn Read method.
func
(
c
*
PipeConn
)
Read
(
b
[]
byte
)
(
int
,
error
)
{
func
(
c
*
PipeConn
)
Read
(
b
[]
byte
)
(
int
,
error
)
{
// Use ReadFile() rather than Read() because the latter
// Use ReadFile() rather than Read() because the latter
// contains a workaround that eats ERROR_BROKEN_PIPE.
// contains a workaround that eats ERROR_BROKEN_PIPE.
overlapped
,
err
:=
newOverlapped
()
overlapped
,
err
:=
newOverlapped
()
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
err
return
0
,
err
}
}
defer
syscall
.
CloseHandle
(
overlapped
.
HEvent
)
defer
syscall
.
CloseHandle
(
overlapped
.
HEvent
)
var
n
uint32
var
n
uint32
err
=
syscall
.
ReadFile
(
c
.
handle
,
b
,
&
n
,
overlapped
)
err
=
syscall
.
ReadFile
(
c
.
handle
,
b
,
&
n
,
overlapped
)
return
c
.
completeRequest
(
iodata
{
n
,
err
},
c
.
readDeadline
,
overlapped
)
return
c
.
completeRequest
(
iodata
{
n
,
err
},
c
.
readDeadline
,
overlapped
)
}
}
// Write implements the net.Conn Write method.
// Write implements the net.Conn Write method.
func
(
c
*
PipeConn
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
func
(
c
*
PipeConn
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
overlapped
,
err
:=
newOverlapped
()
overlapped
,
err
:=
newOverlapped
()
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
err
return
0
,
err
}
}
defer
syscall
.
CloseHandle
(
overlapped
.
HEvent
)
defer
syscall
.
CloseHandle
(
overlapped
.
HEvent
)
var
n
uint32
var
n
uint32
err
=
syscall
.
WriteFile
(
c
.
handle
,
b
,
&
n
,
overlapped
)
err
=
syscall
.
WriteFile
(
c
.
handle
,
b
,
&
n
,
overlapped
)
return
c
.
completeRequest
(
iodata
{
n
,
err
},
c
.
writeDeadline
,
overlapped
)
return
c
.
completeRequest
(
iodata
{
n
,
err
},
c
.
writeDeadline
,
overlapped
)
}
}
// Close closes the connection.
// Close closes the connection.
func
(
c
*
PipeConn
)
Close
()
error
{
func
(
c
*
PipeConn
)
Close
()
error
{
return
syscall
.
CloseHandle
(
c
.
handle
)
return
syscall
.
CloseHandle
(
c
.
handle
)
}
}
// LocalAddr returns the local network address.
// LocalAddr returns the local network address.
func
(
c
*
PipeConn
)
LocalAddr
()
net
.
Addr
{
func
(
c
*
PipeConn
)
LocalAddr
()
net
.
Addr
{
return
c
.
addr
return
c
.
addr
}
}
// RemoteAddr returns the remote network address.
// RemoteAddr returns the remote network address.
func
(
c
*
PipeConn
)
RemoteAddr
()
net
.
Addr
{
func
(
c
*
PipeConn
)
RemoteAddr
()
net
.
Addr
{
// not sure what to do here, we don't have remote addr....
// not sure what to do here, we don't have remote addr....
return
c
.
addr
return
c
.
addr
}
}
// SetDeadline implements the net.Conn SetDeadline method.
// SetDeadline implements the net.Conn SetDeadline method.
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
func
(
c
*
PipeConn
)
SetDeadline
(
t
time
.
Time
)
error
{
func
(
c
*
PipeConn
)
SetDeadline
(
t
time
.
Time
)
error
{
c
.
SetReadDeadline
(
t
)
c
.
SetReadDeadline
(
t
)
c
.
SetWriteDeadline
(
t
)
c
.
SetWriteDeadline
(
t
)
return
nil
return
nil
}
}
// SetReadDeadline implements the net.Conn SetReadDeadline method.
// SetReadDeadline implements the net.Conn SetReadDeadline method.
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
func
(
c
*
PipeConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
func
(
c
*
PipeConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
c
.
readDeadline
=
&
t
c
.
readDeadline
=
&
t
return
nil
return
nil
}
}
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
// Note that timeouts are only supported on Windows Vista/Server 2008 and above
func
(
c
*
PipeConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
func
(
c
*
PipeConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
c
.
writeDeadline
=
&
t
c
.
writeDeadline
=
&
t
return
nil
return
nil
}
}
// PipeAddr represents the address of a named pipe.
// PipeAddr represents the address of a named pipe.
type
PipeAddr
string
type
PipeAddr
string
// Network returns the address's network name, "pipe".
// Network returns the address's network name, "pipe".
func
(
a
PipeAddr
)
Network
()
string
{
return
"pipe"
}
func
(
a
PipeAddr
)
Network
()
string
{
return
"pipe"
}
// String returns the address of the pipe
// String returns the address of the pipe
func
(
a
PipeAddr
)
String
()
string
{
func
(
a
PipeAddr
)
String
()
string
{
return
string
(
a
)
return
string
(
a
)
}
}
// createPipe is a helper function to make sure we always create pipes
// createPipe is a helper function to make sure we always create pipes
// with the same arguments, since subsequent calls to create pipe need
// with the same arguments, since subsequent calls to create pipe need
// to use the same arguments as the first one. If first is set, fail
// to use the same arguments as the first one. If first is set, fail
// if the pipe already exists.
// if the pipe already exists.
func
createPipe
(
address
string
,
first
bool
)
(
syscall
.
Handle
,
error
)
{
func
createPipe
(
address
string
,
first
bool
)
(
syscall
.
Handle
,
error
)
{
n
,
err
:=
syscall
.
UTF16PtrFromString
(
address
)
n
,
err
:=
syscall
.
UTF16PtrFromString
(
address
)
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
err
return
0
,
err
}
}
mode
:=
uint32
(
pipe_access_duplex
|
syscall
.
FILE_FLAG_OVERLAPPED
)
mode
:=
uint32
(
pipe_access_duplex
|
syscall
.
FILE_FLAG_OVERLAPPED
)
if
first
{
if
first
{
mode
|=
file_flag_first_pipe_instance
mode
|=
file_flag_first_pipe_instance
}
}
return
createNamedPipe
(
n
,
return
createNamedPipe
(
n
,
mode
,
mode
,
pipe_type_byte
,
pipe_type_byte
,
pipe_unlimited_instances
,
pipe_unlimited_instances
,
512
,
512
,
0
,
nil
)
512
,
512
,
0
,
nil
)
}
}
func
badAddr
(
addr
string
)
PipeError
{
func
badAddr
(
addr
string
)
PipeError
{
return
PipeError
{
fmt
.
Sprintf
(
"Invalid pipe address '%s'."
,
addr
),
false
}
return
PipeError
{
fmt
.
Sprintf
(
"Invalid pipe address '%s'."
,
addr
),
false
}
}
}
func
timeout
(
addr
string
)
PipeError
{
func
timeout
(
addr
string
)
PipeError
{
return
PipeError
{
fmt
.
Sprintf
(
"Pipe IO timed out waiting for '%s'"
,
addr
),
true
}
return
PipeError
{
fmt
.
Sprintf
(
"Pipe IO timed out waiting for '%s'"
,
addr
),
true
}
}
}
func
newIpcClient
(
cfg
IpcConfig
,
codec
codec
.
Codec
)
(
*
ipcClient
,
error
)
{
c
,
err
:=
Dial
(
cfg
.
Endpoint
)
if
err
!=
nil
{
func
newIpcClient
(
cfg
IpcConfig
,
codec
codec
.
Codec
)
(
*
ipcClient
,
error
)
{
return
nil
,
err
c
,
err
:=
Dial
(
cfg
.
Endpoint
)
}
if
err
!=
nil
{
return
nil
,
err
return
&
ipcClient
{
codec
.
New
(
c
)},
nil
}
}
return
&
ipcClient
{
codec
.
New
(
c
)},
nil
func
startIpc
(
cfg
IpcConfig
,
codec
codec
.
Codec
,
api
api
.
EthereumApi
)
error
{
}
os
.
Remove
(
cfg
.
Endpoint
)
// in case it still exists from a previous run
func
startIpc
(
cfg
IpcConfig
,
codec
codec
.
Codec
,
api
api
.
EthereumApi
)
error
{
l
,
err
:=
Listen
(
cfg
.
Endpoint
)
os
.
Remove
(
cfg
.
Endpoint
)
// in case it still exists from a previous run
if
err
!=
nil
{
return
err
l
,
err
:=
Listen
(
cfg
.
Endpoint
)
}
if
err
!=
nil
{
os
.
Chmod
(
cfg
.
Endpoint
,
0600
)
return
err
}
go
func
()
{
os
.
Chmod
(
cfg
.
Endpoint
,
0600
)
for
{
conn
,
err
:=
l
.
Accept
()
go
func
()
{
if
err
!=
nil
{
for
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Error accepting ipc connection - %v
\n
"
,
err
)
conn
,
err
:=
l
.
Accept
()
continue
if
err
!=
nil
{
}
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Error accepting ipc connection - %v
\n
"
,
err
)
continue
go
func
(
conn
net
.
Conn
)
{
}
codec
:=
codec
.
New
(
conn
)
go
func
(
conn
net
.
Conn
)
{
for
{
codec
:=
codec
.
New
(
conn
)
req
,
err
:=
codec
.
ReadRequest
()
if
err
==
io
.
EOF
{
for
{
codec
.
Close
()
req
,
err
:=
codec
.
ReadRequest
()
return
if
err
==
io
.
EOF
{
}
else
if
err
!=
nil
{
codec
.
Close
()
glog
.
V
(
logger
.
Error
)
.
Infof
(
"IPC recv err - %v
\n
"
,
err
)
return
codec
.
Close
()
}
else
if
err
!=
nil
{
return
glog
.
V
(
logger
.
Error
)
.
Infof
(
"IPC recv err - %v
\n
"
,
err
)
}
codec
.
Close
()
return
var
rpcResponse
interface
{}
}
res
,
err
:=
api
.
Execute
(
req
)
var
rpcResponse
interface
{}
rpcResponse
=
shared
.
NewRpcResponse
(
req
.
Id
,
req
.
Jsonrpc
,
res
,
err
)
res
,
err
:=
api
.
Execute
(
req
)
err
=
codec
.
WriteResponse
(
rpcResponse
)
if
err
!=
nil
{
rpcResponse
=
shared
.
NewRpcResponse
(
req
.
Id
,
req
.
Jsonrpc
,
res
,
err
)
glog
.
V
(
logger
.
Error
)
.
Infof
(
"IPC send err - %v
\n
"
,
err
)
err
=
codec
.
WriteResponse
(
rpcResponse
)
codec
.
Close
()
if
err
!=
nil
{
return
glog
.
V
(
logger
.
Error
)
.
Infof
(
"IPC send err - %v
\n
"
,
err
)
}
codec
.
Close
()
}
return
}(
conn
)
}
}
}
}()
}(
conn
)
}
glog
.
V
(
logger
.
Info
)
.
Infof
(
"IPC service started (%s)
\n
"
,
cfg
.
Endpoint
)
}()
return
nil
glog
.
V
(
logger
.
Info
)
.
Infof
(
"IPC service started (%s)
\n
"
,
cfg
.
Endpoint
)
}
return
nil
}
rpc/jeth.go
View file @
09d0d55f
...
@@ -4,12 +4,13 @@ import (
...
@@ -4,12 +4,13 @@ import (
"encoding/json"
"encoding/json"
"fmt"
"fmt"
"reflect"
"github.com/ethereum/go-ethereum/jsre"
"github.com/ethereum/go-ethereum/jsre"
"github.com/robertkrimen/otto"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/rpc/shared"
"github.com/ethereum/go-ethereum/rpc/shared"
"
reflect
"
"
github.com/robertkrimen/otto
"
)
)
type
Jeth
struct
{
type
Jeth
struct
{
...
...
rpc/shared/types.go
View file @
09d0d55f
...
@@ -2,6 +2,7 @@ package shared
...
@@ -2,6 +2,7 @@ package shared
import
(
import
(
"encoding/json"
"encoding/json"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/logger/glog"
)
)
...
@@ -45,15 +46,15 @@ func NewRpcResponse(id interface{}, jsonrpcver string, reply interface{}, err er
...
@@ -45,15 +46,15 @@ func NewRpcResponse(id interface{}, jsonrpcver string, reply interface{}, err er
var
response
interface
{}
var
response
interface
{}
switch
err
.
(
type
)
{
switch
err
.
(
type
)
{
case
nil
:
case
nil
:
response
=
&
SuccessResponse
{
Jsonrpc
:
jsonrpcver
,
Id
:
id
,
Result
:
reply
}
response
=
&
SuccessResponse
{
Jsonrpc
:
jsonrpcver
,
Id
:
id
,
Result
:
reply
}
case
*
NotImplementedError
:
case
*
NotImplementedError
:
jsonerr
:=
&
ErrorObject
{
-
32601
,
err
.
Error
()}
jsonerr
:=
&
ErrorObject
{
-
32601
,
err
.
Error
()}
response
=
&
ErrorResponse
{
Jsonrpc
:
jsonrpcver
,
Id
:
id
,
Error
:
jsonerr
}
response
=
&
ErrorResponse
{
Jsonrpc
:
jsonrpcver
,
Id
:
id
,
Error
:
jsonerr
}
case
*
DecodeParamError
,
*
InsufficientParamsError
,
*
ValidationError
,
*
InvalidTypeError
:
case
*
DecodeParamError
,
*
InsufficientParamsError
,
*
ValidationError
,
*
InvalidTypeError
:
jsonerr
:=
&
ErrorObject
{
-
32602
,
err
.
Error
()}
jsonerr
:=
&
ErrorObject
{
-
32602
,
err
.
Error
()}
response
=
&
ErrorResponse
{
Jsonrpc
:
jsonrpcver
,
Id
:
id
,
Error
:
jsonerr
}
response
=
&
ErrorResponse
{
Jsonrpc
:
jsonrpcver
,
Id
:
id
,
Error
:
jsonerr
}
default
:
default
:
jsonerr
:=
&
ErrorObject
{
-
32603
,
err
.
Error
()}
jsonerr
:=
&
ErrorObject
{
-
32603
,
err
.
Error
()}
response
=
&
ErrorResponse
{
Jsonrpc
:
jsonrpcver
,
Id
:
id
,
Error
:
jsonerr
}
response
=
&
ErrorResponse
{
Jsonrpc
:
jsonrpcver
,
Id
:
id
,
Error
:
jsonerr
}
}
}
...
...
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