Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add unix protocol support #84

Merged
merged 3 commits into from
Feb 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 13 additions & 1 deletion src/codec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ function stringToStringTuples (str) {
throw ParseError('invalid address: ' + str)
}

// if it's a path proto, take the rest
if (proto.path) {
tuples.push([
part,
// TODO: should we need to check each path part to see if it's a proto?
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can go with this now, and when we add new protocols we thing about it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. It should be reasonable for us to have an address that's /unix/a/b/c/d/e/f/ip4/0.0.0.0/tcp/1234, but users would need to avoid addresses like /unix/c/p2p/d.sock/ip4/0.0.0.0/tcp/12341, since it has a proto name in the unix path. Having at least basic support for unix addresses is the important thing right now.

// This would allow for other protocols to be added after a unix path,
// however it would have issues if the path had a protocol name in the path
cleanPath(parts.slice(p).join('/'))
])
break
}

tuples.push([part, parts[p]])
}

Expand All @@ -69,7 +81,7 @@ function stringTuplesToString (tuples) {
}
})

return '/' + parts.join('/')
return cleanPath(parts.join('/'))
}

// [[str name, str addr]... ] -> [[int code, Buffer]... ]
Expand Down
4 changes: 4 additions & 0 deletions src/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ Convert.toString = function convertToString (proto, buf) {
case 132: // sctp
return buf2port(buf)

case 53: // dns
case 54: // dns4
case 55: // dns6
case 56: // dnsaddr
case 400: // unix
return buf2str(buf)

case 421: // ipfs
Expand All @@ -56,9 +58,11 @@ Convert.toBuffer = function convertToBuffer (proto, str) {
case 132: // sctp
return port2buf(parseInt(str, 10))

case 53: // dns
case 54: // dns4
case 55: // dns6
case 56: // dnsaddr
case 400: // unix
return str2buf(str)

case 421: // ipfs
Expand Down
27 changes: 27 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,33 @@ Multiaddr.prototype.getPeerId = function getPeerId () {
return b58str
}

/**
* Extract the path if the multiaddr contains one
*
* @return {String|null} path - The path of the multiaddr, or null if no path protocol is present
* @example
* const mh1 = Multiaddr('/ip4/8.8.8.8/tcp/1080/unix/tmp/p2p.sock')
* // <Multiaddr 0408080808060438 - /ip4/8.8.8.8/tcp/1080/unix/tmp/p2p.sock>
*
* // should return utf8 string or null if the id is missing or invalid
* const path = mh1.getPath()
*/
Multiaddr.prototype.getPath = function getPath () {
let path = null
try {
path = this.stringTuples().filter((tuple) => {
const proto = protocols(tuple[0])
if (proto.path) {
return true
}
})[0][1]
} catch (e) {
path = null
}

return path
}

/**
* Checks if two Multiaddrs are the same
*
Expand Down
29 changes: 18 additions & 11 deletions src/protocols-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,38 @@ Protocols.V = V
Protocols.table = [
[4, 32, 'ip4'],
[6, 16, 'tcp'],
[273, 16, 'udp'],
[33, 16, 'dccp'],
[41, 128, 'ip6'],
[42, V, 'ip6zone'],
[53, V, 'dns', 'resolvable'],
[54, V, 'dns4', 'resolvable'],
[55, V, 'dns6', 'resolvable'],
[56, V, 'dnsaddr', 'resolvable'],
[132, 16, 'sctp'],
// all of the below use varint for size
[273, 16, 'udp'],
[275, 0, 'p2p-webrtc-star'],
[276, 0, 'p2p-webrtc-direct'],
[277, 0, 'p2p-stardust'],
[290, 0, 'p2p-circuit'],
[301, 0, 'udt'],
[302, 0, 'utp'],
[400, V, 'unix', false, 'path'],
// `p2p` is the preferred name for 421
[421, Protocols.lengthPrefixedVarSize, 'p2p'],
[421, V, 'p2p'],
// `ipfs` has been added after `p2p` so that it is used by default.
// The reason for this is to provide better backwards support for
// code bases that do not yet support the `p2p` proto name. Eventually
// `p2p` should become the default.
[421, Protocols.lengthPrefixedVarSize, 'ipfs'],
[480, 0, 'http'],
[421, V, 'ipfs'],
[443, 0, 'https'],
[444, 96, 'onion'],
[445, 296, 'onion3'],
[446, V, 'garlic64'],
[460, 0, 'quic'],
[477, 0, 'ws'],
[478, 0, 'wss'],
[479, 0, 'p2p-websocket-star'],
[277, 0, 'p2p-stardust'],
[275, 0, 'p2p-webrtc-star'],
[276, 0, 'p2p-webrtc-direct'],
[290, 0, 'p2p-circuit']
[480, 0, 'http']
]

Protocols.names = {}
Expand All @@ -65,12 +71,13 @@ Protocols.table.map(row => {

Protocols.object = p

function p (code, size, name, resolvable) {
function p (code, size, name, resolvable, path) {
return {
code: code,
size: size,
name: name,
resolvable: Boolean(resolvable)
resolvable: Boolean(resolvable),
path: Boolean(path)
}
}

Expand Down
79 changes: 79 additions & 0 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,13 +260,27 @@ describe('variants', () => {
expect(addr.toString()).to.equal(str)
})

it('ip4 + tcp + unix', () => {
const str = '/ip4/127.0.0.1/tcp/80/unix/a/b/c/d/e/f'
const addr = multiaddr(str)
expect(addr).to.have.property('buffer')
expect(addr.toString()).to.equal(str)
})

it('ip6 + tcp + http', () => {
const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/http'
const addr = multiaddr(str)
expect(addr).to.have.property('buffer')
expect(addr.toString()).to.equal(str)
})

it('ip6 + tcp + unix', () => {
const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/unix/a/b/c/d/e/f'
const addr = multiaddr(str)
expect(addr).to.have.property('buffer')
expect(addr.toString()).to.equal(str)
})

it('ip4 + tcp + https', () => {
const str = '/ip4/127.0.0.1/tcp/8000/https'
const addr = multiaddr(str)
Expand Down Expand Up @@ -323,6 +337,13 @@ describe('variants', () => {
expect(addr.toString()).to.equal(str.replace('/p2p/', '/ipfs/'))
})

it('unix', () => {
const str = '/unix/a/b/c/d/e'
const addr = multiaddr(str)
expect(addr).to.have.property('buffer')
expect(addr.toString()).to.equal(str)
})

it('p2p', () => {
const str = '/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC'
const addr = multiaddr(str)
Expand Down Expand Up @@ -413,11 +434,13 @@ describe('helpers', () => {
.to.eql([{
code: 4,
name: 'ip4',
path: false,
size: 32,
resolvable: false
}, {
code: 302,
name: 'utp',
path: false,
size: 0,
resolvable: false
}])
Expand All @@ -429,16 +452,19 @@ describe('helpers', () => {
).to.be.eql([{
code: 4,
name: 'ip4',
path: false,
size: 32,
resolvable: false
}, {
code: 302,
name: 'utp',
path: false,
size: 0,
resolvable: false
}, {
code: 421,
name: 'ipfs',
path: false,
size: -1,
resolvable: false
}])
Expand All @@ -450,16 +476,43 @@ describe('helpers', () => {
).to.be.eql([{
code: 4,
name: 'ip4',
path: false,
size: 32,
resolvable: false
}, {
code: 302,
name: 'utp',
path: false,
size: 0,
resolvable: false
}, {
code: 421,
name: 'ipfs',
path: false,
size: -1,
resolvable: false
}])
})

it('works with unix', () => {
expect(
multiaddr('/ip4/0.0.0.0/tcp/8000/unix/tmp/p2p.sock').protos()
).to.be.eql([{
code: 4,
name: 'ip4',
path: false,
size: 32,
resolvable: false
}, {
code: 6,
name: 'tcp',
path: false,
size: 16,
resolvable: false
}, {
code: 400,
name: 'unix',
path: true,
size: -1,
resolvable: false
}])
Expand Down Expand Up @@ -663,6 +716,26 @@ describe('helpers', () => {
})
})

describe('.getPath', () => {
it('should return a path for unix', () => {
expect(
multiaddr('/unix/tmp/p2p.sock').getPath()
).to.eql('/tmp/p2p.sock')
})

it('should return a path for unix when other protos exist', () => {
expect(
multiaddr('/ip4/0.0.0.0/tcp/1234/unix/tmp/p2p.sock').getPath()
).to.eql('/tmp/p2p.sock')
})

it('should not return a path when no path proto exists', () => {
expect(
multiaddr('/ip4/0.0.0.0/tcp/1234/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPath()
).to.eql(null)
})
})

describe('multiaddr.isMultiaddr', () => {
it('handles different inputs', () => {
expect(multiaddr.isMultiaddr(multiaddr('/'))).to.be.eql(true)
Expand All @@ -676,6 +749,12 @@ describe('helpers', () => {
describe('resolvable multiaddrs', () => {
describe('.isName', () => {
it('valid name dns', () => {
const str = '/dns/ipfs.io'
const addr = multiaddr(str)
expect(multiaddr.isName(addr)).to.equal(true)
})

it('valid name dnsaddr', () => {
const str = '/dnsaddr/ipfs.io'
const addr = multiaddr(str)
expect(multiaddr.isName(addr)).to.equal(true)
Expand Down