Commit 2c052c9f authored by Benjamin Chelli's avatar Benjamin Chelli

Add connection autoclose + socket error handling + API documentation

parent e22a8aa1
......@@ -10,36 +10,102 @@ The development is still at an experimental stage and should not be yet consider
npm install smb2
## Usage
## API
### var smb2Client = new SMB2 ( options )
The SMB2 class is the constructor of your SMB2 client.
the parameter ```options``` accepts this list of attributes:
- ```share``` (mandatory): the share you want to access
- ```domain``` (mandatory): the domain of which the user is registred
- ```username``` (mandatory): the username of the user that access the share
- ```password``` (mandatory): the password
- ```packetConcurrency``` (optional): default ```20```, the number of simulatanous packet when writting / reading data from the share
- ```autoCloseTimeout``` (optional): default ```10000```, the timeout in milliseconds before to close the SMB2 session and the socket, if setted to ```0``` the connection will never be closed unless you do it
Example:
```javascript
// load the library
var SMB2 = require('smb2');
// create an SMB2 instance
var s = new SMB2({
var smb2Client = new SMB2({
share:'\\\\000.000.000.000\\c$'
, domain:'DOMAIN'
, username:'username'
, password:'password!'
});
```
// read the content of the folder
s.readDir('Windows\\System32', function(err, files){
// if an error happen => throw it
### smb2Client.readdir ( path, callback )
Asynchronous readdir(3). Reads the contents of a directory. The callback gets two arguments (err, files) where files is an array of the names of the files in the directory excluding '.' and '..'.
Example:
```javascript
smb2Client.readdir('Windows\\System32', function(err, files){
if(err) throw err;
// display content in the console
console.log(files);
// close the connection
s.close();
});
```
### smb2Client.readFile ( filename, [options], callback )
- ```filename``` String
- ```options``` Object
- ```encoding``` String | Null default = null
- ```callback``` Function
Asynchronously reads the entire contents of a file. Example:
```javascript
smb2Client.readFile('path\\to\\my\\file.txt', function(err, data){
if(err) throw err;
console.log(data);
});
```
The callback is passed two arguments (err, data), where data is the contents of the file.
If no encoding is specified, then the raw buffer is returned.
### smb2Client.writeFile ( filename, data, [options], callback )
- ```filename``` String
- ```data``` String | Buffer
- ```options``` Object
- ```encoding``` String | Null default = 'utf8'
- ```callback``` Function
Asynchronously writes data to a file, replacing the file if it already exists. data can be a string or a buffer.
The encoding option is ignored if data is a buffer. It defaults to 'utf8'.
Example:
```javascript
smb2Client.writeFile('path\\to\\my\\file.txt', 'Hello Node', function (err) {
if (err) throw err;
console.log('It\'s saved!');
});
```
### smb2Client.exists ( path, callback )
Test whether or not the given path exists by checking with the file system. Then call the callback argument with either true or false. Example:
```javascript
smb2Client.exists('path\\to\\my\\file.txt', function (err, exists) {
if (err) throw err;
console.log(exists ? "it's there" : "it's not there!");
});
```
### smb2Client.unlinkFile ( path, callback )
Asynchronous unlink(2). No arguments other than a possible exception are given to the completion callback.
```javascript
smb2Client.unlink('path\\to\\my\\file.txt', function (err) {
if (err) throw err;
console.log("file has been deleted");
});
```
### smb2Client.close ( )
This function will close the open connection if opened, it will be called automatically after ```autoCloseTimeout``` ms of no SMB2 call on the server.
## References
The[MS-SMB2]: Server Message Block (SMB) Protocol Versions 2 and 3
......
......@@ -41,9 +41,12 @@ var SMB = module.exports = function(opt){
// save the full path
this.fullPath = opt.share;
// packet concurrency
// packet concurrency default 20
this.packetConcurrency = opt.packetConcurrency || 20;
// close timeout default 60s
this.autoCloseTimeout = opt.autoCloseTimeout || 10000;
// store authentification
this.domain = opt.domain;
this.username = opt.username;
......@@ -53,6 +56,7 @@ var SMB = module.exports = function(opt){
this.SessionId = 0;
// create a socket
this.connected = false;
this.socket = new net.Socket({
allowHalfOpen:true
});
......@@ -60,7 +64,11 @@ var SMB = module.exports = function(opt){
// attach data events to socket
this.socket.on('data', parseResponse(this));
var connection = this;
this.socket.on('error', function(){
connection.errorHandler = [];
this.socket.on('error', function(err){
if(connection.errorHandler.length > 0){
connection.errorHandler[0].call(null, err)
}
if(connection.debug){
console.log('-- error');
console.log(arguments);
......@@ -86,7 +94,11 @@ var proto = SMB.prototype = {};
*
*/
proto.close = function(){
this.socket.end();
clearAutoCloseTimeout(this);
if(this.connected){
this.connected = false;
this.socket.end();
}
}
......@@ -107,6 +119,7 @@ proto.readdir = function(path, cb){
var connection = this;
connect(connection, function(err){
cb = scheduleAutoClose(connection, cb);
if(err) cb(err);
// SMB2 open directory
else SMB2Request('open', {path:path}, connection, function(err, file){
......@@ -152,6 +165,7 @@ proto.readFile = function(filename, options, cb){
}
connect(connection, function(err){
cb = scheduleAutoClose(connection, cb);
if(err) cb(err);
// SMB2 open file
else SMB2Request('open', {path:filename}, connection, function(err, file){
......@@ -189,7 +203,10 @@ proto.readFile = function(filename, options, cb){
createPackets();
if(nbRemainingPackets==0 && offset.ge(fileLength)) {
SMB2Request('close', file, connection, function(err){
cb && cb(err, result.toString());
if(options.encoding){
result = result.toString(options.encoding);
}
cb && cb(err, result);
})
}
}
......@@ -238,9 +255,11 @@ proto.writeFile = function(filename, data, options, cb){
options = {};
}
options.encoding = options.encoding || 'utf8';
var connection = this
, file
, fileContent = new Buffer(data)
, fileContent = Buffer.isBuffer(data) ? data : new Buffer(data, options.encoding)
, fileLength = new bigint(8, fileContent.length)
;
......@@ -320,27 +339,14 @@ proto.writeFile = function(filename, data, options, cb){
connect(connection, function(err){
cb = scheduleAutoClose(connection, cb);
if(err) cb(err);
else connection.exists(filename, function(err, exists){
if(err) cb && cb(err);
else if(!exists){
createFile(function(){
setFileSize(function(){
writeFile(function(){
closeFile(cb);
});
});
else createFile(function(){
setFileSize(function(){
writeFile(function(){
closeFile(cb);
});
} else {
cb(new Error('File already exists'));
}
});
});
});
......@@ -363,6 +369,7 @@ proto.exists = function(path, cb){
var connection = this;
connect(connection, function(err){
cb = scheduleAutoClose(connection, cb);
if(err) cb(err);
else SMB2Request('open', {path:path}, connection, function(err, file){
if(err) cb && cb(null, false);
......@@ -376,8 +383,8 @@ proto.exists = function(path, cb){
/*
* unlinkFile
* ==========
* unlink
* ======
*
* remove file:
*
......@@ -388,10 +395,11 @@ proto.exists = function(path, cb){
* - close the file
*
*/
proto.unlinkFile = function(path, cb){
proto.unlink = function(path, cb){
var connection = this;
connect(connection, function(err){
cb = scheduleAutoClose(connection, cb);
if(err) cb(err);
else connection.exists(path, function(err, exists){
......@@ -427,13 +435,15 @@ proto.unlinkFile = function(path, cb){
/*
* PRIVATE FUNCTION TO HANDLE CONNECTION
*/
connect = function(connection, cb){
function connect(connection, cb){
if(connection.connected){
cb && cb(null);
return;
}
cb = scheduleAutoClose(connection, cb);
// open TCP socket
connection.socket.connect(port, connection.ip);
......@@ -460,6 +470,45 @@ connect = function(connection, cb){
}
/*
* PRIVATE FUNCTION TO HANDLE CLOSING THE CONNECTION
*/
function clearAutoCloseTimeout(connection){
if(connection.scheduledAutoClose){
clearTimeout(connection.scheduledAutoClose);
connection.scheduledAutoClose = null;
}
}
function setAutoCloseTimeout(connection){
clearAutoCloseTimeout(connection);
if(connection.autoCloseTimeout != 0){
connection.scheduledAutoClose = setTimeout(function(){
connection.close();
}, connection.autoCloseTimeout);
}
}
function scheduleAutoClose(connection, cb){
addErrorListener(connection, cb);
clearAutoCloseTimeout(connection);
return function(){
removeErrorListener(connection);
setAutoCloseTimeout(connection);
cb.apply(null, arguments);
}
}
/*
* PRIVATE FUNCTIONS TO HANDLE ERRORS
*/
function addErrorListener(connection, callback){
connection.errorHandler.unshift(callback);
}
function removeErrorListener(connection){
connection.errorHandler.shift();
}
/*
* MESSAGE MANAGMENT
*/
......
......@@ -4,7 +4,7 @@
, "description":"SMB2 Client"
, "homepage": "https://github.com/bchelli/node-smb2"
, "version":"0.2.0"
, "version":"0.2.1"
, "engines": [
"node"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment