2

I'm currently working on implementing a privacy preserving data mining algorithm. For the communication part between the different parties I'm using Netty 4.0. The communication flow between the parties looks like this:

         -- multiplicationMsg --> ... -- multiplicationMsg -->
   P_{1}                                                       P_{N}
         <-- multiplicationMsg -- ... <-- multiplicationMsg --

where P_{1} is the master party that initiates and controls the whole computation. The logic for the secure multi-party multiplication is located in Netty ChannelHandlers. There is also another protocol for secure addition.

At the moment I use a similar solution like this, shown by Norman Maurer from Netty core team, to get informed if a sub-protocol computation has finished. But that feels a bit like fighting against the framework.

Is there a way to get a custom promise from channel.write(msg), that will be created and fulfilled in the ChannelPipeline? In my example above, it should be fulfilled when multiplicationMsg arrives back at P_{1}.

Edit 1

This is what I normally do to write a message from outside of the ChannelPipeline:

ChannelFuture f = channel.write(msg);
future.addListener(new ChannelFutureListener() {
    public void operationComplete(ChannelFuture future) {
         //do something with the future
    }
});

The ChannelFuture f from the example above will be fulfilled, if the data could be written to the socket or if a failure occurs. But I need a way do get back a custom Future in addition to the ChannelFuture, somehow like:

