Skip to content

Commit

Permalink
fix: correctly destroy socket on close (#208)
Browse files Browse the repository at this point in the history
* chore: update owner references

* fix: correctly destroy socket on close

This fixes an issue where the client would never close, hanging the server and preventing shutdown

* fix: only set timeout if greater than 0

* fix: move dependency to top

* fix: notify of command that caused error

* fix: emit disconnect event on client close
  • Loading branch information
Tyler Stewart authored Jul 20, 2020
1 parent 649d582 commit ca576ac
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 15 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<a href="https://github.com/trs/ftp-srv">
<a href="https://github.com/autovance/ftp-srv">
<img alt="ftp-srv" src="logo.png" width="600px" />
</a>
</p>
Expand All @@ -14,8 +14,8 @@
<img alt="npm" src="https://img.shields.io/npm/dm/ftp-srv.svg?style=for-the-badge" />
</a>

<a href="https://circleci.com/gh/trs/workflows/ftp-srv/tree/master">
<img alt="circleci" src="https://img.shields.io/circleci/project/github/trs/ftp-srv/master.svg?style=for-the-badge" />
<a href="https://circleci.com/gh/autovance/workflows/ftp-srv/tree/master">
<img alt="circleci" src="https://img.shields.io/circleci/project/github/autovance/ftp-srv/master.svg?style=for-the-badge" />
</a>
</p>

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"types": "./ftp-srv.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/trs/ftp-srv"
"url": "https://github.com/autovance/ftp-srv"
},
"scripts": {
"pre-release": "npm run verify",
Expand Down
10 changes: 5 additions & 5 deletions src/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,25 @@ class FtpCommands {
log.trace({command: logCommand}, 'Handle command');

if (!REGISTRY.hasOwnProperty(command.directive)) {
return this.connection.reply(502, 'Command not allowed');
return this.connection.reply(502, `Command not allowed: ${command.directive}`);
}

if (_.includes(this.blacklist, command.directive)) {
return this.connection.reply(502, 'Command blacklisted');
return this.connection.reply(502, `Command blacklisted: ${command.directive}`);
}

if (this.whitelist.length > 0 && !_.includes(this.whitelist, command.directive)) {
return this.connection.reply(502, 'Command not whitelisted');
return this.connection.reply(502, `Command not whitelisted: ${command.directive}`);
}

const commandRegister = REGISTRY[command.directive];
const commandFlags = _.get(commandRegister, 'flags', {});
if (!commandFlags.no_auth && !this.connection.authenticated) {
return this.connection.reply(530, 'Command requires authentication');
return this.connection.reply(530, `Command requires authentication: ${command.directive}`);
}

if (!commandRegister.handler) {
return this.connection.reply(502, 'Handler not set on command');
return this.connection.reply(502, `Handler not set on command: ${command.directive}`);
}

const handler = commandRegister.handler.bind(this.connection);
Expand Down
2 changes: 1 addition & 1 deletion src/commands/registration/feat.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const _ = require('lodash');
const registry = require('../registry');

module.exports = {
directive: 'FEAT',
handler: function () {
const registry = require('../registry');
const features = Object.keys(registry)
.reduce((feats, cmd) => {
const feat = _.get(registry[cmd], 'flags.feat', null);
Expand Down
9 changes: 6 additions & 3 deletions src/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class FtpConnection extends EventEmitter {
this.commandSocket.on('data', this._handleData.bind(this));
this.commandSocket.on('timeout', () => {
this.log.trace('Client timeout');
this.close().catch((e) => this.log.trace(e, 'Client close error'));
this.close();
});
this.commandSocket.on('close', () => {
if (this.connector) this.connector.end();
Expand Down Expand Up @@ -72,7 +72,7 @@ class FtpConnection extends EventEmitter {
close(code = 421, message = 'Closing connection') {
return Promise.resolve(code)
.then((_code) => _code && this.reply(_code, message))
.then(() => this.commandSocket && this.commandSocket.end());
.finally(() => this.commandSocket && this.commandSocket.destroy());
}

login(username, password) {
Expand Down Expand Up @@ -136,7 +136,10 @@ class FtpConnection extends EventEmitter {
}
resolve();
});
} else reject(new errors.SocketError('Socket not writable'));
} else {
this.log.trace({message: letter.message}, 'Could not write message');
reject(new errors.SocketError('Socket not writable'));
}
});
};

Expand Down
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ class FtpServer extends EventEmitter {
this.options.timeout = isNaN(timeout) ? 0 : Number(timeout);

const serverConnectionHandler = (socket) => {
socket.setTimeout(this.options.timeout);
this.options.timeout > 0 && socket.setTimeout(this.options.timeout);
let connection = new Connection(this, {log: this.log, socket});
this.connections[connection.id] = connection;

socket.on('close', () => this.disconnectClient(connection.id));
socket.once('close', () => this.emit('disconnect', {connection, id: connection.id}));

const greeting = this._greeting || [];
const features = this._features || 'Ready';
Expand Down Expand Up @@ -119,7 +120,6 @@ class FtpServer extends EventEmitter {
return new Promise((resolve) => {
const client = this.connections[id];
if (!client) return resolve();
this.emit('disconnect', {connection: client, id});
delete this.connections[id];
try {
client.close(0);
Expand Down

0 comments on commit ca576ac

Please sign in to comment.