Quite a while ago I posted a question about how to use a proxy in minecraft.
To sum most of the question up, I'm working on a mob in which I would like to be able to change the proxy of the JVM whenever I want during the code. I understand that it is easy to just set the proxy when invoking the VM but I want to be able to change it in real-time while in the game so that when I connect to a server my IP is different (this mod is mostly going to be used by people who are parranoid of joining servers and people knowing their IP.
I have tried setting System Properties as so:
System.setProperty("http.proxyHost", "186.116.8.170");
System.setProperty("http.proxyPort", "8080");
and also tried doing
System.setProperty("https.proxyHost", "186.116.8.170");
System.setProperty("https.proxyPort", "8080");
but none of that worked.
I would appreciate any help given, thanks.
minecraft used netty, you need to use mixin to modify net.minecraft.network.NetworkManager
code for 1.8.9 below
#Mixin(NetworkManager.class)
public abstract class MixinNetworkManager {
#Shadow
#Final
public static LazyLoadBase<NioEventLoopGroup> CLIENT_NIO_EVENTLOOP;
#Overwrite
public static NetworkManager createNetworkManagerAndConnect(InetAddress address, int serverPort, boolean useNativeTransport) {
final NetworkManager networkmanager = new NetworkManager(EnumPacketDirection.CLIENTBOUND);
Bootstrap bootstrap=new Bootstrap();
EventLoopGroup eventLoopGroup;
Proxy proxy=ProxyManager.INSTANCE.getProxy();
if(proxy.type().equals(Proxy.Type.DIRECT)){
eventLoopGroup=CLIENT_NIO_EVENTLOOP.getValue();
bootstrap.channel(NioSocketChannel.class);
}else {
if(!Epoll.isAvailable()||!useNativeTransport){
System.out.println("Something goes wrong! Maybe you can disable proxy. [Epoll="+Epoll.isAvailable()+", UNT="+useNativeTransport+"]");
}
eventLoopGroup=new OioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).build());
bootstrap.channelFactory(new ProxyOioChannelFactory(proxy));
}
bootstrap.group(eventLoopGroup).handler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) {
try {
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
} catch (ChannelException var3) {
var3.printStackTrace();
}
channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("splitter", new MessageDeserializer2()).addLast("decoder", new MessageDeserializer(EnumPacketDirection.CLIENTBOUND)).addLast("prepender", new MessageSerializer2()).addLast("encoder", new MessageSerializer(EnumPacketDirection.SERVERBOUND)).addLast("packet_handler", networkmanager);
}
});
bootstrap.connect(address, serverPort).syncUninterruptibly();
return networkmanager;
}
Related
I'm trying to make Socks v4 work out of the box in java.net, and I seem to have succeeded!
Roughtly the code that I'm using is this:
class SocketImplFactorySocks4 implements SocketImplFactory {
#Override
public SocketImpl createSocketImpl() {
System.out.println("Socket implementation triggered");
try {
return socketSocks4Factory();
} catch (Exception e) {
e.printStackTrace();
throw new Error("Can't go further");
}
}
private SocketImpl socketSocks4Factory() throws
[...] {
Class<?> aClass = Class.forName("java.net.SocksSocketImpl");
Constructor<?> cons = aClass.getDeclaredConstructor();
if (!cons.isAccessible())
cons.setAccessible(true);
Object socket = cons.newInstance();
Method method = socket.getClass().getDeclaredMethod("setV4");
if (!method.isAccessible())
method.setAccessible(true);
method.invoke(socket);
Field field = socket.getClass().getDeclaredField("useV4");
field.setAccessible(true);
Object value = field.get(socket);
return (SocketImpl) socket;
}
}
Long story short, it works when I create a socket and pass -DsocksProxyHost and -DsocksProxyPort.
My problem is when I use the same code in my junit test, I can check with Reflections that Socket.impl.useV4 is set to true, socksProxy* settings are set systemwide, but when I use my socket, it avoids using proxy altogether (I can see it in wireshark).
It's either JUnit or Gradle, but I've reached my limits. Please advice on where should I go next. build.gradle.kts for reference:
tasks{
test{
systemProperty("socksProxyHost", "localhost")
systemProperty("socksProxyPort", "8080")
}
}
Thanks in advance!
Well, it took me way too much time to figure it out, but I did. My initial goal was to test my Socks v4 server code, but there were two problems on my way:
1) Even though Java Socket has support for Socks v4 as client, it is not enabled by default. And there is no way to flip the toggle.
2) Having solved #1, I tried to write E2E test to smoke the whole thing, but for some reason it was avoiding going into the Socks proxy, even though the toggle (useV4) was true. This is what I came with here on SO.
To solve the first problem, I implemented SocketImplFactory (see above in the question).
What helped to tackle the topic question was my admin background, even though it didn't kick in until recently. :) I separated the original suspects (JUnit and Gradle) and made the test in a standalone psvm file. The test didn't work, it still avoided going through the proxy. And this is when it hit me: exception for localhost!
Basically, there is a hardcoded exception for localhost(127.0.0.1, ::, etc) deep in Java core library. After some searching I came across DsocksNonProxyHosts option. Which didn't help, as you might have guessed already :)
Eventually I ended up at this answer, which mentioned that I might need to implement ProxySelector. Which I did:
static class myProxySelector extends ProxySelector {
#Override
public List<Proxy> select(URI uri) {
List<Proxy> proxyl = new ArrayList<Proxy>(1);
InetSocketAddress saddr = InetSocketAddress.createUnresolved("localhost", 1080);
Proxy proxy = SocksProxy.create(saddr, 4);
proxyl.add(proxy);
System.out.println("Selecting Proxy for " + uri.toASCIIString());
return proxyl;
}
#Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
if (uri == null || sa == null || ioe == null) {
throw new IllegalArgumentException("Arguments can't be null.");
}
}
}
The whole socket setup looks like this:
private void setupSocket() throws IOException {
Socket.setSocketImplFactory(new SocketImplFactorySocks4());
ProxySelector proxySelector = new myProxySelector();
ProxySelector.setDefault(proxySelector);
proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 1080));
}
Now everything I wanted works: I'm both able to E2E-test my socks4 code and can do it localhost.
I'm using JAVA/Spring MVC and I need to make a Connection Pool for a Third Party Application integration in my application becouse when i try to connect it multiple time my application and server System utilize 100% RAM.
here i have to problem, when users start to hit a specific method (callGenerationService()) multiple time, my Heap memory(RAM space) increases and becomes 100% and application going to slow becouse of it connect third party application multiple times ? here i need to create a connection only once and get it multiple times. where my connection like,
public class ClickToCallServiceImpl implements ClickToCallServiceInterface {
Client client = null;
#Override
public ClickToCall callGenerationService(ClickToCall clickToCall) {
client = new Client();
client.connect("127.0.0.1", 8021 , "password", 10); //Every time Connection Connect.
client.setEventSubscriptions("plain", "all");
// client.sendSyncApiCommand("",""); //here i run command on every hit like.
client.sendSyncApiCommand(clickToCall.command1, clickToCall.command2);
client.close();
}
}
and here 'ClickToCall' is a #Component Bean/POJO Class with variables setters and getters.
Is there, how to we create a connection (either pool or only once connect) for above connection where i connect only once and hit clickToCall.Command1 and clickToCall.Command2 multiple times and utilize less RAM? Thanks in advance.
Please note that I'm not an expert of freeswitch esl so you must check the code properly. Anyway this is what I would do.
First I create a Factory for Client
public class FreeSwitchEslClientFactory extends BasePooledObjectFactory<Client> {
#Override
public Client create() throws Exception {
//Create and connect: NOTE I'M NOT AN EXPERT OF ESL FREESWITCH SO YOU MUST CHECK IT PROPERLY
Client client = new Client();
client.connect("127.0.0.1", 8021 , "password", 10);
client.setEventSubscriptions("plain", "all");
return client;
}
#Override
public PooledObject<Client> wrap(Client obj) {
return new DefaultPooledObject<Client>(obj);
}
}
Then I create a shareable GenericObjectPool:
#Configuration
#ComponentScan(basePackages= {"it.olgna.spring.pool"})
public class CommonPoolConfig {
#Bean("clientPool")
public GenericObjectPool<Client> clientPool(){
GenericObjectPool<Client> result = new GenericObjectPool<Client>(new FreeSwitchEslClientFactory());
//Pool config e.g. max pool dimension
result.setMaxTotal(20);
return result;
}
}
Finally I use the created pool in order to get the Client obj:
#Component
public class FreeSwitchEslCommandSender {
#Autowired
#Qualifier("clientPool")
private GenericObjectPool<Client> pool;
public void sendCommand(String command, String param) throws Exception{
Client client = null;
try {
client = pool.borrowObject();
client.sendSyncApiCommand(command, param);
} finally {
if( client != null ) {
client.close();
}
pool.returnObject(client);
}
}
}
I didn't test (also because I can't) it but it should work. In any case I pray you to properly check the configuration. I don't know if it's OK to always create a Client object and connect or if it's better to connect when you want to send command
I hope it can be useful
EDIT INFORMATION
Sorry I made an error early. You must return the client to the pool
I updated my FreeSwitchEslCommandSender class
Angelo
While performing a client-server communication with various forums, I am unable to perform Remote-object's lookup on the client machine.
The errors which I receive are ConnectIOException(NoRouteToHostException), and sometimes ConnectException and sometimes someother.
This is not what I want to ask. But, the main concern is how should I setup client platform and server platform --- talking about networking details --- this is what I doubt interferes with my connection.
My questions :-
How should I edit my /etc/hosts file on both client-side and server-side? Server's IP- 192.168.1.8 & Client's IP-192.168.1.100. Means, should I add the system name in both the files:
192.168.1.8 SERVER-1 # on the server side
192.168.1.100 CLIENT-1 # on the client side
Should I edit like this? Can this be one of the possible concerns? I just want to remove any doubts left over to perform the rmi-communication!
Also, I am also setting Server's hostname property using System.setProperty("java.rmi.server.hostname",192.168.1.8); on the server side. Should I do the same on the client-side too?
I've read about setting classpath while running the java program on both server-side as well as the client-side. I did this too,but,again the same exceptions. No difference at all. I've read that since Java update 6u45, classpaths aren't necessary to include! Please throw some light on this too...
If I am missing something, Please enlighten about the same too. A brief idea/link to resources are most preferred.
You don't need any of this unless you have a problem. The most usual problem is the one described in the RMI FAQ #A.1, and editing the hosts file of the server or setting java.rmi.server.hostname in the server JVM is the solution to that.
'No route to host' is a network connectivity problem, not an RMI problem, and not one you'll solve with code or system property settings.
Setting the classpath has nothing to do with network problems.
Here is server example of which transfers an concrete class. This class must be exist in server and client classpath with same structure
Message:
public class MyMessage implements Serializable {
private static final long serialVersionUID = -696658756914311143L;
public String Title;
public String Body;
public MyMessage(String strTitle) {
Title = strTitle;
Body = "";
}
public MyMessage() {
Title = "";
Body = "";
}
}
And here is the server code that gets an message and returns another message:
public class SimpleServer {
public String ServerName;
ServerRemoteObject mRemoteObject;
public SimpleServer(String pServerName) {
ServerName = pServerName;
}
public void bindYourself() {
try {
mRemoteObject = new ServerRemoteObject(this);
java.rmi.registry.Registry iRegistry = LocateRegistry.getRegistry(RegistryContstants.RMIPort);
iRegistry.rebind(RegistryContstants.CMName, mRemoteObject);
} catch (Exception e) {
e.printStackTrace();
mRemoteObject = null;
}
}
public MyMessage handleEvent(MyMessage mMessage) {
MyMessage iMessage = new MyMessage();
iMessage.Body = "Response body";
iMessage.Title = "Response title";
return iMessage;
}
public static void main(String[] server) {
SimpleServer iServer = new SimpleServer("SERVER1");
iServer.bindYourself();
while (true) {
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
and here is the remote interface of server remote object:
public interface ISimpleServer extends java.rmi.Remote{
public MyMessage doaction(MyMessage message) throws java.rmi.RemoteException;
}
all you need is adding MyMessage class both in server and client classpath.
I have a Java app that uses the Jetty WebSocket Client, version 9.x. It works fine for text messages sent from the server, but the binary listener is never invoked. I have a Javascript client implementation which I'm basically duplicating. I'm doing the same exact thing in Javascript that I do in Java, calling the same server. The Javascript works, and the Java doesn't. So I'm thinking that something is not configured properly in Jetty for binary listeners.
For example, the server is sending blob data. I know that in the Javascript client, I can set the binarytype to either arraybuffer or blob. I figured there may be a similar setting required in Jetty, but I've looked all through the API and searched many examples online. There are precious few examples of binary listeners online, and no mention anywhere of setting the binarytype, or any other special setting required to make binary llisteners work.
Here's a consolidated representation of my code. The code is spread throughout various classes, so this is not a stand-alone app, but I think it shows what I'm doing. The server is implemented with libwebsockets.
Client implementation
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
client = new WebSocketClient();
client.start();
client.setMaxBinaryMessageBufferSize((int) 500e6);//just to be sure
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setSubProtocols("pipe-data");
client = new SimpleSocket();
client.connect(socket, uri, request);
Socket implementation
#WebSocket
public class SimpleSocket {
#SuppressWarnings("unused")
private Session session;
private SocketHandlerBase handler;
private boolean connected = false;
public SimpleSocket(SocketHandlerBase listener) {
this.handler = listener;
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
this.handler.onClose(statusCode, reason);
this.connected = false;
}
#OnWebSocketConnect
public void onConnect(Session session) {
this.handler.onConnect(session);
this.connected = true;
}
//invoked when text messages are sent
#OnWebSocketMessage
public void onMessage(String msg) {
this.handler.onMessage(msg);
}
//does not get invoked when binary data is sent
#OnWebSocketMessage
public void onMessage(byte buf[], int offset, int length) {
this.handler.onMessage(buf, offset, length);
}
public boolean isConnected() {
return this.connected;
}
public SocketHandlerBase getHandler() {
return this.handler;
}
}
There was a hard to find problem with the server I was calling. A very specific configuration of invocation arguments was causing the binary listener to not be called. Nothing about the Jetty client or WebSockets in general involved here.
I am trying to do a git pull/push using jgit's api with the following code
org.eclipse.jgit.api.Git.open(theRepoFile).pull().call()
but I am getting exceptions
JSchException Auth fail
com.jcraft.jsch.Session.connect (Session.java:461)
org.eclipse.jgit.transport.JschConfigSessionFactory.getSession (JschConfigSessionFactory.java:116)
org.eclipse.jgit.transport.SshTransport.getSession (SshTransport.java:121)
org.eclipse.jgit.transport.TransportGitSsh$SshPushConnection.<init> (TransportGitSsh.java:306)
org.eclipse.jgit.transport.TransportGitSsh.openPush (TransportGitSsh.java:152)
org.eclipse.jgit.transport.PushProcess.execute (PushProcess.java:130)
org.eclipse.jgit.transport.Transport.push (Transport.java:1127)
org.eclipse.jgit.api.PushCommand.call (PushCommand.java:153)
Even though using cgit pull and pushing works.
I tried checking SO for example code
Java git client using jgit
but the above question does not provide a complete coded example of what is necessary to do a git pull with a remote repo that is normally authenticated via ssh keys. There should be a way to get the credential information from ~/.ssh/ or the windows equivalent.
Jsch will automatically detect your SSH keys but will fail if these are protected by a password. You need to specify the passphrase through a CredentialsProvider like this:
JschConfigSessionFactory sessionFactory = new JschConfigSessionFactory() {
#Override
protected void configure(OpenSshConfig.Host hc, Session session) {
CredentialsProvider provider = new CredentialsProvider() {
#Override
public boolean isInteractive() {
return false;
}
#Override
public boolean supports(CredentialItem... items) {
return true;
}
#Override
public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {
for (CredentialItem item : items) {
((CredentialItem.StringType) item).setValue("yourpassphrase");
}
return true;
}
};
UserInfo userInfo = new CredentialsProviderUserInfo(session, provider);
session.setUserInfo(userInfo);
}
};
SshSessionFactory.setInstance(sessionFactory);
The problem is Jsch does not support ssh-agents out of the box. One will need to configure https://github.com/ymnk/jsch-agent-proxy to get it to work.
An alternative is to make your own org.eclipse.jgit.transport.CredentialsProvider and set the org.eclipse.jgit.transport.CredentialItem to the correct values (by requesting them from the user or looking up a file). You can change the default CredentialsProvider with org.eclipse.jgit.transport.CredentialsProvider/setDefault
See my clojure library dj for details: https://github.com/bmillare/dj/blob/library/src/dj/git.clj
I vaguely remember getting an error with JSch that blocked me for a while because the log was not very explicit. I can't tell for sure it's the same problem but I followed this page to solve my problem:
https://help.github.com/articles/generating-ssh-keys
(it was due to a wrong network configuration)