|
@@ -2,6 +2,7 @@ package edgevpn
|
|
|
|
|
|
import (
|
|
|
"context"
|
|
|
+ "fmt"
|
|
|
"io"
|
|
|
"net"
|
|
|
"os"
|
|
@@ -47,6 +48,117 @@ func New(p ...Option) *EdgeVPN {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func (e *EdgeVPN) ExposeService(ledger *blockchain.Ledger, serviceID, dstaddress string) {
|
|
|
+ // 1) Register the ServiceID <-> PeerID Association
|
|
|
+ // By announcing periodically our service to the blockchain
|
|
|
+ ledger.Announce(
|
|
|
+ context.Background(),
|
|
|
+ e.config.LedgerAnnounceTime,
|
|
|
+ func() {
|
|
|
+ key := fmt.Sprintf("service-%s", serviceID)
|
|
|
+ // Retrieve current ID for ip in the blockchain
|
|
|
+ existingValue, found := ledger.GetKey(key)
|
|
|
+ // If mismatch, update the blockchain
|
|
|
+ if !found || existingValue.PeerID != e.host.ID().String() {
|
|
|
+ updatedMap := map[string]blockchain.Data{}
|
|
|
+ updatedMap[key] = blockchain.Data{PeerID: e.host.ID().String()}
|
|
|
+ ledger.Add(updatedMap)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ )
|
|
|
+
|
|
|
+ // 2) Set a stream handler
|
|
|
+ // which connect to the given address/Port and Send what we receive from the Stream.
|
|
|
+ e.config.StreamHandlers[protocol.ID(ServiceProtocol)] = func(stream network.Stream) {
|
|
|
+ go func() {
|
|
|
+ e.config.Logger.Sugar().Info("Received connection from", stream.Conn().RemotePeer().String())
|
|
|
+ // TODO: Gate connection by PeerID: stream.Conn().RemotePeer().String()
|
|
|
+ // we need a list of known peers
|
|
|
+ e.config.Logger.Sugar().Info("Dialing", dstaddress)
|
|
|
+
|
|
|
+ c, err := net.Dial("tcp", dstaddress)
|
|
|
+ if err != nil {
|
|
|
+ e.config.Logger.Sugar().Info("Reset", stream.Conn().RemotePeer().String(), err.Error())
|
|
|
+ stream.Reset()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ closer := make(chan struct{}, 2)
|
|
|
+ go copyStream(closer, stream, c)
|
|
|
+ go copyStream(closer, c, stream)
|
|
|
+ <-closer
|
|
|
+
|
|
|
+ stream.Close()
|
|
|
+ c.Close()
|
|
|
+
|
|
|
+ e.config.Logger.Sugar().Info("Done", stream.Conn().RemotePeer().String())
|
|
|
+
|
|
|
+ }()
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func copyStream(closer chan struct{}, dst io.Writer, src io.Reader) {
|
|
|
+ _, _ = io.Copy(dst, src)
|
|
|
+ closer <- struct{}{} // connection is closed, send signal to stop proxy
|
|
|
+}
|
|
|
+
|
|
|
+func (e *EdgeVPN) ConnectToService(ledger *blockchain.Ledger, serviceID string, srcaddr string) error {
|
|
|
+ // Open local port for listening
|
|
|
+ l, err := net.Listen("tcp", srcaddr)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ fmt.Println("Listening on ", srcaddr)
|
|
|
+
|
|
|
+ defer l.Close()
|
|
|
+ for {
|
|
|
+ // Listen for an incoming connection.
|
|
|
+ conn, err := l.Accept()
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("Error accepting: ", err.Error())
|
|
|
+ os.Exit(1)
|
|
|
+ }
|
|
|
+ e.config.Logger.Sugar().Info("New connection from", l.Addr().String())
|
|
|
+ // Handle connections in a new goroutine, forwarding to the p2p service
|
|
|
+ go func() {
|
|
|
+ key := fmt.Sprintf("service-%s", serviceID)
|
|
|
+ // Retrieve current ID for ip in the blockchain
|
|
|
+ existingValue, found := ledger.GetKey(key)
|
|
|
+ // If mismatch, update the blockchain
|
|
|
+ if !found {
|
|
|
+ e.config.Logger.Sugar().Info("service not found on blockchain")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // Decode the Peer
|
|
|
+ d, err := peer.Decode(existingValue.PeerID)
|
|
|
+ if err != nil {
|
|
|
+ e.config.Logger.Sugar().Infof("could not decode peer '%s'", existingValue.PeerID)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // Open a stream
|
|
|
+ stream, err := e.host.NewStream(context.Background(), d, ServiceProtocol)
|
|
|
+ if err != nil {
|
|
|
+ e.config.Logger.Sugar().Infof("could not open stream '%s'", err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ e.config.Logger.Sugar().Info("Redirecting", l.Addr().String(), "to", serviceID)
|
|
|
+
|
|
|
+ closer := make(chan struct{}, 2)
|
|
|
+ go copyStream(closer, stream, conn)
|
|
|
+ go copyStream(closer, conn, stream)
|
|
|
+ <-closer
|
|
|
+
|
|
|
+ stream.Close()
|
|
|
+ conn.Close()
|
|
|
+ e.config.Logger.Sugar().Info("Done handling", l.Addr().String(), "to", serviceID)
|
|
|
+ }()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Join the network with the ledger.
|
|
|
+// It does the minimal action required to be connected
|
|
|
+// without any active packet routing
|
|
|
func (e *EdgeVPN) Join(ledger *blockchain.Ledger) error {
|
|
|
// Set the handler when we receive messages
|
|
|
// The ledger needs to read them and update the internal blockchain
|