1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.spdy.server;
20
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Queue;
24 import java.util.concurrent.ConcurrentLinkedQueue;
25 import java.util.concurrent.atomic.AtomicBoolean;
26
27 import org.eclipse.jetty.io.Connection;
28 import org.eclipse.jetty.io.EndPoint;
29 import org.eclipse.jetty.server.AbstractConnectionFactory;
30 import org.eclipse.jetty.server.Connector;
31 import org.eclipse.jetty.spdy.CompressionFactory;
32 import org.eclipse.jetty.spdy.FlowControlStrategy;
33 import org.eclipse.jetty.spdy.StandardCompressionFactory;
34 import org.eclipse.jetty.spdy.StandardSession;
35 import org.eclipse.jetty.spdy.api.GoAwayInfo;
36 import org.eclipse.jetty.spdy.api.Session;
37 import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
38 import org.eclipse.jetty.spdy.client.FlowControlStrategyFactory;
39 import org.eclipse.jetty.spdy.client.SPDYConnection;
40 import org.eclipse.jetty.spdy.generator.Generator;
41 import org.eclipse.jetty.spdy.parser.Parser;
42 import org.eclipse.jetty.util.Callback;
43 import org.eclipse.jetty.util.annotation.ManagedAttribute;
44 import org.eclipse.jetty.util.annotation.ManagedObject;
45 import org.eclipse.jetty.util.log.Log;
46 import org.eclipse.jetty.util.log.Logger;
47
48 @ManagedObject("SPDY Server Connection Factory")
49 public class SPDYServerConnectionFactory extends AbstractConnectionFactory
50 {
51 private static final Logger LOG = Log.getLogger(SPDYServerConnectionFactory.class);
52
53
54
55 public static void checkNPNAvailable()
56 {
57 try
58 {
59 Class<?> npn = ClassLoader.getSystemClassLoader().loadClass("org.eclipse.jetty.npn.NextProtoNego");
60 if (npn.getClassLoader() != null)
61 throw new IllegalStateException("NextProtoNego must be on JVM boot path");
62 }
63 catch (ClassNotFoundException e)
64 {
65 throw new IllegalStateException("No NextProtoNego on boot path", e);
66 }
67 }
68
69 private final short version;
70 private final ServerSessionFrameListener listener;
71 private int initialWindowSize;
72 private final Queue<Session> sessions = new ConcurrentLinkedQueue<>();
73
74 public SPDYServerConnectionFactory(int version)
75 {
76 this(version, null);
77 }
78
79 public SPDYServerConnectionFactory(int version, ServerSessionFrameListener listener)
80 {
81 super("spdy/" + version);
82 this.version = (short)version;
83 this.listener = listener;
84 setInitialWindowSize(65536);
85 }
86
87 @ManagedAttribute("SPDY version")
88 public short getVersion()
89 {
90 return version;
91 }
92
93 public ServerSessionFrameListener getServerSessionFrameListener()
94 {
95 return listener;
96 }
97
98 @Override
99 public Connection newConnection(Connector connector, EndPoint endPoint)
100 {
101 CompressionFactory compressionFactory = new StandardCompressionFactory();
102 Parser parser = new Parser(compressionFactory.newDecompressor());
103 Generator generator = new Generator(connector.getByteBufferPool(), compressionFactory.newCompressor());
104
105 ServerSessionFrameListener listener = provideServerSessionFrameListener(connector, endPoint);
106 SPDYConnection connection = new ServerSPDYConnection(connector, endPoint, parser, listener, getInputBufferSize());
107
108 FlowControlStrategy flowControlStrategy = newFlowControlStrategy(version);
109
110 StandardSession session = new StandardSession(getVersion(), connector.getByteBufferPool(),
111 connector.getExecutor(), connector.getScheduler(), connection, endPoint, connection, 2, listener,
112 generator, flowControlStrategy);
113 session.setWindowSize(getInitialWindowSize());
114 parser.addListener(session);
115 connection.setSession(session);
116
117 sessionOpened(session);
118
119 return configure(connection, connector, endPoint);
120 }
121
122 protected FlowControlStrategy newFlowControlStrategy(short version)
123 {
124 return FlowControlStrategyFactory.newFlowControlStrategy(version);
125 }
126
127 protected ServerSessionFrameListener provideServerSessionFrameListener(Connector connector, EndPoint endPoint)
128 {
129 return listener;
130 }
131
132 @ManagedAttribute("Initial Window Size")
133 public int getInitialWindowSize()
134 {
135 return initialWindowSize;
136 }
137
138 public void setInitialWindowSize(int initialWindowSize)
139 {
140 this.initialWindowSize = initialWindowSize;
141 }
142
143 protected boolean sessionOpened(Session session)
144 {
145
146 return sessions.offer(session);
147 }
148
149 protected boolean sessionClosed(Session session)
150 {
151
152
153 return sessions.remove(session);
154 }
155
156 void closeSessions()
157 {
158 for (Session session : sessions)
159 session.goAway(new GoAwayInfo(), new Callback.Adapter());
160 sessions.clear();
161 }
162
163 @Override
164 protected void doStop() throws Exception
165 {
166 closeSessions();
167 super.doStop();
168 }
169
170 public Collection<Session> getSessions()
171 {
172 return Collections.unmodifiableCollection(sessions);
173 }
174
175 private class ServerSPDYConnection extends SPDYConnection implements Runnable
176 {
177 private final ServerSessionFrameListener listener;
178 private final AtomicBoolean connected = new AtomicBoolean();
179
180 private ServerSPDYConnection(Connector connector, EndPoint endPoint, Parser parser, ServerSessionFrameListener listener, int bufferSize)
181 {
182 super(endPoint, connector.getByteBufferPool(), parser, connector.getExecutor(), bufferSize);
183 this.listener = listener;
184 }
185
186 @Override
187 public void onOpen()
188 {
189 super.onOpen();
190 if (connected.compareAndSet(false, true))
191 getExecutor().execute(this);
192 }
193
194 @Override
195 public void onClose()
196 {
197 super.onClose();
198 sessionClosed(getSession());
199 }
200
201 @Override
202 public void run()
203 {
204
205 if (listener != null)
206 listener.onConnect(getSession());
207 }
208 }
209
210 }