1/*******************************************************************************
2 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.agent.rt.internal.output;
13
14import java.io.IOException;
15import java.io.InputStream;
16import java.io.InterruptedIOException;
17import java.io.OutputStream;
18import java.net.InetAddress;
19import java.net.Socket;
20import java.net.SocketAddress;
21import java.net.SocketException;
22import java.net.SocketImpl;
23import java.nio.channels.SocketChannel;
24import java.util.Queue;
25import java.util.concurrent.ConcurrentLinkedQueue;
26
27/**
28 * Simulates two connected {@link Socket} objects. No physical connection is
29 * established for this. The behavior includes the (inconsistent) exception
30 * messages have been derived from Sun JDK 1.5.0_18-b02.
31 */
32public class MockSocketConnection {
33
34	private final MockSocket socketA;
35
36	private final MockSocket socketB;
37
38	public MockSocketConnection() throws SocketException {
39		socketA = new MockSocket();
40		socketB = new MockSocket();
41		socketA.connect(socketB);
42	}
43
44	public MockSocket getSocketA() {
45		return socketA;
46	}
47
48	public MockSocket getSocketB() {
49		return socketB;
50	}
51
52	class MockSocket extends Socket {
53
54		private MockSocket other;
55
56		private boolean closed;
57
58		private final Queue<Byte> buffer = new ConcurrentLinkedQueue<Byte>();
59
60		private final OutputStream out = new OutputStream() {
61
62			@Override
63			public void write(int b) throws IOException {
64				if (closed) {
65					throw new SocketException("Socket closed");
66				}
67				synchronized (other.buffer) {
68					other.buffer.add(Byte.valueOf((byte) b));
69					other.buffer.notifyAll();
70				}
71			}
72		};
73
74		private final InputStream in = new InputStream() {
75
76			@Override
77			public int read() throws IOException {
78				synchronized (buffer) {
79					try {
80						while (true) {
81							if (closed) {
82								throw new SocketException("socket closed");
83							}
84							if (other.closed) {
85								return -1;
86							}
87							final Byte b = buffer.poll();
88							buffer.notifyAll();
89							if (b != null) {
90								return 0xff & b.intValue();
91							}
92							buffer.wait();
93						}
94					} catch (InterruptedException e) {
95						throw new InterruptedIOException();
96					}
97				}
98			}
99
100			@Override
101			public int available() throws IOException {
102				synchronized (buffer) {
103					return buffer.size();
104				}
105			}
106
107		};
108
109		private MockSocket() throws SocketException {
110			super((SocketImpl) null);
111			closed = false;
112		}
113
114		private void connect(MockSocket other) {
115			this.other = other;
116			other.other = this;
117		}
118
119		public void waitUntilInputBufferIsEmpty() throws InterruptedException {
120			synchronized (buffer) {
121				while (!closed && !buffer.isEmpty()) {
122					buffer.wait();
123				}
124			}
125		}
126
127		// socket methods with mocking behavior:
128
129		@Override
130		public OutputStream getOutputStream() throws IOException {
131			if (isClosed()) {
132				throw new SocketException("Socket is closed");
133			}
134			return out;
135		}
136
137		@Override
138		public InputStream getInputStream() throws IOException {
139			if (isClosed()) {
140				throw new SocketException("Socket is closed");
141			}
142			return in;
143		}
144
145		@Override
146		public void close() throws IOException {
147			synchronized (buffer) {
148				closed = true;
149				buffer.notifyAll();
150			}
151			synchronized (other.buffer) {
152				other.buffer.notifyAll();
153			}
154		}
155
156		@Override
157		public boolean isClosed() {
158			synchronized (buffer) {
159				return closed;
160			}
161		}
162
163		// unsupported socket methods:
164
165		@Override
166		public void bind(SocketAddress bindpoint) throws IOException {
167			throw new AssertionError();
168		}
169
170		@Override
171		public void connect(SocketAddress endpoint, int timeout)
172				throws IOException {
173			throw new AssertionError();
174		}
175
176		@Override
177		public void connect(SocketAddress endpoint) throws IOException {
178			throw new AssertionError();
179		}
180
181		@Override
182		public SocketChannel getChannel() {
183			throw new AssertionError();
184		}
185
186		@Override
187		public InetAddress getInetAddress() {
188			throw new AssertionError();
189		}
190
191		@Override
192		public boolean getKeepAlive() throws SocketException {
193			throw new AssertionError();
194		}
195
196		@Override
197		public InetAddress getLocalAddress() {
198			throw new AssertionError();
199		}
200
201		@Override
202		public int getLocalPort() {
203			throw new AssertionError();
204		}
205
206		@Override
207		public SocketAddress getLocalSocketAddress() {
208			throw new AssertionError();
209		}
210
211		@Override
212		public boolean getOOBInline() throws SocketException {
213			throw new AssertionError();
214		}
215
216		@Override
217		public int getPort() {
218			throw new AssertionError();
219		}
220
221		@Override
222		public synchronized int getReceiveBufferSize() throws SocketException {
223			throw new AssertionError();
224		}
225
226		@Override
227		public SocketAddress getRemoteSocketAddress() {
228			throw new AssertionError();
229		}
230
231		@Override
232		public boolean getReuseAddress() throws SocketException {
233			throw new AssertionError();
234		}
235
236		@Override
237		public synchronized int getSendBufferSize() throws SocketException {
238			throw new AssertionError();
239		}
240
241		@Override
242		public int getSoLinger() throws SocketException {
243			throw new AssertionError();
244		}
245
246		@Override
247		public synchronized int getSoTimeout() throws SocketException {
248			throw new AssertionError();
249		}
250
251		@Override
252		public boolean getTcpNoDelay() throws SocketException {
253			throw new AssertionError();
254		}
255
256		@Override
257		public int getTrafficClass() throws SocketException {
258			throw new AssertionError();
259		}
260
261		@Override
262		public boolean isBound() {
263			throw new AssertionError();
264		}
265
266		@Override
267		public boolean isConnected() {
268			throw new AssertionError();
269		}
270
271		@Override
272		public boolean isInputShutdown() {
273			throw new AssertionError();
274		}
275
276		@Override
277		public boolean isOutputShutdown() {
278			throw new AssertionError();
279		}
280
281		@Override
282		public void sendUrgentData(int data) throws IOException {
283			throw new AssertionError();
284		}
285
286		@Override
287		public void setKeepAlive(boolean on) throws SocketException {
288			throw new AssertionError();
289		}
290
291		@Override
292		public void setOOBInline(boolean on) throws SocketException {
293			throw new AssertionError();
294		}
295
296		@Override
297		public void setPerformancePreferences(int connectionTime, int latency,
298				int bandwidth) {
299			throw new AssertionError();
300		}
301
302		@Override
303		public synchronized void setReceiveBufferSize(int size)
304				throws SocketException {
305			throw new AssertionError();
306		}
307
308		@Override
309		public void setReuseAddress(boolean on) throws SocketException {
310			throw new AssertionError();
311		}
312
313		@Override
314		public synchronized void setSendBufferSize(int size)
315				throws SocketException {
316			throw new AssertionError();
317		}
318
319		@Override
320		public void setSoLinger(boolean on, int linger) throws SocketException {
321			throw new AssertionError();
322		}
323
324		@Override
325		public synchronized void setSoTimeout(int timeout)
326				throws SocketException {
327			throw new AssertionError();
328		}
329
330		@Override
331		public void setTcpNoDelay(boolean on) throws SocketException {
332			throw new AssertionError();
333		}
334
335		@Override
336		public void setTrafficClass(int tc) throws SocketException {
337			throw new AssertionError();
338		}
339
340		@Override
341		public void shutdownInput() throws IOException {
342			throw new AssertionError();
343		}
344
345		@Override
346		public void shutdownOutput() throws IOException {
347			throw new AssertionError();
348		}
349
350	}
351
352}
353