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