diff --git a/src/core/api.go b/src/core/api.go index 607a03aa..75d9d7b3 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -181,8 +181,10 @@ func (c *Core) SetLogger(log util.Logger) { } // AddPeer adds a peer. This should be specified in the peer URI format, e.g.: -// tcp://a.b.c.d:e -// socks://a.b.c.d:e/f.g.h.i:j +// +// tcp://a.b.c.d:e +// socks://a.b.c.d:e/f.g.h.i:j +// // This adds the peer to the peer list, so that they will be called again if the // connection drops. func (c *Core) AddPeer(uri string, sourceInterface string) error { @@ -190,12 +192,12 @@ func (c *Core) AddPeer(uri string, sourceInterface string) error { if err != nil { return err } - err = c.CallPeer(u, sourceInterface) + info, err := c.links.call(u, sourceInterface) if err != nil { return err } phony.Block(c, func() { - c.config._peers[Peer{uri, sourceInterface}] = struct{}{} + c.config._peers[Peer{uri, sourceInterface}] = &info }) return nil } @@ -203,10 +205,24 @@ func (c *Core) AddPeer(uri string, sourceInterface string) error { // RemovePeer removes a peer. The peer should be specified in URI format, see AddPeer. // The peer is not disconnected immediately. func (c *Core) RemovePeer(uri string, sourceInterface string) error { + var err error phony.Block(c, func() { - delete(c.config._peers, Peer{uri, sourceInterface}) + peer := Peer{uri, sourceInterface} + linkInfo, ok := c.config._peers[peer] + if !ok { + err = fmt.Errorf("peer not configured") + return + } + if ok && linkInfo != nil { + c.links.Act(nil, func() { + if link := c.links._links[*linkInfo]; link != nil { + _ = link.close() + } + }) + } + delete(c.config._peers, peer) }) - return nil + return err } // CallPeer calls a peer once. This should be specified in the peer URI format, @@ -218,7 +234,8 @@ func (c *Core) RemovePeer(uri string, sourceInterface string) error { // This does not add the peer to the peer list, so if the connection drops, the // peer will not be called again automatically. func (c *Core) CallPeer(u *url.URL, sintf string) error { - return c.links.call(u, sintf) + _, err := c.links.call(u, sintf) + return err } func (c *Core) PublicKey() ed25519.PublicKey { diff --git a/src/core/core.go b/src/core/core.go index 5cfcc7a2..b8315416 100644 --- a/src/core/core.go +++ b/src/core/core.go @@ -36,7 +36,7 @@ type Core struct { log util.Logger addPeerTimer *time.Timer config struct { - _peers map[Peer]struct{} // configurable after startup + _peers map[Peer]*linkInfo // configurable after startup _listeners map[ListenAddress]struct{} // configurable after startup nodeinfo NodeInfo // immutable after startup nodeinfoPrivacy NodeInfoPrivacy // immutable after startup @@ -66,7 +66,7 @@ func New(secret ed25519.PrivateKey, logger util.Logger, opts ...SetupOption) (*C if c.PacketConn, err = iwe.NewPacketConn(c.secret); err != nil { return nil, fmt.Errorf("error creating encryption: %w", err) } - c.config._peers = map[Peer]struct{}{} + c.config._peers = map[Peer]*linkInfo{} c.config._listeners = map[ListenAddress]struct{}{} c.config._allowedPublicKeys = map[[32]byte]struct{}{} for _, opt := range opts { diff --git a/src/core/link.go b/src/core/link.go index 26e44669..963963a4 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -108,10 +108,10 @@ func (l *links) isConnectedTo(info linkInfo) bool { return isConnected } -func (l *links) call(u *url.URL, sintf string) error { +func (l *links) call(u *url.URL, sintf string) (linkInfo, error) { info := linkInfoFor(u.Scheme, sintf, u.Host) if l.isConnectedTo(info) { - return nil + return info, nil } options := linkOptions{ pinnedEd25519Keys: map[keyArray]struct{}{}, @@ -119,7 +119,7 @@ func (l *links) call(u *url.URL, sintf string) error { for _, pubkey := range u.Query()["key"] { sigPub, err := hex.DecodeString(pubkey) if err != nil { - return fmt.Errorf("pinned key contains invalid hex characters") + return info, fmt.Errorf("pinned key contains invalid hex characters") } var sigPubKey keyArray copy(sigPubKey[:], sigPub) @@ -172,9 +172,9 @@ func (l *links) call(u *url.URL, sintf string) error { }() default: - return errors.New("unknown call scheme: " + u.Scheme) + return info, errors.New("unknown call scheme: " + u.Scheme) } - return nil + return info, nil } func (l *links) listen(u *url.URL, sintf string) (*Listener, error) { diff --git a/src/core/options.go b/src/core/options.go index 8009aa3b..66aa16ce 100644 --- a/src/core/options.go +++ b/src/core/options.go @@ -7,7 +7,7 @@ import ( func (c *Core) _applyOption(opt SetupOption) { switch v := opt.(type) { case Peer: - c.config._peers[v] = struct{}{} + c.config._peers[v] = nil case ListenAddress: c.config._listeners[v] = struct{}{} case NodeInfo: