jira.codehaus.org

  • Log In Access more options
    • Online Help
    • Keyboard Shortcuts
    • About JIRA
    • JIRA Credits
    • What?s New
  • Dashboards Access more options (Alt+d)
  • Projects Access more options (Alt+p)
  • Issues Access more options (Alt+i)
  • Jetty
  • JETTY-597

Jetty does not close the socket when client has close the socket.

  • Log In
  • Views
    • XML
    • Word
    • Printable

Details

  • Type: Improvement Improvement
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Won't Fix
  • Affects Version/s: 7.0.0pre1
  • Fix Version/s: None
  • Component/s: Bayeux
  • Labels:
    None
  • Environment:
    linux 2.6

Description

I wrote a sample code to see how jetty close the socket. but I found that jetty won't close the socket even after the client closed the peer-socket. this is my source code, very simple:

public static void main(String[] args) throws Exception {

Handler handler = new AbstractHandler() {
public void handle(String target, HttpServletRequest request,
HttpServletResponse response, int dispatch)
throws IOException, ServletException {
Continuation cont = ContinuationSupport.getContinuation(
request, null);
if(cont.isPending()) { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println("<h1>Hello</h1>"); ((Request) request).setHandled(true); }else{ cont.suspend(0); }
}
};

Server server = new Server();
Connector connector = new SelectChannelConnector();
connector.setPort(8080);
server.setConnectors(new Connector[] { connector });
server.setHandler(handler);
server.start();
}

i can reproduce this bug by following way:

1. open web browser to access http://locahost:8080/hello . as the first time, it is suspended by continuation, and wait for being resumed.
2. close the web browser to simulate the user's leaving.
3. run command "nestat -tanp | grep 8080" to watch the tcp connection:

tcp 0 0 127.0.0.1:43465 127.0.0.1:8080 FIN_WAIT2 -
tcp6 0 0 :::8080 :::* LISTEN 22866/java
tcp6 1 0 127.0.0.1:8080 127.0.0.1:43465 CLOSE_WAIT 22866/java

abviously, CLOSE_WAIT status tells me that the socket is waiting for being closed. I think, since i have closed the web browser, the socket of server should be close at once.

Issue Links

supercedes

Bug - A problem which impairs or prevents the functions of the product. JETTY-593 the pending continuation won't be resumed even after connection is closed

  • Major - Major loss of function.
  • Resolved - A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.

Activity

Ascending order - Click to sort in descending order
  • All
  • Comments
  • Work Log
  • History
  • Activity
Hide
Permalink
Jan Bartel added a comment - 04/Jun/08 8:03 PM

Some info: this is really an artifact of the implementation. In jetty6 after a suspend(), the request has to be redispatched via a call to either timeout() or resume() before it can notice that the socket has closed. In jetty7, which implements the servlet 3 api, if you are writing to the response whilst suspended (which is a new feature), then you can see that the client socket has closed. Being able to notice that the socket has closed if you are NOT doing IO would be nice to have, but is difficult to implement.

We'll keep this issue open until we think of a way of doing it or give up

regards
Jan

Show
Jan Bartel added a comment - 04/Jun/08 8:03 PM Some info: this is really an artifact of the implementation. In jetty6 after a suspend(), the request has to be redispatched via a call to either timeout() or resume() before it can notice that the socket has closed. In jetty7, which implements the servlet 3 api, if you are writing to the response whilst suspended (which is a new feature), then you can see that the client socket has closed. Being able to notice that the socket has closed if you are NOT doing IO would be nice to have, but is difficult to implement. We'll keep this issue open until we think of a way of doing it or give up regards Jan
Hide
Permalink
Greg Wilkins added a comment - 05/Jun/08 8:33 PM

Just to clarify what Jan said.

This has always been an issue in the servlet spec, that an IO event like connection close is not communicated to the application - until such time as the application attempts an IO operation.

Suspend/Resume does not introduce this problem, it just makes applications possible that have longer times between IO operations!

Once apon a time, Jetty used to interrupt servlets if the connection was closed... but this caused all sorts of issues with code that does not implement interrupt handling correctly.

In Jetty-7, we did experiment with an IO event forcing a resume, but the issue there is that it prevents suspend being used for quality of service, as an IO event will wakeup a request earlier. So we stopped that.

What the servlet spec needs is extensible async IO, so that the app/framework can be given the close event and decide if it should resume, complete or error. eg. should we resume a POST that may change state, even though the users connection is gone? Jetty cannot decide that!

I will change this issue from a bug to a feature request, as I'm sure we can provide this extensibility, even if it is not in the spec.

Show
Greg Wilkins added a comment - 05/Jun/08 8:33 PM Just to clarify what Jan said. This has always been an issue in the servlet spec, that an IO event like connection close is not communicated to the application - until such time as the application attempts an IO operation. Suspend/Resume does not introduce this problem, it just makes applications possible that have longer times between IO operations! Once apon a time, Jetty used to interrupt servlets if the connection was closed... but this caused all sorts of issues with code that does not implement interrupt handling correctly. In Jetty-7, we did experiment with an IO event forcing a resume, but the issue there is that it prevents suspend being used for quality of service, as an IO event will wakeup a request earlier. So we stopped that. What the servlet spec needs is extensible async IO, so that the app/framework can be given the close event and decide if it should resume, complete or error. eg. should we resume a POST that may change state, even though the users connection is gone? Jetty cannot decide that! I will change this issue from a bug to a feature request, as I'm sure we can provide this extensibility, even if it is not in the spec.
Hide
Permalink
Kevin Conaway added a comment - 21/Jan/10 4:02 PM

Once apon a time, Jetty used to interrupt servlets if the connection was closed... but this caused all sorts of issues with code that does not implement interrupt handling correctly.

Is it possible to add some kind of hook or observer feature for a given request so that clients can at least have the option of being notified when a connection is terminated after it has been dispatched?

Show
Kevin Conaway added a comment - 21/Jan/10 4:02 PM
Once apon a time, Jetty used to interrupt servlets if the connection was closed... but this caused all sorts of issues with code that does not implement interrupt handling correctly.
Is it possible to add some kind of hook or observer feature for a given request so that clients can at least have the option of being notified when a connection is terminated after it has been dispatched?
Hide
Permalink
Greg Wilkins added a comment - 16/Mar/10 5:40 PM

Currently it is not easily possible because there is no onError interested op, that can be called back if only a close (or other error has happened). Without this, any data arriving would turn into a busy loop - or else we would have to read it... which would be a DOS problem.

Maybe NIO2 might help... but I've not looked yet.

Show
Greg Wilkins added a comment - 16/Mar/10 5:40 PM Currently it is not easily possible because there is no onError interested op, that can be called back if only a close (or other error has happened). Without this, any data arriving would turn into a busy loop - or else we would have to read it... which would be a DOS problem. Maybe NIO2 might help... but I've not looked yet.
Hide
Permalink
Jan Ypma added a comment - 04/Nov/11 7:40 AM - edited

According to https://forums.oracle.com/forums/thread.jspa?threadID=2123535 , registering the key for OP_READ is enough to be notified of closures: read() would return -1 afterwards.

Jetty is doing something to this extent. But even with the latest Jetty code (SelectChannelEndpoint.java:371-ish) :

371: _interestOps =
372: ((!_dispatched || _readBlocked) ? SelectionKey.OP_READ : 0)
373: | ((!_writable || _writeBlocked) ? SelectionKey.OP_WRITE : 0);

The key is only registered for OP_READ if there currently is a blocked thread waiting on a read for it (if I understood correctly). This won't be the case when the connection is a suspended continuation, put away for an async event to wake it back up.

Does this mean that Jetty doesn't get the OP_READ when there's no waiting thread for it?

Show
Jan Ypma added a comment - 04/Nov/11 7:40 AM - edited According to https://forums.oracle.com/forums/thread.jspa?threadID=2123535 , registering the key for OP_READ is enough to be notified of closures: read() would return -1 afterwards. Jetty is doing something to this extent. But even with the latest Jetty code (SelectChannelEndpoint.java:371-ish) : 371: _interestOps = 372: ((!_dispatched || _readBlocked) ? SelectionKey.OP_READ : 0) 373: | ((!_writable || _writeBlocked) ? SelectionKey.OP_WRITE : 0); The key is only registered for OP_READ if there currently is a blocked thread waiting on a read for it (if I understood correctly). This won't be the case when the connection is a suspended continuation, put away for an async event to wake it back up. Does this mean that Jetty doesn't get the OP_READ when there's no waiting thread for it?
Hide
Permalink
Greg Wilkins added a comment - 08/Nov/11 9:37 PM

The key part of that code is the test for !_dispatched. So while a thread is dispatched to handled the connection, we do not register for read interest unless that thread blocks on a read.

But it is true that while suspended, we are considered dispatched and will not register for read interest. This is by design because we can't have the suspended connection resumed just because there is data to be read - this might be a pipelined request, data we are not ready to read yet or a DOS attack.

If you want proper TCP/IP back pressure, you only read when you are ready to read. The down side of this is that you will not see a closed connection until you are ready to read (or write). But note that with half closed connection, just because there is a -1 ready to read, does not mean you should abandon the request... you can still complete a response, flush it and close the connection.

Show
Greg Wilkins added a comment - 08/Nov/11 9:37 PM The key part of that code is the test for !_dispatched. So while a thread is dispatched to handled the connection, we do not register for read interest unless that thread blocks on a read. But it is true that while suspended, we are considered dispatched and will not register for read interest. This is by design because we can't have the suspended connection resumed just because there is data to be read - this might be a pipelined request, data we are not ready to read yet or a DOS attack. If you want proper TCP/IP back pressure, you only read when you are ready to read. The down side of this is that you will not see a closed connection until you are ready to read (or write). But note that with half closed connection, just because there is a -1 ready to read, does not mean you should abandon the request... you can still complete a response, flush it and close the connection.

People

  • Assignee:
    Unassigned
    Reporter:
    Temp
Vote (3)
Watch (3)

Dates

  • Created:
    04/Jun/08 1:38 PM
    Updated:
    08/Nov/11 9:37 PM
    Resolved:
    16/Mar/10 5:40 PM
  • Atlassian JIRA (v5.0.4#731-sha1:3aa7374)
  • Report a problem
  • Powered by a free Atlassian JIRA open source license for Codehaus. Try JIRA - bug tracking software for your team.