blob: b048b7c4a7e334925fd2953e702c2584368b27b2 [file] [log] [blame]
package naming
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
"veyron2/ipc/version"
"veyron2/naming"
)
const (
separator = "@"
suffix = "@@"
)
var errInvalidEndpointString = errors.New("invalid endpoint string")
// Network is the string returned by naming.Endpoint.Network implementations
// defined in this package.
const Network = "veyron"
// Endpoint is a naming.Endpoint implementation used to convey RPC information.
type Endpoint struct {
Protocol string
Address string
RID naming.RoutingID
MinIPCVersion version.IPCVersion
MaxIPCVersion version.IPCVersion
}
// NewEndpoint creates a new endpoint from a string as per naming.NewEndpoint
func NewEndpoint(input string) (naming.Endpoint, error) {
var ep Endpoint
// The prefix and suffix are optional.
input = strings.TrimPrefix(strings.TrimSuffix(input, suffix), separator)
parts := strings.Split(input, separator)
if len(parts) == 1 {
err := ep.parseHostPort(parts[0])
return &ep, err
}
version, err := strconv.ParseUint(parts[0], 10, 16)
if err != nil {
return nil, fmt.Errorf("invalid version: %v", err)
}
switch version {
case 1:
err = ep.parseV1(parts)
case 2:
err = ep.parseV2(parts)
default:
err = errInvalidEndpointString
}
return &ep, err
}
func (ep *Endpoint) parseHostPort(input string) error {
// Could be in host:port format.
if _, _, err := net.SplitHostPort(input); err != nil {
return errInvalidEndpointString
}
ep.Protocol = "tcp"
ep.Address = input
ep.RID = naming.NullRoutingID
return nil
}
func (ep *Endpoint) parseV1(parts []string) error {
if len(parts) != 4 {
return errInvalidEndpointString
}
ep.Protocol = parts[1]
if len(ep.Protocol) == 0 {
ep.Protocol = "tcp"
}
ep.Address = parts[2]
if len(ep.Address) == 0 {
ep.Address = net.JoinHostPort("", "0")
}
if err := ep.RID.FromString(parts[3]); err != nil {
return fmt.Errorf("invalid routing id: %v", err)
}
return nil
}
func parseIPCVersion(input string) (version.IPCVersion, error) {
if input == "" {
return version.UnknownIPCVersion, nil
}
v, err := strconv.ParseUint(input, 10, 32)
if err != nil {
err = fmt.Errorf("invalid IPC version: %s, %v", err)
}
return version.IPCVersion(v), err
}
func printIPCVersion(v version.IPCVersion) string {
if v == version.UnknownIPCVersion {
return ""
}
return strconv.FormatUint(uint64(v), 10)
}
func (ep *Endpoint) parseV2(parts []string) error {
var err error
if len(parts) != 6 {
return errInvalidEndpointString
}
if err = ep.parseV1(parts[:4]); err != nil {
return err
}
if ep.MinIPCVersion, err = parseIPCVersion(parts[4]); err != nil {
return fmt.Errorf("invalid IPC version: %v", err)
}
if ep.MaxIPCVersion, err = parseIPCVersion(parts[5]); err != nil {
return fmt.Errorf("invalid IPC version: %v", err)
}
return nil
}
func (ep *Endpoint) RoutingID() naming.RoutingID { return ep.RID }
func (ep *Endpoint) Network() string { return Network }
func (ep *Endpoint) String() string {
return fmt.Sprintf("%s2@%s@%s@%s@%s@%s@@",
separator, ep.Protocol, ep.Address, ep.RID,
printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion))
}
func (ep *Endpoint) version() int { return 2 }
func (ep *Endpoint) Addr() net.Addr {
return &addr{network: ep.Protocol, address: ep.Address}
}
type addr struct {
network, address string
}
func (a *addr) Network() string {
return a.network
}
func (a *addr) String() string {
return a.address
}