@@ -26,6 +26,7 @@ import (
2626 "github.com/lightningnetwork/lnd/fn"
2727 "github.com/lightningnetwork/lnd/macaroons"
2828 "google.golang.org/grpc"
29+ "google.golang.org/grpc/metadata"
2930 "gopkg.in/macaroon-bakery.v2/bakery"
3031 "gopkg.in/macaroon-bakery.v2/bakery/checkers"
3132 "gopkg.in/macaroon.v2"
@@ -77,10 +78,23 @@ func newSessionRPCServer(cfg *sessionRpcServerConfig) (*sessionRpcServer,
7778 // actual mailbox server that spins up the Terminal Connect server
7879 // interface.
7980 server := session .NewServer (
80- func (opts ... grpc.ServerOption ) * grpc.Server {
81- allOpts := append (cfg .grpcOptions , opts ... )
81+ func (id session.ID , opts ... grpc.ServerOption ) * grpc.Server {
82+ // Add the session ID injector interceptors first so
83+ // that the session ID is available in the context of
84+ // all interceptors that come after.
85+ allOpts := []grpc.ServerOption {
86+ addSessionIDToStreamCtx (id ),
87+ addSessionIDToUnaryCtx (id ),
88+ }
89+
90+ allOpts = append (allOpts , cfg .grpcOptions ... )
91+ allOpts = append (allOpts , opts ... )
92+
93+ // Construct the gRPC server with the options.
8294 grpcServer := grpc .NewServer (allOpts ... )
8395
96+ // Register various grpc servers with the LNC session
97+ // server.
8498 cfg .registerGrpcServers (grpcServer )
8599
86100 return grpcServer
@@ -94,6 +108,62 @@ func newSessionRPCServer(cfg *sessionRpcServerConfig) (*sessionRpcServer,
94108 }, nil
95109}
96110
111+ // wrappedServerStream is a wrapper around the grpc.ServerStream that allows us
112+ // to set a custom context. This is needed since the stream handler function
113+ // doesn't take a context as an argument, but rather has a Context method on the
114+ // handler itself. So we use this custom wrapper to override this method.
115+ type wrappedServerStream struct {
116+ grpc.ServerStream
117+ ctx context.Context
118+ }
119+
120+ // Context returns the context of the stream.
121+ //
122+ // NOTE: This implements the grpc.ServerStream Context method.
123+ func (w * wrappedServerStream ) Context () context.Context {
124+ return w .ctx
125+ }
126+
127+ // addSessionIDToStreamCtx is a gRPC stream interceptor that adds the given
128+ // session ID to the context of the stream. This allows us to access the
129+ // session ID later on for any gRPC calls made through this stream.
130+ func addSessionIDToStreamCtx (id session.ID ) grpc.ServerOption {
131+ return grpc .StreamInterceptor (func (srv any , ss grpc.ServerStream ,
132+ info * grpc.StreamServerInfo ,
133+ handler grpc.StreamHandler ) error {
134+
135+ md , _ := metadata .FromIncomingContext (ss .Context ())
136+ mdCopy := md .Copy ()
137+ session .AddToGRPCMetadata (mdCopy , id )
138+
139+ // Wrap the original stream with our custom context.
140+ wrapped := & wrappedServerStream {
141+ ServerStream : ss ,
142+ ctx : metadata .NewIncomingContext (
143+ ss .Context (), mdCopy ,
144+ ),
145+ }
146+
147+ return handler (srv , wrapped )
148+ })
149+ }
150+
151+ // addSessionIDToUnaryCtx is a gRPC unary interceptor that adds the given
152+ // session ID to the context of the unary call. This allows us to access the
153+ // session ID later on for any gRPC calls made through this context.
154+ func addSessionIDToUnaryCtx (id session.ID ) grpc.ServerOption {
155+ return grpc .UnaryInterceptor (func (ctx context.Context , req any ,
156+ info * grpc.UnaryServerInfo ,
157+ handler grpc.UnaryHandler ) (resp any , err error ) {
158+
159+ md , _ := metadata .FromIncomingContext (ctx )
160+ mdCopy := md .Copy ()
161+ session .AddToGRPCMetadata (mdCopy , id )
162+
163+ return handler (metadata .NewIncomingContext (ctx , mdCopy ), req )
164+ })
165+ }
166+
97167// start all the components necessary for the sessionRpcServer to start serving
98168// requests. This includes resuming all non-revoked sessions.
99169func (s * sessionRpcServer ) start (ctx context.Context ) error {
0 commit comments