Commit 3f6456bc authored by ale's avatar ale
Browse files

Update internal dependencies

parent 3b53d9f8
Pipeline #10515 passed with stages
in 56 seconds
module git.autistici.org/id/go-sso
go 1.14
require (
git.autistici.org/ai3/go-common v0.0.0-20210110180225-a05c683cfe23
git.autistici.org/id/auth v0.0.0-20200212081728-3d44524ae2e5
git.autistici.org/id/auth v0.0.0-20210110171913-dd493db32815
git.autistici.org/id/keystore v0.0.0-20210110165905-d5b171e81071
github.com/beevik/etree v0.0.0-20171015221209-af219c0c7ea1 // indirect
github.com/crewjam/saml v0.0.0-20190521120225-344d075952c9
......
......@@ -5,13 +5,12 @@ contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj
git.autistici.org/ai3/go-common v0.0.0-20210109170950-49f8d26bcc81/go.mod h1:nuLJyKZZaC3DBPN4gA1qdGXcm0U5WCcus1z3pI8RdTE=
git.autistici.org/ai3/go-common v0.0.0-20210110180225-a05c683cfe23 h1:YHSG7Vr8nPRmXa7tW2UR8kfzwerjA5GD+bI84nxq2kA=
git.autistici.org/ai3/go-common v0.0.0-20210110180225-a05c683cfe23/go.mod h1:Iik+i0XmqNPTBjWl3vicFz0kjfFK5HBvyFsfIC4S1Ik=
git.autistici.org/id/auth v0.0.0-20200212081728-3d44524ae2e5 h1:mxuJFOy4mgSJd54eBC2nVvT4mv9t8qp14mAin+TBnP0=
git.autistici.org/id/auth v0.0.0-20200212081728-3d44524ae2e5/go.mod h1:opFyv0ktv8UuXHezBQL3FrUg6en8h8P5I14kLMBC1Jg=
git.autistici.org/id/auth v0.0.0-20210110171913-dd493db32815 h1:gjBHxd2voc+mqHKQqUxkgVqQWGlysWZKJFIRcINpI40=
git.autistici.org/id/auth v0.0.0-20210110171913-dd493db32815/go.mod h1:Hq4zcqE2hbrXsC9j79kzfnBf2BqlGmuVCRIz+AwX/FY=
git.autistici.org/id/go-sso v0.0.0-20181118174541-ad4e62357912/go.mod h1:B9omXX7rw0qgWdBoF4RZnM7clwEVejoAe8oNJWETBZ0=
git.autistici.org/id/keystore v0.0.0-20190630084729-9f1f2da00729 h1:Tdlsb+MV/ytp+wv2uGEwwa2RllLYD/1ttPyiWxIWMtM=
git.autistici.org/id/keystore v0.0.0-20190630084729-9f1f2da00729/go.mod h1:h3iymQHFhVSsFYbPByQcJJzkzKL/ZF4DenH9637200s=
git.autistici.org/id/keystore v0.0.0-20210110165905-d5b171e81071 h1:VFS052hG95WpNe+kNsNPXfa+3P41SbMPeolJLG3B9TU=
git.autistici.org/id/keystore v0.0.0-20210110165905-d5b171e81071/go.mod h1:4A1OkW4qvDg3mhI2IQ3lNL1DsrJJwTuYuGPUe6ZfDBM=
git.autistici.org/id/usermetadb v0.0.0-20190209105239-61e5a7b24130/go.mod h1:mChOzl9ekSRcfHoFwe3Uv1mccoaZwurlDsIuKRxM8no=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
......@@ -42,6 +41,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/boombuler/barcode v0.0.0-20170618053812-56ef0af91246/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
......@@ -57,6 +58,7 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
......@@ -102,6 +104,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY=
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
......@@ -256,6 +259,7 @@ github.com/oschwald/maxminddb-golang v0.0.0-20170901134056-26fe5ace1c70 h1:XGLYU
github.com/oschwald/maxminddb-golang v0.0.0-20170901134056-26fe5ace1c70/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
......@@ -268,6 +272,7 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/otp v1.0.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
......@@ -328,6 +333,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/theckman/go-flock v0.8.0 h1:h0ssvtvRY44GJyWJW9cZhahYVVnLVaAhlB8H/4TOt5c=
github.com/theckman/go-flock v0.8.0/go.mod h1:kjuth3y9VJ2aNlkNEO99G/8lp9fMIKaGyBmh84IBheM=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ=
......
include: "https://git.autistici.org/ai3/build-deb/raw/master/ci-common.yml"
include: "https://git.autistici.org/ai3/build-deb/raw/master/ci-nextstable.yml"
......@@ -21,10 +21,11 @@ backends such as Memcached for short-term storage, and
anonymized user activity data. For this reason, it is recommended to
install an auth-server on every host.
It listens for authorization requests over a UNIX socket. UNIX
permissions should be used to control access to the socket if
necessary. Clients speak a custom simple line-based attribute/value
protocol, and can send multiple requests over the same connection.
The authentication protocol is a simple line-based text protocol. The
auth-server can listen on a UNIX or TCP socket: in the first case,
filesystem permissions should be used to control access to the socket,
while in the second case there is support for SSL, with optional
checks on the provided client certificates.
## Services
......@@ -37,8 +38,9 @@ functionality and user backends.
The authentication server data model is based on the concept of a
*user account*. The server knows how to retrieve user accounts stored
in LDAP, but it has to be told the specific details of how to find
them and how to map the information there to what it needs.
in LDAP or SQL databases, but it has to be told the specific details
of how to find them and how to map the information there to what it
needs.
## Other Dependencies
......@@ -306,6 +308,9 @@ substitution symbol `?` as placeholder for query parameters.
The only mandatory query is *get_user*, if the other ones are not
specified the associated fields will be empty.
Note that the relational queries (*get_user_groups*, *get_user_u2f*
and *get_user_asp*) should NOT return rows containing NULL values.
### Example database schema
The following could be a (very simple) example database schema for a
......@@ -367,6 +372,9 @@ add specific users to it easily.
The daemon can run either standalone or be socket-activated by
systemd, which is what the Debian package does.
Check out the output of *auth-server --help* for documentation on how
to configure the listening sockets.
## Wire protocol
The rationale behind the wire protocol ("why not http?") is twofold:
......
......@@ -3,15 +3,19 @@ package client
import (
"context"
"net"
"net/textproto"
"strings"
"github.com/cenkalti/backoff"
"go.opencensus.io/trace"
"git.autistici.org/id/auth"
"git.autistici.org/id/auth/lineproto"
)
var DefaultSocketPath = "/run/auth/socket"
var (
DefaultSocketPath = "/run/auth/socket"
DefaultPoolSize = 3
)
type Client interface {
Authenticate(context.Context, *auth.Request) (*auth.Response, error)
......@@ -20,12 +24,20 @@ type Client interface {
type socketClient struct {
socketPath string
codec auth.Codec
pool *Pool
}
func New(socketPath string) Client {
return &socketClient{
socketPath: socketPath,
codec: auth.DefaultCodec,
pool: NewPool(func() (*lineproto.Conn, error) {
c, err := net.Dial("unix", socketPath)
if err != nil {
return nil, err
}
return lineproto.NewConn(c, ""), nil
}, DefaultPoolSize),
}
}
......@@ -47,6 +59,8 @@ func (c *socketClient) Authenticate(ctx context.Context, req *auth.Request) (*au
resp, err = c.doAuthenticate(sctx, req)
if err == nil {
return nil
} else if strings.Contains(err.Error(), "use of closed network connection") {
return err
} else if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
return netErr
}
......@@ -59,52 +73,45 @@ func (c *socketClient) Authenticate(ctx context.Context, req *auth.Request) (*au
}
func (c *socketClient) doAuthenticate(ctx context.Context, req *auth.Request) (*auth.Response, error) {
// Create the connection outside of the timed goroutine, so
// that we can call Close() on exit regardless of the reason:
// this way, when a timeout occurs or the context is canceled,
// the pending request terminates immediately.
conn, err := textproto.Dial("unix", c.socketPath)
if err != nil {
return nil, err
}
defer conn.Close()
// Make space in the channel for at least one element, or we
// will leak a goroutine whenever the authentication request
// times out.
done := make(chan error, 1)
var resp auth.Response
go func() {
defer close(done)
// Write the auth command to the connection.
if err := conn.PrintfLine("auth %s", string(c.codec.Encode(req))); err != nil {
done <- err
return
err := c.pool.WithConn(func(conn *lineproto.Conn) error {
// Make space in the channel for at least one element, or we
// will leak a goroutine whenever the authentication request
// times out.
done := make(chan error, 1)
go func() {
defer close(done)
// Write the auth command to the connection.
if err := conn.WriteLine([]byte("auth "), c.codec.Encode(req)); err != nil {
done <- err
return
}
// Read the response.
line, err := conn.ReadLine()
if err != nil {
done <- err
return
}
if err := c.codec.Decode(line, &resp); err != nil {
done <- err
return
}
done <- nil
}()
// Wait for the call to terminate, or the context to time out,
// whichever happens first.
select {
case err := <-done:
return err
case <-ctx.Done():
return ctx.Err()
}
// Read the response.
line, err := conn.ReadLineBytes()
if err != nil {
done <- err
return
}
if err := c.codec.Decode(line, &resp); err != nil {
done <- err
return
}
done <- nil
}()
// Wait for the call to terminate, or the context to time out,
// whichever happens first.
select {
case err := <-done:
return &resp, err
case <-ctx.Done():
return nil, ctx.Err()
}
})
return &resp, err
}
func responseToTraceStatus(resp *auth.Response, err error) trace.Status {
......
package client
import (
"git.autistici.org/id/auth/lineproto"
)
type PoolDialer func() (*lineproto.Conn, error)
type Pool struct {
ch chan *lineproto.Conn
dialer PoolDialer
}
func NewPool(dialer PoolDialer, size int) *Pool {
return &Pool{
ch: make(chan *lineproto.Conn, size),
dialer: dialer,
}
}
func (p *Pool) WithConn(f func(*lineproto.Conn) error) error {
// Acquire a connection.
var conn *lineproto.Conn
select {
case conn = <-p.ch:
default:
var err error
conn, err = p.dialer()
if err != nil {
return err
}
}
// Run the function and inspect its return value.
err := f(conn)
if err != nil {
conn.Close()
} else {
select {
case p.ch <- conn:
default:
conn.Close()
}
}
return err
}
module git.autistici.org/id/auth
go 1.15
require (
git.autistici.org/ai3/go-common v0.0.0-20210109170950-49f8d26bcc81
git.autistici.org/id/usermetadb v0.0.0-20190209105239-61e5a7b24130
github.com/boombuler/barcode v0.0.0-20170618053812-56ef0af91246 // indirect
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-systemd/v22 v22.1.0
github.com/go-ldap/ldap/v3 v3.2.4
github.com/go-sql-driver/mysql v1.4.0
github.com/google/go-cmp v0.5.4
github.com/lib/pq v0.0.0-20190326042056-d6156e141ac6
github.com/mattn/go-sqlite3 v0.0.0-20180926090220-0a88db3545c4
github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627
github.com/pquerna/otp v1.0.0
github.com/prometheus/client_golang v1.9.0
github.com/theckman/go-flock v0.8.0
github.com/tstranex/u2f v1.0.0
go.opencensus.io v0.22.5
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
google.golang.org/appengine v1.4.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.3.0
)
This diff is collapsed.
package lineproto
import (
"bufio"
"net"
)
type Reader struct {
r *bufio.Reader
}
func (r *Reader) ReadLine() ([]byte, error) {
var line []byte
for {
l, more, err := r.r.ReadLine()
if err != nil {
return nil, err
}
// Avoid the copy if the first call produced a full line.
if line == nil && !more {
return l, nil
}
line = append(line, l...)
if !more {
break
}
}
return line, nil
}
type Writer struct {
w *bufio.Writer
}
var crlf = []byte("\r\n")
func (w *Writer) WriteLine(args ...[]byte) error {
for _, arg := range args {
_, err := w.w.Write(arg)
if err != nil {
return err
}
}
_, err := w.w.Write(crlf)
if err != nil {
return err
}
return w.w.Flush()
}
type Conn struct {
net.Conn
*Reader
*Writer
ServerName string
}
func NewConn(c net.Conn, name string) *Conn {
return &Conn{
Conn: c,
Reader: &Reader{r: bufio.NewReader(c)},
Writer: &Writer{w: bufio.NewWriter(c)},
ServerName: name,
}
}
func (c *Conn) Close() error {
return c.Conn.Close()
}
package lineproto
import (
"context"
"errors"
"io"
"log"
"strings"
"time"
"github.com/prometheus/client_golang/prometheus"
)
// LineHandler is the handler for LineServer.
type LineHandler interface {
ServeLine(context.Context, LineResponseWriter, []byte) error
}
// ErrCloseConnection must be returned by a LineHandler when we want
// to cleanly terminate the connection without raising an error.
var ErrCloseConnection = errors.New("close")
// LineResponseWriter writes a single-line response to the underlying
// connection.
type LineResponseWriter interface {
// WriteLine writes a response as a single line (the line
// terminator is added by the function).
WriteLine(...[]byte) error
}
// LineServer implements a line-based text protocol. It satisfies the
// Handler interface.
type LineServer struct {
handler LineHandler
IdleTimeout time.Duration
WriteTimeout time.Duration
RequestTimeout time.Duration
}
var (
defaultIdleTimeout = 600 * time.Second
defaultWriteTimeout = 10 * time.Second
defaultRequestTimeout = 30 * time.Second
)
// NewLineServer returns a new LineServer with the given handler and
// default I/O timeouts.
func NewLineServer(h LineHandler) *LineServer {
return &LineServer{
handler: h,
IdleTimeout: defaultIdleTimeout,
WriteTimeout: defaultWriteTimeout,
RequestTimeout: defaultRequestTimeout,
}
}
// ServeConnection handles a new connection. It will accept multiple
// requests on the same connection (or not, depending on the client
// preference).
func (l *LineServer) ServeConnection(c *Conn) {
totalConnections.WithLabelValues(c.ServerName).Inc()
for {
c.Conn.SetReadDeadline(time.Now().Add(l.IdleTimeout)) // nolint
line, err := c.ReadLine()
if err == io.EOF {
break
} else if err != nil {
if !strings.Contains(err.Error(), "use of closed network connection") {
log.Printf("client error: %v", err)
}
break
}
// Create a context for the request and call the
// handler with it. Set a write deadline on the
// connection to allow the full RequestTimeout time to
// generate the response.
start := time.Now()
c.Conn.SetWriteDeadline(start.Add(l.RequestTimeout + l.WriteTimeout)) // nolint
ctx, cancel := context.WithTimeout(context.Background(), l.RequestTimeout)
err = l.handler.ServeLine(ctx, c, line)
elapsedMs := time.Since(start).Nanoseconds() / 1000000
requestLatencyHist.WithLabelValues(c.ServerName).
Observe(float64(elapsedMs))
cancel()
// Close the connection on error, or on empty response.
if err != nil {
totalRequests.WithLabelValues(c.ServerName, "error").Inc()
if err != ErrCloseConnection {
log.Printf("request error: %v", err)
}
break
}
totalRequests.WithLabelValues(c.ServerName, "ok").Inc()
}
}
// Instrumentation metrics.
var (
totalConnections = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "lineproto_connections_total",
Help: "Total number of connections.",
},
[]string{"listener"},
)
totalRequests = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "lineproto_requests_total",
Help: "Total number of requests.",
},
[]string{"listener", "status"},
)
// Histogram buckets are tuned for the low-milliseconds range
// (the largest bucket sits at ~1s).
requestLatencyHist = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "lineproto_requests_latency_ms",
Help: "Latency of requests.",
Buckets: prometheus.ExponentialBuckets(5, 1.4142, 16),
},
[]string{"listener"},
)
)
func init() {
prometheus.MustRegister(totalConnections)
prometheus.MustRegister(totalRequests)
prometheus.MustRegister(requestLatencyHist)
}
package lineproto
import (
"container/list"
"net"
"sync"
"sync/atomic"
)
type Handler interface {
ServeConnection(c *Conn)
}
type Server struct {
Name string
l net.Listener
h Handler
// Keep track of active connections so we can shut them down
// on Close.
closing atomic.Value
wg sync.WaitGroup
connMx sync.Mutex
conns list.List
}
func NewServer(name string, l net.Listener, h Handler) *Server {
s := &Server{
Name: name,
l: l,
h: h,
}
s.closing.Store(false)
return s
}
// Close the socket listener and release all associated resources.
// Waits for active connections to terminate before returning.
func (s *Server) Close() {
s.closing.Store(true)
// Close the listener to stop incoming connections.
s.l.Close() // nolint
// Close all active connections (this will return an error to
// the client if the connection is not idle).
s.connMx.Lock()
for el := s.conns.Front(); el != nil; el = el.Next() { </