Skip to content

Commit 0710ad1

Browse files
committed
merged conflicted branch 'master' of https://github.com/fomojola/Java-WebSocket (TooTallNate#101)
2 parents f2b26e1 + 0a4a98c commit 0710ad1

8 files changed

+395
-29
lines changed

example/SSLServer.java

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// @formatter:off
2+
3+
import java.io.File;
4+
import java.io.FileInputStream;
5+
import java.net.InetAddress;
6+
import java.net.InetSocketAddress;
7+
import java.net.Socket;
8+
import java.nio.channels.SocketChannel;
9+
import java.security.KeyStore;
10+
import java.util.List;
11+
12+
import javax.net.ssl.KeyManagerFactory;
13+
import javax.net.ssl.SSLContext;
14+
import javax.net.ssl.SSLEngine;
15+
import javax.net.ssl.TrustManagerFactory;
16+
17+
import org.java_websocket.SSLSocketChannel;
18+
import org.java_websocket.WebSocket;
19+
import org.java_websocket.WebSocketAdapter;
20+
import org.java_websocket.WebSocketImpl;
21+
import org.java_websocket.drafts.Draft;
22+
import org.java_websocket.handshake.ClientHandshake;
23+
import org.java_websocket.server.WebSocketServer;
24+
25+
/*
26+
* Create the appropriate websocket server.
27+
*/
28+
public class SSLServer implements WebSocketServer.WebSocketServerFactory
29+
{
30+
private static final String STORETYPE = "JKS";
31+
private static final String KEYSTORE = "keystore.jks";
32+
private static final String STOREPASSWORD = "storepassword";
33+
private static final String KEYPASSWORD = "keypassword";
34+
35+
public static void main(String[] args) throws Exception
36+
{
37+
new SSLServer();
38+
}
39+
40+
private SSLContext sslContext;
41+
42+
void loadFromFile() throws Exception
43+
{
44+
// load up the key store
45+
KeyStore ks = KeyStore.getInstance(STORETYPE);
46+
File kf = new File(KEYSTORE);
47+
ks.load(new FileInputStream(kf), STOREPASSWORD.toCharArray());
48+
49+
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
50+
kmf.init(ks, KEYPASSWORD.toCharArray());
51+
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
52+
tmf.init(ks);
53+
54+
sslContext = SSLContext.getInstance("TLS");
55+
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
56+
}
57+
58+
/*
59+
* Keystore with certificate created like so (in JKS format):
60+
*
61+
keytool -genkey -validity 3650 -keystore "keystore.jks" -storepass "storepassword" -keypass "keypassword" -alias "default" -dname "CN=127.0.0.1, OU=MyOrgUnit, O=MyOrg, L=MyCity, S=MyRegion, C=MyCountry"
62+
*/
63+
SSLServer() throws Exception
64+
{
65+
sslContext = null;
66+
loadFromFile();
67+
68+
// create the web socket server
69+
WebSocketSource wsgateway = new WebSocketSource(8001, InetAddress.getByName("127.0.0.1"));
70+
wsgateway.setWebSocketFactory(this);
71+
wsgateway.start();
72+
}
73+
74+
@Override
75+
public WebSocketImpl createWebSocket( WebSocketAdapter a, Draft d, Socket c ) {
76+
77+
return new WebSocketImpl( a, d, c );
78+
}
79+
80+
@Override
81+
public WebSocketImpl createWebSocket( WebSocketAdapter a, List<Draft> d, Socket s ) {
82+
if(sslContext != null) try{
83+
SSLEngine e = sslContext.createSSLEngine();
84+
e.setUseClientMode(false);
85+
return new WebSocketImpl( a, d, s );
86+
} catch ( Exception e1 ) {
87+
}
88+
return new WebSocketImpl( a, d, s );
89+
}
90+
91+
@Override
92+
public SocketChannel wrapChannel( SocketChannel c ) {
93+
if( sslContext != null )
94+
try {
95+
SSLEngine e = sslContext.createSSLEngine();
96+
e.setUseClientMode( false );
97+
new SSLSocketChannel( c, e );
98+
} catch ( Exception e1 ) {
99+
}
100+
101+
return c;
102+
}
103+
104+
class WebSocketSource extends WebSocketServer
105+
{
106+
private WebSocket handle;
107+
WebSocketSource(int port, InetAddress addr)
108+
{
109+
super(new InetSocketAddress(addr, port));
110+
handle = null;
111+
}
112+
113+
@Override
114+
public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3)
115+
{
116+
System.err.println("---------------------------->Closed");
117+
if(arg0 == handle) handle = null;
118+
}
119+
120+
@Override
121+
public void onError(WebSocket arg0, Exception arg1) {
122+
// TODO Auto-generated method stub
123+
}
124+
125+
@Override
126+
public void onMessage(WebSocket arg0, String arg1)
127+
{
128+
if(arg0 != handle){
129+
arg0.close(org.java_websocket.framing.CloseFrame.NORMAL);
130+
return;
131+
}
132+
133+
System.out.println("--------->["+arg1+"]");
134+
}
135+
136+
@Override
137+
public void onOpen(WebSocket arg0, ClientHandshake arg1)
138+
{
139+
// nothing to see just yet
140+
if(handle == null){
141+
handle = arg0;
142+
}else if(handle != arg0){
143+
arg0.close(org.java_websocket.framing.CloseFrame.NORMAL);
144+
}
145+
}
146+
147+
void done()
148+
{
149+
if(handle != null) handle.close(org.java_websocket.framing.CloseFrame.NORMAL);
150+
}
151+
}
152+
}
153+
154+
//@formatter:on
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/**
2+
* Copyright (C) 2003 Alexander Kout
3+
* Originally from the jFxp project (http://jfxp.sourceforge.net/).
4+
* Copied with permission June 11, 2012 by Femi Omojola (fomojola@ideasynthesis.com).
5+
*/
6+
package org.java_websocket;
7+
8+
import java.io.IOException;
9+
import java.net.Socket;
10+
import java.net.SocketAddress;
11+
import java.nio.ByteBuffer;
12+
import java.nio.channels.ByteChannel;
13+
import java.nio.channels.SelectableChannel;
14+
import java.nio.channels.SocketChannel;
15+
16+
import javax.net.ssl.SSLEngine;
17+
import javax.net.ssl.SSLEngineResult;
18+
import javax.net.ssl.SSLException;
19+
import javax.net.ssl.SSLSession;
20+
21+
/**
22+
* Implements the relevant portions of the SocketChannel interface with the SSLEngine wrapper.
23+
*/
24+
public class SSLSocketChannel implements ByteChannel
25+
{
26+
private ByteBuffer clientIn, clientOut, cTOs, sTOc, wbuf;
27+
private SocketChannel sc;
28+
private SSLEngineResult res;
29+
private SSLEngine sslEngine;
30+
private int SSL;
31+
32+
public SSLSocketChannel(SocketChannel sc, SSLEngine sslEngine) throws IOException
33+
{
34+
this.sc = sc;
35+
this.sslEngine = sslEngine;
36+
SSL = 1;
37+
try {
38+
sslEngine.setEnableSessionCreation(true);
39+
SSLSession session = sslEngine.getSession();
40+
createBuffers(session);
41+
// wrap
42+
clientOut.clear();
43+
sc.write(wrap(clientOut));
44+
while (res.getHandshakeStatus() !=
45+
SSLEngineResult.HandshakeStatus.FINISHED) {
46+
if (res.getHandshakeStatus() ==
47+
SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
48+
// unwrap
49+
sTOc.clear();
50+
while (sc.read(sTOc) < 1)
51+
Thread.sleep(20);
52+
sTOc.flip();
53+
unwrap(sTOc);
54+
if (res.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.FINISHED) {
55+
clientOut.clear();
56+
sc.write(wrap(clientOut));
57+
}
58+
} else if (res.getHandshakeStatus() ==
59+
SSLEngineResult.HandshakeStatus.NEED_WRAP) {
60+
// wrap
61+
clientOut.clear();
62+
sc.write(wrap(clientOut));
63+
} else {Thread.sleep(1000);}
64+
}
65+
clientIn.clear();
66+
clientIn.flip();
67+
SSL = 4;
68+
} catch (Exception e) {
69+
e.printStackTrace(System.out);
70+
SSL = 0;
71+
}
72+
}
73+
74+
private synchronized ByteBuffer wrap(ByteBuffer b) throws SSLException {
75+
cTOs.clear();
76+
res = sslEngine.wrap(b, cTOs);
77+
cTOs.flip();
78+
return cTOs;
79+
}
80+
81+
private synchronized ByteBuffer unwrap(ByteBuffer b) throws SSLException {
82+
clientIn.clear();
83+
int pos;
84+
while (b.hasRemaining()) {
85+
res = sslEngine.unwrap(b, clientIn);
86+
if (res.getHandshakeStatus() ==
87+
SSLEngineResult.HandshakeStatus.NEED_TASK) {
88+
// Task
89+
Runnable task;
90+
while ((task=sslEngine.getDelegatedTask()) != null)
91+
{
92+
task.run();
93+
}
94+
} else if (res.getHandshakeStatus() ==
95+
SSLEngineResult.HandshakeStatus.FINISHED) {
96+
return clientIn;
97+
} else if (res.getStatus() ==
98+
SSLEngineResult.Status.BUFFER_UNDERFLOW) {
99+
return clientIn;
100+
}
101+
}
102+
return clientIn;
103+
}
104+
105+
private void createBuffers(SSLSession session) {
106+
107+
int appBufferMax = session.getApplicationBufferSize();
108+
int netBufferMax = session.getPacketBufferSize();
109+
110+
clientIn = ByteBuffer.allocate(65536);
111+
clientOut = ByteBuffer.allocate(appBufferMax);
112+
wbuf = ByteBuffer.allocate(65536);
113+
114+
cTOs = ByteBuffer.allocate(netBufferMax);
115+
sTOc = ByteBuffer.allocate(netBufferMax);
116+
117+
}
118+
119+
public int write(ByteBuffer src) throws IOException {
120+
if (SSL == 4) {
121+
return sc.write(wrap(src));
122+
}
123+
return sc.write(src);
124+
}
125+
126+
public int read(ByteBuffer dst) throws IOException {
127+
int amount = 0, limit;
128+
if (SSL == 4) {
129+
// test if there was a buffer overflow in dst
130+
if (clientIn.hasRemaining()) {
131+
limit = Math.min(clientIn.remaining(), dst.remaining());
132+
for (int i = 0; i < limit; i++) {
133+
dst.put(clientIn.get());
134+
amount++;
135+
}
136+
return amount;
137+
}
138+
// test if some bytes left from last read (e.g. BUFFER_UNDERFLOW)
139+
if (sTOc.hasRemaining()) {
140+
unwrap(sTOc);
141+
clientIn.flip();
142+
limit = Math.min(clientIn.limit(), dst.remaining());
143+
for (int i = 0; i < limit; i++) {
144+
dst.put(clientIn.get());
145+
amount++;
146+
}
147+
if (res.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW) {
148+
sTOc.clear();
149+
sTOc.flip();
150+
return amount;
151+
}
152+
}
153+
if (!sTOc.hasRemaining())
154+
sTOc.clear();
155+
else
156+
sTOc.compact();
157+
158+
if (sc.read(sTOc) == -1) {
159+
sTOc.clear();
160+
sTOc.flip();
161+
return -1;
162+
}
163+
sTOc.flip();
164+
unwrap(sTOc);
165+
// write in dst
166+
clientIn.flip();
167+
limit = Math.min(clientIn.limit(), dst.remaining());
168+
for (int i = 0; i < limit; i++) {
169+
dst.put(clientIn.get());
170+
amount++;
171+
}
172+
return amount;
173+
}
174+
return sc.read(dst);
175+
}
176+
177+
public boolean isConnected() {
178+
return sc.isConnected();
179+
}
180+
181+
public void close() throws IOException {
182+
if (SSL == 4) {
183+
sslEngine.closeOutbound();
184+
sslEngine.getSession().invalidate();
185+
clientOut.clear();
186+
sc.write(wrap(clientOut));
187+
sc.close();
188+
} else
189+
sc.close();
190+
}
191+
192+
public SelectableChannel configureBlocking(boolean b) throws IOException {
193+
return sc.configureBlocking(b);
194+
}
195+
196+
public boolean connect(SocketAddress remote) throws IOException {
197+
return sc.connect(remote);
198+
}
199+
200+
public boolean finishConnect() throws IOException {
201+
return sc.finishConnect();
202+
}
203+
204+
public Socket socket() {
205+
return sc.socket();
206+
}
207+
208+
public boolean isInboundDone() {
209+
return sslEngine.isInboundDone();
210+
}
211+
212+
@Override
213+
public boolean isOpen() {
214+
return sc.isOpen();
215+
}
216+
}

src/org/java_websocket/SocketChannelIOHelper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import java.io.IOException;
44
import java.nio.ByteBuffer;
5-
import java.nio.channels.SocketChannel;
5+
import java.nio.channels.ByteChannel;
66

77
import org.java_websocket.drafts.Draft;
88

99
public class SocketChannelIOHelper {
1010

11-
public static boolean read( final ByteBuffer buf, WebSocketImpl ws, SocketChannel channel ) throws IOException {
11+
public static boolean read( final ByteBuffer buf, WebSocketImpl ws, ByteChannel channel ) throws IOException {
1212
buf.clear();
1313
int read = channel.read( buf );
1414
buf.flip();
@@ -21,7 +21,7 @@ public static boolean read( final ByteBuffer buf, WebSocketImpl ws, SocketChanne
2121
return read != 0;
2222
}
2323

24-
public static boolean batch( WebSocketImpl ws, SocketChannel sockchannel ) throws IOException {
24+
public static boolean batch( WebSocketImpl ws, ByteChannel sockchannel ) throws IOException {
2525
ByteBuffer buffer = ws.outQueue.peek();
2626
while ( buffer != null ) {
2727
/*int written = */sockchannel.write( buffer );

0 commit comments

Comments
 (0)