package org.opendedup.sdfs.network; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.util.ArrayList; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; import org.opendedup.sdfs.Main; import org.opendedup.sdfs.filestore.HashChunk; import org.opendedup.sdfs.servers.HashChunkService; import org.opendedup.util.StringUtils; /** * @author Sam Silverberg This is the network class that is used within the * Chunk store to service all client requests and responses. It is * threaded and is spawned by @see * com.annesam.sdfs.network.NetworkHCServer when a new TCP connect in * accepted. */ class ClientThread extends Thread { // DataInputStream is = null; DataOutputStream os = null; Socket clientSocket = null; private ReentrantLock writelock = new ReentrantLock(); private static ArrayList<ClientThread> clients = new ArrayList<ClientThread>(); private static Logger log = Logger.getLogger("sdfs"); public ClientThread(Socket clientSocket) { this.clientSocket = clientSocket; log.finer("Client Threads is " + clients.size()); addClient(this); } public static void addClient(ClientThread client) { clients.add(client); } public static void removeClient(ClientThread client) { clients.remove(client); } public void run() { try { // is = new DataInputStream(clientSocket.getInputStream()); BufferedReader reader = new BufferedReader(new InputStreamReader( clientSocket.getInputStream()), 32768 * 2); DataInputStream is = new DataInputStream(new BufferedInputStream( clientSocket.getInputStream(), 32768 * 2)); os = new DataOutputStream(new BufferedOutputStream(clientSocket .getOutputStream())); String versionMessage = "SDFS version " + Main.PROTOCOL_VERSION + "\r\n"; os.write(versionMessage.getBytes()); os.flush(); while (true) { try { byte cmd = is.readByte(); if (cmd == NetworkCMDS.QUIT_CMD) { log.info("Quiting Client Network Thread"); break; } if (cmd == NetworkCMDS.HASH_EXISTS_CMD) { byte[] hash = new byte[is.readShort()]; is.readFully(hash); boolean exists = HashChunkService.hashExists(hash); try { writelock.lock(); os.writeBoolean(exists); os.flush(); writelock.unlock(); } catch (IOException e) { if (writelock.isLocked()) writelock.unlock(); throw new IOException(e.toString()); } finally { } } if (cmd == NetworkCMDS.WRITE_HASH_CMD || cmd == NetworkCMDS.WRITE_COMPRESSED_CMD) { byte[] hash = new byte[is.readShort()]; is.readFully(hash); int len = is.readInt(); byte[] chunkBytes = new byte[len]; is.readFully(chunkBytes); boolean done = false; if (cmd == NetworkCMDS.WRITE_COMPRESSED_CMD) { done = HashChunkService.writeChunk(hash, chunkBytes, len, len, true); } else { done = HashChunkService.writeChunk(hash, chunkBytes, len, len, false); } try { writelock.lock(); os.writeBoolean(done); os.flush(); writelock.unlock(); } catch (IOException e) { if (writelock.isLocked()) writelock.unlock(); throw new IOException(e.toString()); } finally { } } if (cmd == NetworkCMDS.FETCH_CMD || cmd == NetworkCMDS.FETCH_COMPRESSED_CMD) { byte[] hash = new byte[is.readShort()]; is.readFully(hash); HashChunk dChunk = null; try { dChunk = HashChunkService.fetchChunk(hash); if (cmd == NetworkCMDS.FETCH_COMPRESSED_CMD && !dChunk.isCompressed()) { /* * byte[] cChunk = CompressionUtils * .compress(dChunk.getData()); try { * writelock.lock(); os.writeInt(cChunk.length); * os.write(cChunk); os.flush(); * writelock.unlock(); } catch (IOException e) { * if(writelock.isLocked()) writelock.unlock(); * throw new IOException(e.toString()); } * finally { * * } */ throw new Exception("not implemented"); } else if (cmd == NetworkCMDS.FETCH_CMD && dChunk.isCompressed()) { /* * byte[] cChunk = CompressionUtils * .decompress(dChunk.getData()); * * try { writelock.lock(); * os.writeInt(cChunk.length); os.write(cChunk); * os.flush(); writelock.unlock(); } catch * (IOException e) { if(writelock.isLocked()) * writelock.unlock(); throw new * IOException(e.toString()); } finally { * * } */ throw new IOException("Not implemented"); } else { try { writelock.lock(); os.writeInt(dChunk.getData().length); os.write(dChunk.getData()); os.flush(); writelock.unlock(); } catch (IOException e) { if (writelock.isLocked()) writelock.unlock(); throw new IOException(e.toString()); } finally { } } } catch (NullPointerException e) { log.warning("chunk " + StringUtils.getHexString(hash) + " does not exist"); try { writelock.lock(); os.writeInt(-1); os.flush(); writelock.unlock(); } catch (IOException e1) { if (writelock.isLocked()) writelock.unlock(); throw new IOException(e1.toString()); } finally { } } } if (cmd == NetworkCMDS.PING_CMD) { try { writelock.lock(); os.writeShort(NetworkCMDS.PING_CMD); os.flush(); writelock.unlock(); } catch (IOException e) { if (writelock.isLocked()) writelock.unlock(); throw new IOException(e.toString()); } finally { } } } catch (Exception e) { log.log(Level.FINEST, "unable to write data", e); try { reader.close(); } catch (Exception e1) { } try { os.close(); } catch (Exception e1) { } try { is.close(); } catch (Exception e1) { } try { clientSocket.close(); } catch (Exception e1) { } break; } } try { reader.close(); } catch (Exception e1) { } try { os.close(); } catch (Exception e1) { } try { is.close(); } catch (Exception e1) { } try { clientSocket.close(); } catch (Exception e1) { } clientSocket.close(); } catch (IOException e) { } finally { ClientThread.removeClient(this); } } public static final int byteArrayToInt(byte[] b) { return (b[0] << 24) + ((b[1] & 0xFF) << 16) + ((b[2] & 0xFF) << 8) + (b[3] & 0xFF); } }