/* This file is part of the Android Clementine Remote. * Copyright (C) 2013, Andreas Muttscheller <asfa194@gmail.com> * * 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 <http://www.gnu.org/licenses/>. */ package de.qspool.clementineremote.backend; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketTimeoutException; import de.qspool.clementineremote.backend.pb.ClementineMessage; import de.qspool.clementineremote.backend.pb.ClementineMessage.ErrorMessage; import de.qspool.clementineremote.backend.pb.ClementinePbParser; public class ClementineSimpleConnection { // Socket, input and output streams protected Socket mSocket; protected DataInputStream mIn; protected DataOutputStream mOut; // Protocol buffer data private ClementinePbParser mClementinePbParser = new ClementinePbParser(); /** * Try to connect to Clementine * * @param message The Request Object. Stores the ip to connect to. */ public boolean createConnection(ClementineMessage message) { SocketAddress socketAddress = new InetSocketAddress(message.getIp(), message.getPort()); mSocket = new Socket(); try { mSocket.connect(socketAddress, 3000); mIn = new DataInputStream(mSocket.getInputStream()); mOut = new DataOutputStream(new BufferedOutputStream(mSocket.getOutputStream())); // Send the connect request to clementine sendRequest(message); } catch (IOException e) { return false; } return true; } /** * Send a request to clementine * * @param message The request as a RequestToThread object * @return true if data was sent, false if not */ public boolean sendRequest(ClementineMessage message) { // Create the protocolbuffer byte[] data = message.getMessage().toByteArray(); try { mOut.writeInt(data.length); mOut.write(data); mOut.flush(); } catch (Exception e) { // Try to reconnect e.printStackTrace(); closeSocket(); return false; } return true; } /** * Get the raw protocol buffer message. This function blocks until data is * available! * * @returns The parsed protocol buffer */ public ClementineMessage getProtoc(int timeout) { ClementineMessage message; try { // Read the data and return it mSocket.setSoTimeout(timeout); int len = mIn.readInt(); // Check length. If it is less zero or more than 50mb it's very likely we got invalid data if (len < 0 || len > 52428800) { throw new IOException("Invalid data length"); } byte[] data = new byte[len]; mIn.readFully(data, 0, len); message = mClementinePbParser.parse(data); } catch (SocketTimeoutException e) { message = new ClementineMessage(ErrorMessage.TIMEOUT); } catch (IOException e) { message = new ClementineMessage(ErrorMessage.IO_EXCEPTION); } return message; } /** * Check if the Socket is still connected * * @return true if a connection is established */ public boolean isConnected() { if (mSocket == null || mOut == null || !mSocket.isConnected() || mSocket.isClosed()) { return false; } else { return true; } } /** * Disconnect from Clementine * * @param message The RequestDisconnect Object */ public void disconnect(ClementineMessage message) { if (isConnected()) { // Send the disconnect message to clementine byte[] data = message.getMessage().toByteArray(); try { // Now send the data mOut.writeInt(data.length); mOut.write(data); mOut.flush(); closeSocket(); } catch (IOException e) { } } } /** * Close the socket and the in and out streams */ protected void closeSocket() { try { mOut.close(); mSocket.close(); } catch (IOException e) { } } }