2018-04-19 11:36:56 +00:00
|
|
|
package discoverer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"git.loafle.net/commons/util-go/net/cidr"
|
2018-04-26 09:00:24 +00:00
|
|
|
"git.loafle.net/overflow/commons-go/core/util"
|
|
|
|
ocmd "git.loafle.net/overflow/commons-go/model/discovery"
|
2018-04-19 11:36:56 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type DiscoveryDataType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
DiscoveryDataTypeNone DiscoveryDataType = iota
|
|
|
|
DiscoveryDataTypeStart
|
|
|
|
DiscoveryDataTypeStop
|
|
|
|
DiscoveryDataTypeError
|
|
|
|
DiscoveryDataTypeZone
|
|
|
|
DiscoveryDataTypeHost
|
|
|
|
DiscoveryDataTypePort
|
|
|
|
DiscoveryDataTypeService
|
|
|
|
)
|
|
|
|
|
|
|
|
type DiscoveryData struct {
|
|
|
|
Type DiscoveryDataType
|
|
|
|
Result interface{}
|
|
|
|
Error error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (dd *DiscoveryData) Release() {
|
|
|
|
releaseDiscoveryData(dd)
|
|
|
|
}
|
|
|
|
|
|
|
|
var _discoverer Discoverer
|
|
|
|
|
|
|
|
func GetDiscoverer() Discoverer {
|
|
|
|
if nil == _discoverer {
|
|
|
|
_discoverer = &defaultDiscoverer{}
|
|
|
|
}
|
|
|
|
return _discoverer
|
|
|
|
}
|
|
|
|
|
|
|
|
type Discoverer interface {
|
|
|
|
Retain() chan *DiscoveryData
|
|
|
|
Release(dataChan chan *DiscoveryData)
|
2018-04-27 16:20:01 +00:00
|
|
|
DiscoverZone(dataChan chan *DiscoveryData, dz *ocmd.DiscoverZone)
|
|
|
|
DiscoverHost(dataChan chan *DiscoveryData, zone *ocmd.Zone, dh *ocmd.DiscoverHost)
|
|
|
|
DiscoverPort(dataChan chan *DiscoveryData, host *ocmd.Host, dp *ocmd.DiscoverPort)
|
|
|
|
DiscoverSerice(dataChan chan *DiscoveryData, port *ocmd.Port, ds *ocmd.DiscoverService)
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type defaultDiscoverer struct {
|
|
|
|
dataChanPool chan chan *DiscoveryData
|
|
|
|
|
|
|
|
stopChan chan struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *defaultDiscoverer) Retain() chan *DiscoveryData {
|
|
|
|
if nil == d.dataChanPool {
|
|
|
|
d.dataChanPool = make(chan chan *DiscoveryData, 1)
|
|
|
|
d.dataChanPool <- make(chan *DiscoveryData, 256)
|
|
|
|
}
|
|
|
|
return <-d.dataChanPool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *defaultDiscoverer) Release(dataChan chan *DiscoveryData) {
|
|
|
|
d.dataChanPool <- dataChan
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *defaultDiscoverer) Stop(dataChan chan *DiscoveryData) {
|
|
|
|
if nil != d.stopChan {
|
|
|
|
close(d.stopChan)
|
|
|
|
d.stopChan = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-27 16:20:01 +00:00
|
|
|
func (d *defaultDiscoverer) DiscoverZone(dataChan chan *DiscoveryData, dz *ocmd.DiscoverZone) {
|
2018-04-19 11:36:56 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
d.stopChan = make(chan struct{})
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeStart, util.Now(), nil, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
wg.Add(1)
|
|
|
|
go d.innerDiscoverZone(&wg, dataChan, dz)
|
|
|
|
wg.Wait()
|
|
|
|
if nil != d.stopChan {
|
|
|
|
close(d.stopChan)
|
|
|
|
d.stopChan = nil
|
|
|
|
}
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeStop, util.Now(), nil, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
|
2018-04-27 16:20:01 +00:00
|
|
|
func (d *defaultDiscoverer) DiscoverHost(dataChan chan *DiscoveryData, zone *ocmd.Zone, dh *ocmd.DiscoverHost) {
|
2018-04-19 11:36:56 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
d.stopChan = make(chan struct{})
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeStart, util.Now(), nil, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
wg.Add(1)
|
|
|
|
go d.innerDiscoverHost(&wg, dataChan, zone, dh)
|
|
|
|
wg.Wait()
|
|
|
|
if nil != d.stopChan {
|
|
|
|
close(d.stopChan)
|
|
|
|
d.stopChan = nil
|
|
|
|
}
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeStop, util.Now(), nil, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
|
2018-04-27 16:20:01 +00:00
|
|
|
func (d *defaultDiscoverer) DiscoverPort(dataChan chan *DiscoveryData, host *ocmd.Host, dp *ocmd.DiscoverPort) {
|
2018-04-19 11:36:56 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
d.stopChan = make(chan struct{})
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeStart, util.Now(), nil, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
wg.Add(1)
|
|
|
|
go d.innerDiscoverPort(&wg, dataChan, host, dp)
|
|
|
|
wg.Wait()
|
|
|
|
if nil != d.stopChan {
|
|
|
|
close(d.stopChan)
|
|
|
|
d.stopChan = nil
|
|
|
|
}
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeStop, util.Now(), nil, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
|
2018-04-27 16:20:01 +00:00
|
|
|
func (d *defaultDiscoverer) DiscoverSerice(dataChan chan *DiscoveryData, port *ocmd.Port, ds *ocmd.DiscoverService) {
|
2018-04-19 11:36:56 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
d.stopChan = make(chan struct{})
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeStart, util.Now(), nil, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
wg.Add(1)
|
|
|
|
go d.innerDiscoverSerice(&wg, dataChan, port, ds)
|
|
|
|
wg.Wait()
|
|
|
|
if nil != d.stopChan {
|
|
|
|
close(d.stopChan)
|
|
|
|
d.stopChan = nil
|
|
|
|
}
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeStop, util.Now(), nil, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
|
2018-04-27 16:20:01 +00:00
|
|
|
func (d *defaultDiscoverer) innerDiscoverZone(wg *sync.WaitGroup, dataChan chan *DiscoveryData, dz *ocmd.DiscoverZone) {
|
2018-04-19 11:36:56 +00:00
|
|
|
defer func() {
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
taskScan(d,
|
|
|
|
func(resultChan chan interface{}, errChan chan error, doneChan chan struct{}, stopChan chan struct{}) {
|
|
|
|
scanZone(dz, resultChan, errChan, doneChan, stopChan)
|
|
|
|
},
|
|
|
|
func(result interface{}) {
|
2018-04-26 09:00:24 +00:00
|
|
|
z := result.(*ocmd.Zone)
|
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeZone, util.Now(), z, nil)
|
2018-04-27 16:20:01 +00:00
|
|
|
if nil != dz.DiscoverHost {
|
2018-04-19 11:36:56 +00:00
|
|
|
cr, _ := cidr.NewCIDRRanger(z.Network)
|
2018-04-27 16:20:01 +00:00
|
|
|
dh := &ocmd.DiscoverHost{
|
2018-04-27 16:56:47 +00:00
|
|
|
FirstScanRangeV4: cr.First().String(),
|
|
|
|
LastScanRangeV4: cr.Last().String(),
|
|
|
|
DiscoverPort: dz.DiscoverHost.DiscoverPort,
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
wg.Add(1)
|
2018-04-19 14:45:39 +00:00
|
|
|
go d.innerDiscoverHost(wg, dataChan, z, dh)
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
func(err error) {
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeError, util.Now(), nil, err)
|
2018-04-19 11:36:56 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-04-27 16:20:01 +00:00
|
|
|
func (d *defaultDiscoverer) innerDiscoverHost(wg *sync.WaitGroup, dataChan chan *DiscoveryData, zone *ocmd.Zone, dh *ocmd.DiscoverHost) {
|
2018-04-19 11:36:56 +00:00
|
|
|
defer func() {
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
taskScan(d,
|
|
|
|
func(resultChan chan interface{}, errChan chan error, doneChan chan struct{}, stopChan chan struct{}) {
|
|
|
|
scanHost(zone, dh, resultChan, errChan, doneChan, stopChan)
|
|
|
|
},
|
|
|
|
func(result interface{}) {
|
2018-04-26 09:00:24 +00:00
|
|
|
h := result.(*ocmd.Host)
|
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeHost, util.Now(), h, nil)
|
2018-04-27 16:20:01 +00:00
|
|
|
if nil != dh.DiscoverPort {
|
2018-04-19 11:36:56 +00:00
|
|
|
wg.Add(1)
|
2018-04-27 16:20:01 +00:00
|
|
|
go d.innerDiscoverPort(wg, dataChan, h, dh.DiscoverPort)
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
func(err error) {
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeError, util.Now(), nil, err)
|
2018-04-19 11:36:56 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-04-27 16:20:01 +00:00
|
|
|
func (d *defaultDiscoverer) innerDiscoverPort(wg *sync.WaitGroup, dataChan chan *DiscoveryData, host *ocmd.Host, dp *ocmd.DiscoverPort) {
|
2018-04-19 11:36:56 +00:00
|
|
|
defer func() {
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
taskScan(d,
|
|
|
|
func(resultChan chan interface{}, errChan chan error, doneChan chan struct{}, stopChan chan struct{}) {
|
|
|
|
scanPort(host, dp, resultChan, errChan, doneChan, stopChan)
|
|
|
|
},
|
|
|
|
func(result interface{}) {
|
2018-04-26 09:00:24 +00:00
|
|
|
p := result.(*ocmd.Port)
|
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypePort, util.Now(), p, nil)
|
2018-04-27 16:20:01 +00:00
|
|
|
if nil != dp.DiscoverService {
|
2018-04-19 11:36:56 +00:00
|
|
|
wg.Add(1)
|
2018-04-27 16:20:01 +00:00
|
|
|
go d.innerDiscoverSerice(wg, dataChan, p, dp.DiscoverService)
|
2018-04-19 11:36:56 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
func(err error) {
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeError, util.Now(), nil, err)
|
2018-04-19 11:36:56 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-04-27 16:20:01 +00:00
|
|
|
func (d *defaultDiscoverer) innerDiscoverSerice(wg *sync.WaitGroup, dataChan chan *DiscoveryData, port *ocmd.Port, ds *ocmd.DiscoverService) {
|
2018-04-19 11:36:56 +00:00
|
|
|
defer func() {
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
taskScan(d,
|
|
|
|
func(resultChan chan interface{}, errChan chan error, doneChan chan struct{}, stopChan chan struct{}) {
|
|
|
|
scanService(port, ds, resultChan, errChan, doneChan, stopChan)
|
|
|
|
},
|
|
|
|
func(result interface{}) {
|
2018-04-26 09:00:24 +00:00
|
|
|
s := result.(*ocmd.Service)
|
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeService, util.Now(), s, nil)
|
2018-04-19 11:36:56 +00:00
|
|
|
},
|
|
|
|
func(err error) {
|
2018-04-26 09:00:24 +00:00
|
|
|
dataChan <- retainDiscoveryData(DiscoveryDataTypeError, util.Now(), nil, err)
|
2018-04-19 11:36:56 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func taskScan(d *defaultDiscoverer,
|
|
|
|
taskFunc func(resultChan chan interface{}, errChan chan error, doneChan chan struct{}, stopChan chan struct{}),
|
|
|
|
reesultFunc func(result interface{}),
|
|
|
|
errorFunc func(err error)) {
|
|
|
|
|
|
|
|
resultChan := make(chan interface{})
|
|
|
|
errChan := make(chan error)
|
|
|
|
stopChan := make(chan struct{})
|
|
|
|
doneChan := make(chan struct{})
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
}()
|
|
|
|
|
|
|
|
go taskFunc(resultChan, errChan, doneChan, stopChan)
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case r := <-resultChan:
|
|
|
|
reesultFunc(r)
|
|
|
|
case err := <-errChan:
|
|
|
|
errorFunc(err)
|
|
|
|
case <-doneChan:
|
|
|
|
return
|
|
|
|
case <-d.stopChan:
|
|
|
|
close(stopChan)
|
|
|
|
<-doneChan
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var discoveryDataPool sync.Pool
|
|
|
|
|
2018-04-26 09:00:24 +00:00
|
|
|
func retainDiscoveryData(discoveryDataType DiscoveryDataType, t util.Timestamp, result interface{}, err error) *DiscoveryData {
|
2018-04-19 11:36:56 +00:00
|
|
|
v := discoveryDataPool.Get()
|
|
|
|
var discoveryData *DiscoveryData
|
|
|
|
if v == nil {
|
|
|
|
discoveryData = &DiscoveryData{}
|
|
|
|
} else {
|
|
|
|
discoveryData = v.(*DiscoveryData)
|
|
|
|
}
|
|
|
|
|
|
|
|
discoveryData.Type = discoveryDataType
|
|
|
|
discoveryData.Result = result
|
|
|
|
discoveryData.Error = err
|
|
|
|
|
|
|
|
return discoveryData
|
|
|
|
}
|
|
|
|
|
|
|
|
func releaseDiscoveryData(discoveryData *DiscoveryData) {
|
|
|
|
discoveryData.Type = DiscoveryDataTypeNone
|
|
|
|
discoveryData.Result = nil
|
|
|
|
discoveryData.Error = nil
|
|
|
|
|
|
|
|
discoveryDataPool.Put(discoveryData)
|
|
|
|
}
|