ChannelFuture f = channel.write(msg);
future.addListener(new ChannelFutureListener() {
    public void operationComplete(ChannelFuture future) {
         // I need something like the following
         if(future.isSuccess()) {
             Future myFuture = future.getMyFuture();
         }
    }
});
kunerd
  • 1,076
  • 10
  • 25
  • So the promise objects returned from the `write(..)` methods seem to have well a well defined purpose which is to communicate I/O related status related to that write. However you can generate your own promises via [channel.newPromise()](http://netty.io/4.0/api/io/netty/channel/Channel.html#newPromise()) and use what ever criteria you want to mark them as successful. For example your criteria could be to mark the promise as failed (or timeout) if any responses fail and successful if you get N successful responses back. – Scott Mitchell Dec 03 '14 at 02:24
  • [ChannelHandlerContext](http://netty.io/4.0/api/io/netty/channel/ChannelHandlerContext.html#newPromise()) also exposes the same interface. Does this give you what you need, or am I misinterpreting your question? – Scott Mitchell Dec 03 '14 at 02:25
  • Edited my question to clarify my needs. – kunerd Dec 03 '14 at 14:18
  • When do you expect this `getMyFuture()` will be set, and by who? Does adding a member variable to your `ChannelFutureListener` do what you need? – Scott Mitchell Dec 03 '14 at 15:43
  • The `getMyFuture()` should be set and later also fulfilled from one of my `ChannelHandler`s. – kunerd Dec 03 '14 at 17:03
  • What is preventing you from adding a `Future myFuture;` member to your implementation of the `ChannelFutureListener`? – Scott Mitchell Dec 04 '14 at 04:46
  • But how do I set/access this member from withing my `ChannelHandler`? – kunerd Dec 05 '14 at 08:39
  • [ChannelFutureListener](http://netty.io/4.0/api/io/netty/channel/ChannelFutureListener.html) is an interface and you don't have to use it as an anonymous class. You can make your own full fledged class that implements ChannelFutureListener and put what ever you want into it, initialize however you want, and determine its interface/lifetime that suites your needs. – Scott Mitchell Dec 05 '14 at 18:43
  • I think we talk past each other. I only used the `ChannelFutureListener` as anonymous class to keep the example short. So you mean that I should create a class, e.g. `MyListener` that implements `ChannelFutureListener` and has a member `Future myFuture`? Then I should create an instance of `MyListener` and pass it to `f.addListener()`? How could I now set `myFuture` from inside my `ChannelHandler`? Could you please give some example. – kunerd Dec 05 '14 at 19:49
  • You can always specify your own promise when writing - channel.write(msg, promise); and then write(...) will return the promise you specified. But this answer seems way too simple to be missed out, so I guess you might be looking for something else. – trustin Dec 07 '14 at 03:05
  • At Scott Mitchell and trustin: Thank you very much. I think I see a possible solution now. I will add an answer after I implemented it. – kunerd Dec 08 '14 at 12:10
  • Sounds like you have a solution but here is some more context to hopefully help. `How could I now set myFuture from inside my ChannelHandler?` This will depend upon what you are trying to do, what your interfaces are, and other limitations. However I think it boils down to just make sure you `ChannelHandler` has access to `MyListener`. Then `ChannelHandler` can use the setters/getters of the `MyListener` to complete your future, or set a new promise, or w/e you need to do. – Scott Mitchell Dec 09 '14 at 23:36

1 Answers1

5

There are many ways to do it, here's one example building on top of netty:

From outside the pipeline, send the message using a public method inside a class (let's say, IoClient) containing the ChannelFuture (from the connection initialization). The method would look something like this:

public MyCustomFuture send(String msg) {
  MyCustomFuture responseFuture = new MyCustomFuture();

  channelFuture.channel().pipeline().get(MyAppClientHandler.class).setResponseFuture(responseFuture);
  channelFuture.channel().writeAndFlush(msg);   

  return responseFuture;
}

MyCustomFuture is the custom class we create implementing netty's Future interface, so it's instance will proxy our message. MyAppClientHandler is the netty pipe to be fulfilling the promise (in responseFuture), and .setResponseFuture(...) adds the proxy to the pipe.

Depending on the initialization of the channel, channelFuture.channel() might still be null, giving us a NullPointerException. So we need to change the code above to insert the proxy from inside a callback:

public MyCustomFuture send(final String msg) {
  final MyCustomFuture responseFuture = new MyCustomFuture();

  channelFuture.addListener(new GenericFutureListener<ChannelFuture>() {
    @Override
    public void operationComplete(ChannelFuture future) throws Exception {
      channelFuture.channel().pipeline()
          .get(MyAppClientHandler.class).setResponseFuture(responseFuture);
      channelFuture.channel().writeAndFlush(msg);                               
    }
  });

  return responseFuture;
}

One more thing about MyCustomFuture is that it will need a setter method:

public void set(String msg) throws InterruptedException {
  if (state == State.DONE) {
    return;
  }
  blockingReplyHolder.put(msg);
  state = State.DONE;
}

blockingReplyHolder, as the name suggests, is the implementation's field that holds the message that fulfills the promise and blocks if it still doesn't exist (check Future)

Right. Now, when the expected message reaches the pipe MyAppClientHandler, we can fulfill the promise like:

protected void channelRead(ChannelHandlerContext ctx, String msg) throws Exception {
    responseFuture.set(msg);
}

The resulting custom API's usage would be:

MyCustomFuture future = ioClient.send(message);
// do other stuff if needed
String response = future.get(); // waits if necessary
// make use of the response

This answer was born from a example I was toying with.

Seigo
  • 178
  • 1
  • 6
  • Thanks for your answer. Would it be possible to use a `Promise` instead of `MyCustomFuture`? I ask because the `Promise` has a setter by default. – kunerd Mar 27 '15 at 08:02
  • Yes, well noticed. `Promise` is most likely the abstraction Netty intended for this case. – Seigo Mar 27 '15 at 19:27
  • hi I try do implement simple client that connects to remote server and start sending msg possibly from many threads, on this one connection. I guess this is a scenario kunerd had. and I understand that this was a reason he needed resolve future from handler. Now I dont really see how answers from Scott Mitchell and trustin help here. is the set promise exposed somehow to handlers? the @Seigo answer will only work if there is single conversation per connection, as concurrent invocation of send method for same connection will override responseFuture. – kamiseq Jul 19 '15 at 18:15
  • ok, I guess there is no way netty will help you implementing simple multiplexer, I somehow though handler context is created per write to channel – kamiseq Jul 27 '15 at 18:01
  • It can be problem with asyn response? How to collecting request and response future for example when i send 2 req to tcp server and second request's response can be return before first. I have this logic and i used transaction id(it common for request and response in my case) i used following way; https://stackoverflow.com/questions/55516609/netty-channelfuture-timeout-when-response-received but some responses are not collecting to response. Tcp response received but future.get method received timeout exception. What can be occur in this line? – mertaksu Apr 04 '19 at 19:26