6 Commits

Author SHA1 Message Date
eyedeekay
c6312df797 enhance README and refactor router initialization methods for improved clarity and structure 2025-09-07 15:50:42 -04:00
eyedeekay
9c7e791376 GODOC UPDATE CHECKIN 2025-08-22 18:42:51 -04:00
eyedeekay
9effc63e85 work on boostrap config 2025-08-22 18:29:31 -04:00
eyedeekay
06b1464c97 fix error constants 2025-08-22 17:14:52 -04:00
eyedeekay
d278f0d66e fix timestamper 2025-08-22 17:12:53 -04:00
eyedeekay
89243ead72 fix flipped fragmentation bit check 2025-08-22 16:53:49 -04:00
35 changed files with 9623 additions and 8213 deletions

View File

@@ -77,6 +77,10 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Connection management
- [ ] Peer Tests
- [ ] Introducers
- [Noise Subsystem (see also https://github.com/go-i2p/go-noise)](https://github.com/go-i2p/go-noise)
- [X] Noise Socket Framework
- [X] NTCP2 Socket Framework
- [ ] SSU2 Socket Framework
- Tunnels
- [X] Message structure parsing (delivery instructions)
- [X] Fragment handling and reassembly

2
go.mod
View File

@@ -6,7 +6,7 @@ require (
github.com/beevik/ntp v1.4.3
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e
github.com/go-i2p/common v0.0.0-20250715213359-dfa5527ece83
github.com/go-i2p/crypto v0.0.0-20250716230511-565a0995440c
github.com/go-i2p/crypto v0.0.0-20250728221606-06ae9eeb4fda
github.com/go-i2p/go-noise v0.0.0-20250805210353-74f980a2439d
github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c
github.com/go-i2p/su3 v0.0.0-20250716183548-497fadf45e84

2
go.sum
View File

@@ -19,6 +19,8 @@ github.com/go-i2p/common v0.0.0-20250715213359-dfa5527ece83 h1:F6xM06QyqR+qMYA4S
github.com/go-i2p/common v0.0.0-20250715213359-dfa5527ece83/go.mod h1:e6X6esQk0zaevdZPZecKY7n8+wOfOLukQfWw558DYfk=
github.com/go-i2p/crypto v0.0.0-20250716230511-565a0995440c h1:s+bMNveuZg8rhIolwy7w451Y4qirhhYZbbmvLfBIDw4=
github.com/go-i2p/crypto v0.0.0-20250716230511-565a0995440c/go.mod h1:5felGikM6K5D95TLvVxew1UfR0BdtPpfmJLZa8cuY5U=
github.com/go-i2p/crypto v0.0.0-20250728221606-06ae9eeb4fda h1:hO4Q8Uh/jf0NkZt7qJgs9jX9d4pDkvQl9ZdKeEQv8OQ=
github.com/go-i2p/crypto v0.0.0-20250728221606-06ae9eeb4fda/go.mod h1:5felGikM6K5D95TLvVxew1UfR0BdtPpfmJLZa8cuY5U=
github.com/go-i2p/go-noise v0.0.0-20250805210353-74f980a2439d h1:4DKwGZZ2yalAjrrOTw9Zoz31lOMXysw5PZTqKYazlVw=
github.com/go-i2p/go-noise v0.0.0-20250805210353-74f980a2439d/go.mod h1:lNh+uKTp1nBVhY1MqJ7sNQWORRf1SMmYvu10Suv0zT8=
github.com/go-i2p/logger v0.0.0-20241123010126-3050657e5d0c h1:VTiECn3dFEmUlZjto+wOwJ7SSJTHPLyNprQMR5HzIMI=

View File

@@ -17,7 +17,7 @@ type Bootstrap interface {
// try obtaining at most n router infos
// if n is 0 then try obtaining as many router infos as possible
// returns nil and error if we cannot fetch ANY router infos
// returns a channel that yields 1 slice of router infos containing n or fewer router infos, caller must close channel after use
// returns a slice of router infos containing n or fewer router infos
GetPeers(ctx context.Context, n int) ([]router_info.RouterInfo, error)
}
```

View File

@@ -12,6 +12,6 @@ type Bootstrap interface {
// try obtaining at most n router infos
// if n is 0 then try obtaining as many router infos as possible
// returns nil and error if we cannot fetch ANY router infos
// returns a channel that yields 1 slice of router infos containing n or fewer router infos, caller must close channel after use
// returns a slice of router infos containing n or fewer router infos
GetPeers(ctx context.Context, n int) ([]router_info.RouterInfo, error)
}

View File

@@ -46,38 +46,10 @@
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init -->
<g id="node1" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init</title>
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init | defined in .:0&#10;at reseed_bootstrap.go:15: calling [github.com/go&#45;i2p/logger.GetGoI2PLogger]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M96.2644,-52C96.2644,-52 66.2644,-52 66.2644,-52 60.2644,-52 54.2644,-46 54.2644,-40 54.2644,-40 54.2644,-28 54.2644,-28 54.2644,-22 60.2644,-16 66.2644,-16 66.2644,-16 96.2644,-16 96.2644,-16 102.2644,-16 108.2644,-22 108.2644,-28 108.2644,-28 108.2644,-40 108.2644,-40 108.2644,-46 102.2644,-52 96.2644,-52"/>
<text text-anchor="middle" x="81.2644" y="-29.8" font-family="Verdana" font-size="14.00" fill="#000000">init</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/logger.GetGoI2PLogger -->
<g id="node2" class="node">
<title>github.com/go&#45;i2p/logger.GetGoI2PLogger</title>
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/logger.GetGoI2PLogger | defined in log.go:120">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M336.813,-52C336.813,-52 239.434,-52 239.434,-52 233.434,-52 227.434,-46 227.434,-40 227.434,-40 227.434,-28 227.434,-28 227.434,-22 233.434,-16 239.434,-16 239.434,-16 336.813,-16 336.813,-16 342.813,-16 348.813,-22 348.813,-28 348.813,-28 348.813,-40 348.813,-40 348.813,-46 342.813,-52 336.813,-52"/>
<text text-anchor="middle" x="288.1235" y="-38.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="288.1235" y="-21.4" font-family="Verdana" font-size="14.00" fill="#000000">GetGoI2PLogger</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init&#45;&gt;github.com/go&#45;i2p/logger.GetGoI2PLogger -->
<g id="edge7" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init&#45;&gt;github.com/go&#45;i2p/logger.GetGoI2PLogger</title>
<g id="a_edge7"><a xlink:title="at reseed_bootstrap.go:15: calling [github.com/go&#45;i2p/logger.GetGoI2PLogger]">
<path fill="none" stroke="#8b4513" d="M108.3076,-34C135.736,-34 179.3573,-34 216.7663,-34"/>
<polygon fill="#8b4513" stroke="#8b4513" points="217.1342,-37.5001 227.1342,-34 217.1341,-30.5001 217.1342,-37.5001"/>
</a>
</g>
</g>
<!-- github.com/samber/oops.Errorf -->
<g id="node3" class="node">
<g id="node1" class="node">
<title>github.com/samber/oops.Errorf</title>
<g id="a_node3"><a xlink:title="github.com/samber/oops.Errorf | defined in oops.go:34">
<g id="a_node1"><a xlink:title="github.com/samber/oops.Errorf | defined in oops.go:34">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M305.3188,-113C305.3188,-113 270.9282,-113 270.9282,-113 264.9282,-113 258.9282,-107 258.9282,-101 258.9282,-101 258.9282,-89 258.9282,-89 258.9282,-83 264.9282,-77 270.9282,-77 270.9282,-77 305.3188,-77 305.3188,-77 311.3188,-77 317.3188,-83 317.3188,-89 317.3188,-89 317.3188,-101 317.3188,-101 317.3188,-107 311.3188,-113 305.3188,-113"/>
<text text-anchor="middle" x="288.1235" y="-99.2" font-family="Verdana" font-size="14.00" fill="#000000">oops</text>
<text text-anchor="middle" x="288.1235" y="-82.4" font-family="Verdana" font-size="14.00" fill="#000000">Errorf</text>
@@ -85,28 +57,56 @@
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed -->
<g id="node4" class="node">
<g id="node2" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed</title>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed | defined in new.go:10">
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed | defined in new.go:10">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M321.4764,-174C321.4764,-174 254.7706,-174 254.7706,-174 248.7706,-174 242.7706,-168 242.7706,-162 242.7706,-162 242.7706,-150 242.7706,-150 242.7706,-144 248.7706,-138 254.7706,-138 254.7706,-138 321.4764,-138 321.4764,-138 327.4764,-138 333.4764,-144 333.4764,-150 333.4764,-150 333.4764,-162 333.4764,-162 333.4764,-168 327.4764,-174 321.4764,-174"/>
<text text-anchor="middle" x="288.1235" y="-160.2" font-family="Verdana" font-size="14.00" fill="#000000">reseed</text>
<text text-anchor="middle" x="288.1235" y="-143.4" font-family="Verdana" font-size="14.00" fill="#000000">NewReseed</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init -->
<g id="node3" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init</title>
<g id="a_node3"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init | defined in .:0&#10;at reseed_bootstrap.go:15: calling [github.com/go&#45;i2p/logger.GetGoI2PLogger]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M96.2644,-52C96.2644,-52 66.2644,-52 66.2644,-52 60.2644,-52 54.2644,-46 54.2644,-40 54.2644,-40 54.2644,-28 54.2644,-28 54.2644,-22 60.2644,-16 66.2644,-16 66.2644,-16 96.2644,-16 96.2644,-16 102.2644,-16 108.2644,-22 108.2644,-28 108.2644,-28 108.2644,-40 108.2644,-40 108.2644,-46 102.2644,-52 96.2644,-52"/>
<text text-anchor="middle" x="81.2644" y="-29.8" font-family="Verdana" font-size="14.00" fill="#000000">init</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/logger.GetGoI2PLogger -->
<g id="node4" class="node">
<title>github.com/go&#45;i2p/logger.GetGoI2PLogger</title>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/logger.GetGoI2PLogger | defined in log.go:120">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M336.813,-52C336.813,-52 239.434,-52 239.434,-52 233.434,-52 227.434,-46 227.434,-40 227.434,-40 227.434,-28 227.434,-28 227.434,-22 233.434,-16 239.434,-16 239.434,-16 336.813,-16 336.813,-16 342.813,-16 348.813,-22 348.813,-28 348.813,-28 348.813,-40 348.813,-40 348.813,-46 342.813,-52 336.813,-52"/>
<text text-anchor="middle" x="288.1235" y="-38.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="288.1235" y="-21.4" font-family="Verdana" font-size="14.00" fill="#000000">GetGoI2PLogger</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init&#45;&gt;github.com/go&#45;i2p/logger.GetGoI2PLogger -->
<g id="edge10" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.init&#45;&gt;github.com/go&#45;i2p/logger.GetGoI2PLogger</title>
<g id="a_edge10"><a xlink:title="at reseed_bootstrap.go:15: calling [github.com/go&#45;i2p/logger.GetGoI2PLogger]">
<path fill="none" stroke="#8b4513" d="M108.3076,-34C135.736,-34 179.3573,-34 216.7663,-34"/>
<polygon fill="#8b4513" stroke="#8b4513" points="217.1342,-37.5001 227.1342,-34 217.1341,-30.5001 217.1342,-37.5001"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers -->
<g id="node5" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers</title>
<g id="a_node5"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers | defined in reseed_bootstrap.go:32&#10;at reseed_bootstrap.go:43: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:43: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at reseed_bootstrap.go:46: calling [github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed]&#10;at reseed_bootstrap.go:49: calling [(github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]&#10;at reseed_bootstrap.go:40: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:52: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:72: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:58: calling [(*github.com/go&#45;i2p/logger.Logger).WithFields]&#10;at reseed_bootstrap.go:62: calling [(*github.com/sirupsen/logrus.Logger).Info]">
<g id="a_node5"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers | defined in reseed_bootstrap.go:32&#10;at reseed_bootstrap.go:40: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:52: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:72: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:43: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:46: calling [github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.NewReseed]&#10;at reseed_bootstrap.go:49: calling [(github.com/go&#45;i2p/go&#45;i2p/lib/netdb/reseed.Reseed).SingleReseed]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]&#10;at reseed_bootstrap.go:62: calling [(*github.com/sirupsen/logrus.Logger).Info]&#10;at reseed_bootstrap.go:43: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at reseed_bootstrap.go:58: calling [(*github.com/go&#45;i2p/logger.Logger).WithFields]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M106.2947,-374C106.2947,-374 56.2341,-374 56.2341,-374 50.2341,-374 44.2341,-368 44.2341,-362 44.2341,-362 44.2341,-350 44.2341,-350 44.2341,-344 50.2341,-338 56.2341,-338 56.2341,-338 106.2947,-338 106.2947,-338 112.2947,-338 118.2947,-344 118.2947,-350 118.2947,-350 118.2947,-362 118.2947,-362 118.2947,-368 112.2947,-374 106.2947,-374"/>
<text text-anchor="middle" x="81.2644" y="-351.8" font-family="Verdana" font-size="14.00" fill="#000000">GetPeers</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;github.com/samber/oops.Errorf -->
<g id="edge8" class="edge">
<g id="edge1" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;github.com/samber/oops.Errorf</title>
<g id="a_edge8"><a xlink:title="at reseed_bootstrap.go:40: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:52: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:72: calling [github.com/samber/oops.Errorf]">
<g id="a_edge1"><a xlink:title="at reseed_bootstrap.go:40: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:52: calling [github.com/samber/oops.Errorf]&#10;at reseed_bootstrap.go:72: calling [github.com/samber/oops.Errorf]">
<path fill="none" stroke="#8b4513" d="M118.4074,-352.073C131.5385,-349.0001 145.5161,-343.5697 155.5288,-334 190.8891,-300.2044 195.4391,-162.9154 227.5288,-126 233.5557,-119.0668 241.5102,-113.4857 249.6658,-109.0748"/>
<polygon fill="#8b4513" stroke="#8b4513" points="251.4166,-112.115 258.8672,-104.5824 248.3454,-105.8247 251.4166,-112.115"/>
</a>
@@ -132,9 +132,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge1" class="edge">
<g id="edge2" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge1"><a xlink:title="at reseed_bootstrap.go:43: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<g id="a_edge2"><a xlink:title="at reseed_bootstrap.go:43: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at reseed_bootstrap.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M118.5683,-348.6617C130.8549,-345.2944 144.2489,-340.5496 155.5288,-334 193.8581,-311.7444 191.4175,-290.6986 227.5288,-265 231.4159,-262.2337 235.5842,-259.5689 239.8482,-257.0424"/>
<polygon fill="#8b4513" stroke="#8b4513" points="241.6859,-260.0242 248.6757,-252.0623 238.2464,-253.9275 241.6859,-260.0242"/>
</a>
@@ -208,9 +208,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge2" class="edge">
<g id="edge8" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge2"><a xlink:title="at reseed_bootstrap.go:43: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<g id="a_edge8"><a xlink:title="at reseed_bootstrap.go:43: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M106.6294,-374.0251C143.6948,-400.3648 212.738,-449.4289 254.1541,-478.8604"/>
<polygon fill="#8b4513" stroke="#8b4513" points="252.3722,-481.8878 262.551,-484.8275 256.427,-476.1818 252.3722,-481.8878"/>
</a>
@@ -227,9 +227,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/sirupsen/logrus.Logger).Info -->
<g id="edge10" class="edge">
<g id="edge7" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/bootstrap.ReseedBootstrap).GetPeers&#45;&gt;(*github.com/sirupsen/logrus.Logger).Info</title>
<g id="a_edge10"><a xlink:title="at reseed_bootstrap.go:62: calling [(*github.com/sirupsen/logrus.Logger).Info]">
<g id="a_edge7"><a xlink:title="at reseed_bootstrap.go:62: calling [(*github.com/sirupsen/logrus.Logger).Info]">
<path fill="none" stroke="#8b4513" d="M92.3256,-374.0399C114.3749,-408.7975 166.9292,-485.8578 227.5288,-534 234.1285,-539.243 241.7932,-543.9051 249.4061,-547.8995"/>
<polygon fill="#8b4513" stroke="#8b4513" points="248.0753,-551.1458 258.5915,-552.435 251.1745,-544.8692 248.0753,-551.1458"/>
</a>

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -22,7 +22,20 @@ var (
var DefaultBootstrapConfig = BootstrapConfig{
LowPeerThreshold: 10,
ReseedServers: []*ReseedConfig{},
ReseedServers: []*ReseedConfig{
{
Url: "https://reseed.i2p-projekt.de/",
SU3Fingerprint: "PLACEHOLDER_FINGERPRINT_1",
},
{
Url: "https://i2p.mooo.com/netDb/",
SU3Fingerprint: "PLACEHOLDER_FINGERPRINT_2",
},
{
Url: "https://netdb.i2p2.no/",
SU3Fingerprint: "PLACEHOLDER_FINGERPRINT_3",
},
},
}
```
default configuration for network bootstrap
@@ -37,6 +50,10 @@ default settings for netdb
```go
var RouterConfigProperties = DefaultRouterConfig()
```
RouterConfigProperties is a global mutable configuration object DEPRECATED: This
global variable is mutated by UpdateRouterConfig() creating hidden dependencies
and making testing difficult. Use NewRouterConfigFromViper() instead to get a
fresh config object without global state issues.
#### func BuildI2PDirPath
@@ -55,6 +72,9 @@ func InitConfig()
```go
func UpdateRouterConfig()
```
UpdateRouterConfig updates the global RouterConfigProperties from viper settings
DEPRECATED: Use NewRouterConfigFromViper() instead to avoid global state
mutation
#### type BootstrapConfig
@@ -115,6 +135,15 @@ router.config options
func DefaultRouterConfig() *RouterConfig
```
#### func NewRouterConfigFromViper
```go
func NewRouterConfigFromViper() *RouterConfig
```
NewRouterConfigFromViper creates a new RouterConfig from current viper settings
This is the preferred way to get config instead of using the global
RouterConfigProperties
config

View File

@@ -18,6 +18,21 @@ type BootstrapConfig struct {
// default configuration for network bootstrap
var DefaultBootstrapConfig = BootstrapConfig{
LowPeerThreshold: 10,
// TODO: add reseed servers
ReseedServers: []*ReseedConfig{},
// Standard I2P reseed servers for network bootstrap
// These are example reseed servers - in production, use actual I2P reseed servers
// with their correct SU3 signing key fingerprints
ReseedServers: []*ReseedConfig{
{
Url: "https://reseed.i2p-projekt.de/",
SU3Fingerprint: "PLACEHOLDER_FINGERPRINT_1",
},
{
Url: "https://i2p.mooo.com/netDb/",
SU3Fingerprint: "PLACEHOLDER_FINGERPRINT_2",
},
{
Url: "https://netdb.i2p2.no/",
SU3Fingerprint: "PLACEHOLDER_FINGERPRINT_3",
},
},
}

View File

@@ -50,6 +50,37 @@ func setDefaults() {
viper.SetDefault("bootstrap.reseed_servers", []ReseedConfig{})
}
// NewRouterConfigFromViper creates a new RouterConfig from current viper settings
// This is the preferred way to get config instead of using the global RouterConfigProperties
func NewRouterConfigFromViper() *RouterConfig {
// Create NetDb configuration
netDbConfig := &NetDbConfig{
Path: viper.GetString("netdb.path"),
}
// Create Bootstrap configuration
var reseedServers []*ReseedConfig
if err := viper.UnmarshalKey("bootstrap.reseed_servers", &reseedServers); err != nil {
log.Warnf("Error parsing reseed servers: %s", err)
reseedServers = []*ReseedConfig{}
}
bootstrapConfig := &BootstrapConfig{
LowPeerThreshold: viper.GetInt("bootstrap.low_peer_threshold"),
ReseedServers: reseedServers,
}
// Create and return new RouterConfig
return &RouterConfig{
BaseDir: viper.GetString("base_dir"),
WorkingDir: viper.GetString("working_dir"),
NetDb: netDbConfig,
Bootstrap: bootstrapConfig,
}
}
// UpdateRouterConfig updates the global RouterConfigProperties from viper settings
// DEPRECATED: Use NewRouterConfigFromViper() instead to avoid global state mutation
func UpdateRouterConfig() {
// Update Router configuration
RouterConfigProperties.BaseDir = viper.GetString("base_dir")

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -36,4 +36,8 @@ func DefaultRouterConfig() *RouterConfig {
return defaultRouterConfig
}
// RouterConfigProperties is a global mutable configuration object
// DEPRECATED: This global variable is mutated by UpdateRouterConfig() creating
// hidden dependencies and making testing difficult. Use NewRouterConfigFromViper()
// instead to get a fresh config object without global state issues.
var RouterConfigProperties = DefaultRouterConfig()

View File

@@ -30,8 +30,8 @@ I2NP Message Type Constants Moved from: header.go
var (
ERR_I2NP_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np header data")
ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np build request record data")
ERR_BUILD_RESPONSE_RECORD_NOT_ENOUGH_DATA = errors.New("not enough i2np build request record data")
ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA = errors.New("not enough i2np database lookup data")
ERR_BUILD_RESPONSE_RECORD_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np build request record data")
ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np database lookup data")
)
```
I2NP Error Constants Moved from: header.go, build_request_record.go,
@@ -914,6 +914,13 @@ func (mr *MessageRouter) SetNetDB(netdb NetDBStore)
```
SetNetDB sets the NetDB store for database operations
#### func (*MessageRouter) SetPeerSelector
```go
func (mr *MessageRouter) SetPeerSelector(selector tunnel.PeerSelector)
```
SetPeerSelector sets the peer selector for the TunnelManager
#### type MessageRouterConfig
```go
@@ -1229,15 +1236,16 @@ CreateTunnelRecord creates a build request record with interface methods
#### type TunnelManager
```go
type TunnelManager struct{}
type TunnelManager struct {
}
```
TunnelManager demonstrates tunnel-related interface usage
TunnelManager coordinates tunnel building and management
#### func NewTunnelManager
```go
func NewTunnelManager() *TunnelManager
func NewTunnelManager(peerSelector tunnel.PeerSelector) *TunnelManager
```
NewTunnelManager creates a new tunnel manager
@@ -1256,6 +1264,13 @@ func (tm *TunnelManager) ProcessTunnelReply(handler TunnelReplyHandler) error
ProcessTunnelReply processes tunnel build replies using TunnelReplyHandler
interface
#### func (*TunnelManager) SetSessionProvider
```go
func (tm *TunnelManager) SetSessionProvider(provider SessionProvider)
```
SetSessionProvider sets the session provider for sending tunnel build messages
#### type TunnelReplyHandler
```go

View File

@@ -1,8 +1,6 @@
package i2np
import (
"errors"
"github.com/samber/oops"
)
@@ -28,6 +26,6 @@ const (
var (
ERR_I2NP_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np header data")
ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np build request record data")
ERR_BUILD_RESPONSE_RECORD_NOT_ENOUGH_DATA = errors.New("not enough i2np build request record data")
ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA = errors.New("not enough i2np database lookup data")
ERR_BUILD_RESPONSE_RECORD_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np build request record data")
ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np database lookup data")
)

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 312 KiB

After

Width:  |  Height:  |  Size: 354 KiB

View File

@@ -1,14 +1,23 @@
package i2np
import (
"errors"
"testing"
"time"
common "github.com/go-i2p/common/data"
"github.com/go-i2p/common/router_info"
"github.com/go-i2p/go-i2p/lib/tunnel"
"github.com/stretchr/testify/assert"
)
// MockTestPeerSelector for interfaces testing
type MockTestPeerSelector struct{}
func (m *MockTestPeerSelector) SelectPeers(count int, exclude []common.Hash) ([]router_info.RouterInfo, error) {
return nil, errors.New("insufficient peers available") // Intentionally return error for simple testing
}
func TestInterfaceSatisfaction(t *testing.T) {
// Test that our types satisfy their interfaces
@@ -82,7 +91,7 @@ func TestMessageProcessor(t *testing.T) {
}
func TestTunnelManager(t *testing.T) {
manager := NewTunnelManager()
manager := NewTunnelManager(&MockTestPeerSelector{}) // Use mock peer selector for test
// Create build request records
records := [8]BuildRequestRecord{}
@@ -93,13 +102,14 @@ func TestTunnelManager(t *testing.T) {
}
}
// Test with TunnelBuild
// Test with TunnelBuild - should get error due to insufficient peers
builder := NewTunnelBuilder(records)
err := manager.BuildTunnel(builder)
assert.NoError(t, err)
assert.Error(t, err)
assert.Contains(t, err.Error(), "insufficient peers")
assert.Equal(t, 8, builder.GetRecordCount())
// Test with VariableTunnelBuild
// Test with VariableTunnelBuild - should also get error
variableRecords := []BuildRequestRecord{
{ReceiveTunnel: 1, NextTunnel: 2},
{ReceiveTunnel: 3, NextTunnel: 4},
@@ -107,7 +117,8 @@ func TestTunnelManager(t *testing.T) {
}
variableBuilder := NewVariableTunnelBuilder(variableRecords)
err = manager.BuildTunnel(variableBuilder)
assert.NoError(t, err)
assert.Error(t, err)
assert.Contains(t, err.Error(), "insufficient peers")
assert.Equal(t, 3, variableBuilder.GetRecordCount())
}
@@ -155,6 +166,9 @@ func TestMessageRouter(t *testing.T) {
}
router := NewMessageRouter(config)
// Set up peer selector for tunnel operations
router.SetPeerSelector(&MockTestPeerSelector{})
// Test routing data message
dataMsg := NewDataMessage([]byte("router test"))
err := router.RouteMessage(dataMsg)
@@ -167,11 +181,12 @@ func TestMessageRouter(t *testing.T) {
err = router.RouteDatabaseMessage(lookup)
assert.NoError(t, err)
// Test routing tunnel message
// Test routing tunnel message - should get error due to insufficient peers
records := [8]BuildRequestRecord{}
builder := NewTunnelBuilder(records)
err = router.RouteTunnelMessage(builder)
assert.NoError(t, err)
assert.Error(t, err)
assert.Contains(t, err.Error(), "insufficient peers")
}
func TestInterfaceComposition(t *testing.T) {

View File

@@ -5,6 +5,9 @@ import (
"time"
common "github.com/go-i2p/common/data"
"github.com/go-i2p/common/router_info"
"github.com/go-i2p/go-i2p/lib/tunnel"
"github.com/sirupsen/logrus"
)
// MessageProcessor demonstrates interface-based message processing
@@ -37,7 +40,7 @@ func (p *MessageProcessor) ProcessMessage(msg I2NPMessage) error {
func (p *MessageProcessor) processDataMessage(msg I2NPMessage) error {
if payloadCarrier, ok := msg.(PayloadCarrier); ok {
payload := payloadCarrier.GetPayload()
fmt.Printf("Processing data message with %d bytes of payload\n", len(payload))
log.WithField("payload_size", len(payload)).Debug("Processing data message")
return nil
}
return fmt.Errorf("message does not implement PayloadCarrier interface")
@@ -48,7 +51,10 @@ func (p *MessageProcessor) processDeliveryStatusMessage(msg I2NPMessage) error {
if statusReporter, ok := msg.(StatusReporter); ok {
msgID := statusReporter.GetStatusMessageID()
timestamp := statusReporter.GetTimestamp()
fmt.Printf("Processing delivery status for message %d at %v\n", msgID, timestamp)
log.WithFields(logrus.Fields{
"message_id": msgID,
"timestamp": timestamp,
}).Debug("Processing delivery status")
return nil
}
return fmt.Errorf("message does not implement StatusReporter interface")
@@ -58,41 +64,133 @@ func (p *MessageProcessor) processDeliveryStatusMessage(msg I2NPMessage) error {
func (p *MessageProcessor) processTunnelDataMessage(msg I2NPMessage) error {
if tunnelCarrier, ok := msg.(TunnelCarrier); ok {
data := tunnelCarrier.GetTunnelData()
fmt.Printf("Processing tunnel data message with %d bytes\n", len(data))
log.WithField("data_size", len(data)).Debug("Processing tunnel data message")
return nil
}
return fmt.Errorf("message does not implement TunnelCarrier interface")
}
// TunnelManager demonstrates tunnel-related interface usage
type TunnelManager struct{}
// TunnelManager coordinates tunnel building and management
type TunnelManager struct {
pool *tunnel.Pool
sessionProvider SessionProvider
peerSelector tunnel.PeerSelector
}
// NewTunnelManager creates a new tunnel manager
func NewTunnelManager() *TunnelManager {
return &TunnelManager{}
func NewTunnelManager(peerSelector tunnel.PeerSelector) *TunnelManager {
pool := tunnel.NewTunnelPool(peerSelector)
return &TunnelManager{
pool: pool,
peerSelector: peerSelector,
}
}
// SetSessionProvider sets the session provider for sending tunnel build messages
func (tm *TunnelManager) SetSessionProvider(provider SessionProvider) {
tm.sessionProvider = provider
}
// BuildTunnel builds a tunnel using TunnelBuilder interface
func (tm *TunnelManager) BuildTunnel(builder TunnelBuilder) error {
if tm.peerSelector == nil {
return fmt.Errorf("no peer selector configured")
}
records := builder.GetBuildRecords()
count := builder.GetRecordCount()
fmt.Printf("Building tunnel with %d records\n", count)
for i, record := range records {
if i >= count {
break
}
fmt.Printf("Record %d: Receive Tunnel %d, Next Tunnel %d\n",
i, record.GetReceiveTunnel(), record.GetNextTunnel())
if count == 0 {
return fmt.Errorf("no build records provided")
}
// Select peers for tunnel hops (excluding ourselves)
peers, err := tm.peerSelector.SelectPeers(count, nil)
if err != nil {
return fmt.Errorf("failed to select peers for tunnel: %w", err)
}
if len(peers) < count {
return fmt.Errorf("insufficient peers available: need %d, got %d", count, len(peers))
}
// Generate tunnel ID for this tunnel
tunnelID := tm.generateTunnelID()
// Create tunnel state tracking
tunnelState := &tunnel.TunnelState{
ID: tunnelID,
Hops: make([]common.Hash, count),
State: tunnel.TunnelBuilding,
CreatedAt: time.Now(),
Responses: make([]tunnel.BuildResponse, 0, count),
}
// Populate hops with selected peer hashes
for i, peer := range peers[:count] {
tunnelState.Hops[i] = peer.IdentHash()
}
// Add tunnel to pool for tracking
tm.pool.AddTunnel(tunnelState)
// Send build requests to each hop
return tm.sendTunnelBuildRequests(records, peers[:count], tunnelID)
}
// generateTunnelID generates a new unique tunnel ID
func (tm *TunnelManager) generateTunnelID() tunnel.TunnelID {
// Simple tunnel ID generation - in production this should be cryptographically secure
return tunnel.TunnelID(time.Now().UnixNano() & 0xFFFFFFFF)
}
// sendTunnelBuildRequests sends tunnel build requests to each selected peer
func (tm *TunnelManager) sendTunnelBuildRequests(records []BuildRequestRecord, peers []router_info.RouterInfo, tunnelID tunnel.TunnelID) error {
if tm.sessionProvider == nil {
return fmt.Errorf("no session provider available for sending tunnel build requests")
}
log.WithFields(logrus.Fields{
"tunnel_id": tunnelID,
"peer_count": len(peers),
}).Debug("Sending tunnel build requests")
// Send build request to each peer
for i := range records {
if i >= len(peers) {
break
}
peer := peers[i]
peerHash := peer.IdentHash()
// Get transport session to this peer
_, err := tm.sessionProvider.GetSessionByHash(peerHash)
if err != nil {
log.WithFields(logrus.Fields{
"peer_hash": fmt.Sprintf("%x", peerHash[:8]),
"error": err,
}).Warn("Failed to get session for peer")
continue
}
// Create a tunnel build message (simplified - would need proper I2NP message creation)
log.WithFields(logrus.Fields{
"hop_index": i,
"peer_hash": fmt.Sprintf("%x", peerHash[:8]),
}).Debug("Sending build request to hop")
// In a real implementation, we would create a proper TunnelBuild I2NP message
// session.QueueSendI2NP(buildMessage)
}
log.WithField("tunnel_id", tunnelID).Debug("Tunnel build requests sent")
return nil
}
// ProcessTunnelReply processes tunnel build replies using TunnelReplyHandler interface
func (tm *TunnelManager) ProcessTunnelReply(handler TunnelReplyHandler) error {
records := handler.GetReplyRecords()
fmt.Printf("Processing tunnel reply with %d records\n", len(records))
log.WithField("record_count", len(records)).Debug("Processing tunnel reply")
return handler.ProcessReply()
}
@@ -147,27 +245,38 @@ func (dm *DatabaseManager) SetSessionProvider(provider SessionProvider) {
dm.sessionProvider = provider
}
// SetPeerSelector sets the peer selector for the TunnelManager
func (mr *MessageRouter) SetPeerSelector(selector tunnel.PeerSelector) {
mr.tunnelMgr.peerSelector = selector
if mr.tunnelMgr.pool != nil {
mr.tunnelMgr.pool = tunnel.NewTunnelPool(selector)
}
}
// PerformLookup performs a database lookup using DatabaseReader interface and generates appropriate responses
func (dm *DatabaseManager) PerformLookup(reader DatabaseReader) error {
key := reader.GetKey()
from := reader.GetFrom()
flags := reader.GetFlags()
fmt.Printf("Performing lookup for key %x from %x with flags %d\n",
key[:8], from[:8], flags)
log.WithFields(logrus.Fields{
"key": fmt.Sprintf("%x", key[:8]),
"from": fmt.Sprintf("%x", from[:8]),
"flags": flags,
}).Debug("Performing database lookup")
// If no session provider is available, just perform the lookup logic without sending responses
// This maintains backward compatibility with existing tests
if dm.sessionProvider == nil {
fmt.Println("No session provider available, performing lookup without sending response")
log.Debug("No session provider available, performing lookup without sending response")
if dm.retriever != nil {
if data, err := dm.retrieveRouterInfo(key); err == nil {
fmt.Printf("RouterInfo found locally: %d bytes\n", len(data))
log.WithField("data_size", len(data)).Debug("RouterInfo found locally")
} else {
fmt.Printf("RouterInfo not found locally: %v\n", err)
log.WithField("error", err).Debug("RouterInfo not found locally")
}
} else {
fmt.Println("No retriever available, cannot perform lookup")
log.Debug("No retriever available, cannot perform lookup")
}
return nil
}
@@ -178,10 +287,10 @@ func (dm *DatabaseManager) PerformLookup(reader DatabaseReader) error {
// RouterInfo found - send DatabaseStore response
return dm.sendDatabaseStoreResponse(key, data, from)
} else {
fmt.Printf("RouterInfo not found locally: %v\n", err)
log.WithField("error", err).Debug("RouterInfo not found locally for remote lookup")
}
} else {
fmt.Println("No retriever available, cannot perform lookup")
log.Debug("No retriever available, cannot perform lookup")
}
// RouterInfo not found - send DatabaseSearchReply response
@@ -238,7 +347,10 @@ func (dm *DatabaseManager) sendResponse(response interface{}, to common.Hash) er
// Send the response
session.QueueSendI2NP(msg)
fmt.Printf("Queued response message type %d for %x\n", msg.Type(), to[:8])
log.WithFields(logrus.Fields{
"message_type": msg.Type(),
"destination": fmt.Sprintf("%x", to[:8]),
}).Debug("Queued response message")
return nil
}
@@ -248,7 +360,7 @@ func (dm *DatabaseManager) createDatabaseStoreMessage(store *DatabaseStore) I2NP
if data, err := store.MarshalBinary(); err == nil {
msg.SetData(data)
} else {
fmt.Printf("Failed to marshal DatabaseStore: %v\n", err)
log.WithField("error", err).Error("Failed to marshal DatabaseStore")
}
return msg
}
@@ -259,7 +371,7 @@ func (dm *DatabaseManager) createDatabaseSearchReplyMessage(reply *DatabaseSearc
if data, err := reply.MarshalBinary(); err == nil {
msg.SetData(data)
} else {
fmt.Printf("Failed to marshal DatabaseSearchReply: %v\n", err)
log.WithField("error", err).Error("Failed to marshal DatabaseSearchReply")
}
return msg
}
@@ -270,8 +382,11 @@ func (dm *DatabaseManager) StoreData(writer DatabaseWriter) error {
data := writer.GetStoreData()
dataType := writer.GetStoreType()
fmt.Printf("Storing %d bytes of type %d for key %x\n",
len(data), dataType, key[:8])
log.WithFields(logrus.Fields{
"data_size": len(data),
"data_type": dataType,
"key": fmt.Sprintf("%x", key[:8]),
}).Debug("Storing RouterInfo data")
if dm.netdb != nil {
return dm.netdb.StoreRouterInfo(key, data, dataType)
@@ -294,8 +409,11 @@ func (sm *SessionManager) ProcessKeys(provider SessionKeyProvider) error {
layerKey := provider.GetLayerKey()
ivKey := provider.GetIVKey()
fmt.Printf("Processing session keys: reply=%x, layer=%x, iv=%x\n",
replyKey[:8], layerKey[:8], ivKey[:8])
log.WithFields(logrus.Fields{
"reply_key": fmt.Sprintf("%x", replyKey[:8]),
"layer_key": fmt.Sprintf("%x", layerKey[:8]),
"iv_key": fmt.Sprintf("%x", ivKey[:8]),
}).Debug("Processing session keys")
return nil
}
@@ -305,14 +423,17 @@ func (sm *SessionManager) ProcessTags(provider SessionTagProvider) error {
tags := provider.GetReplyTags()
count := provider.GetTagCount()
fmt.Printf("Processing %d session tags\n", count)
log.WithField("tag_count", count).Debug("Processing session tags")
for i, tag := range tags {
if i >= count {
break
}
// Convert session tag to bytes for display
tagBytes := tag.Bytes()
fmt.Printf("Tag %d: %x\n", i, tagBytes[:8])
log.WithFields(logrus.Fields{
"tag_index": i,
"tag": fmt.Sprintf("%x", tagBytes[:8]),
}).Debug("Processing session tag")
}
return nil
@@ -340,7 +461,7 @@ func NewMessageRouter(config MessageRouterConfig) *MessageRouter {
config: config,
processor: NewMessageProcessor(),
dbManager: NewDatabaseManager(nil), // Will be set later via SetNetDB
tunnelMgr: NewTunnelManager(),
tunnelMgr: NewTunnelManager(nil), // Will be set later via SetPeerSelector
sessionMgr: NewSessionManager(),
}
}
@@ -354,7 +475,10 @@ func (mr *MessageRouter) SetNetDB(netdb NetDBStore) {
func (mr *MessageRouter) RouteMessage(msg I2NPMessage) error {
// Log message if enabled
if mr.config.EnableLogging {
fmt.Printf("Routing message type %d with ID %d\n", msg.Type(), msg.MessageID())
log.WithFields(logrus.Fields{
"message_type": msg.Type(),
"message_id": msg.MessageID(),
}).Debug("Routing message")
}
// Check for expiration

View File

@@ -46,38 +46,10 @@
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey -->
<g id="node1" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey</title>
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey | defined in routerinfo_keystore.go:71&#10;at routerinfo_keystore.go:73: calling [github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M397.9478,-52C397.9478,-52 300.6304,-52 300.6304,-52 294.6304,-52 288.6304,-46 288.6304,-40 288.6304,-40 288.6304,-28 288.6304,-28 288.6304,-22 294.6304,-16 300.6304,-16 300.6304,-16 397.9478,-16 397.9478,-16 403.9478,-16 409.9478,-22 409.9478,-28 409.9478,-28 409.9478,-40 409.9478,-40 409.9478,-46 403.9478,-52 397.9478,-52"/>
<text text-anchor="middle" x="349.2891" y="-29.8" font-family="Verdana" font-size="14.00" fill="#000000">generateNewKey</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key -->
<g id="node2" class="node">
<title>github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key</title>
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key | defined in utils.go:18">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M656.7807,-52C656.7807,-52 531.9997,-52 531.9997,-52 525.9997,-52 519.9997,-46 519.9997,-40 519.9997,-40 519.9997,-28 519.9997,-28 519.9997,-22 525.9997,-16 531.9997,-16 531.9997,-16 656.7807,-16 656.7807,-16 662.7807,-16 668.7807,-22 668.7807,-28 668.7807,-28 668.7807,-40 668.7807,-40 668.7807,-46 662.7807,-52 656.7807,-52"/>
<text text-anchor="middle" x="594.3902" y="-38.2" font-family="Verdana" font-size="14.00" fill="#000000">ed25519</text>
<text text-anchor="middle" x="594.3902" y="-21.4" font-family="Verdana" font-size="14.00" fill="#000000">GenerateEd25519Key</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey&#45;&gt;github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key -->
<g id="edge12" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey&#45;&gt;github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key</title>
<g id="a_edge12"><a xlink:title="at routerinfo_keystore.go:73: calling [github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key]">
<path fill="none" stroke="#8b4513" d="M409.8759,-34C440.0665,-34 477.0656,-34 509.9856,-34"/>
<polygon fill="#8b4513" stroke="#8b4513" points="510.0592,-37.5001 520.0592,-34 510.0591,-30.5001 510.0592,-37.5001"/>
</a>
</g>
</g>
<!-- github.com/samber/oops.Errorf -->
<g id="node3" class="node">
<g id="node1" class="node">
<title>github.com/samber/oops.Errorf</title>
<g id="a_node3"><a xlink:title="github.com/samber/oops.Errorf | defined in oops.go:34">
<g id="a_node1"><a xlink:title="github.com/samber/oops.Errorf | defined in oops.go:34">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M366.4844,-460C366.4844,-460 332.0938,-460 332.0938,-460 326.0938,-460 320.0938,-454 320.0938,-448 320.0938,-448 320.0938,-436 320.0938,-436 320.0938,-430 326.0938,-424 332.0938,-424 332.0938,-424 366.4844,-424 366.4844,-424 372.4844,-424 378.4844,-430 378.4844,-436 378.4844,-436 378.4844,-448 378.4844,-448 378.4844,-454 372.4844,-460 366.4844,-460"/>
<text text-anchor="middle" x="349.2891" y="-446.2" font-family="Verdana" font-size="14.00" fill="#000000">oops</text>
<text text-anchor="middle" x="349.2891" y="-429.4" font-family="Verdana" font-size="14.00" fill="#000000">Errorf</text>
@@ -85,9 +57,9 @@
</g>
</g>
<!-- github.com/go&#45;i2p/common/data.NewIntegerFromInt -->
<g id="node4" class="node">
<g id="node2" class="node">
<title>github.com/go&#45;i2p/common/data.NewIntegerFromInt</title>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/common/data.NewIntegerFromInt | defined in integer.go:61">
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/common/data.NewIntegerFromInt | defined in integer.go:61">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M405.2429,-521C405.2429,-521 293.3353,-521 293.3353,-521 287.3353,-521 281.3353,-515 281.3353,-509 281.3353,-509 281.3353,-497 281.3353,-497 281.3353,-491 287.3353,-485 293.3353,-485 293.3353,-485 405.2429,-485 405.2429,-485 411.2429,-485 417.2429,-491 417.2429,-497 417.2429,-497 417.2429,-509 417.2429,-509 417.2429,-515 411.2429,-521 405.2429,-521"/>
<text text-anchor="middle" x="349.2891" y="-507.2" font-family="Verdana" font-size="14.00" fill="#000000">data</text>
<text text-anchor="middle" x="349.2891" y="-490.4" font-family="Verdana" font-size="14.00" fill="#000000">NewIntegerFromInt</text>
@@ -95,9 +67,9 @@
</g>
</g>
<!-- github.com/go&#45;i2p/common/certificate.NewCertificateWithType -->
<g id="node5" class="node">
<g id="node3" class="node">
<title>github.com/go&#45;i2p/common/certificate.NewCertificateWithType</title>
<g id="a_node5"><a xlink:title="github.com/go&#45;i2p/common/certificate.NewCertificateWithType | defined in certificate_struct.go:79">
<g id="a_node3"><a xlink:title="github.com/go&#45;i2p/common/certificate.NewCertificateWithType | defined in certificate_struct.go:79">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M420.5587,-582C420.5587,-582 278.0195,-582 278.0195,-582 272.0195,-582 266.0195,-576 266.0195,-570 266.0195,-570 266.0195,-558 266.0195,-558 266.0195,-552 272.0195,-546 278.0195,-546 278.0195,-546 420.5587,-546 420.5587,-546 426.5587,-546 432.5587,-552 432.5587,-558 432.5587,-558 432.5587,-570 432.5587,-570 432.5587,-576 426.5587,-582 420.5587,-582"/>
<text text-anchor="middle" x="349.2891" y="-568.2" font-family="Verdana" font-size="14.00" fill="#000000">certificate</text>
<text text-anchor="middle" x="349.2891" y="-551.4" font-family="Verdana" font-size="14.00" fill="#000000">NewCertificateWithType</text>
@@ -105,9 +77,9 @@
</g>
</g>
<!-- github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate -->
<g id="node6" class="node">
<g id="node4" class="node">
<title>github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate</title>
<g id="a_node6"><a xlink:title="github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate | defined in key_certificate_struct.go:116">
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate | defined in key_certificate_struct.go:116">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M435.1014,-643C435.1014,-643 263.4768,-643 263.4768,-643 257.4768,-643 251.4768,-637 251.4768,-631 251.4768,-631 251.4768,-619 251.4768,-619 251.4768,-613 257.4768,-607 263.4768,-607 263.4768,-607 435.1014,-607 435.1014,-607 441.1014,-607 447.1014,-613 447.1014,-619 447.1014,-619 447.1014,-631 447.1014,-631 447.1014,-637 441.1014,-643 435.1014,-643"/>
<text text-anchor="middle" x="349.2891" y="-629.2" font-family="Verdana" font-size="14.00" fill="#000000">key_certificate</text>
<text text-anchor="middle" x="349.2891" y="-612.4" font-family="Verdana" font-size="14.00" fill="#000000">KeyCertificateFromCertificate</text>
@@ -115,9 +87,9 @@
</g>
</g>
<!-- github.com/go&#45;i2p/common/router_identity.NewRouterIdentity -->
<g id="node7" class="node">
<g id="node5" class="node">
<title>github.com/go&#45;i2p/common/router_identity.NewRouterIdentity</title>
<g id="a_node7"><a xlink:title="github.com/go&#45;i2p/common/router_identity.NewRouterIdentity | defined in router_identity_struct.go:37">
<g id="a_node5"><a xlink:title="github.com/go&#45;i2p/common/router_identity.NewRouterIdentity | defined in router_identity_struct.go:37">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M403.3663,-704C403.3663,-704 295.2119,-704 295.2119,-704 289.2119,-704 283.2119,-698 283.2119,-692 283.2119,-692 283.2119,-680 283.2119,-680 283.2119,-674 289.2119,-668 295.2119,-668 295.2119,-668 403.3663,-668 403.3663,-668 409.3663,-668 415.3663,-674 415.3663,-680 415.3663,-680 415.3663,-692 415.3663,-692 415.3663,-698 409.3663,-704 403.3663,-704"/>
<text text-anchor="middle" x="349.2891" y="-690.2" font-family="Verdana" font-size="14.00" fill="#000000">router_identity</text>
<text text-anchor="middle" x="349.2891" y="-673.4" font-family="Verdana" font-size="14.00" fill="#000000">NewRouterIdentity</text>
@@ -125,28 +97,56 @@
</g>
</g>
<!-- github.com/go&#45;i2p/common/router_info.NewRouterInfo -->
<g id="node8" class="node">
<g id="node6" class="node">
<title>github.com/go&#45;i2p/common/router_info.NewRouterInfo</title>
<g id="a_node8"><a xlink:title="github.com/go&#45;i2p/common/router_info.NewRouterInfo | defined in router_info_struct.go:116">
<g id="a_node6"><a xlink:title="github.com/go&#45;i2p/common/router_info.NewRouterInfo | defined in router_info_struct.go:116">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M393.1406,-765C393.1406,-765 305.4376,-765 305.4376,-765 299.4376,-765 293.4376,-759 293.4376,-753 293.4376,-753 293.4376,-741 293.4376,-741 293.4376,-735 299.4376,-729 305.4376,-729 305.4376,-729 393.1406,-729 393.1406,-729 399.1406,-729 405.1406,-735 405.1406,-741 405.1406,-741 405.1406,-753 405.1406,-753 405.1406,-759 399.1406,-765 393.1406,-765"/>
<text text-anchor="middle" x="349.2891" y="-751.2" font-family="Verdana" font-size="14.00" fill="#000000">router_info</text>
<text text-anchor="middle" x="349.2891" y="-734.4" font-family="Verdana" font-size="14.00" fill="#000000">NewRouterInfo</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey -->
<g id="node7" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey</title>
<g id="a_node7"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey | defined in routerinfo_keystore.go:71&#10;at routerinfo_keystore.go:73: calling [github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M397.9478,-52C397.9478,-52 300.6304,-52 300.6304,-52 294.6304,-52 288.6304,-46 288.6304,-40 288.6304,-40 288.6304,-28 288.6304,-28 288.6304,-22 294.6304,-16 300.6304,-16 300.6304,-16 397.9478,-16 397.9478,-16 403.9478,-16 409.9478,-22 409.9478,-28 409.9478,-28 409.9478,-40 409.9478,-40 409.9478,-46 403.9478,-52 397.9478,-52"/>
<text text-anchor="middle" x="349.2891" y="-29.8" font-family="Verdana" font-size="14.00" fill="#000000">generateNewKey</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key -->
<g id="node8" class="node">
<title>github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key</title>
<g id="a_node8"><a xlink:title="github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key | defined in utils.go:18">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M656.7807,-52C656.7807,-52 531.9997,-52 531.9997,-52 525.9997,-52 519.9997,-46 519.9997,-40 519.9997,-40 519.9997,-28 519.9997,-28 519.9997,-22 525.9997,-16 531.9997,-16 531.9997,-16 656.7807,-16 656.7807,-16 662.7807,-16 668.7807,-22 668.7807,-28 668.7807,-28 668.7807,-40 668.7807,-40 668.7807,-46 662.7807,-52 656.7807,-52"/>
<text text-anchor="middle" x="594.3902" y="-38.2" font-family="Verdana" font-size="14.00" fill="#000000">ed25519</text>
<text text-anchor="middle" x="594.3902" y="-21.4" font-family="Verdana" font-size="14.00" fill="#000000">GenerateEd25519Key</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey&#45;&gt;github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key -->
<g id="edge7" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey&#45;&gt;github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key</title>
<g id="a_edge7"><a xlink:title="at routerinfo_keystore.go:73: calling [github.com/go&#45;i2p/crypto/ed25519.GenerateEd25519Key]">
<path fill="none" stroke="#8b4513" d="M409.8759,-34C440.0665,-34 477.0656,-34 509.9856,-34"/>
<polygon fill="#8b4513" stroke="#8b4513" points="510.0592,-37.5001 520.0592,-34 510.0591,-30.5001 510.0592,-37.5001"/>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore -->
<g id="node9" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore</title>
<g id="a_node9"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore | defined in routerinfo_keystore.go:37&#10;at routerinfo_keystore.go:56: calling [github.com/go&#45;i2p/go&#45;i2p/lib/keys.loadExistingKey]&#10;at routerinfo_keystore.go:47: calling [github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey]&#10;at routerinfo_keystore.go:62: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper]">
<g id="a_node9"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore | defined in routerinfo_keystore.go:37&#10;at routerinfo_keystore.go:47: calling [github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey]&#10;at routerinfo_keystore.go:62: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper]&#10;at routerinfo_keystore.go:56: calling [github.com/go&#45;i2p/go&#45;i2p/lib/keys.loadExistingKey]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M166.575,-113C166.575,-113 27.808,-113 27.808,-113 21.808,-113 15.808,-107 15.808,-101 15.808,-101 15.808,-89 15.808,-89 15.808,-83 21.808,-77 27.808,-77 27.808,-77 166.575,-77 166.575,-77 172.575,-77 178.575,-83 178.575,-89 178.575,-89 178.575,-101 178.575,-101 178.575,-107 172.575,-113 166.575,-113"/>
<text text-anchor="middle" x="97.1915" y="-90.8" font-family="Verdana" font-size="14.00" fill="#000000">NewRouterInfoKeystore</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey -->
<g id="edge9" class="edge">
<g id="edge1" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey</title>
<g id="a_edge9"><a xlink:title="at routerinfo_keystore.go:47: calling [github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey]">
<g id="a_edge1"><a xlink:title="at routerinfo_keystore.go:47: calling [github.com/go&#45;i2p/go&#45;i2p/lib/keys.generateNewKey]">
<path fill="none" stroke="#000000" d="M171.8059,-76.9456C205.49,-68.795 245.0892,-59.2132 278.3268,-51.1707"/>
<polygon fill="#000000" stroke="#000000" points="279.5277,-54.4812 288.424,-48.7275 277.8814,-47.6776 279.5277,-54.4812"/>
</a>
@@ -155,7 +155,7 @@
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper -->
<g id="node10" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper</title>
<g id="a_node10"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper | defined in router_timestamper.go:55">
<g id="a_node10"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper | defined in router_timestamper.go:57">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M418.6838,-113C418.6838,-113 279.8944,-113 279.8944,-113 273.8944,-113 267.8944,-107 267.8944,-101 267.8944,-101 267.8944,-89 267.8944,-89 267.8944,-83 273.8944,-77 279.8944,-77 279.8944,-77 418.6838,-77 418.6838,-77 424.6838,-77 430.6838,-83 430.6838,-89 430.6838,-89 430.6838,-101 430.6838,-101 430.6838,-107 424.6838,-113 418.6838,-113"/>
<text text-anchor="middle" x="349.2891" y="-99.2" font-family="Verdana" font-size="14.00" fill="#000000">sntp</text>
<text text-anchor="middle" x="349.2891" y="-82.4" font-family="Verdana" font-size="14.00" fill="#000000">NewRouterTimestamper</text>
@@ -163,9 +163,9 @@
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper -->
<g id="edge16" class="edge">
<g id="edge2" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper</title>
<g id="a_edge16"><a xlink:title="at routerinfo_keystore.go:62: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper]">
<g id="a_edge2"><a xlink:title="at routerinfo_keystore.go:62: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper]">
<path fill="none" stroke="#8b4513" d="M178.6922,-95C203.9647,-95 231.9791,-95 257.8783,-95"/>
<polygon fill="#8b4513" stroke="#8b4513" points="258.069,-98.5001 268.069,-95 258.0689,-91.5001 258.069,-98.5001"/>
</a>
@@ -181,9 +181,9 @@
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/keys.loadExistingKey -->
<g id="edge5" class="edge">
<g id="edge16" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/keys.NewRouterInfoKeystore&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/keys.loadExistingKey</title>
<g id="a_edge5"><a xlink:title="at routerinfo_keystore.go:56: calling [github.com/go&#45;i2p/go&#45;i2p/lib/keys.loadExistingKey]">
<g id="a_edge16"><a xlink:title="at routerinfo_keystore.go:56: calling [github.com/go&#45;i2p/go&#45;i2p/lib/keys.loadExistingKey]">
<path fill="none" stroke="#000000" d="M171.8059,-113.0544C206.1638,-121.368 246.6757,-131.1707 280.3135,-139.31"/>
<polygon fill="#000000" stroke="#000000" points="279.5188,-142.7186 290.0615,-141.6687 281.1651,-135.915 279.5188,-142.7186"/>
</a>
@@ -208,9 +208,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.KeyStoreImpl).StoreKeys&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.KeyStoreImpl).KeyID -->
<g id="edge6" class="edge">
<g id="edge11" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.KeyStoreImpl).StoreKeys&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.KeyStoreImpl).KeyID</title>
<g id="a_edge6"><a xlink:title="at types.go:66: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.KeyStoreImpl).KeyID]">
<g id="a_edge11"><a xlink:title="at types.go:66: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.KeyStoreImpl).KeyID]">
<path fill="none" stroke="#000000" d="M138.538,-234C185.2893,-234 260.9744,-234 307.789,-234"/>
<polygon fill="#000000" stroke="#000000" points="307.8904,-237.5001 317.8903,-234 307.8903,-230.5001 307.8904,-237.5001"/>
</a>
@@ -219,61 +219,61 @@
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo -->
<g id="node14" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo</title>
<g id="a_node14"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo | defined in routerinfo_keystore.go:127&#10;at routerinfo_keystore.go:129: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).GetKeys]&#10;at routerinfo_keystore.go:147: calling [github.com/go&#45;i2p/common/certificate.NewCertificateWithType]&#10;at routerinfo_keystore.go:179: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime]&#10;at routerinfo_keystore.go:187: calling [github.com/go&#45;i2p/common/router_info.NewRouterInfo]&#10;at routerinfo_keystore.go:131: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:138: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:142: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:149: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:155: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:164: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:175: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:196: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:168: calling [github.com/go&#45;i2p/common/router_identity.NewRouterIdentity]&#10;at routerinfo_keystore.go:136: calling [github.com/go&#45;i2p/common/data.NewIntegerFromInt]&#10;at routerinfo_keystore.go:140: calling [github.com/go&#45;i2p/common/data.NewIntegerFromInt]&#10;at routerinfo_keystore.go:153: calling [github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate]&#10;at routerinfo_keystore.go:158: calling [(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).CryptoSize]&#10;at routerinfo_keystore.go:159: calling [(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).SignatureSize]">
<g id="a_node14"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo | defined in routerinfo_keystore.go:127&#10;at routerinfo_keystore.go:131: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:138: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:142: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:149: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:155: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:164: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:175: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:196: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:136: calling [github.com/go&#45;i2p/common/data.NewIntegerFromInt]&#10;at routerinfo_keystore.go:140: calling [github.com/go&#45;i2p/common/data.NewIntegerFromInt]&#10;at routerinfo_keystore.go:158: calling [(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).CryptoSize]&#10;at routerinfo_keystore.go:179: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime]&#10;at routerinfo_keystore.go:153: calling [github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate]&#10;at routerinfo_keystore.go:159: calling [(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).SignatureSize]&#10;at routerinfo_keystore.go:168: calling [github.com/go&#45;i2p/common/router_identity.NewRouterIdentity]&#10;at routerinfo_keystore.go:129: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).GetKeys]&#10;at routerinfo_keystore.go:187: calling [github.com/go&#45;i2p/common/router_info.NewRouterInfo]&#10;at routerinfo_keystore.go:147: calling [github.com/go&#45;i2p/common/certificate.NewCertificateWithType]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M155.0528,-399C155.0528,-399 39.3302,-399 39.3302,-399 33.3302,-399 27.3302,-393 27.3302,-387 27.3302,-387 27.3302,-375 27.3302,-375 27.3302,-369 33.3302,-363 39.3302,-363 39.3302,-363 155.0528,-363 155.0528,-363 161.0528,-363 167.0528,-369 167.0528,-375 167.0528,-375 167.0528,-387 167.0528,-387 167.0528,-393 161.0528,-399 155.0528,-399"/>
<text text-anchor="middle" x="97.1915" y="-376.8" font-family="Verdana" font-size="14.00" fill="#000000">ConstructRouterInfo</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/samber/oops.Errorf -->
<g id="edge7" class="edge">
<g id="edge3" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/samber/oops.Errorf</title>
<g id="a_edge7"><a xlink:title="at routerinfo_keystore.go:131: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:138: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:142: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:149: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:155: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:164: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:175: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:196: calling [github.com/samber/oops.Errorf]">
<g id="a_edge3"><a xlink:title="at routerinfo_keystore.go:131: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:138: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:142: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:149: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:155: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:164: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:175: calling [github.com/samber/oops.Errorf]&#10;at routerinfo_keystore.go:196: calling [github.com/samber/oops.Errorf]">
<path fill="none" stroke="#8b4513" d="M167.08,-397.9109C213.1652,-409.0621 271.84,-423.2597 309.9668,-432.4852"/>
<polygon fill="#8b4513" stroke="#8b4513" points="309.6054,-435.9987 320.1481,-434.9488 311.2518,-429.195 309.6054,-435.9987"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/data.NewIntegerFromInt -->
<g id="edge10" class="edge">
<g id="edge4" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/data.NewIntegerFromInt</title>
<g id="a_edge10"><a xlink:title="at routerinfo_keystore.go:136: calling [github.com/go&#45;i2p/common/data.NewIntegerFromInt]&#10;at routerinfo_keystore.go:140: calling [github.com/go&#45;i2p/common/data.NewIntegerFromInt]">
<g id="a_edge4"><a xlink:title="at routerinfo_keystore.go:136: calling [github.com/go&#45;i2p/common/data.NewIntegerFromInt]&#10;at routerinfo_keystore.go:140: calling [github.com/go&#45;i2p/common/data.NewIntegerFromInt]">
<path fill="none" stroke="#8b4513" d="M123.1572,-399.1526C152.9874,-419.3634 203.9423,-451.9481 251.383,-473 258.3525,-476.0928 265.735,-478.9913 273.1963,-481.6739"/>
<polygon fill="#8b4513" stroke="#8b4513" points="272.0695,-484.9875 282.6643,-484.9547 274.3614,-478.3734 272.0695,-484.9875"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/certificate.NewCertificateWithType -->
<g id="edge2" class="edge">
<g id="edge15" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/certificate.NewCertificateWithType</title>
<g id="a_edge2"><a xlink:title="at routerinfo_keystore.go:147: calling [github.com/go&#45;i2p/common/certificate.NewCertificateWithType]">
<g id="a_edge15"><a xlink:title="at routerinfo_keystore.go:147: calling [github.com/go&#45;i2p/common/certificate.NewCertificateWithType]">
<path fill="none" stroke="#8b4513" d="M110.5872,-399.178C135.0387,-431.0938 190.0671,-497.2932 251.383,-534 256.3177,-536.9541 261.5687,-539.6407 266.9773,-542.0802"/>
<polygon fill="#8b4513" stroke="#8b4513" points="265.6254,-545.3085 276.2004,-545.9561 268.3373,-538.8552 265.6254,-545.3085"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate -->
<g id="edge13" class="edge">
<g id="edge8" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate</title>
<g id="a_edge13"><a xlink:title="at routerinfo_keystore.go:153: calling [github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate]">
<g id="a_edge8"><a xlink:title="at routerinfo_keystore.go:153: calling [github.com/go&#45;i2p/common/key_certificate.KeyCertificateFromCertificate]">
<path fill="none" stroke="#8b4513" d="M105.2684,-399.2715C124.4441,-440.5391 176.7586,-541.5127 251.383,-595 255.2437,-597.7672 259.365,-600.2835 263.6505,-602.5712"/>
<polygon fill="#8b4513" stroke="#8b4513" points="262.1237,-605.7207 272.6467,-606.9531 265.1891,-599.4275 262.1237,-605.7207"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/router_identity.NewRouterIdentity -->
<g id="edge8" class="edge">
<g id="edge10" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/router_identity.NewRouterIdentity</title>
<g id="a_edge8"><a xlink:title="at routerinfo_keystore.go:168: calling [github.com/go&#45;i2p/common/router_identity.NewRouterIdentity]">
<g id="a_edge10"><a xlink:title="at routerinfo_keystore.go:168: calling [github.com/go&#45;i2p/common/router_identity.NewRouterIdentity]">
<path fill="none" stroke="#8b4513" d="M102.1769,-399.1952C116.5795,-448.3171 162.9659,-584.7115 251.383,-656 258.0476,-661.3735 265.6693,-665.787 273.6522,-669.4114"/>
<polygon fill="#8b4513" stroke="#8b4513" points="272.5737,-672.7521 283.1536,-673.314 275.2333,-666.277 272.5737,-672.7521"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/router_info.NewRouterInfo -->
<g id="edge4" class="edge">
<g id="edge13" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;github.com/go&#45;i2p/common/router_info.NewRouterInfo</title>
<g id="a_edge4"><a xlink:title="at routerinfo_keystore.go:187: calling [github.com/go&#45;i2p/common/router_info.NewRouterInfo]">
<g id="a_edge13"><a xlink:title="at routerinfo_keystore.go:187: calling [github.com/go&#45;i2p/common/router_info.NewRouterInfo]">
<path fill="none" stroke="#8b4513" d="M100.1446,-399.0269C110.2618,-454.9599 148.7515,-627.1761 251.383,-717 260.5801,-725.0494 271.8986,-730.9391 283.5356,-735.2484"/>
<polygon fill="#8b4513" stroke="#8b4513" points="282.7525,-738.6764 293.346,-738.5094 284.9605,-732.0337 282.7525,-738.6764"/>
</a>
@@ -289,9 +289,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).GetKeys -->
<g id="edge1" class="edge">
<g id="edge12" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).GetKeys</title>
<g id="a_edge1"><a xlink:title="at routerinfo_keystore.go:129: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).GetKeys]">
<g id="a_edge12"><a xlink:title="at routerinfo_keystore.go:129: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).GetKeys]">
<path fill="none" stroke="#000000" d="M167.08,-381C210.2349,-381 264.4294,-381 302.4534,-381"/>
<polygon fill="#000000" stroke="#000000" points="302.7267,-384.5001 312.7267,-381 302.7266,-377.5001 302.7267,-384.5001"/>
</a>
@@ -300,7 +300,7 @@
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime -->
<g id="node18" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime</title>
<g id="a_node18"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime | defined in router_timestamper.go:418">
<g id="a_node18"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime | defined in router_timestamper.go:424">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M395.3133,-843C395.3133,-843 303.2649,-843 303.2649,-843 297.2649,-843 291.2649,-837 291.2649,-831 291.2649,-831 291.2649,-819 291.2649,-819 291.2649,-813 297.2649,-807 303.2649,-807 303.2649,-807 395.3133,-807 395.3133,-807 401.3133,-807 407.3133,-813 407.3133,-819 407.3133,-819 407.3133,-831 407.3133,-831 407.3133,-837 401.3133,-843 395.3133,-843"/>
<text text-anchor="middle" x="349.2891" y="-829.2" font-family="Verdana" font-size="14.00" fill="#000000">sntp</text>
<text text-anchor="middle" x="349.2891" y="-812.4" font-family="Verdana" font-size="14.00" fill="#000000">GetCurrentTime</text>
@@ -308,9 +308,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime -->
<g id="edge3" class="edge">
<g id="edge6" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime</title>
<g id="a_edge3"><a xlink:title="at routerinfo_keystore.go:179: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime]">
<g id="a_edge6"><a xlink:title="at routerinfo_keystore.go:179: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime]">
<path fill="none" stroke="#8b4513" d="M98.3907,-399.4173C103.1159,-459.3916 124.8601,-652.392 214.383,-777 229.877,-798.5663 255.9295,-810.4922 281.0313,-817.0679"/>
<polygon fill="#8b4513" stroke="#8b4513" points="280.4133,-820.5182 290.9504,-819.4138 282.0244,-813.7061 280.4133,-820.5182"/>
</a>
@@ -327,9 +327,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).CryptoSize -->
<g id="edge14" class="edge">
<g id="edge5" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).CryptoSize</title>
<g id="a_edge14"><a xlink:title="at routerinfo_keystore.go:158: calling [(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).CryptoSize]">
<g id="a_edge5"><a xlink:title="at routerinfo_keystore.go:158: calling [(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).CryptoSize]">
<path fill="none" stroke="#8b4513" d="M100.8634,-399.2164C117.0358,-477.8466 184.1015,-787.3271 251.383,-857 263.5568,-869.6065 279.3207,-880.0373 294.6285,-888.2592"/>
<polygon fill="#8b4513" stroke="#8b4513" points="293.0637,-891.3901 303.5582,-892.8446 296.2613,-885.1631 293.0637,-891.3901"/>
</a>
@@ -346,9 +346,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).SignatureSize -->
<g id="edge15" class="edge">
<g id="edge9" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).ConstructRouterInfo&#45;&gt;(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).SignatureSize</title>
<g id="a_edge15"><a xlink:title="at routerinfo_keystore.go:159: calling [(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).SignatureSize]">
<g id="a_edge9"><a xlink:title="at routerinfo_keystore.go:159: calling [(github.com/go&#45;i2p/common/key_certificate.KeyCertificate).SignatureSize]">
<path fill="none" stroke="#8b4513" d="M99.814,-399.2223C112.7051,-486.4192 171.9458,-860.2164 251.383,-942 260.7106,-951.6031 273.0223,-958.1524 285.7555,-962.6135"/>
<polygon fill="#8b4513" stroke="#8b4513" points="284.9448,-966.0262 295.5324,-965.634 287.011,-959.3381 284.9448,-966.0262"/>
</a>
@@ -373,9 +373,9 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).StoreKeys&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).KeyID -->
<g id="edge11" class="edge">
<g id="edge14" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).StoreKeys&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).KeyID</title>
<g id="a_edge11"><a xlink:title="at routerinfo_keystore.go:103: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).KeyID]">
<g id="a_edge14"><a xlink:title="at routerinfo_keystore.go:103: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/keys.RouterInfoKeystore).KeyID]">
<path fill="none" stroke="#000000" d="M138.538,-320C185.2893,-320 260.9744,-320 307.789,-320"/>
<polygon fill="#000000" stroke="#000000" points="307.8904,-323.5001 317.8903,-320 307.8903,-316.5001 307.8904,-323.5001"/>
</a>

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -215,6 +215,14 @@ func (db *StdNetDB) Save() (err error)
func (db *StdNetDB) SaveEntry(e *Entry) (err error)
```
#### func (*StdNetDB) SelectPeers
```go
func (db *StdNetDB) SelectPeers(count int, exclude []common.Hash) ([]router_info.RouterInfo, error)
```
SelectPeers selects a random subset of peers for tunnel building Filters out
unreachable routers and excludes specified hashes
#### func (*StdNetDB) Size
```go

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 252 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -11,6 +11,8 @@ import (
"strings"
"sync"
"github.com/go-i2p/crypto/rand"
"github.com/go-i2p/logger"
"github.com/sirupsen/logrus"
@@ -131,6 +133,80 @@ func (db *StdNetDB) GetAllRouterInfos() (ri []router_info.RouterInfo) {
return
}
// buildExcludeMap creates a map for fast hash lookup during peer filtering
func (db *StdNetDB) buildExcludeMap(exclude []common.Hash) map[common.Hash]bool {
excludeMap := make(map[common.Hash]bool)
for _, hash := range exclude {
excludeMap[hash] = true
}
return excludeMap
}
// filterAvailablePeers filters router infos excluding specified hashes and checking reachability
func (db *StdNetDB) filterAvailablePeers(allRouterInfos []router_info.RouterInfo, excludeMap map[common.Hash]bool) []router_info.RouterInfo {
var available []router_info.RouterInfo
for _, ri := range allRouterInfos {
riHash := ri.IdentHash()
if !excludeMap[riHash] {
// Basic reachability check - router should have valid addresses
if len(ri.RouterAddresses()) > 0 {
available = append(available, ri)
}
}
}
return available
}
// selectRandomPeers randomly selects the requested number of peers from available pool
func (db *StdNetDB) selectRandomPeers(available []router_info.RouterInfo, count int) []router_info.RouterInfo {
selected := make([]router_info.RouterInfo, count)
selectedIndices := make(map[int]bool)
for i := 0; i < count; i++ {
var idx int
for {
idx = rand.Intn(len(available))
if !selectedIndices[idx] {
selectedIndices[idx] = true
break
}
}
selected[i] = available[idx]
}
return selected
}
// SelectPeers selects a random subset of peers for tunnel building
// Filters out unreachable routers and excludes specified hashes
func (db *StdNetDB) SelectPeers(count int, exclude []common.Hash) ([]router_info.RouterInfo, error) {
log.WithFields(logrus.Fields{
"count": count,
"exclude": len(exclude),
}).Debug("Selecting peers for tunnel building")
allRouterInfos := db.GetAllRouterInfos()
if len(allRouterInfos) == 0 {
return nil, fmt.Errorf("no router infos available for peer selection")
}
excludeMap := db.buildExcludeMap(exclude)
available := db.filterAvailablePeers(allRouterInfos, excludeMap)
if len(available) == 0 {
return nil, fmt.Errorf("no suitable peers available after filtering")
}
// If we have fewer available peers than requested, return all
if len(available) <= count {
log.WithField("available_peers", len(available)).Debug("Returning all available peers")
return available, nil
}
selected := db.selectRandomPeers(available, count)
log.WithField("selected_peers", count).Debug("Peer selection completed")
return selected, nil
}
// get the skiplist file that a RouterInfo with this hash would go in
func (db *StdNetDB) SkiplistFile(hash common.Hash) (fpath string) {
fname := base64.EncodeToString(hash[:])
@@ -368,8 +444,8 @@ func (db *StdNetDB) SaveEntry(e *Entry) (err error) {
func (db *StdNetDB) Save() (err error) {
log.Debug("Saving all NetDB entries")
db.riMutex.Lock()
for _, dbe := range db.RouterInfos {
if e := db.SaveEntry(&dbe); e != nil {
for _, entry := range db.RouterInfos {
if e := db.SaveEntry(&entry); e != nil {
err = e
log.WithError(e).Error("Failed to save NetDB entry")
}

View File

@@ -216,13 +216,16 @@ func (r *Router) Start() {
go r.mainloop()
}
// run i2p router mainloop
func (r *Router) mainloop() {
// initializeNetDB creates and configures the network database
func (r *Router) initializeNetDB() error {
log.Debug("Entering router mainloop")
r.StdNetDB = netdb.NewStdNetDB(r.cfg.NetDb.Path)
log.WithField("netdb_path", r.cfg.NetDb.Path).Debug("Created StdNetDB")
return nil
}
// Initialize message router and connect to NetDB
// initializeMessageRouter sets up message routing with NetDB integration
func (r *Router) initializeMessageRouter() {
messageConfig := i2np.MessageRouterConfig{
MaxRetries: 3,
DefaultTimeout: 30 * time.Second,
@@ -230,63 +233,86 @@ func (r *Router) mainloop() {
}
r.messageRouter = i2np.NewMessageRouter(messageConfig)
r.messageRouter.SetNetDB(r.StdNetDB)
log.Debug("Message router initialized with NetDB integration")
r.messageRouter.SetPeerSelector(r.StdNetDB)
log.Debug("Message router initialized with NetDB integration and peer selection")
}
// make sure the netdb is ready
var e error
// ensureNetDBReady validates NetDB state and performs reseed if needed
func (r *Router) ensureNetDBReady() error {
if err := r.StdNetDB.Ensure(); err != nil {
e = err
log.WithError(err).Error("Failed to ensure NetDB")
return err
}
if sz := r.StdNetDB.Size(); sz >= 0 {
log.WithField("size", sz).Debug("NetDB Size: " + strconv.Itoa(sz))
} else {
log.Warn("Unable to determine NetDB size")
}
if r.StdNetDB.Size() < r.cfg.Bootstrap.LowPeerThreshold {
log.Info("NetDB below threshold, initiating reseed")
return r.performReseed()
}
return nil
}
// Create a bootstrap instance
bootstrapper := bootstrap.NewReseedBootstrap(r.cfg.Bootstrap)
// performReseed executes network database reseeding process
func (r *Router) performReseed() error {
log.Info("NetDB below threshold, initiating reseed")
// Reseed the network database
if err := r.StdNetDB.Reseed(bootstrapper, r.cfg.Bootstrap.LowPeerThreshold); err != nil {
log.WithError(err).Warn("Initial reseed failed, continuing with limited NetDB")
// Continue anyway, we might have some peers
bootstrapper := bootstrap.NewReseedBootstrap(r.cfg.Bootstrap)
if err := r.StdNetDB.Reseed(bootstrapper, r.cfg.Bootstrap.LowPeerThreshold); err != nil {
log.WithError(err).Warn("Initial reseed failed, continuing with limited NetDB")
return err
}
return nil
}
// runMainLoop executes the primary router event loop
func (r *Router) runMainLoop() {
log.WithFields(logrus.Fields{
"at": "(Router) mainloop",
}).Debug("Router ready with database message processing enabled")
for {
r.runMux.RLock()
shouldRun := r.running
r.runMux.RUnlock()
if !shouldRun {
break
}
select {
case <-r.closeChnl:
log.Debug("Router received close signal in mainloop")
return
case <-time.After(time.Second):
// Continue loop after 1 second timeout
}
}
if e == nil {
// netdb ready
log.WithFields(logrus.Fields{
"at": "(Router) mainloop",
}).Debug("Router ready with database message processing enabled")
}
for {
// Check if we should continue running in a thread-safe way
r.runMux.RLock()
shouldRun := r.running
r.runMux.RUnlock()
// run i2p router mainloop
func (r *Router) mainloop() {
if err := r.initializeNetDB(); err != nil {
log.WithError(err).Error("Failed to initialize NetDB")
r.Stop()
return
}
if !shouldRun {
break
}
r.initializeMessageRouter()
// Use select to make shutdown more responsive
select {
case <-r.closeChnl:
log.Debug("Router received close signal in mainloop")
return
case <-time.After(time.Second):
// Continue loop after 1 second timeout
}
}
} else {
// netdb failed
if err := r.ensureNetDBReady(); err != nil {
log.WithFields(logrus.Fields{
"at": "(Router) mainloop",
"reason": e.Error(),
"reason": err.Error(),
}).Error("Netdb Startup failed")
r.Stop()
return
}
r.runMainLoop()
log.Debug("Exiting router mainloop")
}

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View File

@@ -150,6 +150,14 @@ func (s *NTCP2Session) SendQueueSize() int
```
SendQueueSize returns how many I2NP messages are not completely sent yet.
#### func (*NTCP2Session) SetCleanupCallback
```go
func (s *NTCP2Session) SetCleanupCallback(callback func())
```
SetCleanupCallback sets a callback function that will be called when the session
closes
#### type NTCP2Transport
```go

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

@@ -25,8 +25,8 @@
<g id="clust4" class="cluster">
<title>cluster_*github.com/sirupsen/logrus.Logger</title>
<g id="a_clust4"><a xlink:title="type: *github.com/sirupsen/logrus.Logger">
<path fill="#eed8ae" stroke="#000000" stroke-width=".5" d="M251.2623,-476C251.2623,-476 305.5835,-476 305.5835,-476 311.5835,-476 317.5835,-482 317.5835,-488 317.5835,-488 317.5835,-542 317.5835,-542 317.5835,-548 311.5835,-554 305.5835,-554 305.5835,-554 251.2623,-554 251.2623,-554 245.2623,-554 239.2623,-548 239.2623,-542 239.2623,-542 239.2623,-488 239.2623,-488 239.2623,-482 245.2623,-476 251.2623,-476"/>
<text text-anchor="middle" x="278.4229" y="-484.5" font-family="Arial" font-size="15.00" fill="#222222">(*Logger)</text>
<path fill="#eed8ae" stroke="#000000" stroke-width=".5" d="M251.2623,-477C251.2623,-477 305.5835,-477 305.5835,-477 311.5835,-477 317.5835,-483 317.5835,-489 317.5835,-489 317.5835,-543 317.5835,-543 317.5835,-549 311.5835,-555 305.5835,-555 305.5835,-555 251.2623,-555 251.2623,-555 245.2623,-555 239.2623,-549 239.2623,-543 239.2623,-543 239.2623,-489 239.2623,-489 239.2623,-483 245.2623,-477 251.2623,-477"/>
<text text-anchor="middle" x="278.4229" y="-485.5" font-family="Arial" font-size="15.00" fill="#222222">(*Logger)</text>
</a>
</g>
</g>
@@ -41,15 +41,15 @@
<g id="clust2" class="cluster">
<title>cluster_*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer</title>
<g id="a_clust2"><a xlink:title="type: *github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer">
<path fill="#b0c4de" stroke="#000000" stroke-width=".5" d="M20,-181C20,-181 133.3282,-181 133.3282,-181 139.3282,-181 145.3282,-187 145.3282,-193 145.3282,-193 145.3282,-491 145.3282,-491 145.3282,-497 139.3282,-503 133.3282,-503 133.3282,-503 20,-503 20,-503 14,-503 8,-497 8,-491 8,-491 8,-193 8,-193 8,-187 14,-181 20,-181"/>
<text text-anchor="middle" x="76.6641" y="-189.5" font-family="Arial" font-size="15.00" fill="#222222">(*TransportMuxer)</text>
<path fill="#b0c4de" stroke="#000000" stroke-width=".5" d="M20,-154C20,-154 133.3282,-154 133.3282,-154 139.3282,-154 145.3282,-160 145.3282,-166 145.3282,-166 145.3282,-464 145.3282,-464 145.3282,-470 139.3282,-476 133.3282,-476 133.3282,-476 20,-476 20,-476 14,-476 8,-470 8,-464 8,-464 8,-166 8,-166 8,-160 14,-154 20,-154"/>
<text text-anchor="middle" x="76.6641" y="-162.5" font-family="Arial" font-size="15.00" fill="#222222">(*TransportMuxer)</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/transport.Mux -->
<g id="node1" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/transport.Mux</title>
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/transport.Mux | defined in multi.go:18&#10;at multi.go:19: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:22: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:19: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/transport.Mux | defined in multi.go:18&#10;at multi.go:19: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:19: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:22: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M91.6641,-607C91.6641,-607 61.6641,-607 61.6641,-607 55.6641,-607 49.6641,-601 49.6641,-595 49.6641,-595 49.6641,-583 49.6641,-583 49.6641,-577 55.6641,-571 61.6641,-571 61.6641,-571 91.6641,-571 91.6641,-571 97.6641,-571 103.6641,-577 103.6641,-583 103.6641,-583 103.6641,-595 103.6641,-595 103.6641,-601 97.6641,-607 91.6641,-607"/>
<text text-anchor="middle" x="76.6641" y="-584.8" font-family="Verdana" font-size="14.00" fill="#000000">Mux</text>
</a>
@@ -66,11 +66,11 @@
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/transport.Mux&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge21" class="edge">
<g id="edge16" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/transport.Mux&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge21"><a xlink:title="at multi.go:19: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M94.9434,-570.6918C120.6186,-545.6706 169.5856,-500.434 217.3282,-470 220.8462,-467.7574 224.573,-465.5919 228.3803,-463.526"/>
<polygon fill="#8b4513" stroke="#8b4513" points="230.0685,-466.5935 237.35,-458.8973 226.8584,-460.3729 230.0685,-466.5935"/>
<g id="a_edge16"><a xlink:title="at multi.go:19: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M95.0317,-570.9518C120.8095,-546.264 169.8949,-501.5498 217.3282,-471 220.858,-468.7266 224.5933,-466.5191 228.4066,-464.4039"/>
<polygon fill="#8b4513" stroke="#8b4513" points="230.1865,-467.4219 237.3855,-459.6486 226.9103,-461.2359 230.1865,-467.4219"/>
</a>
</g>
</g>
@@ -78,18 +78,18 @@
<g id="node14" class="node">
<title>(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_node14"><a xlink:title="(*github.com/sirupsen/logrus.Logger).Debug | defined in logger.go:221">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M296.7449,-546C296.7449,-546 259.1009,-546 259.1009,-546 253.1009,-546 247.1009,-540 247.1009,-534 247.1009,-534 247.1009,-522 247.1009,-522 247.1009,-516 253.1009,-510 259.1009,-510 259.1009,-510 296.7449,-510 296.7449,-510 302.7449,-510 308.7449,-516 308.7449,-522 308.7449,-522 308.7449,-534 308.7449,-534 308.7449,-540 302.7449,-546 296.7449,-546"/>
<text text-anchor="middle" x="277.9229" y="-532.2" font-family="Verdana" font-size="14.00" fill="#000000">logrus</text>
<text text-anchor="middle" x="277.9229" y="-515.4" font-family="Verdana" font-size="14.00" fill="#000000">Debug</text>
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M296.7449,-547C296.7449,-547 259.1009,-547 259.1009,-547 253.1009,-547 247.1009,-541 247.1009,-535 247.1009,-535 247.1009,-523 247.1009,-523 247.1009,-517 253.1009,-511 259.1009,-511 259.1009,-511 296.7449,-511 296.7449,-511 302.7449,-511 308.7449,-517 308.7449,-523 308.7449,-523 308.7449,-535 308.7449,-535 308.7449,-541 302.7449,-547 296.7449,-547"/>
<text text-anchor="middle" x="277.9229" y="-533.2" font-family="Verdana" font-size="14.00" fill="#000000">logrus</text>
<text text-anchor="middle" x="277.9229" y="-516.4" font-family="Verdana" font-size="14.00" fill="#000000">Debug</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/transport.Mux&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge2" class="edge">
<g id="edge21" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/transport.Mux&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge2"><a xlink:title="at multi.go:19: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:22: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M103.9423,-593.9785C125.428,-596.8474 155.894,-598.5612 181.3282,-591 206.7912,-583.4302 231.807,-566.7843 249.9994,-552.5035"/>
<polygon fill="#8b4513" stroke="#8b4513" points="252.281,-555.1597 257.855,-546.1496 247.8789,-549.7171 252.281,-555.1597"/>
<g id="a_edge21"><a xlink:title="at multi.go:19: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:22: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M103.9271,-593.9271C125.4045,-596.7676 155.8666,-598.4683 181.3282,-591 206.5328,-583.6071 231.3907,-567.3902 249.5769,-553.3961"/>
<polygon fill="#8b4513" stroke="#8b4513" points="251.7782,-556.1173 257.4405,-547.1624 247.4297,-550.6318 251.7782,-556.1173"/>
</a>
</g>
</g>
@@ -106,18 +106,18 @@
<g id="node3" class="node">
<title>github.com/samber/oops.Errorf</title>
<g id="a_node3"><a xlink:title="github.com/samber/oops.Errorf | defined in oops.go:34">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M295.1182,-52C295.1182,-52 260.7276,-52 260.7276,-52 254.7276,-52 248.7276,-46 248.7276,-40 248.7276,-40 248.7276,-28 248.7276,-28 248.7276,-22 254.7276,-16 260.7276,-16 260.7276,-16 295.1182,-16 295.1182,-16 301.1182,-16 307.1182,-22 307.1182,-28 307.1182,-28 307.1182,-40 307.1182,-40 307.1182,-46 301.1182,-52 295.1182,-52"/>
<text text-anchor="middle" x="277.9229" y="-38.2" font-family="Verdana" font-size="14.00" fill="#000000">oops</text>
<text text-anchor="middle" x="277.9229" y="-21.4" font-family="Verdana" font-size="14.00" fill="#000000">Errorf</text>
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M295.1182,-113C295.1182,-113 260.7276,-113 260.7276,-113 254.7276,-113 248.7276,-107 248.7276,-101 248.7276,-101 248.7276,-89 248.7276,-89 248.7276,-83 254.7276,-77 260.7276,-77 260.7276,-77 295.1182,-77 295.1182,-77 301.1182,-77 307.1182,-83 307.1182,-89 307.1182,-89 307.1182,-101 307.1182,-101 307.1182,-107 301.1182,-113 295.1182,-113"/>
<text text-anchor="middle" x="277.9229" y="-99.2" font-family="Verdana" font-size="14.00" fill="#000000">oops</text>
<text text-anchor="middle" x="277.9229" y="-82.4" font-family="Verdana" font-size="14.00" fill="#000000">Errorf</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/transport.init&#45;&gt;github.com/samber/oops.Errorf -->
<g id="edge11" class="edge">
<g id="edge22" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/transport.init&#45;&gt;github.com/samber/oops.Errorf</title>
<g id="a_edge11"><a xlink:title="at errors.go:6: calling [github.com/samber/oops.Errorf]">
<path fill="none" stroke="#8b4513" d="M103.8068,-38.3257C138.4765,-37.4644 198.7348,-35.9673 238.475,-34.98"/>
<polygon fill="#8b4513" stroke="#8b4513" points="238.6944,-38.4758 248.6043,-34.7284 238.5204,-31.4779 238.6944,-38.4758"/>
<g id="a_edge22"><a xlink:title="at errors.go:6: calling [github.com/samber/oops.Errorf]">
<path fill="none" stroke="#8b4513" d="M103.8068,-46.5524C138.5502,-56.2197 198.9914,-73.0374 238.7284,-84.0942"/>
<polygon fill="#8b4513" stroke="#8b4513" points="238.032,-87.5333 248.6043,-86.8421 239.9086,-80.7895 238.032,-87.5333"/>
</a>
</g>
</g>
@@ -125,110 +125,72 @@
<g id="node4" class="node">
<title>github.com/go&#45;i2p/logger.GetGoI2PLogger</title>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/logger.GetGoI2PLogger | defined in log.go:120">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M326.6124,-113C326.6124,-113 229.2334,-113 229.2334,-113 223.2334,-113 217.2334,-107 217.2334,-101 217.2334,-101 217.2334,-89 217.2334,-89 217.2334,-83 223.2334,-77 229.2334,-77 229.2334,-77 326.6124,-77 326.6124,-77 332.6124,-77 338.6124,-83 338.6124,-89 338.6124,-89 338.6124,-101 338.6124,-101 338.6124,-107 332.6124,-113 326.6124,-113"/>
<text text-anchor="middle" x="277.9229" y="-99.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="277.9229" y="-82.4" font-family="Verdana" font-size="14.00" fill="#000000">GetGoI2PLogger</text>
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M326.6124,-52C326.6124,-52 229.2334,-52 229.2334,-52 223.2334,-52 217.2334,-46 217.2334,-40 217.2334,-40 217.2334,-28 217.2334,-28 217.2334,-22 223.2334,-16 229.2334,-16 229.2334,-16 326.6124,-16 326.6124,-16 332.6124,-16 338.6124,-22 338.6124,-28 338.6124,-28 338.6124,-40 338.6124,-40 338.6124,-46 332.6124,-52 326.6124,-52"/>
<text text-anchor="middle" x="277.9229" y="-38.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="277.9229" y="-21.4" font-family="Verdana" font-size="14.00" fill="#000000">GetGoI2PLogger</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/transport.init&#45;&gt;github.com/go&#45;i2p/logger.GetGoI2PLogger -->
<g id="edge7" class="edge">
<g id="edge4" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/transport.init&#45;&gt;github.com/go&#45;i2p/logger.GetGoI2PLogger</title>
<g id="a_edge7"><a xlink:title="at multi.go:8: calling [github.com/go&#45;i2p/logger.GetGoI2PLogger]">
<path fill="none" stroke="#8b4513" d="M103.9173,-44.9123C125.1259,-49.6571 155.2389,-56.7091 181.3282,-64 192.1517,-67.0247 203.5808,-70.4675 214.6411,-73.9321"/>
<polygon fill="#8b4513" stroke="#8b4513" points="213.6512,-77.2899 224.2413,-76.9723 215.7646,-70.6165 213.6512,-77.2899"/>
<g id="a_edge4"><a xlink:title="at multi.go:8: calling [github.com/go&#45;i2p/logger.GetGoI2PLogger]">
<path fill="none" stroke="#8b4513" d="M103.8068,-38.3257C130.076,-37.6731 171.036,-36.6555 206.63,-35.7712"/>
<polygon fill="#8b4513" stroke="#8b4513" points="207.0846,-39.2611 216.9946,-35.5137 206.9107,-32.2632 207.0846,-39.2611"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity -->
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name -->
<g id="node5" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity</title>
<g id="a_node5"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity | defined in multi.go:27&#10;at multi.go:28: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:38: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:36: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).Error]&#10;at multi.go:28: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:36: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M107.6,-312C107.6,-312 45.7282,-312 45.7282,-312 39.7282,-312 33.7282,-306 33.7282,-300 33.7282,-300 33.7282,-288 33.7282,-288 33.7282,-282 39.7282,-276 45.7282,-276 45.7282,-276 107.6,-276 107.6,-276 113.6,-276 119.6,-282 119.6,-288 119.6,-288 119.6,-300 119.6,-300 119.6,-306 113.6,-312 107.6,-312"/>
<text text-anchor="middle" x="76.6641" y="-289.8" font-family="Verdana" font-size="14.00" fill="#000000">SetIdentity</text>
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name</title>
<g id="a_node5"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name | defined in multi.go:59&#10;at multi.go:60: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:67: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:67: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M93.5921,-468C93.5921,-468 59.7361,-468 59.7361,-468 53.7361,-468 47.7361,-462 47.7361,-456 47.7361,-456 47.7361,-444 47.7361,-444 47.7361,-438 53.7361,-432 59.7361,-432 59.7361,-432 93.5921,-432 93.5921,-432 99.5921,-432 105.5921,-438 105.5921,-444 105.5921,-444 105.5921,-456 105.5921,-456 105.5921,-462 99.5921,-468 93.5921,-468"/>
<text text-anchor="middle" x="76.6641" y="-445.8" font-family="Verdana" font-size="14.00" fill="#000000">Name</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge19" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge19"><a xlink:title="at multi.go:28: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:36: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M119.4578,-302.3757C140.2123,-308.2737 164.2756,-318.0591 181.3282,-334 209.22,-360.0735 190.7014,-384.636 217.3282,-412 220.7307,-415.4967 224.6255,-418.6487 228.7632,-421.4758"/>
<polygon fill="#8b4513" stroke="#8b4513" points="227.1601,-424.598 237.5174,-426.8289 230.8119,-418.626 227.1601,-424.598"/>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge23" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge23"><a xlink:title="at multi.go:67: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M105.4996,-448.8538C137.093,-447.598 188.3869,-445.559 226.8299,-444.0309"/>
<polygon fill="#8b4513" stroke="#8b4513" points="227.4519,-447.5091 237.3049,-443.6146 227.1738,-440.5146 227.4519,-447.5091"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="node11" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_node11"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).WithError | defined in log.go:66">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M306.4544,-399C306.4544,-399 249.3914,-399 249.3914,-399 243.3914,-399 237.3914,-393 237.3914,-387 237.3914,-387 237.3914,-375 237.3914,-375 237.3914,-369 243.3914,-363 249.3914,-363 249.3914,-363 306.4544,-363 306.4544,-363 312.4544,-363 318.4544,-369 318.4544,-375 318.4544,-375 318.4544,-387 318.4544,-387 318.4544,-393 312.4544,-399 306.4544,-399"/>
<text text-anchor="middle" x="277.9229" y="-385.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="277.9229" y="-368.4" font-family="Verdana" font-size="14.00" fill="#000000">WithError</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="edge20" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_edge20"><a xlink:title="at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="none" stroke="#8b4513" d="M119.3928,-292.1913C139.2988,-293.0739 162.6522,-296.6923 181.3282,-307 203.4495,-319.2093 197.561,-335.2623 217.3282,-351 220.8323,-353.7898 224.638,-356.4144 228.5775,-358.8611"/>
<polygon fill="#8b4513" stroke="#8b4513" points="226.9404,-361.9575 237.3504,-363.9283 230.4416,-355.8959 226.9404,-361.9575"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/logger.Logger).Error -->
<g id="node12" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).Error</title>
<g id="a_node12"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).Error | defined in log.go:42">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M295.6892,-277C295.6892,-277 260.1566,-277 260.1566,-277 254.1566,-277 248.1566,-271 248.1566,-265 248.1566,-265 248.1566,-253 248.1566,-253 248.1566,-247 254.1566,-241 260.1566,-241 260.1566,-241 295.6892,-241 295.6892,-241 301.6892,-241 307.6892,-247 307.6892,-253 307.6892,-253 307.6892,-265 307.6892,-265 307.6892,-271 301.6892,-277 295.6892,-277"/>
<text text-anchor="middle" x="277.9229" y="-263.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="277.9229" y="-246.4" font-family="Verdana" font-size="14.00" fill="#000000">Error</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Error -->
<g id="edge13" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Error</title>
<g id="a_edge13"><a xlink:title="at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).Error]">
<path fill="none" stroke="#8b4513" d="M119.6231,-280.4637C128.8132,-276.2048 137.9607,-270.7867 145.3282,-264 169.4606,-241.7701 152.1597,-215.8249 180.3282,-199 193.4449,-191.1655 225.9673,-214.3436 249.8796,-234.1329"/>
<polygon fill="#8b4513" stroke="#8b4513" points="247.7189,-236.8893 257.6184,-240.6644 252.2338,-231.5399 247.7189,-236.8893"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge12" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge12"><a xlink:title="at multi.go:28: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:38: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:36: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M119.4911,-307.7944C128.7922,-312.2219 138.0209,-317.8807 145.3282,-325 198.008,-376.3247 173.0223,-415.2942 217.3282,-474 225.3658,-484.6499 235.7473,-494.8091 245.6393,-503.3836"/>
<polygon fill="#8b4513" stroke="#8b4513" points="243.5011,-506.1583 253.4134,-509.8996 247.9977,-500.7935 243.5011,-506.1583"/>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge5" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge5"><a xlink:title="at multi.go:60: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:67: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M105.4492,-454.1346C118.7547,-457.2385 134.065,-462.6384 145.3282,-472 170.5609,-492.9727 152.1597,-520.1751 180.3282,-537 197.1992,-547.0769 218.7327,-546.4226 237.2782,-542.6735"/>
<polygon fill="#8b4513" stroke="#8b4513" points="238.2995,-546.0286 247.2254,-540.3208 236.6882,-539.2165 238.2995,-546.0286"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible -->
<g id="node6" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible</title>
<g id="a_node6"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible | defined in multi.go:100&#10;at multi.go:101: calling [(github.com/go&#45;i2p/common/router_info.RouterInfo).String]&#10;at multi.go:101: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:109: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:104: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:101: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:104: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M109.4929,-373C109.4929,-373 43.8353,-373 43.8353,-373 37.8353,-373 31.8353,-367 31.8353,-361 31.8353,-361 31.8353,-349 31.8353,-349 31.8353,-343 37.8353,-337 43.8353,-337 43.8353,-337 109.4929,-337 109.4929,-337 115.4929,-337 121.4929,-343 121.4929,-349 121.4929,-349 121.4929,-361 121.4929,-361 121.4929,-367 115.4929,-373 109.4929,-373"/>
<text text-anchor="middle" x="76.6641" y="-350.8" font-family="Verdana" font-size="14.00" fill="#000000">Compatible</text>
<g id="a_node6"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible | defined in multi.go:100&#10;at multi.go:101: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:109: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:104: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:101: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:104: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:101: calling [(github.com/go&#45;i2p/common/router_info.RouterInfo).String]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M109.4929,-407C109.4929,-407 43.8353,-407 43.8353,-407 37.8353,-407 31.8353,-401 31.8353,-395 31.8353,-395 31.8353,-383 31.8353,-383 31.8353,-377 37.8353,-371 43.8353,-371 43.8353,-371 109.4929,-371 109.4929,-371 115.4929,-371 121.4929,-377 121.4929,-383 121.4929,-383 121.4929,-395 121.4929,-395 121.4929,-401 115.4929,-407 109.4929,-407"/>
<text text-anchor="middle" x="76.6641" y="-384.8" font-family="Verdana" font-size="14.00" fill="#000000">Compatible</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge22" class="edge">
<g id="edge9" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge22"><a xlink:title="at multi.go:101: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:104: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M118.3651,-373.0265C150.2534,-386.8111 194.3315,-405.8652 228.0805,-420.4542"/>
<polygon fill="#8b4513" stroke="#8b4513" points="226.7389,-423.6872 237.3068,-424.4425 229.5165,-417.2618 226.7389,-423.6872"/>
<g id="a_edge9"><a xlink:title="at multi.go:101: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:104: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M121.33,-400.7624C152.8146,-409.0537 195.0163,-420.1672 227.6757,-428.7678"/>
<polygon fill="#8b4513" stroke="#8b4513" points="226.921,-432.1883 237.4826,-431.3504 228.7036,-425.4191 226.921,-432.1883"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge9" class="edge">
<g id="edge6" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge9"><a xlink:title="at multi.go:101: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:109: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:104: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M121.5919,-371.6625C129.8804,-375.7208 138.1687,-380.5055 145.3282,-386 185.4172,-416.7661 182.3569,-437.5214 217.3282,-474 226.8695,-483.9525 237.969,-494.1855 248.0417,-503.0308"/>
<polygon fill="#8b4513" stroke="#8b4513" points="246.0003,-505.893 255.8504,-509.7951 250.5836,-500.6021 246.0003,-505.893"/>
<g id="a_edge6"><a xlink:title="at multi.go:101: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:109: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:104: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M121.3352,-403.077C130.1218,-407.4232 138.6687,-412.9765 145.3282,-420 174.8583,-451.144 147.3947,-482.4798 180.3282,-510 195.863,-522.9813 217.6474,-528.0562 236.6946,-529.7444"/>
<polygon fill="#8b4513" stroke="#8b4513" points="236.745,-533.2537 246.9377,-530.3625 237.1667,-526.2664 236.745,-533.2537"/>
</a>
</g>
</g>
@@ -243,38 +205,112 @@
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible&#45;&gt;(github.com/go&#45;i2p/common/router_info.RouterInfo).String -->
<g id="edge8" class="edge">
<g id="edge17" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Compatible&#45;&gt;(github.com/go&#45;i2p/common/router_info.RouterInfo).String</title>
<g id="a_edge8"><a xlink:title="at multi.go:101: calling [(github.com/go&#45;i2p/common/router_info.RouterInfo).String]">
<path fill="none" stroke="#8b4513" d="M121.6137,-340.2747C130.084,-336.1932 138.4352,-331.1479 145.3282,-325 192.8878,-282.5816 170.2155,-243.9141 217.3282,-201 219.8904,-198.6662 222.6809,-196.4955 225.6113,-194.4817"/>
<polygon fill="#8b4513" stroke="#8b4513" points="227.485,-197.4384 234.1674,-189.2167 223.8164,-191.4767 227.485,-197.4384"/>
<g id="a_edge17"><a xlink:title="at multi.go:101: calling [(github.com/go&#45;i2p/common/router_info.RouterInfo).String]">
<path fill="none" stroke="#8b4513" d="M121.3878,-375.1403C130.0695,-370.9644 138.5607,-365.6623 145.3282,-359 200.3212,-304.8619 162.9052,-255.711 217.3282,-201 219.9333,-198.3811 222.8291,-195.9803 225.9027,-193.7839"/>
<polygon fill="#8b4513" stroke="#8b4513" points="227.7869,-196.7336 234.377,-188.4377 224.0519,-190.8133 227.7869,-196.7336"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close -->
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity -->
<g id="node7" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close</title>
<g id="a_node7"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close | defined in multi.go:43&#10;at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]&#10;at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]&#10;at multi.go:44: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:54: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:51: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M92.5506,-434C92.5506,-434 60.7776,-434 60.7776,-434 54.7776,-434 48.7776,-428 48.7776,-422 48.7776,-422 48.7776,-410 48.7776,-410 48.7776,-404 54.7776,-398 60.7776,-398 60.7776,-398 92.5506,-398 92.5506,-398 98.5506,-398 104.5506,-404 104.5506,-410 104.5506,-410 104.5506,-422 104.5506,-422 104.5506,-428 98.5506,-434 92.5506,-434"/>
<text text-anchor="middle" x="76.6641" y="-411.8" font-family="Verdana" font-size="14.00" fill="#000000">Close</text>
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity</title>
<g id="a_node7"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity | defined in multi.go:27&#10;at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).Error]&#10;at multi.go:28: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:38: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:36: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]&#10;at multi.go:28: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:36: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M107.6,-346C107.6,-346 45.7282,-346 45.7282,-346 39.7282,-346 33.7282,-340 33.7282,-334 33.7282,-334 33.7282,-322 33.7282,-322 33.7282,-316 39.7282,-310 45.7282,-310 45.7282,-310 107.6,-310 107.6,-310 113.6,-310 119.6,-316 119.6,-322 119.6,-322 119.6,-334 119.6,-334 119.6,-340 113.6,-346 107.6,-346"/>
<text text-anchor="middle" x="76.6641" y="-323.8" font-family="Verdana" font-size="14.00" fill="#000000">SetIdentity</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge14" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge14"><a xlink:title="at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M104.6483,-419.6152C136.2767,-423.7012 188.4064,-430.4356 227.2405,-435.4525"/>
<polygon fill="#8b4513" stroke="#8b4513" points="226.9427,-438.943 237.3087,-436.7532 227.8396,-432.0007 226.9427,-438.943"/>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge18" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge18"><a xlink:title="at multi.go:28: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:36: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M119.4915,-345.6533C128.2121,-349.7123 137.1997,-354.2449 145.3282,-359 179.6255,-379.0639 183.3938,-391.3283 217.3282,-412 221.3758,-414.4657 225.6539,-416.8998 229.9891,-419.251"/>
<polygon fill="#8b4513" stroke="#8b4513" points="228.4326,-422.3869 238.9124,-423.9443 231.6912,-416.1916 228.4326,-422.3869"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError -->
<!-- (*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="node11" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_node11"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).WithError | defined in log.go:66">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M306.4544,-399C306.4544,-399 249.3914,-399 249.3914,-399 243.3914,-399 237.3914,-393 237.3914,-387 237.3914,-387 237.3914,-375 237.3914,-375 237.3914,-369 243.3914,-363 249.3914,-363 249.3914,-363 306.4544,-363 306.4544,-363 312.4544,-363 318.4544,-369 318.4544,-375 318.4544,-375 318.4544,-387 318.4544,-387 318.4544,-393 312.4544,-399 306.4544,-399"/>
<text text-anchor="middle" x="277.9229" y="-385.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="277.9229" y="-368.4" font-family="Verdana" font-size="14.00" fill="#000000">WithError</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="edge11" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_edge11"><a xlink:title="at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="none" stroke="#8b4513" d="M119.5237,-326.6676C138.7019,-327.0339 161.4268,-328.811 181.3282,-334 182.7984,-334.3833 207.814,-346.5613 232.0167,-358.4235"/>
<polygon fill="#8b4513" stroke="#8b4513" points="230.6826,-361.6674 241.202,-362.9291 233.7654,-355.3828 230.6826,-361.6674"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/logger.Logger).Error -->
<g id="node12" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).Error</title>
<g id="a_node12"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).Error | defined in log.go:42">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M295.6892,-338C295.6892,-338 260.1566,-338 260.1566,-338 254.1566,-338 248.1566,-332 248.1566,-326 248.1566,-326 248.1566,-314 248.1566,-314 248.1566,-308 254.1566,-302 260.1566,-302 260.1566,-302 295.6892,-302 295.6892,-302 301.6892,-302 307.6892,-308 307.6892,-314 307.6892,-314 307.6892,-326 307.6892,-326 307.6892,-332 301.6892,-338 295.6892,-338"/>
<text text-anchor="middle" x="277.9229" y="-324.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="277.9229" y="-307.4" font-family="Verdana" font-size="14.00" fill="#000000">Error</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Error -->
<g id="edge1" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Error</title>
<g id="a_edge1"><a xlink:title="at multi.go:32: calling [(*github.com/go&#45;i2p/logger.Logger).Error]">
<path fill="none" stroke="#8b4513" d="M119.5493,-313.1968C128.5425,-309.043 137.6254,-303.9884 145.3282,-298 165.3315,-282.4486 157.5674,-264.1319 180.3282,-253 201.2194,-242.7825 198.5286,-276.3101 217.3282,-290 223.9336,-294.8101 231.427,-299.2224 238.837,-303.0976"/>
<polygon fill="#8b4513" stroke="#8b4513" points="237.5932,-306.388 248.1054,-307.7086 240.7111,-300.1207 237.5932,-306.388"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge10" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_edge10"><a xlink:title="at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="none" stroke="#8b4513" d="M104.6483,-411.1334C136.2767,-405.6331 188.4064,-396.5674 227.2405,-389.8139"/>
<polygon fill="#8b4513" stroke="#8b4513" points="228.0563,-393.2247 237.3087,-388.063 226.8569,-386.3282 228.0563,-393.2247"/>
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).SetIdentity&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge10"><a xlink:title="at multi.go:28: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:38: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:36: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M119.7212,-340.567C129.2346,-345.0703 138.5005,-351.071 145.3282,-359 182.6945,-402.3932 143.3184,-439.3023 180.3282,-483 194.9305,-500.2411 217.439,-511.4473 237.1615,-518.478"/>
<polygon fill="#8b4513" stroke="#8b4513" points="236.2743,-521.8711 246.8677,-521.6929 238.4753,-515.2261 236.2743,-521.8711"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession -->
<g id="node8" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession</title>
<g id="a_node8"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession | defined in multi.go:74&#10;at multi.go:75: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:79: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:89: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]&#10;at multi.go:75: calling [(github.com/go&#45;i2p/common/router_info.RouterInfo).String]&#10;at multi.go:93: calling [(*github.com/go&#45;i2p/logger.Logger).Error]&#10;at multi.go:75: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:79: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:89: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M108.1529,-224C108.1529,-224 45.1753,-224 45.1753,-224 39.1753,-224 33.1753,-218 33.1753,-212 33.1753,-212 33.1753,-200 33.1753,-200 33.1753,-194 39.1753,-188 45.1753,-188 45.1753,-188 108.1529,-188 108.1529,-188 114.1529,-188 120.1529,-194 120.1529,-200 120.1529,-200 120.1529,-212 120.1529,-212 120.1529,-218 114.1529,-224 108.1529,-224"/>
<text text-anchor="middle" x="76.6641" y="-201.8" font-family="Verdana" font-size="14.00" fill="#000000">GetSession</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge2" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge2"><a xlink:title="at multi.go:75: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:79: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:89: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M120.1618,-219.6536C129.3269,-224.0699 138.328,-229.7594 145.3282,-237 203.786,-297.4654 159.9569,-350.5027 217.3282,-412 220.7039,-415.6184 224.6109,-418.8587 228.7828,-421.7472"/>
<polygon fill="#8b4513" stroke="#8b4513" points="227.2813,-424.9327 237.6328,-427.1906 230.9487,-418.9702 227.2813,-424.9327"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="edge3" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_edge3"><a xlink:title="at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="none" stroke="#8b4513" d="M120.3588,-221.0963C129.2062,-225.379 138.0248,-230.6487 145.3282,-237 190.5472,-276.3237 172.817,-310.8769 217.3282,-351 220.7055,-354.0443 224.448,-356.8542 228.3679,-359.4309"/>
<polygon fill="#8b4513" stroke="#8b4513" points="226.7828,-362.5614 237.1596,-364.6998 230.3812,-356.5571 226.7828,-362.5614"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Error -->
<g id="edge13" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Error</title>
<g id="a_edge13"><a xlink:title="at multi.go:93: calling [(*github.com/go&#45;i2p/logger.Logger).Error]">
<path fill="none" stroke="#8b4513" d="M120.3605,-217.6857C140.138,-224.2904 163.1093,-233.895 181.3282,-247 201.562,-261.5543 197.7415,-274.5859 217.3282,-290 223.8143,-295.1044 231.3086,-299.6679 238.7679,-303.6027"/>
<polygon fill="#8b4513" stroke="#8b4513" points="237.6057,-306.9332 248.1192,-308.2438 240.7178,-300.663 237.6057,-306.9332"/>
</a>
</g>
</g>
@@ -282,117 +318,81 @@
<g id="node13" class="node">
<title>(*github.com/go&#45;i2p/logger.Logger).Warn</title>
<g id="a_node13"><a xlink:title="(*github.com/go&#45;i2p/logger.Logger).Warn | defined in log.go:30">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M295.6892,-338C295.6892,-338 260.1566,-338 260.1566,-338 254.1566,-338 248.1566,-332 248.1566,-326 248.1566,-326 248.1566,-314 248.1566,-314 248.1566,-308 254.1566,-302 260.1566,-302 260.1566,-302 295.6892,-302 295.6892,-302 301.6892,-302 307.6892,-308 307.6892,-314 307.6892,-314 307.6892,-326 307.6892,-326 307.6892,-332 301.6892,-338 295.6892,-338"/>
<text text-anchor="middle" x="277.9229" y="-324.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="277.9229" y="-307.4" font-family="Verdana" font-size="14.00" fill="#000000">Warn</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Warn -->
<g id="edge17" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Warn</title>
<g id="a_edge17"><a xlink:title="at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]">
<path fill="none" stroke="#8b4513" d="M104.8687,-404.0539C117.3337,-398.6776 132.1266,-392.1648 145.3282,-386 177.0765,-371.1742 212.5944,-353.4318 238.8736,-340.0783"/>
<polygon fill="#8b4513" stroke="#8b4513" points="240.7921,-343.0291 248.1134,-335.3707 237.6143,-336.7919 240.7921,-343.0291"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge23" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge23"><a xlink:title="at multi.go:44: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:54: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:51: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M104.7719,-427.747C117.3517,-433.2441 132.2614,-440.0935 145.3282,-447 178.9682,-464.7807 215.7924,-487.5584 242.0789,-504.4284"/>
<polygon fill="#8b4513" stroke="#8b4513" points="240.2694,-507.4262 250.5697,-509.9073 244.0648,-501.5444 240.2694,-507.4262"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession -->
<g id="node8" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession</title>
<g id="a_node8"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession | defined in multi.go:74&#10;at multi.go:75: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:79: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:89: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:93: calling [(*github.com/go&#45;i2p/logger.Logger).Error]&#10;at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]&#10;at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]&#10;at multi.go:75: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:79: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:89: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:75: calling [(github.com/go&#45;i2p/common/router_info.RouterInfo).String]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M108.1529,-251C108.1529,-251 45.1753,-251 45.1753,-251 39.1753,-251 33.1753,-245 33.1753,-239 33.1753,-239 33.1753,-227 33.1753,-227 33.1753,-221 39.1753,-215 45.1753,-215 45.1753,-215 108.1529,-215 108.1529,-215 114.1529,-215 120.1529,-221 120.1529,-227 120.1529,-227 120.1529,-239 120.1529,-239 120.1529,-245 114.1529,-251 108.1529,-251"/>
<text text-anchor="middle" x="76.6641" y="-228.8" font-family="Verdana" font-size="14.00" fill="#000000">GetSession</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge15" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge15"><a xlink:title="at multi.go:75: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:79: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:89: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M120.3821,-230.8724C141.3723,-232.2116 165.3673,-237.5705 181.3282,-253 233.4216,-303.3593 172.5123,-355.0674 217.3282,-412 220.5581,-416.1031 224.4951,-419.6861 228.796,-422.8059"/>
<polygon fill="#8b4513" stroke="#8b4513" points="227.1,-425.8741 237.4252,-428.2493 230.8347,-419.9537 227.1,-425.8741"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="edge4" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_edge4"><a xlink:title="at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="none" stroke="#8b4513" d="M120.5012,-249.8156C129.0577,-253.9092 137.7251,-258.668 145.3282,-264 164.1132,-277.1736 166.5849,-283.42 181.3282,-301 198.924,-321.9813 196.4419,-333.2916 217.3282,-351 220.7446,-353.8966 224.4887,-356.5961 228.3869,-359.0931"/>
<polygon fill="#8b4513" stroke="#8b4513" points="226.7083,-362.1665 237.0996,-364.2335 230.2654,-356.1376 226.7083,-362.1665"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Error -->
<g id="edge3" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Error</title>
<g id="a_edge3"><a xlink:title="at multi.go:93: calling [(*github.com/go&#45;i2p/logger.Logger).Error]">
<path fill="none" stroke="#8b4513" d="M120.1864,-225.5178C129.3503,-222.2808 138.3448,-217.6435 145.3282,-211 177.4405,-180.4509 144.4802,-93.3694 181.3282,-118 216.1179,-141.2548 193.0955,-170.8842 217.3282,-205 224.9903,-215.787 235.1838,-225.9258 245.0208,-234.4406"/>
<polygon fill="#8b4513" stroke="#8b4513" points="242.8547,-237.1915 252.7784,-240.9026 247.3349,-231.813 242.8547,-237.1915"/>
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M295.6892,-277C295.6892,-277 260.1566,-277 260.1566,-277 254.1566,-277 248.1566,-271 248.1566,-265 248.1566,-265 248.1566,-253 248.1566,-253 248.1566,-247 254.1566,-241 260.1566,-241 260.1566,-241 295.6892,-241 295.6892,-241 301.6892,-241 307.6892,-247 307.6892,-253 307.6892,-253 307.6892,-265 307.6892,-265 307.6892,-271 301.6892,-277 295.6892,-277"/>
<text text-anchor="middle" x="277.9229" y="-263.2" font-family="Verdana" font-size="14.00" fill="#000000">logger</text>
<text text-anchor="middle" x="277.9229" y="-246.4" font-family="Verdana" font-size="14.00" fill="#000000">Warn</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Warn -->
<g id="edge5" class="edge">
<g id="edge20" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Warn</title>
<g id="a_edge5"><a xlink:title="at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]">
<path fill="none" stroke="#8b4513" d="M120.3019,-224.5924C129.2522,-221.4065 138.1273,-217.0239 145.3282,-211 170.9564,-189.5608 155.0084,-124.4157 181.3282,-145 233.6326,-185.9064 175.7195,-238.2525 217.3282,-290 222.9933,-297.0455 230.734,-302.567 238.7886,-306.8438"/>
<polygon fill="#8b4513" stroke="#8b4513" points="237.3853,-310.0517 247.9222,-311.1585 240.3753,-303.7224 237.3853,-310.0517"/>
<g id="a_edge20"><a xlink:title="at multi.go:83: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]">
<path fill="none" stroke="#8b4513" d="M120.3343,-217.5002C155.3277,-226.7155 204.0233,-239.5391 237.9897,-248.4839"/>
<polygon fill="#8b4513" stroke="#8b4513" points="237.4651,-251.965 248.0267,-251.1271 239.2477,-245.1958 237.4651,-251.965"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge1" class="edge">
<g id="edge19" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge1"><a xlink:title="at multi.go:75: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:79: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:89: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M120.4851,-246.3502C129.6351,-250.7808 138.5484,-256.5526 145.3282,-264 211.7491,-336.9614 162.7138,-391.8271 217.3282,-474 224.5905,-484.9269 234.5858,-495.0487 244.3654,-503.5056"/>
<polygon fill="#8b4513" stroke="#8b4513" points="242.1712,-506.2329 252.1058,-509.9145 246.6354,-500.8411 242.1712,-506.2329"/>
<g id="a_edge19"><a xlink:title="at multi.go:75: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:79: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:89: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M120.3235,-219.0039C129.5902,-223.4639 138.5948,-229.3357 145.3282,-237 181.6572,-278.3519 187.8874,-427.4918 217.3282,-474 224.4635,-485.2718 234.5166,-495.6742 244.3871,-504.3286"/>
<polygon fill="#8b4513" stroke="#8b4513" points="242.2915,-507.1389 252.2047,-510.8777 246.7867,-501.773 242.2915,-507.1389"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(github.com/go&#45;i2p/common/router_info.RouterInfo).String -->
<g id="edge18" class="edge">
<g id="edge12" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).GetSession&#45;&gt;(github.com/go&#45;i2p/common/router_info.RouterInfo).String</title>
<g id="a_edge18"><a xlink:title="at multi.go:75: calling [(github.com/go&#45;i2p/common/router_info.RouterInfo).String]">
<path fill="none" stroke="#8b4513" d="M120.2849,-225.6204C129.4443,-222.3786 138.412,-217.7134 145.3282,-211 178.8153,-178.4948 142.2235,-138.9445 180.3282,-112 199.8364,-98.2053 197.4326,-137.7701 217.3282,-151 219.8561,-152.681 222.5286,-154.2527 225.2867,-155.7195"/>
<polygon fill="#8b4513" stroke="#8b4513" points="223.7845,-158.8807 234.3144,-160.0521 226.8133,-152.5699 223.7845,-158.8807"/>
<g id="a_edge12"><a xlink:title="at multi.go:75: calling [(github.com/go&#45;i2p/common/router_info.RouterInfo).String]">
<path fill="none" stroke="#8b4513" d="M120.1864,-198.5178C129.3503,-195.2808 138.3448,-190.6435 145.3282,-184 177.3256,-153.5602 144.0142,-116.134 180.3282,-91 206.0891,-73.1701 193.152,-131.074 217.3282,-151 219.7545,-152.9998 222.378,-154.8256 225.1263,-156.4915"/>
<polygon fill="#8b4513" stroke="#8b4513" points="223.7597,-159.7273 234.2394,-161.2853 227.0186,-153.5321 223.7597,-159.7273"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name -->
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close -->
<g id="node9" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name</title>
<g id="a_node9"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name | defined in multi.go:59&#10;at multi.go:67: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:60: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:67: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M93.5921,-495C93.5921,-495 59.7361,-495 59.7361,-495 53.7361,-495 47.7361,-489 47.7361,-483 47.7361,-483 47.7361,-471 47.7361,-471 47.7361,-465 53.7361,-459 59.7361,-459 59.7361,-459 93.5921,-459 93.5921,-459 99.5921,-459 105.5921,-465 105.5921,-471 105.5921,-471 105.5921,-483 105.5921,-483 105.5921,-489 99.5921,-495 93.5921,-495"/>
<text text-anchor="middle" x="76.6641" y="-472.8" font-family="Verdana" font-size="14.00" fill="#000000">Name</text>
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close</title>
<g id="a_node9"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close | defined in multi.go:43&#10;at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]&#10;at multi.go:44: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:54: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:51: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M92.5506,-285C92.5506,-285 60.7776,-285 60.7776,-285 54.7776,-285 48.7776,-279 48.7776,-273 48.7776,-273 48.7776,-261 48.7776,-261 48.7776,-255 54.7776,-249 60.7776,-249 60.7776,-249 92.5506,-249 92.5506,-249 98.5506,-249 104.5506,-255 104.5506,-261 104.5506,-261 104.5506,-273 104.5506,-273 104.5506,-279 98.5506,-285 92.5506,-285"/>
<text text-anchor="middle" x="76.6641" y="-262.8" font-family="Verdana" font-size="14.00" fill="#000000">Close</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge6" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge6"><a xlink:title="at multi.go:67: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M105.4996,-471.9854C137.228,-466.4676 188.8257,-457.4945 227.322,-450.7998"/>
<polygon fill="#8b4513" stroke="#8b4513" points="228.0525,-454.2254 237.3049,-449.0637 226.8531,-447.3289 228.0525,-454.2254"/>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField -->
<g id="edge7" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithField</title>
<g id="a_edge7"><a xlink:title="at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]&#10;at multi.go:51: calling [(*github.com/go&#45;i2p/logger.Logger).WithField]">
<path fill="none" stroke="#8b4513" d="M104.8586,-275.4837C118.1837,-280.4947 133.6822,-287.8723 145.3282,-298 190.5472,-337.3237 172.817,-371.8769 217.3282,-412 220.8485,-415.1733 224.7657,-418.0919 228.8669,-420.7571"/>
<polygon fill="#8b4513" stroke="#8b4513" points="227.0909,-423.773 237.4756,-425.8726 230.6668,-417.7553 227.0909,-423.773"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge16" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Name&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge16"><a xlink:title="at multi.go:60: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:67: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M105.4996,-484.3071C140.0952,-493.0738 198.3132,-507.8265 237.413,-517.7346"/>
<polygon fill="#8b4513" stroke="#8b4513" points="236.6075,-521.141 247.1609,-520.2048 238.3271,-514.3555 236.6075,-521.141"/>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError -->
<g id="edge15" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).WithError</title>
<g id="a_edge15"><a xlink:title="at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).WithError]">
<path fill="none" stroke="#8b4513" d="M104.7267,-278.0833C117.4341,-283.5001 132.4581,-290.471 145.3282,-298 179.6255,-318.0639 183.3938,-330.3283 217.3282,-351 221.3758,-353.4657 225.6539,-355.8998 229.9891,-358.251"/>
<polygon fill="#8b4513" stroke="#8b4513" points="228.4326,-361.3869 238.9124,-362.9443 231.6912,-355.1916 228.4326,-361.3869"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Warn -->
<g id="edge8" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/go&#45;i2p/logger.Logger).Warn</title>
<g id="a_edge8"><a xlink:title="at multi.go:49: calling [(*github.com/go&#45;i2p/logger.Logger).Warn]">
<path fill="none" stroke="#8b4513" d="M104.8465,-257.6689C125.7738,-251.7086 155.1089,-245.3776 181.3282,-247 199.9051,-248.1495 220.3772,-250.5311 237.6749,-252.8719"/>
<polygon fill="#8b4513" stroke="#8b4513" points="237.6016,-256.3956 247.9897,-254.3127 238.5701,-249.4629 237.6016,-256.3956"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug -->
<g id="edge14" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/transport.TransportMuxer).Close&#45;&gt;(*github.com/sirupsen/logrus.Logger).Debug</title>
<g id="a_edge14"><a xlink:title="at multi.go:44: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:54: calling [(*github.com/sirupsen/logrus.Logger).Debug]&#10;at multi.go:51: calling [(*github.com/sirupsen/logrus.Logger).Debug]">
<path fill="none" stroke="#8b4513" d="M104.7917,-273.2978C118.9355,-277.8704 135.1829,-285.5145 145.3282,-298 190.6856,-353.8197 141.3164,-395.5747 180.3282,-456 194.6242,-478.1431 218.115,-496.0211 238.4675,-508.5419"/>
<polygon fill="#8b4513" stroke="#8b4513" points="236.8686,-511.6627 247.2568,-513.745 240.4345,-505.639 236.8686,-511.6627"/>
</a>
</g>
</g>

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -36,6 +36,18 @@ const (
)
```
#### type BuildResponse
```go
type BuildResponse struct {
HopIndex int // Index of the hop that responded
Success bool // Whether the hop accepted the tunnel
Reply []byte // Raw response data
}
```
BuildResponse represents a response from a tunnel hop
#### type DecryptedTunnelMessage
```go
@@ -246,13 +258,82 @@ type Participant struct {
```
#### type PeerSelector
```go
type PeerSelector interface {
SelectPeers(count int, exclude []common.Hash) ([]router_info.RouterInfo, error)
}
```
PeerSelector defines interface for selecting peers for tunnel building
#### type Pool
```go
type Pool struct{}
type Pool struct {
}
```
a pool of tunnels which we have created
Pool manages a collection of tunnels
#### func NewTunnelPool
```go
func NewTunnelPool(selector PeerSelector) *Pool
```
NewTunnelPool creates a new tunnel pool with the given peer selector
#### func (*Pool) AddTunnel
```go
func (p *Pool) AddTunnel(tunnel *TunnelState)
```
AddTunnel adds a new tunnel to the pool
#### func (*Pool) CleanupExpiredTunnels
```go
func (p *Pool) CleanupExpiredTunnels(maxAge time.Duration)
```
CleanupExpiredTunnels removes tunnels that have been building for too long
#### func (*Pool) GetActiveTunnels
```go
func (p *Pool) GetActiveTunnels() []*TunnelState
```
GetActiveTunnels returns all active tunnels
#### func (*Pool) GetTunnel
```go
func (p *Pool) GetTunnel(id TunnelID) (*TunnelState, bool)
```
GetTunnel retrieves a tunnel by ID
#### func (*Pool) RemoveTunnel
```go
func (p *Pool) RemoveTunnel(id TunnelID)
```
RemoveTunnel removes a tunnel from the pool
#### type TunnelBuildState
```go
type TunnelBuildState int
```
TunnelBuildState represents different states during tunnel building
```go
const (
TunnelBuilding TunnelBuildState = iota // Tunnel is being built
TunnelReady // Tunnel is ready for use
TunnelFailed // Tunnel build failed
)
```
#### type TunnelID
@@ -261,6 +342,22 @@ type TunnelID uint32
```
#### type TunnelState
```go
type TunnelState struct {
ID TunnelID
Hops []common.Hash // Router hashes for each hop
State TunnelBuildState // Current build state
CreatedAt time.Time // When tunnel building started
ResponseCount int // Number of responses received
Responses []BuildResponse // Responses from each hop
}
```
TunnelState represents the current state of a tunnel during building
tunnel

View File

@@ -4,13 +4,10 @@ import (
"encoding/binary"
common "github.com/go-i2p/common/data"
"github.com/go-i2p/logger"
"github.com/samber/oops"
"github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
/*
I2P First Fragment Delivery Instructions
https://geti2p.net/spec/tunnel-message#struct-tunnelmessagedeliveryinstructions
@@ -172,7 +169,7 @@ func (delivery_instructions DeliveryInstructions) Type() (int, error) {
follow-on fragment initial I2NP message
fragment or a complete fragment
*/
if (delivery_instructions[0] & 0x08) == 0x08 {
if (delivery_instructions[0] & 0x80) == 0x80 {
log.Debug("DeliveryInstructions type: FOLLOW_ON_FRAGMENT")
return FOLLOW_ON_FRAGMENT, nil
}

5
lib/tunnel/log.go Normal file
View File

@@ -0,0 +1,5 @@
package tunnel
import "github.com/go-i2p/logger"
var log = logger.GetGoI2PLogger()

View File

@@ -1,4 +1,117 @@
package tunnel
// a pool of tunnels which we have created
type Pool struct{}
import (
"sync"
"time"
common "github.com/go-i2p/common/data"
"github.com/go-i2p/common/router_info"
)
// TunnelState represents the current state of a tunnel during building
type TunnelState struct {
ID TunnelID
Hops []common.Hash // Router hashes for each hop
State TunnelBuildState // Current build state
CreatedAt time.Time // When tunnel building started
ResponseCount int // Number of responses received
Responses []BuildResponse // Responses from each hop
}
// TunnelBuildState represents different states during tunnel building
type TunnelBuildState int
const (
TunnelBuilding TunnelBuildState = iota // Tunnel is being built
TunnelReady // Tunnel is ready for use
TunnelFailed // Tunnel build failed
)
// BuildResponse represents a response from a tunnel hop
type BuildResponse struct {
HopIndex int // Index of the hop that responded
Success bool // Whether the hop accepted the tunnel
Reply []byte // Raw response data
}
// PeerSelector defines interface for selecting peers for tunnel building
type PeerSelector interface {
SelectPeers(count int, exclude []common.Hash) ([]router_info.RouterInfo, error)
}
// Pool manages a collection of tunnels
type Pool struct {
tunnels map[TunnelID]*TunnelState
mutex sync.RWMutex
peerSelector PeerSelector
}
// NewTunnelPool creates a new tunnel pool with the given peer selector
func NewTunnelPool(selector PeerSelector) *Pool {
return &Pool{
tunnels: make(map[TunnelID]*TunnelState),
peerSelector: selector,
}
}
// GetTunnel retrieves a tunnel by ID
func (p *Pool) GetTunnel(id TunnelID) (*TunnelState, bool) {
p.mutex.RLock()
defer p.mutex.RUnlock()
tunnel, exists := p.tunnels[id]
return tunnel, exists
}
// AddTunnel adds a new tunnel to the pool
func (p *Pool) AddTunnel(tunnel *TunnelState) {
p.mutex.Lock()
defer p.mutex.Unlock()
p.tunnels[tunnel.ID] = tunnel
log.WithField("tunnel_id", tunnel.ID).Debug("Added tunnel to pool")
}
// RemoveTunnel removes a tunnel from the pool
func (p *Pool) RemoveTunnel(id TunnelID) {
p.mutex.Lock()
defer p.mutex.Unlock()
delete(p.tunnels, id)
log.WithField("tunnel_id", id).Debug("Removed tunnel from pool")
}
// GetActiveTunnels returns all active tunnels
func (p *Pool) GetActiveTunnels() []*TunnelState {
p.mutex.RLock()
defer p.mutex.RUnlock()
var active []*TunnelState
for _, tunnel := range p.tunnels {
if tunnel.State == TunnelReady {
active = append(active, tunnel)
}
}
log.WithField("active_count", len(active)).Debug("Retrieved active tunnels")
return active
}
// CleanupExpiredTunnels removes tunnels that have been building for too long
func (p *Pool) CleanupExpiredTunnels(maxAge time.Duration) {
p.mutex.Lock()
defer p.mutex.Unlock()
now := time.Now()
var expired []TunnelID
for id, tunnel := range p.tunnels {
if tunnel.State == TunnelBuilding && now.Sub(tunnel.CreatedAt) > maxAge {
expired = append(expired, id)
}
}
for _, id := range expired {
delete(p.tunnels, id)
}
if len(expired) > 0 {
log.WithField("expired_count", len(expired)).Warn("Cleaned up expired tunnels")
}
}

106
lib/tunnel/pool_test.go Normal file
View File

@@ -0,0 +1,106 @@
package tunnel
import (
"testing"
"time"
common "github.com/go-i2p/common/data"
"github.com/go-i2p/common/router_info"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// MockPeerSelector for testing
type MockPeerSelector struct {
peers []router_info.RouterInfo
}
func (m *MockPeerSelector) SelectPeers(count int, exclude []common.Hash) ([]router_info.RouterInfo, error) {
if len(m.peers) < count {
return m.peers, nil
}
return m.peers[:count], nil
}
func TestTunnelPool(t *testing.T) {
selector := &MockPeerSelector{}
pool := NewTunnelPool(selector)
require.NotNil(t, pool)
assert.Empty(t, pool.GetActiveTunnels())
}
func TestTunnelState(t *testing.T) {
tunnelID := TunnelID(12345)
state := &TunnelState{
ID: tunnelID,
Hops: []common.Hash{},
State: TunnelBuilding,
CreatedAt: time.Now(),
}
assert.Equal(t, tunnelID, state.ID)
assert.Equal(t, TunnelBuilding, state.State)
assert.Empty(t, state.Hops)
}
func TestTunnelPoolOperations(t *testing.T) {
selector := &MockPeerSelector{}
pool := NewTunnelPool(selector)
// Test adding a tunnel
tunnel := &TunnelState{
ID: TunnelID(123),
State: TunnelBuilding,
CreatedAt: time.Now(),
}
pool.AddTunnel(tunnel)
// Test retrieving tunnel
retrieved, exists := pool.GetTunnel(TunnelID(123))
assert.True(t, exists)
assert.Equal(t, tunnel.ID, retrieved.ID)
// Test tunnel doesn't exist
_, exists = pool.GetTunnel(TunnelID(999))
assert.False(t, exists)
// Test removing tunnel
pool.RemoveTunnel(TunnelID(123))
_, exists = pool.GetTunnel(TunnelID(123))
assert.False(t, exists)
}
func TestTunnelCleanup(t *testing.T) {
selector := &MockPeerSelector{}
pool := NewTunnelPool(selector)
// Add an old tunnel
oldTunnel := &TunnelState{
ID: TunnelID(1),
State: TunnelBuilding,
CreatedAt: time.Now().Add(-10 * time.Minute),
}
// Add a recent tunnel
recentTunnel := &TunnelState{
ID: TunnelID(2),
State: TunnelBuilding,
CreatedAt: time.Now(),
}
pool.AddTunnel(oldTunnel)
pool.AddTunnel(recentTunnel)
// Cleanup tunnels older than 5 minutes
pool.CleanupExpiredTunnels(5 * time.Minute)
// Old tunnel should be gone, recent one should remain
_, exists := pool.GetTunnel(TunnelID(1))
assert.False(t, exists)
_, exists = pool.GetTunnel(TunnelID(2))
assert.True(t, exists)
}

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 239 KiB

After

Width:  |  Height:  |  Size: 252 KiB

View File

@@ -14,75 +14,75 @@
<polygon fill="#e6ecfa" stroke="#000000" stroke-width=".5" points="8,-8 8,-212 284.9384,-212 284.9384,-8 8,-8"/>
<text text-anchor="middle" x="146.4692" y="-191.8" font-family="Arial" font-size="18.00" fill="#000000">signals</text>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init -->
<g id="node1" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init</title>
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init | defined in .:0&#10;at .:0: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M63.2132,-174C63.2132,-174 33.2132,-174 33.2132,-174 27.2132,-174 21.2132,-168 21.2132,-162 21.2132,-162 21.2132,-150 21.2132,-150 21.2132,-144 27.2132,-138 33.2132,-138 33.2132,-138 63.2132,-138 63.2132,-138 69.2132,-138 75.2132,-144 75.2132,-150 75.2132,-150 75.2132,-162 75.2132,-162 75.2132,-168 69.2132,-174 63.2132,-174"/>
<text text-anchor="middle" x="48.2132" y="-151.8" font-family="Verdana" font-size="14.00" fill="#000000">init</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1 -->
<g id="node2" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1</title>
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1 | defined in unix.go:11">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M231.3551,-174C231.3551,-174 199.0097,-174 199.0097,-174 193.0097,-174 187.0097,-168 187.0097,-162 187.0097,-162 187.0097,-150 187.0097,-150 187.0097,-144 193.0097,-138 199.0097,-138 199.0097,-138 231.3551,-138 231.3551,-138 237.3551,-138 243.3551,-144 243.3551,-150 243.3551,-150 243.3551,-162 243.3551,-162 243.3551,-168 237.3551,-174 231.3551,-174"/>
<text text-anchor="middle" x="215.1824" y="-151.8" font-family="Verdana" font-size="14.00" fill="#000000">init#1</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1 -->
<g id="edge1" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1</title>
<g id="a_edge1"><a xlink:title="at .:0: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1]">
<path fill="none" stroke="#000000" d="M75.4113,-156C102.9748,-156 145.8607,-156 176.8609,-156"/>
<polygon fill="#000000" stroke="#000000" points="176.8791,-159.5001 186.879,-156 176.879,-152.5001 176.8791,-159.5001"/>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.Handle -->
<g id="node3" class="node">
<g id="node1" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.Handle</title>
<g id="a_node3"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.Handle | defined in unix.go:15&#10;at unix.go:23: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload]&#10;at unix.go:25: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M68.641,-83C68.641,-83 27.7854,-83 27.7854,-83 21.7854,-83 15.7854,-77 15.7854,-71 15.7854,-71 15.7854,-59 15.7854,-59 15.7854,-53 21.7854,-47 27.7854,-47 27.7854,-47 68.641,-47 68.641,-47 74.641,-47 80.641,-53 80.641,-59 80.641,-59 80.641,-71 80.641,-71 80.641,-77 74.641,-83 68.641,-83"/>
<text text-anchor="middle" x="48.2132" y="-60.8" font-family="Verdana" font-size="14.00" fill="#000000">Handle</text>
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.Handle | defined in unix.go:15&#10;at unix.go:23: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload]&#10;at unix.go:25: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M68.641,-143C68.641,-143 27.7854,-143 27.7854,-143 21.7854,-143 15.7854,-137 15.7854,-131 15.7854,-131 15.7854,-119 15.7854,-119 15.7854,-113 21.7854,-107 27.7854,-107 27.7854,-107 68.641,-107 68.641,-107 74.641,-107 80.641,-113 80.641,-119 80.641,-119 80.641,-131 80.641,-131 80.641,-137 74.641,-143 68.641,-143"/>
<text text-anchor="middle" x="48.2132" y="-120.8" font-family="Verdana" font-size="14.00" fill="#000000">Handle</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload -->
<g id="node4" class="node">
<g id="node2" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload</title>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload | defined in signals.go:17">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M253.6586,-52C253.6586,-52 176.7062,-52 176.7062,-52 170.7062,-52 164.7062,-46 164.7062,-40 164.7062,-40 164.7062,-28 164.7062,-28 164.7062,-22 170.7062,-16 176.7062,-16 176.7062,-16 253.6586,-16 253.6586,-16 259.6586,-16 265.6586,-22 265.6586,-28 265.6586,-28 265.6586,-40 265.6586,-40 265.6586,-46 259.6586,-52 253.6586,-52"/>
<text text-anchor="middle" x="215.1824" y="-29.8" font-family="Verdana" font-size="14.00" fill="#000000">handleReload</text>
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload | defined in signals.go:17">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M253.6586,-113C253.6586,-113 176.7062,-113 176.7062,-113 170.7062,-113 164.7062,-107 164.7062,-101 164.7062,-101 164.7062,-89 164.7062,-89 164.7062,-83 170.7062,-77 176.7062,-77 176.7062,-77 253.6586,-77 253.6586,-77 259.6586,-77 265.6586,-83 265.6586,-89 265.6586,-89 265.6586,-101 265.6586,-101 265.6586,-107 259.6586,-113 253.6586,-113"/>
<text text-anchor="middle" x="215.1824" y="-90.8" font-family="Verdana" font-size="14.00" fill="#000000">handleReload</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.Handle&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload -->
<g id="edge2" class="edge">
<g id="edge1" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.Handle&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload</title>
<g id="a_edge2"><a xlink:title="at unix.go:23: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload]">
<path fill="none" stroke="#000000" d="M80.8029,-58.9493C101.7394,-55.0622 129.5814,-49.8929 154.4915,-45.2681"/>
<polygon fill="#000000" stroke="#000000" points="155.4019,-48.6589 164.5949,-43.3922 154.124,-41.7765 155.4019,-48.6589"/>
<g id="a_edge1"><a xlink:title="at unix.go:23: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleReload]">
<path fill="none" stroke="#000000" d="M80.8029,-119.1445C101.7394,-115.3827 129.5814,-110.3803 154.4915,-105.9046"/>
<polygon fill="#000000" stroke="#000000" points="155.3715,-109.3026 164.5949,-104.0892 154.1336,-102.4129 155.3715,-109.3026"/>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted -->
<g id="node5" class="node">
<g id="node3" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted</title>
<g id="a_node5"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted | defined in signals.go:29">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M264.6954,-113C264.6954,-113 165.6694,-113 165.6694,-113 159.6694,-113 153.6694,-107 153.6694,-101 153.6694,-101 153.6694,-89 153.6694,-89 153.6694,-83 159.6694,-77 165.6694,-77 165.6694,-77 264.6954,-77 264.6954,-77 270.6954,-77 276.6954,-83 276.6954,-89 276.6954,-89 276.6954,-101 276.6954,-101 276.6954,-107 270.6954,-113 264.6954,-113"/>
<text text-anchor="middle" x="215.1824" y="-90.8" font-family="Verdana" font-size="14.00" fill="#000000">handleInterrupted</text>
<g id="a_node3"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted | defined in signals.go:29">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M264.6954,-174C264.6954,-174 165.6694,-174 165.6694,-174 159.6694,-174 153.6694,-168 153.6694,-162 153.6694,-162 153.6694,-150 153.6694,-150 153.6694,-144 159.6694,-138 165.6694,-138 165.6694,-138 264.6954,-138 264.6954,-138 270.6954,-138 276.6954,-144 276.6954,-150 276.6954,-150 276.6954,-162 276.6954,-162 276.6954,-168 270.6954,-174 264.6954,-174"/>
<text text-anchor="middle" x="215.1824" y="-151.8" font-family="Verdana" font-size="14.00" fill="#000000">handleInterrupted</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.Handle&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted -->
<g id="edge3" class="edge">
<g id="edge2" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.Handle&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted</title>
<g id="a_edge3"><a xlink:title="at unix.go:25: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted]">
<path fill="none" stroke="#000000" d="M80.8029,-70.8555C98.7443,-74.0791 121.7569,-78.2139 143.6498,-82.1475"/>
<polygon fill="#000000" stroke="#000000" points="143.1463,-85.613 153.6077,-83.9366 144.3842,-78.7233 143.1463,-85.613"/>
<g id="a_edge2"><a xlink:title="at unix.go:25: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.handleInterrupted]">
<path fill="none" stroke="#000000" d="M80.8029,-131.0507C98.7443,-134.3818 121.7569,-138.6543 143.6498,-142.719"/>
<polygon fill="#000000" stroke="#000000" points="143.1368,-146.1835 153.6077,-144.5679 144.4146,-139.3011 143.1368,-146.1835"/>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init -->
<g id="node4" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init</title>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init | defined in .:0&#10;at .:0: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M63.2132,-52C63.2132,-52 33.2132,-52 33.2132,-52 27.2132,-52 21.2132,-46 21.2132,-40 21.2132,-40 21.2132,-28 21.2132,-28 21.2132,-22 27.2132,-16 33.2132,-16 33.2132,-16 63.2132,-16 63.2132,-16 69.2132,-16 75.2132,-22 75.2132,-28 75.2132,-28 75.2132,-40 75.2132,-40 75.2132,-46 69.2132,-52 63.2132,-52"/>
<text text-anchor="middle" x="48.2132" y="-29.8" font-family="Verdana" font-size="14.00" fill="#000000">init</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1 -->
<g id="node5" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1</title>
<g id="a_node5"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1 | defined in unix.go:11">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M231.3551,-52C231.3551,-52 199.0097,-52 199.0097,-52 193.0097,-52 187.0097,-46 187.0097,-40 187.0097,-40 187.0097,-28 187.0097,-28 187.0097,-22 193.0097,-16 199.0097,-16 199.0097,-16 231.3551,-16 231.3551,-16 237.3551,-16 243.3551,-22 243.3551,-28 243.3551,-28 243.3551,-40 243.3551,-40 243.3551,-46 237.3551,-52 231.3551,-52"/>
<text text-anchor="middle" x="215.1824" y="-29.8" font-family="Verdana" font-size="14.00" fill="#000000">init#1</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1 -->
<g id="edge3" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1</title>
<g id="a_edge3"><a xlink:title="at .:0: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/signals.init#1]">
<path fill="none" stroke="#000000" d="M75.4113,-34C102.9748,-34 145.8607,-34 176.8609,-34"/>
<polygon fill="#000000" stroke="#000000" points="176.8791,-37.5001 186.879,-34 176.879,-30.5001 176.8791,-37.5001"/>
</a>
</g>
</g>

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -2,12 +2,13 @@ package sntp
import (
"fmt"
"math/rand"
"net"
"strings"
"sync"
"time"
"github.com/go-i2p/crypto/rand"
"github.com/beevik/ntp"
)
@@ -37,6 +38,7 @@ type RouterTimestamper struct {
stopChan chan struct{}
waitGroup sync.WaitGroup
ntpClient NTPClient
timeOffset time.Duration // Store the current time offset from system time
}
const (
@@ -340,6 +342,10 @@ func (rt *RouterTimestamper) queryTime(servers []string, timeout time.Duration,
func (rt *RouterTimestamper) stampTime(now time.Time) {
rt.mutex.Lock()
defer rt.mutex.Unlock()
// Store the time offset for GetCurrentTime
rt.timeOffset = now.Sub(time.Now())
for _, listener := range rt.listeners {
listener.SetNow(now, 0)
}
@@ -423,16 +429,12 @@ func (rt *RouterTimestamper) GetCurrentTime() time.Time {
time.Sleep(100 * time.Millisecond)
}
// Return current time based on latest offset
// Return current time based on stored offset
rt.mutex.Lock()
defer rt.mutex.Unlock()
if len(rt.listeners) > 0 {
// Use first listener's time if available
var t time.Time
rt.listeners[0].SetNow(t, 0) // Get current time from listener
return t
}
return time.Now() // Fallback to system time
// Return system time adjusted by the stored time offset
return time.Now().Add(rt.timeOffset)
}
// GetServers returns a copy of the current server list safely

View File

@@ -4,15 +4,15 @@
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: gocallvis Pages: 1 -->
<svg width="1420pt" height="548pt"
viewBox="0.00 0.00 1420.13 548.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(0 548)">
<svg width="1420pt" height="628pt"
viewBox="0.00 0.00 1420.13 628.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(0 628)">
<title>gocallvis</title>
<polygon fill="#d3d3d3" stroke="transparent" points="0,0 0,-548 1420.1336,-548 1420.1336,0 0,0"/>
<polygon fill="#d3d3d3" stroke="transparent" points="0,0 0,-628 1420.1336,-628 1420.1336,0 0,0"/>
<g id="clust1" class="cluster">
<title>cluster_focus</title>
<polygon fill="#e6ecfa" stroke="#000000" stroke-width=".5" points="8,-8 8,-540 1412.1336,-540 1412.1336,-8 8,-8"/>
<text text-anchor="middle" x="710.0668" y="-519.8" font-family="Arial" font-size="18.00" fill="#000000">sntp</text>
<polygon fill="#e6ecfa" stroke="#000000" stroke-width=".5" points="8,-8 8,-620 1412.1336,-620 1412.1336,-8 8,-8"/>
<text text-anchor="middle" x="710.0668" y="-599.8" font-family="Arial" font-size="18.00" fill="#000000">sntp</text>
</g>
<g id="clust4" class="cluster">
<title>cluster_*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones</title>
@@ -25,379 +25,436 @@
<g id="clust3" class="cluster">
<title>cluster_*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper</title>
<g id="a_clust3"><a xlink:title="type: *github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper">
<path fill="#b0c4de" stroke="#000000" stroke-width=".5" d="M32.6697,-216C32.6697,-216 1163.3285,-216 1163.3285,-216 1169.3285,-216 1175.3285,-222 1175.3285,-228 1175.3285,-228 1175.3285,-404 1175.3285,-404 1175.3285,-410 1169.3285,-416 1163.3285,-416 1163.3285,-416 32.6697,-416 32.6697,-416 26.6697,-416 20.6697,-410 20.6697,-404 20.6697,-404 20.6697,-228 20.6697,-228 20.6697,-222 26.6697,-216 32.6697,-216"/>
<text text-anchor="middle" x="597.9991" y="-224.5" font-family="Arial" font-size="15.00" fill="#222222">(*RouterTimestamper)</text>
<path fill="#b0c4de" stroke="#000000" stroke-width=".5" d="M32.6697,-277C32.6697,-277 1163.3285,-277 1163.3285,-277 1169.3285,-277 1175.3285,-283 1175.3285,-289 1175.3285,-289 1175.3285,-465 1175.3285,-465 1175.3285,-471 1169.3285,-477 1163.3285,-477 1163.3285,-477 32.6697,-477 32.6697,-477 26.6697,-477 20.6697,-471 20.6697,-465 20.6697,-465 20.6697,-289 20.6697,-289 20.6697,-283 26.6697,-277 32.6697,-277"/>
<text text-anchor="middle" x="597.9991" y="-285.5" font-family="Arial" font-size="15.00" fill="#222222">(*RouterTimestamper)</text>
</a>
</g>
</g>
<g id="clust2" class="cluster">
<title>cluster_*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.DefaultNTPClient</title>
<g id="a_clust2"><a xlink:title="type: *github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.DefaultNTPClient">
<path fill="#b0c4de" stroke="#000000" stroke-width=".5" d="M28,-424C28,-424 151.31,-424 151.31,-424 157.31,-424 163.31,-430 163.31,-436 163.31,-436 163.31,-490 163.31,-490 163.31,-496 157.31,-502 151.31,-502 151.31,-502 28,-502 28,-502 22,-502 16,-496 16,-490 16,-490 16,-436 16,-436 16,-430 22,-424 28,-424"/>
<text text-anchor="middle" x="89.655" y="-432.5" font-family="Arial" font-size="15.00" fill="#222222">(*DefaultNTPClient)</text>
<path fill="#b0c4de" stroke="#000000" stroke-width=".5" d="M28,-504C28,-504 151.31,-504 151.31,-504 157.31,-504 163.31,-510 163.31,-516 163.31,-516 163.31,-570 163.31,-570 163.31,-576 157.31,-582 151.31,-582 151.31,-582 28,-582 28,-582 22,-582 16,-576 16,-570 16,-570 16,-516 16,-516 16,-510 22,-504 28,-504"/>
<text text-anchor="middle" x="89.655" y="-512.5" font-family="Arial" font-size="15.00" fill="#222222">(*DefaultNTPClient)</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode -->
<g id="node1" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode</title>
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode | defined in router_timestamper.go:414">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M1186.2513,-460C1186.2513,-460 1061.4169,-460 1061.4169,-460 1055.4169,-460 1049.4169,-454 1049.4169,-448 1049.4169,-448 1049.4169,-436 1049.4169,-436 1049.4169,-430 1055.4169,-424 1061.4169,-424 1061.4169,-424 1186.2513,-424 1186.2513,-424 1192.2513,-424 1198.2513,-430 1198.2513,-436 1198.2513,-436 1198.2513,-448 1198.2513,-448 1198.2513,-454 1192.2513,-460 1186.2513,-460"/>
<text text-anchor="middle" x="1123.8341" y="-437.8" font-family="Verdana" font-size="14.00" fill="#000000">getLocalCountryCode</text>
<g id="a_node1"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode | defined in router_timestamper.go:420">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M1186.2513,-521C1186.2513,-521 1061.4169,-521 1061.4169,-521 1055.4169,-521 1049.4169,-515 1049.4169,-509 1049.4169,-509 1049.4169,-497 1049.4169,-497 1049.4169,-491 1055.4169,-485 1061.4169,-485 1061.4169,-485 1186.2513,-485 1186.2513,-485 1192.2513,-485 1198.2513,-491 1198.2513,-497 1198.2513,-497 1198.2513,-509 1198.2513,-509 1198.2513,-515 1192.2513,-521 1186.2513,-521"/>
<text text-anchor="middle" x="1123.8341" y="-498.8" font-family="Verdana" font-size="14.00" fill="#000000">getLocalCountryCode</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity -->
<g id="node2" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity</title>
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity | defined in router_timestamper.go:392">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M964.834,-469C964.834,-469 833.0024,-469 833.0024,-469 827.0024,-469 821.0024,-463 821.0024,-457 821.0024,-457 821.0024,-445 821.0024,-445 821.0024,-439 827.0024,-433 833.0024,-433 833.0024,-433 964.834,-433 964.834,-433 970.834,-433 976.834,-439 976.834,-445 976.834,-445 976.834,-457 976.834,-457 976.834,-463 970.834,-469 964.834,-469"/>
<text text-anchor="middle" x="898.9182" y="-446.8" font-family="Verdana" font-size="14.00" fill="#000000">checkIPv6Connectivity</text>
<g id="a_node2"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity | defined in router_timestamper.go:398">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M964.834,-530C964.834,-530 833.0024,-530 833.0024,-530 827.0024,-530 821.0024,-524 821.0024,-518 821.0024,-518 821.0024,-506 821.0024,-506 821.0024,-500 827.0024,-494 833.0024,-494 833.0024,-494 964.834,-494 964.834,-494 970.834,-494 976.834,-500 976.834,-506 976.834,-506 976.834,-518 976.834,-518 976.834,-524 970.834,-530 964.834,-530"/>
<text text-anchor="middle" x="898.9182" y="-507.8" font-family="Verdana" font-size="14.00" fill="#000000">checkIPv6Connectivity</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/crypto/rand.Intn -->
<g id="node3" class="node">
<title>github.com/go&#45;i2p/crypto/rand.Intn</title>
<g id="a_node3"><a xlink:title="github.com/go&#45;i2p/crypto/rand.Intn | defined in prng.go:337">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M1138.8341,-269C1138.8341,-269 1108.8341,-269 1108.8341,-269 1102.8341,-269 1096.8341,-263 1096.8341,-257 1096.8341,-257 1096.8341,-245 1096.8341,-245 1096.8341,-239 1102.8341,-233 1108.8341,-233 1108.8341,-233 1138.8341,-233 1138.8341,-233 1144.8341,-233 1150.8341,-239 1150.8341,-245 1150.8341,-245 1150.8341,-257 1150.8341,-257 1150.8341,-263 1144.8341,-269 1138.8341,-269"/>
<text text-anchor="middle" x="1123.8341" y="-255.2" font-family="Verdana" font-size="14.00" fill="#000000">rand</text>
<text text-anchor="middle" x="1123.8341" y="-238.4" font-family="Verdana" font-size="14.00" fill="#000000">Intn</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration -->
<g id="node3" class="node">
<g id="node4" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration</title>
<g id="a_node3"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration | defined in router_timestamper.go:407">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M1158.2573,-208C1158.2573,-208 1089.4109,-208 1089.4109,-208 1083.4109,-208 1077.4109,-202 1077.4109,-196 1077.4109,-196 1077.4109,-184 1077.4109,-184 1077.4109,-178 1083.4109,-172 1089.4109,-172 1089.4109,-172 1158.2573,-172 1158.2573,-172 1164.2573,-172 1170.2573,-178 1170.2573,-184 1170.2573,-184 1170.2573,-196 1170.2573,-196 1170.2573,-202 1164.2573,-208 1158.2573,-208"/>
<text text-anchor="middle" x="1123.8341" y="-185.8" font-family="Verdana" font-size="14.00" fill="#000000">absDuration</text>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration | defined in router_timestamper.go:413">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M1158.2573,-582C1158.2573,-582 1089.4109,-582 1089.4109,-582 1083.4109,-582 1077.4109,-576 1077.4109,-570 1077.4109,-570 1077.4109,-558 1077.4109,-558 1077.4109,-552 1083.4109,-546 1089.4109,-546 1089.4109,-546 1158.2573,-546 1158.2573,-546 1164.2573,-546 1170.2573,-552 1170.2573,-558 1170.2573,-558 1170.2573,-570 1170.2573,-570 1170.2573,-576 1164.2573,-582 1158.2573,-582"/>
<text text-anchor="middle" x="1123.8341" y="-559.8" font-family="Verdana" font-size="14.00" fill="#000000">absDuration</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/crypto/rand.Float64 -->
<g id="node5" class="node">
<title>github.com/go&#45;i2p/crypto/rand.Float64</title>
<g id="a_node5"><a xlink:title="github.com/go&#45;i2p/crypto/rand.Float64 | defined in prng.go:342">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M1145.1129,-208C1145.1129,-208 1102.5553,-208 1102.5553,-208 1096.5553,-208 1090.5553,-202 1090.5553,-196 1090.5553,-196 1090.5553,-184 1090.5553,-184 1090.5553,-178 1096.5553,-172 1102.5553,-172 1102.5553,-172 1145.1129,-172 1145.1129,-172 1151.1129,-172 1157.1129,-178 1157.1129,-184 1157.1129,-184 1157.1129,-196 1157.1129,-196 1157.1129,-202 1151.1129,-208 1145.1129,-208"/>
<text text-anchor="middle" x="1123.8341" y="-194.2" font-family="Verdana" font-size="14.00" fill="#000000">rand</text>
<text text-anchor="middle" x="1123.8341" y="-177.4" font-family="Verdana" font-size="14.00" fill="#000000">Float64</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones -->
<g id="node4" class="node">
<g id="node6" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones</title>
<g id="a_node4"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones | defined in zones.go:19&#10;at zones.go:24: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M929.0586,-121C929.0586,-121 868.7778,-121 868.7778,-121 862.7778,-121 856.7778,-115 856.7778,-109 856.7778,-109 856.7778,-97 856.7778,-97 856.7778,-91 862.7778,-85 868.7778,-85 868.7778,-85 929.0586,-85 929.0586,-85 935.0586,-85 941.0586,-91 941.0586,-97 941.0586,-97 941.0586,-109 941.0586,-109 941.0586,-115 935.0586,-121 929.0586,-121"/>
<text text-anchor="middle" x="898.9182" y="-98.8" font-family="Verdana" font-size="14.00" fill="#000000">NewZones</text>
<g id="a_node6"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones | defined in zones.go:19&#10;at zones.go:24: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M929.0586,-166C929.0586,-166 868.7778,-166 868.7778,-166 862.7778,-166 856.7778,-160 856.7778,-154 856.7778,-154 856.7778,-142 856.7778,-142 856.7778,-136 862.7778,-130 868.7778,-130 868.7778,-130 929.0586,-130 929.0586,-130 935.0586,-130 941.0586,-136 941.0586,-142 941.0586,-142 941.0586,-154 941.0586,-154 941.0586,-160 935.0586,-166 929.0586,-166"/>
<text text-anchor="middle" x="898.9182" y="-143.8" font-family="Verdana" font-size="14.00" fill="#000000">NewZones</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize -->
<g id="node20" class="node">
<g id="node23" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize</title>
<g id="a_node20"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize | defined in zones.go:36&#10;at zones.go:51: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile]">
<g id="a_node23"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize | defined in zones.go:36&#10;at zones.go:51: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M1148.3215,-86C1148.3215,-86 1099.3467,-86 1099.3467,-86 1093.3467,-86 1087.3467,-80 1087.3467,-74 1087.3467,-74 1087.3467,-62 1087.3467,-62 1087.3467,-56 1093.3467,-50 1099.3467,-50 1099.3467,-50 1148.3215,-50 1148.3215,-50 1154.3215,-50 1160.3215,-56 1160.3215,-62 1160.3215,-62 1160.3215,-74 1160.3215,-74 1160.3215,-80 1154.3215,-86 1148.3215,-86"/>
<text text-anchor="middle" x="1123.8341" y="-63.8" font-family="Verdana" font-size="14.00" fill="#000000">initialize</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize -->
<g id="edge13" class="edge">
<g id="edge17" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize</title>
<g id="a_edge13"><a xlink:title="at zones.go:24: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize]">
<path fill="none" stroke="#000000" d="M941.2232,-96.4168C979.9704,-90.3872 1037.2175,-81.4787 1077.2557,-75.2482"/>
<polygon fill="#000000" stroke="#000000" points="1077.9539,-78.6818 1087.2968,-73.6857 1076.8775,-71.765 1077.9539,-78.6818"/>
</a>
</g>
</g>
<!-- github.com/beevik/ntp.QueryWithOptions -->
<g id="node5" class="node">
<title>github.com/beevik/ntp.QueryWithOptions</title>
<g id="a_node5"><a xlink:title="github.com/beevik/ntp.QueryWithOptions | defined in ntp.go:432">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M355.7754,-494C355.7754,-494 248.1546,-494 248.1546,-494 242.1546,-494 236.1546,-488 236.1546,-482 236.1546,-482 236.1546,-470 236.1546,-470 236.1546,-464 242.1546,-458 248.1546,-458 248.1546,-458 355.7754,-458 355.7754,-458 361.7754,-458 367.7754,-464 367.7754,-470 367.7754,-470 367.7754,-482 367.7754,-482 367.7754,-488 361.7754,-494 355.7754,-494"/>
<text text-anchor="middle" x="301.965" y="-480.2" font-family="Verdana" font-size="14.00" fill="#000000">ntp</text>
<text text-anchor="middle" x="301.965" y="-463.4" font-family="Verdana" font-size="14.00" fill="#000000">QueryWithOptions</text>
<g id="a_edge17"><a xlink:title="at zones.go:24: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize]">
<path fill="none" stroke="#000000" d="M941.2232,-132.9526C980.135,-119.1121 1037.704,-98.6355 1077.7648,-84.3863"/>
<polygon fill="#000000" stroke="#000000" points="1079.048,-87.6448 1087.2968,-80.9959 1076.7021,-81.0495 1079.048,-87.6448"/>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper -->
<g id="node6" class="node">
<g id="node7" class="node">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper</title>
<g id="a_node6"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper | defined in router_timestamper.go:55&#10;at router_timestamper.go:61: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones]&#10;at router_timestamper.go:65: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M736.4082,-138C736.4082,-138 597.6188,-138 597.6188,-138 591.6188,-138 585.6188,-132 585.6188,-126 585.6188,-126 585.6188,-114 585.6188,-114 585.6188,-108 591.6188,-102 597.6188,-102 597.6188,-102 736.4082,-102 736.4082,-102 742.4082,-102 748.4082,-108 748.4082,-114 748.4082,-114 748.4082,-126 748.4082,-126 748.4082,-132 742.4082,-138 736.4082,-138"/>
<text text-anchor="middle" x="667.0135" y="-115.8" font-family="Verdana" font-size="14.00" fill="#000000">NewRouterTimestamper</text>
<g id="a_node7"><a xlink:title="github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper | defined in router_timestamper.go:57&#10;at router_timestamper.go:63: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones]&#10;at router_timestamper.go:67: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M736.4082,-193C736.4082,-193 597.6188,-193 597.6188,-193 591.6188,-193 585.6188,-187 585.6188,-181 585.6188,-181 585.6188,-169 585.6188,-169 585.6188,-163 591.6188,-157 597.6188,-157 597.6188,-157 736.4082,-157 736.4082,-157 742.4082,-157 748.4082,-163 748.4082,-169 748.4082,-169 748.4082,-181 748.4082,-181 748.4082,-187 742.4082,-193 736.4082,-193"/>
<text text-anchor="middle" x="667.0135" y="-170.8" font-family="Verdana" font-size="14.00" fill="#000000">NewRouterTimestamper</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones -->
<g id="edge8" class="edge">
<g id="edge12" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones</title>
<g id="a_edge8"><a xlink:title="at router_timestamper.go:61: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones]">
<path fill="none" stroke="#000000" d="M748.4483,-114.0303C780.9942,-111.6445 817.5321,-108.9661 846.4526,-106.846"/>
<polygon fill="#000000" stroke="#000000" points="847.024,-110.3136 856.7413,-106.0918 846.5122,-103.3324 847.024,-110.3136"/>
<g id="a_edge12"><a xlink:title="at router_timestamper.go:63: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewZones]">
<path fill="none" stroke="#000000" d="M748.4483,-165.5188C780.9942,-161.7296 817.5321,-157.4755 846.4526,-154.1084"/>
<polygon fill="#000000" stroke="#000000" points="847.2132,-157.5436 856.7413,-152.9105 846.4036,-150.5906 847.2132,-157.5436"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig -->
<g id="node8" class="node">
<g id="node11" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig</title>
<g id="a_node8"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig | defined in router_timestamper.go:348&#10;at router_timestamper.go:378: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone]&#10;at router_timestamper.go:369: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M937.126,-286C937.126,-286 860.7104,-286 860.7104,-286 854.7104,-286 848.7104,-280 848.7104,-274 848.7104,-274 848.7104,-262 848.7104,-262 848.7104,-256 854.7104,-250 860.7104,-250 860.7104,-250 937.126,-250 937.126,-250 943.126,-250 949.126,-256 949.126,-262 949.126,-262 949.126,-274 949.126,-274 949.126,-280 943.126,-286 937.126,-286"/>
<text text-anchor="middle" x="898.9182" y="-263.8" font-family="Verdana" font-size="14.00" fill="#000000">updateConfig</text>
<g id="a_node11"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig | defined in router_timestamper.go:354&#10;at router_timestamper.go:384: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone]&#10;at router_timestamper.go:375: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M937.126,-347C937.126,-347 860.7104,-347 860.7104,-347 854.7104,-347 848.7104,-341 848.7104,-335 848.7104,-335 848.7104,-323 848.7104,-323 848.7104,-317 854.7104,-311 860.7104,-311 860.7104,-311 937.126,-311 937.126,-311 943.126,-311 949.126,-317 949.126,-323 949.126,-323 949.126,-335 949.126,-335 949.126,-341 943.126,-347 937.126,-347"/>
<text text-anchor="middle" x="898.9182" y="-324.8" font-family="Verdana" font-size="14.00" fill="#000000">updateConfig</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig -->
<g id="edge19" class="edge">
<g id="edge22" class="edge">
<title>github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.NewRouterTimestamper&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig</title>
<g id="a_edge19"><a xlink:title="at router_timestamper.go:65: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig]">
<path fill="none" stroke="#000000" d="M684.2314,-138.2078C711.018,-165.5021 765.4158,-216.9173 821.2106,-246 826.759,-248.8921 832.7343,-251.4444 838.8191,-253.6875"/>
<polygon fill="#000000" stroke="#000000" points="837.8309,-257.0483 848.4253,-256.9623 840.0896,-250.4227 837.8309,-257.0483"/>
<g id="a_edge22"><a xlink:title="at router_timestamper.go:67: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig]">
<path fill="none" stroke="#000000" d="M706.453,-193.1268C720.3615,-200.4579 735.6497,-209.6463 748.2106,-220 787.1596,-252.1049 778.8325,-279.5801 821.2106,-307 826.6183,-310.499 832.5874,-313.4506 838.7424,-315.9386"/>
<polygon fill="#000000" stroke="#000000" points="837.9192,-319.363 848.5134,-319.4789 840.3038,-312.7816 837.9192,-319.363"/>
</a>
</g>
</g>
<!-- github.com/beevik/ntp.QueryWithOptions -->
<g id="node8" class="node">
<title>github.com/beevik/ntp.QueryWithOptions</title>
<g id="a_node8"><a xlink:title="github.com/beevik/ntp.QueryWithOptions | defined in ntp.go:432">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M355.7754,-582C355.7754,-582 248.1546,-582 248.1546,-582 242.1546,-582 236.1546,-576 236.1546,-570 236.1546,-570 236.1546,-558 236.1546,-558 236.1546,-552 242.1546,-546 248.1546,-546 248.1546,-546 355.7754,-546 355.7754,-546 361.7754,-546 367.7754,-552 367.7754,-558 367.7754,-558 367.7754,-570 367.7754,-570 367.7754,-576 361.7754,-582 355.7754,-582"/>
<text text-anchor="middle" x="301.965" y="-568.2" font-family="Verdana" font-size="14.00" fill="#000000">ntp</text>
<text text-anchor="middle" x="301.965" y="-551.4" font-family="Verdana" font-size="14.00" fill="#000000">QueryWithOptions</text>
</a>
</g>
</g>
<!-- github.com/go&#45;i2p/crypto/rand.Int63n -->
<g id="node9" class="node">
<title>github.com/go&#45;i2p/crypto/rand.Int63n</title>
<g id="a_node9"><a xlink:title="github.com/go&#45;i2p/crypto/rand.Int63n | defined in prng.go:327">
<path fill="#ffe4b5" stroke="#000000" stroke-width="1.5" d="M685.0664,-269C685.0664,-269 648.9606,-269 648.9606,-269 642.9606,-269 636.9606,-263 636.9606,-257 636.9606,-257 636.9606,-245 636.9606,-245 636.9606,-239 642.9606,-233 648.9606,-233 648.9606,-233 685.0664,-233 685.0664,-233 691.0664,-233 697.0664,-239 697.0664,-245 697.0664,-245 697.0664,-257 697.0664,-257 697.0664,-263 691.0664,-269 685.0664,-269"/>
<text text-anchor="middle" x="667.0135" y="-255.2" font-family="Verdana" font-size="14.00" fill="#000000">rand</text>
<text text-anchor="middle" x="667.0135" y="-238.4" font-family="Verdana" font-size="14.00" fill="#000000">Int63n</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.DefaultNTPClient).QueryWithOptions -->
<g id="node7" class="node">
<g id="node10" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.DefaultNTPClient).QueryWithOptions</title>
<g id="a_node7"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.DefaultNTPClient).QueryWithOptions | defined in router_timestamper.go:20&#10;at router_timestamper.go:21: calling [github.com/beevik/ntp.QueryWithOptions]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M143.4654,-494C143.4654,-494 35.8446,-494 35.8446,-494 29.8446,-494 23.8446,-488 23.8446,-482 23.8446,-482 23.8446,-470 23.8446,-470 23.8446,-464 29.8446,-458 35.8446,-458 35.8446,-458 143.4654,-458 143.4654,-458 149.4654,-458 155.4654,-464 155.4654,-470 155.4654,-470 155.4654,-482 155.4654,-482 155.4654,-488 149.4654,-494 143.4654,-494"/>
<text text-anchor="middle" x="89.655" y="-471.8" font-family="Verdana" font-size="14.00" fill="#000000">QueryWithOptions</text>
<g id="a_node10"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.DefaultNTPClient).QueryWithOptions | defined in router_timestamper.go:21&#10;at router_timestamper.go:22: calling [github.com/beevik/ntp.QueryWithOptions]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M143.4654,-574C143.4654,-574 35.8446,-574 35.8446,-574 29.8446,-574 23.8446,-568 23.8446,-562 23.8446,-562 23.8446,-550 23.8446,-550 23.8446,-544 29.8446,-538 35.8446,-538 35.8446,-538 143.4654,-538 143.4654,-538 149.4654,-538 155.4654,-544 155.4654,-550 155.4654,-550 155.4654,-562 155.4654,-562 155.4654,-568 149.4654,-574 143.4654,-574"/>
<text text-anchor="middle" x="89.655" y="-551.8" font-family="Verdana" font-size="14.00" fill="#000000">QueryWithOptions</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.DefaultNTPClient).QueryWithOptions&#45;&gt;github.com/beevik/ntp.QueryWithOptions -->
<g id="edge7" class="edge">
<g id="edge18" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.DefaultNTPClient).QueryWithOptions&#45;&gt;github.com/beevik/ntp.QueryWithOptions</title>
<g id="a_edge7"><a xlink:title="at router_timestamper.go:21: calling [github.com/beevik/ntp.QueryWithOptions]">
<path fill="none" stroke="#8b4513" d="M155.3772,-476C177.7612,-476 202.965,-476 226.0794,-476"/>
<polygon fill="#8b4513" stroke="#8b4513" points="226.1878,-479.5001 236.1878,-476 226.1878,-472.5001 226.1878,-479.5001"/>
<g id="a_edge18"><a xlink:title="at router_timestamper.go:22: calling [github.com/beevik/ntp.QueryWithOptions]">
<path fill="none" stroke="#8b4513" d="M155.3772,-558.4765C177.7612,-559.3199 202.965,-560.2696 226.0794,-561.1406"/>
<polygon fill="#8b4513" stroke="#8b4513" points="226.0631,-564.6423 236.1878,-561.5215 226.3267,-557.6473 226.0631,-564.6423"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode -->
<g id="edge14" class="edge">
<g id="edge13" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode</title>
<g id="a_edge14"><a xlink:title="at router_timestamper.go:369: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode]">
<path fill="none" stroke="#000000" d="M949.2861,-282.535C959.0176,-286.82 968.6526,-292.2328 976.6258,-299 1022.0787,-337.5781 1002.2441,-377.3308 1047.4553,-417.4837"/>
<polygon fill="#000000" stroke="#000000" points="1045.3444,-420.2793 1055.2899,-423.9314 1049.7925,-414.8743 1045.3444,-420.2793"/>
<g id="a_edge13"><a xlink:title="at router_timestamper.go:375: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.getLocalCountryCode]">
<path fill="none" stroke="#000000" d="M949.2861,-343.535C959.0176,-347.82 968.6526,-353.2328 976.6258,-360 1022.0787,-398.5781 1002.2441,-438.3308 1047.4553,-478.4837"/>
<polygon fill="#000000" stroke="#000000" points="1045.3444,-481.2793 1055.2899,-484.9314 1049.7925,-475.8743 1045.3444,-481.2793"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone -->
<g id="node19" class="node">
<g id="node22" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone</title>
<g id="a_node19"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone | defined in zones.go:28">
<g id="a_node22"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone | defined in zones.go:28">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M1148.3131,-147C1148.3131,-147 1099.3551,-147 1099.3551,-147 1093.3551,-147 1087.3551,-141 1087.3551,-135 1087.3551,-135 1087.3551,-123 1087.3551,-123 1087.3551,-117 1093.3551,-111 1099.3551,-111 1099.3551,-111 1148.3131,-111 1148.3131,-111 1154.3131,-111 1160.3131,-117 1160.3131,-123 1160.3131,-123 1160.3131,-135 1160.3131,-135 1160.3131,-141 1154.3131,-147 1148.3131,-147"/>
<text text-anchor="middle" x="1123.8341" y="-124.8" font-family="Verdana" font-size="14.00" fill="#000000">GetZone</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone -->
<g id="edge1" class="edge">
<g id="edge7" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone</title>
<g id="a_edge1"><a xlink:title="at router_timestamper.go:378: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone]">
<path fill="none" stroke="#000000" d="M949.0305,-264.8332C971.0415,-261.1253 995.8619,-253.4902 1013.6258,-238 1045.1651,-210.4976 1018.5362,-179.0098 1049.6258,-151 1057.338,-144.0518 1067.153,-139.2936 1077.0995,-136.0365"/>
<polygon fill="#000000" stroke="#000000" points="1078.334,-139.3254 1087.0168,-133.2543 1076.4431,-132.5856 1078.334,-139.3254"/>
<g id="a_edge7"><a xlink:title="at router_timestamper.go:384: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).GetZone]">
<path fill="none" stroke="#000000" d="M949.1807,-323.0476C959.3803,-319.7307 969.2326,-314.6741 976.6258,-307 1023.5933,-258.2479 965.3569,-207.46 1012.6258,-159 1029.3963,-141.807 1054.909,-134.1432 1077.2695,-130.8515"/>
<polygon fill="#000000" stroke="#000000" points="1077.7772,-134.3156 1087.2787,-129.6283 1076.928,-127.3673 1077.7772,-134.3156"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery -->
<g id="node9" class="node">
<g id="node12" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery</title>
<g id="a_node9"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery | defined in router_timestamper.go:129&#10;at router_timestamper.go:131: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity]&#10;at router_timestamper.go:130: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig]&#10;at router_timestamper.go:153: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool]&#10;at router_timestamper.go:146: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime]&#10;at router_timestamper.go:154: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M721.6312,-373C721.6312,-373 612.3958,-373 612.3958,-373 606.3958,-373 600.3958,-367 600.3958,-361 600.3958,-361 600.3958,-349 600.3958,-349 600.3958,-343 606.3958,-337 612.3958,-337 612.3958,-337 721.6312,-337 721.6312,-337 727.6312,-337 733.6312,-343 733.6312,-349 733.6312,-349 733.6312,-361 733.6312,-361 733.6312,-367 727.6312,-373 721.6312,-373"/>
<text text-anchor="middle" x="667.0135" y="-350.8" font-family="Verdana" font-size="14.00" fill="#000000">performTimeQuery</text>
<g id="a_node12"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery | defined in router_timestamper.go:131&#10;at router_timestamper.go:133: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity]&#10;at router_timestamper.go:148: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime]&#10;at router_timestamper.go:156: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime]&#10;at router_timestamper.go:132: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig]&#10;at router_timestamper.go:155: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M721.6312,-408C721.6312,-408 612.3958,-408 612.3958,-408 606.3958,-408 600.3958,-402 600.3958,-396 600.3958,-396 600.3958,-384 600.3958,-384 600.3958,-378 606.3958,-372 612.3958,-372 612.3958,-372 721.6312,-372 721.6312,-372 727.6312,-372 733.6312,-378 733.6312,-384 733.6312,-384 733.6312,-396 733.6312,-396 733.6312,-402 727.6312,-408 721.6312,-408"/>
<text text-anchor="middle" x="667.0135" y="-385.8" font-family="Verdana" font-size="14.00" fill="#000000">performTimeQuery</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity -->
<g id="edge2" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity</title>
<g id="a_edge2"><a xlink:title="at router_timestamper.go:131: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity]">
<path fill="none" stroke="#000000" d="M707.0278,-373.0762C738.0115,-386.9049 782.098,-406.2171 821.2106,-422 827.1696,-424.4046 833.4124,-426.8521 839.6589,-429.2544"/>
<polygon fill="#000000" stroke="#000000" points="838.8467,-432.6904 849.4376,-432.9798 841.3388,-426.149 838.8467,-432.6904"/>
<g id="a_edge2"><a xlink:title="at router_timestamper.go:133: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.checkIPv6Connectivity]">
<path fill="none" stroke="#000000" d="M733.7246,-405.0487C738.7538,-407.09 743.6427,-409.3964 748.2106,-412 787.5311,-434.4118 782.9694,-458.7924 821.2106,-483 824.8379,-485.2961 828.6741,-487.4508 832.6216,-489.4657"/>
<polygon fill="#000000" stroke="#000000" points="831.4534,-492.7856 841.9879,-493.9146 834.4568,-486.4626 831.4534,-492.7856"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig -->
<g id="edge4" class="edge">
<g id="edge14" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig</title>
<g id="a_edge4"><a xlink:title="at router_timestamper.go:130: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig]">
<path fill="none" stroke="#000000" d="M733.7716,-337.905C738.6888,-336.3431 743.5464,-334.7038 748.2106,-333 781.8287,-320.7195 788.3537,-313.1921 821.2106,-299 828.086,-296.0303 835.3442,-292.9992 842.5522,-290.052"/>
<polygon fill="#000000" stroke="#000000" points="844.3555,-293.0978 852.3093,-286.0988 841.7268,-286.6101 844.3555,-293.0978"/>
<g id="a_edge14"><a xlink:title="at router_timestamper.go:132: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).updateConfig]">
<path fill="none" stroke="#000000" d="M733.7788,-372.4381C767.0048,-363.6984 806.8451,-353.2188 839.069,-344.7427"/>
<polygon fill="#000000" stroke="#000000" points="840.0285,-348.1094 848.8092,-342.1806 838.2478,-341.3397 840.0285,-348.1094"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime -->
<g id="node10" class="node">
<g id="node13" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime</title>
<g id="a_node10"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime | defined in router_timestamper.go:286&#10;at router_timestamper.go:336: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime]&#10;at router_timestamper.go:317: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]&#10;at router_timestamper.go:329: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]&#10;at router_timestamper.go:318: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M929.8429,-347C929.8429,-347 867.9935,-347 867.9935,-347 861.9935,-347 855.9935,-341 855.9935,-335 855.9935,-335 855.9935,-323 855.9935,-323 855.9935,-317 861.9935,-311 867.9935,-311 867.9935,-311 929.8429,-311 929.8429,-311 935.8429,-311 941.8429,-317 941.8429,-323 941.8429,-323 941.8429,-335 941.8429,-335 941.8429,-341 935.8429,-347 929.8429,-347"/>
<text text-anchor="middle" x="898.9182" y="-324.8" font-family="Verdana" font-size="14.00" fill="#000000">queryTime</text>
<g id="a_node13"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime | defined in router_timestamper.go:288&#10;at router_timestamper.go:298: calling [github.com/go&#45;i2p/crypto/rand.Intn]&#10;at router_timestamper.go:338: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime]&#10;at router_timestamper.go:319: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]&#10;at router_timestamper.go:331: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]&#10;at router_timestamper.go:320: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M929.8429,-469C929.8429,-469 867.9935,-469 867.9935,-469 861.9935,-469 855.9935,-463 855.9935,-457 855.9935,-457 855.9935,-445 855.9935,-445 855.9935,-439 861.9935,-433 867.9935,-433 867.9935,-433 929.8429,-433 929.8429,-433 935.8429,-433 941.8429,-439 941.8429,-445 941.8429,-445 941.8429,-457 941.8429,-457 941.8429,-463 935.8429,-469 929.8429,-469"/>
<text text-anchor="middle" x="898.9182" y="-446.8" font-family="Verdana" font-size="14.00" fill="#000000">queryTime</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime -->
<g id="edge16" class="edge">
<g id="edge4" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime</title>
<g id="a_edge16"><a xlink:title="at router_timestamper.go:146: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime]&#10;at router_timestamper.go:154: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime]">
<path fill="none" stroke="#000000" d="M733.7788,-347.5146C769.4301,-343.5176 812.6965,-338.6668 845.998,-334.9332"/>
<polygon fill="#000000" stroke="#000000" points="846.4458,-338.405 855.9936,-333.8125 845.6658,-331.4485 846.4458,-338.405"/>
<g id="a_edge4"><a xlink:title="at router_timestamper.go:148: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime]&#10;at router_timestamper.go:156: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime]">
<path fill="none" stroke="#000000" d="M733.7788,-407.5619C769.4301,-416.9396 812.6965,-428.3203 845.998,-437.0799"/>
<polygon fill="#000000" stroke="#000000" points="845.4322,-440.5501 855.9936,-439.7091 847.2129,-433.7804 845.4322,-440.5501"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool -->
<g id="node12" class="node">
<g id="node15" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool</title>
<g id="a_node12"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool | defined in router_timestamper.go:125">
<g id="a_node15"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool | defined in router_timestamper.go:127&#10;at router_timestamper.go:128: calling [github.com/go&#45;i2p/crypto/rand.Float64]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M944.9466,-408C944.9466,-408 852.8898,-408 852.8898,-408 846.8898,-408 840.8898,-402 840.8898,-396 840.8898,-396 840.8898,-384 840.8898,-384 840.8898,-378 846.8898,-372 852.8898,-372 852.8898,-372 944.9466,-372 944.9466,-372 950.9466,-372 956.9466,-378 956.9466,-384 956.9466,-384 956.9466,-396 956.9466,-396 956.9466,-402 950.9466,-408 944.9466,-408"/>
<text text-anchor="middle" x="898.9182" y="-385.8" font-family="Verdana" font-size="14.00" fill="#000000">secureRandBool</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool -->
<g id="edge9" class="edge">
<g id="edge21" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool</title>
<g id="a_edge9"><a xlink:title="at router_timestamper.go:153: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool]">
<path fill="none" stroke="#000000" d="M733.7788,-365.0765C764.1938,-369.6668 800.1513,-375.0937 830.7354,-379.7096"/>
<polygon fill="#000000" stroke="#000000" points="830.4753,-383.2099 840.8856,-381.2415 831.5199,-376.2883 830.4753,-383.2099"/>
<g id="a_edge21"><a xlink:title="at router_timestamper.go:155: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool]">
<path fill="none" stroke="#000000" d="M733.7788,-390C764.1938,-390 800.1513,-390 830.7354,-390"/>
<polygon fill="#000000" stroke="#000000" points="830.8857,-393.5001 840.8856,-390 830.8856,-386.5001 830.8857,-393.5001"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime&#45;&gt;github.com/go&#45;i2p/crypto/rand.Intn -->
<g id="edge3" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime&#45;&gt;github.com/go&#45;i2p/crypto/rand.Intn</title>
<g id="a_edge3"><a xlink:title="at router_timestamper.go:298: calling [github.com/go&#45;i2p/crypto/rand.Intn]">
<path fill="none" stroke="#8b4513" d="M941.6403,-440.8899C954.0074,-436.375 966.8054,-429.976 976.6258,-421 1030.7633,-371.5178 993.5475,-320.2714 1049.6258,-273 1060.0028,-264.2526 1073.7426,-258.9831 1086.5765,-255.8087"/>
<polygon fill="#8b4513" stroke="#8b4513" points="1087.5363,-259.1831 1096.5933,-253.6857 1086.0849,-252.3352 1087.5363,-259.1831"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration -->
<g id="edge15" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration</title>
<g id="a_edge15"><a xlink:title="at router_timestamper.go:317: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]&#10;at router_timestamper.go:329: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]&#10;at router_timestamper.go:318: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]">
<path fill="none" stroke="#000000" d="M942.0155,-316.7584C953.8548,-312.2574 966.2725,-306.4 976.6258,-299 1017.6903,-269.6493 1007.4174,-239.6803 1049.6258,-212 1055.2126,-208.3362 1061.4284,-205.2657 1067.8181,-202.6962"/>
<polygon fill="#000000" stroke="#000000" points="1069.0411,-205.9758 1077.2513,-199.2794 1066.6571,-199.3943 1069.0411,-205.9758"/>
<g id="a_edge15"><a xlink:title="at router_timestamper.go:319: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]&#10;at router_timestamper.go:331: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]&#10;at router_timestamper.go:320: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]">
<path fill="none" stroke="#000000" d="M941.6998,-459.6552C953.4102,-462.9364 965.8398,-467.3023 976.6258,-473 1014.0109,-492.7486 1013.3642,-512.2572 1049.6258,-534 1055.3912,-537.457 1061.6274,-540.6787 1067.9508,-543.6306"/>
<polygon fill="#000000" stroke="#000000" points="1066.6734,-546.893 1077.2328,-547.7584 1069.5178,-540.4969 1066.6734,-546.893"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime -->
<g id="node11" class="node">
<g id="node14" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime</title>
<g id="a_node11"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime | defined in router_timestamper.go:340">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M1155.3229,-347C1155.3229,-347 1092.3453,-347 1092.3453,-347 1086.3453,-347 1080.3453,-341 1080.3453,-335 1080.3453,-335 1080.3453,-323 1080.3453,-323 1080.3453,-317 1086.3453,-311 1092.3453,-311 1092.3453,-311 1155.3229,-311 1155.3229,-311 1161.3229,-311 1167.3229,-317 1167.3229,-323 1167.3229,-323 1167.3229,-335 1167.3229,-335 1167.3229,-341 1161.3229,-347 1155.3229,-347"/>
<text text-anchor="middle" x="1123.8341" y="-324.8" font-family="Verdana" font-size="14.00" fill="#000000">stampTime</text>
<g id="a_node14"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime | defined in router_timestamper.go:342">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M1155.3229,-460C1155.3229,-460 1092.3453,-460 1092.3453,-460 1086.3453,-460 1080.3453,-454 1080.3453,-448 1080.3453,-448 1080.3453,-436 1080.3453,-436 1080.3453,-430 1086.3453,-424 1092.3453,-424 1092.3453,-424 1155.3229,-424 1155.3229,-424 1161.3229,-424 1167.3229,-430 1167.3229,-436 1167.3229,-436 1167.3229,-448 1167.3229,-448 1167.3229,-454 1161.3229,-460 1155.3229,-460"/>
<text text-anchor="middle" x="1123.8341" y="-437.8" font-family="Verdana" font-size="14.00" fill="#000000">stampTime</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime -->
<g id="edge5" class="edge">
<g id="edge8" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).queryTime&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime</title>
<g id="a_edge5"><a xlink:title="at router_timestamper.go:336: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime]">
<path fill="none" stroke="#000000" d="M941.7526,-329C978.1397,-329 1030.5595,-329 1069.8194,-329"/>
<polygon fill="#000000" stroke="#000000" points="1070.0083,-332.5001 1080.0083,-329 1070.0083,-325.5001 1070.0083,-332.5001"/>
<g id="a_edge8"><a xlink:title="at router_timestamper.go:338: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).stampTime]">
<path fill="none" stroke="#000000" d="M941.7526,-449.286C978.1397,-447.83 1030.5595,-445.7324 1069.8194,-444.1614"/>
<polygon fill="#000000" stroke="#000000" points="1070.1563,-447.6508 1080.0083,-443.7537 1069.8763,-440.6564 1070.1563,-447.6508"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run -->
<g id="node13" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run</title>
<g id="a_node13"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run | defined in router_timestamper.go:219&#10;at router_timestamper.go:222: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M491.7182,-408C491.7182,-408 461.7182,-408 461.7182,-408 455.7182,-408 449.7182,-402 449.7182,-396 449.7182,-396 449.7182,-384 449.7182,-384 449.7182,-378 455.7182,-372 461.7182,-372 461.7182,-372 491.7182,-372 491.7182,-372 497.7182,-372 503.7182,-378 503.7182,-384 503.7182,-384 503.7182,-396 503.7182,-396 503.7182,-402 497.7182,-408 491.7182,-408"/>
<text text-anchor="middle" x="476.7182" y="-385.8" font-family="Verdana" font-size="14.00" fill="#000000">run</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery -->
<g id="edge17" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery</title>
<g id="a_edge17"><a xlink:title="at router_timestamper.go:222: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery]">
<path fill="none" stroke="#000000" d="M503.9829,-384.9854C526.512,-380.8417 559.6361,-374.7494 590.1523,-369.1367"/>
<polygon fill="#000000" stroke="#000000" points="591.1804,-372.5064 600.3823,-367.2551 589.9141,-365.6218 591.1804,-372.5064"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start -->
<g id="node14" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start</title>
<g id="a_node14"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start | defined in router_timestamper.go:69&#10;at router_timestamper.go:75: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M316.965,-408C316.965,-408 286.965,-408 286.965,-408 280.965,-408 274.965,-402 274.965,-396 274.965,-396 274.965,-384 274.965,-384 274.965,-378 280.965,-372 286.965,-372 286.965,-372 316.965,-372 316.965,-372 322.965,-372 328.965,-378 328.965,-384 328.965,-384 328.965,-396 328.965,-396 328.965,-402 322.965,-408 316.965,-408"/>
<text text-anchor="middle" x="301.965" y="-385.8" font-family="Verdana" font-size="14.00" fill="#000000">Start</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run -->
<g id="edge18" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run</title>
<g id="a_edge18"><a xlink:title="at router_timestamper.go:75: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run]">
<path fill="none" stroke="#000000" d="M329.2702,-390C355.1753,-390 394.7342,-390 426.3574,-390"/>
<polygon fill="#000000" stroke="#000000" points="439.6048,-393.5 449.6048,-390 439.6047,-386.5 439.6048,-393.5"/>
<polyline fill="none" stroke="#000000" points="439.6048,-390 434.6048,-390.0001 "/>
<ellipse fill="none" stroke="#000000" cx="430.6048" cy="-390.0001" rx="4" ry="4"/>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool&#45;&gt;github.com/go&#45;i2p/crypto/rand.Float64 -->
<g id="edge9" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).secureRandBool&#45;&gt;github.com/go&#45;i2p/crypto/rand.Float64</title>
<g id="a_edge9"><a xlink:title="at router_timestamper.go:128: calling [github.com/go&#45;i2p/crypto/rand.Float64]">
<path fill="none" stroke="#8b4513" d="M957.232,-372.9594C964.2314,-369.3856 970.9108,-365.1072 976.6258,-360 1028.95,-313.2407 997.6714,-267.1698 1049.6258,-220 1058.4587,-211.9806 1069.713,-205.966 1080.7713,-201.5134"/>
<polygon fill="#8b4513" stroke="#8b4513" points="1082.1899,-204.7212 1090.373,-197.9915 1079.7793,-198.1493 1082.1899,-204.7212"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce -->
<g id="node15" class="node">
<g id="node16" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce</title>
<g id="a_node15"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce | defined in router_timestamper.go:282&#10;at router_timestamper.go:283: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M500.9149,-347C500.9149,-347 452.5215,-347 452.5215,-347 446.5215,-347 440.5215,-341 440.5215,-335 440.5215,-335 440.5215,-323 440.5215,-323 440.5215,-317 446.5215,-311 452.5215,-311 452.5215,-311 500.9149,-311 500.9149,-311 506.9149,-311 512.9149,-317 512.9149,-323 512.9149,-323 512.9149,-335 512.9149,-335 512.9149,-341 506.9149,-347 500.9149,-347"/>
<text text-anchor="middle" x="476.7182" y="-324.8" font-family="Verdana" font-size="14.00" fill="#000000">runOnce</text>
<g id="a_node16"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce | defined in router_timestamper.go:284&#10;at router_timestamper.go:285: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M500.9149,-408C500.9149,-408 452.5215,-408 452.5215,-408 446.5215,-408 440.5215,-402 440.5215,-396 440.5215,-396 440.5215,-384 440.5215,-384 440.5215,-378 446.5215,-372 452.5215,-372 452.5215,-372 500.9149,-372 500.9149,-372 506.9149,-372 512.9149,-378 512.9149,-384 512.9149,-384 512.9149,-396 512.9149,-396 512.9149,-402 506.9149,-408 500.9149,-408"/>
<text text-anchor="middle" x="476.7182" y="-385.8" font-family="Verdana" font-size="14.00" fill="#000000">runOnce</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery -->
<g id="edge10" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery</title>
<g id="a_edge10"><a xlink:title="at router_timestamper.go:283: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery]">
<path fill="none" stroke="#000000" d="M512.9592,-333.9516C534.7608,-336.9303 563.365,-340.8385 590.0004,-344.4777"/>
<polygon fill="#000000" stroke="#000000" points="589.7122,-347.9708 600.0939,-345.8568 590.6598,-341.0352 589.7122,-347.9708"/>
<g id="a_edge10"><a xlink:title="at router_timestamper.go:285: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery]">
<path fill="none" stroke="#000000" d="M512.9592,-390C534.7608,-390 563.365,-390 590.0004,-390"/>
<polygon fill="#000000" stroke="#000000" points="590.094,-393.5001 600.0939,-390 590.0939,-386.5001 590.094,-393.5001"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow -->
<g id="node16" class="node">
<g id="node17" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow</title>
<g id="a_node16"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow | defined in router_timestamper.go:119&#10;at router_timestamper.go:121: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M347.1672,-347C347.1672,-347 256.7628,-347 256.7628,-347 250.7628,-347 244.7628,-341 244.7628,-335 244.7628,-335 244.7628,-323 244.7628,-323 244.7628,-317 250.7628,-311 256.7628,-311 256.7628,-311 347.1672,-311 347.1672,-311 353.1672,-311 359.1672,-317 359.1672,-323 359.1672,-323 359.1672,-335 359.1672,-335 359.1672,-341 353.1672,-347 347.1672,-347"/>
<text text-anchor="middle" x="301.965" y="-324.8" font-family="Verdana" font-size="14.00" fill="#000000">TimestampNow</text>
<g id="a_node17"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow | defined in router_timestamper.go:121&#10;at router_timestamper.go:123: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M347.1672,-408C347.1672,-408 256.7628,-408 256.7628,-408 250.7628,-408 244.7628,-402 244.7628,-396 244.7628,-396 244.7628,-384 244.7628,-384 244.7628,-378 250.7628,-372 256.7628,-372 256.7628,-372 347.1672,-372 347.1672,-372 353.1672,-372 359.1672,-378 359.1672,-384 359.1672,-384 359.1672,-396 359.1672,-396 359.1672,-402 353.1672,-408 347.1672,-408"/>
<text text-anchor="middle" x="301.965" y="-385.8" font-family="Verdana" font-size="14.00" fill="#000000">TimestampNow</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce -->
<g id="edge6" class="edge">
<g id="edge5" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce</title>
<g id="a_edge6"><a xlink:title="at router_timestamper.go:121: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce]">
<path fill="none" stroke="#000000" d="M359.1857,-329C377.8039,-329 398.5042,-329 417.2807,-329"/>
<polygon fill="#000000" stroke="#000000" points="430.5192,-332.5 440.5192,-329 430.5192,-325.5 430.5192,-332.5"/>
<polyline fill="none" stroke="#000000" points="430.5192,-329 425.5192,-329.0001 "/>
<ellipse fill="none" stroke="#000000" cx="421.5192" cy="-329.0001" rx="4" ry="4"/>
<g id="a_edge5"><a xlink:title="at router_timestamper.go:123: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).runOnce]">
<path fill="none" stroke="#000000" d="M359.1857,-390C377.8039,-390 398.5042,-390 417.2807,-390"/>
<polygon fill="#000000" stroke="#000000" points="430.5192,-393.5 440.5192,-390 430.5192,-386.5 430.5192,-393.5"/>
<polyline fill="none" stroke="#000000" points="430.5192,-390 425.5192,-390.0001 "/>
<ellipse fill="none" stroke="#000000" cx="421.5192" cy="-390.0001" rx="4" ry="4"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime -->
<g id="node17" class="node">
<g id="node18" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime</title>
<g id="a_node17"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime | defined in router_timestamper.go:418&#10;at router_timestamper.go:421: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M135.6792,-347C135.6792,-347 43.6308,-347 43.6308,-347 37.6308,-347 31.6308,-341 31.6308,-335 31.6308,-335 31.6308,-323 31.6308,-323 31.6308,-317 37.6308,-311 43.6308,-311 43.6308,-311 135.6792,-311 135.6792,-311 141.6792,-311 147.6792,-317 147.6792,-323 147.6792,-323 147.6792,-335 147.6792,-335 147.6792,-341 141.6792,-347 135.6792,-347"/>
<text text-anchor="middle" x="89.655" y="-324.8" font-family="Verdana" font-size="14.00" fill="#000000">GetCurrentTime</text>
<g id="a_node18"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime | defined in router_timestamper.go:424&#10;at router_timestamper.go:427: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M135.6792,-408C135.6792,-408 43.6308,-408 43.6308,-408 37.6308,-408 31.6308,-402 31.6308,-396 31.6308,-396 31.6308,-384 31.6308,-384 31.6308,-378 37.6308,-372 43.6308,-372 43.6308,-372 135.6792,-372 135.6792,-372 141.6792,-372 147.6792,-378 147.6792,-384 147.6792,-384 147.6792,-396 147.6792,-396 147.6792,-402 141.6792,-408 135.6792,-408"/>
<text text-anchor="middle" x="89.655" y="-385.8" font-family="Verdana" font-size="14.00" fill="#000000">GetCurrentTime</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow -->
<g id="edge3" class="edge">
<g id="edge16" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).GetCurrentTime&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow</title>
<g id="a_edge3"><a xlink:title="at router_timestamper.go:421: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow]">
<path fill="none" stroke="#000000" d="M147.9505,-329C174.7367,-329 206.6648,-329 234.487,-329"/>
<polygon fill="#000000" stroke="#000000" points="234.5344,-332.5001 244.5344,-329 234.5343,-325.5001 234.5344,-332.5001"/>
<g id="a_edge16"><a xlink:title="at router_timestamper.go:427: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).TimestampNow]">
<path fill="none" stroke="#000000" d="M147.9505,-390C174.7367,-390 206.6648,-390 234.487,-390"/>
<polygon fill="#000000" stroke="#000000" points="234.5344,-393.5001 244.5344,-390 234.5343,-386.5001 234.5344,-393.5001"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run -->
<g id="node19" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run</title>
<g id="a_node19"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run | defined in router_timestamper.go:221&#10;at router_timestamper.go:224: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery]&#10;at router_timestamper.go:236: calling [github.com/go&#45;i2p/crypto/rand.Int63n]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M491.7182,-347C491.7182,-347 461.7182,-347 461.7182,-347 455.7182,-347 449.7182,-341 449.7182,-335 449.7182,-335 449.7182,-323 449.7182,-323 449.7182,-317 455.7182,-311 461.7182,-311 461.7182,-311 491.7182,-311 491.7182,-311 497.7182,-311 503.7182,-317 503.7182,-323 503.7182,-323 503.7182,-335 503.7182,-335 503.7182,-341 497.7182,-347 491.7182,-347"/>
<text text-anchor="middle" x="476.7182" y="-324.8" font-family="Verdana" font-size="14.00" fill="#000000">run</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run&#45;&gt;github.com/go&#45;i2p/crypto/rand.Int63n -->
<g id="edge6" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run&#45;&gt;github.com/go&#45;i2p/crypto/rand.Int63n</title>
<g id="a_edge6"><a xlink:title="at router_timestamper.go:236: calling [github.com/go&#45;i2p/crypto/rand.Int63n]">
<path fill="none" stroke="#8b4513" d="M503.7811,-313.0838C525.4211,-300.8593 556.8297,-284.2233 585.8164,-273 598.9488,-267.9153 613.7075,-263.5399 627.0045,-260.0608"/>
<polygon fill="#8b4513" stroke="#8b4513" points="627.9979,-263.4199 636.8367,-257.5781 626.2841,-256.6329 627.9979,-263.4199"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery -->
<g id="edge1" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery</title>
<g id="a_edge1"><a xlink:title="at router_timestamper.go:224: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).performTimeQuery]">
<path fill="none" stroke="#000000" d="M503.8667,-339.377C525.8187,-347.6046 557.6035,-359.1503 585.8164,-368 587.2535,-368.4508 588.7066,-368.9009 590.172,-369.3498"/>
<polygon fill="#000000" stroke="#000000" points="589.4012,-372.7724 599.9848,-372.2862 591.408,-366.0662 589.4012,-372.7724"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).validateResponse -->
<g id="node18" class="node">
<g id="node20" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).validateResponse</title>
<g id="a_node18"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).validateResponse | defined in verification.go:10&#10;at verification.go:28: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M138.6256,-286C138.6256,-286 40.6844,-286 40.6844,-286 34.6844,-286 28.6844,-280 28.6844,-274 28.6844,-274 28.6844,-262 28.6844,-262 28.6844,-256 34.6844,-250 40.6844,-250 40.6844,-250 138.6256,-250 138.6256,-250 144.6256,-250 150.6256,-256 150.6256,-262 150.6256,-262 150.6256,-274 150.6256,-274 150.6256,-280 144.6256,-286 138.6256,-286"/>
<text text-anchor="middle" x="89.655" y="-263.8" font-family="Verdana" font-size="14.00" fill="#000000">validateResponse</text>
<g id="a_node20"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).validateResponse | defined in verification.go:10&#10;at verification.go:28: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M138.6256,-469C138.6256,-469 40.6844,-469 40.6844,-469 34.6844,-469 28.6844,-463 28.6844,-457 28.6844,-457 28.6844,-445 28.6844,-445 28.6844,-439 34.6844,-433 40.6844,-433 40.6844,-433 138.6256,-433 138.6256,-433 144.6256,-433 150.6256,-439 150.6256,-445 150.6256,-445 150.6256,-457 150.6256,-457 150.6256,-463 144.6256,-469 138.6256,-469"/>
<text text-anchor="middle" x="89.655" y="-446.8" font-family="Verdana" font-size="14.00" fill="#000000">validateResponse</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).validateResponse&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration -->
<g id="edge11" class="edge">
<g id="edge19" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).validateResponse&#45;&gt;github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration</title>
<g id="a_edge11"><a xlink:title="at verification.go:28: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]">
<path fill="none" stroke="#000000" d="M125.453,-249.8939C166.855,-230.6609 237.5896,-203 301.965,-203 301.965,-203 301.965,-203 898.9182,-203 956.2509,-203 1021.6676,-198.7379 1067.1138,-195.0945"/>
<polygon fill="#000000" stroke="#000000" points="1067.6758,-198.5603 1077.3571,-194.2567 1067.1051,-191.5836 1067.6758,-198.5603"/>
<g id="a_edge19"><a xlink:title="at verification.go:28: calling [github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.absDuration]">
<path fill="none" stroke="#000000" d="M150.7035,-459.8486C276.0906,-477.7634 571.8203,-518.6846 821.2106,-543 906.8083,-551.3457 1006.3432,-557.5892 1067.203,-561.0165"/>
<polygon fill="#000000" stroke="#000000" points="1067.1876,-564.521 1077.3669,-561.5829 1067.5772,-557.5318 1067.1876,-564.521"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start -->
<g id="node21" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start</title>
<g id="a_node21"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start | defined in router_timestamper.go:71&#10;at router_timestamper.go:77: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run]">
<path fill="#add8e6" stroke="#000000" stroke-width="1.5" d="M316.965,-347C316.965,-347 286.965,-347 286.965,-347 280.965,-347 274.965,-341 274.965,-335 274.965,-335 274.965,-323 274.965,-323 274.965,-317 280.965,-311 286.965,-311 286.965,-311 316.965,-311 316.965,-311 322.965,-311 328.965,-317 328.965,-323 328.965,-323 328.965,-335 328.965,-335 328.965,-341 322.965,-347 316.965,-347"/>
<text text-anchor="middle" x="301.965" y="-324.8" font-family="Verdana" font-size="14.00" fill="#000000">Start</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run -->
<g id="edge20" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).Start&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run</title>
<g id="a_edge20"><a xlink:title="at router_timestamper.go:77: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.RouterTimestamper).run]">
<path fill="none" stroke="#000000" d="M329.2702,-329C355.1753,-329 394.7342,-329 426.3574,-329"/>
<polygon fill="#000000" stroke="#000000" points="439.6048,-332.5 449.6048,-329 439.6047,-325.5 439.6048,-332.5"/>
<polyline fill="none" stroke="#000000" points="439.6048,-329 434.6048,-329.0001 "/>
<ellipse fill="none" stroke="#000000" cx="430.6048" cy="-329.0001" rx="4" ry="4"/>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile -->
<g id="node21" class="node">
<g id="node24" class="node">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile</title>
<g id="a_node21"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile | defined in zones.go:54">
<g id="a_node24"><a xlink:title="(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile | defined in zones.go:54">
<path fill="#add8e6" stroke="#000000" stroke-width=".5" d="M1384.1792,-86C1384.1792,-86 1282.9968,-86 1282.9968,-86 1276.9968,-86 1270.9968,-80 1270.9968,-74 1270.9968,-74 1270.9968,-62 1270.9968,-62 1270.9968,-56 1276.9968,-50 1282.9968,-50 1282.9968,-50 1384.1792,-50 1384.1792,-50 1390.1792,-50 1396.1792,-56 1396.1792,-62 1396.1792,-62 1396.1792,-74 1396.1792,-74 1396.1792,-80 1390.1792,-86 1384.1792,-86"/>
<text text-anchor="middle" x="1333.588" y="-63.8" font-family="Verdana" font-size="14.00" fill="#000000">readContinentFile</text>
</a>
</g>
</g>
<!-- (*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile -->
<g id="edge12" class="edge">
<g id="edge11" class="edge">
<title>(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).initialize&#45;&gt;(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile</title>
<g id="a_edge12"><a xlink:title="at zones.go:51: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile]">
<g id="a_edge11"><a xlink:title="at zones.go:51: calling [(*github.com/go&#45;i2p/go&#45;i2p/lib/util/time/sntp.Zones).readContinentFile]">
<path fill="none" stroke="#000000" d="M1160.3704,-68C1187.9205,-68 1226.6146,-68 1260.4451,-68"/>
<polygon fill="#000000" stroke="#000000" points="1260.7704,-71.5001 1270.7704,-68 1260.7703,-64.5001 1260.7704,-71.5001"/>
</a>

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 45 KiB