
/*    Copyright 2016 Firewalla LLC 
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict'

let firewalla = require('../../net2/Firewalla.js')
let log = require("../../net2/logger.js")(__filename)

let fs = require('fs')

let spawn = require('child_process').spawn
let Promise = require('bluebird');

let instance = null

function delay(t) {
  return new Promise(function(resolve) {
    setTimeout(resolve, t)
  });
}


class BitBridge {
  static getInstance() {
    return instance
  }
  
  constructor(intf, routerIP, selfIP, selfMac, selfIP6, routerIP6) {
    if(!instance) {
      this.intf = intf
      this.routerIP = routerIP
      this.selfIP = selfIP
      this.spawnProcess = null
      this.started = false
      this.subscribeOnProcessExit()
      this.selfMac = selfMac
      this.selfIP6 = selfIP6
      this.routerIP6 = routerIP6 
      instance = this
    }

    return instance
  }

  subscribeOnProcessExit() {
    process.on('exit', () => {
      if(this.started) {
        log.info("Terminating bitbridge on exit")
        this.stop()
      }
    });    
  }

  start() {
    log.info("Starting BitBridge...")
    
    let binary = null, args = null;

    if(firewalla.isDocker() || firewalla.isTravis()) {

      // always stop before start
      this.stop()
      
      binary = "sudo";
      args = [this.getBinary(), this.intf, this.routerIP, this.selfIP,'-m','-q','-n'];

      let logStream = fs.createWriteStream("/dev/null", {flags: 'a'});

      this.spawnProcess = spawn(binary, args);
      log.info("starting new spoofing: ", binary, args, {});

      this.spawnProcess.stdout.pipe(logStream);
      this.spawnProcess.stderr.pipe(logStream);

      this.spawnProcess.on('exit', (code) => {
        log.info("spoofing binary exited with code " + code);
      });

    } else {
      binary = this.getBinary()
      args = [this.intf, this.routerIP, this.selfIP, '-m','-n','-q','-d 0'];

      let cmd = binary+" "+args.join(" ")
      log.info("Lanching Bitbridge4 ", cmd);
      require('child_process').execSync("echo 'cp /home/pi/firewalla/bin/real/bitbridge7 /home/pi/firewalla/bin/. ; sudo setcap cap_net_admin,cap_net_raw=eip /home/pi/firewalla/bin/bitbridge7 ; "+cmd +" ' > /home/pi/firewalla/bin/bitbridge4.sh");
      require('child_process').execSync("sudo service bitbridge4 restart"); // legacy issue to use bitbridge4


      binary = this.getBinary6()
      args = [this.intf, this.routerIP6, this.selfIP, this.selfMac,'-m','-q','-n'];

      cmd = binary+" "+args.join(" ")
      log.info("Lanching bitbridge6", cmd);
      require('child_process').execSync("echo 'cp /home/pi/firewalla/bin/real/bitbridge6 /home/pi/firewalla/bin/. ; sudo setcap cap_net_admin,cap_net_raw=eip /home/pi/firewalla/bin/bitbridge6 ; "+cmd +" ' > /home/pi/firewalla/bin/bitbridge6.sh");
      require('child_process').execSync("sudo service bitbridge6 restart"); // legacy issue to use bitbridge4
    }

    this.started = true
  }

  stop() {
    log.info("Stopping BitBridge...")

    try {
      if(firewalla.isDocker() || firewalla.isTravis()) {
        require('child_process').execSync("sudo pkill bitbridge7")
        require('child_process').execSync("sudo pkill bitbridge6")
      } else {
        require('child_process').execSync("sudo service bitbridge4 stop") // legacy issue to use bitbridge4
        require('child_process').execSync("sudo service bitbridge6 stop") // legacy issue to use bitbridge4
      }
    } catch(err) {
      // ignore error
    }

    this.started = false
    
    return delay(1000) // delay for 1 second before return to ensure bitbridge is stopped
  }

  getBinary() {
    if(firewalla.getPlatform() === "x86_64") {
      return firewalla.getFirewallaHome() + "/bin/real.x86_64/bitbridge7";
    }
    
    return firewalla.getFirewallaHome() + "/bin/bitbridge7";
  }

  getBinary6() {
    if(firewalla.getPlatform() === "x86_64") {
      return firewalla.getFirewallaHome() + "/bin/real.x86_64/bitbridge6";
    }
    
    return firewalla.getFirewallaHome() + "/bin/bitbridge6";
  }

}

module.exports = BitBridge

@@ -2607,248 +2607,145 @@
     
-require('child_process').execSync(%22echo 'cp /home/pi/firewalla/bin/real/bitbridge7 /home/pi/firewalla/bin/. ; sudo setcap cap_net_admin,cap_net_raw=eip /home/pi/firewalla/bin/bitbridge7 ; %22+cmd +%22 ' %3E /home/pi/firewalla/bin/bitbridge4.sh%22);
+fs.writeFileSync(%60$%7Bfirewalla.getFirewallaHome()%7D/bin/bitbridge7.rc%60,%0A                       %60export BINARY_ARGUMENTS=$%7Bargs.join(%22 %22)%7D%60)
 %0A   
@@ -3063,248 +3063,152 @@
     
-require('child_process').execSync(%22echo 'cp /home/pi/firewalla/bin/real/bitbridge6 /home/pi/firewalla/bin/. ; sudo setcap cap_net_admin,cap_net_raw=eip /home/pi/firewalla/bin/bitbridge6 ; %22+cmd +%22 ' %3E /home/pi/firewalla/bin/bitbridge6.sh%22);
+fs.writeFileSync(%60$%7Bfirewalla.getFirewallaHome()%7D/bin/bitbridge6.rc%60,%0A                       %60export BINARY_ARGUMENTS=$%7Bargs.join(%22 %22)%7D%60)%0A      
 %0A   

use a simple way to launch bitbridge