Is it possible to obtain a reference to connected client's x509Certificate object in Remote server implementation?
Rewrited RMISocketFactory:
RMISocketFactory.setSocketFactory(
new java.rmi.server.RMISocketFactory() {
...
#Override
public ServerSocket createServerSocket(int port)
throws IOException {
SSLServerSocket socket = ...
socket.setNeedClientAuth(true);
return socket;
}
});
Remote Object:
public class RMIServer extends UnicastRemoteObject implements IRMIServer {
public RMIServer() throws RemoteException {
super(0);
}
#Override
public String foo() throws RemoteException {
System.out.println(getClientCertificate().getSubjectDN().getName()); // something like this?
}
}
You've hit on a major design flaw in RMI. It's practically impossible for an RMI server to get hold of the client certificate, or vice versa, as it's practically impossible to know which SSLSocket is in use for the current call. They should have provided a way to attach something like a HandshakeCompletionListener.
Related
Does anyone know why channelReadComplete gets called before channelRead in some situations? I have a server that is pretty dumb right now that another netty server connects to. The first initializer does this:
final EventExecutorGroup taskGroup = new DefaultEventExecutorGroup(50);
ChannelPipeline pipeline = ctx.pipeline();
pipeline.addLast(taskGroup, "ServerHandler", new ServerHandler());
And then in ServerHandler
public class ServerHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("channelRead");
// ctx.write(msg);
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
System.out.println("channelReadComplete");
// ctx.flush();
}
I consistently get channelReadComplete before channelRead when the first netty server connects to the second netty server. Is there a reason for this?
My server code looks something like this:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server implements Runnable {
private ServerSocket serverSocket;
public Server(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
#Override
public void run() {
try {
Socket client = serverSocket.accept();
// do stuff
} catch (IOException e) {
e.printStackTrace();
}
}
}
My plan was to write a mock client that connects to the server socket, and verifies the result, but in order to do that I need to know which port to connect to. However, this information is private.
None of the options I was thinking about are good practice I think:
If I use a predefined port number for the tests, I have no guarantee that it will be available. Even if it's available just before the test, it might be, theoretically snatched by the time I try to use it.
If I pass 0 as port number (so that ServerSocket will atomically provide a free port), I still have no access to it.
I could add a getServerPort() method to the interface or create a constructor that accepts a ServerSocket object, but changing the interface only for the sake of testing is considered bad practice.
As written, your class is not really suited for unit test.
The problem is that your direct call to new ServerSocket() basically deprives your ability to control what the socket object will be doing.
So, what you can do:
interface SocketFactory {
public ServerSocket createSocketFor(int port);
}
class SocketFactoryImpl implements SocketFactory {
...
public class Server implements Runnable {
public Server(int port) {
this(port, new SocketFactoryImpl());
}
Server(int port, SocketFactory socketFactory) {
...
In other words: you use dependency injection in order to provide a mean to your "class under test" to create those objects that it needs to do its work.
From there: you can use a mocking framework such as EasyMock in order to control what a mocked SocketFactory object will return (probably a mocked ServerSocket object). And now that you have full control over the ServerSocket used by your production code ... you can test whatever situation you want.
Long story short: don't call new; instead use dependency injection to gain full control over your class under test.
(and maybe watch these videos to really understand what writing testable code is about).
I have a very basic question. I have just started with vertx Framework. There is one thing I am not able to understand like
vertx.createNetServer().connectHandler(new Handler<NetSocket>() {
#Override
public void handle(final NetSocket socket) {
socket.dataHandler(new Handler<Buffer>() {
public void handle(Buffer buffer) {
/* I can access the socket object inside this handler */
socket.write("Hello");
}
});
}
}).listen(1234);
but if I write the handler function separately like this
Handler<Message> socketHandler = new Handler<Buffer>() {
public void handle(Buffer buffer) {
/* How can i access the socket object now */
socket.write("Hello"); //this will give error as it does not recognize the socket object
}
};
vertx.createNetServer().connectHandler(new Handler<NetSocket>() {
#Override
public void handle(final NetSocket socket) {
socket.dataHandler(socketHandler);//now I write handler separately
}
}).listen(1234);
Handler can be anywhere in the same java class or other java class. Please help me me how I can write handler separately and still access the socket object.
In your second example, you're not passing socket to socketHandler, so you cannot expect socketHandler to know about it.
You could solve this by creating a method like createSocketHandler(final Socket socket) that returns a Handler<Message> and that replaces your socketHandler variable.
To learn more, and to find out why you need socket to be final, look up "anonymous inner classes"
I'm writing a small RMI based Chat application.
The idea is: the Client registers himself on the Server, and everytime the server receives a message from a client, he pushes this message to all other clients.
But I receive a NotSerializableException although, the object, I'm passing as a method parameter implements the Remote interface.
Here is some code:
(The problematic part is the this parameter in this.chatServ.registriereClient(this); (ClientChat Implementation))
The (ClientChat)interface:
public interface ChatClient extends Remote
{
}
(ClientChat)Implementation:
public class ChatClientImpl implements ChatClient
{
ChatServer chatServ;
String clientName;
public ChatClientImpl(String clientName, ChatServer chatServ) {
this.chatServ = chatServ;
this.clientName = clientName;
try {
this.chatServ.registriereClient(this);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
(ServerChat) Interface
public interface ChatServer extends Remote
{
void registriereClient(ChatClient client) throws RemoteException;
}
(ServerChat) Implementation
public class LobbyChatServerImpl implements ChatServer
{
ArrayList<ChatClient> clientListe = null;
#Override
public void registriereClient(ChatClient client) {
System.out.println("Client registriert");
this.clientListe.add(client);
}
}
Client:
public static void main(String[] args) {
ChatServer lobbyChatServer = null;
try {
Registry registry = LocateRegistry.getRegistry(Server.RMI_PORT);
lobbyChatServer = (ChatServer) registry.lookup("LobbyChatServer");
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
ChatClient lobbyChat = new ChatClientImpl(name, lobbyChatServer);
}
Server:
public static void main(String[] args) {
try {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
Registry registry = LocateRegistry.getRegistry(RMI_PORT);
ChatServer lobbyChatStub = (ChatServer)UnicastRemoteObject.exportObject(new LobbyChatServerImpl(), 0);
registry.bind("LobbyChatServer", lobbyChatStub);
} catch (RemoteException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
e.printStackTrace();
}
}
Exception:
java.rmi.MarshalException: error marshalling arguments; nested exception is:
java.io.NotSerializableException: de.XX.Chat.ChatClientImpl
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:156)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at $Proxy0.registriereClient(Unknown Source)
at de.XX.Chat.ChatClientImpl.<init>(ChatClientImpl.java:19)
at de.XX.Client.main(Client.java:49)
Caused by: java.io.NotSerializableException: de.XX.Chat.ChatClientImpl
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:292)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:151)
... 5 more
As already said, I wonder why i get this kind of Exception, although ChatClientImpl is already Remote.
Hope you can help me:)
Objects passed as parameters or results of remote methods must be either:
Serializable (or Externalizable), or
Exported remote objects.
Yours is neither. However as it implements a Remote interface clearly you intended (2).
Objects that extend UnicastRemoteObject are auto-exported on construction. Objects that don't must be exported explicitly, via UnicastRemoteObject.exportObject().
What you can do is setup a callback object. This is one which extends UnicastRemoteObject and when you pass this it becomes a callback.
http://www.cs.swan.ac.uk/~csneal/InternetComputing/RMIChat.html
Remote is not Serializable. You can't pass a proxy object this way. Even if you made it Serializable it would send a copy of the object which would exist on the server. The copy of the object on the client would not be called.
For your "server" to send messages to your "client" you have to create a service on the "client" to make it a server.
You may find that using a messaging solution such as JMS is better suited to this take. A JMS server has topics which you can publish to and subscribe from. A simple JMS server to use is Active MQ.
Looks like you might have forgotten to 'extends UnicastRemoteObject' on the interface implementations:
public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{
}
and
public class LobbyChatServerImpl extends UnicastRemoteObject implements ChatServer{
}
How do I keep an RMI server running? It currently, just binds and object, then exits..
public class WutServer {
public static void main(String[] args) throws RemoteException {
Registry registry = LocateRegistry.createRegistry(1099);
try {
registry.bind("WutManager", new WutManager());
System.out.println("Ready..");
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am simply running this class. I didn't run rmic or anything..
How do I force it to stay running?
Try this:
Remote stub = UnicastRemoteObject.exportObject(new WutManager(), 0);
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("WutManager", stub);
Note: WutManager should implement java.rmi.Remote.
Your server is being DGC'd and then GC'd, which causes it to be unexported, which eventually causes the JVM to exit if it has nothing else to do. To stop that, if you are creating the Registry via LocateRegistry.createRegistry(), keep the return value of that method in a static variable. Otherwise keep a static reference to your server object.
This is an old question, but here is a new answer.
On OSX, using latest Java 9.0.4 I find that the program exits. If I use latest Java 1.8.0.162 then it does not exit and the server remains running.
You need to make WutServer implement the interface that clients will access it by, which in turn should inherit from the marker interface Remote. You also probably want to make the WutServer class inherit from UnicastRemoteObject; while there are other ways to build the remoting support, inheriting from UnicastRemoteObject is definitely the easiest way to get something going.
Try this instead (though you should probably separate the remote interface into another file and have it be redistributed separately):
public class WutServer extends UnicastRemoteObject implements WutServer.Wut {
interface Wut extends Remote {
String wut() throws RemoteException;
}
// Because of the exception...
public WutServer() throws RemoteException {}
public String wut() { return "wut"; }
public static void main(String[] args) throws RemoteException {
LocateRegistry.createRegistry(1099).rebind("WutManager",new WutServer());
System.out.println("Ready...");
}
}
Create an object and call wait of the object at the end of the main function. That is;
public static void main(String[] args) throws RemoteException {
Registry registry = LocateRegistry.createRegistry(1099);
//your object to wait
Object lockObject=new Object();
try {
registry.bind("WutManager", new WutManager());
System.out.println("Ready..");
//here makes your rmi server non-stop
synchronized(lockObject){
lockObject.wait();
}
}catch (Exception e) {
e.printStackTrace();
}
}