package io.eguan.nbdsrv; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import io.eguan.nbdsrv.packet.NbdException; import java.io.IOException; import java.nio.ByteBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents a client connection. Handle the device and the socket. * * @author oodrive * @author ebredzinski * */ final class ClientConnection { private static final Logger LOGGER = LoggerFactory.getLogger(ClientConnection.class); /** The Export Server */ private final ExportServer server; /** A handle on the client socket */ private final SocketHandle socketHandle; /** The current phase */ private PhaseAbstract phase; /** The remote flags set by the client */ private long remoteFlags; /** The name of the export chosen by the client */ private String exportName; /** The device on which the client is connected */ private NbdDevice device; ClientConnection(final SocketHandle socketHandle, final ExportServer server, final boolean isModern) { this.socketHandle = socketHandle; this.phase = new HandshakePhase(this); this.server = server; } /** * Gets the current phase. * * @return an {@link PhaseAbstract} */ final PhaseAbstract getPhase() { return phase; } /** * Set the new phase. * * @param phase * the new {@link PhaseAbstract} */ final void setPhase(final PhaseAbstract phase) { this.phase = phase; } /** * Gets the remote flags. * * @return a long corresponding to the flags */ final long getRemoteFlags() { return this.remoteFlags; } /** * Set the remote flags. * * @param flags * a long corresponding to the new flags */ final void setRemoteFlags(final long flags) { this.remoteFlags = flags; } /** * Gets the export name chosen by the client for this connection. * * @return a String representing the name of this export */ final String getExportName() { return this.exportName; } /** * Set the export name chosen by the client to use for this connection. * * @param name * represents the name of this export */ final void setExportName(final String name) { this.exportName = name; } /** * Gets the device for this connection. * * @return a {@link NbdDevice} */ final NbdDevice getNbdDevice() { return device; } /** * Set the device for this connection. * * @param name * the name of the device */ final void setNbdDevice(final String name) { this.device = server.getDevice(name); } /** * Write data into the socket up to the limit of each buffer. * * @param src * an array of {@link ByteBuffer} which contain the data */ final long write(final ByteBuffer[] src) throws IOException { return socketHandle.write(src); } /** * Write data into the socket up to the limit of the buffer. * * @param src * a {@link ByteBuffer} which contains the data */ final long write(final ByteBuffer src) throws IOException { return socketHandle.write(src); } /** * Read data in the socket and fill the buffer up to its limit. * * @param dst * a {@link ByteBuffer} to fill with received data */ final long read(final ByteBuffer dst) throws IOException { return socketHandle.read(dst); } /** * Close the connection. * */ final void close() { LOGGER.debug("Close connection"); try { socketHandle.close(); } catch (final Throwable t) { LOGGER.warn("Failed to close socket", t); } try { server.removeConnection(socketHandle.getSocket()); } catch (final Throwable t) { LOGGER.warn("Failed to remove client connection", t); } try { socketHandle.cancelKey(); } catch (final Throwable t) { LOGGER.warn("Failed to cancel selected key", t); } } /** * Get the address of the connected client. * * @return a {@link String} representing the remote address */ final String getRemoteAddress() { return socketHandle.getRemoteAddress(); } /** * Tells if the socket is readable and disable read. * * @return true if the socket is readable * */ final boolean isReadable() { return socketHandle.isReadable(); } /** * Enable the ability to receive data on the socket. * */ final void enableRead() { socketHandle.enableRead(); } /** * Gets the export size. * * @return the export size */ public final long getExportSize() throws NbdException { if (device == null) { throw new NbdException("Unknown Export : Export Name option has not been set"); } return device.getSize(); } /** * Tells of the export is read-only. * * @return <code>true</code> if the export is read-only */ public final boolean isExportReadOnly() throws NbdException { if (device == null) { throw new NbdException("Unknown Export : Export Name option has not been set"); } return device.isReadOnly(); } /** * Gets the list of the exports. * * @return an array of string representing the name of all the exports */ public final String[] getExportList() { return server.getExportList(); } /** * Tells if trim is enabled or not. * * @return <code>true</code> if trim is enabled, <code>false</code> otherwise */ public final boolean isTrimEnabled() { return server.isTrimEnabled(); } }