blob: 7b3251c322102758177089431e0a7a96d7e16e94 [file] [log] [blame]
package rt
import (
"errors"
"fmt"
iipc "veyron.io/veyron/veyron/runtimes/google/ipc"
imanager "veyron.io/veyron/veyron/runtimes/google/ipc/stream/manager"
"veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"
iversion "veyron.io/veyron/veyron/runtimes/google/ipc/version"
ivtrace "veyron.io/veyron/veyron/runtimes/google/vtrace"
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/i18n"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/ipc/stream"
"veyron.io/veyron/veyron2/ipc/version"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/options"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/verror2"
"veyron.io/veyron/veyron2/vtrace"
)
// fixedPublicIDStore implements security.PublicIDStore. It embeds a (fixed) PublicID that
// is both the default and the PublicID to be used for any peer. Adding a new PublicID
// to the store is disallowed, and setting the default principal-pattern is a no-op.
type fixedPublicIDStore struct {
id security.PublicID
}
func (fixedPublicIDStore) Add(id security.PublicID, peerPattern security.BlessingPattern) error {
return errors.New("adding new PublicIDs is disallowed for this PublicIDStore")
}
func (s fixedPublicIDStore) ForPeer(peer security.PublicID) (security.PublicID, error) {
return s.id, nil
}
func (s fixedPublicIDStore) DefaultPublicID() (security.PublicID, error) {
return s.id, nil
}
func (fixedPublicIDStore) SetDefaultBlessingPattern(pattern security.BlessingPattern) error {
return errors.New("SetDefaultBlessingPattern is disallowed on a fixed PublicIDStore")
}
// localID is an option for passing a PrivateID and PublicIDStore
// to a server or client.
type localID struct {
id security.PrivateID
store security.PublicIDStore
}
func (lID *localID) Sign(message []byte) (security.Signature, error) {
return lID.id.Sign(message)
}
func (lID *localID) AsClient(server security.PublicID) (security.PublicID, error) {
return lID.store.ForPeer(server)
}
func (lID *localID) AsServer() (security.PublicID, error) {
return lID.store.DefaultPublicID()
}
func (*localID) IPCClientOpt() {
//nologcall
}
func (*localID) IPCStreamVCOpt() {}
func (*localID) IPCServerOpt() {
//nologcall
}
func (*localID) IPCStreamListenerOpt() {}
// newLocalID returns a localID embedding the runtime's PrivateID and a fixed
// PublicIDStore constructed from the provided PublicID or the runtiume's PublicIDStore
// if the provided PublicID is nil.
func (rt *vrt) newLocalID(id security.PublicID) vc.LocalID {
lID := &localID{id: rt.id, store: rt.store}
if id != nil {
lID.store = fixedPublicIDStore{id}
}
return lID
}
func (rt *vrt) NewClient(opts ...ipc.ClientOpt) (ipc.Client, error) {
rt.mu.Lock()
sm := rt.sm[0]
rt.mu.Unlock()
ns := rt.ns
var id security.PublicID
var otherOpts []ipc.ClientOpt
for _, opt := range opts {
switch topt := opt.(type) {
case options.StreamManager:
sm = topt.Manager
case options.Namespace:
ns = topt.Namespace
case options.LocalID:
id = topt.PublicID
default:
otherOpts = append(otherOpts, opt)
}
}
// Add the option that provides the local identity to the client.
otherOpts = append(otherOpts, rt.newLocalID(id), vc.LocalPrincipal{rt.principal})
if !rt.useNewSecurityModelInIPCClients {
otherOpts = append(otherOpts, &iversion.Range{Min: version.IPCVersion2, Max: version.IPCVersion3})
}
return iipc.InternalNewClient(sm, ns, otherOpts...)
}
func (rt *vrt) Client() ipc.Client {
return rt.client
}
func (rt *vrt) NewContext() context.T {
ctx := iipc.InternalNewContext(rt)
ctx = i18n.ContextWithLangID(ctx, rt.lang)
ctx = verror2.ContextWithComponentName(ctx, rt.program)
ctx, _ = ivtrace.WithNewSpan(ctx, "") // Initial span has empty name.
return ctx
}
func (rt *vrt) WithNewSpan(ctx context.T, name string) (context.T, vtrace.Span) {
return ivtrace.WithNewSpan(ctx, name)
}
func (rt *vrt) SpanFromContext(ctx context.T) vtrace.Span {
return ivtrace.FromContext(ctx)
}
func (rt *vrt) NewServer(opts ...ipc.ServerOpt) (ipc.Server, error) {
rt.mu.Lock()
// Create a new RoutingID (and StreamManager) for each server, except
// the first one. The reasoning is for the first server to share the
// RoutingID (and StreamManager) with Clients.
//
// TODO(ashankar/caprita): special-casing the first server is ugly, and
// has diminished practical benefits since the first server in practice
// is the app cycle manager server. If the goal of sharing connections
// between Clients and Servers in the same Runtime is still important,
// we need to think of other ways to achieve it.
sm := rt.sm[0]
rt.nServers++
nServers := rt.nServers
rt.mu.Unlock()
if nServers > 1 {
var err error
sm, err = rt.NewStreamManager()
if err != nil {
return nil, fmt.Errorf("failed to create ipc/stream/Manager: %v", err)
}
}
ns := rt.ns
var id security.PublicID
var otherOpts []ipc.ServerOpt
for _, opt := range opts {
switch topt := opt.(type) {
case options.Namespace:
ns = topt
case options.LocalID:
id = topt.PublicID
default:
otherOpts = append(otherOpts, opt)
}
}
// Add the option that provides the local identity to the server.
otherOpts = append(otherOpts, rt.newLocalID(id), vc.LocalPrincipal{rt.principal})
ctx := rt.NewContext()
return iipc.InternalNewServer(ctx, sm, ns, otherOpts...)
}
func (rt *vrt) NewStreamManager(opts ...stream.ManagerOpt) (stream.Manager, error) {
rid, err := naming.NewRoutingID()
if err != nil {
return nil, err
}
sm := imanager.InternalNew(rid)
rt.mu.Lock()
defer rt.mu.Unlock()
if rt.cleaningUp {
sm.Shutdown() // For whatever it's worth.
return nil, errCleaningUp
}
rt.sm = append(rt.sm, sm)
return sm, nil
}