-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
81 lines (69 loc) · 2.1 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
'use strict'
const {platform, networkInterfaces} = require('os')
const {exec} = require('child_process')
const duplexify = require('duplexify')
const isSupported = () => {
// see https://github.com/derhuerst/node-awdl/issues/2
if (platform() !== 'darwin') return false
const {awdl0} = networkInterfaces()
if (!Array.isArray(awdl0) || !awdl0[0]) return false
return awdl0[0].family === 'IPv6'
}
const listenOnAWDL = (port, opt = {}) => {
if (!Number.isInteger(port)) throw new Error('port must be an integer')
opt = {
udp: false, // Use UDP instead of TCP?
readonly: false, // Disallow sending data?
// Set SO_RECV_ANYIF to receive traffic from all interfaces?
recvAnyif: false,
...opt
}
const iface = (networkInterfaces().awdl0 || [])[0]
const call = [
'nc', // netcat
'-b', 'awdl0', // use the `awdl0` network interface
'-6', // IPv6
// todo: -k
// Forces nc to stay listening for another connection after its current
// connection is completed.
'-l', port + '',
]
if (opt.udp) call.push('-u')
if (opt.readonly) call.push('-d')
if (opt.recvAnyif) call.push('-A')
const onExit = (err, stderr) => {
stream.removeListener('close', exitOnClose)
if (!err) {
stream.destroy()
return
}
const text = err ? err.message : (err + '')
const msg = text.split('\n')[0]
const error = new Error('failed to listen on the AWDL interface: ' + msg)
error.spawnError = err
error.stderr = stderr
stream.destroy(error)
}
const proc = exec(call.join(' '), {encoding: 'buffer'}, onExit)
const exitOnClose = () => {
proc.kill('SIGKILL') // let child process exit immediately
}
const stream = opt.readonly
? proc.stdout
: duplexify(proc.stdin, proc.stdout, {
// If the process exits with an error, `proc.stdin` and/or
// `proc.stdout` are being `destroy()`ed *without* an `Error`.
// In order to `destroy()` our duplex stream with an appropriate
// `Error`, we do that manually.
autoDestroy: false
})
stream.once('close', exitOnClose)
// expose useful info
stream.interface = iface
stream.process = proc
return stream
}
module.exports = {
isSupported,
listenOnAWDL,
}