/// <summary> /// Gets a listener on a port within the assigned port range. /// </summary> /// <param name="connection">Connection for which to create the listener.</param> /// <param name="pasvOptions">The options for the <see cref="IPasvListener"/>.</param> /// <returns>Configured PasvListener.</returns> /// <exception cref="SocketException">When no free port could be found, or other bad things happen. See <see cref="SocketError"/>.</exception> private IPasvListener CreateListenerInRange(IFtpConnection connection, PasvListenerOptions pasvOptions) { lock (_listenerLock) { // randomize ports so we don't always get the ports in the same order foreach (var port in GetPorts(pasvOptions)) { try { return(new PasvListener(connection.LocalEndPoint.Address, port, pasvOptions.PublicAddress)); } catch (SocketException se) { // retry if the socket is already in use, else throw the underlying exception if (se.SocketErrorCode != SocketError.AddressAlreadyInUse) { _log?.LogError(se, "Could not create listener"); throw; } } } // if we reach this point, we have not been able to create a listener within range _log?.LogWarning("No free ports available for data connection"); throw new SocketException((int)SocketError.AddressAlreadyInUse); } }
private IEnumerable <int> GetPorts(PasvListenerOptions options) { var portRangeCount = (options.PasvMaxPort - options.PasvMinPort + 1) * 2; while (portRangeCount-- != 0) { yield return(_prng.Next(options.PasvMinPort, options.PasvMaxPort + 1)); } }