Skip to content
This repository was archived by the owner on Oct 5, 2021. It is now read-only.

make multiaddr-net more pluggable #15

Merged
merged 5 commits into from
May 16, 2016
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
256 changes: 171 additions & 85 deletions convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,112 +4,198 @@ import (
"fmt"
"net"
"strings"
"sync"

ma "github.com/jbenet/go-multiaddr"
utp "github.com/jbenet/go-multiaddr-net/utp"
)

var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion")

type AddrParser func(a net.Addr) (ma.Multiaddr, error)
type MaddrParser func(ma ma.Multiaddr) (net.Addr, error)

var maddrParsers map[string]MaddrParser
var addrParsers map[string]AddrParser
var addrParsersLock sync.Mutex

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A concurrency test or two would be nice to have.


func init() {
addrParsers = make(map[string]AddrParser)
maddrParsers = make(map[string]MaddrParser)

registerDefaultAddrParsers()
registerDefaultMaddrParsers()
}

func registerDefaultAddrParsers() {
funcs := map[string]AddrParser{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about adding the default addr/maddr parsers using the public RegisterAddressType?

My thinking is that if it's awkward or undesirable to do so, then that may be a signal that the public API needs some massaging to be likeable enough to use for registering them internally too. Does that make sense?

"tcp": ParseTcpNetAddr,
"udp": ParseUdpNetAddr,
"utp": ParseUtpNetAddr,
"ip": ParseIpNetAddr,
}

for k, v := range funcs {
addrParsers[k] = v
addrParsers[k+"4"] = v
addrParsers[k+"6"] = v
}

addrParsers["ip+net"] = ParseIpPlusNetAddr
}

func RegisterAddressType(netname, maname string, ap AddrParser, mp MaddrParser) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a test for this would be nice to have.

addrParsersLock.Lock()
defer addrParsersLock.Unlock()
addrParsers[netname] = ap
maddrParsers[maname] = mp
}

func ParseTcpNetAddr(a net.Addr) (ma.Multiaddr, error) {
Copy link

@hackergrrl hackergrrl May 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the Parse* methods need to be public? If so, tests would be awesome!

ac, ok := a.(*net.TCPAddr)
if !ok {
return nil, errIncorrectNetAddr
}

// Get IP Addr
ipm, err := FromIP(ac.IP)
if err != nil {
return nil, errIncorrectNetAddr
}

// Get TCP Addr
tcpm, err := ma.NewMultiaddr(fmt.Sprintf("/tcp/%d", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}

// Encapsulate
return ipm.Encapsulate(tcpm), nil
}

func ParseUdpNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.UDPAddr)
if !ok {
return nil, errIncorrectNetAddr
}

// Get IP Addr
ipm, err := FromIP(ac.IP)
if err != nil {
return nil, errIncorrectNetAddr
}

// Get UDP Addr
udpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}

// Encapsulate
return ipm.Encapsulate(udpm), nil
}

func ParseUtpNetAddr(a net.Addr) (ma.Multiaddr, error) {
acc, ok := a.(*utp.Addr)
if !ok {
return nil, errIncorrectNetAddr
}

// Get UDP Addr
ac, ok := acc.Child().(*net.UDPAddr)
if !ok {
return nil, errIncorrectNetAddr
}

// Get IP Addr
ipm, err := FromIP(ac.IP)
if err != nil {
return nil, errIncorrectNetAddr
}

// Get UDP Addr
utpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d/utp", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}

// Encapsulate
return ipm.Encapsulate(utpm), nil
}

func ParseIpNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.IPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIP(ac.IP)
}

func ParseIpPlusNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.IPNet)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIP(ac.IP)
}

func getAddrParser(net string) (AddrParser, error) {
addrParsersLock.Lock()
defer addrParsersLock.Unlock()

parser, ok := addrParsers[net]
if !ok {
return nil, fmt.Errorf("unknown network %v", net)
}
return parser, nil
}

// FromNetAddr converts a net.Addr type to a Multiaddr.
func FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
if a == nil {
return nil, fmt.Errorf("nil multiaddr")
}
p, err := getAddrParser(a.Network())
if err != nil {
return nil, err
}

switch a.Network() {
case "tcp", "tcp4", "tcp6":
ac, ok := a.(*net.TCPAddr)
if !ok {
return nil, errIncorrectNetAddr
}

// Get IP Addr
ipm, err := FromIP(ac.IP)
if err != nil {
return nil, errIncorrectNetAddr
}

// Get TCP Addr
tcpm, err := ma.NewMultiaddr(fmt.Sprintf("/tcp/%d", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}

// Encapsulate
return ipm.Encapsulate(tcpm), nil

case "udp", "upd4", "udp6":
ac, ok := a.(*net.UDPAddr)
if !ok {
return nil, errIncorrectNetAddr
}

// Get IP Addr
ipm, err := FromIP(ac.IP)
if err != nil {
return nil, errIncorrectNetAddr
}

// Get UDP Addr
udpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}

// Encapsulate
return ipm.Encapsulate(udpm), nil

case "utp", "utp4", "utp6":
acc, ok := a.(*utp.Addr)
if !ok {
return nil, errIncorrectNetAddr
}

// Get UDP Addr
ac, ok := acc.Child().(*net.UDPAddr)
if !ok {
return nil, errIncorrectNetAddr
}

// Get IP Addr
ipm, err := FromIP(ac.IP)
if err != nil {
return nil, errIncorrectNetAddr
}

// Get UDP Addr
utpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d/utp", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}

// Encapsulate
return ipm.Encapsulate(utpm), nil

case "ip", "ip4", "ip6":
ac, ok := a.(*net.IPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIP(ac.IP)

case "ip+net":
ac, ok := a.(*net.IPNet)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIP(ac.IP)
return p(a)
}

default:
return nil, fmt.Errorf("unknown network %v", a.Network())
func getMaddrParser(name string) (MaddrParser, error) {
addrParsersLock.Lock()
defer addrParsersLock.Unlock()
p, ok := maddrParsers[name]
if !ok {
return nil, fmt.Errorf("network not supported: %s", name)
}

return p, nil
}

// ToNetAddr converts a Multiaddr to a net.Addr
// Must be ThinWaist. acceptable protocol stacks are:
// /ip{4,6}/{tcp, udp}
func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
protos := maddr.Protocols()
final := protos[len(protos)-1]

p, err := getMaddrParser(final.Name)
if err != nil {
return nil, err
}

return p(maddr)
}

func registerDefaultMaddrParsers() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're keeping this (i.e. not using the public API for registering), could we move it up to live with the registerDefaultAddrParsers?

for _, net := range []string{"tcp", "udp", "utp", "ip", "ip4", "ip6"} {
maddrParsers[net] = parseBasicNetAddr
}
}

func parseBasicNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
network, host, err := DialArgs(maddr)
if err != nil {
return nil, err
Expand Down