blob: a5836104387ac88dbf73c27368a59abc0877fadb [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package flow
import (
"fmt"
"sync"
"time"
"v.io/v23/context"
"v.io/v23/naming"
)
// Protocol is the interface that protocols for use with vanadium RPCs must implement.
type Protocol interface {
// Dial is the function used to create Conn objects given a
// protocol-specific string representation of an address.
// The returned Conn must also frame the connection.
Dial(ctx *context.T, protocol, address string, timeout time.Duration) (Conn, error)
// Resolve is the function used for protocol-specific address normalization.
// e.g. the TCP resolve performs DNS resolution.
// Resolve returns the protocol and resolved addresses.
Resolve(ctx *context.T, protocol, address string) (string, []string, error)
// Listen is the function used to create Listener objects given a
// protocol-specific string representation of the address a server will listen on.
// The Conns returned from Listener must frame connections.
Listen(ctx *context.T, protocol, address string) (Listener, error)
}
// RegisterProtocol makes available a Protocol to RegisteredProtocol.
// If the protocol represents other actual protocols, you need to specify all the
// actual protocols. E.g, "wsh" represents "tcp4", "tcp6", "ws4", and "ws6".
//
// Implementations of the Manager interface are expected to use this registry
// in order to expand the reach of the types of network protocols they can
// handle.
//
// Successive calls to RegisterProtocol replace the contents of a previous
// call to it and returns trues if a previous value was replaced, false otherwise.
func RegisterProtocol(protocol string, obj Protocol, p ...string) bool {
// This is for handling the common case where protocol is a "singleton", to
// make it easier to specify.
if len(p) == 0 {
p = []string{protocol}
}
registryLock.Lock()
defer registryLock.Unlock()
_, present := registry[protocol]
registry[protocol] = registryEntry{obj, p}
return present
}
// RegisterUnknownProtocol registers a Protocol for endpoints with
// no specified protocol.
//
// The desired protocol provided in the first argument will be passed to the
// Protocol methods as the actual protocol to use when dialing, resolving, or listening.
//
// The protocol itself must have already been registered before RegisterUnknownProtocol
// is called, otherwise we'll panic.
func RegisterUnknownProtocol(protocol string, obj Protocol) bool {
var p []string
registryLock.RLock()
r, present := registry[protocol]
if !present {
panic(fmt.Sprintf("%s not registered", protocol))
}
p = r.p
registryLock.RUnlock()
return RegisterProtocol(naming.UnknownProtocol, wrappedProtocol{protocol, obj}, p...)
}
type wrappedProtocol struct {
protocol string
obj Protocol
}
func (p wrappedProtocol) Dial(ctx *context.T, _, address string, timeout time.Duration) (Conn, error) {
return p.obj.Dial(ctx, p.protocol, address, timeout)
}
func (p wrappedProtocol) Resolve(ctx *context.T, _, address string) (string, []string, error) {
return p.obj.Resolve(ctx, p.protocol, address)
}
func (p wrappedProtocol) Listen(ctx *context.T, _, address string) (Listener, error) {
return p.obj.Listen(ctx, p.protocol, address)
}
// RegisteredProtocol returns the Protocol object registered with a
// previous call to RegisterProtocol.
func RegisteredProtocol(protocol string) (Protocol, []string) {
registryLock.RLock()
e := registry[protocol]
registryLock.RUnlock()
return e.obj, e.p
}
// RegisteredProtocols returns the list of protocols that have been previously
// registered using RegisterProtocol. The underlying implementation will
// support additional protocols such as those supported by the native RPC stack.
func RegisteredProtocols() []string {
registryLock.RLock()
defer registryLock.RUnlock()
p := make([]string, 0, len(registry))
for k, _ := range registry {
p = append(p, k)
}
return p
}
type registryEntry struct {
obj Protocol
p []string
}
var (
registryLock sync.RWMutex
registry = make(map[string]registryEntry)
)