2 * jFCPlib - FcpConnectionHandler.java - Copyright © 2008–2016 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.fcp;
20 import java.io.EOFException;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.nio.ByteBuffer;
24 import java.nio.charset.Charset;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
29 * Handles an FCP connection to a node.
31 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
33 class FcpConnectionHandler implements Runnable {
36 private static final Logger logger = Logger.getLogger(FcpConnectionHandler.class.getName());
38 /** The underlying connection. */
39 private final FcpConnection fcpConnection;
41 /** The input stream from the node. */
42 private final InputStream remoteInputStream;
44 /** Whether to stop the connection handler. */
45 private boolean shouldStop;
47 /** Whether the next read line feed should be ignored. */
48 private boolean ignoreNextLinefeed;
51 * Creates a new connection handler that operates on the given connection
54 * @param fcpConnection
55 * The underlying FCP connection
56 * @param remoteInputStream
57 * The input stream from the node
59 public FcpConnectionHandler(FcpConnection fcpConnection, InputStream remoteInputStream) {
60 this.fcpConnection = fcpConnection;
61 this.remoteInputStream = remoteInputStream;
69 FcpMessage fcpMessage = null;
70 Throwable throwable = null;
78 String line = readLine();
79 logger.log(Level.FINEST, String.format("read line: %1$s", line));
81 throwable = new EOFException();
84 if (line.length() == 0) {
88 if (fcpMessage == null) {
89 fcpMessage = new FcpMessage(line);
92 if ("EndMessage".equalsIgnoreCase(line) || "Data".equalsIgnoreCase(line)) {
93 fcpConnection.handleMessage(fcpMessage);
96 int equalSign = line.indexOf('=');
97 if (equalSign == -1) {
98 /* something's fishy! */
101 String field = line.substring(0, equalSign);
102 String value = line.substring(equalSign + 1);
103 assert fcpMessage != null: "fcp message is null";
104 fcpMessage.setField(field, value);
105 } catch (IOException ioe1) {
110 fcpConnection.handleDisconnect(throwable);
114 * Stops the connection handler.
117 synchronized (this) {
127 * Reads bytes from {@link #remoteInputStream} until ‘\r’ or ‘\n’ are
128 * encountered and decodes the read bytes using UTF-8.
130 * @return The decoded line
131 * @throws IOException
132 * if an I/O error occurs
134 private String readLine() throws IOException {
135 byte[] readBytes = new byte[512];
138 int nextByte = remoteInputStream.read();
139 if (nextByte == -1) {
140 if (readIndex == 0) {
145 if (nextByte == 10) {
146 if (!ignoreNextLinefeed) {
150 ignoreNextLinefeed = false;
151 if (nextByte == 13) {
152 ignoreNextLinefeed = true;
155 if (readIndex == readBytes.length) {
156 /* recopy & enlarge array */
157 byte[] newReadBytes = new byte[readBytes.length * 2];
158 System.arraycopy(readBytes, 0, newReadBytes, 0, readBytes.length);
159 readBytes = newReadBytes;
161 readBytes[readIndex++] = (byte) nextByte;
163 ByteBuffer byteBuffer = ByteBuffer.wrap(readBytes, 0, readIndex);
164 return Charset.forName("UTF-8").decode(byteBuffer).toString();