Compare commits

...

36 Commits

Author SHA1 Message Date
c7f695bf4b chore: update deps and more non Travis ci
chore: improve test listener closures

License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2019-02-27 15:09:52 +01:00
8279d3500c chore: remove travis test bail
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2019-02-26 19:42:02 +01:00
9660c3daee chore: add missing npm script for aegir
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2019-02-26 19:21:04 +01:00
ea762d12ee chore: remove unneeded deps
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2019-02-26 19:18:35 +01:00
eedc264a9a chore: remove browser builds from travis
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2019-02-26 19:12:49 +01:00
5ce2566885 chore: use travis and update badges
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2019-02-26 19:06:34 +01:00
2be751a758 chore: update deps
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2019-02-26 19:02:08 +01:00
2ab529ec31 test: rename file to fix coverage
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-11-15 20:08:44 +01:00
4f80c195a8 chore: fix test runner for aegir on jenkins
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-11-15 19:29:54 +01:00
537ebee0b4 fix: allow internal
libp2p should eventually handle listen versus announce addresses, this helps with ip6 support in the interim

License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-11-15 19:21:36 +01:00
5f8571efb0 fix: only expose external hosts
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-11-09 23:50:24 +01:00
299b795f8a chore: fix linting
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-11-09 23:15:09 +01:00
c9e8dd5714 feat: add support for ip6 wildcards
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-11-09 23:10:52 +01:00
3ab43a3604 chore: prefer const over let (#99)
Prefer const over let when the binding is static, in order to comply with an upcoming Standard rule.
2018-10-31 08:35:55 +00:00
3aad2ed243 chore: release version v0.13.0
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-09-12 19:40:49 +02:00
01cfbda2e7 chore: update contributors 2018-09-12 19:40:49 +02:00
eba0b48744 feat: add support for dialing over dns
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-09-12 19:38:02 +02:00
a0c23e49f7 chore: release version v0.12.1
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-07-31 14:13:11 +02:00
66ab208182 chore: update contributors 2018-07-31 14:13:10 +02:00
168d111158 chore: update deps and fix test runner
License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>
2018-07-31 14:08:31 +02:00
4b04b17dfa fix: invalid ip address and daemon can be crashed by remote user
Per the nodeJS documentation, a Net socket.remoteAddress value may
be undefined if the socket is destroyed, as by a client disconnect.
A multiaddr cannot be created for an invalid IP address (such as
the undefined remote address of a destroyed socket). Currently
the attempt results in a crash that can be triggered remotely. This
commit catches the exception in get-multiaddr and returns an
undefined value to listener rather than throwing an exception when
trying to process defective or destroyed socket data. Listener then
terminates processing of the incoming p2p connections that generate
this error condition.

fixes: https://github.com/libp2p/js-libp2p-tcp/issues/93
fixes: https://github.com/ipfs/js-ipfs/issues/1447
2018-07-31 13:51:27 +02:00
6c36a46831 test: fixes listen-dial test "dial and destroy on listener" (#97) 2018-07-31 13:46:12 +02:00
d39ec2db40 chore: add lead maintainer (#94)
* chore: add lead maintainer

License: MIT
Signed-off-by: Jacob Heun <jacobheun@gmail.com>

* Update package.json
2018-06-26 17:58:30 +02:00
79428f3e62 chore: release version v0.12.0 2018-04-05 17:00:33 +01:00
8a394b5286 chore: update contributors 2018-04-05 17:00:33 +01:00
b7f73bcda1 test: fix dial error test 2018-04-05 17:00:19 +01:00
8b44aa28ee chore: update deps 2018-04-05 16:56:23 +01:00
ded1f6831c feat: add class-is module 2018-04-05 16:55:54 +01:00
5ef24695fc docs: fixing the broken example in README (#91)
* Working example fix

* Char fix

* Corrected output, and add yarn to gitignore
2018-04-05 16:55:25 +01:00
df0aa059ca chore: release version v0.11.6 2018-02-20 10:27:27 +00:00
bf74e9acad chore: update contributors 2018-02-20 10:27:26 +00:00
83c4617e8d chore: update deps 2018-02-20 10:27:17 +00:00
3b7e68bc8a docs: update and polish 2018-02-20 10:25:18 +00:00
de1d7fe75c chore: tiny refactor 2018-02-07 06:40:00 +00:00
9c77a69ae3 chore: tiny refactor 2018-02-07 06:26:02 +00:00
50840a8067 test: refactor 2018-02-07 06:06:15 +00:00
16 changed files with 305 additions and 237 deletions

3
.gitignore vendored
View File

@ -4,6 +4,9 @@ docs
test/repo-tests* test/repo-tests*
**/bundle.js **/bundle.js
# yarn
yarn.lock
# Logs # Logs
logs logs
*.log *.log

View File

@ -1,32 +1,28 @@
# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
sudo: false
language: node_js language: node_js
cache: npm
stages:
- check
- test
- cov
matrix: node_js:
- '10'
os:
- linux
- osx
- windows
script: npx nyc -s npm run test:node
after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
jobs:
include: include:
- node_js: 6 - stage: check
env: CXX=g++-4.8 script:
- node_js: 8 - npx aegir commitlint --travis
env: CXX=g++-4.8 - npx aegir dep-check
# - node_js: stable - npm run lint
# env: CXX=g++-4.8
script: notifications:
- npm run lint email: false
- npm run test
- npm run coverage
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
after_success:
- npm run coverage-publish
addons:
firefox: 'latest'
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8

View File

@ -1,3 +1,38 @@
<a name="0.13.0"></a>
# [0.13.0](https://github.com/libp2p/js-libp2p-tcp/compare/v0.12.1...v0.13.0) (2018-09-12)
### Features
* add support for dialing over dns ([eba0b48](https://github.com/libp2p/js-libp2p-tcp/commit/eba0b48))
<a name="0.12.1"></a>
## [0.12.1](https://github.com/libp2p/js-libp2p-tcp/compare/v0.12.0...v0.12.1) (2018-07-31)
### Bug Fixes
* invalid ip address and daemon can be crashed by remote user ([4b04b17](https://github.com/libp2p/js-libp2p-tcp/commit/4b04b17))
<a name="0.12.0"></a>
# [0.12.0](https://github.com/libp2p/js-libp2p-tcp/compare/v0.11.6...v0.12.0) (2018-04-05)
### Features
* add class-is module ([ded1f68](https://github.com/libp2p/js-libp2p-tcp/commit/ded1f68))
<a name="0.11.6"></a>
## [0.11.6](https://github.com/libp2p/js-libp2p-tcp/compare/v0.11.5...v0.11.6) (2018-02-20)
<a name="0.11.5"></a> <a name="0.11.5"></a>
## [0.11.5](https://github.com/libp2p/js-libp2p-tcp/compare/v0.11.4...v0.11.5) (2018-02-07) ## [0.11.5](https://github.com/libp2p/js-libp2p-tcp/compare/v0.11.4...v0.11.5) (2018-02-07)

View File

@ -1,31 +1,30 @@
# js-libp2p-tcp # js-libp2p-tcp
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) [![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
[![Build Status](https://travis-ci.org/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://travis-ci.org/libp2p/js-libp2p-tcp) [![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p)
[![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-tcp/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-tcp?branch=master) [![](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-tcp)
[![](https://img.shields.io/travis/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://travis-ci.com/libp2p/js-libp2p-tcp)
[![Dependency Status](https://david-dm.org/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-tcp) [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-tcp)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
![](https://img.shields.io/badge/npm-%3E%3D3.0.0-orange.svg?style=flat-square) ![](https://img.shields.io/badge/npm-%3E%3D6.0.0-orange.svg?style=flat-square)
![](https://img.shields.io/badge/Node.js-%3E%3D6.0.0-orange.svg?style=flat-square) ![](https://img.shields.io/badge/Node.js-%3E%3D10.0.0-orange.svg?style=flat-square)
![](https://raw.githubusercontent.com/libp2p/interface-connection/master/img/badge.png) [![](https://raw.githubusercontent.com/libp2p/interface-transport/master/img/badge.png)](https://github.com/libp2p/interface-transport)
![](https://raw.githubusercontent.com/libp2p/interface-transport/master/img/badge.png) [![](https://raw.githubusercontent.com/libp2p/interface-connection/master/img/badge.png)](https://github.com/libp2p/interface-connection)
> Node.js implementation of the TCP module that libp2p uses, which implements the [interface-connection](https://github.com/libp2p/interface-connection) interface for dial/listen.
`libp2p-tcp` in Node.js is a very thin shim that adds support for dialing to a `multiaddr`. This small shim will enable libp2p to use other different transports. > JavaScript implementation of the TCP module for libp2p. It exposes the [interface-transport](https://github.com/libp2p/interface-connection) for dial/listen. `libp2p-tcp` is a very thin shim that adds support for dialing to a `multiaddr`. This small shim will enable libp2p to use other different transports.
**Note:** This module uses [pull-streams](https://pull-stream.github.io) for all stream based interfaces. ## Lead Maintainer
[Jacob Heun](https://github.com/jacobheun)
## Table of Contents ## Table of Contents
- [Install](#install) - [Install](#install)
- [npm](#npm) - [npm](#npm)
- [Usage](#usage) - [Usage](#usage)
- [Example](#example)
- [This module uses `pull-streams`](#this-module-uses-pull-streams)
- [Converting `pull-streams` to Node.js Streams](#converting-pull-streams-to-nodejs-streams)
- [API](#api) - [API](#api)
- [Contribute](#contribute) - [Contribute](#contribute)
- [License](#license) - [License](#license)
@ -35,24 +34,21 @@
### npm ### npm
```sh ```sh
> npm i libp2p-tcp > npm install libp2p-tcp
``` ```
## Usage ## Usage
### Example
```js ```js
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
const pull = require('pull-stream') const pull = require('pull-stream')
const mh1 = multiaddr('/ip4/127.0.0.1/tcp/9090') const mh = multiaddr('/ip4/127.0.0.1/tcp/9090')
const mh2 = multiaddr('/ip6/::/tcp/9092')
const tcp = new TCP() const tcp = new TCP()
const listener = tcp.createListener(mh1, (socket) => { const listener = tcp.createListener((socket) => {
console.log('new connection opened') console.log('new connection opened')
pull( pull(
pull.values(['hello']), pull.values(['hello']),
@ -60,15 +56,21 @@ const listener = tcp.createListener(mh1, (socket) => {
) )
}) })
listener.listen(() => { listener.listen(mh, () => {
console.log('listening') console.log('listening')
pull( pull(
tcp.dial(mh1), tcp.dial(mh),
pull.log, pull.collect((err, values) => {
pull.onEnd(() => { if (!err) {
tcp.close() console.log(`Value: ${values.toString()}`)
}) } else {
console.log(`Error: ${err}`)
}
// Close connection after reading
listener.close()
}),
) )
}) })
``` ```
@ -78,35 +80,13 @@ Outputs:
```sh ```sh
listening listening
new connection opened new connection opened
hello Value: hello
``` ```
### This module uses `pull-streams`
We expose a streaming interface based on `pull-streams`, rather then on the Node.js core streams implementation (aka Node.js streams). `pull-streams` offers us a better mechanism for error handling and flow control guarantees. If you would like to know more about why we did this, see the discussion at this [issue](https://github.com/ipfs/js-ipfs/issues/362).
You can learn more about pull-streams at:
- [The history of Node.js streams, nodebp April 2014](https://www.youtube.com/watch?v=g5ewQEuXjsQ)
- [The history of streams, 2016](http://dominictarr.com/post/145135293917/history-of-streams)
- [pull-streams, the simple streaming primitive](http://dominictarr.com/post/149248845122/pull-streams-pull-streams-are-a-very-simple)
- [pull-streams documentation](https://pull-stream.github.io/)
#### Converting `pull-streams` to Node.js Streams
If you are a Node.js streams user, you can convert a pull-stream to a Node.js stream using the module [`pull-stream-to-stream`](https://github.com/dominictarr/pull-stream-to-stream), giving you an instance of a Node.js stream that is linked to the pull-stream. For example:
```js
const pullToStream = require('pull-stream-to-stream')
const nodeStreamInstance = pullToStream(pullStreamInstance)
// nodeStreamInstance is an instance of a Node.js Stream
```
To learn more about this utility, visit https://pull-stream.github.io/#pull-stream-to-stream.
## API ## API
### Transport
[![](https://raw.githubusercontent.com/libp2p/interface-transport/master/img/badge.png)](https://github.com/libp2p/interface-transport) [![](https://raw.githubusercontent.com/libp2p/interface-transport/master/img/badge.png)](https://github.com/libp2p/interface-transport)
`libp2p-tcp` accepts TCP addresses both IPFS and non IPFS encapsulated addresses, i.e: `libp2p-tcp` accepts TCP addresses both IPFS and non IPFS encapsulated addresses, i.e:
@ -116,6 +96,10 @@ To learn more about this utility, visit https://pull-stream.github.io/#pull-stre
Both for dialing and listening. Both for dialing and listening.
### Connection
[![](https://raw.githubusercontent.com/libp2p/interface-connection/master/img/badge.png)](https://github.com/libp2p/interface-connection)
## Contribute ## Contribute
Contributions are welcome! The libp2p implementation in JavaScript is a work in progress. As such, there's a few things you can do right now to help out: Contributions are welcome! The libp2p implementation in JavaScript is a work in progress. As such, there's a few things you can do right now to help out:

View File

@ -1,29 +0,0 @@
# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
version: "{build}"
environment:
matrix:
- nodejs_version: "6"
- nodejs_version: "8"
matrix:
fast_finish: true
install:
# Install Node.js
- ps: Install-Product node $env:nodejs_version
# Upgrade npm
- npm install -g npm
# Output our current versions for debugging
- node --version
- npm --version
# Install our package dependencies
- npm install
test_script:
- npm run test:node
build: off

2
ci/Jenkinsfile vendored
View File

@ -1,2 +0,0 @@
// Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
javascript()

View File

@ -1,15 +0,0 @@
# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
machine:
node:
version: stable
dependencies:
pre:
- google-chrome --version
- curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- sudo dpkg -i google-chrome.deb || true
- sudo apt-get update
- sudo apt-get install -f
- sudo apt-get install --only-upgrade lsb-base
- sudo dpkg -i google-chrome.deb
- google-chrome --version

View File

@ -1,11 +1,17 @@
{ {
"name": "libp2p-tcp", "name": "libp2p-tcp",
"version": "0.11.5", "version": "0.13.0",
"description": "Node.js implementation of the TCP module that libp2p uses, which implements the interface-connection and interface-transport interfaces", "description": "Node.js implementation of the TCP module that libp2p uses, which implements the interface-connection and interface-transport interfaces",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js", "main": "src/index.js",
"files": [
"dist",
"src"
],
"scripts": { "scripts": {
"lint": "aegir lint", "lint": "aegir lint",
"test": "aegir test -t node", "test": "aegir test -t node -f test/**/*.js",
"test:node": "aegir test -t node -f test/**/*.js",
"release": "aegir release -t node --no-build", "release": "aegir release -t node --no-build",
"release-minor": "aegir release -t node --type minor --no-build", "release-minor": "aegir release -t node --type minor --no-build",
"release-major": "aegir-release -t node --type major --no-build", "release-major": "aegir-release -t node --type major --no-build",
@ -23,7 +29,6 @@
"keywords": [ "keywords": [
"IPFS" "IPFS"
], ],
"author": "David Dias <daviddias@ipfs.io>",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/libp2p/js-libp2p-tcp/issues" "url": "https://github.com/libp2p/js-libp2p-tcp/issues"
@ -34,36 +39,38 @@
"npm": ">=3.0.0" "npm": ">=3.0.0"
}, },
"devDependencies": { "devDependencies": {
"aegir": "^12.4.0", "aegir": "^18.2.0",
"chai": "^4.1.2", "chai": "^4.2.0",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"interface-transport": "~0.3.5", "interface-transport": "~0.3.7",
"lodash.isfunction": "^3.0.9", "pull-stream": "^3.6.9"
"pre-commit": "^1.2.2",
"pull-stream": "^3.6.1"
}, },
"dependencies": { "dependencies": {
"debug": "^3.1.0", "class-is": "^1.1.0",
"interface-connection": "~0.3.2", "debug": "^4.1.1",
"interface-connection": "~0.3.3",
"ip-address": "^5.8.9", "ip-address": "^5.8.9",
"lodash.includes": "^4.3.0", "mafmt": "^6.0.6",
"lodash.isfunction": "^3.0.9", "multiaddr": "^6.0.5",
"mafmt": "^3.0.2",
"multiaddr": "^3.0.2",
"once": "^1.4.0", "once": "^1.4.0",
"stream-to-pull-stream": "^1.7.2" "stream-to-pull-stream": "^1.7.2"
}, },
"contributors": [ "contributors": [
"Alan Shaw <alan@tableflip.io>", "Alan Shaw <alan@tableflip.io>",
"David Dias <daviddias.p@gmail.com>", "David Dias <daviddias.p@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>", "Dmitriy Ryajov <dryajov@gmail.com>",
"Drew Stone <drewstone329@gmail.com>",
"Evan Schwartz <evan.mark.schwartz@gmail.com>", "Evan Schwartz <evan.mark.schwartz@gmail.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Greenkeeper <support@greenkeeper.io>", "Greenkeeper <support@greenkeeper.io>",
"Jacob Heun <jacobheun@gmail.com>",
"Jacob Heun <jake@andyet.net>",
"João Antunes <j.goncalo.antunes@gmail.com>", "João Antunes <j.goncalo.antunes@gmail.com>",
"Pedro Teixeira <i@pgte.me>", "Pedro Teixeira <i@pgte.me>",
"Prashanth Chandra <coolshanth94@gmail.com>", "Prashanth Chandra <coolshanth94@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>", "Richard Littauer <richard.littauer@gmail.com>",
"Stephen Whitmore <stephen.whitmore@gmail.com>" "Stephen Whitmore <stephen.whitmore@gmail.com>",
"TomCoded <tomtinkerer@gmail.com>"
] ]
} }

View File

@ -2,21 +2,32 @@
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
const Address6 = require('ip-address').Address6 const Address6 = require('ip-address').Address6
const debug = require('debug')
const log = debug('libp2p:tcp:get-multiaddr')
module.exports = (socket) => { module.exports = (socket) => {
let mh let ma
if (socket.remoteFamily === 'IPv6') { try {
var addr = new Address6(socket.remoteAddress) if (socket.remoteFamily === 'IPv6') {
if (addr.v4) { const addr = new Address6(socket.remoteAddress)
var ip4 = addr.to4().correctForm()
mh = multiaddr('/ip4/' + ip4 + '/tcp/' + socket.remotePort) if (addr.v4) {
const ip4 = addr.to4().correctForm()
ma = multiaddr('/ip4/' + ip4 +
'/tcp/' + socket.remotePort
)
} else {
ma = multiaddr('/ip6/' + socket.remoteAddress +
'/tcp/' + socket.remotePort
)
}
} else { } else {
mh = multiaddr('/ip6/' + socket.remoteAddress + '/tcp/' + socket.remotePort) ma = multiaddr('/ip4/' + socket.remoteAddress +
'/tcp/' + socket.remotePort)
} }
} else { } catch (err) {
mh = multiaddr('/ip4/' + socket.remoteAddress + '/tcp/' + socket.remotePort) log(err)
} }
return ma
return mh
} }

View File

@ -3,8 +3,7 @@
const net = require('net') const net = require('net')
const toPull = require('stream-to-pull-stream') const toPull = require('stream-to-pull-stream')
const mafmt = require('mafmt') const mafmt = require('mafmt')
const includes = require('lodash.includes') const withIs = require('class-is')
const isFunction = require('lodash.isfunction')
const Connection = require('interface-connection').Connection const Connection = require('interface-connection').Connection
const once = require('once') const once = require('once')
const debug = require('debug') const debug = require('debug')
@ -16,14 +15,13 @@ function noop () {}
class TCP { class TCP {
dial (ma, options, callback) { dial (ma, options, callback) {
if (isFunction(options)) { if (typeof options === 'function') {
callback = options callback = options
options = {} options = {}
} }
callback = callback || noop callback = once(callback || noop)
callback = once(callback)
const cOpts = ma.toOptions() const cOpts = ma.toOptions()
log('Connecting to %s %s', cOpts.port, cOpts.host) log('Connecting to %s %s', cOpts.port, cOpts.host)
@ -53,12 +51,12 @@ class TCP {
} }
createListener (options, handler) { createListener (options, handler) {
if (isFunction(options)) { if (typeof options === 'function') {
handler = options handler = options
options = {} options = {}
} }
handler = handler || (() => {}) handler = handler || noop
return createListener(handler) return createListener(handler)
} }
@ -69,11 +67,11 @@ class TCP {
} }
return multiaddrs.filter((ma) => { return multiaddrs.filter((ma) => {
if (includes(ma.protoNames(), 'p2p-circuit')) { if (ma.protoNames().includes('p2p-circuit')) {
return false return false
} }
if (includes(ma.protoNames(), 'ipfs')) { if (ma.protoNames().includes('ipfs')) {
ma = ma.decapsulate('ipfs') ma = ma.decapsulate('ipfs')
} }
@ -82,4 +80,4 @@ class TCP {
} }
} }
module.exports = TCP module.exports = withIs(TCP, { className: 'TCP', symbolName: '@libp2p/js-libp2p-tcp/tcp' })

View File

@ -3,7 +3,6 @@
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
const Connection = require('interface-connection').Connection const Connection = require('interface-connection').Connection
const os = require('os') const os = require('os')
const includes = require('lodash.includes')
const net = require('net') const net = require('net')
const toPull = require('stream-to-pull-stream') const toPull = require('stream-to-pull-stream')
const EventEmitter = require('events').EventEmitter const EventEmitter = require('events').EventEmitter
@ -12,7 +11,6 @@ const log = debug('libp2p:tcp:listen')
const getMultiaddr = require('./get-multiaddr') const getMultiaddr = require('./get-multiaddr')
const IPFS_CODE = 421
const CLOSE_TIMEOUT = 2000 const CLOSE_TIMEOUT = 2000
function noop () {} function noop () {}
@ -25,6 +23,15 @@ module.exports = (handler) => {
socket.on('error', noop) socket.on('error', noop)
const addr = getMultiaddr(socket) const addr = getMultiaddr(socket)
if (!addr) {
if (socket.remoteAddress === undefined) {
log('connection closed before p2p connection made')
} else {
log('error interpreting incoming p2p connection')
}
return
}
log('new connection', addr.toString()) log('new connection', addr.toString())
const s = toPull.duplex(socket) const s = toPull.duplex(socket)
@ -70,15 +77,10 @@ module.exports = (handler) => {
}) })
} }
let ipfsId
let listeningAddr let listeningAddr
listener.listen = (ma, callback) => { listener.listen = (ma, callback) => {
listeningAddr = ma listeningAddr = ma
if (includes(ma.protoNames(), 'ipfs')) {
ipfsId = getIpfsId(ma)
listeningAddr = ma.decapsulate('ipfs')
}
const lOpts = listeningAddr.toOptions() const lOpts = listeningAddr.toOptions()
log('Listening on %s %s', lOpts.port, lOpts.host) log('Listening on %s %s', lOpts.port, lOpts.host)
@ -96,33 +98,43 @@ module.exports = (handler) => {
// Because TCP will only return the IPv6 version // Because TCP will only return the IPv6 version
// we need to capture from the passed multiaddr // we need to capture from the passed multiaddr
if (listeningAddr.toString().indexOf('ip4') !== -1) { if (listeningAddr.toString().indexOf('ip4') !== -1) {
let m = listeningAddr.decapsulate('tcp') if (listeningAddr.toString().indexOf('0.0.0.0') !== -1) {
m = m.encapsulate('/tcp/' + address.port)
if (ipfsId) {
m = m.encapsulate('/ipfs/' + ipfsId)
}
if (m.toString().indexOf('0.0.0.0') !== -1) {
const netInterfaces = os.networkInterfaces() const netInterfaces = os.networkInterfaces()
Object.keys(netInterfaces).forEach((niKey) => { Object.keys(netInterfaces).forEach((niKey) => {
netInterfaces[niKey].forEach((ni) => { netInterfaces[niKey].forEach((ni) => {
if (ni.family === 'IPv4') { if (ni.family === 'IPv4') {
multiaddrs.push(multiaddr(m.toString().replace('0.0.0.0', ni.address))) multiaddrs.push(
multiaddr(listeningAddr.toString().replace('0.0.0.0', ni.address))
)
} }
}) })
}) })
} else { } else {
multiaddrs.push(m) multiaddrs.push(listeningAddr)
} }
} }
if (address.family === 'IPv6') { if (address.family === 'IPv6') {
let ma = multiaddr('/ip6/' + address.address + '/tcp/' + address.port) // Listen on all available addresses when using wildcard
if (ipfsId) { if (listeningAddr.toString().indexOf('/::/') !== -1) {
ma = ma.encapsulate('/ipfs/' + ipfsId) const netInterfaces = os.networkInterfaces()
Object.keys(netInterfaces).forEach((niKey) => {
netInterfaces[niKey].forEach((ni) => {
if (ni.family === address.family) {
const maOpts = listeningAddr.toOptions()
if (maOpts.host === '::') {
maOpts.family = address.family
maOpts.address = ni.address
multiaddrs.push(
multiaddr.fromNodeAddress(maOpts, maOpts.transport)
)
}
}
})
})
} else {
multiaddrs.push(listeningAddr)
} }
multiaddrs.push(ma)
} }
callback(null, multiaddrs) callback(null, multiaddrs)
@ -131,12 +143,6 @@ module.exports = (handler) => {
return listener return listener
} }
function getIpfsId (ma) {
return ma.stringTuples().filter((tuple) => {
return tuple[0] === IPFS_CODE
})[0][1]
}
function trackSocket (server, socket) { function trackSocket (server, socket) {
const key = `${socket.remoteAddress}:${socket.remotePort}` const key = `${socket.remoteAddress}:${socket.remotePort}`
server.__connections[key] = socket server.__connections[key] = socket

View File

@ -3,16 +3,18 @@
const tests = require('interface-transport') const tests = require('interface-transport')
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
const Tcp = require('../src') const TCP = require('../src')
describe('interface-transport compliance', () => { describe('interface-transport compliance', () => {
tests({ tests({
setup (cb) { setup (cb) {
let tcp = new Tcp() const tcp = new TCP()
const addrs = [ const addrs = [
multiaddr('/ip4/127.0.0.1/tcp/9091'), multiaddr('/ip4/127.0.0.1/tcp/9091'),
multiaddr('/ip4/127.0.0.1/tcp/9092'), multiaddr('/ip4/127.0.0.1/tcp/9092'),
multiaddr('/ip4/127.0.0.1/tcp/9093') multiaddr('/ip4/127.0.0.1/tcp/9093'),
multiaddr('/ip6/::/tcp/9094'),
multiaddr('/dns4/ipfs.io')
] ]
cb(null, tcp, addrs) cb(null, tcp, addrs)
}, },

View File

@ -89,7 +89,7 @@ describe('Connection Wrap', () => {
}) })
it('dial error', (done) => { it('dial error', (done) => {
tcp.dial(multiaddr('/ip4/999.0.0.1/tcp/1234'), (err) => { tcp.dial(multiaddr('/ip4/127.0.0.1/tcp/22234'), (err) => {
expect(err).to.exist() expect(err).to.exist()
done() done()
}) })

View File

@ -9,6 +9,9 @@ const TCP = require('../src')
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
describe('filter addrs', () => { describe('filter addrs', () => {
const base = '/ip4/127.0.0.1'
const ipfs = '/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw'
let tcp let tcp
before(() => { before(() => {
@ -16,25 +19,26 @@ describe('filter addrs', () => {
}) })
it('filter valid addrs for this transport', () => { it('filter valid addrs for this transport', () => {
const mh1 = multiaddr('/ip4/127.0.0.1/tcp/9090') const ma1 = multiaddr(base + '/tcp/9090')
const mh2 = multiaddr('/ip4/127.0.0.1/udp/9090') const ma2 = multiaddr(base + '/udp/9090')
const mh3 = multiaddr('/ip4/127.0.0.1/tcp/9090/http') const ma3 = multiaddr(base + '/tcp/9090/http')
const mh4 = multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw') const ma4 = multiaddr(base + '/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw')
const mh5 = multiaddr('/ip4/127.0.0.1/tcp/9090/http/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw') const ma5 = multiaddr(base + '/tcp/9090/http' + ipfs)
const mh6 = multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw' + const ma6 = multiaddr('/ip4/127.0.0.1/tcp/9090/p2p-circuit' + ipfs)
'/p2p-circuit/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw') const ma7 = multiaddr('/dns4/libp2p.io/tcp/9090')
const ma8 = multiaddr('/dnsaddr/libp2p.io/tcp/9090')
const valid = tcp.filter([mh1, mh2, mh3, mh4, mh5, mh6]) const valid = tcp.filter([ma1, ma2, ma3, ma4, ma5, ma6, ma7, ma8])
expect(valid.length).to.equal(2) expect(valid.length).to.equal(4)
expect(valid[0]).to.deep.equal(mh1) expect(valid[0]).to.deep.equal(ma1)
expect(valid[1]).to.deep.equal(mh4) expect(valid[1]).to.deep.equal(ma4)
}) })
it('filter a single addr for this transport', () => { it('filter a single addr for this transport', () => {
const mh1 = multiaddr('/ip4/127.0.0.1/tcp/9090') const ma1 = multiaddr(base + '/tcp/9090')
const valid = tcp.filter(mh1) const valid = tcp.filter(ma1)
expect(valid.length).to.equal(1) expect(valid.length).to.equal(1)
expect(valid[0]).to.deep.equal(mh1) expect(valid[0]).to.eql(ma1)
}) })
}) })

View File

@ -0,0 +1,54 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const getMultiaddr = require('../src/get-multiaddr')
const goodSocket4 = {
remoteAddress: '127.0.0.1',
remotePort: '9090',
remoteFamily: 'IPv4'
}
const goodSocket6 = {
remoteAddress: '::1',
remotePort: '9090',
remoteFamily: 'IPv6'
}
const badSocket = {}
const badSocketData = {
remoteAddress: 'aewmrn4awoew',
remotePort: '234',
remoteFamily: 'Hufflepuff'
}
describe('getMultiaddr multiaddr creation', () => {
it('creates multiaddr from valid socket data', (done) => {
expect(getMultiaddr(goodSocket4))
.to.exist()
done()
})
it('creates multiaddr from valid IPv6 socket data', (done) => {
expect(getMultiaddr(goodSocket6))
.to.exist()
done()
})
it('returns undefined multiaddr from missing socket data', (done) => {
expect(getMultiaddr(badSocket))
.to.equal(undefined)
done()
})
it('returns undefined multiaddr from unparseable socket data', (done) => {
expect(getMultiaddr(badSocketData))
.to.equal(undefined)
done()
})
})

View File

@ -1,4 +1,5 @@
/* eslint-env mocha */ /* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 5] */
'use strict' 'use strict'
const pull = require('pull-stream') const pull = require('pull-stream')
@ -13,14 +14,19 @@ const isCI = process.env.CI
describe('listen', () => { describe('listen', () => {
let tcp let tcp
let listener
beforeEach(() => { beforeEach(() => {
tcp = new TCP() tcp = new TCP()
}) })
afterEach((done) => {
listener ? listener.close(done) : done()
})
it('close listener with connections, through timeout', (done) => { it('close listener with connections, through timeout', (done) => {
const mh = multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw') const mh = multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw')
const listener = tcp.createListener((conn) => { listener = tcp.createListener((conn) => {
pull(conn, conn) pull(conn, conn)
}) })
@ -32,97 +38,106 @@ describe('listen', () => {
socket1.end() socket1.end()
socket1.on('error', () => {}) socket1.on('error', () => {})
socket2.on('error', () => {}) socket2.on('error', () => {})
socket1.on('connect', () => { socket1.on('connect', done)
listener.close(done)
})
}) })
}) })
it('listen on port 0', (done) => { it('listen on port 0', (done) => {
const mh = multiaddr('/ip4/127.0.0.1/tcp/0') const mh = multiaddr('/ip4/127.0.0.1/tcp/0')
const listener = tcp.createListener((conn) => {}) listener = tcp.createListener((conn) => {})
listener.listen(mh, () => { listener.listen(mh, done)
listener.close(done)
})
}) })
it('listen on IPv6 addr', (done) => { it('listen on IPv6 addr', (done) => {
if (isCI) { return done() } if (isCI) { return done() }
const mh = multiaddr('/ip6/::/tcp/9090') const mh = multiaddr('/ip6/::/tcp/9090')
const listener = tcp.createListener((conn) => {}) listener = tcp.createListener((conn) => {})
listener.listen(mh, () => { listener.listen(mh, done)
listener.close(done)
})
}) })
it('listen on any Interface', (done) => { it('listen on any Interface', (done) => {
const mh = multiaddr('/ip4/0.0.0.0/tcp/9090') const mh = multiaddr('/ip4/0.0.0.0/tcp/9090')
const listener = tcp.createListener((conn) => {}) listener = tcp.createListener((conn) => {})
listener.listen(mh, () => { listener.listen(mh, done)
listener.close(done)
})
}) })
it('getAddrs', (done) => { it('getAddrs', (done) => {
const mh = multiaddr('/ip4/127.0.0.1/tcp/9090') const mh = multiaddr('/ip4/127.0.0.1/tcp/9090')
const listener = tcp.createListener((conn) => {}) listener = tcp.createListener((conn) => {})
listener.listen(mh, () => { listener.listen(mh, () => {
listener.getAddrs((err, multiaddrs) => { listener.getAddrs((err, multiaddrs) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(multiaddrs.length).to.equal(1) expect(multiaddrs.length).to.equal(1)
expect(multiaddrs[0]).to.deep.equal(mh) expect(multiaddrs[0]).to.deep.equal(mh)
listener.close(done) done()
}) })
}) })
}) })
it('getAddrs on port 0 listen', (done) => { it('getAddrs on port 0 listen', (done) => {
const mh = multiaddr('/ip4/127.0.0.1/tcp/0') const mh = multiaddr('/ip4/127.0.0.1/tcp/0')
const listener = tcp.createListener((conn) => {}) listener = tcp.createListener((conn) => {})
listener.listen(mh, () => { listener.listen(mh, () => {
listener.getAddrs((err, multiaddrs) => { listener.getAddrs((err, multiaddrs) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(multiaddrs.length).to.equal(1) expect(multiaddrs.length).to.equal(1)
listener.close(done) done()
}) })
}) })
}) })
it('getAddrs from listening on 0.0.0.0', (done) => { it('getAddrs from listening on 0.0.0.0', (done) => {
const mh = multiaddr('/ip4/0.0.0.0/tcp/9090') const mh = multiaddr('/ip4/0.0.0.0/tcp/9090')
const listener = tcp.createListener((conn) => {}) listener = tcp.createListener((conn) => {})
listener.listen(mh, () => { listener.listen(mh, () => {
listener.getAddrs((err, multiaddrs) => { listener.getAddrs((err, multiaddrs) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(multiaddrs.length > 0).to.equal(true) expect(multiaddrs.length > 0).to.equal(true)
expect(multiaddrs[0].toString().indexOf('0.0.0.0')).to.equal(-1) expect(multiaddrs[0].toString().indexOf('0.0.0.0')).to.equal(-1)
listener.close(done) done()
}) })
}) })
}) })
it('getAddrs from listening on 0.0.0.0 and port 0', (done) => { it('getAddrs from listening on 0.0.0.0 and port 0', (done) => {
const mh = multiaddr('/ip4/0.0.0.0/tcp/0') const mh = multiaddr('/ip4/0.0.0.0/tcp/0')
const listener = tcp.createListener((conn) => {}) listener = tcp.createListener((conn) => {})
listener.listen(mh, () => { listener.listen(mh, () => {
listener.getAddrs((err, multiaddrs) => { listener.getAddrs((err, multiaddrs) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(multiaddrs.length > 0).to.equal(true) expect(multiaddrs.length > 0).to.equal(true)
expect(multiaddrs[0].toString().indexOf('0.0.0.0')).to.equal(-1) multiaddrs.forEach((m) => {
listener.close(done) expect(m.toOptions().host).to.not.eql('0.0.0.0')
})
done()
})
})
})
it('getAddrs from listening on ip6 \'::\'', (done) => {
const mh = multiaddr('/ip6/::/tcp/9090')
listener = tcp.createListener((conn) => {})
listener.listen(mh, () => {
listener.getAddrs((err, multiaddrs) => {
expect(err).to.not.exist()
expect(multiaddrs.length > 0).to.equal(true)
multiaddrs.forEach((m) => {
expect(m.toOptions().host).to.not.eql('::')
})
done()
}) })
}) })
}) })
it('getAddrs preserves IPFS Id', (done) => { it('getAddrs preserves IPFS Id', (done) => {
const mh = multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw') const mh = multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw')
const listener = tcp.createListener((conn) => {}) listener = tcp.createListener((conn) => {})
listener.listen(mh, () => { listener.listen(mh, () => {
listener.getAddrs((err, multiaddrs) => { listener.getAddrs((err, multiaddrs) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(multiaddrs.length).to.equal(1) expect(multiaddrs.length).to.equal(1)
expect(multiaddrs[0]).to.deep.equal(mh) expect(multiaddrs[0]).to.deep.equal(mh)
listener.close(done) done()
}) })
}) })
}) })
@ -194,10 +209,9 @@ describe('dial', () => {
}) })
}) })
// TODO: figure out why is this failing it('dial and destroy on listener', (done) => {
it.skip('dial and destroy on listener', (done) => {
let count = 0 let count = 0
const closed = ++count === 2 ? finish() : null const closed = () => ++count === 2 ? finish() : null
const ma = multiaddr('/ip6/::/tcp/9067') const ma = multiaddr('/ip6/::/tcp/9067')