# File lib/rhc/commands/port-forward.rb, line 75
    def run(app)

      rest_domain = rest_client.find_domain options.namespace
      rest_app = rest_domain.find_application app

      ssh_uri = URI.parse(rest_app.ssh_url)
      say "Using #{rest_app.ssh_url}..." if options.debug

      forwarding_specs = []

      begin
        say "Checking available ports..."

        Net::SSH.start(ssh_uri.host, ssh_uri.user) do |ssh|
          ssh.exec! "rhc-list-ports" do |channel, stream, data|
            if stream == :stderr
              data.each_line do |line|
                line.chomp!
                # FIXME: This is really brittle; there must be a better way
                # for the server to tell us that permission (what permission?)
                # is denied.
                raise RHC::PermissionDeniedException.new "Permission denied." if line =~ /permission denied/i
                # ...and also which services are available for the application
                # for us to forward ports for.
                if line =~ /\A\s*(\S+) -> #{IP_AND_PORT}/
                  debug fs = ForwardingSpec.new($1, $2, $3.to_i)
                  forwarding_specs << fs
                else
                  debug line
                end

              end
            end
          end
          
          if forwarding_specs.length == 0
            # check if the gears have been stopped
            ggs = rest_app.gear_groups
            if ggs.any? { |gg|
              gears = gg.gears
              true if gears.any? { |g| g["state"] == "stopped" }
            }
              warn "Application #{rest_app.name} is stopped. Please restart the application and try again."
              return 1
            else
              raise RHC::NoPortsToForwardException.new "There are no available ports to forward for this application. Your application may be stopped." 
            end
          end

          begin
            Net::SSH.start(ssh_uri.host, ssh_uri.user) do |ssh|
              say "Forwarding ports"
              forwarding_specs.each do |fs|
                given_up = nil
                while !fs.bound? && !given_up
                  begin
                    args = fs.to_fwd_args
                    debug args.inspect
                    ssh.forward.local(*args)
                    fs.bound = true
                  rescue Errno::EADDRINUSE
                    debug "trying local port #{fs.port_from}"
                    fs.port_from += 1
                  rescue Timeout::Error, Errno::EADDRNOTAVAIL, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Net::SSH::AuthenticationFailed => e
                    given_up = true
                  end
                end
              end

              bound_ports = forwarding_specs.select(&:bound?)
              if bound_ports.length > 0
                items = bound_ports.map do |fs|
                  [fs.service, "#{fs.host_from}:#{fs.port_from}", " => ", "#{fs.remote_host}:#{fs.port_to.to_s}"]
                end
                table(items, :header => ["Service", "Connect to", "    ", "Forward to"]).each { |s| success "  #{s}" }
              end

              # for failed port forwarding attempts
              failed_port_forwards = forwarding_specs.select { |fs| !fs.bound? }
              if failed_port_forwards.length > 0
                ssh_cmd_arg = failed_port_forwards.map { |fs| fs.to_cmd_arg }.join(" ")
                ssh_cmd = "ssh -N #{ssh_cmd_arg} #{ssh_uri.user}@#{ssh_uri.host}"
                warn "Error forwarding some port(s). You can try to forward manually by running:\n#{ssh_cmd}"
              else
                say "Press CTRL-C to terminate port forwarding"
              end

              unless forwarding_specs.any?(&:bound?)
                warn "No ports have been bound"
                return
              end
              ssh.loop { true }
            end
          rescue Interrupt
            results { say "Ending port forward" }
            return 0
          end

        end

      rescue Timeout::Error, Errno::EADDRNOTAVAIL, Errno::EADDRINUSE, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Net::SSH::AuthenticationFailed => e
        ssh_cmd = ["ssh","-N"]
        unbound_fs = forwarding_specs.select { |fs| !fs.bound? }
        ssh_cmd += unbound_fs.map { |fs| fs.to_cmd_arg }
        ssh_cmd += ["#{ssh_uri.user}@#{ssh_uri.host}"]
        raise RHC::PortForwardFailedException.new("#{e.message + "\n" if options.debug}Error trying to forward ports. You can try to forward manually by running:\n" + ssh_cmd.join(" "))
      end

      return 0
    rescue RestClient::Exception => e
      error "Connection to #{openshift_server} failed: #{e.message}"
      return 1
    end