mirror of
https://github.com/nabbar/golib.git
synced 2025-10-04 15:32:48 +08:00
Package Socket/Server:
- fix UDP as kernel SOCKGRAM - add unixgram as kernel SOCKGRAM for local socket file - optimize parallel statment - optimize code / minor bugs fix - add IsRunning function - add timeout shutdown based on periodicly check of IsRunning - fix close channel before send empty struct to stop process - optimize clean shutdown - optimize connection process to use less resources and lock pipeline less time
This commit is contained in:
@@ -35,6 +35,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const DefaultBufferSize = 32 * 1024
|
const DefaultBufferSize = 32 * 1024
|
||||||
|
const EOL byte = '\n'
|
||||||
|
|
||||||
type ConnState uint8
|
type ConnState uint8
|
||||||
|
|
||||||
@@ -79,13 +80,16 @@ type Handler func(request io.Reader, response io.Writer)
|
|||||||
type Response func(r io.Reader)
|
type Response func(r io.Reader)
|
||||||
|
|
||||||
type Server interface {
|
type Server interface {
|
||||||
|
io.Closer
|
||||||
|
|
||||||
RegisterFuncError(f FuncError)
|
RegisterFuncError(f FuncError)
|
||||||
RegisterFuncInfo(f FuncInfo)
|
RegisterFuncInfo(f FuncInfo)
|
||||||
RegisterFuncInfoServer(f FuncInfoSrv)
|
RegisterFuncInfoServer(f FuncInfoSrv)
|
||||||
|
|
||||||
SetTLS(enable bool, config libtls.TLSConfig) error
|
SetTLS(enable bool, config libtls.TLSConfig) error
|
||||||
Listen(ctx context.Context) error
|
Listen(ctx context.Context) error
|
||||||
Shutdown()
|
Shutdown() error
|
||||||
|
IsRunning() bool
|
||||||
Done() <-chan struct{}
|
Done() <-chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -30,8 +30,9 @@ import "fmt"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidAddress = fmt.Errorf("invalid listen address")
|
ErrInvalidAddress = fmt.Errorf("invalid listen address")
|
||||||
ErrInvalidHostName = fmt.Errorf("invalid server host name")
|
|
||||||
ErrInvalidHostPort = fmt.Errorf("invalid server host port")
|
|
||||||
ErrContextClosed = fmt.Errorf("context closed")
|
ErrContextClosed = fmt.Errorf("context closed")
|
||||||
ErrServerClosed = fmt.Errorf("server closed")
|
ErrServerClosed = fmt.Errorf("server closed")
|
||||||
|
ErrInvalidHandler = fmt.Errorf("invalid handler")
|
||||||
|
ErrShutdownTimeout = fmt.Errorf("timeout on stopping socket")
|
||||||
|
ErrInvalidInstance = fmt.Errorf("invalid socket instance")
|
||||||
)
|
)
|
||||||
|
@@ -57,6 +57,7 @@ func New(h libsck.Handler, sizeBuffRead libsiz.Size) ServerTcp {
|
|||||||
h: f,
|
h: f,
|
||||||
c: c,
|
c: c,
|
||||||
s: s,
|
s: s,
|
||||||
|
r: new(atomic.Bool),
|
||||||
fe: new(atomic.Value),
|
fe: new(atomic.Value),
|
||||||
fi: new(atomic.Value),
|
fi: new(atomic.Value),
|
||||||
fs: new(atomic.Value),
|
fs: new(atomic.Value),
|
||||||
|
@@ -33,6 +33,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
libptc "github.com/nabbar/golib/network/protocol"
|
libptc "github.com/nabbar/golib/network/protocol"
|
||||||
libsck "github.com/nabbar/golib/socket"
|
libsck "github.com/nabbar/golib/socket"
|
||||||
@@ -80,44 +81,67 @@ func (o *srv) Listen(ctx context.Context) error {
|
|||||||
e error
|
e error
|
||||||
l net.Listener
|
l net.Listener
|
||||||
a = o.getAddress()
|
a = o.getAddress()
|
||||||
|
s = new(atomic.Bool)
|
||||||
)
|
)
|
||||||
|
|
||||||
var fctClose = func() {
|
|
||||||
o.fctInfoSrv("closing listen socket '%s %s'", libptc.NetworkTCP.String(), a)
|
|
||||||
if l != nil {
|
|
||||||
o.fctError(l.Close())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer fctClose()
|
|
||||||
|
|
||||||
if len(a) == 0 {
|
if len(a) == 0 {
|
||||||
return ErrInvalidAddress
|
return ErrInvalidAddress
|
||||||
|
} else if hdl := o.handler(); hdl == nil {
|
||||||
|
return ErrInvalidHandler
|
||||||
} else if l, e = o.getListen(a); e != nil {
|
} else if l, e = o.getListen(a); e != nil {
|
||||||
o.fctError(e)
|
o.fctError(e)
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fctClose = func() {
|
||||||
|
o.fctInfoSrv("closing listen socket '%s %s'", libptc.NetworkTCP.String(), a)
|
||||||
|
|
||||||
|
if l != nil {
|
||||||
|
_ = l.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
o.r.Store(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer fctClose()
|
||||||
|
s.Store(false)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
go func() {
|
||||||
|
_ = o.Shutdown()
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-o.Done()
|
||||||
|
|
||||||
|
e = nil
|
||||||
|
s.Store(true)
|
||||||
|
|
||||||
|
if l != nil {
|
||||||
|
o.fctError(l.Close())
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
o.r.Store(true)
|
||||||
// Accept new connection or stop if context or shutdown trigger
|
// Accept new connection or stop if context or shutdown trigger
|
||||||
for {
|
for {
|
||||||
select {
|
// Accept an incoming connection.
|
||||||
case <-ctx.Done():
|
if l == nil {
|
||||||
return ErrContextClosed
|
return ErrServerClosed
|
||||||
case <-o.Done():
|
} else if s.Load() {
|
||||||
return nil
|
return e
|
||||||
default:
|
}
|
||||||
// Accept an incoming connection.
|
|
||||||
if l == nil {
|
|
||||||
return ErrServerClosed
|
|
||||||
}
|
|
||||||
|
|
||||||
co, ce := l.Accept()
|
if co, ce := l.Accept(); ce != nil && !s.Load() {
|
||||||
|
o.fctError(ce)
|
||||||
if ce != nil {
|
} else {
|
||||||
o.fctError(ce)
|
o.fctInfo(co.LocalAddr(), co.RemoteAddr(), libsck.ConnectionNew)
|
||||||
} else {
|
go o.Conn(co)
|
||||||
go o.Conn(co)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,12 +152,10 @@ func (o *srv) Conn(conn net.Conn) {
|
|||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
o.fctInfo(conn.LocalAddr(), conn.RemoteAddr(), libsck.ConnectionNew)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
rdr = bufio.NewReaderSize(conn, o.buffSize())
|
rdr = bufio.NewReaderSize(conn, o.buffSize())
|
||||||
buf []byte
|
msg []byte
|
||||||
hdl libsck.Handler
|
hdl libsck.Handler
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -142,7 +164,7 @@ func (o *srv) Conn(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
buf, err = rdr.ReadBytes('\n')
|
msg, err = rdr.ReadBytes('\n')
|
||||||
|
|
||||||
o.fctInfo(conn.LocalAddr(), conn.RemoteAddr(), libsck.ConnectionRead)
|
o.fctInfo(conn.LocalAddr(), conn.RemoteAddr(), libsck.ConnectionRead)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -152,7 +174,13 @@ func (o *srv) Conn(conn net.Conn) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var buf = bytes.NewBuffer(msg)
|
||||||
|
|
||||||
|
if !bytes.HasSuffix(msg, []byte{libsck.EOL}) {
|
||||||
|
buf.Write([]byte{libsck.EOL})
|
||||||
|
}
|
||||||
|
|
||||||
o.fctInfo(conn.LocalAddr(), conn.RemoteAddr(), libsck.ConnectionHandler)
|
o.fctInfo(conn.LocalAddr(), conn.RemoteAddr(), libsck.ConnectionHandler)
|
||||||
hdl(bytes.NewBuffer(buf), conn)
|
hdl(buf, conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,10 +27,12 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
libptc "github.com/nabbar/golib/network/protocol"
|
libptc "github.com/nabbar/golib/network/protocol"
|
||||||
|
|
||||||
@@ -58,6 +60,7 @@ type srv struct {
|
|||||||
h *atomic.Value // handler
|
h *atomic.Value // handler
|
||||||
c *atomic.Value // chan []byte
|
c *atomic.Value // chan []byte
|
||||||
s *atomic.Value // chan struct{}
|
s *atomic.Value // chan struct{}
|
||||||
|
r *atomic.Bool // is Running
|
||||||
|
|
||||||
fe *atomic.Value // function error
|
fe *atomic.Value // function error
|
||||||
fi *atomic.Value // function info
|
fi *atomic.Value // function info
|
||||||
@@ -67,6 +70,10 @@ type srv struct {
|
|||||||
ad *atomic.Value // Server address url
|
ad *atomic.Value // Server address url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *srv) IsRunning() bool {
|
||||||
|
return o.r.Load()
|
||||||
|
}
|
||||||
|
|
||||||
func (o *srv) Done() <-chan struct{} {
|
func (o *srv) Done() <-chan struct{} {
|
||||||
s := o.s.Load()
|
s := o.s.Load()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
@@ -76,14 +83,47 @@ func (o *srv) Done() <-chan struct{} {
|
|||||||
return closedChanStruct
|
return closedChanStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *srv) Shutdown() {
|
func (o *srv) Close() error {
|
||||||
|
return o.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *srv) Shutdown() error {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return
|
return ErrInvalidInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
s := o.s.Load()
|
s := o.s.Load()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
o.s.Store(nil)
|
if c, k := s.(chan struct{}); k {
|
||||||
|
c <- struct{}{}
|
||||||
|
o.s.Store(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
tck = time.NewTicker(100 * time.Millisecond)
|
||||||
|
ctx, cnl = context.WithTimeout(context.Background(), 25*time.Second)
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if s != nil {
|
||||||
|
o.s.Store(closedChanStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
tck.Stop()
|
||||||
|
cnl()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ErrShutdownTimeout
|
||||||
|
case <-tck.C:
|
||||||
|
if o.IsRunning() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,8 +29,10 @@ package udp
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidAddress = fmt.Errorf("invalid listen address")
|
ErrInvalidAddress = fmt.Errorf("invalid listen address")
|
||||||
ErrContextClosed = fmt.Errorf("context closed")
|
ErrContextClosed = fmt.Errorf("context closed")
|
||||||
ErrServerClosed = fmt.Errorf("server closed")
|
ErrServerClosed = fmt.Errorf("server closed")
|
||||||
ErrInvalidHandler = fmt.Errorf("invalid handler")
|
ErrInvalidHandler = fmt.Errorf("invalid handler")
|
||||||
|
ErrShutdownTimeout = fmt.Errorf("timeout on stopping socket")
|
||||||
|
ErrInvalidInstance = fmt.Errorf("invalid socket instance")
|
||||||
)
|
)
|
||||||
|
@@ -56,6 +56,7 @@ func New(h libsck.Handler, sizeBuffRead libsiz.Size) ServerTcp {
|
|||||||
h: f,
|
h: f,
|
||||||
c: c,
|
c: c,
|
||||||
s: s,
|
s: s,
|
||||||
|
r: new(atomic.Bool),
|
||||||
fe: new(atomic.Value),
|
fe: new(atomic.Value),
|
||||||
fi: new(atomic.Value),
|
fi: new(atomic.Value),
|
||||||
fs: new(atomic.Value),
|
fs: new(atomic.Value),
|
||||||
|
@@ -31,6 +31,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
libptc "github.com/nabbar/golib/network/protocol"
|
libptc "github.com/nabbar/golib/network/protocol"
|
||||||
libsck "github.com/nabbar/golib/socket"
|
libsck "github.com/nabbar/golib/socket"
|
||||||
@@ -78,6 +79,7 @@ func (o *srv) Listen(ctx context.Context) error {
|
|||||||
err error
|
err error
|
||||||
nbr int
|
nbr int
|
||||||
loc *net.UDPAddr
|
loc *net.UDPAddr
|
||||||
|
stp = new(atomic.Bool)
|
||||||
rem net.Addr
|
rem net.Addr
|
||||||
con *net.UDPConn
|
con *net.UDPConn
|
||||||
adr = o.getAddress()
|
adr = o.getAddress()
|
||||||
@@ -92,55 +94,86 @@ func (o *srv) Listen(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var fctClose = func() {
|
|
||||||
o.fctInfoSrv("closing listen socket '%s %s'", libptc.NetworkUDP.String(), adr)
|
|
||||||
if con != nil {
|
|
||||||
o.fctError(con.Close())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer fctClose()
|
|
||||||
|
|
||||||
if con, err = net.ListenUDP(libptc.NetworkUDP.Code(), loc); err != nil {
|
if con, err = net.ListenUDP(libptc.NetworkUDP.Code(), loc); err != nil {
|
||||||
o.fctError(err)
|
o.fctError(err)
|
||||||
return err
|
return err
|
||||||
} else {
|
|
||||||
o.fctInfoSrv("starting listening socket '%s %s'", libptc.NetworkUDP.String(), adr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fctClose = func() {
|
||||||
|
o.fctInfoSrv("closing listen socket '%s %s'", libptc.NetworkUDP.String(), adr)
|
||||||
|
|
||||||
|
if con != nil {
|
||||||
|
_ = con.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
o.r.Store(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer fctClose()
|
||||||
|
stp.Store(false)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
go func() {
|
||||||
|
_ = o.Shutdown()
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-o.Done()
|
||||||
|
|
||||||
|
err = nil
|
||||||
|
stp.Store(true)
|
||||||
|
|
||||||
|
if con != nil {
|
||||||
|
o.fctError(con.Close())
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
o.r.Store(true)
|
||||||
|
|
||||||
|
o.fctInfoSrv("starting listening socket '%s %s'", libptc.NetworkUDP.String(), adr)
|
||||||
// Accept new connection or stop if context or shutdown trigger
|
// Accept new connection or stop if context or shutdown trigger
|
||||||
for {
|
for {
|
||||||
select {
|
// Accept an incoming connection.
|
||||||
case <-ctx.Done():
|
if con == nil {
|
||||||
return ErrContextClosed
|
return ErrServerClosed
|
||||||
case <-o.Done():
|
} else if stp.Load() {
|
||||||
return nil
|
return err
|
||||||
default:
|
|
||||||
// Accept an incoming connection.
|
|
||||||
if con == nil {
|
|
||||||
return ErrServerClosed
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf = make([]byte, o.buffSize())
|
|
||||||
nbr, rem, err = con.ReadFrom(buf)
|
|
||||||
|
|
||||||
if rem == nil {
|
|
||||||
rem = &net.UDPAddr{}
|
|
||||||
}
|
|
||||||
|
|
||||||
o.fctInfo(loc, rem, libsck.ConnectionRead)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
o.fctError(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
go func(la, ra net.Addr, b []byte) {
|
|
||||||
o.fctInfo(la, ra, libsck.ConnectionHandler)
|
|
||||||
r := bytes.NewBuffer(b)
|
|
||||||
r.WriteString("\n")
|
|
||||||
hdl(r, io.Discard)
|
|
||||||
}(loc, rem, buf[:nbr])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
buf = make([]byte, o.buffSize())
|
||||||
|
rer error
|
||||||
|
)
|
||||||
|
|
||||||
|
nbr, rem, rer = con.ReadFrom(buf)
|
||||||
|
|
||||||
|
if rem == nil {
|
||||||
|
rem = &net.UDPAddr{}
|
||||||
|
}
|
||||||
|
|
||||||
|
o.fctInfo(loc, rem, libsck.ConnectionRead)
|
||||||
|
|
||||||
|
if rer != nil {
|
||||||
|
if !stp.Load() {
|
||||||
|
o.fctError(rer)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(la, ra net.Addr, b []byte) {
|
||||||
|
o.fctInfo(la, ra, libsck.ConnectionHandler)
|
||||||
|
|
||||||
|
r := bytes.NewBuffer(b)
|
||||||
|
if !bytes.HasSuffix(b, []byte{libsck.EOL}) {
|
||||||
|
r.Write([]byte{libsck.EOL})
|
||||||
|
}
|
||||||
|
|
||||||
|
hdl(r, io.Discard)
|
||||||
|
}(loc, rem, buf[:nbr])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,9 +27,11 @@
|
|||||||
package udp
|
package udp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
libptc "github.com/nabbar/golib/network/protocol"
|
libptc "github.com/nabbar/golib/network/protocol"
|
||||||
|
|
||||||
@@ -52,6 +54,7 @@ type srv struct {
|
|||||||
h *atomic.Value // handler
|
h *atomic.Value // handler
|
||||||
c *atomic.Value // chan []byte
|
c *atomic.Value // chan []byte
|
||||||
s *atomic.Value // chan struct{}
|
s *atomic.Value // chan struct{}
|
||||||
|
r *atomic.Bool // is Running
|
||||||
|
|
||||||
fe *atomic.Value // function error
|
fe *atomic.Value // function error
|
||||||
fi *atomic.Value // function info
|
fi *atomic.Value // function info
|
||||||
@@ -61,6 +64,10 @@ type srv struct {
|
|||||||
ad *atomic.Value // Server address url
|
ad *atomic.Value // Server address url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *srv) IsRunning() bool {
|
||||||
|
return o.r.Load()
|
||||||
|
}
|
||||||
|
|
||||||
func (o *srv) Done() <-chan struct{} {
|
func (o *srv) Done() <-chan struct{} {
|
||||||
s := o.s.Load()
|
s := o.s.Load()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
@@ -70,14 +77,47 @@ func (o *srv) Done() <-chan struct{} {
|
|||||||
return closedChanStruct
|
return closedChanStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *srv) Shutdown() {
|
func (o *srv) Close() error {
|
||||||
|
return o.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *srv) Shutdown() error {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return
|
return ErrInvalidInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
s := o.s.Load()
|
s := o.s.Load()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
o.s.Store(nil)
|
if c, k := s.(chan struct{}); k {
|
||||||
|
c <- struct{}{}
|
||||||
|
o.s.Store(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
tck = time.NewTicker(100 * time.Millisecond)
|
||||||
|
ctx, cnl = context.WithTimeout(context.Background(), 25*time.Second)
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if s != nil {
|
||||||
|
o.s.Store(closedChanStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
tck.Stop()
|
||||||
|
cnl()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ErrShutdownTimeout
|
||||||
|
case <-tck.C:
|
||||||
|
if o.IsRunning() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -32,8 +32,10 @@ package unix
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrContextClosed = fmt.Errorf("context closed")
|
ErrContextClosed = fmt.Errorf("context closed")
|
||||||
ErrServerClosed = fmt.Errorf("server closed")
|
ErrServerClosed = fmt.Errorf("server closed")
|
||||||
ErrInvalidGroup = fmt.Errorf("invalid unix group for socket group permission")
|
ErrInvalidGroup = fmt.Errorf("invalid unix group for socket group permission")
|
||||||
ErrInvalidHandler = fmt.Errorf("invalid handler")
|
ErrInvalidHandler = fmt.Errorf("invalid handler")
|
||||||
|
ErrShutdownTimeout = fmt.Errorf("timeout on stopping socket")
|
||||||
|
ErrInvalidInstance = fmt.Errorf("invalid socket instance")
|
||||||
)
|
)
|
||||||
|
@@ -75,6 +75,7 @@ func New(h libsck.Handler, sizeBuffRead libsiz.Size) ServerUnix {
|
|||||||
h: f,
|
h: f,
|
||||||
c: c,
|
c: c,
|
||||||
s: s,
|
s: s,
|
||||||
|
r: new(atomic.Bool),
|
||||||
fe: new(atomic.Value),
|
fe: new(atomic.Value),
|
||||||
fi: new(atomic.Value),
|
fi: new(atomic.Value),
|
||||||
fs: new(atomic.Value),
|
fs: new(atomic.Value),
|
||||||
|
@@ -40,6 +40,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
libptc "github.com/nabbar/golib/network/protocol"
|
libptc "github.com/nabbar/golib/network/protocol"
|
||||||
@@ -156,45 +157,72 @@ func (o *srv) Listen(ctx context.Context) error {
|
|||||||
e error
|
e error
|
||||||
f string
|
f string
|
||||||
l net.Listener
|
l net.Listener
|
||||||
|
s = new(atomic.Bool)
|
||||||
)
|
)
|
||||||
|
|
||||||
if f, e = o.getSocketFile(); e != nil {
|
if f, e = o.getSocketFile(); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
} else if hdl := o.handler(); hdl == nil {
|
||||||
|
return ErrInvalidHandler
|
||||||
var fctClose = func() {
|
|
||||||
if l != nil {
|
|
||||||
o.fctError(l.Close())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, e = os.Stat(f); e == nil {
|
|
||||||
o.fctError(os.Remove(f))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l, e = o.getListen(f); e != nil {
|
if l, e = o.getListen(f); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
defer fctClose()
|
var fctClose = func() {
|
||||||
|
o.fctInfoSrv("closing listen socket '%s %s'", libptc.NetworkUnixGram.String(), f)
|
||||||
|
|
||||||
|
if l != nil {
|
||||||
|
_ = l.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, e = os.Stat(f); e == nil {
|
||||||
|
o.fctError(os.Remove(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
o.r.Store(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer fctClose()
|
||||||
|
s.Store(false)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
go func() {
|
||||||
|
_ = o.Shutdown()
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-o.Done()
|
||||||
|
|
||||||
|
e = nil
|
||||||
|
s.Store(true)
|
||||||
|
|
||||||
|
if l != nil {
|
||||||
|
o.fctError(l.Close())
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
o.r.Store(true)
|
||||||
// Accept new connection or stop if context or shutdown trigger
|
// Accept new connection or stop if context or shutdown trigger
|
||||||
for {
|
for {
|
||||||
select {
|
// Accept an incoming connection.
|
||||||
case <-ctx.Done():
|
if l == nil {
|
||||||
return ErrContextClosed
|
return ErrServerClosed
|
||||||
case <-o.Done():
|
} else if s.Load() {
|
||||||
return nil
|
return e
|
||||||
default:
|
}
|
||||||
// Accept an incoming connection.
|
|
||||||
if l == nil {
|
if co, ce := l.Accept(); ce != nil && !s.Load() {
|
||||||
return ErrServerClosed
|
o.fctError(ce)
|
||||||
} else if co, ce := l.Accept(); ce != nil {
|
} else {
|
||||||
o.fctError(ce)
|
o.fctInfo(co.LocalAddr(), co.RemoteAddr(), libsck.ConnectionNew)
|
||||||
} else {
|
go o.Conn(co)
|
||||||
o.fctInfo(co.LocalAddr(), co.RemoteAddr(), libsck.ConnectionNew)
|
|
||||||
go o.Conn(co)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,12 +233,10 @@ func (o *srv) Conn(con net.Conn) {
|
|||||||
_ = con.Close()
|
_ = con.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionNew)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
rdr = bufio.NewReaderSize(con, o.buffSize())
|
rdr = bufio.NewReaderSize(con, o.buffSize())
|
||||||
buf []byte
|
msg []byte
|
||||||
hdl libsck.Handler
|
hdl libsck.Handler
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -219,7 +245,7 @@ func (o *srv) Conn(con net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
buf, err = rdr.ReadBytes('\n')
|
msg, err = rdr.ReadBytes('\n')
|
||||||
|
|
||||||
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionRead)
|
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionRead)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -229,7 +255,13 @@ func (o *srv) Conn(con net.Conn) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var buf = bytes.NewBuffer(msg)
|
||||||
|
|
||||||
|
if !bytes.HasSuffix(msg, []byte{libsck.EOL}) {
|
||||||
|
buf.Write([]byte{libsck.EOL})
|
||||||
|
}
|
||||||
|
|
||||||
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionHandler)
|
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionHandler)
|
||||||
hdl(bytes.NewBuffer(buf), con)
|
hdl(buf, con)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,10 +30,12 @@
|
|||||||
package unix
|
package unix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
libptc "github.com/nabbar/golib/network/protocol"
|
libptc "github.com/nabbar/golib/network/protocol"
|
||||||
|
|
||||||
@@ -56,6 +58,7 @@ type srv struct {
|
|||||||
h *atomic.Value // handler
|
h *atomic.Value // handler
|
||||||
c *atomic.Value // chan []byte
|
c *atomic.Value // chan []byte
|
||||||
s *atomic.Value // chan struct{}
|
s *atomic.Value // chan struct{}
|
||||||
|
r *atomic.Bool // is Running
|
||||||
|
|
||||||
fe *atomic.Value // function error
|
fe *atomic.Value // function error
|
||||||
fi *atomic.Value // function info
|
fi *atomic.Value // function info
|
||||||
@@ -67,6 +70,10 @@ type srv struct {
|
|||||||
sg *atomic.Int32 // file unix group perm
|
sg *atomic.Int32 // file unix group perm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *srv) IsRunning() bool {
|
||||||
|
return o.r.Load()
|
||||||
|
}
|
||||||
|
|
||||||
func (o *srv) Done() <-chan struct{} {
|
func (o *srv) Done() <-chan struct{} {
|
||||||
s := o.s.Load()
|
s := o.s.Load()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
@@ -76,14 +83,47 @@ func (o *srv) Done() <-chan struct{} {
|
|||||||
return closedChanStruct
|
return closedChanStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *srv) Shutdown() {
|
func (o *srv) Close() error {
|
||||||
|
return o.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *srv) Shutdown() error {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return
|
return ErrInvalidInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
s := o.s.Load()
|
s := o.s.Load()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
o.s.Store(nil)
|
if c, k := s.(chan struct{}); k {
|
||||||
|
c <- struct{}{}
|
||||||
|
o.s.Store(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
tck = time.NewTicker(100 * time.Millisecond)
|
||||||
|
ctx, cnl = context.WithTimeout(context.Background(), 25*time.Second)
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if s != nil {
|
||||||
|
o.s.Store(closedChanStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
tck.Stop()
|
||||||
|
cnl()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ErrShutdownTimeout
|
||||||
|
case <-tck.C:
|
||||||
|
if o.IsRunning() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -32,8 +32,10 @@ package unixgram
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrContextClosed = fmt.Errorf("context closed")
|
ErrContextClosed = fmt.Errorf("context closed")
|
||||||
ErrServerClosed = fmt.Errorf("server closed")
|
ErrServerClosed = fmt.Errorf("server closed")
|
||||||
ErrInvalidGroup = fmt.Errorf("invalid unix group for socket group permission")
|
ErrInvalidGroup = fmt.Errorf("invalid unix group for socket group permission")
|
||||||
ErrInvalidHandler = fmt.Errorf("invalid handler")
|
ErrInvalidHandler = fmt.Errorf("invalid handler")
|
||||||
|
ErrShutdownTimeout = fmt.Errorf("timeout on stopping socket")
|
||||||
|
ErrInvalidInstance = fmt.Errorf("invalid socket instance")
|
||||||
)
|
)
|
||||||
|
@@ -75,6 +75,7 @@ func New(h libsck.Handler, sizeBuffRead libsiz.Size) ServerUnixGram {
|
|||||||
h: f,
|
h: f,
|
||||||
c: c,
|
c: c,
|
||||||
s: s,
|
s: s,
|
||||||
|
r: new(atomic.Bool),
|
||||||
fe: new(atomic.Value),
|
fe: new(atomic.Value),
|
||||||
fi: new(atomic.Value),
|
fi: new(atomic.Value),
|
||||||
fs: new(atomic.Value),
|
fs: new(atomic.Value),
|
||||||
|
@@ -39,6 +39,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
libptc "github.com/nabbar/golib/network/protocol"
|
libptc "github.com/nabbar/golib/network/protocol"
|
||||||
@@ -151,6 +152,7 @@ func (o *srv) Listen(ctx context.Context) error {
|
|||||||
err error
|
err error
|
||||||
nbr int
|
nbr int
|
||||||
uxf string
|
uxf string
|
||||||
|
stp = new(atomic.Bool)
|
||||||
loc *net.UnixAddr
|
loc *net.UnixAddr
|
||||||
rem net.Addr
|
rem net.Addr
|
||||||
con *net.UnixConn
|
con *net.UnixConn
|
||||||
@@ -168,9 +170,10 @@ func (o *srv) Listen(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fctClose = func() {
|
var fctClose = func() {
|
||||||
|
o.fctInfoSrv("closing listen socket '%s %s'", libptc.NetworkUnixGram.String(), uxf)
|
||||||
|
|
||||||
if con != nil {
|
if con != nil {
|
||||||
o.fctInfoSrv("closing listen socket '%s %s'", libptc.NetworkUnixGram.String(), uxf)
|
_ = con.Close()
|
||||||
o.fctError(con.Close())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = os.Stat(uxf); err == nil {
|
if _, err = os.Stat(uxf); err == nil {
|
||||||
@@ -179,40 +182,69 @@ func (o *srv) Listen(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer fctClose()
|
defer fctClose()
|
||||||
|
stp.Store(false)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
go func() {
|
||||||
|
_ = o.Shutdown()
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-o.Done()
|
||||||
|
|
||||||
|
err = nil
|
||||||
|
stp.Store(true)
|
||||||
|
|
||||||
|
if con != nil {
|
||||||
|
o.fctError(con.Close())
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
|
||||||
|
o.r.Store(true)
|
||||||
// Accept new connection or stop if context or shutdown trigger
|
// Accept new connection or stop if context or shutdown trigger
|
||||||
for {
|
for {
|
||||||
select {
|
// Accept an incoming connection.
|
||||||
case <-ctx.Done():
|
if con == nil {
|
||||||
return ErrContextClosed
|
return ErrServerClosed
|
||||||
case <-o.Done():
|
} else if stp.Load() {
|
||||||
return nil
|
return err
|
||||||
default:
|
|
||||||
// Accept an incoming connection.
|
|
||||||
if con == nil {
|
|
||||||
return ErrServerClosed
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf = make([]byte, o.buffSize())
|
|
||||||
nbr, rem, err = con.ReadFrom(buf)
|
|
||||||
|
|
||||||
if rem == nil {
|
|
||||||
rem = &net.UnixAddr{}
|
|
||||||
}
|
|
||||||
|
|
||||||
o.fctInfo(loc, rem, libsck.ConnectionRead)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
o.fctError(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
go func(la, ra net.Addr, b []byte) {
|
|
||||||
o.fctInfo(la, ra, libsck.ConnectionHandler)
|
|
||||||
r := bytes.NewBuffer(b)
|
|
||||||
r.WriteString("\n")
|
|
||||||
hdl(r, io.Discard)
|
|
||||||
}(loc, rem, buf[:nbr])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
buf = make([]byte, o.buffSize())
|
||||||
|
rer error
|
||||||
|
)
|
||||||
|
|
||||||
|
nbr, rem, rer = con.ReadFrom(buf)
|
||||||
|
|
||||||
|
if rem == nil {
|
||||||
|
rem = &net.UnixAddr{}
|
||||||
|
}
|
||||||
|
|
||||||
|
o.fctInfo(loc, rem, libsck.ConnectionRead)
|
||||||
|
|
||||||
|
if rer != nil {
|
||||||
|
if !stp.Load() {
|
||||||
|
o.fctError(rer)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(la, ra net.Addr, b []byte) {
|
||||||
|
o.fctInfo(la, ra, libsck.ConnectionHandler)
|
||||||
|
|
||||||
|
r := bytes.NewBuffer(b)
|
||||||
|
|
||||||
|
if !bytes.HasSuffix(b, []byte{libsck.EOL}) {
|
||||||
|
r.Write([]byte{libsck.EOL})
|
||||||
|
}
|
||||||
|
|
||||||
|
hdl(r, io.Discard)
|
||||||
|
}(loc, rem, buf[:nbr])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,10 +30,12 @@
|
|||||||
package unixgram
|
package unixgram
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
libptc "github.com/nabbar/golib/network/protocol"
|
libptc "github.com/nabbar/golib/network/protocol"
|
||||||
|
|
||||||
@@ -56,6 +58,7 @@ type srv struct {
|
|||||||
h *atomic.Value // handler
|
h *atomic.Value // handler
|
||||||
c *atomic.Value // chan []byte
|
c *atomic.Value // chan []byte
|
||||||
s *atomic.Value // chan struct{}
|
s *atomic.Value // chan struct{}
|
||||||
|
r *atomic.Bool // is Running
|
||||||
|
|
||||||
fe *atomic.Value // function error
|
fe *atomic.Value // function error
|
||||||
fi *atomic.Value // function info
|
fi *atomic.Value // function info
|
||||||
@@ -67,6 +70,10 @@ type srv struct {
|
|||||||
sg *atomic.Int32 // file unix group perm
|
sg *atomic.Int32 // file unix group perm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *srv) IsRunning() bool {
|
||||||
|
return o.r.Load()
|
||||||
|
}
|
||||||
|
|
||||||
func (o *srv) Done() <-chan struct{} {
|
func (o *srv) Done() <-chan struct{} {
|
||||||
s := o.s.Load()
|
s := o.s.Load()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
@@ -76,14 +83,47 @@ func (o *srv) Done() <-chan struct{} {
|
|||||||
return closedChanStruct
|
return closedChanStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *srv) Shutdown() {
|
func (o *srv) Close() error {
|
||||||
|
return o.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *srv) Shutdown() error {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return
|
return ErrInvalidInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
s := o.s.Load()
|
s := o.s.Load()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
o.s.Store(nil)
|
if c, k := s.(chan struct{}); k {
|
||||||
|
c <- struct{}{}
|
||||||
|
o.s.Store(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
tck = time.NewTicker(100 * time.Millisecond)
|
||||||
|
ctx, cnl = context.WithTimeout(context.Background(), 25*time.Second)
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if s != nil {
|
||||||
|
o.s.Store(closedChanStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
tck.Stop()
|
||||||
|
cnl()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ErrShutdownTimeout
|
||||||
|
case <-tck.C:
|
||||||
|
if o.IsRunning() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user