"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
Object.defineProperty(exports, "__esModule", { value: true });
exports.RetryTcpListenerFactory = void 0;
const net = require("net");
/**
 * Implementation of a TCP listener factory that retries forwarding with nearby ports and falls back to a random port.
 * We make the assumption that the remote port that is being connected to and localPort numbers are the same.
 */
class RetryTcpListenerFactory {
    constructor(localAddress) {
        this.localAddress = localAddress;
    }
    async createTcpListener(remotePort, localIPAddress, localPort, canChangeLocalPort, cancellation) {
        // The SSH protocol may specify a local IP address for forwarding, but that is ignored
        // by tunnels. Instead, the tunnel client can specify the local IP address.
        if (localIPAddress.indexOf(':') >= 0) {
            // Convert special local address values from IPv4 to IPv6.
            if (this.localAddress === '0.0.0.0') {
                localIPAddress = '::';
            }
            else if (this.localAddress === '127.0.0.1') {
                localIPAddress = '::1';
            }
        }
        else {
            // IPv4
            localIPAddress = this.localAddress;
        }
        const maxOffset = 10;
        const listener = net.createServer();
        for (let offset = 0;; offset++) {
            // After reaching the max offset, pass 0 to pick a random available port.
            const localPortNumber = offset === maxOffset ? 0 : localPort + offset;
            try {
                return await new Promise((resolve, reject) => {
                    listener.listen({
                        host: localIPAddress,
                        port: localPortNumber,
                        ipv6Only: net.isIPv6(localIPAddress),
                    });
                    listener.on('listening', () => {
                        if (remotePort) {
                            const { address, port } = listener.address();
                            console.log(`Forwarding from ${address}:${port} to host port ${remotePort}.`);
                        }
                        resolve(listener);
                    });
                    listener.on('error', (err) => {
                        reject(err);
                    });
                });
            }
            catch (err) {
                if (offset < maxOffset && canChangeLocalPort) {
                    console.log('Listening on port ' + localPortNumber + ' failed: ' + err);
                    console.log('Incrementing port and trying again');
                    continue;
                }
                else {
                    throw err;
                }
            }
        }
    }
}
exports.RetryTcpListenerFactory = RetryTcpListenerFactory;
//# sourceMappingURL=https://main.vscode-cdn.net/sourcemaps/6a44c352bd24569c417e530095901b649960f9f8/node_modules/@microsoft/dev-tunnels-connections/retryTcpListenerFactory.js.map