/* * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ package com.l2jserver.communityserver.network.netcon; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import com.l2jserver.communityserver.network.netcon.crypt.NewCrypt; /** * @author Forsaiken */ public abstract class NetConnection extends Thread { private static final NewCrypt INITIAL_CRYPT = new NewCrypt("_;v.]05-31!|+-%xT!^[$\00"); private final NetConnectionConfig _config; /* TCP */ private Socket _tcpCon; private BufferedInputStream _tcpIn; private BufferedOutputStream _tcpOut; /* CRYPT */ private NewCrypt _crypt; protected NetConnection(NetConnectionConfig config) { _config = config; } public final void connect(final String address, final int port) throws UnknownHostException, IOException { connect(new Socket(address, port)); } public final void connect(final Socket remoteConnection) throws IOException { if (isConnected()) throw new IOException("TCP Connect: Allready connected."); _crypt = INITIAL_CRYPT; _tcpCon = remoteConnection; _tcpOut = new BufferedOutputStream(_tcpCon.getOutputStream(), _config.TCP_SEND_BUFFER_SIZE); _tcpIn = new BufferedInputStream(_tcpCon.getInputStream(), _config.TCP_RECEIVE_BUFFER_SIZE); } public final boolean isConnected() throws IOException { return _tcpCon != null && _tcpCon.isConnected(); } public final int getConnectionPort() throws IOException { if (!isConnected()) throw new IOException("TCP: Not connected."); return _tcpCon.getPort(); } public final String getConnectionAddress() throws IOException { if (!isConnected()) throw new IOException("TCP: Not connected."); return _tcpCon.getInetAddress().getHostAddress(); } protected final byte[] read() throws IOException { if (_tcpCon == null) throw new IOException("TCP Read: Not initialized."); if (_tcpCon.isClosed()) throw new IOException("TCP Read: Connection closed."); final int lengthLo = _tcpIn.read(); final int lengthHi = _tcpIn.read(); final int length = lengthHi * 256 + lengthLo; if (lengthHi < 0) throw new IOException("TCP Read: Failed reading."); final byte[] data = new byte[length - 2]; int receivedBytes = 0; int newBytes = 0; int left = length - 2; while ((newBytes != -1) && (receivedBytes < length - 2)) { if (receivedBytes == 0) newBytes = this._tcpIn.read(data, 0, left); else newBytes = this._tcpIn.read(data, receivedBytes, left); receivedBytes += newBytes; left -= newBytes; } if (receivedBytes != length - 2) throw new IOException("TCP Read: Incomplete Packet recived."); return decrypt(data); } protected final void write(final BaseWritePacket packet) throws IOException { if (_tcpCon == null) throw new IOException("TCP Write: Not initialized."); if (_tcpCon.isClosed()) throw new IOException("TCP Write: Connection closed."); final byte[] data = crypt(packet.getContent()); final int len = data.length + 2; synchronized (_tcpOut) { _tcpOut.write(len & 0xFF); _tcpOut.write(len >> 8 & 0xFF); _tcpOut.write(data); _tcpOut.flush(); } } protected final void close(final BaseWritePacket packet) throws IOException { try { if (packet != null) write(packet); } finally { if (_tcpIn != null) { _tcpIn.close(); _tcpIn = null; } if (_tcpOut != null) { _tcpOut.close(); _tcpOut = null; } if (_tcpCon != null) { _tcpCon.close(); _tcpCon = null; } } } public final void setCrypt(final NewCrypt crypt) { _crypt = crypt; } private final byte[] decrypt(byte[] data) throws IOException { data = _crypt.decrypt(data); if (!NewCrypt.verifyChecksum(data)) throw new IOException("CRYPT: Incorrect packet checksum."); return data; } private final byte[] crypt(final byte[] data) throws IOException { NewCrypt.appendChecksum(data); return _crypt.crypt(data); } public abstract void run(); }