@@ -8,7 +8,6 @@ package beacon
|
||||
|
||||
import (
|
||||
"net"
|
||||
stdsync "sync"
|
||||
|
||||
"github.com/thejerf/suture"
|
||||
)
|
||||
@@ -24,21 +23,3 @@ type Interface interface {
|
||||
Recv() ([]byte, net.Addr)
|
||||
Error() error
|
||||
}
|
||||
|
||||
type errorHolder struct {
|
||||
err error
|
||||
mut stdsync.Mutex // uses stdlib sync as I want this to be trivially embeddable, and there is no risk of blocking
|
||||
}
|
||||
|
||||
func (e *errorHolder) setError(err error) {
|
||||
e.mut.Lock()
|
||||
e.err = err
|
||||
e.mut.Unlock()
|
||||
}
|
||||
|
||||
func (e *errorHolder) Error() error {
|
||||
e.mut.Lock()
|
||||
err := e.err
|
||||
e.mut.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/thejerf/suture"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/util"
|
||||
)
|
||||
|
||||
type Broadcast struct {
|
||||
@@ -44,16 +45,16 @@ func NewBroadcast(port int) *Broadcast {
|
||||
}
|
||||
|
||||
b.br = &broadcastReader{
|
||||
port: port,
|
||||
outbox: b.outbox,
|
||||
connMut: sync.NewMutex(),
|
||||
port: port,
|
||||
outbox: b.outbox,
|
||||
}
|
||||
b.br.ServiceWithError = util.AsServiceWithError(b.br.serve)
|
||||
b.Add(b.br)
|
||||
b.bw = &broadcastWriter{
|
||||
port: port,
|
||||
inbox: b.inbox,
|
||||
connMut: sync.NewMutex(),
|
||||
port: port,
|
||||
inbox: b.inbox,
|
||||
}
|
||||
b.bw.ServiceWithError = util.AsServiceWithError(b.bw.serve)
|
||||
b.Add(b.bw)
|
||||
|
||||
return b
|
||||
@@ -76,34 +77,42 @@ func (b *Broadcast) Error() error {
|
||||
}
|
||||
|
||||
type broadcastWriter struct {
|
||||
port int
|
||||
inbox chan []byte
|
||||
conn *net.UDPConn
|
||||
connMut sync.Mutex
|
||||
errorHolder
|
||||
util.ServiceWithError
|
||||
port int
|
||||
inbox chan []byte
|
||||
}
|
||||
|
||||
func (w *broadcastWriter) Serve() {
|
||||
func (w *broadcastWriter) serve(stop chan struct{}) error {
|
||||
l.Debugln(w, "starting")
|
||||
defer l.Debugln(w, "stopping")
|
||||
|
||||
conn, err := net.ListenUDP("udp4", nil)
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
w.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func() {
|
||||
select {
|
||||
case <-stop:
|
||||
case <-done:
|
||||
}
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
w.connMut.Lock()
|
||||
w.conn = conn
|
||||
w.connMut.Unlock()
|
||||
for {
|
||||
var bs []byte
|
||||
select {
|
||||
case bs = <-w.inbox:
|
||||
case <-stop:
|
||||
return nil
|
||||
}
|
||||
|
||||
for bs := range w.inbox {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
w.setError(err)
|
||||
w.SetError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -134,14 +143,13 @@ func (w *broadcastWriter) Serve() {
|
||||
// Write timeouts should not happen. We treat it as a fatal
|
||||
// error on the socket.
|
||||
l.Debugln(err)
|
||||
w.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// Some other error that we don't expect. Debug and continue.
|
||||
l.Debugln(err)
|
||||
w.setError(err)
|
||||
w.SetError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -150,57 +158,49 @@ func (w *broadcastWriter) Serve() {
|
||||
}
|
||||
|
||||
if success > 0 {
|
||||
w.setError(nil)
|
||||
w.SetError(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *broadcastWriter) Stop() {
|
||||
w.connMut.Lock()
|
||||
if w.conn != nil {
|
||||
w.conn.Close()
|
||||
}
|
||||
w.connMut.Unlock()
|
||||
}
|
||||
|
||||
func (w *broadcastWriter) String() string {
|
||||
return fmt.Sprintf("broadcastWriter@%p", w)
|
||||
}
|
||||
|
||||
type broadcastReader struct {
|
||||
port int
|
||||
outbox chan recv
|
||||
conn *net.UDPConn
|
||||
connMut sync.Mutex
|
||||
errorHolder
|
||||
util.ServiceWithError
|
||||
port int
|
||||
outbox chan recv
|
||||
}
|
||||
|
||||
func (r *broadcastReader) Serve() {
|
||||
func (r *broadcastReader) serve(stop chan struct{}) error {
|
||||
l.Debugln(r, "starting")
|
||||
defer l.Debugln(r, "stopping")
|
||||
|
||||
conn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: r.port})
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
r.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
r.connMut.Lock()
|
||||
r.conn = conn
|
||||
r.connMut.Unlock()
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func() {
|
||||
select {
|
||||
case <-stop:
|
||||
case <-done:
|
||||
}
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
bs := make([]byte, 65536)
|
||||
for {
|
||||
n, addr, err := conn.ReadFrom(bs)
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
r.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
r.setError(nil)
|
||||
r.SetError(nil)
|
||||
|
||||
l.Debugf("recv %d bytes from %s", n, addr)
|
||||
|
||||
@@ -208,19 +208,12 @@ func (r *broadcastReader) Serve() {
|
||||
copy(c, bs)
|
||||
select {
|
||||
case r.outbox <- recv{c, addr}:
|
||||
case <-stop:
|
||||
return nil
|
||||
default:
|
||||
l.Debugln("dropping message")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (r *broadcastReader) Stop() {
|
||||
r.connMut.Lock()
|
||||
if r.conn != nil {
|
||||
r.conn.Close()
|
||||
}
|
||||
r.connMut.Unlock()
|
||||
}
|
||||
|
||||
func (r *broadcastReader) String() string {
|
||||
|
||||
@@ -48,14 +48,14 @@ func NewMulticast(addr string) *Multicast {
|
||||
addr: addr,
|
||||
outbox: m.outbox,
|
||||
}
|
||||
m.mr.Service = util.AsService(m.mr.serve)
|
||||
m.mr.ServiceWithError = util.AsServiceWithError(m.mr.serve)
|
||||
m.Add(m.mr)
|
||||
|
||||
m.mw = &multicastWriter{
|
||||
addr: addr,
|
||||
inbox: m.inbox,
|
||||
}
|
||||
m.mw.Service = util.AsService(m.mw.serve)
|
||||
m.mw.ServiceWithError = util.AsServiceWithError(m.mw.serve)
|
||||
m.Add(m.mw)
|
||||
|
||||
return m
|
||||
@@ -78,29 +78,35 @@ func (m *Multicast) Error() error {
|
||||
}
|
||||
|
||||
type multicastWriter struct {
|
||||
suture.Service
|
||||
util.ServiceWithError
|
||||
addr string
|
||||
inbox <-chan []byte
|
||||
errorHolder
|
||||
}
|
||||
|
||||
func (w *multicastWriter) serve(stop chan struct{}) {
|
||||
func (w *multicastWriter) serve(stop chan struct{}) error {
|
||||
l.Debugln(w, "starting")
|
||||
defer l.Debugln(w, "stopping")
|
||||
|
||||
gaddr, err := net.ResolveUDPAddr("udp6", w.addr)
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
w.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := net.ListenPacket("udp6", ":0")
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
w.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func() {
|
||||
select {
|
||||
case <-stop:
|
||||
case <-done:
|
||||
}
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
pconn := ipv6.NewPacketConn(conn)
|
||||
|
||||
@@ -113,14 +119,13 @@ func (w *multicastWriter) serve(stop chan struct{}) {
|
||||
select {
|
||||
case bs = <-w.inbox:
|
||||
case <-stop:
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
intfs, err := net.Interfaces()
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
w.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
success := 0
|
||||
@@ -132,7 +137,7 @@ func (w *multicastWriter) serve(stop chan struct{}) {
|
||||
|
||||
if err != nil {
|
||||
l.Debugln(err, "on write to", gaddr, intf.Name)
|
||||
w.setError(err)
|
||||
w.SetError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -142,16 +147,13 @@ func (w *multicastWriter) serve(stop chan struct{}) {
|
||||
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if success > 0 {
|
||||
w.setError(nil)
|
||||
} else {
|
||||
l.Debugln(err)
|
||||
w.setError(err)
|
||||
w.SetError(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,35 +163,40 @@ func (w *multicastWriter) String() string {
|
||||
}
|
||||
|
||||
type multicastReader struct {
|
||||
suture.Service
|
||||
util.ServiceWithError
|
||||
addr string
|
||||
outbox chan<- recv
|
||||
errorHolder
|
||||
}
|
||||
|
||||
func (r *multicastReader) serve(stop chan struct{}) {
|
||||
func (r *multicastReader) serve(stop chan struct{}) error {
|
||||
l.Debugln(r, "starting")
|
||||
defer l.Debugln(r, "stopping")
|
||||
|
||||
gaddr, err := net.ResolveUDPAddr("udp6", r.addr)
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
r.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := net.ListenPacket("udp6", r.addr)
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
r.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func() {
|
||||
select {
|
||||
case <-stop:
|
||||
case <-done:
|
||||
}
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
intfs, err := net.Interfaces()
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
r.setError(err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
pconn := ipv6.NewPacketConn(conn)
|
||||
@@ -206,16 +213,20 @@ func (r *multicastReader) serve(stop chan struct{}) {
|
||||
|
||||
if joined == 0 {
|
||||
l.Debugln("no multicast interfaces available")
|
||||
r.setError(errors.New("no multicast interfaces available"))
|
||||
return
|
||||
return errors.New("no multicast interfaces available")
|
||||
}
|
||||
|
||||
bs := make([]byte, 65536)
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
n, _, addr, err := pconn.ReadFrom(bs)
|
||||
if err != nil {
|
||||
l.Debugln(err)
|
||||
r.setError(err)
|
||||
r.SetError(err)
|
||||
continue
|
||||
}
|
||||
l.Debugf("recv %d bytes from %s", n, addr)
|
||||
@@ -224,8 +235,6 @@ func (r *multicastReader) serve(stop chan struct{}) {
|
||||
copy(c, bs)
|
||||
select {
|
||||
case r.outbox <- recv{c, addr}:
|
||||
case <-stop:
|
||||
return
|
||||
default:
|
||||
l.Debugln("dropping message")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user