mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Merge branch 'develop' into neilalexander/tryall
This commit is contained in:
		
						commit
						1adc88ec77
					
				
					 13 changed files with 190 additions and 50 deletions
				
			
		
							
								
								
									
										18
									
								
								CHANGELOG.md
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								CHANGELOG.md
									
										
									
									
									
								
							| 
						 | 
					@ -26,6 +26,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 | 
				
			||||||
- in case of vulnerabilities.
 | 
					- in case of vulnerabilities.
 | 
				
			||||||
-->
 | 
					-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.4.7] - 2022-11-20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Added
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Dropped outbound peerings will now try to reconnect after a single second, rather than waiting up to 60 seconds for the normal peer timer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Session encryption keys are now rotated at most once per minute, which reduces CPU usage and improves throughput on fast low latency links
 | 
				
			||||||
 | 
					- Buffers are now reused in the session encryption handler, which improves session throughput and reduces memory allocations
 | 
				
			||||||
 | 
					- Buffers are now reused in the router for DHT and path traffic, which improves overall routing throughput and reduces memory allocations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Fixed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- A bug in the admin socket where requests fail unless `arguments` is specified has been fixed
 | 
				
			||||||
 | 
					- Certificates on TLS listeners will no longer expire after a year
 | 
				
			||||||
 | 
					- The `-address` and `-subnet` command line options now return a useful warning when no configuration is specified
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [0.4.6] - 2022-10-25
 | 
					## [0.4.6] - 2022-10-25
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Added
 | 
					### Added
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -247,7 +247,12 @@ func run(args yggArgs, ctx context.Context) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		// No flags were provided, therefore print the list of flags to stdout.
 | 
							// No flags were provided, therefore print the list of flags to stdout.
 | 
				
			||||||
 | 
							fmt.Println("Usage:")
 | 
				
			||||||
		flag.PrintDefaults()
 | 
							flag.PrintDefaults()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if args.getaddr || args.getsnet {
 | 
				
			||||||
 | 
								fmt.Println("\nError: You need to specify some config data using -useconf or -useconffile.")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Have we got a working configuration? If we don't then it probably means
 | 
						// Have we got a working configuration? If we don't then it probably means
 | 
				
			||||||
	// that neither -autoconf, -useconf or -useconffile were set above. Stop
 | 
						// that neither -autoconf, -useconf or -useconffile were set above. Stop
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,6 +159,11 @@ func (m *Yggdrasil) Stop() error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Retry resets the peer connection timer and tries to dial them immediately.
 | 
				
			||||||
 | 
					func (m *Yggdrasil) RetryPeersNow() {
 | 
				
			||||||
 | 
						m.core.RetryPeersNow()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GenerateConfigJSON generates mobile-friendly configuration in JSON format
 | 
					// GenerateConfigJSON generates mobile-friendly configuration in JSON format
 | 
				
			||||||
func GenerateConfigJSON() []byte {
 | 
					func GenerateConfigJSON() []byte {
 | 
				
			||||||
	nc := defaults.GenerateConfig()
 | 
						nc := defaults.GenerateConfig()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
										
									
									
									
								
							| 
						 | 
					@ -3,7 +3,7 @@ module github.com/yggdrasil-network/yggdrasil-go
 | 
				
			||||||
go 1.17
 | 
					go 1.17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2
 | 
						github.com/Arceliar/ironwood v0.0.0-20221115123222-ec61cea2f439
 | 
				
			||||||
	github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979
 | 
						github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979
 | 
				
			||||||
	github.com/cheggaaa/pb/v3 v3.0.8
 | 
						github.com/cheggaaa/pb/v3 v3.0.8
 | 
				
			||||||
	github.com/gologme/log v1.2.0
 | 
						github.com/gologme/log v1.2.0
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@ require (
 | 
				
			||||||
	github.com/kardianos/minwinsvc v1.0.2
 | 
						github.com/kardianos/minwinsvc v1.0.2
 | 
				
			||||||
	github.com/mitchellh/mapstructure v1.4.1
 | 
						github.com/mitchellh/mapstructure v1.4.1
 | 
				
			||||||
	github.com/vishvananda/netlink v1.1.0
 | 
						github.com/vishvananda/netlink v1.1.0
 | 
				
			||||||
	golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
 | 
						golang.org/x/mobile v0.0.0-20221110043201-43a038452099
 | 
				
			||||||
	golang.org/x/net v0.0.0-20221014081412-f15817d10f9b
 | 
						golang.org/x/net v0.0.0-20221014081412-f15817d10f9b
 | 
				
			||||||
	golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43
 | 
						golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43
 | 
				
			||||||
	golang.org/x/text v0.3.8
 | 
						golang.org/x/text v0.3.8
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								go.sum
									
										
									
									
									
								
							| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2 h1:Usab30pNT2i/vZvpXcN9uOr5IO1RZPcUqoGH0DIAPnU=
 | 
					github.com/Arceliar/ironwood v0.0.0-20221115123222-ec61cea2f439 h1:eOW6/XIs06TnUn9GPCnfv71CQZw8edP3u3mH3lZt6iM=
 | 
				
			||||||
github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk=
 | 
					github.com/Arceliar/ironwood v0.0.0-20221115123222-ec61cea2f439/go.mod h1:RP72rucOFm5udrnEzTmIWLRVGQiV/fSUAQXJ0RST/nk=
 | 
				
			||||||
github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ=
 | 
					github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979 h1:WndgpSW13S32VLQ3ugUxx2EnnWmgba1kCqPkd4Gk1yQ=
 | 
				
			||||||
github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI=
 | 
					github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI=
 | 
				
			||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 | 
					github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 | 
				
			||||||
| 
						 | 
					@ -55,8 +55,8 @@ golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9t
 | 
				
			||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 | 
					golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 | 
				
			||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
					golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
				
			||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 | 
					golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 | 
				
			||||||
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e h1:zSgtO19fpg781xknwqiQPmOHaASr6E7ZVlTseLd9Fx4=
 | 
					golang.org/x/mobile v0.0.0-20221110043201-43a038452099 h1:aIu0lKmfdgtn2uTj7JI2oN4TUrQvgB+wzTPO23bCKt8=
 | 
				
			||||||
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY=
 | 
					golang.org/x/mobile v0.0.0-20221110043201-43a038452099/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY=
 | 
				
			||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 | 
					golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 | 
				
			||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
					golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
				
			||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
 | 
					golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,7 +194,7 @@ func (c *Core) AddPeer(uri string, sourceInterface string) error {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	info, err := c.links.call(u, sourceInterface)
 | 
						info, err := c.links.call(u, sourceInterface, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -236,7 +236,7 @@ func (c *Core) RemovePeer(uri string, sourceInterface string) error {
 | 
				
			||||||
// This does not add the peer to the peer list, so if the connection drops, the
 | 
					// This does not add the peer to the peer list, so if the connection drops, the
 | 
				
			||||||
// peer will not be called again automatically.
 | 
					// peer will not be called again automatically.
 | 
				
			||||||
func (c *Core) CallPeer(u *url.URL, sintf string) error {
 | 
					func (c *Core) CallPeer(u *url.URL, sintf string) error {
 | 
				
			||||||
	_, err := c.links.call(u, sintf)
 | 
						_, err := c.links.call(u, sintf, nil)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,6 +121,13 @@ func (c *Core) _addPeerLoop() {
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Core) RetryPeersNow() {
 | 
				
			||||||
 | 
						if c.addPeerTimer != nil && !c.addPeerTimer.Stop() {
 | 
				
			||||||
 | 
							<-c.addPeerTimer.C
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c.Act(nil, c._addPeerLoop)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Stop shuts down the Yggdrasil node.
 | 
					// Stop shuts down the Yggdrasil node.
 | 
				
			||||||
func (c *Core) Stop() {
 | 
					func (c *Core) Stop() {
 | 
				
			||||||
	phony.Block(c, func() {
 | 
						phony.Block(c, func() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,11 @@ type linkInfo struct {
 | 
				
			||||||
	remote   string // Remote name or address
 | 
						remote   string // Remote name or address
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type linkDial struct {
 | 
				
			||||||
 | 
						url   *url.URL
 | 
				
			||||||
 | 
						sintf string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type link struct {
 | 
					type link struct {
 | 
				
			||||||
	lname    string
 | 
						lname    string
 | 
				
			||||||
	links    *links
 | 
						links    *links
 | 
				
			||||||
| 
						 | 
					@ -105,9 +110,12 @@ func (l *links) isConnectedTo(info linkInfo) bool {
 | 
				
			||||||
	return isConnected
 | 
						return isConnected
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *links) call(u *url.URL, sintf string) (linkInfo, error) {
 | 
					func (l *links) call(u *url.URL, sintf string, errch chan<- error) (info linkInfo, err error) {
 | 
				
			||||||
	info := linkInfoFor(u.Scheme, sintf, u.Host)
 | 
						info = linkInfoFor(u.Scheme, sintf, u.Host)
 | 
				
			||||||
	if l.isConnectedTo(info) {
 | 
						if l.isConnectedTo(info) {
 | 
				
			||||||
 | 
							if errch != nil {
 | 
				
			||||||
 | 
								close(errch) // already connected, no error
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return info, nil
 | 
							return info, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	options := linkOptions{
 | 
						options := linkOptions{
 | 
				
			||||||
| 
						 | 
					@ -116,6 +124,9 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) {
 | 
				
			||||||
	for _, pubkey := range u.Query()["key"] {
 | 
						for _, pubkey := range u.Query()["key"] {
 | 
				
			||||||
		sigPub, err := hex.DecodeString(pubkey)
 | 
							sigPub, err := hex.DecodeString(pubkey)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if errch != nil {
 | 
				
			||||||
 | 
									close(errch)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			return info, fmt.Errorf("pinned key contains invalid hex characters")
 | 
								return info, fmt.Errorf("pinned key contains invalid hex characters")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		var sigPubKey keyArray
 | 
							var sigPubKey keyArray
 | 
				
			||||||
| 
						 | 
					@ -125,6 +136,9 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) {
 | 
				
			||||||
	if p := u.Query().Get("priority"); p != "" {
 | 
						if p := u.Query().Get("priority"); p != "" {
 | 
				
			||||||
		pi, err := strconv.ParseUint(p, 10, 8)
 | 
							pi, err := strconv.ParseUint(p, 10, 8)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if errch != nil {
 | 
				
			||||||
 | 
									close(errch)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			return info, fmt.Errorf("priority invalid: %w", err)
 | 
								return info, fmt.Errorf("priority invalid: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		options.priority = uint8(pi)
 | 
							options.priority = uint8(pi)
 | 
				
			||||||
| 
						 | 
					@ -132,15 +146,27 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) {
 | 
				
			||||||
	switch info.linkType {
 | 
						switch info.linkType {
 | 
				
			||||||
	case "tcp":
 | 
						case "tcp":
 | 
				
			||||||
		go func() {
 | 
							go func() {
 | 
				
			||||||
 | 
								if errch != nil {
 | 
				
			||||||
 | 
									defer close(errch)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if err := l.tcp.dial(u, options, sintf); err != nil && err != io.EOF {
 | 
								if err := l.tcp.dial(u, options, sintf); err != nil && err != io.EOF {
 | 
				
			||||||
				l.core.log.Warnf("Failed to dial TCP %s: %s\n", u.Host, err)
 | 
									l.core.log.Warnf("Failed to dial TCP %s: %s\n", u.Host, err)
 | 
				
			||||||
 | 
									if errch != nil {
 | 
				
			||||||
 | 
										errch <- err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case "socks":
 | 
						case "socks":
 | 
				
			||||||
		go func() {
 | 
							go func() {
 | 
				
			||||||
 | 
								if errch != nil {
 | 
				
			||||||
 | 
									defer close(errch)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if err := l.socks.dial(u, options); err != nil && err != io.EOF {
 | 
								if err := l.socks.dial(u, options); err != nil && err != io.EOF {
 | 
				
			||||||
				l.core.log.Warnf("Failed to dial SOCKS %s: %s\n", u.Host, err)
 | 
									l.core.log.Warnf("Failed to dial SOCKS %s: %s\n", u.Host, err)
 | 
				
			||||||
 | 
									if errch != nil {
 | 
				
			||||||
 | 
										errch <- err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,19 +189,34 @@ func (l *links) call(u *url.URL, sintf string) (linkInfo, error) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		go func() {
 | 
							go func() {
 | 
				
			||||||
 | 
								if errch != nil {
 | 
				
			||||||
 | 
									defer close(errch)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if err := l.tls.dial(u, options, sintf, tlsSNI); err != nil && err != io.EOF {
 | 
								if err := l.tls.dial(u, options, sintf, tlsSNI); err != nil && err != io.EOF {
 | 
				
			||||||
				l.core.log.Warnf("Failed to dial TLS %s: %s\n", u.Host, err)
 | 
									l.core.log.Warnf("Failed to dial TLS %s: %s\n", u.Host, err)
 | 
				
			||||||
 | 
									if errch != nil {
 | 
				
			||||||
 | 
										errch <- err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case "unix":
 | 
						case "unix":
 | 
				
			||||||
		go func() {
 | 
							go func() {
 | 
				
			||||||
 | 
								if errch != nil {
 | 
				
			||||||
 | 
									defer close(errch)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if err := l.unix.dial(u, options, sintf); err != nil && err != io.EOF {
 | 
								if err := l.unix.dial(u, options, sintf); err != nil && err != io.EOF {
 | 
				
			||||||
				l.core.log.Warnf("Failed to dial UNIX %s: %s\n", u.Host, err)
 | 
									l.core.log.Warnf("Failed to dial UNIX %s: %s\n", u.Host, err)
 | 
				
			||||||
 | 
									if errch != nil {
 | 
				
			||||||
 | 
										errch <- err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
 | 
							if errch != nil {
 | 
				
			||||||
 | 
								close(errch)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return info, errors.New("unknown call scheme: " + u.Scheme)
 | 
							return info, errors.New("unknown call scheme: " + u.Scheme)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return info, nil
 | 
						return info, nil
 | 
				
			||||||
| 
						 | 
					@ -197,7 +238,7 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
 | 
				
			||||||
	return listener, err
 | 
						return listener, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *links) create(conn net.Conn, name string, info linkInfo, incoming, force bool, options linkOptions) error {
 | 
					func (l *links) create(conn net.Conn, dial *linkDial, name string, info linkInfo, incoming, force bool, options linkOptions) error {
 | 
				
			||||||
	intf := link{
 | 
						intf := link{
 | 
				
			||||||
		conn: &linkConn{
 | 
							conn: &linkConn{
 | 
				
			||||||
			Conn: conn,
 | 
								Conn: conn,
 | 
				
			||||||
| 
						 | 
					@ -211,14 +252,14 @@ func (l *links) create(conn net.Conn, name string, info linkInfo, incoming, forc
 | 
				
			||||||
		force:    force,
 | 
							force:    force,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		if err := intf.handler(); err != nil {
 | 
							if err := intf.handler(dial); err != nil {
 | 
				
			||||||
			l.core.log.Errorf("Link handler %s error (%s): %s", name, conn.RemoteAddr(), err)
 | 
								l.core.log.Errorf("Link handler %s error (%s): %s", name, conn.RemoteAddr(), err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (intf *link) handler() error {
 | 
					func (intf *link) handler(dial *linkDial) error {
 | 
				
			||||||
	defer intf.conn.Close() // nolint:errcheck
 | 
						defer intf.conn.Close() // nolint:errcheck
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Don't connect to this link more than once.
 | 
						// Don't connect to this link more than once.
 | 
				
			||||||
| 
						 | 
					@ -321,6 +362,30 @@ func (intf *link) handler() error {
 | 
				
			||||||
		intf.links.core.log.Infof("Disconnected %s %s: %s, source %s; error: %s",
 | 
							intf.links.core.log.Infof("Disconnected %s %s: %s, source %s; error: %s",
 | 
				
			||||||
			dir, strings.ToUpper(intf.info.linkType), remoteStr, localStr, err)
 | 
								dir, strings.ToUpper(intf.info.linkType), remoteStr, localStr, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !intf.incoming && dial != nil {
 | 
				
			||||||
 | 
							// The connection was one that we dialled, so wait a second and try to
 | 
				
			||||||
 | 
							// dial it again.
 | 
				
			||||||
 | 
							var retry func(attempt int)
 | 
				
			||||||
 | 
							retry = func(attempt int) {
 | 
				
			||||||
 | 
								// intf.links.core.log.Infof("Retrying %s (attempt %d of 5)...", dial.url.String(), attempt)
 | 
				
			||||||
 | 
								errch := make(chan error, 1)
 | 
				
			||||||
 | 
								if _, err := intf.links.call(dial.url, dial.sintf, errch); err != nil {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if err := <-errch; err != nil {
 | 
				
			||||||
 | 
									if attempt < 3 {
 | 
				
			||||||
 | 
										time.AfterFunc(time.Second, func() {
 | 
				
			||||||
 | 
											retry(attempt + 1)
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							time.AfterFunc(time.Second, func() {
 | 
				
			||||||
 | 
								retry(1)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,13 +37,17 @@ func (l *linkSOCKS) dial(url *url.URL, options linkOptions) error {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return l.handler(url.String(), info, conn, options, false)
 | 
						dial := &linkDial{
 | 
				
			||||||
 | 
							url: url,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return l.handler(dial, info, conn, options, false)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *linkSOCKS) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error {
 | 
					func (l *linkSOCKS) handler(dial *linkDial, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error {
 | 
				
			||||||
	return l.links.create(
 | 
						return l.links.create(
 | 
				
			||||||
		conn,              // connection
 | 
							conn,              // connection
 | 
				
			||||||
		name,     // connection name
 | 
							dial,              // connection URL
 | 
				
			||||||
 | 
							dial.url.String(), // connection name
 | 
				
			||||||
		info,              // connection info
 | 
							info,              // connection info
 | 
				
			||||||
		incoming,          // not incoming
 | 
							incoming,          // not incoming
 | 
				
			||||||
		false,             // not forced
 | 
							false,             // not forced
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,10 +32,6 @@ func (l *links) newLinkTCP() *linkTCP {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *linkTCP) dial(url *url.URL, options linkOptions, sintf string) error {
 | 
					func (l *linkTCP) dial(url *url.URL, options linkOptions, sintf string) error {
 | 
				
			||||||
	info := linkInfoFor("tcp", sintf, url.Host)
 | 
					 | 
				
			||||||
	if l.links.isConnectedTo(info) {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	host, p, err := net.SplitHostPort(url.Host)
 | 
						host, p, err := net.SplitHostPort(url.Host)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
| 
						 | 
					@ -57,12 +53,20 @@ func (l *linkTCP) dial(url *url.URL, options linkOptions, sintf string) error {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							info := linkInfoFor("tcp", sintf, tcpIDFor(dialer.LocalAddr, addr))
 | 
				
			||||||
 | 
							if l.links.isConnectedTo(info) {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		conn, err := dialer.DialContext(l.core.ctx, "tcp", addr.String())
 | 
							conn, err := dialer.DialContext(l.core.ctx, "tcp", addr.String())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		uri := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/")
 | 
							name := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/")
 | 
				
			||||||
		return l.handler(uri, info, conn, options, false, false)
 | 
							dial := &linkDial{
 | 
				
			||||||
 | 
								url:   url,
 | 
				
			||||||
 | 
								sintf: sintf,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return l.handler(dial, name, info, conn, options, false, false)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return fmt.Errorf("failed to connect via %d addresses", len(ips))
 | 
						return fmt.Errorf("failed to connect via %d addresses", len(ips))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -98,10 +102,11 @@ func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
				
			||||||
				cancel()
 | 
									cancel()
 | 
				
			||||||
				break
 | 
									break
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								laddr := conn.LocalAddr().(*net.TCPAddr)
 | 
				
			||||||
			raddr := conn.RemoteAddr().(*net.TCPAddr)
 | 
								raddr := conn.RemoteAddr().(*net.TCPAddr)
 | 
				
			||||||
			name := fmt.Sprintf("tcp://%s", raddr)
 | 
								name := fmt.Sprintf("tcp://%s", raddr)
 | 
				
			||||||
			info := linkInfoFor("tcp", sintf, raddr.String())
 | 
								info := linkInfoFor("tcp", sintf, tcpIDFor(laddr, raddr))
 | 
				
			||||||
			if err = l.handler(name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil {
 | 
								if err = l.handler(nil, name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil {
 | 
				
			||||||
				l.core.log.Errorln("Failed to create inbound link:", err)
 | 
									l.core.log.Errorln("Failed to create inbound link:", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -112,9 +117,10 @@ func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
				
			||||||
	return entry, nil
 | 
						return entry, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *linkTCP) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error {
 | 
					func (l *linkTCP) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error {
 | 
				
			||||||
	return l.links.create(
 | 
						return l.links.create(
 | 
				
			||||||
		conn,     // connection
 | 
							conn,     // connection
 | 
				
			||||||
 | 
							dial,     // connection URL
 | 
				
			||||||
		name,     // connection name
 | 
							name,     // connection name
 | 
				
			||||||
		info,     // connection info
 | 
							info,     // connection info
 | 
				
			||||||
		incoming, // not incoming
 | 
							incoming, // not incoming
 | 
				
			||||||
| 
						 | 
					@ -195,3 +201,16 @@ func (l *linkTCP) dialerFor(dst *net.TCPAddr, sintf string) (*net.Dialer, error)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return dialer, nil
 | 
						return dialer, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func tcpIDFor(local net.Addr, remoteAddr *net.TCPAddr) string {
 | 
				
			||||||
 | 
						if localAddr, ok := local.(*net.TCPAddr); ok && localAddr.IP.Equal(remoteAddr.IP) {
 | 
				
			||||||
 | 
							// Nodes running on the same host — include both the IP and port.
 | 
				
			||||||
 | 
							return remoteAddr.String()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if remoteAddr.IP.IsLinkLocalUnicast() {
 | 
				
			||||||
 | 
							// Nodes discovered via multicast — include the IP only.
 | 
				
			||||||
 | 
							return remoteAddr.IP.String()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Nodes connected remotely — include both the IP and port.
 | 
				
			||||||
 | 
						return remoteAddr.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,10 +48,6 @@ func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *linkTLS) dial(url *url.URL, options linkOptions, sintf, sni string) error {
 | 
					func (l *linkTLS) dial(url *url.URL, options linkOptions, sintf, sni string) error {
 | 
				
			||||||
	info := linkInfoFor("tls", sintf, url.Host)
 | 
					 | 
				
			||||||
	if l.links.isConnectedTo(info) {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	host, p, err := net.SplitHostPort(url.Host)
 | 
						host, p, err := net.SplitHostPort(url.Host)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
| 
						 | 
					@ -73,6 +69,10 @@ func (l *linkTLS) dial(url *url.URL, options linkOptions, sintf, sni string) err
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							info := linkInfoFor("tls", sintf, tcpIDFor(dialer.LocalAddr, addr))
 | 
				
			||||||
 | 
							if l.links.isConnectedTo(info) {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		tlsconfig := l.config.Clone()
 | 
							tlsconfig := l.config.Clone()
 | 
				
			||||||
		tlsconfig.ServerName = sni
 | 
							tlsconfig.ServerName = sni
 | 
				
			||||||
		tlsdialer := &tls.Dialer{
 | 
							tlsdialer := &tls.Dialer{
 | 
				
			||||||
| 
						 | 
					@ -83,8 +83,12 @@ func (l *linkTLS) dial(url *url.URL, options linkOptions, sintf, sni string) err
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		uri := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/")
 | 
							name := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/")
 | 
				
			||||||
		return l.handler(uri, info, conn, options, false, false)
 | 
							dial := &linkDial{
 | 
				
			||||||
 | 
								url:   url,
 | 
				
			||||||
 | 
								sintf: sintf,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return l.handler(dial, name, info, conn, options, false, false)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return fmt.Errorf("failed to connect via %d addresses", len(ips))
 | 
						return fmt.Errorf("failed to connect via %d addresses", len(ips))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -121,10 +125,11 @@ func (l *linkTLS) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
				
			||||||
				cancel()
 | 
									cancel()
 | 
				
			||||||
				break
 | 
									break
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								laddr := conn.LocalAddr().(*net.TCPAddr)
 | 
				
			||||||
			raddr := conn.RemoteAddr().(*net.TCPAddr)
 | 
								raddr := conn.RemoteAddr().(*net.TCPAddr)
 | 
				
			||||||
			name := fmt.Sprintf("tls://%s", raddr)
 | 
								name := fmt.Sprintf("tls://%s", raddr)
 | 
				
			||||||
			info := linkInfoFor("tls", sintf, raddr.String())
 | 
								info := linkInfoFor("tls", sintf, tcpIDFor(laddr, raddr))
 | 
				
			||||||
			if err = l.handler(name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil {
 | 
								if err = l.handler(nil, name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil {
 | 
				
			||||||
				l.core.log.Errorln("Failed to create inbound link:", err)
 | 
									l.core.log.Errorln("Failed to create inbound link:", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -135,20 +140,18 @@ func (l *linkTLS) listen(url *url.URL, sintf string) (*Listener, error) {
 | 
				
			||||||
	return entry, nil
 | 
						return entry, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RFC5280 section 4.1.2.5
 | 
				
			||||||
 | 
					var notAfterNeverExpires = time.Date(9999, time.December, 31, 23, 59, 59, 0, time.UTC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *linkTLS) generateConfig() (*tls.Config, error) {
 | 
					func (l *linkTLS) generateConfig() (*tls.Config, error) {
 | 
				
			||||||
	certBuf := &bytes.Buffer{}
 | 
						certBuf := &bytes.Buffer{}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// TODO: because NotAfter is finite, we should add some mechanism to
 | 
					 | 
				
			||||||
	// regenerate the certificate and restart the listeners periodically
 | 
					 | 
				
			||||||
	// for nodes with very high uptimes. Perhaps regenerate certs and restart
 | 
					 | 
				
			||||||
	// listeners every few months or so.
 | 
					 | 
				
			||||||
	cert := x509.Certificate{
 | 
						cert := x509.Certificate{
 | 
				
			||||||
		SerialNumber: big.NewInt(1),
 | 
							SerialNumber: big.NewInt(1),
 | 
				
			||||||
		Subject: pkix.Name{
 | 
							Subject: pkix.Name{
 | 
				
			||||||
			CommonName: hex.EncodeToString(l.links.core.public[:]),
 | 
								CommonName: hex.EncodeToString(l.links.core.public[:]),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		NotBefore:             time.Now(),
 | 
							NotBefore:             time.Now(),
 | 
				
			||||||
		NotAfter:              time.Now().Add(time.Hour * 24 * 365),
 | 
							NotAfter:              notAfterNeverExpires,
 | 
				
			||||||
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
 | 
							KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
 | 
				
			||||||
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
 | 
							ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
 | 
				
			||||||
		BasicConstraintsValid: true,
 | 
							BasicConstraintsValid: true,
 | 
				
			||||||
| 
						 | 
					@ -182,6 +185,6 @@ func (l *linkTLS) generateConfig() (*tls.Config, error) {
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *linkTLS) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error {
 | 
					func (l *linkTLS) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error {
 | 
				
			||||||
	return l.tcp.handler(name, info, conn, options, incoming, force)
 | 
						return l.tcp.handler(dial, name, info, conn, options, incoming, force)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,10 @@ func (l *linkUNIX) dial(url *url.URL, options linkOptions, _ string) error {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return l.handler(url.String(), info, conn, options, false)
 | 
						dial := &linkDial{
 | 
				
			||||||
 | 
							url: url,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return l.handler(dial, url.String(), info, conn, options, false)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *linkUNIX) listen(url *url.URL, _ string) (*Listener, error) {
 | 
					func (l *linkUNIX) listen(url *url.URL, _ string) (*Listener, error) {
 | 
				
			||||||
| 
						 | 
					@ -74,7 +77,7 @@ func (l *linkUNIX) listen(url *url.URL, _ string) (*Listener, error) {
 | 
				
			||||||
				break
 | 
									break
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			info := linkInfoFor("unix", "", url.String())
 | 
								info := linkInfoFor("unix", "", url.String())
 | 
				
			||||||
			if err = l.handler(url.String(), info, conn, linkOptionsForListener(url), true); err != nil {
 | 
								if err = l.handler(nil, url.String(), info, conn, linkOptionsForListener(url), true); err != nil {
 | 
				
			||||||
				l.core.log.Errorln("Failed to create inbound link:", err)
 | 
									l.core.log.Errorln("Failed to create inbound link:", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -85,9 +88,10 @@ func (l *linkUNIX) listen(url *url.URL, _ string) (*Listener, error) {
 | 
				
			||||||
	return entry, nil
 | 
						return entry, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *linkUNIX) handler(name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error {
 | 
					func (l *linkUNIX) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming bool) error {
 | 
				
			||||||
	return l.links.create(
 | 
						return l.links.create(
 | 
				
			||||||
		conn,     // connection
 | 
							conn,     // connection
 | 
				
			||||||
 | 
							dial,     // connection URL
 | 
				
			||||||
		name,     // connection name
 | 
							name,     // connection name
 | 
				
			||||||
		info,     // connection info
 | 
							info,     // connection info
 | 
				
			||||||
		incoming, // not incoming
 | 
							incoming, // not incoming
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ type Multicast struct {
 | 
				
			||||||
	_isOpen     bool
 | 
						_isOpen     bool
 | 
				
			||||||
	_listeners  map[string]*listenerInfo
 | 
						_listeners  map[string]*listenerInfo
 | 
				
			||||||
	_interfaces map[string]*interfaceInfo
 | 
						_interfaces map[string]*interfaceInfo
 | 
				
			||||||
 | 
						_timer      *time.Timer
 | 
				
			||||||
	config      struct {
 | 
						config      struct {
 | 
				
			||||||
		_groupAddr  GroupAddress
 | 
							_groupAddr  GroupAddress
 | 
				
			||||||
		_interfaces map[MulticastInterface]struct{}
 | 
							_interfaces map[MulticastInterface]struct{}
 | 
				
			||||||
| 
						 | 
					@ -207,6 +208,15 @@ func (m *Multicast) _getAllowedInterfaces() map[string]*interfaceInfo {
 | 
				
			||||||
	return interfaces
 | 
						return interfaces
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Multicast) AnnounceNow() {
 | 
				
			||||||
 | 
						phony.Block(m, func() {
 | 
				
			||||||
 | 
							if m._timer != nil && !m._timer.Stop() {
 | 
				
			||||||
 | 
								<-m._timer.C
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							m.Act(nil, m._announce)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Multicast) _announce() {
 | 
					func (m *Multicast) _announce() {
 | 
				
			||||||
	if !m._isOpen {
 | 
						if !m._isOpen {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -329,7 +339,7 @@ func (m *Multicast) _announce() {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	time.AfterFunc(time.Second, func() {
 | 
						m._timer = time.AfterFunc(time.Second, func() {
 | 
				
			||||||
		m.Act(nil, m._announce)
 | 
							m.Act(nil, m._announce)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue