View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.spdy.client;
20  
21  import java.io.IOException;
22  import java.nio.channels.SocketChannel;
23  import java.util.List;
24  import java.util.concurrent.Executor;
25  
26  import javax.net.ssl.SSLEngine;
27  
28  import org.eclipse.jetty.io.AbstractConnection;
29  import org.eclipse.jetty.io.Connection;
30  import org.eclipse.jetty.io.EndPoint;
31  import org.eclipse.jetty.io.RuntimeIOException;
32  import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
33  import org.eclipse.jetty.npn.NextProtoNego;
34  import org.eclipse.jetty.util.BufferUtil;
35  import org.eclipse.jetty.util.log.Log;
36  import org.eclipse.jetty.util.log.Logger;
37  
38  public class NextProtoNegoClientConnection extends AbstractConnection implements NextProtoNego.ClientProvider
39  {
40      private final Logger LOG = Log.getLogger(getClass());
41      private final SocketChannel channel;
42      private final Object attachment;
43      private final SPDYClient client;
44      private final SSLEngine engine;
45      private volatile boolean completed;
46  
47      public NextProtoNegoClientConnection(SocketChannel channel, DecryptedEndPoint endPoint, Object attachment, Executor executor, SPDYClient client)
48      {
49          super(endPoint, executor);
50          this.channel = channel;
51          this.attachment = attachment;
52          this.client = client;
53          this.engine = endPoint.getSslConnection().getSSLEngine();
54          NextProtoNego.put(engine, this);
55      }
56  
57      @Override
58      public void onOpen()
59      {
60          super.onOpen();
61          try
62          {
63              getEndPoint().flush(BufferUtil.EMPTY_BUFFER);
64              if (completed)
65                  replaceConnection();
66              else
67                  fillInterested();
68          }
69          catch(IOException e)
70          {
71              throw new RuntimeIOException(e);
72          }
73      }
74  
75      @Override
76      public void onFillable()
77      {
78          while (true)
79          {
80              int filled = fill();
81              if (filled == 0 && !completed)
82                  fillInterested();
83              if (filled <= 0 || completed)
84                  break;
85          }
86          if (completed)
87              replaceConnection();
88      }
89  
90      private int fill()
91      {
92          try
93          {
94              return getEndPoint().fill(BufferUtil.EMPTY_BUFFER);
95          }
96          catch (IOException x)
97          {
98              LOG.debug(x);
99              NextProtoNego.remove(engine);
100             getEndPoint().close();
101             return -1;
102         }
103     }
104 
105     @Override
106     public boolean supports()
107     {
108         return true;
109     }
110 
111     @Override
112     public void unsupported()
113     {
114         NextProtoNego.remove(engine);
115         completed = true;
116     }
117 
118     @Override
119     public String selectProtocol(List<String> protocols)
120     {
121         NextProtoNego.remove(engine);
122         completed = true;
123         String protocol = client.selectProtocol(protocols);
124         return protocol == null ? null : protocol;
125     }
126 
127     private void replaceConnection()
128     {
129         EndPoint endPoint = getEndPoint();
130         Connection connection = client.getConnectionFactory().newConnection(channel, endPoint, attachment);
131         endPoint.getConnection().onClose();
132         endPoint.setConnection(connection);
133         connection.onOpen();
134     }
135 }