?
Solved

Force refused/timed out connection, SocketChannel with Selector

Posted on 2009-12-29
6
Medium Priority
?
955 Views
Last Modified: 2013-12-29
I have an application which needs to behave a certain way when a connection made with a SocketChannel is refused or times out. It behaves as expected when connecting to the production host, but I am trying to write a self-contained test for it in JUnit and am having trouble getting the refusal or the timeout to occur when I attempt to connect to a ServerSocket established locally.

When it times out (using setSoTimeout(100)) talking to the remote host or the remote host refuses the connection, calling finishConnect() on the selected key will raise a ConnectException, which I can then catch and deal with appropriately. But when attempting to connect to an unbound port locally in the JUnit test, it neither times out nor receives a connection refusal. Instead it loops forever, never selecting the key for the connection attempt. Same story if I bind() the port to a ServerSocket but never accept().

Unfortunately the work is covered by an NDA, so I can't post code. But just at first glance, is there something the remote host is configured to do, that I need to do to refuse the connection or make the connection time out locally?
0
Comment
Question by:dberner9
  • 3
  • 3
6 Comments
 
LVL 2

Expert Comment

by:themuppeteer
ID: 26170455
I'm having trouble following your explanation but some thoughts anyway..
are you sure the port isn't open and a connect happened ?
(you
0
 
LVL 2

Expert Comment

by:themuppeteer
ID: 26170482
you could put a breakpoint in your test case and walk through there to see, or use netstat to check your open ports)
what do you mean with 'loops' forever ? what do you loop ?
I had experience with a firewall creating strange behaviour in my program too (took us a long time to figure it out)
perhaps you can first try to test a succeeding connection and then let it fail ?
good luck
0
 
LVL 5

Author Comment

by:dberner9
ID: 26171659
what do you mean with 'loops' forever ? what do you loop ?

I've created an event loop that gets a set of keys from the selector and calls appropriate methods based on the operations that are ready. Something like the code below.

are you sure the port isn't open and a connect happened ?

I would expect if a connect happened that the isConnectable() operation would get selected. It's not selecting ANYTHING when the port isn't bound. This happens even when I do stupid things like try to connect to port 7654 on cnn.com.

Further, when I do the exact same operation in a test main() function, it works as expected.

perhaps you can first try to test a succeeding connection and then let it fail ?

The successful connection works just fine. It transmits data back and forth perfectly. When I then close the port, it throws an exception on read (not write) saying the connection was forcefully terminated, rather than just returning a -1. This is also weird because I thought that closing a ServerSocket would keep existing TCP connections alive (frustratingly, in a test main() function, this is once again exactly what happens).

Selector sel = openSelector();
SocketChannel[] s = new SocketChannel[SOCKETS];

for(;;)
  for(int i = 0; i < s.length; i++) {
    SocketChannel c = s[i];
    if((c == null || !c.isOpen()) && connect) { // connect is a member boolean that can be set in another thread
      SocketChannel c = openChannel();
      c.configureBlocking(false);
      sel.register(c,OP_CONNECT);
      s[i] = c;
    } else if((c != null && c.isOpen()) && !connect) {
      for(SelectionKey key : sel.getKeys()) {
        if(key.channel() == c) {
          key.cancel();
        }
      }
      c.close();
    }
  }
  keys = sel.selectNow();
  for(SelectionKey key : keys) {
    if(key.isConnectable()) {
      key.cancel();
      sel.register(key.channel(),OP_READ | OP_WRITE);
    }
    ByteBuffer out = null;
    if(key.isReadable()) {
      ByteBuffer in = ByteBuffer.allocateDirect(100);
      if(((ReadableByteChannel)key.channel()).read(b) < 0) {
        key.channel().close();
        key.cancel();
        continue;
      }
      in.flip();
      out = doReadWrite(in);
    }
    if(out != null && out.remaining() > 0 && key.isWritable()) {
      ((WritableByteChannel)key.channel()).write(out);
    }
  }
}

Open in new window

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Author Comment

by:dberner9
ID: 26171707
Er, sorry, below is what should happen for key.isConnectable(). This is a rewrite from memory.

if(key.isConnectable()) {
      key.cancel();
      try {
        if(key.finishConnect()) 
          sel.register(key.channel(),OP_READ | OP_WRITE);
      } catch (ConnectException ce) {
        log.warn("Connection failed", ce);
        for(SocketChannel c : s) {
          if(c == key.channel()) key.channel().close();
        }
      }
    }

Open in new window

0
 
LVL 5

Accepted Solution

by:
dberner9 earned 0 total points
ID: 26172966
I'm an idiot.

I switched to using select() instead of selectNow(), and it worked. It failed other tests (it needs to shut down within 1 second of being told to), but

Turns out there is just a race condition between my tests and my code, and I just wasn't allowing it enough time.

I wish I knew how to write tests for TCP without the race conditions, but unfortunately you have to fail quickly if something's timing out in a unit test. In real world conditions you can block while waiting.
0
 
LVL 2

Expert Comment

by:themuppeteer
ID: 26178686
ok, I'm glad you found a solution!
0

Featured Post

Upgrade your Question Security!

Add Premium security features to your question to ensure its privacy or anonymity. Learn more about your ability to control Question Security today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Configuring network clients can be a chore, especially if there are a large number of them or a lot of itinerant users.  DHCP dynamically manages this process, much to the relief of users and administrators alike!
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:
Suggested Courses
Course of the Month15 days, 14 hours left to enroll

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question