diff --git a/services/logger/logger.go b/services/logger/logger.go index 2b0306f5..a15d429b 100644 --- a/services/logger/logger.go +++ b/services/logger/logger.go @@ -3,7 +3,9 @@ package logger import ( "bytes" "encoding/json" + "errors" "fmt" + "io" "log" "os" "runtime" @@ -14,9 +16,17 @@ import ( "time" "github.com/untangle/golang-shared/services/overseer" + "github.com/untangle/golang-shared/util" ) -const logConfigFile = "/tmp/logconfig.js" +// Config struct retains information about the where the log level map is stored, default log levels and writer that should be used +type Config struct { + FileLocation string + LogLevelMap map[string]string + OutputWriter io.Writer +} + +var config Config var logLevelName = [...]string{"EMERG", "ALERT", "CRIT", "ERROR", "WARN", "NOTICE", "INFO", "DEBUG", "TRACE"} var logLevelMap map[string]*int32 @@ -52,16 +62,26 @@ const LogLevelDebug int32 = 7 const LogLevelTrace int32 = 8 // Startup starts the logging service -func Startup() { +func Startup(newConfig Config) { + config = newConfig + err := validateConfig() + if err != nil { + Err("Logger Configuration is invalid: %s\n", err.Error()) + return + } + // capture startup time launchTime = time.Now() // create the map and load the Log configuration - logLevelMap = make(map[string]*int32) loadLoggerConfig() // Set system logger to use our logger - log.SetOutput(NewLogWriter("system")) + if config.OutputWriter != nil { + log.SetOutput(config.OutputWriter) + } else { + log.SetOutput(DefaultLogWriter("system")) + } } // Shutdown stops the logging service @@ -191,8 +211,8 @@ type LogWriter struct { source string } -// NewLogWriter creates an io Writer to steam output to the Log facility -func NewLogWriter(name string) *LogWriter { +// DefaultLogWriter creates an io Writer to steam output to the Log facility +func DefaultLogWriter(name string) *LogWriter { writer := new(LogWriter) writer.buffer = make([]byte, 0) writer.source = name @@ -331,23 +351,37 @@ func logMessage(level int32, format string, args ...interface{}) { } } +// validateConfig ensures all the log levels set in config.LogLevelMap are valid +func validateConfig() error { + if config.FileLocation == "" { + return errors.New("FileLocation must be set") + } + for key, value := range config.LogLevelMap { + if !util.ContainsString(logLevelName[:], value) { + return fmt.Errorf("%s is using an incorrect log level: %s", key, value) + } + } + return nil +} + // loadLoggerConfig loads the logger configuration file func loadLoggerConfig() { var file *os.File var info os.FileInfo var err error + logLevelMap = make(map[string]*int32) // open the logger configuration file - file, err = os.Open(logConfigFile) + file, err = os.Open(config.FileLocation) // if there was an error create the config and try the open again if err != nil { - initLoggerConfig() - file, err = os.Open(logConfigFile) + writeLoggerConfigToJSON() + file, err = os.Open(config.FileLocation) // if there is still an error we are out of options if err != nil { - Err("Unable to load Log configuration file: %s\n", logConfigFile) + Err("Unable to load Log configuration file: %s\n", config.FileLocation) return } } @@ -363,7 +397,7 @@ func loadLoggerConfig() { } // read the raw configuration json from the file - config := make(map[string]string) + serviceMap := make(map[string]string) var data = make([]byte, info.Size()) len, err := file.Read(data) @@ -373,14 +407,14 @@ func loadLoggerConfig() { } // unmarshal the configuration into a map - err = json.Unmarshal(data, &config) + err = json.Unmarshal(data, &serviceMap) if err != nil { Err("Unable to parse Log configuration\n") return } // put the name/string pairs from the file into the name/int lookup map we us in the Log function - for cfgname, cfglevel := range config { + for cfgname, cfglevel := range serviceMap { // ignore any comment strings that start and end with underscore if strings.HasPrefix(cfgname, "_") && strings.HasSuffix(cfgname, "_") { continue @@ -402,71 +436,18 @@ func loadLoggerConfig() { } } -func initLoggerConfig() { - Alert("Log configuration not found. Creating default file: %s\n", logConfigFile) - - // create a comment that shows all valid log level names - var comment string - for item, element := range logLevelName { - if item != 0 { - comment += "|" - } - comment += element - } - - // make a map and fill it with a default log level for every package - config := make(map[string]string) - config["_FileVersion_"] = "200" - config["_ValidLevels_"] = comment - - // plugins - config["certfetch"] = "INFO" - config["certsniff"] = "INFO" - config["classify"] = "INFO" - config["dns"] = "INFO" - config["example"] = "INFO" - config["geoip"] = "INFO" - config["predicttraffic"] = "INFO" - config["reporter"] = "INFO" - config["revdns"] = "INFO" - config["sni"] = "INFO" - config["stats"] = "INFO" - config["threatprevention"] = "INFO" - config["sitefilter"] = "INFO" - - // services - config["certcache"] = "INFO" - config["certmanager"] = "INFO" - config["dict"] = "INFO" - config["dispatch"] = "INFO" - config["kernel"] = "INFO" - config["logger"] = "INFO" - config["netspace"] = "INFO" - config["overseer"] = "INFO" - config["predicttrafficsvc"] = "INFO" - config["reports"] = "INFO" - config["restd"] = "INFO" - config["settings"] = "INFO" - config["webroot"] = "INFO" - - // static source names used in the low level c handlers - config["common"] = "INFO" - config["conntrack"] = "INFO" - config["netlogger"] = "INFO" - config["nfqueue"] = "INFO" - config["warehouse"] = "INFO" - config["system"] = "INFO" - config["gin"] = "INFO" +func writeLoggerConfigToJSON() { + Alert("Log configuration not found. Creating default File: %s\n", config.FileLocation) // convert the config map to a json object - jstr, err := json.MarshalIndent(config, "", "") + jstr, err := json.MarshalIndent(config.LogLevelMap, "", "") if err != nil { Alert("Log failure creating default configuration: %s\n", err.Error()) return } // create the logger configuration file - file, err := os.Create(logConfigFile) + file, err := os.Create(config.FileLocation) if err != nil { return } diff --git a/util/util.go b/util/util.go new file mode 100644 index 00000000..7d575a28 --- /dev/null +++ b/util/util.go @@ -0,0 +1,11 @@ +package util + +// ContainsString checks if a string is contained in an array of strings +func ContainsString(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/vendor/github.com/pebbe/zmq4/LICENSE.txt b/vendor/github.com/pebbe/zmq4/LICENSE.txt new file mode 100644 index 00000000..76950f8a --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/LICENSE.txt @@ -0,0 +1,25 @@ +Copyright (c) 2013-2018, 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. diff --git a/vendor/github.com/pebbe/zmq4/README.md b/vendor/github.com/pebbe/zmq4/README.md new file mode 100644 index 00000000..417c8ff9 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/README.md @@ -0,0 +1,108 @@ +A Go interface to [ZeroMQ](http://www.zeromq.org/) version 4. + + +---------------------------------------------------------------- + +## Warning + +Starting with Go 1.14, on Unix-like systems, you will get a lot of +interrupted signal calls. See the top of a package documentation +for a fix. + +---------------------------------------------------------------- + + +[![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 + +## Requirements + +zmq4 is just a wrapper for the ZeroMQ library. It doesn't include the +library itself. So you need to have ZeroMQ installed, including its +development files. On Linux and Darwin you can check this with (`$` is +the command prompt): + +``` +$ pkg-config --modversion libzmq +4.3.1 +``` + +The Go compiler must be able to compile C code. You can check this +with: +``` +$ go env CGO_ENABLED +1 +``` + +You can't do cross-compilation. That would disable C. + +## 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". diff --git a/vendor/github.com/pebbe/zmq4/auth.go b/vendor/github.com/pebbe/zmq4/auth.go new file mode 100644 index 00000000..aa2465f3 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/auth.go @@ -0,0 +1,647 @@ +/* + +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 +#include + +#include "zmq4.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.zmq4_curve_public(public, secret); int(i) != 0 { + return "", errget(err) + } + z85PublicKey = C.GoString(public) + return z85PublicKey, nil +} diff --git a/vendor/github.com/pebbe/zmq4/ctxoptions_unix.go b/vendor/github.com/pebbe/zmq4/ctxoptions_unix.go new file mode 100644 index 00000000..c980cd18 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/ctxoptions_unix.go @@ -0,0 +1,56 @@ +// +build !windows + +package zmq4 + +/* +#include +#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) +} diff --git a/vendor/github.com/pebbe/zmq4/ctxoptions_windows.go b/vendor/github.com/pebbe/zmq4/ctxoptions_windows.go new file mode 100644 index 00000000..b9760139 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/ctxoptions_windows.go @@ -0,0 +1,44 @@ +// +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 +} diff --git a/vendor/github.com/pebbe/zmq4/doc.go b/vendor/github.com/pebbe/zmq4/doc.go new file mode 100644 index 00000000..93a66005 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/doc.go @@ -0,0 +1,58 @@ +/* +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. + +---- + +Since Go 1.14 you will get a lot of interrupted system calls. + +See: https://golang.org/doc/go1.14#runtime + +There are two options to prevent this. + +The first option is to build your program with the environment variable: + + GODEBUG=asyncpreemptoff=1 + +The second option is to let the program retry after an interrupted system call. + +Initially, this is set to true, for the global context, and for contexts +created with NewContext(). + +When you install a signal handler, for instance to handle Ctrl-C, you should +probably clear this option in your signal handler. For example: + + zctx, _ := zmq.NewContext() + + ctx, cancel := context.WithCancel(context.Background()) + + go func() { + chSignal := make(chan os.Signal, 1) + signal.Notify(chSignal, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM) + <-chSignal + zmq4.SetRetryAfterEINTR(false) + zctx.SetRetryAfterEINTR(false) + cancel() + }() + +---- + +*/ +package zmq4 diff --git a/vendor/github.com/pebbe/zmq4/dummy.c b/vendor/github.com/pebbe/zmq4/dummy.c new file mode 100644 index 00000000..0fca94d0 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/dummy.c @@ -0,0 +1,5 @@ +/* + +You need CGO_ENABLED=1 to build this package + +*/ diff --git a/vendor/github.com/pebbe/zmq4/errors.go b/vendor/github.com/pebbe/zmq4/errors.go new file mode 100644 index 00000000..21a1900d --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/errors.go @@ -0,0 +1,103 @@ +package zmq4 + +/* +#include +*/ +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) +} + +func (ctx *Context) retry(err error) bool { + if !ctx.retryEINTR || err == nil { + return false + } + eno, ok := err.(syscall.Errno) + if !ok { + return false + } + return eno == syscall.EINTR +} diff --git a/vendor/github.com/pebbe/zmq4/polling.go b/vendor/github.com/pebbe/zmq4/polling.go new file mode 100644 index 00000000..70343564 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/polling.go @@ -0,0 +1,198 @@ +package zmq4 + +/* +#include +#include "zmq4.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)) + + var ctx *Context + for _, soc := range p.socks { + if !soc.opened { + return lst, ErrorSocketClosed + } + // assume all sockets have the same context + ctx = soc.ctx + } + + t := timeout + if t > 0 { + t = t / time.Millisecond + } + if t < 0 { + t = -1 + } + var rv C.int + var err error + for { + rv, err = C.zmq4_poll(&p.items[0], C.int(len(p.items)), C.long(t)) + if rv >= 0 || ctx == nil || !ctx.retry(err) { + break + } + } + 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) +} diff --git a/vendor/github.com/pebbe/zmq4/reactor.go b/vendor/github.com/pebbe/zmq4/reactor.go new file mode 100644 index 00000000..3d5a974b --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/reactor.go @@ -0,0 +1,200 @@ +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) + +Warning: + +There are problems with the reactor showing up with Go 1.14 (and later) +such as data race occurrences and code lock-up. Using SetRetryAfterEINTR +seems an effective fix, but at the moment there is no guaranty. +*/ +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: %v\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 +} diff --git a/vendor/github.com/pebbe/zmq4/socketget.go b/vendor/github.com/pebbe/zmq4/socketget.go new file mode 100644 index 00000000..a413860f --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/socketget.go @@ -0,0 +1,688 @@ +package zmq4 + +/* +#include +#include +#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) + var i C.int + var err error + for { + i, err = C.zmq4_getsockopt(soc.soc, opt, unsafe.Pointer(&value[0]), &size) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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) + var i C.int + var err error + for { + i, err = C.zmq4_getsockopt(soc.soc, opt, unsafe.Pointer(&value[0]), &size) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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)) + var i C.int + var err error + for { + i, err = C.zmq4_getsockopt(soc.soc, opt, unsafe.Pointer(&value), &size) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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)) + var i C.int + var err error + for { + i, err = C.zmq4_getsockopt(soc.soc, opt, unsafe.Pointer(&value), &size) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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)) + var i C.int + var err error + for { + i, err = C.zmq4_getsockopt(soc.soc, opt, unsafe.Pointer(&value), &size) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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) +} diff --git a/vendor/github.com/pebbe/zmq4/socketget_unix.go b/vendor/github.com/pebbe/zmq4/socketget_unix.go new file mode 100644 index 00000000..2671b33b --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/socketget_unix.go @@ -0,0 +1,15 @@ +// +build !windows + +package zmq4 + +/* +#include +*/ +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) +} diff --git a/vendor/github.com/pebbe/zmq4/socketget_windows.go b/vendor/github.com/pebbe/zmq4/socketget_windows.go new file mode 100644 index 00000000..5f82610c --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/socketget_windows.go @@ -0,0 +1,39 @@ +// +build windows + +package zmq4 + +/* +#include +#include +#include "zmq4.h" +*/ +import "C" + +// winsock2.h needed for ZeroMQ version 4.3.3 + +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)) + var i C.int + var err error + for { + i, err = C.zmq4_getsockopt(soc.soc, C.ZMQ_FD, unsafe.Pointer(&value), &size) + // not really necessary because Windows doesn't have EINTR + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if i != 0 { + return uintptr(0), errget(err) + } + return uintptr(value), nil +} diff --git a/vendor/github.com/pebbe/zmq4/socketset.go b/vendor/github.com/pebbe/zmq4/socketset.go new file mode 100644 index 00000000..1a9a22f1 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/socketset.go @@ -0,0 +1,840 @@ +package zmq4 + +/* +#include +#include +#include +#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)) + var i C.int + var err error + for { + i, err = C.zmq4_setsockopt(soc.soc, opt, unsafe.Pointer(cs), C.size_t(len(s))) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if i != 0 { + return errget(err) + } + return nil +} + +func (soc *Socket) setNullString(opt C.int) error { + if !soc.opened { + return ErrorSocketClosed + } + var i C.int + var err error + for { + i, err = C.zmq4_setsockopt(soc.soc, opt, nil, 0) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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) + var i C.int + var err error + for { + i, err = C.zmq4_setsockopt(soc.soc, opt, unsafe.Pointer(&val), C.size_t(unsafe.Sizeof(val))) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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) + var i C.int + var err error + for { + i, err = C.zmq4_setsockopt(soc.soc, opt, unsafe.Pointer(&val), C.size_t(unsafe.Sizeof(val))) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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) + var i C.int + var err error + for { + i, err = C.zmq4_setsockopt(soc.soc, opt, unsafe.Pointer(&val), C.size_t(unsafe.Sizeof(val))) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if 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) +} diff --git a/vendor/github.com/pebbe/zmq4/utils.go b/vendor/github.com/pebbe/zmq4/utils.go new file mode 100644 index 00000000..3a0fa458 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/utils.go @@ -0,0 +1,206 @@ +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 +} diff --git a/vendor/github.com/pebbe/zmq4/wrappers_unix.go b/vendor/github.com/pebbe/zmq4/wrappers_unix.go new file mode 100644 index 00000000..db941b31 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/wrappers_unix.go @@ -0,0 +1,130 @@ +// +build !windows + +package zmq4 + +/* + +#include +#include + +#if ZMQ_VERSION_MINOR < 2 +// Version < 4.2.x +#include +int zmq_curve_public (char *z85_public_key, const char *z85_secret_key); +#endif // Version < 4.2.x + +#if ZMQ_VERSION_MINOR < 1 +const char *zmq_msg_gets (zmq_msg_t *msg, const char *property); +#if ZMQ_VERSION_PATCH < 5 +// Version < 4.0.5 +int zmq_proxy_steerable (const void *frontend, const void *backend, const void *capture, const void *control); +#endif // Version < 4.0.5 +#endif // Version == 4.0.x + +int zmq4_bind (void *socket, const char *endpoint) +{ + return zmq_bind(socket, endpoint); +} + +int zmq4_close (void *socket) +{ + return zmq_close(socket); +} + +int zmq4_connect (void *socket, const char *endpoint) +{ + return zmq_connect(socket, endpoint); +} + +int zmq4_ctx_get (void *context, int option_name) +{ + return zmq_ctx_get(context, option_name); +} + +void *zmq4_ctx_new () +{ + return zmq_ctx_new(); +} + +int zmq4_ctx_set (void *context, int option_name, int option_value) +{ + return zmq_ctx_set(context, option_name, option_value); +} + +int zmq4_ctx_term (void *context) +{ + return zmq_ctx_term(context); +} + +int zmq4_curve_keypair (char *z85_public_key, char *z85_secret_key) +{ + return zmq_curve_keypair(z85_public_key, z85_secret_key); +} + +int zmq4_curve_public (char *z85_public_key, char *z85_secret_key) +{ + return zmq_curve_public(z85_public_key, z85_secret_key); +} + +int zmq4_disconnect (void *socket, const char *endpoint) +{ + return zmq_disconnect(socket, endpoint); +} + +int zmq4_getsockopt (void *socket, int option_name, void *option_value, size_t *option_len) +{ + return zmq_getsockopt(socket, option_name, option_value, option_len); +} + +const char *zmq4_msg_gets (zmq_msg_t *message, const char *property) +{ + return zmq_msg_gets(message, property); +} + +int zmq4_msg_recv (zmq_msg_t *msg, void *socket, int flags) +{ + return zmq_msg_recv(msg, socket, flags); +} + +int zmq4_poll (zmq_pollitem_t *items, int nitems, long timeout) +{ + return zmq_poll(items, nitems, timeout); +} + +int zmq4_proxy (void *frontend, void *backend, void *capture) +{ + return zmq_proxy(frontend, backend, capture); +} + +int zmq4_proxy_steerable (void *frontend, void *backend, void *capture, void *control) +{ + return zmq_proxy_steerable(frontend, backend, capture, control); +} + +int zmq4_send (void *socket, void *buf, size_t len, int flags) +{ + return zmq_send(socket, buf, len, flags); +} + +int zmq4_setsockopt (void *socket, int option_name, const void *option_value, size_t option_len) +{ + return zmq_setsockopt(socket, option_name, option_value, option_len); +} + +void *zmq4_socket (void *context, int type) +{ + return zmq_socket(context, type); +} + +int zmq4_socket_monitor (void *socket, char *endpoint, int events) +{ + return zmq_socket_monitor(socket, endpoint, events); +} + +int zmq4_unbind (void *socket, const char *endpoint) +{ + return zmq_unbind(socket, endpoint); +} + +*/ +import "C" diff --git a/vendor/github.com/pebbe/zmq4/wrappers_windows.go b/vendor/github.com/pebbe/zmq4/wrappers_windows.go new file mode 100644 index 00000000..3742c70d --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/wrappers_windows.go @@ -0,0 +1,213 @@ +// +build windows + +package zmq4 + +/* + +#include +#include + +#if ZMQ_VERSION_MINOR < 2 +// Version < 4.2.x +#include +int zmq_curve_public (char *z85_public_key, const char *z85_secret_key); +#endif // Version < 4.2.x + +#if ZMQ_VERSION_MINOR < 1 +const char *zmq_msg_gets (zmq_msg_t *msg, const char *property); +#if ZMQ_VERSION_PATCH < 5 +// Version < 4.0.5 +int zmq_proxy_steerable (const void *frontend, const void *backend, const void *capture, const void *control); +#endif // Version < 4.0.5 +#endif // Version == 4.0.x + +int zmq4_bind (void *socket, const char *endpoint) +{ + int i; + i = zmq_bind(socket, endpoint); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_close (void *socket) +{ + int i; + i = zmq_close(socket); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_connect (void *socket, const char *endpoint) +{ + int i; + i = zmq_connect(socket, endpoint); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_ctx_get (void *context, int option_name) +{ + int i; + i = zmq_ctx_get(context, option_name); + if (i < 0) + errno = zmq_errno(); + return i; +} + +void *zmq4_ctx_new () +{ + void *v; + v = zmq_ctx_new(); + if (v == NULL) + errno = zmq_errno(); + return v; +} + +int zmq4_ctx_set (void *context, int option_name, int option_value) +{ + int i; + i = zmq_ctx_set(context, option_name, option_value); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_ctx_term (void *context) +{ + int i; + i = zmq_ctx_term(context); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_curve_keypair (char *z85_public_key, char *z85_secret_key) +{ + int i; + i = zmq_curve_keypair(z85_public_key, z85_secret_key); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_curve_public (char *z85_public_key, char *z85_secret_key) +{ + int i; + i = zmq_curve_public(z85_public_key, z85_secret_key); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_disconnect (void *socket, const char *endpoint) +{ + int i; + i = zmq_disconnect(socket, endpoint); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_getsockopt (void *socket, int option_name, void *option_value, size_t *option_len) +{ + int i; + i = zmq_getsockopt(socket, option_name, option_value, option_len); + if (i < 0) + errno = zmq_errno(); + return i; +} + +const char *zmq4_msg_gets (zmq_msg_t *message, const char *property) +{ + const char *s; + s = zmq_msg_gets(message, property); + if (s == NULL) + errno = zmq_errno(); + return s; +} + +int zmq4_msg_recv (zmq_msg_t *msg, void *socket, int flags) +{ + int i; + i = zmq_msg_recv(msg, socket, flags); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_poll (zmq_pollitem_t *items, int nitems, long timeout) +{ + int i; + i = zmq_poll(items, nitems, timeout); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_proxy (void *frontend, void *backend, void *capture) +{ + int i; + i = zmq_proxy(frontend, backend, capture); + errno = zmq_errno(); + return i; +} + +int zmq4_proxy_steerable (void *frontend, void *backend, void *capture, void *control) +{ + int i; + i = zmq_proxy_steerable(frontend, backend, capture, control); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_send (void *socket, void *buf, size_t len, int flags) +{ + int i; + i = zmq_send(socket, buf, len, flags); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_setsockopt (void *socket, int option_name, const void *option_value, size_t option_len) +{ + int i; + i = zmq_setsockopt(socket, option_name, option_value, option_len); + if (i < 0) + errno = zmq_errno(); + return i; +} + +void *zmq4_socket (void *context, int type) +{ + void *v; + v = zmq_socket(context, type); + if (v == NULL) + errno = zmq_errno(); + return v; +} + +int zmq4_socket_monitor (void *socket, char *endpoint, int events) +{ + int i; + i = zmq_socket_monitor(socket, endpoint, events); + if (i < 0) + errno = zmq_errno(); + return i; +} + +int zmq4_unbind (void *socket, const char *endpoint) +{ + int i; + i = zmq_unbind(socket, endpoint); + if (i < 0) + errno = zmq_errno(); + return i; +} + +*/ +import "C" diff --git a/vendor/github.com/pebbe/zmq4/zmq4.go b/vendor/github.com/pebbe/zmq4/zmq4.go new file mode 100644 index 00000000..1c296b1f --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/zmq4.go @@ -0,0 +1,1530 @@ +package zmq4 + +/* +#cgo !windows pkg-config: libzmq +#cgo windows CFLAGS: -I/usr/local/include +#cgo windows LDFLAGS: -L/usr/local/lib -lzmq +#include +#if ZMQ_VERSION_MINOR < 2 +#include +#endif +#include +#include +#include "zmq4.h" + +int + zmq4_major = ZMQ_VERSION_MAJOR, + zmq4_minor = ZMQ_VERSION_MINOR, + zmq4_patch = ZMQ_VERSION_PATCH; + +#if ZMQ_VERSION_MINOR > 0 +// Version >= 4.1.x + +typedef struct { + uint16_t event; // id of the event as bitfield + int32_t value; // value is either error code, fd or reconnect interval +} zmq_event_t; + +#else +// Version == 4.0.x + +const char *zmq_msg_gets (zmq_msg_t *msg, const char *property) { + return NULL; +} + +int zmq_has (const char *capability) { + return 0; +} + +#if ZMQ_VERSION_PATCH < 5 +// Version < 4.0.5 + +int zmq_proxy_steerable (const void *frontend, const void *backend, const void *capture, const void *control) { + return -1; +} + +#endif // Version < 4.0.5 + +#endif // Version == 4.0.x + +void zmq4_get_event40(zmq_msg_t *msg, int *ev, int *val) { + zmq_event_t event; + const char* data = (char*)zmq_msg_data(msg); + memcpy(&(event.event), data, sizeof(event.event)); + memcpy(&(event.value), data+sizeof(event.event), sizeof(event.value)); + *ev = (int)(event.event); + *val = (int)(event.value); +} +void zmq4_get_event41(zmq_msg_t *msg, int *ev, int *val) { + uint8_t *data = (uint8_t *) zmq_msg_data (msg); + uint16_t event = *(uint16_t *) (data); + *ev = (int)event; + *val = (int)(*(uint32_t *) (data + 2)); +} +void *zmq4_memcpy(void *dest, const void *src, size_t n) { + return memcpy(dest, src, n); +} +*/ +import "C" + +import ( + "errors" + "fmt" + "runtime" + "strings" + "unsafe" +) + +var ( + defaultCtx *Context + + major, minor, patch int + + ErrorContextClosed = errors.New("Context is closed") + ErrorSocketClosed = errors.New("Socket is closed") + ErrorMoreExpected = errors.New("More expected") + ErrorNotImplemented405 = errors.New("Not implemented, requires 0MQ version 4.0.5") + ErrorNotImplemented41 = errors.New("Not implemented, requires 0MQ version 4.1") + ErrorNotImplemented42 = errors.New("Not implemented, requires 0MQ version 4.2") + ErrorNotImplementedWindows = errors.New("Not implemented on Windows") + ErrorNoSocket = errors.New("No such socket") + + initVersionError error + initContextError error + + // api compatibility, based on changes in header files + api = map[[2]int]int{ + [2]int{0, 0}: 1, + [2]int{0, 1}: 2, + [2]int{0, 2}: 3, + [2]int{0, 3}: 3, + [2]int{0, 4}: 3, + [2]int{0, 5}: 4, + [2]int{0, 6}: 4, + [2]int{0, 7}: 4, + [2]int{0, 8}: 4, + [2]int{0, 9}: 4, + [2]int{0, 10}: 4, + [2]int{1, 0}: 5, + [2]int{1, 1}: 6, + [2]int{1, 2}: 6, + [2]int{1, 3}: 6, + [2]int{1, 4}: 6, + [2]int{1, 5}: 6, + [2]int{1, 6}: 7, + [2]int{1, 7}: 7, + [2]int{1, 8}: 7, + [2]int{2, 0}: 8, + [2]int{2, 1}: 9, + [2]int{2, 2}: 9, + [2]int{2, 3}: 9, + [2]int{2, 4}: 9, + [2]int{2, 5}: 9, + [2]int{3, 0}: 10, + [2]int{3, 1}: 10, + [2]int{3, 2}: 10, + [2]int{3, 3}: 10, + } +) + +func init() { + major, minor, patch = Version() + if major != 4 { + initVersionError = fmt.Errorf("Using zmq4 with ZeroMQ major version %d", major) + return + } + + v, ok1 := api[[2]int{minor, patch}] + w, ok2 := api[[2]int{int(C.zmq4_minor), int(C.zmq4_patch)}] + if v != w || !ok1 || !ok2 { + if major != int(C.zmq4_major) || minor != int(C.zmq4_minor) || patch != int(C.zmq4_patch) { + initVersionError = + fmt.Errorf( + "zmq4 was installed with ZeroMQ version %d.%d.%d, but the application links with version %d.%d.%d", + int(C.zmq4_major), int(C.zmq4_minor), int(C.zmq4_patch), + major, minor, patch) + return + } + } + + var err error + defaultCtx = &Context{} + defaultCtx.ctx, err = C.zmq4_ctx_new() + if defaultCtx.ctx == nil { + initContextError = fmt.Errorf("Init of ZeroMQ context failed: %v", errget(err)) + return + } + defaultCtx.opened = true + defaultCtx.retryEINTR = true +} + +//. Util + +// Report 0MQ library version. +func Version() (major, minor, patch int) { + if initVersionError != nil { + return 0, 0, 0 + } + var maj, min, pat C.int + C.zmq_version(&maj, &min, &pat) + return int(maj), int(min), int(pat) +} + +// Get 0MQ error message string. +func Error(e int) string { + return C.GoString(C.zmq_strerror(C.int(e))) +} + +//. Context + +const ( + MaxSocketsDflt = int(C.ZMQ_MAX_SOCKETS_DFLT) + IoThreadsDflt = int(C.ZMQ_IO_THREADS_DFLT) +) + +/* +A context that is not the default context. +*/ +type Context struct { + ctx unsafe.Pointer + retryEINTR bool + opened bool + err error +} + +// Create a new context. +func NewContext() (ctx *Context, err error) { + if initVersionError != nil { + return nil, initVersionError + } + ctx = &Context{} + c, e := C.zmq4_ctx_new() + if c == nil { + err = errget(e) + ctx.err = err + } else { + ctx.ctx = c + ctx.retryEINTR = true + ctx.opened = true + runtime.SetFinalizer(ctx, (*Context).Term) + } + return +} + +/* +Terminates the default context. + +For linger behavior, see: http://api.zeromq.org/4-1:zmq-ctx-term +*/ +func Term() error { + if initVersionError != nil { + return initVersionError + } + if initContextError != nil { + return initContextError + } + return defaultCtx.Term() +} + +/* +Terminates the context. + +For linger behavior, see: http://api.zeromq.org/4-1:zmq-ctx-term +*/ +func (ctx *Context) Term() error { + if ctx.opened { + ctx.opened = false + var n C.int + var err error + for { + n, err = C.zmq4_ctx_term(ctx.ctx) + if n == 0 || !ctx.retry(err) { + break + } + } + if n != 0 { + ctx.err = errget(err) + } + } + return ctx.err +} + +func getOption(ctx *Context, o C.int) (int, error) { + if !ctx.opened { + return 0, ErrorContextClosed + } + nc, err := C.zmq4_ctx_get(ctx.ctx, o) + n := int(nc) + if n < 0 { + return n, errget(err) + } + return n, nil +} + +// Returns the size of the 0MQ thread pool in the default context. +func GetIoThreads() (int, error) { + if initVersionError != nil { + return 0, initVersionError + } + if initContextError != nil { + return 0, initContextError + } + return defaultCtx.GetIoThreads() +} + +// Returns the size of the 0MQ thread pool. +func (ctx *Context) GetIoThreads() (int, error) { + return getOption(ctx, C.ZMQ_IO_THREADS) +} + +// Returns the maximum number of sockets allowed in the default context. +func GetMaxSockets() (int, error) { + if initVersionError != nil { + return 0, initVersionError + } + if initContextError != nil { + return 0, initContextError + } + return defaultCtx.GetMaxSockets() +} + +// Returns the maximum number of sockets allowed. +func (ctx *Context) GetMaxSockets() (int, error) { + return getOption(ctx, C.ZMQ_MAX_SOCKETS) +} + +/* +Returns the maximum message size in the default context. + +Returns ErrorNotImplemented42 with ZeroMQ version < 4.2 +*/ +func GetMaxMsgsz() (int, error) { + if initVersionError != nil { + return 0, initVersionError + } + if initContextError != nil { + return 0, initContextError + } + return defaultCtx.GetMaxMsgsz() +} + +/* +Returns the maximum message size. + +Returns ErrorNotImplemented42 with ZeroMQ version < 4.2 +*/ +func (ctx *Context) GetMaxMsgsz() (int, error) { + if minor < 2 { + return 0, ErrorNotImplemented42 + } + return getOption(ctx, C.ZMQ_MAX_MSGSZ) +} + +// Returns the IPv6 option in the default context. +func GetIpv6() (bool, error) { + if initVersionError != nil { + return false, initVersionError + } + if initContextError != nil { + return false, initContextError + } + return defaultCtx.GetIpv6() +} + +// Returns the IPv6 option. +func (ctx *Context) GetIpv6() (bool, error) { + i, e := getOption(ctx, C.ZMQ_IPV6) + if i == 0 { + return false, e + } + return true, e +} + +/* +Returns the blocky setting in the default context. + +Returns ErrorNotImplemented42 with ZeroMQ version < 4.2 +*/ +func GetBlocky() (bool, error) { + if initVersionError != nil { + return false, initVersionError + } + if initContextError != nil { + return false, initContextError + } + return defaultCtx.GetBlocky() +} + +/* +Returns the blocky setting. + +Returns ErrorNotImplemented42 with ZeroMQ version < 4.2 +*/ +func (ctx *Context) GetBlocky() (bool, error) { + if minor < 2 { + return false, ErrorNotImplemented42 + } + i, e := getOption(ctx, C.ZMQ_BLOCKY) + if i == 0 { + return false, e + } + return true, e +} + +/* +Returns the retry after EINTR setting in the default context. +*/ +func GetRetryAfterEINTR() bool { + return defaultCtx.GetRetryAfterEINTR() +} + +/* +Returns the retry after EINTR setting. +*/ +func (ctx *Context) GetRetryAfterEINTR() bool { + return ctx.retryEINTR +} + +func setOption(ctx *Context, o C.int, n int) error { + if !ctx.opened { + return ErrorContextClosed + } + i, err := C.zmq4_ctx_set(ctx.ctx, o, C.int(n)) + if int(i) != 0 { + return errget(err) + } + return nil +} + +/* +Specifies the size of the 0MQ thread pool to handle I/O operations in +the default context. If your application is using only the inproc +transport for messaging you may set this to zero, otherwise set it to at +least one. This option only applies before creating any sockets. + +Default value: 1 +*/ +func SetIoThreads(n int) error { + if initVersionError != nil { + return initVersionError + } + if initContextError != nil { + return initContextError + } + return defaultCtx.SetIoThreads(n) +} + +/* +Specifies the size of the 0MQ thread pool to handle I/O operations. If +your application is using only the inproc transport for messaging you +may set this to zero, otherwise set it to at least one. This option only +applies before creating any sockets. + +Default value: 1 +*/ +func (ctx *Context) SetIoThreads(n int) error { + return setOption(ctx, C.ZMQ_IO_THREADS, n) +} + +/* +Sets the scheduling policy for default 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 SetThreadSchedPolicy(n int) error { + if initVersionError != nil { + return initVersionError + } + if initContextError != nil { + return initContextError + } + return defaultCtx.SetThreadSchedPolicy(n) +} + +/* +Sets scheduling priority for default 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 SetThreadPriority(n int) error { + if initVersionError != nil { + return initVersionError + } + if initContextError != nil { + return initContextError + } + return defaultCtx.SetThreadPriority(n) +} + +/* +Set maximum message size in the default context. + +Default value: INT_MAX + +Returns ErrorNotImplemented42 with ZeroMQ version < 4.2 +*/ +func SetMaxMsgsz(n int) error { + if initVersionError != nil { + return initVersionError + } + if initContextError != nil { + return initContextError + } + return defaultCtx.SetMaxMsgsz(n) +} + +/* +Set maximum message size. + +Default value: INT_MAX + +Returns ErrorNotImplemented42 with ZeroMQ version < 4.2 +*/ +func (ctx *Context) SetMaxMsgsz(n int) error { + if minor < 2 { + return ErrorNotImplemented42 + } + return setOption(ctx, C.ZMQ_MAX_MSGSZ, n) +} + +/* +Sets the maximum number of sockets allowed in the default context. + +Default value: 1024 +*/ +func SetMaxSockets(n int) error { + if initVersionError != nil { + return initVersionError + } + if initContextError != nil { + return initContextError + } + return defaultCtx.SetMaxSockets(n) +} + +/* +Sets the maximum number of sockets allowed. + +Default value: 1024 +*/ +func (ctx *Context) SetMaxSockets(n int) error { + return setOption(ctx, C.ZMQ_MAX_SOCKETS, n) +} + +/* +Sets the IPv6 value for all sockets created in the default context from this point onwards. +A value of true means IPv6 is enabled, while false means the socket will use only IPv4. +When IPv6 is enabled, a socket will connect to, or accept connections from, both IPv4 and IPv6 hosts. + +Default value: false +*/ +func SetIpv6(i bool) error { + if initVersionError != nil { + return initVersionError + } + if initContextError != nil { + return initContextError + } + return defaultCtx.SetIpv6(i) +} + +/* +Sets the IPv6 value for all sockets created in the context from this point onwards. +A value of true means IPv6 is enabled, while false means the socket will use only IPv4. +When IPv6 is enabled, a socket will connect to, or accept connections from, both IPv4 and IPv6 hosts. + +Default value: false +*/ +func (ctx *Context) SetIpv6(i bool) error { + n := 0 + if i { + n = 1 + } + return setOption(ctx, C.ZMQ_IPV6, n) +} + +/* +Sets the blocky behavior in the default context. + +See: http://api.zeromq.org/4-2:zmq-ctx-set#toc3 + +Returns ErrorNotImplemented42 with ZeroMQ version < 4.2 +*/ +func SetBlocky(i bool) error { + if initVersionError != nil { + return initVersionError + } + if initContextError != nil { + return initContextError + } + return defaultCtx.SetBlocky(i) +} + +/* +Sets the blocky behavior. + +See: http://api.zeromq.org/4-2:zmq-ctx-set#toc3 + +Returns ErrorNotImplemented42 with ZeroMQ version < 4.2 +*/ +func (ctx *Context) SetBlocky(i bool) error { + if minor < 2 { + return ErrorNotImplemented42 + } + n := 0 + if i { + n = 1 + } + return setOption(ctx, C.ZMQ_BLOCKY, n) +} + +/* +Sets the retry after EINTR setting in the default context. + +Initital value is true. +*/ +func SetRetryAfterEINTR(retry bool) { + defaultCtx.SetRetryAfterEINTR(retry) +} + +/* +Sets the retry after EINTR setting. + +Initital value is true. +*/ +func (ctx *Context) SetRetryAfterEINTR(retry bool) { + ctx.retryEINTR = retry +} + +//. Sockets + +// Specifies the type of a socket, used by NewSocket() +type Type int + +const ( + // Constants for NewSocket() + // See: http://api.zeromq.org/4-1:zmq-socket#toc3 + REQ = Type(C.ZMQ_REQ) + REP = Type(C.ZMQ_REP) + DEALER = Type(C.ZMQ_DEALER) + ROUTER = Type(C.ZMQ_ROUTER) + PUB = Type(C.ZMQ_PUB) + SUB = Type(C.ZMQ_SUB) + XPUB = Type(C.ZMQ_XPUB) + XSUB = Type(C.ZMQ_XSUB) + PUSH = Type(C.ZMQ_PUSH) + PULL = Type(C.ZMQ_PULL) + PAIR = Type(C.ZMQ_PAIR) + STREAM = Type(C.ZMQ_STREAM) +) + +/* +Socket type as string. +*/ +func (t Type) String() string { + switch t { + case REQ: + return "REQ" + case REP: + return "REP" + case DEALER: + return "DEALER" + case ROUTER: + return "ROUTER" + case PUB: + return "PUB" + case SUB: + return "SUB" + case XPUB: + return "XPUB" + case XSUB: + return "XSUB" + case PUSH: + return "PUSH" + case PULL: + return "PULL" + case PAIR: + return "PAIR" + case STREAM: + return "STREAM" + } + return "" +} + +// Used by (*Socket)Send() and (*Socket)Recv() +type Flag int + +const ( + // Flags for (*Socket)Send(), (*Socket)Recv() + // For Send, see: http://api.zeromq.org/4-1:zmq-send#toc2 + // For Recv, see: http://api.zeromq.org/4-1:zmq-msg-recv#toc2 + DONTWAIT = Flag(C.ZMQ_DONTWAIT) + SNDMORE = Flag(C.ZMQ_SNDMORE) +) + +/* +Socket flag as string. +*/ +func (f Flag) String() string { + ff := make([]string, 0) + if f&DONTWAIT != 0 { + ff = append(ff, "DONTWAIT") + } + if f&SNDMORE != 0 { + ff = append(ff, "SNDMORE") + } + if len(ff) == 0 { + return "" + } + return strings.Join(ff, "|") +} + +// Used by (*Socket)Monitor() and (*Socket)RecvEvent() +type Event int + +const ( + // Flags for (*Socket)Monitor() and (*Socket)RecvEvent() + // See: http://api.zeromq.org/4-3:zmq-socket-monitor#toc3 + EVENT_ALL = Event(C.ZMQ_EVENT_ALL) + EVENT_CONNECTED = Event(C.ZMQ_EVENT_CONNECTED) + EVENT_CONNECT_DELAYED = Event(C.ZMQ_EVENT_CONNECT_DELAYED) + EVENT_CONNECT_RETRIED = Event(C.ZMQ_EVENT_CONNECT_RETRIED) + EVENT_LISTENING = Event(C.ZMQ_EVENT_LISTENING) + EVENT_BIND_FAILED = Event(C.ZMQ_EVENT_BIND_FAILED) + EVENT_ACCEPTED = Event(C.ZMQ_EVENT_ACCEPTED) + EVENT_ACCEPT_FAILED = Event(C.ZMQ_EVENT_ACCEPT_FAILED) + EVENT_CLOSED = Event(C.ZMQ_EVENT_CLOSED) + EVENT_CLOSE_FAILED = Event(C.ZMQ_EVENT_CLOSE_FAILED) + EVENT_DISCONNECTED = Event(C.ZMQ_EVENT_DISCONNECTED) + EVENT_MONITOR_STOPPED = Event(C.ZMQ_EVENT_MONITOR_STOPPED) + EVENT_HANDSHAKE_FAILED_NO_DETAIL = Event(C.ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL) + EVENT_HANDSHAKE_SUCCEEDED = Event(C.ZMQ_EVENT_HANDSHAKE_SUCCEEDED) + EVENT_HANDSHAKE_FAILED_PROTOCOL = Event(C.ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL) + EVENT_HANDSHAKE_FAILED_AUTH = Event(C.ZMQ_EVENT_HANDSHAKE_FAILED_AUTH) +) + +/* +Socket event as string. +*/ +func (e Event) String() string { + if e == EVENT_ALL { + return "EVENT_ALL" + } + ee := make([]string, 0) + if e&EVENT_CONNECTED != 0 { + ee = append(ee, "EVENT_CONNECTED") + } + if e&EVENT_CONNECT_DELAYED != 0 { + ee = append(ee, "EVENT_CONNECT_DELAYED") + } + if e&EVENT_CONNECT_RETRIED != 0 { + ee = append(ee, "EVENT_CONNECT_RETRIED") + } + if e&EVENT_LISTENING != 0 { + ee = append(ee, "EVENT_LISTENING") + } + if e&EVENT_BIND_FAILED != 0 { + ee = append(ee, "EVENT_BIND_FAILED") + } + if e&EVENT_ACCEPTED != 0 { + ee = append(ee, "EVENT_ACCEPTED") + } + if e&EVENT_ACCEPT_FAILED != 0 { + ee = append(ee, "EVENT_ACCEPT_FAILED") + } + if e&EVENT_CLOSED != 0 { + ee = append(ee, "EVENT_CLOSED") + } + if e&EVENT_CLOSE_FAILED != 0 { + ee = append(ee, "EVENT_CLOSE_FAILED") + } + if e&EVENT_DISCONNECTED != 0 { + ee = append(ee, "EVENT_DISCONNECTED") + } + if minor >= 3 { + if e&EVENT_HANDSHAKE_FAILED_NO_DETAIL != 0 { + ee = append(ee, "EVENT_HANDSHAKE_FAILED_NO_DETAIL") + } + if e&EVENT_HANDSHAKE_SUCCEEDED != 0 { + ee = append(ee, "EVENT_HANDSHAKE_SUCCEEDED") + } + if e&EVENT_HANDSHAKE_FAILED_PROTOCOL != 0 { + ee = append(ee, "EVENT_HANDSHAKE_FAILED_PROTOCOL") + } + if e&EVENT_HANDSHAKE_FAILED_AUTH != 0 { + ee = append(ee, "EVENT_HANDSHAKE_FAILED_AUTH") + } + } + if len(ee) == 0 { + return "" + } + return strings.Join(ee, "|") +} + +// Used by (soc *Socket)GetEvents() +type State int + +const ( + // Flags for (*Socket)GetEvents() + // See: http://api.zeromq.org/4-1:zmq-getsockopt#toc8 + POLLIN = State(C.ZMQ_POLLIN) + POLLOUT = State(C.ZMQ_POLLOUT) +) + +/* +Socket state as string. +*/ +func (s State) String() string { + ss := make([]string, 0) + if s&POLLIN != 0 { + ss = append(ss, "POLLIN") + } + if s&POLLOUT != 0 { + ss = append(ss, "POLLOUT") + } + if len(ss) == 0 { + return "" + } + return strings.Join(ss, "|") +} + +// Specifies the security mechanism, used by (*Socket)GetMechanism() +type Mechanism int + +const ( + // Constants for (*Socket)GetMechanism() + // See: http://api.zeromq.org/4-1:zmq-getsockopt#toc22 + NULL = Mechanism(C.ZMQ_NULL) + PLAIN = Mechanism(C.ZMQ_PLAIN) + CURVE = Mechanism(C.ZMQ_CURVE) + GSSAPI = Mechanism(C.ZMQ_GSSAPI) +) + +/* +Security mechanism as string. +*/ +func (m Mechanism) String() string { + switch m { + case NULL: + return "NULL" + case PLAIN: + return "PLAIN" + case CURVE: + return "CURVE" + case GSSAPI: + return "GSSAPI" + } + return "" +} + +/* +Socket functions starting with `Set` or `Get` are used for setting and +getting socket options. +*/ +type Socket struct { + soc unsafe.Pointer + ctx *Context + opened bool + err error +} + +/* +Socket as string. +*/ +func (soc Socket) String() string { + if !soc.opened { + return "Socket(CLOSED)" + } + t, err := soc.GetType() + if err != nil { + return fmt.Sprintf("Socket(%v)", err) + } + i, err := soc.GetIdentity() + if err == nil && i != "" { + return fmt.Sprintf("Socket(%v,%q)", t, i) + } + return fmt.Sprintf("Socket(%v,%p)", t, soc.soc) +} + +/* +Create 0MQ socket in the default context. + +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. + +For a description of socket types, see: http://api.zeromq.org/4-1:zmq-socket#toc3 +*/ +func NewSocket(t Type) (soc *Socket, err error) { + if initVersionError != nil { + return nil, initVersionError + } + if initContextError != nil { + return nil, initContextError + } + return defaultCtx.NewSocket(t) +} + +/* +Create 0MQ socket in the given context. + +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. + +For a description of socket types, see: http://api.zeromq.org/4-1:zmq-socket#toc3 +*/ +func (ctx *Context) NewSocket(t Type) (soc *Socket, err error) { + soc = &Socket{} + if !ctx.opened { + return soc, ErrorContextClosed + } + var s unsafe.Pointer + var e error + for { + s, e = C.zmq4_socket(ctx.ctx, C.int(t)) + if s != nil || !ctx.retry(e) { + break + } + } + if s == nil { + err = errget(e) + soc.err = err + } else { + soc.soc = s + soc.ctx = ctx + soc.opened = true + runtime.SetFinalizer(soc, (*Socket).Close) + } + return +} + +// If not called explicitly, the socket will be closed on garbage collection +func (soc *Socket) Close() error { + if soc.opened { + soc.opened = false + var i C.int + var err error + for { + i, err = C.zmq4_close(soc.soc) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if int(i) != 0 { + soc.err = errget(err) + } + soc.soc = unsafe.Pointer(nil) + soc.ctx = nil + } + return soc.err +} + +// Return the context associated with a socket +func (soc *Socket) Context() (*Context, error) { + if !soc.opened { + return nil, ErrorSocketClosed + } + return soc.ctx, nil +} + +/* +Accept incoming connections on a socket. + +For a description of endpoint, see: http://api.zeromq.org/4-1:zmq-bind#toc2 +*/ +func (soc *Socket) Bind(endpoint string) error { + if !soc.opened { + return ErrorSocketClosed + } + s := C.CString(endpoint) + defer C.free(unsafe.Pointer(s)) + var i C.int + var err error + for { + i, err = C.zmq4_bind(soc.soc, s) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if int(i) != 0 { + return errget(err) + } + return nil +} + +/* +Stop accepting connections on a socket. + +For a description of endpoint, see: http://api.zeromq.org/4-1:zmq-bind#toc2 +*/ +func (soc *Socket) Unbind(endpoint string) error { + if !soc.opened { + return ErrorSocketClosed + } + s := C.CString(endpoint) + defer C.free(unsafe.Pointer(s)) + var i C.int + var err error + for { + i, err = C.zmq4_unbind(soc.soc, s) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if int(i) != 0 { + return errget(err) + } + return nil +} + +/* +Create outgoing connection from socket. + +For a description of endpoint, see: http://api.zeromq.org/4-1:zmq-connect#toc2 +*/ +func (soc *Socket) Connect(endpoint string) error { + if !soc.opened { + return ErrorSocketClosed + } + s := C.CString(endpoint) + defer C.free(unsafe.Pointer(s)) + var i C.int + var err error + for { + i, err = C.zmq4_connect(soc.soc, s) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if int(i) != 0 { + return errget(err) + } + return nil +} + +/* +Disconnect a socket. + +For a description of endpoint, see: http://api.zeromq.org/4-1:zmq-disconnect#toc2 +*/ +func (soc *Socket) Disconnect(endpoint string) error { + if !soc.opened { + return ErrorSocketClosed + } + s := C.CString(endpoint) + defer C.free(unsafe.Pointer(s)) + var i C.int + var err error + for { + i, err = C.zmq4_disconnect(soc.soc, s) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if int(i) != 0 { + return errget(err) + } + return nil +} + +/* +Receive a message part from a socket. + +For a description of flags, see: http://api.zeromq.org/4-1:zmq-msg-recv#toc2 +*/ +func (soc *Socket) Recv(flags Flag) (string, error) { + b, err := soc.RecvBytes(flags) + return string(b), err +} + +/* +Receive a message part from a socket. + +For a description of flags, see: http://api.zeromq.org/4-1:zmq-msg-recv#toc2 +*/ +func (soc *Socket) RecvBytes(flags Flag) ([]byte, error) { + if !soc.opened { + return []byte{}, ErrorSocketClosed + } + var msg C.zmq_msg_t + C.zmq_msg_init(&msg) + defer C.zmq_msg_close(&msg) + + var size C.int + var err error + for { + size, err = C.zmq4_msg_recv(&msg, soc.soc, C.int(flags)) + if size >= 0 || !soc.ctx.retry(err) { + break + } + } + if size < 0 { + return []byte{}, errget(err) + } + if size == 0 { + return []byte{}, nil + } + data := make([]byte, int(size)) + C.zmq4_memcpy(unsafe.Pointer(&data[0]), C.zmq_msg_data(&msg), C.size_t(size)) + return data, nil +} + +/* +Send a message part on a socket. + +For a description of flags, see: http://api.zeromq.org/4-1:zmq-send#toc2 +*/ +func (soc *Socket) Send(data string, flags Flag) (int, error) { + return soc.SendBytes([]byte(data), flags) +} + +/* +Send a message part on a socket. + +For a description of flags, see: http://api.zeromq.org/4-1:zmq-send#toc2 +*/ +func (soc *Socket) SendBytes(data []byte, flags Flag) (int, error) { + if !soc.opened { + return 0, ErrorSocketClosed + } + d := data + if len(data) == 0 { + d = []byte{0} + } + var size C.int + var err error + for { + size, err = C.zmq4_send(soc.soc, unsafe.Pointer(&d[0]), C.size_t(len(data)), C.int(flags)) + if size >= 0 || !soc.ctx.retry(err) { + break + } + } + if size < 0 { + return int(size), errget(err) + } + return int(size), nil +} + +/* +Register a monitoring callback. + +See: http://api.zeromq.org/4-1:zmq-socket-monitor#toc2 + +WARNING: Closing a context with a monitoring callback will lead to random crashes. +This is a bug in the ZeroMQ library. +The monitoring callback has the same context as the socket it was created for. + +Example: + + package main + + import ( + zmq "github.com/pebbe/zmq4" + "log" + "time" + ) + + func rep_socket_monitor(addr string) { + s, err := zmq.NewSocket(zmq.PAIR) + if err != nil { + log.Fatalln(err) + } + err = s.Connect(addr) + if err != nil { + log.Fatalln(err) + } + for { + a, b, c, err := s.RecvEvent(0) + if err != nil { + log.Println(err) + break + } + log.Println(a, b, c) + } + s.Close() + } + + func main() { + + // REP socket + rep, err := zmq.NewSocket(zmq.REP) + if err != nil { + log.Fatalln(err) + } + + // REP socket monitor, all events + err = rep.Monitor("inproc://monitor.rep", zmq.EVENT_ALL) + if err != nil { + log.Fatalln(err) + } + go rep_socket_monitor("inproc://monitor.rep") + + // Generate an event + rep.Bind("tcp://*:5555") + if err != nil { + log.Fatalln(err) + } + + // Allow some time for event detection + time.Sleep(time.Second) + + rep.Close() + zmq.Term() + } +*/ +func (soc *Socket) Monitor(addr string, events Event) error { + if !soc.opened { + return ErrorSocketClosed + } + if addr == "" { + var i C.int + var err error + for { + i, err = C.zmq4_socket_monitor(soc.soc, nil, C.int(events)) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if i != 0 { + return errget(err) + } + return nil + } + + s := C.CString(addr) + defer C.free(unsafe.Pointer(s)) + var i C.int + var err error + for { + i, err = C.zmq4_socket_monitor(soc.soc, s, C.int(events)) + if i == 0 || !soc.ctx.retry(err) { + break + } + } + if i != 0 { + return errget(err) + } + return nil +} + +/* +Receive a message part from a socket interpreted as an event. + +For a description of flags, see: http://api.zeromq.org/4-1:zmq-msg-recv#toc2 + +For a description of event_type, see: http://api.zeromq.org/4-1:zmq-socket-monitor#toc3 + +For an example, see: func (*Socket) Monitor +*/ +func (soc *Socket) RecvEvent(flags Flag) (event_type Event, addr string, value int, err error) { + if !soc.opened { + return EVENT_ALL, "", 0, ErrorSocketClosed + } + var msg C.zmq_msg_t + C.zmq_msg_init(&msg) + defer C.zmq_msg_close(&msg) + var size C.int + var e error + for { + size, e = C.zmq4_msg_recv(&msg, soc.soc, C.int(flags)) + if size >= 0 || !soc.ctx.retry(e) { + break + } + } + if size < 0 { + err = errget(e) + return + } + et := C.int(0) + val := C.int(0) + + if minor == 0 { + C.zmq4_get_event40(&msg, &et, &val) + } else { + C.zmq4_get_event41(&msg, &et, &val) + } + more, e := soc.GetRcvmore() + if e != nil { + err = errget(e) + return + } + if !more { + err = ErrorMoreExpected + return + } + addr, e = soc.Recv(flags) + if e != nil { + err = errget(e) + return + } + + event_type = Event(et) + value = int(val) + + return +} + +/* +Start built-in ØMQ proxy + +See: http://api.zeromq.org/4-1:zmq-proxy#toc2 +*/ +func Proxy(frontend, backend, capture *Socket) error { + if !(frontend.opened && backend.opened && (capture == nil || capture.opened)) { + return ErrorSocketClosed + } + var capt unsafe.Pointer + if capture != nil { + capt = capture.soc + } + var err error + for { + _, err = C.zmq4_proxy(frontend.soc, backend.soc, capt) + if !frontend.ctx.retry(err) { + break + } + } + return errget(err) +} + +/* +Start built-in ØMQ proxy with PAUSE/RESUME/TERMINATE control flow + +Returns ErrorNotImplemented405 with ZeroMQ version < 4.0.5 + +See: http://api.zeromq.org/4-1:zmq-proxy-steerable#toc2 +*/ +func ProxySteerable(frontend, backend, capture, control *Socket) error { + if minor == 0 && patch < 5 { + return ErrorNotImplemented405 + } + if !(frontend.opened && backend.opened && (capture == nil || capture.opened) && (control == nil || control.opened)) { + return ErrorSocketClosed + } + var capt, ctrl unsafe.Pointer + if capture != nil { + capt = capture.soc + } + if control != nil { + ctrl = control.soc + } + var i C.int + var err error + for { + i, err = C.zmq4_proxy_steerable(frontend.soc, backend.soc, capt, ctrl) + if i >= 0 || !frontend.ctx.retry(err) { + break + } + } + if i < 0 { + return errget(err) + } + return nil +} + +//. CURVE + +/* +Encode a binary key as Z85 printable text + +See: http://api.zeromq.org/4-1:zmq-z85-encode +*/ +func Z85encode(data string) string { + if initVersionError != nil { + return initVersionError.Error() + } + l1 := len(data) + if l1%4 != 0 { + panic("Z85encode: Length of data not a multiple of 4") + } + d := []byte(data) + + l2 := 5 * l1 / 4 + dest := make([]byte, l2+1) + + C.zmq_z85_encode((*C.char)(unsafe.Pointer(&dest[0])), (*C.uint8_t)(&d[0]), C.size_t(l1)) + + return string(dest[:l2]) +} + +/* +Decode a binary key from Z85 printable text + +See: http://api.zeromq.org/4-1:zmq-z85-decode +*/ +func Z85decode(s string) string { + if initVersionError != nil { + return initVersionError.Error() + } + l1 := len(s) + if l1%5 != 0 { + panic("Z85decode: Length of Z85 string not a multiple of 5") + } + l2 := 4 * l1 / 5 + dest := make([]byte, l2) + cs := C.CString(s) + defer C.free(unsafe.Pointer(cs)) + C.zmq_z85_decode((*C.uint8_t)(&dest[0]), cs) + return string(dest) +} + +/* +Generate a new CURVE keypair + +See: http://api.zeromq.org/4-1:zmq-curve-keypair#toc2 +*/ +func NewCurveKeypair() (z85_public_key, z85_secret_key string, err error) { + if initVersionError != nil { + return "", "", initVersionError + } + var pubkey, seckey [41]byte + if i, err := C.zmq4_curve_keypair((*C.char)(unsafe.Pointer(&pubkey[0])), (*C.char)(unsafe.Pointer(&seckey[0]))); i != 0 { + return "", "", errget(err) + } + return string(pubkey[:40]), string(seckey[:40]), nil +} + +/* +Receive a message part with metadata. + +This requires ZeroMQ version 4.1.0. Lower versions will return the message part without metadata. + +The returned metadata map contains only those properties that exist on the message. + +For a description of flags, see: http://api.zeromq.org/4-1:zmq-msg-recv#toc2 + +For a description of metadata, see: http://api.zeromq.org/4-1:zmq-msg-gets#toc3 +*/ +func (soc *Socket) RecvWithMetadata(flags Flag, properties ...string) (msg string, metadata map[string]string, err error) { + b, p, err := soc.RecvBytesWithMetadata(flags, properties...) + return string(b), p, err +} + +/* +Receive a message part with metadata. + +This requires ZeroMQ version 4.1.0. Lower versions will return the message part without metadata. + +The returned metadata map contains only those properties that exist on the message. + +For a description of flags, see: http://api.zeromq.org/4-1:zmq-msg-recv#toc2 + +For a description of metadata, see: http://api.zeromq.org/4-1:zmq-msg-gets#toc3 +*/ +func (soc *Socket) RecvBytesWithMetadata(flags Flag, properties ...string) (msg []byte, metadata map[string]string, err error) { + if !soc.opened { + return []byte{}, map[string]string{}, ErrorSocketClosed + } + + metadata = make(map[string]string) + + var m C.zmq_msg_t + C.zmq_msg_init(&m) + defer C.zmq_msg_close(&m) + + var size C.int + for { + size, err = C.zmq4_msg_recv(&m, soc.soc, C.int(flags)) + if size >= 0 || !soc.ctx.retry(err) { + break + } + } + if size < 0 { + return []byte{}, metadata, errget(err) + } + + data := make([]byte, int(size)) + if size > 0 { + C.zmq4_memcpy(unsafe.Pointer(&data[0]), C.zmq_msg_data(&m), C.size_t(size)) + } + + if minor > 0 { + for _, p := range properties { + ps := C.CString(p) + s := C.zmq4_msg_gets(&m, ps) + if s != nil { + metadata[p] = C.GoString(s) + } + C.free(unsafe.Pointer(ps)) + } + } + return data, metadata, nil +} + +func hasCap(s string) (value bool) { + if initVersionError != nil { + return false + } + if minor < 1 { + return false + } + cs := C.CString(s) + defer C.free(unsafe.Pointer(cs)) + return C.zmq_has(cs) != 0 +} + +// Returns false for ZeroMQ version < 4.1.0 +// +// Else: returns true if the library supports the ipc:// protocol +func HasIpc() bool { + return hasCap("ipc") +} + +// Returns false for ZeroMQ version < 4.1.0 +// +// Else: returns true if the library supports the pgm:// protocol +func HasPgm() bool { + return hasCap("pgm") +} + +// Returns false for ZeroMQ version < 4.1.0 +// +// Else: returns true if the library supports the tipc:// protocol +func HasTipc() bool { + return hasCap("tipc") +} + +// Returns false for ZeroMQ version < 4.1.0 +// +// Else: returns true if the library supports the norm:// protocol +func HasNorm() bool { + return hasCap("norm") +} + +// Returns false for ZeroMQ version < 4.1.0 +// +// Else: returns true if the library supports the CURVE security mechanism +func HasCurve() bool { + return hasCap("curve") +} + +// Returns false for ZeroMQ version < 4.1.0 +// +// Else: returns true if the library supports the GSSAPI security mechanism +func HasGssapi() bool { + return hasCap("gssapi") +} diff --git a/vendor/github.com/pebbe/zmq4/zmq4.h b/vendor/github.com/pebbe/zmq4/zmq4.h new file mode 100644 index 00000000..ed522845 --- /dev/null +++ b/vendor/github.com/pebbe/zmq4/zmq4.h @@ -0,0 +1,126 @@ +#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 + +#if ZMQ_VERSION_MINOR < 3 + +#define ZMQ_MSG_T_SIZE -1 +#define ZMQ_THREAD_AFFINITY_CPU_ADD -1 +#define ZMQ_THREAD_AFFINITY_CPU_REMOVE -1 +#define ZMQ_THREAD_NAME_PREFIX -1 + +#define ZMQ_GSSAPI_PRINCIPAL_NAMETYPE -1 +#define ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE -1 +#define ZMQ_BINDTODEVICE -1 + +#define ZMQ_GSSAPI_NT_HOSTBASED -1 +#define ZMQ_GSSAPI_NT_USER_NAME -1 +#define ZMQ_GSSAPI_NT_KRB5_PRINCIPAL -1 + +#define ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL -1 +#define ZMQ_EVENT_HANDSHAKE_SUCCEEDED -1 +#define ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL -1 +#define ZMQ_EVENT_HANDSHAKE_FAILED_AUTH -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC -1 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH -1 +#define ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED -1 +#define ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY -1 +#define ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID -1 +#define ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION -1 +#define ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE -1 +#define ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA -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 + +int zmq4_bind (void *socket, const char *endpoint); +int zmq4_close (void *socket); +int zmq4_connect (void *socket, const char *endpoint); +int zmq4_ctx_get (void *context, int option_name); +void *zmq4_ctx_new (void); +int zmq4_ctx_set (void *context, int option_name, int option_value); +int zmq4_ctx_term (void *context); +int zmq4_curve_keypair (char *z85_public_key, char *z85_secret_key); +int zmq4_curve_public (char *z85_public_key, char *z85_secret_key); +int zmq4_disconnect (void *socket, const char *endpoint); +int zmq4_getsockopt (void *socket, int option_name, void *option_value, size_t *option_len); +const char *zmq4_msg_gets (zmq_msg_t *message, const char *property); +int zmq4_msg_recv (zmq_msg_t *msg, void *socket, int flags); +int zmq4_poll (zmq_pollitem_t *items, int nitems, long timeout); +int zmq4_proxy (const void *frontend, const void *backend, const void *capture); +int zmq4_proxy_steerable (const void *frontend, const void *backend, const void *capture, const void *control); +int zmq4_send (void *socket, void *buf, size_t len, int flags); +int zmq4_setsockopt (void *socket, int option_name, const void *option_value, size_t option_len); +void *zmq4_socket (void *context, int type); +int zmq4_socket_monitor (void *socket, char *endpoint, int events); +int zmq4_unbind (void *socket, const char *endpoint); diff --git a/vendor/modules.txt b/vendor/modules.txt index a79d469a..8d06ac23 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,32 +1,34 @@ # github.com/golang/protobuf v1.4.3 github.com/golang/protobuf/ptypes/struct +# github.com/pebbe/zmq4 v1.2.2 +github.com/pebbe/zmq4 # google.golang.org/protobuf v1.25.0 -google.golang.org/protobuf/reflect/protoreflect -google.golang.org/protobuf/runtime/protoimpl -google.golang.org/protobuf/types/known/structpb -google.golang.org/protobuf/encoding/protowire -google.golang.org/protobuf/internal/pragma -google.golang.org/protobuf/internal/filedesc -google.golang.org/protobuf/internal/filetype -google.golang.org/protobuf/internal/impl -google.golang.org/protobuf/internal/version google.golang.org/protobuf/encoding/protojson -google.golang.org/protobuf/internal/errors +google.golang.org/protobuf/encoding/prototext +google.golang.org/protobuf/encoding/protowire google.golang.org/protobuf/internal/descfmt google.golang.org/protobuf/internal/descopts +google.golang.org/protobuf/internal/detrand google.golang.org/protobuf/internal/encoding/defval -google.golang.org/protobuf/internal/genid -google.golang.org/protobuf/internal/strs -google.golang.org/protobuf/proto -google.golang.org/protobuf/reflect/protoregistry -google.golang.org/protobuf/encoding/prototext +google.golang.org/protobuf/internal/encoding/json google.golang.org/protobuf/internal/encoding/messageset google.golang.org/protobuf/internal/encoding/tag +google.golang.org/protobuf/internal/encoding/text +google.golang.org/protobuf/internal/errors google.golang.org/protobuf/internal/fieldsort +google.golang.org/protobuf/internal/filedesc +google.golang.org/protobuf/internal/filetype google.golang.org/protobuf/internal/flags -google.golang.org/protobuf/runtime/protoiface -google.golang.org/protobuf/internal/encoding/json -google.golang.org/protobuf/internal/set -google.golang.org/protobuf/internal/detrand -google.golang.org/protobuf/internal/encoding/text +google.golang.org/protobuf/internal/genid +google.golang.org/protobuf/internal/impl google.golang.org/protobuf/internal/mapsort +google.golang.org/protobuf/internal/pragma +google.golang.org/protobuf/internal/set +google.golang.org/protobuf/internal/strs +google.golang.org/protobuf/internal/version +google.golang.org/protobuf/proto +google.golang.org/protobuf/reflect/protoreflect +google.golang.org/protobuf/reflect/protoregistry +google.golang.org/protobuf/runtime/protoiface +google.golang.org/protobuf/runtime/protoimpl +google.golang.org/protobuf/types/known/structpb