commit
c5b37391ed
17
README.md
17
README.md
|
@ -45,30 +45,16 @@ The ingester is a modular component. Anything that can retrieve the necessary da
|
|||
|
||||
First, install [Go >= 1.11](https://golang.org/dl/#stable). Older versions of Go may work but are not actively supported at this time. Note that the version of Go packaged by Debian stable (or anything prior to Buster) is far too old to work.
|
||||
|
||||
Next, install the ZMQ development library. On Debian-derived distros, this is called `libzmq3-dev`.
|
||||
|
||||
Next, configure your zcashd instance to publish blocks on a ZMQ stream:
|
||||
|
||||
```
|
||||
$ echo "zmqpubcheckedblock=tcp://127.0.0.1:28332" >> $HOME/.zcash/zcashd.conf
|
||||
```
|
||||
|
||||
Now clone this repo and start the ingester. The first run will start slow as Go builds the sqlite C interface:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/zcash-hackworks/lightwalletd
|
||||
$ cd lightwalletd
|
||||
$ go run cmd/ingest/main.go --db-path <path to sqlite db> --zmq-addr 127.0.0.1:28332
|
||||
$ go run cmd/ingest/main.go --conf-file <path_to_zcash.conf> --db-path <path_to_sqllightdb>
|
||||
```
|
||||
|
||||
To see the other command line options, run `go run cmd/ingest/main.go --help`.
|
||||
|
||||
To begin building a compact block database, run your zcashd with the `--reindex` option. This will cause zcashd to recheck all of the blocks it knows about and emit them on the newly configured ZMQ stream for the ingester to read. This is the part of the process that takes a long time.
|
||||
|
||||
**What should I watch out for?**
|
||||
|
||||
Because of how ZMQ works in the zcashd codebase, the ingester doesn't have the ability to retry any blocks it misses without doing a complete reindexing. For now this means that we only recommend running this setup with a completely reliable connection between zcashd and the ingester. So while ZMQ certainly can publish over arbitrary TCP connections, rather than localhost, doing so risks wasting a lot of your time if the connection hiccups.
|
||||
|
||||
## Frontend
|
||||
|
||||
The frontend is the component that talks to clients.
|
||||
|
@ -148,7 +134,6 @@ certbot certonly --standalone --preferred-challenges http -d some.forward.dns.co
|
|||
The first-order dependencies of this code are:
|
||||
|
||||
- Go (>= 1.11 suggested; older versions are currently unsupported)
|
||||
- libzmq3-dev (used by our zmq interface library; optional if ingester changes)
|
||||
- libsqlite3-dev (used by our sqlite interface library; optional with another datastore)
|
||||
|
||||
**Containers**
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
`# apt-get install libzmq3-dev`
|
||||
|
||||
`$ go get github.com/pebbe/zmq4`
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/golang/protobuf/proto"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
zmq "github.com/pebbe/zmq4"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/zcash-hackworks/lightwalletd/frontend"
|
||||
"github.com/zcash-hackworks/lightwalletd/parser"
|
||||
"github.com/zcash-hackworks/lightwalletd/storage"
|
||||
)
|
||||
|
@ -22,20 +27,18 @@ var logger = logrus.New()
|
|||
var db *sql.DB
|
||||
|
||||
type Options struct {
|
||||
zmqAddr string
|
||||
zmqTopic string
|
||||
dbPath string
|
||||
logLevel uint64
|
||||
logPath string
|
||||
zcashConfPath string
|
||||
}
|
||||
|
||||
func main() {
|
||||
opts := &Options{}
|
||||
flag.StringVar(&opts.zmqAddr, "zmq-addr", "127.0.0.1:28332", "the address of the 0MQ publisher")
|
||||
flag.StringVar(&opts.zmqTopic, "zmq-topic", "checkedblock", "the stream to listen to")
|
||||
flag.StringVar(&opts.dbPath, "db-path", "", "the path to a sqlite database file")
|
||||
flag.Uint64Var(&opts.logLevel, "log-level", uint64(logrus.InfoLevel), "log level (logrus 1-7)")
|
||||
flag.StringVar(&opts.logPath, "log-file", "", "log file to write to")
|
||||
flag.StringVar(&opts.zcashConfPath, "conf-file", "", "conf file to pull RPC creds from")
|
||||
// TODO prod metrics
|
||||
// TODO support config from file and env vars
|
||||
flag.Parse()
|
||||
|
@ -69,7 +72,7 @@ func main() {
|
|||
logger.SetLevel(logrus.Level(opts.logLevel))
|
||||
|
||||
log = logger.WithFields(logrus.Fields{
|
||||
"app": "zmqclient",
|
||||
"app": "lightwalletd",
|
||||
})
|
||||
|
||||
// Initialize database
|
||||
|
@ -90,117 +93,157 @@ func main() {
|
|||
}).Fatal("couldn't create SQL tables")
|
||||
}
|
||||
|
||||
// Initialize ZMQ
|
||||
ctx, err := zmq.NewContext()
|
||||
//Initialize RPC connection with full node zcashd
|
||||
rpcClient, err := frontend.NewZRPCFromConf(opts.zcashConfPath)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("couldn't create zmq context")
|
||||
}
|
||||
defer ctx.Term()
|
||||
}).Warn("zcash.conf failed, will try empty credentials for rpc")
|
||||
|
||||
// WARNING: The Socket is not thread safe. This means that you cannot
|
||||
// access the same Socket from different goroutines without using something
|
||||
// like a mutex.
|
||||
sock, err := ctx.NewSocket(zmq.SUB)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("couldn't create zmq context socket")
|
||||
}
|
||||
//Default to testnet, but user MUST specify rpcuser and rpcpassword in zcash.conf; no default
|
||||
rpcClient, err = frontend.NewZRPCFromCreds("127.0.0.1:18232", "", "")
|
||||
|
||||
err = sock.SetSubscribe(opts.zmqTopic)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"stream": opts.zmqTopic,
|
||||
}).Fatal("couldn't subscribe to stream")
|
||||
}
|
||||
|
||||
connString := fmt.Sprintf("tcp://%s", opts.zmqAddr)
|
||||
|
||||
err = sock.Connect(connString)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"connection": connString,
|
||||
}).Fatal("couldn't connect to socket")
|
||||
}
|
||||
defer sock.Close()
|
||||
|
||||
log.Printf("Listening to 0mq on %s", opts.zmqAddr)
|
||||
|
||||
// Start listening for new blocks
|
||||
for {
|
||||
msg, err := sock.RecvMessageBytes(0)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Error("error on msg recv")
|
||||
continue
|
||||
}).Fatal("couldn't start rpc connection")
|
||||
}
|
||||
}
|
||||
|
||||
if len(msg) < 3 {
|
||||
ctx := context.Background()
|
||||
height, err := storage.GetCurrentHeight(ctx, db)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Warn("unable to get current height from local db storage")
|
||||
height = 0
|
||||
}
|
||||
|
||||
|
||||
//ingest from Sapling testnet height
|
||||
if height < 280000 {
|
||||
height = 280000
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Warn("invalid current height read from local db storage")
|
||||
}
|
||||
|
||||
timeout_count := 0
|
||||
reorg_count := -1
|
||||
hash := ""
|
||||
phash := ""
|
||||
// Start listening for new blocks
|
||||
for {
|
||||
if reorg_count > 0 {
|
||||
reorg_count = -1
|
||||
height -= 11
|
||||
}
|
||||
block, err := getBlock(rpcClient, height)
|
||||
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"msg": msg,
|
||||
}).Warn("got unknown message type")
|
||||
continue
|
||||
"height": height,
|
||||
"error": err,
|
||||
}).Warn("error with getblock")
|
||||
timeout_count++
|
||||
if timeout_count == 3 {
|
||||
log.WithFields(logrus.Fields{
|
||||
"timeouts": timeout_count,
|
||||
}).Warn("unable to issue RPC call to zcashd node 3 times")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
topic, body := msg[0], msg[1]
|
||||
|
||||
var sequence int
|
||||
if len(msg[2]) == 4 {
|
||||
sequence = int(binary.LittleEndian.Uint32(msg[len(msg)-1]))
|
||||
}
|
||||
|
||||
switch string(topic) {
|
||||
|
||||
case opts.zmqTopic:
|
||||
handleBlock(db, sequence, body)
|
||||
|
||||
default:
|
||||
log.WithFields(logrus.Fields{
|
||||
"seqnum": sequence,
|
||||
"topic": topic,
|
||||
}).Warn("got message with unknown topic")
|
||||
if block != nil {
|
||||
handleBlock(db, block)
|
||||
if timeout_count > 0 {
|
||||
timeout_count--
|
||||
}
|
||||
phash = hex.EncodeToString(block.GetPrevHash())
|
||||
//check for reorgs once we have inital block hash from startup
|
||||
if hash != phash && reorg_count != -1 {
|
||||
reorg_count++
|
||||
log.WithFields(logrus.Fields{
|
||||
"height": height,
|
||||
"hash": hash,
|
||||
"phash": phash,
|
||||
"reorg": reorg_count,
|
||||
}).Warn("REORG")
|
||||
} else {
|
||||
hash = hex.EncodeToString(block.GetDisplayHash())
|
||||
}
|
||||
if reorg_count == -1 {
|
||||
hash = hex.EncodeToString(block.GetDisplayHash())
|
||||
reorg_count =0
|
||||
}
|
||||
height++
|
||||
} else {
|
||||
//TODO implement blocknotify to minimize polling on corner cases
|
||||
time.Sleep(60 * time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleBlock(db *sql.DB, sequence int, blockData []byte) {
|
||||
func getBlock(rpcClient *rpcclient.Client, height int) (*parser.Block, error) {
|
||||
params := make([]json.RawMessage, 2)
|
||||
params[0] = json.RawMessage("\"" + strconv.Itoa(height) + "\"")
|
||||
params[1] = json.RawMessage("0")
|
||||
result, rpcErr := rpcClient.RawRequest("getblock", params)
|
||||
|
||||
var err error
|
||||
var errCode int64
|
||||
|
||||
// For some reason, the error responses are not JSON
|
||||
if rpcErr != nil {
|
||||
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
|
||||
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
|
||||
//Check to see if we are requesting a height the zcashd doesn't have yet
|
||||
if err == nil && errCode == -8 {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.Wrap(rpcErr, "error requesting block")
|
||||
}
|
||||
|
||||
var blockDataHex string
|
||||
err = json.Unmarshal(result, &blockDataHex)
|
||||
if err != nil{
|
||||
return nil, errors.Wrap(err, "error reading JSON response")
|
||||
}
|
||||
|
||||
blockData, err := hex.DecodeString(blockDataHex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error decoding getblock output")
|
||||
}
|
||||
|
||||
block := parser.NewBlock()
|
||||
rest, err := block.ParseFromSlice(blockData)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"seqnum": sequence,
|
||||
"error": err,
|
||||
}).Error("error parsing block")
|
||||
return
|
||||
return nil, errors.Wrap(err, "error parsing block")
|
||||
}
|
||||
if len(rest) != 0 {
|
||||
log.WithFields(logrus.Fields{
|
||||
"seqnum": sequence,
|
||||
"length": len(rest),
|
||||
}).Warn("received overlong message")
|
||||
return
|
||||
return nil, errors.New("received overlong message")
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
|
||||
func handleBlock(db *sql.DB, block *parser.Block) {
|
||||
prevBlockHash := hex.EncodeToString(block.GetPrevHash())
|
||||
blockHash := hex.EncodeToString(block.GetEncodableHash())
|
||||
marshaledBlock, _ := proto.Marshal(block.ToCompact())
|
||||
|
||||
err = storage.StoreBlock(
|
||||
|
||||
err := storage.StoreBlock(
|
||||
db,
|
||||
block.GetHeight(),
|
||||
prevBlockHash,
|
||||
blockHash,
|
||||
block.HasSaplingTransactions(),
|
||||
marshaledBlock,
|
||||
)
|
||||
|
||||
entry := log.WithFields(logrus.Fields{
|
||||
"seqnum": sequence,
|
||||
"block_height": block.GetHeight(),
|
||||
"block_hash": hex.EncodeToString(block.GetDisplayHash()),
|
||||
"prev_hash": hex.EncodeToString(block.GetDisplayPrevHash()),
|
||||
"block_version": block.GetVersion(),
|
||||
"tx_count": block.GetTxCount(),
|
||||
"sapling": block.HasSaplingTransactions(),
|
||||
|
|
1
go.mod
1
go.mod
|
@ -8,7 +8,6 @@ require (
|
|||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
|
||||
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
||||
github.com/mattn/go-sqlite3 v1.10.0
|
||||
github.com/pebbe/zmq4 v1.0.0
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/sirupsen/logrus v1.2.0
|
||||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -40,8 +40,6 @@ github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO
|
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pebbe/zmq4 v1.0.0 h1:D+MSmPpqkL5PSSmnh8g51ogirUCyemThuZzLW7Nrt78=
|
||||
github.com/pebbe/zmq4 v1.0.0/go.mod h1:7N4y5R18zBiu3l0vajMUWQgZyjv464prE8RCyBcmnZM=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
|
|
@ -8,42 +8,52 @@ import (
|
|||
"github.com/zcash-hackworks/lightwalletd/walletrpc"
|
||||
)
|
||||
|
||||
type block struct {
|
||||
type Block struct {
|
||||
hdr *blockHeader
|
||||
vtx []*Transaction
|
||||
height int
|
||||
}
|
||||
|
||||
func NewBlock() *block {
|
||||
return &block{height: -1}
|
||||
func NewBlock() *Block {
|
||||
return &Block{height: -1}
|
||||
}
|
||||
|
||||
func (b *block) GetVersion() int {
|
||||
func (b *Block) GetVersion() int {
|
||||
return int(b.hdr.Version)
|
||||
}
|
||||
|
||||
func (b *block) GetTxCount() int {
|
||||
func (b *Block) GetTxCount() int {
|
||||
return len(b.vtx)
|
||||
}
|
||||
|
||||
func (b *block) Transactions() []*Transaction {
|
||||
func (b *Block) Transactions() []*Transaction {
|
||||
// TODO: these should NOT be mutable
|
||||
return b.vtx
|
||||
}
|
||||
|
||||
// GetDisplayHash returns the block hash in big-endian display order.
|
||||
func (b *block) GetDisplayHash() []byte {
|
||||
func (b *Block) GetDisplayHash() []byte {
|
||||
return b.hdr.GetDisplayHash()
|
||||
}
|
||||
|
||||
// TODO: encode hash endianness in a type?
|
||||
|
||||
// GetEncodableHash returns the block hash in little-endian wire order.
|
||||
func (b *block) GetEncodableHash() []byte {
|
||||
func (b *Block) GetEncodableHash() []byte {
|
||||
return b.hdr.GetEncodableHash()
|
||||
}
|
||||
|
||||
func (b *block) HasSaplingTransactions() bool {
|
||||
func (b *Block) GetDisplayPrevHash() []byte {
|
||||
h := b.hdr.HashPrevBlock
|
||||
// Reverse byte order
|
||||
for i := 0; i < len(h)/2; i++ {
|
||||
j := len(h) - 1 - i
|
||||
h[i], h[j] = h[j], h[i]
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func (b *Block) HasSaplingTransactions() bool {
|
||||
for _, tx := range b.vtx {
|
||||
if tx.HasSaplingTransactions() {
|
||||
return true
|
||||
|
@ -57,7 +67,7 @@ const genesisTargetDifficulty = 520617983
|
|||
|
||||
// GetHeight() extracts the block height from the coinbase transaction. See
|
||||
// BIP34. Returns block height on success, or -1 on error.
|
||||
func (b *block) GetHeight() int {
|
||||
func (b *Block) GetHeight() int {
|
||||
if b.height != -1 {
|
||||
return b.height
|
||||
}
|
||||
|
@ -83,12 +93,16 @@ func (b *block) GetHeight() int {
|
|||
return int(blockHeight)
|
||||
}
|
||||
|
||||
func (b *block) ToCompact() *walletrpc.CompactBlock {
|
||||
func (b *Block) GetPrevHash() []byte {
|
||||
return b.hdr.HashPrevBlock
|
||||
}
|
||||
|
||||
func (b *Block) ToCompact() *walletrpc.CompactBlock {
|
||||
compactBlock := &walletrpc.CompactBlock{
|
||||
//TODO ProtoVersion: 1,
|
||||
Height: uint64(b.GetHeight()),
|
||||
Hash: b.GetEncodableHash(),
|
||||
PrevHash: b.hdr.HashPrevBlock,
|
||||
Hash: b.GetEncodableHash(),
|
||||
Time: b.hdr.Time,
|
||||
}
|
||||
|
||||
|
@ -103,7 +117,7 @@ func (b *block) ToCompact() *walletrpc.CompactBlock {
|
|||
return compactBlock
|
||||
}
|
||||
|
||||
func (b *block) ParseFromSlice(data []byte) (rest []byte, err error) {
|
||||
func (b *Block) ParseFromSlice(data []byte) (rest []byte, err error) {
|
||||
hdr := NewBlockHeader()
|
||||
data, err = hdr.ParseFromSlice(data)
|
||||
if err != nil {
|
||||
|
|
|
@ -28,6 +28,7 @@ func CreateTables(conn *sql.DB) error {
|
|||
blockTable := `
|
||||
CREATE TABLE IF NOT EXISTS blocks (
|
||||
block_height INTEGER PRIMARY KEY,
|
||||
prev_hash TEXT,
|
||||
block_hash TEXT,
|
||||
sapling BOOL,
|
||||
compact_encoding BLOB
|
||||
|
@ -121,15 +122,15 @@ func GetBlockRange(ctx context.Context, db *sql.DB, blockOut chan<- []byte, errO
|
|||
errOut <- nil
|
||||
}
|
||||
|
||||
func StoreBlock(conn *sql.DB, height int, hash string, sapling bool, encoded []byte) error {
|
||||
insertBlock := "REPLACE INTO blocks (block_height, block_hash, sapling, compact_encoding) values (?, ?, ?, ?)"
|
||||
func StoreBlock(conn *sql.DB, height int, prev_hash string, hash string, sapling bool, encoded []byte) error {
|
||||
insertBlock := "REPLACE INTO blocks (block_height, prev_hash, block_hash, sapling, compact_encoding) values ( ?, ?, ?, ?, ?)"
|
||||
|
||||
tx, err := conn.Begin()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("creating db tx %d", height))
|
||||
}
|
||||
|
||||
_, err = tx.Exec(insertBlock, height, hash, sapling, encoded)
|
||||
_, err = tx.Exec(insertBlock, height, prev_hash, hash, sapling, encoded)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("storing compact block %d", height))
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2013-2014, Peter Kleiweg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,75 +0,0 @@
|
|||
A Go interface to [ZeroMQ](http://www.zeromq.org/) version 4.
|
||||
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/pebbe/zmq4)](https://goreportcard.com/report/github.com/pebbe/zmq4)
|
||||
[![GoDoc](https://godoc.org/github.com/pebbe/zmq4?status.svg)](https://godoc.org/github.com/pebbe/zmq4)
|
||||
|
||||
This requires ZeroMQ version 4.0.1 or above. To use CURVE security in
|
||||
versions prior to 4.2, ZeroMQ must be installed with
|
||||
[libsodium](https://github.com/jedisct1/libsodium) enabled.
|
||||
|
||||
Partial support for ZeroMQ 4.2 DRAFT is available in the alternate
|
||||
version of zmq4 `draft`. The API pertaining to this is subject to
|
||||
change. To use this:
|
||||
|
||||
import (
|
||||
zmq "github.com/pebbe/zmq4/draft"
|
||||
)
|
||||
|
||||
For ZeroMQ version 3, see: http://github.com/pebbe/zmq3
|
||||
|
||||
For ZeroMQ version 2, see: http://github.com/pebbe/zmq2
|
||||
|
||||
Including all examples of [ØMQ - The Guide](http://zguide.zeromq.org/page:all).
|
||||
|
||||
Keywords: zmq, zeromq, 0mq, networks, distributed computing, message passing, fanout, pubsub, pipeline, request-reply
|
||||
|
||||
### See also
|
||||
|
||||
* [Mangos](https://github.com/go-mangos/mangos) — An implementation in pure Go of the SP ("Scalable Protocols") protocols
|
||||
* [go-nanomsg](https://github.com/op/go-nanomsg) — Language bindings for nanomsg in Go
|
||||
* [goczmq](https://github.com/zeromq/goczmq) — A Go interface to CZMQ
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/pebbe/zmq4
|
||||
|
||||
## Docs
|
||||
|
||||
* [package help](http://godoc.org/github.com/pebbe/zmq4)
|
||||
* [wiki](https://github.com/pebbe/zmq4/wiki)
|
||||
|
||||
## API change
|
||||
|
||||
There has been an API change in commit
|
||||
0bc5ab465849847b0556295d9a2023295c4d169e of 2014-06-27, 10:17:55 UTC
|
||||
in the functions `AuthAllow` and `AuthDeny`.
|
||||
|
||||
Old:
|
||||
|
||||
func AuthAllow(addresses ...string)
|
||||
func AuthDeny(addresses ...string)
|
||||
|
||||
New:
|
||||
|
||||
func AuthAllow(domain string, addresses ...string)
|
||||
func AuthDeny(domain string, addresses ...string)
|
||||
|
||||
If `domain` can be parsed as an IP address, it will be interpreted as
|
||||
such, and it and all remaining addresses are added to all domains.
|
||||
|
||||
So this should still work as before:
|
||||
|
||||
zmq.AuthAllow("127.0.0.1", "123.123.123.123")
|
||||
|
||||
But this won't compile:
|
||||
|
||||
a := []string{"127.0.0.1", "123.123.123.123"}
|
||||
zmq.AuthAllow(a...)
|
||||
|
||||
And needs to be rewritten as:
|
||||
|
||||
a := []string{"127.0.0.1", "123.123.123.123"}
|
||||
zmq.AuthAllow("*", a...)
|
||||
|
||||
Furthermore, an address can now be a single IP address, as well as an IP
|
||||
address and mask in CIDR notation, e.g. "123.123.123.0/24".
|
|
@ -1,645 +0,0 @@
|
|||
/*
|
||||
|
||||
This file implements functionality very similar to that of the xauth module in czmq.
|
||||
|
||||
Notable differences in here:
|
||||
|
||||
- domains are supported
|
||||
- domains are used in AuthAllow and AuthDeny too
|
||||
- usernames/passwords are read from memory, not from file
|
||||
- public keys are read from memory, not from file
|
||||
- an address can be a single IP address, or an IP address and mask in CIDR notation
|
||||
- additional functions for configuring server or client socket with a single command
|
||||
|
||||
*/
|
||||
|
||||
package zmq4
|
||||
|
||||
/*
|
||||
#include <zmq.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if ZMQ_VERSION_MINOR < 2
|
||||
// Version < 4.2.x
|
||||
|
||||
int zmq_curve_public (char *z85_public_key, const char *z85_secret_key) { return 0; }
|
||||
|
||||
#endif // Version < 4.2.x
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const CURVE_ALLOW_ANY = "*"
|
||||
|
||||
var (
|
||||
auth_handler *Socket
|
||||
auth_quit *Socket
|
||||
|
||||
auth_init = false
|
||||
auth_verbose = false
|
||||
|
||||
auth_allow = make(map[string]map[string]bool)
|
||||
auth_deny = make(map[string]map[string]bool)
|
||||
auth_allow_net = make(map[string][]*net.IPNet)
|
||||
auth_deny_net = make(map[string][]*net.IPNet)
|
||||
|
||||
auth_users = make(map[string]map[string]string)
|
||||
|
||||
auth_pubkeys = make(map[string]map[string]bool)
|
||||
|
||||
auth_meta_handler = auth_meta_handler_default
|
||||
)
|
||||
|
||||
func auth_meta_handler_default(version, request_id, domain, address, identity, mechanism string, credentials ...string) (metadata map[string]string) {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func auth_isIP(addr string) bool {
|
||||
if net.ParseIP(addr) != nil {
|
||||
return true
|
||||
}
|
||||
if _, _, err := net.ParseCIDR(addr); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func auth_is_allowed(domain, address string) bool {
|
||||
for _, d := range []string{domain, "*"} {
|
||||
if a, ok := auth_allow[d]; ok {
|
||||
if a[address] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
addr := net.ParseIP(address)
|
||||
if addr != nil {
|
||||
for _, d := range []string{domain, "*"} {
|
||||
if a, ok := auth_allow_net[d]; ok {
|
||||
for _, m := range a {
|
||||
if m.Contains(addr) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func auth_is_denied(domain, address string) bool {
|
||||
for _, d := range []string{domain, "*"} {
|
||||
if a, ok := auth_deny[d]; ok {
|
||||
if a[address] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
addr := net.ParseIP(address)
|
||||
if addr != nil {
|
||||
for _, d := range []string{domain, "*"} {
|
||||
if a, ok := auth_deny_net[d]; ok {
|
||||
for _, m := range a {
|
||||
if m.Contains(addr) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func auth_has_allow(domain string) bool {
|
||||
for _, d := range []string{domain, "*"} {
|
||||
if a, ok := auth_allow[d]; ok {
|
||||
if len(a) > 0 || len(auth_allow_net[d]) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func auth_has_deny(domain string) bool {
|
||||
for _, d := range []string{domain, "*"} {
|
||||
if a, ok := auth_deny[d]; ok {
|
||||
if len(a) > 0 || len(auth_deny_net[d]) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func auth_do_handler() {
|
||||
for {
|
||||
|
||||
msg, err := auth_handler.RecvMessage(0)
|
||||
if err != nil {
|
||||
if auth_verbose {
|
||||
log.Println("AUTH: Quitting:", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if msg[0] == "QUIT" {
|
||||
if auth_verbose {
|
||||
log.Println("AUTH: Quitting: received QUIT message")
|
||||
}
|
||||
_, err := auth_handler.SendMessage("QUIT")
|
||||
if err != nil && auth_verbose {
|
||||
log.Println("AUTH: Quitting: bouncing QUIT message:", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
version := msg[0]
|
||||
if version != "1.0" {
|
||||
panic("AUTH: version != 1.0")
|
||||
}
|
||||
|
||||
request_id := msg[1]
|
||||
domain := msg[2]
|
||||
address := msg[3]
|
||||
identity := msg[4]
|
||||
mechanism := msg[5]
|
||||
credentials := msg[6:]
|
||||
|
||||
username := ""
|
||||
password := ""
|
||||
client_key := ""
|
||||
if mechanism == "PLAIN" {
|
||||
username = msg[6]
|
||||
password = msg[7]
|
||||
} else if mechanism == "CURVE" {
|
||||
s := msg[6]
|
||||
if len(s) != 32 {
|
||||
panic("AUTH: len(client_key) != 32")
|
||||
}
|
||||
client_key = Z85encode(s)
|
||||
}
|
||||
|
||||
allowed := false
|
||||
denied := false
|
||||
|
||||
if auth_has_allow(domain) {
|
||||
if auth_is_allowed(domain, address) {
|
||||
allowed = true
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: PASSED (whitelist) domain=%q address=%q\n", domain, address)
|
||||
}
|
||||
} else {
|
||||
denied = true
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: DENIED (not in whitelist) domain=%q address=%q\n", domain, address)
|
||||
}
|
||||
}
|
||||
} else if auth_has_deny(domain) {
|
||||
if auth_is_denied(domain, address) {
|
||||
denied = true
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: DENIED (blacklist) domain=%q address=%q\n", domain, address)
|
||||
}
|
||||
} else {
|
||||
allowed = true
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: PASSED (not in blacklist) domain=%q address=%q\n", domain, address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mechanism-specific checks
|
||||
if !denied {
|
||||
if mechanism == "NULL" && !allowed {
|
||||
// For NULL, we allow if the address wasn't blacklisted
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: ALLOWED (NULL)\n")
|
||||
}
|
||||
allowed = true
|
||||
} else if mechanism == "PLAIN" {
|
||||
// For PLAIN, even a whitelisted address must authenticate
|
||||
allowed = authenticate_plain(domain, username, password)
|
||||
} else if mechanism == "CURVE" {
|
||||
// For CURVE, even a whitelisted address must authenticate
|
||||
allowed = authenticate_curve(domain, client_key)
|
||||
}
|
||||
}
|
||||
if allowed {
|
||||
m := auth_meta_handler(version, request_id, domain, address, identity, mechanism, credentials...)
|
||||
user_id := ""
|
||||
if uid, ok := m["User-Id"]; ok {
|
||||
user_id = uid
|
||||
delete(m, "User-Id")
|
||||
}
|
||||
metadata := make([]byte, 0)
|
||||
for key, value := range m {
|
||||
if len(key) < 256 {
|
||||
metadata = append(metadata, auth_meta_blob(key, value)...)
|
||||
}
|
||||
}
|
||||
auth_handler.SendMessage(version, request_id, "200", "OK", user_id, metadata)
|
||||
} else {
|
||||
auth_handler.SendMessage(version, request_id, "400", "NO ACCESS", "", "")
|
||||
}
|
||||
}
|
||||
|
||||
err := auth_handler.Close()
|
||||
if err != nil && auth_verbose {
|
||||
log.Println("AUTH: Quitting: Close:", err)
|
||||
}
|
||||
if auth_verbose {
|
||||
log.Println("AUTH: Quit")
|
||||
}
|
||||
}
|
||||
|
||||
func authenticate_plain(domain, username, password string) bool {
|
||||
for _, dom := range []string{domain, "*"} {
|
||||
if m, ok := auth_users[dom]; ok {
|
||||
if m[username] == password {
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: ALLOWED (PLAIN) domain=%q username=%q password=%q\n", dom, username, password)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: DENIED (PLAIN) domain=%q username=%q password=%q\n", domain, username, password)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func authenticate_curve(domain, client_key string) bool {
|
||||
for _, dom := range []string{domain, "*"} {
|
||||
if m, ok := auth_pubkeys[dom]; ok {
|
||||
if m[CURVE_ALLOW_ANY] {
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: ALLOWED (CURVE any client) domain=%q\n", dom)
|
||||
}
|
||||
return true
|
||||
}
|
||||
if m[client_key] {
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: ALLOWED (CURVE) domain=%q client_key=%q\n", dom, client_key)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: DENIED (CURVE) domain=%q client_key=%q\n", domain, client_key)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Start authentication.
|
||||
//
|
||||
// Note that until you add policies, all incoming NULL connections are allowed
|
||||
// (classic ZeroMQ behaviour), and all PLAIN and CURVE connections are denied.
|
||||
func AuthStart() (err error) {
|
||||
if auth_init {
|
||||
if auth_verbose {
|
||||
log.Println("AUTH: Already running")
|
||||
}
|
||||
return errors.New("Auth is already running")
|
||||
}
|
||||
|
||||
auth_handler, err = NewSocket(REP)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auth_handler.SetLinger(0)
|
||||
err = auth_handler.Bind("inproc://zeromq.zap.01")
|
||||
if err != nil {
|
||||
auth_handler.Close()
|
||||
return
|
||||
}
|
||||
|
||||
auth_quit, err = NewSocket(REQ)
|
||||
if err != nil {
|
||||
auth_handler.Close()
|
||||
return
|
||||
}
|
||||
auth_quit.SetLinger(0)
|
||||
err = auth_quit.Connect("inproc://zeromq.zap.01")
|
||||
if err != nil {
|
||||
auth_handler.Close()
|
||||
auth_quit.Close()
|
||||
return
|
||||
}
|
||||
|
||||
go auth_do_handler()
|
||||
|
||||
if auth_verbose {
|
||||
log.Println("AUTH: Starting")
|
||||
}
|
||||
|
||||
auth_init = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Stop authentication.
|
||||
func AuthStop() {
|
||||
if !auth_init {
|
||||
if auth_verbose {
|
||||
log.Println("AUTH: Not running, can't stop")
|
||||
}
|
||||
return
|
||||
}
|
||||
if auth_verbose {
|
||||
log.Println("AUTH: Stopping")
|
||||
}
|
||||
_, err := auth_quit.SendMessageDontwait("QUIT")
|
||||
if err != nil && auth_verbose {
|
||||
log.Println("AUTH: Stopping: SendMessageDontwait(\"QUIT\"):", err)
|
||||
}
|
||||
_, err = auth_quit.RecvMessage(0)
|
||||
if err != nil && auth_verbose {
|
||||
log.Println("AUTH: Stopping: RecvMessage:", err)
|
||||
}
|
||||
err = auth_quit.Close()
|
||||
if err != nil && auth_verbose {
|
||||
log.Println("AUTH: Stopping: Close:", err)
|
||||
}
|
||||
if auth_verbose {
|
||||
log.Println("AUTH: Stopped")
|
||||
}
|
||||
|
||||
auth_init = false
|
||||
|
||||
}
|
||||
|
||||
// Allow (whitelist) some addresses for a domain.
|
||||
//
|
||||
// An address can be a single IP address, or an IP address and mask in CIDR notation.
|
||||
//
|
||||
// For NULL, all clients from these addresses will be accepted.
|
||||
//
|
||||
// For PLAIN and CURVE, they will be allowed to continue with authentication.
|
||||
//
|
||||
// You can call this method multiple times to whitelist multiple IP addresses.
|
||||
//
|
||||
// If you whitelist a single address for a domain, any non-whitelisted addresses
|
||||
// for that domain are treated as blacklisted.
|
||||
//
|
||||
// Use domain "*" for all domains.
|
||||
//
|
||||
// For backward compatibility: if domain can be parsed as an IP address, it will be
|
||||
// interpreted as another address, and it and all remaining addresses will be added
|
||||
// to all domains.
|
||||
func AuthAllow(domain string, addresses ...string) {
|
||||
if auth_isIP(domain) {
|
||||
auth_allow_for_domain("*", domain)
|
||||
auth_allow_for_domain("*", addresses...)
|
||||
} else {
|
||||
auth_allow_for_domain(domain, addresses...)
|
||||
}
|
||||
}
|
||||
|
||||
func auth_allow_for_domain(domain string, addresses ...string) {
|
||||
if _, ok := auth_allow[domain]; !ok {
|
||||
auth_allow[domain] = make(map[string]bool)
|
||||
auth_allow_net[domain] = make([]*net.IPNet, 0)
|
||||
}
|
||||
for _, address := range addresses {
|
||||
if _, ipnet, err := net.ParseCIDR(address); err == nil {
|
||||
auth_allow_net[domain] = append(auth_allow_net[domain], ipnet)
|
||||
} else if net.ParseIP(address) != nil {
|
||||
auth_allow[domain][address] = true
|
||||
} else {
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: Allow for domain %q: %q is not a valid address or network\n", domain, address)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deny (blacklist) some addresses for a domain.
|
||||
//
|
||||
// An address can be a single IP address, or an IP address and mask in CIDR notation.
|
||||
//
|
||||
// For all security mechanisms, this rejects the connection without any further authentication.
|
||||
//
|
||||
// Use either a whitelist for a domain, or a blacklist for a domain, not both.
|
||||
// If you define both a whitelist and a blacklist for a domain, only the whitelist takes effect.
|
||||
//
|
||||
// Use domain "*" for all domains.
|
||||
//
|
||||
// For backward compatibility: if domain can be parsed as an IP address, it will be
|
||||
// interpreted as another address, and it and all remaining addresses will be added
|
||||
// to all domains.
|
||||
func AuthDeny(domain string, addresses ...string) {
|
||||
if auth_isIP(domain) {
|
||||
auth_deny_for_domain("*", domain)
|
||||
auth_deny_for_domain("*", addresses...)
|
||||
} else {
|
||||
auth_deny_for_domain(domain, addresses...)
|
||||
}
|
||||
}
|
||||
|
||||
func auth_deny_for_domain(domain string, addresses ...string) {
|
||||
if _, ok := auth_deny[domain]; !ok {
|
||||
auth_deny[domain] = make(map[string]bool)
|
||||
auth_deny_net[domain] = make([]*net.IPNet, 0)
|
||||
}
|
||||
for _, address := range addresses {
|
||||
if _, ipnet, err := net.ParseCIDR(address); err == nil {
|
||||
auth_deny_net[domain] = append(auth_deny_net[domain], ipnet)
|
||||
} else if net.ParseIP(address) != nil {
|
||||
auth_deny[domain][address] = true
|
||||
} else {
|
||||
if auth_verbose {
|
||||
log.Printf("AUTH: Deny for domain %q: %q is not a valid address or network\n", domain, address)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a user for PLAIN authentication for a given domain.
|
||||
//
|
||||
// Set `domain` to "*" to apply to all domains.
|
||||
func AuthPlainAdd(domain, username, password string) {
|
||||
if _, ok := auth_users[domain]; !ok {
|
||||
auth_users[domain] = make(map[string]string)
|
||||
}
|
||||
auth_users[domain][username] = password
|
||||
}
|
||||
|
||||
// Remove users from PLAIN authentication for a given domain.
|
||||
func AuthPlainRemove(domain string, usernames ...string) {
|
||||
if u, ok := auth_users[domain]; ok {
|
||||
for _, username := range usernames {
|
||||
delete(u, username)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all users from PLAIN authentication for a given domain.
|
||||
func AuthPlainRemoveAll(domain string) {
|
||||
delete(auth_users, domain)
|
||||
}
|
||||
|
||||
// Add public user keys for CURVE authentication for a given domain.
|
||||
//
|
||||
// To cover all domains, use "*".
|
||||
//
|
||||
// Public keys are in Z85 printable text format.
|
||||
//
|
||||
// To allow all client keys without checking, specify CURVE_ALLOW_ANY for the key.
|
||||
func AuthCurveAdd(domain string, pubkeys ...string) {
|
||||
if _, ok := auth_pubkeys[domain]; !ok {
|
||||
auth_pubkeys[domain] = make(map[string]bool)
|
||||
}
|
||||
for _, key := range pubkeys {
|
||||
auth_pubkeys[domain][key] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Remove user keys from CURVE authentication for a given domain.
|
||||
func AuthCurveRemove(domain string, pubkeys ...string) {
|
||||
if p, ok := auth_pubkeys[domain]; ok {
|
||||
for _, pubkey := range pubkeys {
|
||||
delete(p, pubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all user keys from CURVE authentication for a given domain.
|
||||
func AuthCurveRemoveAll(domain string) {
|
||||
delete(auth_pubkeys, domain)
|
||||
}
|
||||
|
||||
// Enable verbose tracing of commands and activity.
|
||||
func AuthSetVerbose(verbose bool) {
|
||||
auth_verbose = verbose
|
||||
}
|
||||
|
||||
/*
|
||||
This function sets the metadata handler that is called by the ZAP
|
||||
handler to retrieve key/value properties that should be set on reply
|
||||
messages in case of a status code "200" (succes).
|
||||
|
||||
Default properties are `Socket-Type`, which is already set, and
|
||||
`Identity` and `User-Id` that are empty by default. The last two can be
|
||||
set, and more properties can be added.
|
||||
|
||||
The `User-Id` property is used for the `user id` frame of the reply
|
||||
message. All other properties are stored in the `metadata` frame of the
|
||||
reply message.
|
||||
|
||||
The default handler returns an empty map.
|
||||
|
||||
For the meaning of the handler arguments, and other details, see:
|
||||
http://rfc.zeromq.org/spec:27#toc10
|
||||
*/
|
||||
func AuthSetMetadataHandler(
|
||||
handler func(
|
||||
version, request_id, domain, address, identity, mechanism string, credentials ...string) (metadata map[string]string)) {
|
||||
auth_meta_handler = handler
|
||||
}
|
||||
|
||||
/*
|
||||
This encodes a key/value pair into the format used by a ZAP handler.
|
||||
|
||||
Returns an error if key is more then 255 characters long.
|
||||
*/
|
||||
func AuthMetaBlob(key, value string) (blob []byte, err error) {
|
||||
if len(key) > 255 {
|
||||
return []byte{}, errors.New("Key too long")
|
||||
}
|
||||
return auth_meta_blob(key, value), nil
|
||||
}
|
||||
|
||||
func auth_meta_blob(name, value string) []byte {
|
||||
l1 := len(name)
|
||||
l2 := len(value)
|
||||
b := make([]byte, l1+l2+5)
|
||||
b[0] = byte(l1)
|
||||
b[l1+1] = byte(l2 >> 24 & 255)
|
||||
b[l1+2] = byte(l2 >> 16 & 255)
|
||||
b[l1+3] = byte(l2 >> 8 & 255)
|
||||
b[l1+4] = byte(l2 & 255)
|
||||
copy(b[1:], []byte(name))
|
||||
copy(b[5+l1:], []byte(value))
|
||||
return b
|
||||
}
|
||||
|
||||
//. Additional functions for configuring server or client socket with a single command
|
||||
|
||||
// Set NULL server role.
|
||||
func (server *Socket) ServerAuthNull(domain string) error {
|
||||
err := server.SetPlainServer(0)
|
||||
if err == nil {
|
||||
err = server.SetZapDomain(domain)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Set PLAIN server role.
|
||||
func (server *Socket) ServerAuthPlain(domain string) error {
|
||||
err := server.SetPlainServer(1)
|
||||
if err == nil {
|
||||
err = server.SetZapDomain(domain)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Set CURVE server role.
|
||||
func (server *Socket) ServerAuthCurve(domain, secret_key string) error {
|
||||
err := server.SetCurveServer(1)
|
||||
if err == nil {
|
||||
err = server.SetCurveSecretkey(secret_key)
|
||||
}
|
||||
if err == nil {
|
||||
err = server.SetZapDomain(domain)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Set PLAIN client role.
|
||||
func (client *Socket) ClientAuthPlain(username, password string) error {
|
||||
err := client.SetPlainUsername(username)
|
||||
if err == nil {
|
||||
err = client.SetPlainPassword(password)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Set CURVE client role.
|
||||
func (client *Socket) ClientAuthCurve(server_public_key, client_public_key, client_secret_key string) error {
|
||||
err := client.SetCurveServerkey(server_public_key)
|
||||
if err == nil {
|
||||
err = client.SetCurvePublickey(client_public_key)
|
||||
}
|
||||
if err == nil {
|
||||
client.SetCurveSecretkey(client_secret_key)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Helper function to derive z85 public key from secret key
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
func AuthCurvePublic(z85SecretKey string) (z85PublicKey string, err error) {
|
||||
if minor < 2 {
|
||||
return "", ErrorNotImplemented42
|
||||
}
|
||||
secret := C.CString(z85SecretKey)
|
||||
defer C.free(unsafe.Pointer(secret))
|
||||
public := C.CString(strings.Repeat(" ", 41))
|
||||
defer C.free(unsafe.Pointer(public))
|
||||
if i, err := C.zmq_curve_public(public, secret); int(i) != 0 {
|
||||
return "", errget(err)
|
||||
}
|
||||
z85PublicKey = C.GoString(public)
|
||||
return z85PublicKey, nil
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
package zmq4
|
||||
|
||||
/*
|
||||
#include <zmq.h>
|
||||
#include "zmq4.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
/*
|
||||
Sets the scheduling policy for internal context’s thread pool.
|
||||
|
||||
This option requires ZeroMQ version 4.1, and is not available on Windows.
|
||||
|
||||
Supported values for this option can be found in sched.h file, or at
|
||||
http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
|
||||
|
||||
This option only applies before creating any sockets on the context.
|
||||
|
||||
Default value: -1
|
||||
|
||||
Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
|
||||
Returns ErrorNotImplementedWindows on Windows
|
||||
*/
|
||||
func (ctx *Context) SetThreadSchedPolicy(n int) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
return setOption(ctx, C.ZMQ_THREAD_SCHED_POLICY, n)
|
||||
}
|
||||
|
||||
/*
|
||||
Sets scheduling priority for internal context’s thread pool.
|
||||
|
||||
This option requires ZeroMQ version 4.1, and is not available on Windows.
|
||||
|
||||
Supported values for this option depend on chosen scheduling policy.
|
||||
Details can be found in sched.h file, or at
|
||||
http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
|
||||
|
||||
This option only applies before creating any sockets on the context.
|
||||
|
||||
Default value: -1
|
||||
|
||||
Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
|
||||
Returns ErrorNotImplementedWindows on Windows
|
||||
*/
|
||||
func (ctx *Context) SetThreadPriority(n int) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
return setOption(ctx, C.ZMQ_THREAD_PRIORITY, n)
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// +build windows
|
||||
|
||||
package zmq4
|
||||
|
||||
/*
|
||||
Sets the scheduling policy for internal context’s thread pool.
|
||||
|
||||
This option requires ZeroMQ version 4.1, and is not available on Windows.
|
||||
|
||||
Supported values for this option can be found in sched.h file, or at
|
||||
http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
|
||||
|
||||
This option only applies before creating any sockets on the context.
|
||||
|
||||
Default value: -1
|
||||
|
||||
Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
|
||||
Returns ErrorNotImplementedWindows on Windows
|
||||
*/
|
||||
func (ctx *Context) SetThreadSchedPolicy(n int) error {
|
||||
return ErrorNotImplementedWindows
|
||||
}
|
||||
|
||||
/*
|
||||
Sets scheduling priority for internal context’s thread pool.
|
||||
|
||||
This option requires ZeroMQ version 4.1, and is not available on Windows.
|
||||
|
||||
Supported values for this option depend on chosen scheduling policy.
|
||||
Details can be found in sched.h file, or at
|
||||
http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
|
||||
|
||||
This option only applies before creating any sockets on the context.
|
||||
|
||||
Default value: -1
|
||||
|
||||
Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
|
||||
Returns ErrorNotImplementedWindows on Windows
|
||||
*/
|
||||
func (ctx *Context) SetThreadPriority(n int) error {
|
||||
return ErrorNotImplementedWindows
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
A Go interface to ZeroMQ (zmq, 0mq) version 4.
|
||||
|
||||
For ZeroMQ version 3, see: http://github.com/pebbe/zmq3
|
||||
|
||||
For ZeroMQ version 2, see: http://github.com/pebbe/zmq2
|
||||
|
||||
http://www.zeromq.org/
|
||||
|
||||
See also the wiki: https://github.com/pebbe/zmq4/wiki
|
||||
|
||||
A note on the use of a context:
|
||||
|
||||
This package provides a default context. This is what will be used by
|
||||
the functions without a context receiver, that create a socket or
|
||||
manipulate the context. Package developers that import this package
|
||||
should probably not use the default context with its associated
|
||||
functions, but create their own context(s). See: type Context.
|
||||
*/
|
||||
package zmq4
|
|
@ -1,5 +0,0 @@
|
|||
/*
|
||||
|
||||
You need CGO_ENABLED=1 to build this package
|
||||
|
||||
*/
|
|
@ -1,92 +0,0 @@
|
|||
package zmq4
|
||||
|
||||
/*
|
||||
#include <zmq.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// An Errno is an unsigned number describing an error condition as returned by a call to ZeroMQ.
|
||||
// It implements the error interface.
|
||||
// The number is either a standard system error, or an error defined by the C library of ZeroMQ.
|
||||
type Errno uintptr
|
||||
|
||||
const (
|
||||
// Error conditions defined by the C library of ZeroMQ.
|
||||
|
||||
// On Windows platform some of the standard POSIX errnos are not defined.
|
||||
EADDRINUSE = Errno(C.EADDRINUSE)
|
||||
EADDRNOTAVAIL = Errno(C.EADDRNOTAVAIL)
|
||||
EAFNOSUPPORT = Errno(C.EAFNOSUPPORT)
|
||||
ECONNABORTED = Errno(C.ECONNABORTED)
|
||||
ECONNREFUSED = Errno(C.ECONNREFUSED)
|
||||
ECONNRESET = Errno(C.ECONNRESET)
|
||||
EHOSTUNREACH = Errno(C.EHOSTUNREACH)
|
||||
EINPROGRESS = Errno(C.EINPROGRESS)
|
||||
EMSGSIZE = Errno(C.EMSGSIZE)
|
||||
ENETDOWN = Errno(C.ENETDOWN)
|
||||
ENETRESET = Errno(C.ENETRESET)
|
||||
ENETUNREACH = Errno(C.ENETUNREACH)
|
||||
ENOBUFS = Errno(C.ENOBUFS)
|
||||
ENOTCONN = Errno(C.ENOTCONN)
|
||||
ENOTSOCK = Errno(C.ENOTSOCK)
|
||||
ENOTSUP = Errno(C.ENOTSUP)
|
||||
EPROTONOSUPPORT = Errno(C.EPROTONOSUPPORT)
|
||||
ETIMEDOUT = Errno(C.ETIMEDOUT)
|
||||
|
||||
// Native 0MQ error codes.
|
||||
EFSM = Errno(C.EFSM)
|
||||
EMTHREAD = Errno(C.EMTHREAD)
|
||||
ENOCOMPATPROTO = Errno(C.ENOCOMPATPROTO)
|
||||
ETERM = Errno(C.ETERM)
|
||||
)
|
||||
|
||||
func errget(err error) error {
|
||||
eno, ok := err.(syscall.Errno)
|
||||
if ok {
|
||||
return Errno(eno)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Return Errno as string.
|
||||
func (errno Errno) Error() string {
|
||||
if errno >= C.ZMQ_HAUSNUMERO {
|
||||
return C.GoString(C.zmq_strerror(C.int(errno)))
|
||||
}
|
||||
return syscall.Errno(errno).Error()
|
||||
}
|
||||
|
||||
/*
|
||||
Convert error to Errno.
|
||||
|
||||
Example usage:
|
||||
|
||||
switch AsErrno(err) {
|
||||
|
||||
case zmq.Errno(syscall.EINTR):
|
||||
// standard system error
|
||||
|
||||
// call was interrupted
|
||||
|
||||
case zmq.ETERM:
|
||||
// error defined by ZeroMQ
|
||||
|
||||
// context was terminated
|
||||
|
||||
}
|
||||
|
||||
See also: examples/interrupt.go
|
||||
*/
|
||||
func AsErrno(err error) Errno {
|
||||
if eno, ok := err.(Errno); ok {
|
||||
return eno
|
||||
}
|
||||
if eno, ok := err.(syscall.Errno); ok {
|
||||
return Errno(eno)
|
||||
}
|
||||
return Errno(0)
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
package zmq4
|
||||
|
||||
/*
|
||||
#include <zmq.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Return type for (*Poller)Poll
|
||||
type Polled struct {
|
||||
Socket *Socket // socket with matched event(s)
|
||||
Events State // actual matched event(s)
|
||||
}
|
||||
|
||||
type Poller struct {
|
||||
items []C.zmq_pollitem_t
|
||||
socks []*Socket
|
||||
}
|
||||
|
||||
// Create a new Poller
|
||||
func NewPoller() *Poller {
|
||||
return &Poller{
|
||||
items: make([]C.zmq_pollitem_t, 0),
|
||||
socks: make([]*Socket, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// Add items to the poller
|
||||
//
|
||||
// Events is a bitwise OR of zmq.POLLIN and zmq.POLLOUT
|
||||
//
|
||||
// Returns the id of the item, which can be used as a handle to
|
||||
// (*Poller)Update and as an index into the result of (*Poller)PollAll
|
||||
func (p *Poller) Add(soc *Socket, events State) int {
|
||||
var item C.zmq_pollitem_t
|
||||
item.socket = soc.soc
|
||||
item.fd = 0
|
||||
item.events = C.short(events)
|
||||
p.items = append(p.items, item)
|
||||
p.socks = append(p.socks, soc)
|
||||
return len(p.items) - 1
|
||||
}
|
||||
|
||||
// Update the events mask of a socket in the poller
|
||||
//
|
||||
// Replaces the Poller's bitmask for the specified id with the events parameter passed
|
||||
//
|
||||
// Returns the previous value, or ErrorNoSocket if the id was out of range
|
||||
func (p *Poller) Update(id int, events State) (previous State, err error) {
|
||||
if id >= 0 && id < len(p.items) {
|
||||
previous = State(p.items[id].events)
|
||||
p.items[id].events = C.short(events)
|
||||
return previous, nil
|
||||
}
|
||||
return 0, ErrorNoSocket
|
||||
}
|
||||
|
||||
// Update the events mask of a socket in the poller
|
||||
//
|
||||
// Replaces the Poller's bitmask for the specified socket with the events parameter passed
|
||||
//
|
||||
// Returns the previous value, or ErrorNoSocket if the socket didn't match
|
||||
func (p *Poller) UpdateBySocket(soc *Socket, events State) (previous State, err error) {
|
||||
for id, s := range p.socks {
|
||||
if s == soc {
|
||||
previous = State(p.items[id].events)
|
||||
p.items[id].events = C.short(events)
|
||||
return previous, nil
|
||||
}
|
||||
}
|
||||
return 0, ErrorNoSocket
|
||||
}
|
||||
|
||||
// Remove a socket from the poller
|
||||
//
|
||||
// Returns ErrorNoSocket if the id was out of range
|
||||
func (p *Poller) Remove(id int) error {
|
||||
if id >= 0 && id < len(p.items) {
|
||||
if id == len(p.items)-1 {
|
||||
p.items = p.items[:id]
|
||||
p.socks = p.socks[:id]
|
||||
} else {
|
||||
p.items = append(p.items[:id], p.items[id+1:]...)
|
||||
p.socks = append(p.socks[:id], p.socks[id+1:]...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return ErrorNoSocket
|
||||
}
|
||||
|
||||
// Remove a socket from the poller
|
||||
//
|
||||
// Returns ErrorNoSocket if the socket didn't match
|
||||
func (p *Poller) RemoveBySocket(soc *Socket) error {
|
||||
for id, s := range p.socks {
|
||||
if s == soc {
|
||||
return p.Remove(id)
|
||||
}
|
||||
}
|
||||
return ErrorNoSocket
|
||||
}
|
||||
|
||||
/*
|
||||
Input/output multiplexing
|
||||
|
||||
If timeout < 0, wait forever until a matching event is detected
|
||||
|
||||
Only sockets with matching socket events are returned in the list.
|
||||
|
||||
Example:
|
||||
|
||||
poller := zmq.NewPoller()
|
||||
poller.Add(socket0, zmq.POLLIN)
|
||||
poller.Add(socket1, zmq.POLLIN)
|
||||
// Process messages from both sockets
|
||||
for {
|
||||
sockets, _ := poller.Poll(-1)
|
||||
for _, socket := range sockets {
|
||||
switch s := socket.Socket; s {
|
||||
case socket0:
|
||||
msg, _ := s.Recv(0)
|
||||
// Process msg
|
||||
case socket1:
|
||||
msg, _ := s.Recv(0)
|
||||
// Process msg
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
func (p *Poller) Poll(timeout time.Duration) ([]Polled, error) {
|
||||
return p.poll(timeout, false)
|
||||
}
|
||||
|
||||
/*
|
||||
This is like (*Poller)Poll, but it returns a list of all sockets,
|
||||
in the same order as they were added to the poller,
|
||||
not just those sockets that had an event.
|
||||
|
||||
For each socket in the list, you have to check the Events field
|
||||
to see if there was actually an event.
|
||||
|
||||
When error is not nil, the return list contains no sockets.
|
||||
*/
|
||||
func (p *Poller) PollAll(timeout time.Duration) ([]Polled, error) {
|
||||
return p.poll(timeout, true)
|
||||
}
|
||||
|
||||
func (p *Poller) poll(timeout time.Duration, all bool) ([]Polled, error) {
|
||||
lst := make([]Polled, 0, len(p.items))
|
||||
|
||||
for _, soc := range p.socks {
|
||||
if !soc.opened {
|
||||
return lst, ErrorSocketClosed
|
||||
}
|
||||
}
|
||||
|
||||
t := timeout
|
||||
if t > 0 {
|
||||
t = t / time.Millisecond
|
||||
}
|
||||
if t < 0 {
|
||||
t = -1
|
||||
}
|
||||
rv, err := C.zmq_poll(&p.items[0], C.int(len(p.items)), C.long(t))
|
||||
if rv < 0 {
|
||||
return lst, errget(err)
|
||||
}
|
||||
for i, it := range p.items {
|
||||
if all || it.events&it.revents != 0 {
|
||||
lst = append(lst, Polled{p.socks[i], State(it.revents)})
|
||||
}
|
||||
}
|
||||
return lst, nil
|
||||
}
|
||||
|
||||
// Poller as string.
|
||||
func (p *Poller) String() string {
|
||||
str := make([]string, 0)
|
||||
for i, poll := range p.items {
|
||||
str = append(str, fmt.Sprintf("%v%v", p.socks[i], State(poll.events)))
|
||||
}
|
||||
return fmt.Sprint("Poller", str)
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
package zmq4
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type reactor_socket struct {
|
||||
e State
|
||||
f func(State) error
|
||||
}
|
||||
|
||||
type reactor_channel struct {
|
||||
ch <-chan interface{}
|
||||
f func(interface{}) error
|
||||
limit int
|
||||
}
|
||||
|
||||
type Reactor struct {
|
||||
sockets map[*Socket]*reactor_socket
|
||||
channels map[uint64]*reactor_channel
|
||||
p *Poller
|
||||
idx uint64
|
||||
remove []uint64
|
||||
verbose bool
|
||||
}
|
||||
|
||||
/*
|
||||
Create a reactor to mix the handling of sockets and channels (timers or other channels).
|
||||
|
||||
Example:
|
||||
|
||||
reactor := zmq.NewReactor()
|
||||
reactor.AddSocket(socket1, zmq.POLLIN, socket1_handler)
|
||||
reactor.AddSocket(socket2, zmq.POLLIN, socket2_handler)
|
||||
reactor.AddChannelTime(time.Tick(time.Second), 1, ticker_handler)
|
||||
reactor.Run(time.Second)
|
||||
*/
|
||||
func NewReactor() *Reactor {
|
||||
r := &Reactor{
|
||||
sockets: make(map[*Socket]*reactor_socket),
|
||||
channels: make(map[uint64]*reactor_channel),
|
||||
p: NewPoller(),
|
||||
remove: make([]uint64, 0),
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Add socket handler to the reactor.
|
||||
//
|
||||
// You can have only one handler per socket. Adding a second one will remove the first.
|
||||
//
|
||||
// The handler receives the socket state as an argument: POLLIN, POLLOUT, or both.
|
||||
func (r *Reactor) AddSocket(soc *Socket, events State, handler func(State) error) {
|
||||
r.RemoveSocket(soc)
|
||||
r.sockets[soc] = &reactor_socket{e: events, f: handler}
|
||||
r.p.Add(soc, events)
|
||||
}
|
||||
|
||||
// Remove a socket handler from the reactor.
|
||||
func (r *Reactor) RemoveSocket(soc *Socket) {
|
||||
if _, ok := r.sockets[soc]; ok {
|
||||
delete(r.sockets, soc)
|
||||
// rebuild poller
|
||||
r.p = NewPoller()
|
||||
for s, props := range r.sockets {
|
||||
r.p.Add(s, props.e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add channel handler to the reactor.
|
||||
//
|
||||
// Returns id of added handler, that can be used later to remove it.
|
||||
//
|
||||
// If limit is positive, at most this many items will be handled in each run through the main loop,
|
||||
// otherwise it will process as many items as possible.
|
||||
//
|
||||
// The handler function receives the value received from the channel.
|
||||
func (r *Reactor) AddChannel(ch <-chan interface{}, limit int, handler func(interface{}) error) (id uint64) {
|
||||
r.idx++
|
||||
id = r.idx
|
||||
r.channels[id] = &reactor_channel{ch: ch, f: handler, limit: limit}
|
||||
return
|
||||
}
|
||||
|
||||
// This function wraps AddChannel, using a channel of type time.Time instead of type interface{}.
|
||||
func (r *Reactor) AddChannelTime(ch <-chan time.Time, limit int, handler func(interface{}) error) (id uint64) {
|
||||
ch2 := make(chan interface{})
|
||||
go func() {
|
||||
for {
|
||||
a, ok := <-ch
|
||||
if !ok {
|
||||
close(ch2)
|
||||
break
|
||||
}
|
||||
ch2 <- a
|
||||
}
|
||||
}()
|
||||
return r.AddChannel(ch2, limit, handler)
|
||||
}
|
||||
|
||||
// Remove a channel from the reactor.
|
||||
//
|
||||
// Closed channels are removed automatically.
|
||||
func (r *Reactor) RemoveChannel(id uint64) {
|
||||
r.remove = append(r.remove, id)
|
||||
}
|
||||
|
||||
func (r *Reactor) SetVerbose(verbose bool) {
|
||||
r.verbose = verbose
|
||||
}
|
||||
|
||||
// Run the reactor.
|
||||
//
|
||||
// The interval determines the time-out on the polling of sockets.
|
||||
// Interval must be positive if there are channels.
|
||||
// If there are no channels, you can set interval to -1.
|
||||
//
|
||||
// The run alternates between polling/handling sockets (using the interval as timeout),
|
||||
// and reading/handling channels. The reading of channels is without time-out: if there
|
||||
// is no activity on any channel, the run continues to poll sockets immediately.
|
||||
//
|
||||
// The run exits when any handler returns an error, returning that same error.
|
||||
func (r *Reactor) Run(interval time.Duration) (err error) {
|
||||
for {
|
||||
|
||||
// process requests to remove channels
|
||||
for _, id := range r.remove {
|
||||
delete(r.channels, id)
|
||||
}
|
||||
r.remove = r.remove[0:0]
|
||||
|
||||
CHANNELS:
|
||||
for id, ch := range r.channels {
|
||||
limit := ch.limit
|
||||
for {
|
||||
select {
|
||||
case val, ok := <-ch.ch:
|
||||
if !ok {
|
||||
if r.verbose {
|
||||
fmt.Printf("Reactor(%p) removing closed channel %d\n", r, id)
|
||||
}
|
||||
r.RemoveChannel(id)
|
||||
continue CHANNELS
|
||||
}
|
||||
if r.verbose {
|
||||
fmt.Printf("Reactor(%p) channel %d: %q\n", r, id, val)
|
||||
}
|
||||
err = ch.f(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if ch.limit > 0 {
|
||||
limit--
|
||||
if limit == 0 {
|
||||
continue CHANNELS
|
||||
}
|
||||
}
|
||||
default:
|
||||
continue CHANNELS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.channels) > 0 && interval < 0 {
|
||||
return errors.New("There are channels, but polling time-out is infinite")
|
||||
}
|
||||
|
||||
if len(r.sockets) == 0 {
|
||||
if len(r.channels) == 0 {
|
||||
return errors.New("No sockets to poll, no channels to read")
|
||||
}
|
||||
time.Sleep(interval)
|
||||
continue
|
||||
}
|
||||
|
||||
polled, e := r.p.Poll(interval)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
for _, item := range polled {
|
||||
if r.verbose {
|
||||
fmt.Printf("Reactor(%p) %v\n", r, item)
|
||||
}
|
||||
err = r.sockets[item.Socket].f(item.Events)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,648 +0,0 @@
|
|||
package zmq4
|
||||
|
||||
/*
|
||||
#include <zmq.h>
|
||||
#include <stdint.h>
|
||||
#include "zmq4.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (soc *Socket) getString(opt C.int, bufsize int) (string, error) {
|
||||
if !soc.opened {
|
||||
return "", ErrorSocketClosed
|
||||
}
|
||||
value := make([]byte, bufsize)
|
||||
size := C.size_t(bufsize)
|
||||
if i, err := C.zmq_getsockopt(soc.soc, opt, unsafe.Pointer(&value[0]), &size); i != 0 {
|
||||
return "", errget(err)
|
||||
}
|
||||
return strings.TrimRight(string(value[:int(size)]), "\x00"), nil
|
||||
}
|
||||
|
||||
func (soc *Socket) getStringRaw(opt C.int, bufsize int) (string, error) {
|
||||
if !soc.opened {
|
||||
return "", ErrorSocketClosed
|
||||
}
|
||||
value := make([]byte, bufsize)
|
||||
size := C.size_t(bufsize)
|
||||
if i, err := C.zmq_getsockopt(soc.soc, opt, unsafe.Pointer(&value[0]), &size); i != 0 {
|
||||
return "", errget(err)
|
||||
}
|
||||
return string(value[:int(size)]), nil
|
||||
}
|
||||
|
||||
func (soc *Socket) getInt(opt C.int) (int, error) {
|
||||
if !soc.opened {
|
||||
return 0, ErrorSocketClosed
|
||||
}
|
||||
value := C.int(0)
|
||||
size := C.size_t(unsafe.Sizeof(value))
|
||||
if i, err := C.zmq_getsockopt(soc.soc, opt, unsafe.Pointer(&value), &size); i != 0 {
|
||||
return 0, errget(err)
|
||||
}
|
||||
return int(value), nil
|
||||
}
|
||||
|
||||
func (soc *Socket) getInt64(opt C.int) (int64, error) {
|
||||
if !soc.opened {
|
||||
return 0, ErrorSocketClosed
|
||||
}
|
||||
value := C.int64_t(0)
|
||||
size := C.size_t(unsafe.Sizeof(value))
|
||||
if i, err := C.zmq_getsockopt(soc.soc, opt, unsafe.Pointer(&value), &size); i != 0 {
|
||||
return 0, errget(err)
|
||||
}
|
||||
return int64(value), nil
|
||||
}
|
||||
|
||||
func (soc *Socket) getUInt64(opt C.int) (uint64, error) {
|
||||
if !soc.opened {
|
||||
return 0, ErrorSocketClosed
|
||||
}
|
||||
value := C.uint64_t(0)
|
||||
size := C.size_t(unsafe.Sizeof(value))
|
||||
if i, err := C.zmq_getsockopt(soc.soc, opt, unsafe.Pointer(&value), &size); i != 0 {
|
||||
return 0, errget(err)
|
||||
}
|
||||
return uint64(value), nil
|
||||
}
|
||||
|
||||
// ZMQ_TYPE: Retrieve socket type
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc43
|
||||
func (soc *Socket) GetType() (Type, error) {
|
||||
v, err := soc.getInt(C.ZMQ_TYPE)
|
||||
return Type(v), err
|
||||
}
|
||||
|
||||
// ZMQ_RCVMORE: More message data parts to follow
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc30
|
||||
func (soc *Socket) GetRcvmore() (bool, error) {
|
||||
v, err := soc.getInt(C.ZMQ_RCVMORE)
|
||||
return v != 0, err
|
||||
}
|
||||
|
||||
// ZMQ_SNDHWM: Retrieves high water mark for outbound messages
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc36
|
||||
func (soc *Socket) GetSndhwm() (int, error) {
|
||||
return soc.getInt(C.ZMQ_SNDHWM)
|
||||
}
|
||||
|
||||
// ZMQ_RCVHWM: Retrieve high water mark for inbound messages
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc29
|
||||
func (soc *Socket) GetRcvhwm() (int, error) {
|
||||
return soc.getInt(C.ZMQ_RCVHWM)
|
||||
}
|
||||
|
||||
// ZMQ_AFFINITY: Retrieve I/O thread affinity
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc3
|
||||
func (soc *Socket) GetAffinity() (uint64, error) {
|
||||
return soc.getUInt64(C.ZMQ_AFFINITY)
|
||||
}
|
||||
|
||||
// ZMQ_IDENTITY: Retrieve socket identity
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc15
|
||||
func (soc *Socket) GetIdentity() (string, error) {
|
||||
return soc.getString(C.ZMQ_IDENTITY, 256)
|
||||
}
|
||||
|
||||
// ZMQ_RATE: Retrieve multicast data rate
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc27
|
||||
func (soc *Socket) GetRate() (int, error) {
|
||||
return soc.getInt(C.ZMQ_RATE)
|
||||
}
|
||||
|
||||
// ZMQ_RECOVERY_IVL: Get multicast recovery interval
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc34
|
||||
func (soc *Socket) GetRecoveryIvl() (time.Duration, error) {
|
||||
v, err := soc.getInt(C.ZMQ_RECOVERY_IVL)
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_SNDBUF: Retrieve kernel transmit buffer size
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc35
|
||||
func (soc *Socket) GetSndbuf() (int, error) {
|
||||
return soc.getInt(C.ZMQ_SNDBUF)
|
||||
}
|
||||
|
||||
// ZMQ_RCVBUF: Retrieve kernel receive buffer size
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc28
|
||||
func (soc *Socket) GetRcvbuf() (int, error) {
|
||||
return soc.getInt(C.ZMQ_RCVBUF)
|
||||
}
|
||||
|
||||
// ZMQ_LINGER: Retrieve linger period for socket shutdown
|
||||
//
|
||||
// Returns time.Duration(-1) for infinite
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc20
|
||||
func (soc *Socket) GetLinger() (time.Duration, error) {
|
||||
v, err := soc.getInt(C.ZMQ_LINGER)
|
||||
if v < 0 {
|
||||
return time.Duration(-1), err
|
||||
}
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_RECONNECT_IVL: Retrieve reconnection interval
|
||||
//
|
||||
// Returns time.Duration(-1) for no reconnection
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc32
|
||||
func (soc *Socket) GetReconnectIvl() (time.Duration, error) {
|
||||
v, err := soc.getInt(C.ZMQ_RECONNECT_IVL)
|
||||
if v < 0 {
|
||||
return time.Duration(-1), err
|
||||
}
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_RECONNECT_IVL_MAX: Retrieve maximum reconnection interval
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc33
|
||||
func (soc *Socket) GetReconnectIvlMax() (time.Duration, error) {
|
||||
v, err := soc.getInt(C.ZMQ_RECONNECT_IVL_MAX)
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_BACKLOG: Retrieve maximum length of the queue of outstanding connections
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc4
|
||||
func (soc *Socket) GetBacklog() (int, error) {
|
||||
return soc.getInt(C.ZMQ_BACKLOG)
|
||||
}
|
||||
|
||||
// ZMQ_MAXMSGSIZE: Maximum acceptable inbound message size
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc21
|
||||
func (soc *Socket) GetMaxmsgsize() (int64, error) {
|
||||
return soc.getInt64(C.ZMQ_MAXMSGSIZE)
|
||||
}
|
||||
|
||||
// ZMQ_MULTICAST_HOPS: Maximum network hops for multicast packets
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc23
|
||||
func (soc *Socket) GetMulticastHops() (int, error) {
|
||||
return soc.getInt(C.ZMQ_MULTICAST_HOPS)
|
||||
}
|
||||
|
||||
// ZMQ_RCVTIMEO: Maximum time before a socket operation returns with EAGAIN
|
||||
//
|
||||
// Returns time.Duration(-1) for infinite
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc31
|
||||
func (soc *Socket) GetRcvtimeo() (time.Duration, error) {
|
||||
v, err := soc.getInt(C.ZMQ_RCVTIMEO)
|
||||
if v < 0 {
|
||||
return time.Duration(-1), err
|
||||
}
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_SNDTIMEO: Maximum time before a socket operation returns with EAGAIN
|
||||
//
|
||||
// Returns time.Duration(-1) for infinite
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc37
|
||||
func (soc *Socket) GetSndtimeo() (time.Duration, error) {
|
||||
v, err := soc.getInt(C.ZMQ_SNDTIMEO)
|
||||
if v < 0 {
|
||||
return time.Duration(-1), err
|
||||
}
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_IPV6: Retrieve IPv6 socket status
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc18
|
||||
func (soc *Socket) GetIpv6() (bool, error) {
|
||||
v, err := soc.getInt(C.ZMQ_IPV6)
|
||||
return v != 0, err
|
||||
}
|
||||
|
||||
// ZMQ_IMMEDIATE: Retrieve attach-on-connect value
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc16
|
||||
func (soc *Socket) GetImmediate() (bool, error) {
|
||||
v, err := soc.getInt(C.ZMQ_IMMEDIATE)
|
||||
return v != 0, err
|
||||
}
|
||||
|
||||
// ZMQ_FD: Retrieve file descriptor associated with the socket
|
||||
// see socketget_unix.go and socketget_windows.go
|
||||
|
||||
// ZMQ_EVENTS: Retrieve socket event state
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc8
|
||||
func (soc *Socket) GetEvents() (State, error) {
|
||||
v, err := soc.getInt(C.ZMQ_EVENTS)
|
||||
return State(v), err
|
||||
}
|
||||
|
||||
// ZMQ_LAST_ENDPOINT: Retrieve the last endpoint set
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc19
|
||||
func (soc *Socket) GetLastEndpoint() (string, error) {
|
||||
return soc.getString(C.ZMQ_LAST_ENDPOINT, 1024)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_KEEPALIVE: Override SO_KEEPALIVE socket option
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc38
|
||||
func (soc *Socket) GetTcpKeepalive() (int, error) {
|
||||
return soc.getInt(C.ZMQ_TCP_KEEPALIVE)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPCNT(or TCP_KEEPALIVE on some OS)
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc40
|
||||
func (soc *Socket) GetTcpKeepaliveIdle() (int, error) {
|
||||
return soc.getInt(C.ZMQ_TCP_KEEPALIVE_IDLE)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_KEEPALIVE_CNT: Override TCP_KEEPCNT socket option
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc39
|
||||
func (soc *Socket) GetTcpKeepaliveCnt() (int, error) {
|
||||
return soc.getInt(C.ZMQ_TCP_KEEPALIVE_CNT)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_KEEPALIVE_INTVL: Override TCP_KEEPINTVL socket option
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc41
|
||||
func (soc *Socket) GetTcpKeepaliveIntvl() (int, error) {
|
||||
return soc.getInt(C.ZMQ_TCP_KEEPALIVE_INTVL)
|
||||
}
|
||||
|
||||
// ZMQ_MECHANISM: Retrieve current security mechanism
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc22
|
||||
func (soc *Socket) GetMechanism() (Mechanism, error) {
|
||||
v, err := soc.getInt(C.ZMQ_MECHANISM)
|
||||
return Mechanism(v), err
|
||||
}
|
||||
|
||||
// ZMQ_PLAIN_SERVER: Retrieve current PLAIN server role
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc25
|
||||
func (soc *Socket) GetPlainServer() (int, error) {
|
||||
return soc.getInt(C.ZMQ_PLAIN_SERVER)
|
||||
}
|
||||
|
||||
// ZMQ_PLAIN_USERNAME: Retrieve current PLAIN username
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc26
|
||||
func (soc *Socket) GetPlainUsername() (string, error) {
|
||||
s, err := soc.getString(C.ZMQ_PLAIN_USERNAME, 1024)
|
||||
if n := len(s); n > 0 && s[n-1] == 0 {
|
||||
s = s[:n-1]
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
|
||||
// ZMQ_PLAIN_PASSWORD: Retrieve current password
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc24
|
||||
func (soc *Socket) GetPlainPassword() (string, error) {
|
||||
s, err := soc.getString(C.ZMQ_PLAIN_PASSWORD, 1024)
|
||||
if n := len(s); n > 0 && s[n-1] == 0 {
|
||||
s = s[:n-1]
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_PUBLICKEY: Retrieve current CURVE public key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc5
|
||||
func (soc *Socket) GetCurvePublickeyRaw() (string, error) {
|
||||
return soc.getStringRaw(C.ZMQ_CURVE_PUBLICKEY, 32)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_PUBLICKEY: Retrieve current CURVE public key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc5
|
||||
func (soc *Socket) GetCurvePublickeykeyZ85() (string, error) {
|
||||
return soc.getString(C.ZMQ_CURVE_PUBLICKEY, 41)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_SECRETKEY: Retrieve current CURVE secret key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc6
|
||||
func (soc *Socket) GetCurveSecretkeyRaw() (string, error) {
|
||||
return soc.getStringRaw(C.ZMQ_CURVE_SECRETKEY, 32)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_SECRETKEY: Retrieve current CURVE secret key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc6
|
||||
func (soc *Socket) GetCurveSecretkeyZ85() (string, error) {
|
||||
return soc.getString(C.ZMQ_CURVE_SECRETKEY, 41)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_SERVERKEY: Retrieve current CURVE server key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc7
|
||||
func (soc *Socket) GetCurveServerkeyRaw() (string, error) {
|
||||
return soc.getStringRaw(C.ZMQ_CURVE_SERVERKEY, 32)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_SERVERKEY: Retrieve current CURVE server key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc7
|
||||
func (soc *Socket) GetCurveServerkeyZ85() (string, error) {
|
||||
return soc.getString(C.ZMQ_CURVE_SERVERKEY, 41)
|
||||
}
|
||||
|
||||
// ZMQ_ZAP_DOMAIN: Retrieve RFC 27 authentication domain
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc44
|
||||
func (soc *Socket) GetZapDomain() (string, error) {
|
||||
return soc.getString(C.ZMQ_ZAP_DOMAIN, 1024)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// New in ZeroMQ 4.1.0
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// + : yes
|
||||
// D : deprecated
|
||||
// o : setsockopt only
|
||||
// implemented documented test
|
||||
// ZMQ_ROUTER_HANDOVER o
|
||||
// ZMQ_TOS + +
|
||||
// ZMQ_IPC_FILTER_PID D
|
||||
// ZMQ_IPC_FILTER_UID D
|
||||
// ZMQ_IPC_FILTER_GID D
|
||||
// ZMQ_CONNECT_RID o
|
||||
// ZMQ_GSSAPI_SERVER + +
|
||||
// ZMQ_GSSAPI_PRINCIPAL + +
|
||||
// ZMQ_GSSAPI_SERVICE_PRINCIPAL + +
|
||||
// ZMQ_GSSAPI_PLAINTEXT + +
|
||||
// ZMQ_HANDSHAKE_IVL + +
|
||||
// ZMQ_SOCKS_PROXY +
|
||||
// ZMQ_XPUB_NODROP o?
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// ZMQ_TOS: Retrieve the Type-of-Service socket override status
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc42
|
||||
func (soc *Socket) GetTos() (int, error) {
|
||||
if minor < 1 {
|
||||
return 0, ErrorNotImplemented41
|
||||
}
|
||||
return soc.getInt(C.ZMQ_TOS)
|
||||
}
|
||||
|
||||
// ZMQ_CONNECT_RID: SET ONLY
|
||||
|
||||
// ZMQ_GSSAPI_SERVER: Retrieve current GSSAPI server role
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc12
|
||||
func (soc *Socket) GetGssapiServer() (bool, error) {
|
||||
if minor < 1 {
|
||||
return false, ErrorNotImplemented41
|
||||
}
|
||||
v, err := soc.getInt(C.ZMQ_GSSAPI_SERVER)
|
||||
return v != 0, err
|
||||
}
|
||||
|
||||
// ZMQ_GSSAPI_PRINCIPAL: Retrieve the name of the GSSAPI principal
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc11
|
||||
func (soc *Socket) GetGssapiPrincipal() (string, error) {
|
||||
if minor < 1 {
|
||||
return "", ErrorNotImplemented41
|
||||
}
|
||||
return soc.getString(C.ZMQ_GSSAPI_PRINCIPAL, 1024)
|
||||
}
|
||||
|
||||
// ZMQ_GSSAPI_SERVICE_PRINCIPAL: Retrieve the name of the GSSAPI service principal
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc13
|
||||
func (soc *Socket) GetGssapiServicePrincipal() (string, error) {
|
||||
if minor < 1 {
|
||||
return "", ErrorNotImplemented41
|
||||
}
|
||||
return soc.getString(C.ZMQ_GSSAPI_SERVICE_PRINCIPAL, 1024)
|
||||
}
|
||||
|
||||
// ZMQ_GSSAPI_PLAINTEXT: Retrieve GSSAPI plaintext or encrypted status
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc10
|
||||
func (soc *Socket) GetGssapiPlaintext() (bool, error) {
|
||||
if minor < 1 {
|
||||
return false, ErrorNotImplemented41
|
||||
}
|
||||
v, err := soc.getInt(C.ZMQ_GSSAPI_PLAINTEXT)
|
||||
return v != 0, err
|
||||
}
|
||||
|
||||
// ZMQ_HANDSHAKE_IVL: Retrieve maximum handshake interval
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc14
|
||||
func (soc *Socket) GetHandshakeIvl() (time.Duration, error) {
|
||||
if minor < 1 {
|
||||
return time.Duration(0), ErrorNotImplemented41
|
||||
}
|
||||
v, err := soc.getInt(C.ZMQ_HANDSHAKE_IVL)
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_SOCKS_PROXY: NOT DOCUMENTED
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
func (soc *Socket) GetSocksProxy() (string, error) {
|
||||
if minor < 1 {
|
||||
return "", ErrorNotImplemented41
|
||||
}
|
||||
return soc.getString(C.ZMQ_SOCKS_PROXY, 1024)
|
||||
}
|
||||
|
||||
// ZMQ_XPUB_NODROP: SET ONLY? (not documented)
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// New in ZeroMQ 4.2.0
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// + : yes
|
||||
// o : setsockopt only
|
||||
// implemented documented test
|
||||
// ZMQ_BLOCKY
|
||||
// ZMQ_XPUB_MANUAL o
|
||||
// ZMQ_XPUB_WELCOME_MSG o
|
||||
// ZMQ_STREAM_NOTIFY o
|
||||
// ZMQ_INVERT_MATCHING + +
|
||||
// ZMQ_HEARTBEAT_IVL o
|
||||
// ZMQ_HEARTBEAT_TTL o
|
||||
// ZMQ_HEARTBEAT_TIMEOUT o
|
||||
// ZMQ_XPUB_VERBOSER o
|
||||
// ZMQ_CONNECT_TIMEOUT + +
|
||||
// ZMQ_TCP_MAXRT + +
|
||||
// ZMQ_THREAD_SAFE + +
|
||||
// ZMQ_MULTICAST_MAXTPDU + +
|
||||
// ZMQ_VMCI_BUFFER_SIZE + +
|
||||
// ZMQ_VMCI_BUFFER_MIN_SIZE + +
|
||||
// ZMQ_VMCI_BUFFER_MAX_SIZE + +
|
||||
// ZMQ_VMCI_CONNECT_TIMEOUT + +
|
||||
// ZMQ_USE_FD + +
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// ZMQ_BLOCKY doesn't look like a socket option
|
||||
|
||||
// ZMQ_INVERT_MATCHING: Retrieve inverted filtering status
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc18
|
||||
func (soc *Socket) GetInvertMatching() (int, error) {
|
||||
if minor < 2 {
|
||||
return 0, ErrorNotImplemented42
|
||||
}
|
||||
return soc.getInt(C.ZMQ_INVERT_MATCHING)
|
||||
}
|
||||
|
||||
// ZMQ_CONNECT_TIMEOUT: Retrieve connect() timeout
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc5
|
||||
func (soc *Socket) GetConnectTimeout() (time.Duration, error) {
|
||||
if minor < 2 {
|
||||
return time.Duration(0), ErrorNotImplemented42
|
||||
}
|
||||
v, err := soc.getInt(C.ZMQ_CONNECT_TIMEOUT)
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_TCP_MAXRT: Retrieve Max TCP Retransmit Timeout
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc44
|
||||
func (soc *Socket) GetTcpMaxrt() (time.Duration, error) {
|
||||
if minor < 2 {
|
||||
return time.Duration(0), ErrorNotImplemented42
|
||||
}
|
||||
v, err := soc.getInt(C.ZMQ_TCP_MAXRT)
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_THREAD_SAFE: Retrieve socket thread safety
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc45
|
||||
func (soc *Socket) GetThreadSafe() (bool, error) {
|
||||
if minor < 2 {
|
||||
return false, ErrorNotImplemented42
|
||||
}
|
||||
v, err := soc.getInt(C.ZMQ_THREAD_SAFE)
|
||||
return v != 0, err
|
||||
}
|
||||
|
||||
// ZMQ_MULTICAST_MAXTPDU: Maximum transport data unit size for multicast packets
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc26
|
||||
func (soc *Socket) GetMulticastMaxtpdu() (int, error) {
|
||||
if minor < 2 {
|
||||
return 0, ErrorNotImplemented42
|
||||
}
|
||||
return soc.getInt(C.ZMQ_MULTICAST_MAXTPDU)
|
||||
}
|
||||
|
||||
// ZMQ_VMCI_BUFFER_SIZE: Retrieve buffer size of the VMCI socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc49
|
||||
func (soc *Socket) GetVmciBufferSize() (uint64, error) {
|
||||
if minor < 2 {
|
||||
return 0, ErrorNotImplemented42
|
||||
}
|
||||
return soc.getUInt64(C.ZMQ_VMCI_BUFFER_SIZE)
|
||||
}
|
||||
|
||||
// ZMQ_VMCI_BUFFER_MIN_SIZE: Retrieve min buffer size of the VMCI socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc50
|
||||
func (soc *Socket) GetVmciBufferMinSize() (uint64, error) {
|
||||
if minor < 2 {
|
||||
return 0, ErrorNotImplemented42
|
||||
}
|
||||
return soc.getUInt64(C.ZMQ_VMCI_BUFFER_MIN_SIZE)
|
||||
}
|
||||
|
||||
// ZMQ_VMCI_BUFFER_MAX_SIZE: Retrieve max buffer size of the VMCI socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc51
|
||||
func (soc *Socket) GetVmciBufferMaxSize() (uint64, error) {
|
||||
if minor < 2 {
|
||||
return 0, ErrorNotImplemented42
|
||||
}
|
||||
return soc.getUInt64(C.ZMQ_VMCI_BUFFER_MAX_SIZE)
|
||||
}
|
||||
|
||||
// ZMQ_VMCI_CONNECT_TIMEOUT: Retrieve connection timeout of the VMCI socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc52
|
||||
func (soc *Socket) GetVmciConnectTimeout() (time.Duration, error) {
|
||||
if minor < 2 {
|
||||
return time.Duration(0), ErrorNotImplemented42
|
||||
}
|
||||
v, err := soc.getInt(C.ZMQ_VMCI_CONNECT_TIMEOUT)
|
||||
return time.Duration(v) * time.Millisecond, err
|
||||
}
|
||||
|
||||
// ZMQ_USE_FD: Retrieve the pre-allocated socket file descriptor
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-getsockopt#toc29
|
||||
func (soc *Socket) Getusefd() (int, error) {
|
||||
if minor < 2 {
|
||||
return 0, ErrorNotImplemented42
|
||||
}
|
||||
return soc.getInt(C.ZMQ_USE_FD)
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
package zmq4
|
||||
|
||||
/*
|
||||
#include <zmq.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// ZMQ_FD: Retrieve file descriptor associated with the socket
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-getsockopt#toc9
|
||||
func (soc *Socket) GetFd() (int, error) {
|
||||
return soc.getInt(C.ZMQ_FD)
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// +build windows
|
||||
|
||||
package zmq4
|
||||
|
||||
/*
|
||||
#include <zmq.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/*
|
||||
ZMQ_FD: Retrieve file descriptor associated with the socket
|
||||
|
||||
See: http://api.zeromq.org/4-1:zmq-getsockopt#toc9
|
||||
*/
|
||||
func (soc *Socket) GetFd() (uintptr, error) {
|
||||
value := C.SOCKET(0)
|
||||
size := C.size_t(unsafe.Sizeof(value))
|
||||
if i, err := C.zmq_getsockopt(soc.soc, C.ZMQ_FD, unsafe.Pointer(&value), &size); i != 0 {
|
||||
return uintptr(0), errget(err)
|
||||
}
|
||||
return uintptr(value), nil
|
||||
}
|
|
@ -1,800 +0,0 @@
|
|||
package zmq4
|
||||
|
||||
/*
|
||||
#include <zmq.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "zmq4.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (soc *Socket) setString(opt C.int, s string) error {
|
||||
if !soc.opened {
|
||||
return ErrorSocketClosed
|
||||
}
|
||||
cs := C.CString(s)
|
||||
defer C.free(unsafe.Pointer(cs))
|
||||
if i, err := C.zmq_setsockopt(soc.soc, opt, unsafe.Pointer(cs), C.size_t(len(s))); i != 0 {
|
||||
return errget(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (soc *Socket) setNullString(opt C.int) error {
|
||||
if !soc.opened {
|
||||
return ErrorSocketClosed
|
||||
}
|
||||
if i, err := C.zmq_setsockopt(soc.soc, opt, nil, 0); i != 0 {
|
||||
return errget(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (soc *Socket) setInt(opt C.int, value int) error {
|
||||
if !soc.opened {
|
||||
return ErrorSocketClosed
|
||||
}
|
||||
val := C.int(value)
|
||||
if i, err := C.zmq_setsockopt(soc.soc, opt, unsafe.Pointer(&val), C.size_t(unsafe.Sizeof(val))); i != 0 {
|
||||
return errget(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (soc *Socket) setInt64(opt C.int, value int64) error {
|
||||
if !soc.opened {
|
||||
return ErrorSocketClosed
|
||||
}
|
||||
val := C.int64_t(value)
|
||||
if i, err := C.zmq_setsockopt(soc.soc, opt, unsafe.Pointer(&val), C.size_t(unsafe.Sizeof(val))); i != 0 {
|
||||
return errget(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (soc *Socket) setUInt64(opt C.int, value uint64) error {
|
||||
if !soc.opened {
|
||||
return ErrorSocketClosed
|
||||
}
|
||||
val := C.uint64_t(value)
|
||||
if i, err := C.zmq_setsockopt(soc.soc, opt, unsafe.Pointer(&val), C.size_t(unsafe.Sizeof(val))); i != 0 {
|
||||
return errget(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ZMQ_SNDHWM: Set high water mark for outbound messages
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc39
|
||||
func (soc *Socket) SetSndhwm(value int) error {
|
||||
return soc.setInt(C.ZMQ_SNDHWM, value)
|
||||
}
|
||||
|
||||
// ZMQ_RCVHWM: Set high water mark for inbound messages
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc28
|
||||
func (soc *Socket) SetRcvhwm(value int) error {
|
||||
return soc.setInt(C.ZMQ_RCVHWM, value)
|
||||
}
|
||||
|
||||
// ZMQ_AFFINITY: Set I/O thread affinity
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc3
|
||||
func (soc *Socket) SetAffinity(value uint64) error {
|
||||
return soc.setUInt64(C.ZMQ_AFFINITY, value)
|
||||
}
|
||||
|
||||
// ZMQ_SUBSCRIBE: Establish message filter
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc41
|
||||
func (soc *Socket) SetSubscribe(filter string) error {
|
||||
return soc.setString(C.ZMQ_SUBSCRIBE, filter)
|
||||
}
|
||||
|
||||
// ZMQ_UNSUBSCRIBE: Remove message filter
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc47
|
||||
func (soc *Socket) SetUnsubscribe(filter string) error {
|
||||
return soc.setString(C.ZMQ_UNSUBSCRIBE, filter)
|
||||
}
|
||||
|
||||
// ZMQ_IDENTITY: Set socket identity
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc16
|
||||
func (soc *Socket) SetIdentity(value string) error {
|
||||
return soc.setString(C.ZMQ_IDENTITY, value)
|
||||
}
|
||||
|
||||
// ZMQ_RATE: Set multicast data rate
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc26
|
||||
func (soc *Socket) SetRate(value int) error {
|
||||
return soc.setInt(C.ZMQ_RATE, value)
|
||||
}
|
||||
|
||||
// ZMQ_RECOVERY_IVL: Set multicast recovery interval
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc32
|
||||
func (soc *Socket) SetRecoveryIvl(value time.Duration) error {
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_RECOVERY_IVL, val)
|
||||
}
|
||||
|
||||
// ZMQ_SNDBUF: Set kernel transmit buffer size
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc38
|
||||
func (soc *Socket) SetSndbuf(value int) error {
|
||||
return soc.setInt(C.ZMQ_SNDBUF, value)
|
||||
}
|
||||
|
||||
// ZMQ_RCVBUF: Set kernel receive buffer size
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc27
|
||||
func (soc *Socket) SetRcvbuf(value int) error {
|
||||
return soc.setInt(C.ZMQ_RCVBUF, value)
|
||||
}
|
||||
|
||||
// ZMQ_LINGER: Set linger period for socket shutdown
|
||||
//
|
||||
// For infinite, use -1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc19
|
||||
func (soc *Socket) SetLinger(value time.Duration) error {
|
||||
val := int(value / time.Millisecond)
|
||||
if value == -1 {
|
||||
val = -1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_LINGER, val)
|
||||
}
|
||||
|
||||
// ZMQ_RECONNECT_IVL: Set reconnection interval
|
||||
//
|
||||
// For no reconnection, use -1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc30
|
||||
func (soc *Socket) SetReconnectIvl(value time.Duration) error {
|
||||
val := int(value / time.Millisecond)
|
||||
if value == -1 {
|
||||
val = -1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_RECONNECT_IVL, val)
|
||||
}
|
||||
|
||||
// ZMQ_RECONNECT_IVL_MAX: Set maximum reconnection interval
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc31
|
||||
func (soc *Socket) SetReconnectIvlMax(value time.Duration) error {
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_RECONNECT_IVL_MAX, val)
|
||||
}
|
||||
|
||||
// ZMQ_BACKLOG: Set maximum length of the queue of outstanding connections
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc4
|
||||
func (soc *Socket) SetBacklog(value int) error {
|
||||
return soc.setInt(C.ZMQ_BACKLOG, value)
|
||||
}
|
||||
|
||||
// ZMQ_MAXMSGSIZE: Maximum acceptable inbound message size
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc20
|
||||
func (soc *Socket) SetMaxmsgsize(value int64) error {
|
||||
return soc.setInt64(C.ZMQ_MAXMSGSIZE, value)
|
||||
}
|
||||
|
||||
// ZMQ_MULTICAST_HOPS: Maximum network hops for multicast packets
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc21
|
||||
func (soc *Socket) SetMulticastHops(value int) error {
|
||||
return soc.setInt(C.ZMQ_MULTICAST_HOPS, value)
|
||||
}
|
||||
|
||||
// ZMQ_RCVTIMEO: Maximum time before a recv operation returns with EAGAIN
|
||||
//
|
||||
// For infinite, use -1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc29
|
||||
func (soc *Socket) SetRcvtimeo(value time.Duration) error {
|
||||
val := int(value / time.Millisecond)
|
||||
if value == -1 {
|
||||
val = -1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_RCVTIMEO, val)
|
||||
}
|
||||
|
||||
// ZMQ_SNDTIMEO: Maximum time before a send operation returns with EAGAIN
|
||||
//
|
||||
// For infinite, use -1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc40
|
||||
func (soc *Socket) SetSndtimeo(value time.Duration) error {
|
||||
val := int(value / time.Millisecond)
|
||||
if value == -1 {
|
||||
val = -1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_SNDTIMEO, val)
|
||||
}
|
||||
|
||||
// ZMQ_IPV6: Enable IPv6 on socket
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc18
|
||||
func (soc *Socket) SetIpv6(value bool) error {
|
||||
val := 0
|
||||
if value {
|
||||
val = 1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_IPV6, val)
|
||||
}
|
||||
|
||||
// ZMQ_IMMEDIATE: Queue messages only to completed connections
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc17
|
||||
func (soc *Socket) SetImmediate(value bool) error {
|
||||
val := 0
|
||||
if value {
|
||||
val = 1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_IMMEDIATE, val)
|
||||
}
|
||||
|
||||
// ZMQ_ROUTER_MANDATORY: accept only routable messages on ROUTER sockets
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc36
|
||||
func (soc *Socket) SetRouterMandatory(value int) error {
|
||||
return soc.setInt(C.ZMQ_ROUTER_MANDATORY, value)
|
||||
}
|
||||
|
||||
// ZMQ_ROUTER_RAW: switch ROUTER socket to raw mode
|
||||
//
|
||||
// This option is deprecated since ZeroMQ version 4.1, please use ZMQ_STREAM sockets instead.
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc37
|
||||
func (soc *Socket) SetRouterRaw(value int) error {
|
||||
return soc.setInt(C.ZMQ_ROUTER_RAW, value)
|
||||
}
|
||||
|
||||
// ZMQ_PROBE_ROUTER: bootstrap connections to ROUTER sockets
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc25
|
||||
func (soc *Socket) SetProbeRouter(value int) error {
|
||||
return soc.setInt(C.ZMQ_PROBE_ROUTER, value)
|
||||
}
|
||||
|
||||
// ZMQ_XPUB_VERBOSE: provide all subscription messages on XPUB sockets
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc48
|
||||
func (soc *Socket) SetXpubVerbose(value int) error {
|
||||
return soc.setInt(C.ZMQ_XPUB_VERBOSE, value)
|
||||
}
|
||||
|
||||
// ZMQ_REQ_CORRELATE: match replies with requests
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc33
|
||||
func (soc *Socket) SetReqCorrelate(value int) error {
|
||||
return soc.setInt(C.ZMQ_REQ_CORRELATE, value)
|
||||
}
|
||||
|
||||
// ZMQ_REQ_RELAXED: relax strict alternation between request and reply
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc34
|
||||
func (soc *Socket) SetReqRelaxed(value int) error {
|
||||
return soc.setInt(C.ZMQ_REQ_RELAXED, value)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_KEEPALIVE: Override SO_KEEPALIVE socket option
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc42
|
||||
func (soc *Socket) SetTcpKeepalive(value int) error {
|
||||
return soc.setInt(C.ZMQ_TCP_KEEPALIVE, value)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPCNT(or TCP_KEEPALIVE on some OS)
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc44
|
||||
func (soc *Socket) SetTcpKeepaliveIdle(value int) error {
|
||||
return soc.setInt(C.ZMQ_TCP_KEEPALIVE_IDLE, value)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_KEEPALIVE_CNT: Override TCP_KEEPCNT socket option
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc43
|
||||
func (soc *Socket) SetTcpKeepaliveCnt(value int) error {
|
||||
return soc.setInt(C.ZMQ_TCP_KEEPALIVE_CNT, value)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_KEEPALIVE_INTVL: Override TCP_KEEPINTVL socket option
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc45
|
||||
func (soc *Socket) SetTcpKeepaliveIntvl(value int) error {
|
||||
return soc.setInt(C.ZMQ_TCP_KEEPALIVE_INTVL, value)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_ACCEPT_FILTER: Assign filters to allow new TCP connections
|
||||
//
|
||||
// This option is deprecated since ZeroMQ version 4.1, please use authentication via
|
||||
// the ZAP API and IP address whitelisting / blacklisting.
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc50
|
||||
func (soc *Socket) SetTcpAcceptFilter(filter string) error {
|
||||
if len(filter) == 0 {
|
||||
return soc.setNullString(C.ZMQ_TCP_ACCEPT_FILTER)
|
||||
}
|
||||
return soc.setString(C.ZMQ_TCP_ACCEPT_FILTER, filter)
|
||||
}
|
||||
|
||||
// ZMQ_PLAIN_SERVER: Set PLAIN server role
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc23
|
||||
func (soc *Socket) SetPlainServer(value int) error {
|
||||
return soc.setInt(C.ZMQ_PLAIN_SERVER, value)
|
||||
}
|
||||
|
||||
// ZMQ_PLAIN_USERNAME: Set PLAIN security username
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc24
|
||||
func (soc *Socket) SetPlainUsername(username string) error {
|
||||
if len(username) == 0 {
|
||||
return soc.setNullString(C.ZMQ_PLAIN_USERNAME)
|
||||
}
|
||||
return soc.setString(C.ZMQ_PLAIN_USERNAME, username)
|
||||
}
|
||||
|
||||
// ZMQ_PLAIN_PASSWORD: Set PLAIN security password
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc22
|
||||
func (soc *Socket) SetPlainPassword(password string) error {
|
||||
if len(password) == 0 {
|
||||
return soc.setNullString(C.ZMQ_PLAIN_PASSWORD)
|
||||
}
|
||||
return soc.setString(C.ZMQ_PLAIN_PASSWORD, password)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_SERVER: Set CURVE server role
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc9
|
||||
func (soc *Socket) SetCurveServer(value int) error {
|
||||
return soc.setInt(C.ZMQ_CURVE_SERVER, value)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_PUBLICKEY: Set CURVE public key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc7
|
||||
func (soc *Socket) SetCurvePublickey(key string) error {
|
||||
return soc.setString(C.ZMQ_CURVE_PUBLICKEY, key)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_SECRETKEY: Set CURVE secret key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc8
|
||||
func (soc *Socket) SetCurveSecretkey(key string) error {
|
||||
return soc.setString(C.ZMQ_CURVE_SECRETKEY, key)
|
||||
}
|
||||
|
||||
// ZMQ_CURVE_SERVERKEY: Set CURVE server key
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc10
|
||||
func (soc *Socket) SetCurveServerkey(key string) error {
|
||||
return soc.setString(C.ZMQ_CURVE_SERVERKEY, key)
|
||||
}
|
||||
|
||||
// ZMQ_ZAP_DOMAIN: Set RFC 27 authentication domain
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc49
|
||||
func (soc *Socket) SetZapDomain(domain string) error {
|
||||
return soc.setString(C.ZMQ_ZAP_DOMAIN, domain)
|
||||
}
|
||||
|
||||
// ZMQ_CONFLATE: Keep only last message
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc6
|
||||
func (soc *Socket) SetConflate(value bool) error {
|
||||
val := 0
|
||||
if value {
|
||||
val = 1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_CONFLATE, val)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// New in ZeroMQ 4.1.0
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// + : yes
|
||||
// D : deprecated
|
||||
// implemented documented test
|
||||
// ZMQ_ROUTER_HANDOVER + +
|
||||
// ZMQ_TOS + +
|
||||
// ZMQ_IPC_FILTER_PID D
|
||||
// ZMQ_IPC_FILTER_UID D
|
||||
// ZMQ_IPC_FILTER_GID D
|
||||
// ZMQ_CONNECT_RID + +
|
||||
// ZMQ_GSSAPI_SERVER + +
|
||||
// ZMQ_GSSAPI_PRINCIPAL + +
|
||||
// ZMQ_GSSAPI_SERVICE_PRINCIPAL + +
|
||||
// ZMQ_GSSAPI_PLAINTEXT + +
|
||||
// ZMQ_HANDSHAKE_IVL + +
|
||||
// ZMQ_SOCKS_PROXY +
|
||||
// ZMQ_XPUB_NODROP +
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// ZMQ_ROUTER_HANDOVER: handle duplicate client identities on ROUTER sockets
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc35
|
||||
func (soc *Socket) SetRouterHandover(value bool) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
val := 0
|
||||
if value {
|
||||
val = 1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_ROUTER_HANDOVER, val)
|
||||
}
|
||||
|
||||
// ZMQ_TOS: Set the Type-of-Service on socket
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc46
|
||||
func (soc *Socket) SetTos(value int) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
return soc.setInt(C.ZMQ_TOS, value)
|
||||
}
|
||||
|
||||
// ZMQ_CONNECT_RID: Assign the next outbound connection id
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc5
|
||||
func (soc *Socket) SetConnectRid(value string) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
if value == "" {
|
||||
return soc.setNullString(C.ZMQ_CONNECT_RID)
|
||||
}
|
||||
return soc.setString(C.ZMQ_CONNECT_RID, value)
|
||||
}
|
||||
|
||||
// ZMQ_GSSAPI_SERVER: Set GSSAPI server role
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc13
|
||||
func (soc *Socket) SetGssapiServer(value bool) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
val := 0
|
||||
if value {
|
||||
val = 1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_GSSAPI_SERVER, val)
|
||||
}
|
||||
|
||||
// ZMQ_GSSAPI_PRINCIPAL: Set name of GSSAPI principal
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc12
|
||||
func (soc *Socket) SetGssapiPrincipal(value string) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
return soc.setString(C.ZMQ_GSSAPI_PRINCIPAL, value)
|
||||
}
|
||||
|
||||
// ZMQ_GSSAPI_SERVICE_PRINCIPAL: Set name of GSSAPI service principal
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc14
|
||||
func (soc *Socket) SetGssapiServicePrincipal(value string) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
return soc.setString(C.ZMQ_GSSAPI_SERVICE_PRINCIPAL, value)
|
||||
}
|
||||
|
||||
// ZMQ_GSSAPI_PLAINTEXT: Disable GSSAPI encryption
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc11
|
||||
func (soc *Socket) SetGssapiPlaintext(value bool) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
val := 0
|
||||
if value {
|
||||
val = 1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_GSSAPI_PLAINTEXT, val)
|
||||
}
|
||||
|
||||
// ZMQ_HANDSHAKE_IVL: Set maximum handshake interval
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-1:zmq-setsockopt#toc15
|
||||
func (soc *Socket) SetHandshakeIvl(value time.Duration) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_HANDSHAKE_IVL, val)
|
||||
}
|
||||
|
||||
// ZMQ_SOCKS_PROXY: NOT DOCUMENTED
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
func (soc *Socket) SetSocksProxy(value string) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
if value == "" {
|
||||
return soc.setNullString(C.ZMQ_SOCKS_PROXY)
|
||||
}
|
||||
return soc.setString(C.ZMQ_SOCKS_PROXY, value)
|
||||
}
|
||||
|
||||
// Available since ZeroMQ 4.1, documented since ZeroMQ 4.2
|
||||
|
||||
// ZMQ_XPUB_NODROP: do not silently drop messages if SENDHWM is reached
|
||||
//
|
||||
// Returns ErrorNotImplemented41 with ZeroMQ version < 4.1
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc60
|
||||
func (soc *Socket) SetXpubNodrop(value bool) error {
|
||||
if minor < 1 {
|
||||
return ErrorNotImplemented41
|
||||
}
|
||||
val := 0
|
||||
if value {
|
||||
val = 1
|
||||
}
|
||||
return soc.setInt(C.ZMQ_XPUB_NODROP, val)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// New in ZeroMQ 4.2.0
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// + : yes
|
||||
// o : getsockopt only
|
||||
// implemented documented test
|
||||
// ZMQ_BLOCKY
|
||||
// ZMQ_XPUB_MANUAL + +
|
||||
// ZMQ_XPUB_WELCOME_MSG + +
|
||||
// ZMQ_STREAM_NOTIFY + +
|
||||
// ZMQ_INVERT_MATCHING + +
|
||||
// ZMQ_HEARTBEAT_IVL + +
|
||||
// ZMQ_HEARTBEAT_TTL + +
|
||||
// ZMQ_HEARTBEAT_TIMEOUT + +
|
||||
// ZMQ_XPUB_VERBOSER + +
|
||||
// ZMQ_CONNECT_TIMEOUT + +
|
||||
// ZMQ_TCP_MAXRT + +
|
||||
// ZMQ_THREAD_SAFE o
|
||||
// ZMQ_MULTICAST_MAXTPDU + +
|
||||
// ZMQ_VMCI_BUFFER_SIZE + +
|
||||
// ZMQ_VMCI_BUFFER_MIN_SIZE + +
|
||||
// ZMQ_VMCI_BUFFER_MAX_SIZE + +
|
||||
// ZMQ_VMCI_CONNECT_TIMEOUT + +
|
||||
// ZMQ_USE_FD + +
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// ZMQ_XPUB_MANUAL: change the subscription handling to manual
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc59
|
||||
func (soc *Socket) SetXpubManual(value int) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setInt(C.ZMQ_XPUB_MANUAL, value)
|
||||
}
|
||||
|
||||
// ZMQ_XPUB_WELCOME_MSG: set welcome message that will be received by subscriber when connecting
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc61
|
||||
func (soc *Socket) SetXpubWelcomeMsg(value string) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
if value == "" {
|
||||
return soc.setNullString(C.ZMQ_XPUB_WELCOME_MSG)
|
||||
}
|
||||
return soc.setString(C.ZMQ_XPUB_WELCOME_MSG, value)
|
||||
}
|
||||
|
||||
// ZMQ_STREAM_NOTIFY: send connect and disconnect notifications
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc48
|
||||
func (soc *Socket) SetStreamNotify(value int) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setInt(C.ZMQ_STREAM_NOTIFY, value)
|
||||
}
|
||||
|
||||
// ZMQ_INVERT_MATCHING: Invert message filtering
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc22
|
||||
func (soc *Socket) SetInvertMatching(value int) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setInt(C.ZMQ_INVERT_MATCHING, value)
|
||||
}
|
||||
|
||||
// ZMQ_HEARTBEAT_IVL: Set interval between sending ZMTP heartbeats
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc17
|
||||
func (soc *Socket) SetHeartbeatIvl(value time.Duration) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_HEARTBEAT_IVL, val)
|
||||
}
|
||||
|
||||
// ZMQ_HEARTBEAT_TTL: Set the TTL value for ZMTP heartbeats
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc19
|
||||
func (soc *Socket) SetHeartbeatTtl(value time.Duration) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_HEARTBEAT_TTL, val)
|
||||
}
|
||||
|
||||
// ZMQ_HEARTBEAT_TIMEOUT: Set timeout for ZMTP heartbeats
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc18
|
||||
func (soc *Socket) SetHeartbeatTimeout(value time.Duration) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_HEARTBEAT_TIMEOUT, val)
|
||||
}
|
||||
|
||||
// ZMQ_XPUB_VERBOSER: pass subscribe and unsubscribe messages on XPUB socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc58
|
||||
func (soc *Socket) SetXpubVerboser(value int) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setInt(C.ZMQ_XPUB_VERBOSER, value)
|
||||
}
|
||||
|
||||
// ZMQ_CONNECT_TIMEOUT: Set connect() timeout
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc7
|
||||
func (soc *Socket) SetConnectTimeout(value time.Duration) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_CONNECT_TIMEOUT, val)
|
||||
}
|
||||
|
||||
// ZMQ_TCP_MAXRT: Set TCP Maximum Retransmit Timeout
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc54
|
||||
func (soc *Socket) SetTcpMaxrt(value time.Duration) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_TCP_MAXRT, val)
|
||||
}
|
||||
|
||||
// ZMQ_MULTICAST_MAXTPDU: Maximum transport data unit size for multicast packets
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc27
|
||||
func (soc *Socket) SetMulticastMaxtpdu(value int) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setInt(C.ZMQ_MULTICAST_MAXTPDU, value)
|
||||
}
|
||||
|
||||
// ZMQ_VMCI_BUFFER_SIZE: Set buffer size of the VMCI socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc68
|
||||
func (soc *Socket) SetVmciBufferSize(value uint64) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setUInt64(C.ZMQ_VMCI_BUFFER_SIZE, value)
|
||||
}
|
||||
|
||||
// ZMQ_VMCI_BUFFER_MIN_SIZE: Set min buffer size of the VMCI socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc69
|
||||
func (soc *Socket) SetVmciBufferMinSize(value uint64) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setUInt64(C.ZMQ_VMCI_BUFFER_MIN_SIZE, value)
|
||||
}
|
||||
|
||||
// ZMQ_VMCI_BUFFER_MAX_SIZE: Set max buffer size of the VMCI socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc70
|
||||
func (soc *Socket) SetVmciBufferMaxSize(value uint64) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setUInt64(C.ZMQ_VMCI_BUFFER_MAX_SIZE, value)
|
||||
}
|
||||
|
||||
// ZMQ_VMCI_CONNECT_TIMEOUT: Set connection timeout of the VMCI socket
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc71
|
||||
func (soc *Socket) SetVmciConnectTimeout(value time.Duration) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
val := int(value / time.Millisecond)
|
||||
return soc.setInt(C.ZMQ_VMCI_CONNECT_TIMEOUT, val)
|
||||
}
|
||||
|
||||
// ZMQ_USE_FD: Set the pre-allocated socket file descriptor
|
||||
//
|
||||
// Returns ErrorNotImplemented42 with ZeroMQ version < 4.2
|
||||
//
|
||||
// See: http://api.zeromq.org/4-2:zmq-setsockopt#toc31
|
||||
func (soc *Socket) SetUseFd(value int) error {
|
||||
if minor < 2 {
|
||||
return ErrorNotImplemented42
|
||||
}
|
||||
return soc.setInt(C.ZMQ_USE_FD, value)
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
package zmq4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
/*
|
||||
Send multi-part message on socket.
|
||||
|
||||
Any `[]string' or `[][]byte' is split into separate `string's or `[]byte's
|
||||
|
||||
Any other part that isn't a `string' or `[]byte' is converted
|
||||
to `string' with `fmt.Sprintf("%v", part)'.
|
||||
|
||||
Returns total bytes sent.
|
||||
*/
|
||||
func (soc *Socket) SendMessage(parts ...interface{}) (total int, err error) {
|
||||
return soc.sendMessage(0, parts...)
|
||||
}
|
||||
|
||||
/*
|
||||
Like SendMessage(), but adding the DONTWAIT flag.
|
||||
*/
|
||||
func (soc *Socket) SendMessageDontwait(parts ...interface{}) (total int, err error) {
|
||||
return soc.sendMessage(DONTWAIT, parts...)
|
||||
}
|
||||
|
||||
func (soc *Socket) sendMessage(dontwait Flag, parts ...interface{}) (total int, err error) {
|
||||
|
||||
var last int
|
||||
PARTS:
|
||||
for last = len(parts) - 1; last >= 0; last-- {
|
||||
switch t := parts[last].(type) {
|
||||
case []string:
|
||||
if len(t) > 0 {
|
||||
break PARTS
|
||||
}
|
||||
case [][]byte:
|
||||
if len(t) > 0 {
|
||||
break PARTS
|
||||
}
|
||||
default:
|
||||
break PARTS
|
||||
}
|
||||
}
|
||||
|
||||
opt := SNDMORE | dontwait
|
||||
for i := 0; i <= last; i++ {
|
||||
if i == last {
|
||||
opt = dontwait
|
||||
}
|
||||
switch t := parts[i].(type) {
|
||||
case []string:
|
||||
opt = SNDMORE | dontwait
|
||||
n := len(t) - 1
|
||||
for j, s := range t {
|
||||
if j == n && i == last {
|
||||
opt = dontwait
|
||||
}
|
||||
c, e := soc.Send(s, opt)
|
||||
if e == nil {
|
||||
total += c
|
||||
} else {
|
||||
return -1, e
|
||||
}
|
||||
}
|
||||
case [][]byte:
|
||||
opt = SNDMORE | dontwait
|
||||
n := len(t) - 1
|
||||
for j, b := range t {
|
||||
if j == n && i == last {
|
||||
opt = dontwait
|
||||
}
|
||||
c, e := soc.SendBytes(b, opt)
|
||||
if e == nil {
|
||||
total += c
|
||||
} else {
|
||||
return -1, e
|
||||
}
|
||||
}
|
||||
case string:
|
||||
c, e := soc.Send(t, opt)
|
||||
if e == nil {
|
||||
total += c
|
||||
} else {
|
||||
return -1, e
|
||||
}
|
||||
case []byte:
|
||||
c, e := soc.SendBytes(t, opt)
|
||||
if e == nil {
|
||||
total += c
|
||||
} else {
|
||||
return -1, e
|
||||
}
|
||||
default:
|
||||
c, e := soc.Send(fmt.Sprintf("%v", t), opt)
|
||||
if e == nil {
|
||||
total += c
|
||||
} else {
|
||||
return -1, e
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Receive parts as message from socket.
|
||||
|
||||
Returns last non-nil error code.
|
||||
*/
|
||||
func (soc *Socket) RecvMessage(flags Flag) (msg []string, err error) {
|
||||
msg = make([]string, 0)
|
||||
for {
|
||||
s, e := soc.Recv(flags)
|
||||
if e == nil {
|
||||
msg = append(msg, s)
|
||||
} else {
|
||||
return msg[0:0], e
|
||||
}
|
||||
more, e := soc.GetRcvmore()
|
||||
if e == nil {
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
return msg[0:0], e
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Receive parts as message from socket.
|
||||
|
||||
Returns last non-nil error code.
|
||||
*/
|
||||
func (soc *Socket) RecvMessageBytes(flags Flag) (msg [][]byte, err error) {
|
||||
msg = make([][]byte, 0)
|
||||
for {
|
||||
b, e := soc.RecvBytes(flags)
|
||||
if e == nil {
|
||||
msg = append(msg, b)
|
||||
} else {
|
||||
return msg[0:0], e
|
||||
}
|
||||
more, e := soc.GetRcvmore()
|
||||
if e == nil {
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
return msg[0:0], e
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Receive parts as message from socket, including metadata.
|
||||
|
||||
Metadata is picked from the first message part.
|
||||
|
||||
For details about metadata, see RecvWithMetadata().
|
||||
|
||||
Returns last non-nil error code.
|
||||
*/
|
||||
func (soc *Socket) RecvMessageWithMetadata(flags Flag, properties ...string) (msg []string, metadata map[string]string, err error) {
|
||||
b, p, err := soc.RecvMessageBytesWithMetadata(flags, properties...)
|
||||
m := make([]string, len(b))
|
||||
for i, bt := range b {
|
||||
m[i] = string(bt)
|
||||
}
|
||||
return m, p, err
|
||||
}
|
||||
|
||||
/*
|
||||
Receive parts as message from socket, including metadata.
|
||||
|
||||
Metadata is picked from the first message part.
|
||||
|
||||
For details about metadata, see RecvBytesWithMetadata().
|
||||
|
||||
Returns last non-nil error code.
|
||||
*/
|
||||
func (soc *Socket) RecvMessageBytesWithMetadata(flags Flag, properties ...string) (msg [][]byte, metadata map[string]string, err error) {
|
||||
bb := make([][]byte, 0)
|
||||
b, p, err := soc.RecvBytesWithMetadata(flags, properties...)
|
||||
if err != nil {
|
||||
return bb, p, err
|
||||
}
|
||||
for {
|
||||
bb = append(bb, b)
|
||||
|
||||
var more bool
|
||||
more, err = soc.GetRcvmore()
|
||||
if err != nil || !more {
|
||||
break
|
||||
}
|
||||
b, err = soc.RecvBytes(flags)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return bb, p, err
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,62 +0,0 @@
|
|||
#if ZMQ_VERSION_MAJOR != 4
|
||||
|
||||
#error "You need ZeroMQ version 4 to build this"
|
||||
|
||||
#endif
|
||||
|
||||
#if ZMQ_VERSION_MINOR < 1
|
||||
|
||||
#define ZMQ_CONNECT_RID -1
|
||||
#define ZMQ_GSSAPI -1
|
||||
#define ZMQ_GSSAPI_PLAINTEXT -1
|
||||
#define ZMQ_GSSAPI_PRINCIPAL -1
|
||||
#define ZMQ_GSSAPI_SERVER -1
|
||||
#define ZMQ_GSSAPI_SERVICE_PRINCIPAL -1
|
||||
#define ZMQ_HANDSHAKE_IVL -1
|
||||
#define ZMQ_IPC_FILTER_GID -1
|
||||
#define ZMQ_IPC_FILTER_PID -1
|
||||
#define ZMQ_IPC_FILTER_UID -1
|
||||
#define ZMQ_ROUTER_HANDOVER -1
|
||||
#define ZMQ_SOCKS_PROXY -1
|
||||
#define ZMQ_THREAD_PRIORITY -1
|
||||
#define ZMQ_THREAD_SCHED_POLICY -1
|
||||
#define ZMQ_TOS -1
|
||||
#define ZMQ_XPUB_NODROP -1
|
||||
|
||||
#endif
|
||||
|
||||
#if ZMQ_VERSION_MINOR < 2
|
||||
|
||||
#define ZMQ_MAX_MSGSZ -1
|
||||
|
||||
#define ZMQ_BLOCKY -1
|
||||
#define ZMQ_XPUB_MANUAL -1
|
||||
#define ZMQ_XPUB_WELCOME_MSG -1
|
||||
#define ZMQ_STREAM_NOTIFY -1
|
||||
#define ZMQ_INVERT_MATCHING -1
|
||||
#define ZMQ_HEARTBEAT_IVL -1
|
||||
#define ZMQ_HEARTBEAT_TTL -1
|
||||
#define ZMQ_HEARTBEAT_TIMEOUT -1
|
||||
#define ZMQ_XPUB_VERBOSER -1
|
||||
#define ZMQ_CONNECT_TIMEOUT -1
|
||||
#define ZMQ_TCP_MAXRT -1
|
||||
#define ZMQ_THREAD_SAFE -1
|
||||
#define ZMQ_MULTICAST_MAXTPDU -1
|
||||
#define ZMQ_VMCI_BUFFER_SIZE -1
|
||||
#define ZMQ_VMCI_BUFFER_MIN_SIZE -1
|
||||
#define ZMQ_VMCI_BUFFER_MAX_SIZE -1
|
||||
#define ZMQ_VMCI_CONNECT_TIMEOUT -1
|
||||
#define ZMQ_USE_FD -1
|
||||
|
||||
#define ZMQ_GROUP_MAX_LENGTH -1
|
||||
|
||||
#define ZMQ_POLLPRI -1
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef ZMQ_ROUTING_ID
|
||||
#define ZMQ_ROUTING_ID ZMQ_IDENTITY
|
||||
#endif
|
||||
#ifndef ZMQ_CONNECT_ROUTING_ID
|
||||
#define ZMQ_CONNECT_ROUTING_ID ZMQ_CONNECT_RID
|
||||
#endif
|
|
@ -26,8 +26,6 @@ github.com/golang/protobuf/ptypes/timestamp
|
|||
github.com/konsorten/go-windows-terminal-sequences
|
||||
# github.com/mattn/go-sqlite3 v1.10.0
|
||||
github.com/mattn/go-sqlite3
|
||||
# github.com/pebbe/zmq4 v1.0.0
|
||||
github.com/pebbe/zmq4
|
||||
# github.com/pkg/errors v0.8.0
|
||||
github.com/pkg/errors
|
||||
# github.com/sirupsen/logrus v1.2.0
|
||||
|
|
Loading…
Reference in New Issue