@libp2p/tcp
Version:
A TCP transport for libp2p
107 lines • 4.08 kB
JavaScript
import { InvalidParametersError, TimeoutError } from '@libp2p/interface';
import { AbstractMultiaddrConnection, ipPortToMultiaddr } from '@libp2p/utils';
import { Unix } from '@multiformats/multiaddr-matcher';
import { pEvent } from 'p-event';
class TCPSocketMultiaddrConnection extends AbstractMultiaddrConnection {
socket;
constructor(init) {
let remoteAddr = init.remoteAddr;
// check if we are connected on a unix path
if (init.localAddr != null && Unix.matches(init.localAddr)) {
remoteAddr = init.localAddr;
}
else if (remoteAddr == null) {
if (init.socket.remoteAddress == null || init.socket.remotePort == null) {
// this can be undefined if the socket is destroyed (for example, if the client disconnected)
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketremoteaddress
throw new InvalidParametersError('Could not determine remote address or port');
}
remoteAddr = ipPortToMultiaddr(init.socket.remoteAddress, init.socket.remotePort);
}
super({
...init,
remoteAddr
});
this.socket = init.socket;
// handle incoming data
this.socket.on('data', buf => {
this.onData(buf);
});
// handle socket errors
this.socket.on('error', err => {
this.log('tcp error', remoteAddr, err);
this.abort(err);
});
// by default there is no timeout
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketsettimeouttimeout-callback
this.socket.setTimeout(init.inactivityTimeout ?? (2 * 60 * 1_000));
this.socket.once('timeout', () => {
this.log('tcp timeout', remoteAddr);
// if the socket times out due to inactivity we must manually close the connection
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#event-timeout
this.abort(new TimeoutError());
});
this.socket.once('end', () => {
this.log('tcp end', remoteAddr);
// the remote sent a FIN packet which means no more data will be sent
// https://nodejs.org/dist/latest-v16.x/docs/api/net.html#event-end
// half open TCP sockets are disabled by default so Node.js should send a
// FIN in response to this event and then emit a 'close' event, during
// which we tear down the MultiaddrConnection so there is nothing to do
// until that occurs
this.onTransportClosed();
});
this.socket.once('close', hadError => {
this.log('tcp close', remoteAddr);
if (hadError) {
this.abort(new Error('TCP transmission error'));
return;
}
this.onTransportClosed();
});
// the socket can accept more data
this.socket.on('drain', () => {
this.log('tcp drain');
this.safeDispatchEvent('drain');
});
}
sendData(data) {
let sentBytes = 0;
let canSendMore = true;
for (const buf of data) {
sentBytes += buf.byteLength;
canSendMore = this.socket.write(buf);
if (!canSendMore) {
break;
}
}
return {
sentBytes,
canSendMore
};
}
async sendClose(options) {
if (this.socket.destroyed) {
return;
}
this.socket.destroySoon();
await pEvent(this.socket, 'close', options);
}
sendReset() {
this.socket.resetAndDestroy();
}
sendPause() {
this.socket.pause();
}
sendResume() {
this.socket.resume();
}
}
/**
* Convert a socket into a MultiaddrConnection
* https://github.com/libp2p/interface-transport#multiaddrconnection
*/
export const toMultiaddrConnection = (init) => {
return new TCPSocketMultiaddrConnection(init);
};
//# sourceMappingURL=socket-to-conn.js.map