blob: b01d4db1f1cb8d6941202390a53f4048a514edd7 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.net;
import com.intellij.Patches;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.SystemInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
public class NetUtils {
private static final Logger LOG = Logger.getInstance(NetUtils.class);
private NetUtils() {
}
public static boolean canConnectToSocket(String host, int port) {
return canConnectToSocket(host, port, false);
}
public static boolean canConnectToSocketOpenedByJavaProcess(String host, int port) {
return canConnectToSocket(host, port, Patches.SUN_BUG_ID_7179799);
}
private static boolean canConnectToSocket(String host, int port, boolean alwaysTryToConnectDirectly) {
if (isLocalhost(host)) {
if (!canBindToLocalSocket(host, port)) {
return true;
}
return alwaysTryToConnectDirectly && canConnectToRemoteSocket(host, port);
}
else {
return canConnectToRemoteSocket(host, port);
}
}
public static InetAddress getLoopbackAddress() {
try {
// todo use JDK 7 InetAddress.getLoopbackAddress()
return InetAddress.getByName(null);
}
catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
public static boolean isLocalhost(@NotNull String host) {
return host.equalsIgnoreCase("localhost") || host.equals("127.0.0.1") || host.equals("::1");
}
private static boolean canBindToLocalSocket(String host, int port) {
try {
ServerSocket socket = new ServerSocket();
try {
//it looks like this flag should be set but it leads to incorrect results for NodeJS under Windows
//socket.setReuseAddress(true);
socket.bind(new InetSocketAddress(host, port));
}
finally {
try {
socket.close();
}
catch (IOException ignored) {
}
}
return true;
}
catch (IOException e) {
LOG.debug(e);
return false;
}
}
public static boolean canConnectToRemoteSocket(String host, int port) {
try {
Socket socket = new Socket(host, port);
socket.close();
return true;
}
catch (IOException ignored) {
return false;
}
}
public static int findAvailableSocketPort() throws IOException {
final ServerSocket serverSocket = new ServerSocket(0);
try {
int port = serverSocket.getLocalPort();
// workaround for linux : calling close() immediately after opening socket
// may result that socket is not closed
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (serverSocket) {
try {
//noinspection WaitNotInLoop
serverSocket.wait(1);
}
catch (InterruptedException e) {
LOG.error(e);
}
}
return port;
}
finally {
serverSocket.close();
}
}
public static int tryToFindAvailableSocketPort(int defaultPort) {
try {
return findAvailableSocketPort();
}
catch (IOException ignored) {
return defaultPort;
}
}
public static int tryToFindAvailableSocketPort() {
return tryToFindAvailableSocketPort(-1);
}
public static int[] findAvailableSocketPorts(int capacity) throws IOException {
final int[] ports = new int[capacity];
final ServerSocket[] sockets = new ServerSocket[capacity];
for (int i = 0; i < capacity; i++) {
//noinspection SocketOpenedButNotSafelyClosed
final ServerSocket serverSocket = new ServerSocket(0);
sockets[i] = serverSocket;
ports[i] = serverSocket.getLocalPort();
}
//workaround for linux : calling close() immediately after opening socket
//may result that socket is not closed
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (sockets) {
try {
//noinspection WaitNotInLoop
sockets.wait(1);
}
catch (InterruptedException e) {
LOG.error(e);
}
}
for (ServerSocket socket : sockets) {
socket.close();
}
return ports;
}
public static String getLocalHostString() {
// HACK for Windows with ipv6
String localHostString = "localhost";
try {
final InetAddress localHost = InetAddress.getByName(localHostString);
if ((localHost.getAddress().length != 4 && SystemInfo.isWindows) ||
(localHost.getAddress().length == 4 && SystemInfo.isMac)) {
localHostString = "127.0.0.1";
}
}
catch (UnknownHostException ignored) {
}
return localHostString;
}
/**
* @param indicator Progress indicator.
* @param inputStream source stream
* @param outputStream destination stream
* @param expectedContentSize expected content size, used in progress indicator. can be -1.
* @return bytes copied
* @throws IOException if IO error occur
* @throws com.intellij.openapi.progress.ProcessCanceledException if process was canceled.
*/
public static int copyStreamContent(@Nullable ProgressIndicator indicator,
InputStream inputStream,
OutputStream outputStream,
int expectedContentSize) throws IOException, ProcessCanceledException {
if (indicator != null) {
indicator.checkCanceled();
if (expectedContentSize < 0) indicator.setIndeterminate(true);
}
final byte[] buffer = new byte[4 * 1024];
int count;
int total = 0;
while ((count = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, count);
total += count;
if (indicator != null) {
indicator.checkCanceled();
if (expectedContentSize > 0) {
indicator.setFraction((double)total / expectedContentSize);
}
}
}
if (indicator != null) {
indicator.checkCanceled();
}
return total;
}
}