-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #154 from wetware/feat/system-sock-exports
Add "system socket" API
- Loading branch information
Showing
7 changed files
with
122 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package system | ||
|
||
import ( | ||
"context" | ||
"io" | ||
"runtime" | ||
|
||
local "github.com/libp2p/go-libp2p/core/host" | ||
|
||
"capnproto.org/go/capnp/v3" | ||
"capnproto.org/go/capnp/v3/rpc" | ||
) | ||
|
||
type Dialer interface { | ||
DialRPC(context.Context, local.Host) (*rpc.Conn, error) | ||
} | ||
|
||
func Bootstrap[T ~capnp.ClientKind](ctx context.Context) T { | ||
conn, err := FDSockDialer{}.DialRPC(ctx) | ||
if err != nil { | ||
return failure[T](err) | ||
} | ||
runtime.SetFinalizer(conn, func(c io.Closer) error { | ||
return c.Close() | ||
}) | ||
|
||
client := conn.Bootstrap(ctx) | ||
if err := client.Resolve(ctx); err != nil { | ||
return failure[T](err) | ||
} | ||
|
||
return T(client) | ||
} | ||
|
||
func failure[T ~capnp.ClientKind](err error) T { | ||
return T(capnp.ErrorClient(err)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,54 @@ | ||
package system | ||
|
||
/* | ||
* The contents of this file will be moved to the ww repository | ||
*/ | ||
|
||
import ( | ||
"context" | ||
"io" | ||
"net" | ||
"os" | ||
"runtime" | ||
"syscall" | ||
|
||
"capnproto.org/go/capnp/v3" | ||
"capnproto.org/go/capnp/v3/rpc" | ||
"github.com/wetware/pkg/system" | ||
"golang.org/x/exp/slog" | ||
) | ||
|
||
const ( | ||
// file descriptor for pre-openned TCP socket | ||
// file descriptor for first pre-openned file descriptor. | ||
PREOPENED_FD = 3 | ||
) | ||
|
||
// Boot bootstraps and resolves the Capnp client attached | ||
// to the other end of the pre-openned TCP connection. | ||
// capnp.Client will be capnp.ErrorClient if an error ocurred. | ||
func Boot[T ~capnp.ClientKind](ctx context.Context) (T, capnp.ReleaseFunc) { | ||
var closers []io.Closer | ||
release := func() { | ||
for i := range closers { | ||
// call in reverse order, similar to defer | ||
_ = closers[len(closers)-i-1].Close() | ||
} | ||
// FDSockDialer binds to a pre-opened file descriptor (usually a TCP socket), | ||
// and provides an *rcp.Conn to the host. | ||
type FDSockDialer struct{} | ||
|
||
func (s FDSockDialer) DialRPC(context.Context) (*rpc.Conn, error) { | ||
f := os.NewFile(uintptr(PREOPENED_FD), "") | ||
if err := syscall.SetNonblock(PREOPENED_FD, false); err != nil { | ||
return nil, err | ||
} | ||
|
||
l, err := preopenedListener(&closers) | ||
// Make sure we eventually release the file descriptor. | ||
runtime.SetFinalizer(f, func(c io.Closer) error { | ||
return c.Close() | ||
}) | ||
|
||
l, err := net.FileListener(f) | ||
if err != nil { | ||
defer release() | ||
return failure[T](err) | ||
return nil, err | ||
} | ||
closers = append(closers, l) | ||
defer l.Close() | ||
|
||
tcpConn, err := l.Accept() | ||
raw, err := l.Accept() | ||
if err != nil { | ||
defer release() | ||
return failure[T](err) | ||
return nil, err | ||
} | ||
closers = append(closers, tcpConn) | ||
|
||
conn := rpc.NewConn(rpc.NewStreamTransport(tcpConn), &rpc.Options{ | ||
conn := rpc.NewConn(rpc.NewStreamTransport(raw), &rpc.Options{ | ||
ErrorReporter: system.ErrorReporter{ | ||
Logger: slog.Default().WithGroup("guest"), | ||
}, | ||
}) | ||
closers = append(closers, conn) | ||
|
||
client := conn.Bootstrap(ctx) | ||
return T(client), release | ||
} | ||
|
||
func failure[T ~capnp.ClientKind](err error) (T, capnp.ReleaseFunc) { | ||
return T(capnp.ErrorClient(err)), func() {} | ||
} | ||
|
||
// return the a TCP listener from pre-opened tcp connection by using the fd | ||
func preopenedListener(closers *[]io.Closer) (net.Listener, error) { | ||
f := os.NewFile(uintptr(PREOPENED_FD), "") | ||
|
||
if err := syscall.SetNonblock(PREOPENED_FD, false); err != nil { | ||
return nil, err | ||
} | ||
*closers = append(*closers, f) | ||
|
||
l, err := net.FileListener(f) | ||
if err != nil { | ||
return nil, err | ||
} | ||
*closers = append(*closers, l) | ||
|
||
return l, err | ||
return conn, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package system | ||
|
||
import ( | ||
"context" | ||
"net" | ||
|
||
"capnproto.org/go/capnp/v3" | ||
"capnproto.org/go/capnp/v3/rpc" | ||
"github.com/wetware/pkg/util/log" | ||
) | ||
|
||
// NetSock is a system socket that uses the host's IP stack. | ||
type NetSock struct { | ||
Addr net.Addr | ||
Logger log.Logger | ||
BootstrapClient capnp.Client | ||
|
||
conn *rpc.Conn | ||
} | ||
|
||
func (sock *NetSock) Close(context.Context) error { | ||
sock.BootstrapClient.Release() | ||
|
||
return sock.conn.Close() | ||
} | ||
|
||
func (sock *NetSock) dial(ctx context.Context) error { | ||
raw, err := dial(ctx, sock.Addr) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
sock.conn = rpc.NewConn(rpc.NewStreamTransport(raw), &rpc.Options{ | ||
ErrorReporter: ErrorReporter{Logger: sock.Logger}, | ||
BootstrapClient: sock.BootstrapClient, | ||
}) | ||
|
||
return nil | ||
} | ||
|
||
func dial(ctx context.Context, addr net.Addr) (net.Conn, error) { | ||
dialer := net.Dialer{} | ||
return dialer.DialContext(ctx, addr.Network(), addr.String()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters