sockets - Active FTP Client for Node.js -


i'm trying hand @ writing ftp client against filezilla supports active mode using node.js. i'm new ftp , node.js. thought understanding of tcp socket communication , ftp protocol doing exercise. also, node-ftp jsftp don't seem support active mode, think nice (though used) addition npm.

i've got proof of concept code works @ least sometimes, not time. in case works, client uploads file called file.txt text 'hi'. when works, this:

220-filezilla server version 0.9.41 beta 220-written tim kosse (tim.kosse@gmx.de) 220 please visit http://sourceforge.net/projects/filezilla/  331 password required testuser  230 logged on  listening 200 port command successful  150 opening data channel file transfer.  server close 226 transfer ok  half closed closed  process finished exit code 0 

when doesn't work, this:

220-filezilla server version 0.9.41 beta 220-written tim kosse (tim.kosse@gmx.de) 220 please visit http://sourceforge.net/projects/filezilla/  331 password required testuser  230 logged on  listening 200 port command successful  150 opening data channel file transfer.  server close half closed closed  process finished exit code 0 

so, i'm not getting 226, , i'm not sure why i'm getting inconsistent results.

forgive poorly written code. i'll refactor once i'm confident understand how should work.:

var net = require('net'),     socket = net.socket;  var cmdsocket = new socket(); cmdsocket.setencoding('binary')  var server = undefined; var port = 21; var host = "localhost"; var user = "testuser"; var password = "password1*" var active = true; var supplyuser = true; var supplypassword = true; var supplypassive = true; var waitingforcommand = true; var sendfile = true;  function onconnect(){  }  var str=""; function ondata(chunk) {     console.log(chunk.tostring('binary'));      //if ftp server return code = 220     if(supplyuser){         supplyuser = false;         _send('user ' + user, function(){          });     }else if(supplypassword){         supplypassword = false;         _send('pass ' + password, function(){          });     }     else if(supplypassive){         supplypassive = false;         if(active){             server = net.createserver(function(socket){                 console.log('new connection');                 socket.setkeepalive(true, 5000);                  socket.write('hi', function(){                     console.log('write done');                 })                   socket.on('connect', function(){                     console.log('socket connect');                 });                  socket.on('data', function(d){                     console.log('socket data: ' + d);                 });                  socket.on('error', function(err){                     console.log('socket error: ' + err);                 });                  socket.on('end', function() {                     console.log('socket end');                 });                  socket.on('drain', function(){                     console.log('socket drain');                  });                  socket.on('timeout', function(){                     console.log('socket timeout');                  });                  socket.on('close', function(){                     console.log('socket close');                  });             });              server.on('error', function(e){                console.log(e);             });              server.on('close', function(){                 console.log('server close');             });              server.listen(function(){                 console.log('listening');                  var address = server.address();                 var port = address.port;                 var p1 = math.floor(port/256);                 var p2 = port % 256;                  _sendcommand('port 127,0,0,1,' + p1 + ',' + p2, function(){                  });             });         }else{             _send('pasv', function(){              });         }     }     else if(sendfile){         sendfile = false;          _send('stor file.txt', function(){          });     }     else if(waitingforcommand){         waitingforcommand = false;          cmdsocket.end(null, function(){          });          if(server)server.close(function(){});     } }  function onend() {     console.log('half closed'); }  function onclose(){     console.log('closed'); }  cmdsocket.once('connect', onconnect); cmdsocket.on('data', ondata); cmdsocket.on('end', onend); cmdsocket.on('close', onclose);  cmdsocket.connect(port, host);  function _send(cmd, callback){     cmdsocket.write(cmd + '\r\n', 'binary', callback); } 

also, server appropriate, or should other way?

edit: changed callback in server.listen use random port. has removed 425 getting previously. however, still not getting consistent behavior file transfer.

the flow active mode ftp transfers goes this:

  • connection preamble (user/pass)
  • establish client local socket data
  • inform server of socket (port)
  • tell server open remote file writing (stor)
  • start writing data data socket established above (socket.write())
  • close stream client side (socket.end()) end file transfer
  • tell server done (quit)
  • clean open sockets , servers on client

so once you've done this:

else if(sendfile){     sendfile = false;      _send('stor file.txt', function(){      }); } 

the server respond 150 saying has connected data socket established , ready receive data.

one improvement make easier reason execution @ point change control flow operate on parsed response code rather pre-defined bools.

function ondata(chunk) {   console.log(chunk);   var code = chunk.substring(0,3);    if(code == '220'){ 

instead of:

function ondata(chunk) {   console.log(chunk.tostring('binary'));    //if ftp server return code = 220   if(supplyuser){ 

then can add section sending data:

//ready data else if (code == '150') {   datasocket.write('some wonderful file contents\r\n', function(){});   datasocket.end(null, function(){}); } 

and little more clean up:

//transfer finished else if ( code == '226') {   _send('quit', function(){ console.log("saying goodbye");}); }  //session end else if ( code == '221') {   cmdsocket.end(null, function(){});   if(!!server){ server.close(); } } 

obviously things more complicated if sending multiple files etc, should proof of concept running more reliably:

var net = require('net');   socket = net.socket;  var cmdsocket = new socket(); cmdsocket.setencoding('binary')  var server = undefined; var datasocket = undefined; var port = 21; var host = "localhost"; var user = "username"; var password = "password" var active = true;  function onconnect(){ }  var str=""; function ondata(chunk) {   console.log(chunk.tostring('binary'));   var code = chunk.substring(0,3);   //if ftp server return code = 220   if(code == '220'){       _send('user ' + user, function(){       });   }else if(code == '331'){       _send('pass ' + password, function(){       });   }   else if(code == '230'){       if(active){           server = net.createserver(function(socket){               datasocket = socket;               console.log('new connection');               socket.setkeepalive(true, 5000);                socket.on('connect', function(){                   console.log('socket connect');               });                socket.on('data', function(d){                   console.log('socket data: ' + d);               });                socket.on('error', function(err){                   console.log('socket error: ' + err);               });                socket.on('end', function() {                   console.log('socket end');               });                socket.on('drain', function(){                   console.log('socket drain');               });                socket.on('timeout', function(){                   console.log('socket timeout');               });                socket.on('close', function(){                   console.log('socket close');               });           });            server.on('error', function(e){              console.log(e);           });            server.on('close', function(){               console.log('server close');           });            server.listen(function(){               console.log('listening');                var address = server.address();               var port = address.port;               var p1 = math.floor(port/256);               var p2 = port % 256;                _send('port 127,0,0,1,' + p1 + ',' + p2, function(){                });           });       }else{           _send('pasv', function(){            });       }   }   else if(code == '200'){       _send('stor file.txt', function(){        });   }   //ready data   else if (code == '150') {     datasocket.write('some wonderful file contents\r\n', function(){});     datasocket.end(null, function(){});   }    //transfer finished   else if ( code == '226') {     _send('quit', function(){ console.log("saying goodbye");});   }    //session end   else if ( code == '221') {     cmdsocket.end(null, function(){});     if(!!server){ server.close(); }   } }  function onend() {   console.log('half closed'); }  function onclose(){   console.log('closed'); }  cmdsocket.once('connect', onconnect); cmdsocket.on('data', ondata); cmdsocket.on('end', onend); cmdsocket.on('close', onclose);  cmdsocket.connect(port, host);  function _send(cmd, callback){   cmdsocket.write(cmd + '\r\n', 'binary', callback); } 

Comments

Popular posts from this blog

html - How to style widget with post count different than without post count -

How to remove text and logo OR add Overflow on Android ActionBar using AppCompat on API 8? -

javascript - storing input from prompt in array and displaying the array -