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.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
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.servers.HCServer;
public class HashClient {
private Socket clientSocket = null;
private DataOutputStream os = null;
private DataInputStream is = null;
private BufferedReader inReader = null;
private boolean closed = false;
private HCServer server;
private String name = "";
private static Logger log = Logger.getLogger("sdfs");
private ReentrantLock lock = new ReentrantLock();
// private LRUMap existsBuffers = new LRUMap(10);
public HashClient(HCServer server, String name) {
this.server = server;
this.name = name;
this.openConnection();
}
public String getName() {
return this.name;
}
public boolean isClosed() {
return this.closed;
}
public synchronized void openConnection() {
// System.out.println("Opening Connection to " + server.getHostName());
// Initialization section:
// Try to open a socket on a given host and port
// Try to open input and output streams
try {
log.fine("Connecting to server " + server.getHostName() + " on port " + server.getPort());
clientSocket = new Socket(server.getHostName(), server.getPort());
clientSocket.setKeepAlive(true);
clientSocket.setTcpNoDelay(true);
os = new DataOutputStream(new BufferedOutputStream(clientSocket
.getOutputStream(), Main.CHUNK_LENGTH + 34));
is = new DataInputStream(new BufferedInputStream(clientSocket
.getInputStream(), Main.CHUNK_LENGTH + 34));
inReader = new BufferedReader(new InputStreamReader(clientSocket
.getInputStream()));
// Read the Header Line
inReader.readLine();
this.closed = false;
} catch (UnknownHostException e) {
log.severe("Don't know about host " + server);
this.closed = true;
} catch (Exception e) {
log.log(Level.SEVERE,"Couldn't get I/O for the connection to the host",e);
this.closed = true;
}
}
public void executeCmd(IOCmd cmd) throws IOException {
if (this.closed)
this.openConnection();
lock.lock();
try {
cmd.executeCmd(is, os);
} catch (Exception e) {
this.closed = true;
try {
this.openConnection();
cmd.executeCmd(is, os);
} catch (Exception e1) {
log.log(Level.SEVERE, "unable to execute command", e);
throw new IOException("unable to execute command");
}
} finally {
lock.unlock();
}
}
private void executeUDPCmd(IOCmd cmd) throws SocketTimeoutException,
IOException {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(Main.UDPClientTimeOut);
byte[] b = new byte[33];
ByteBuffer buf = ByteBuffer.wrap(b);
if (cmd.getCmdID() == NetworkCMDS.HASH_EXISTS_CMD) {
HashExistsCmd hcmd = (HashExistsCmd) cmd;
buf.put(NetworkCMDS.HASH_EXISTS_CMD);
buf.put(hcmd.getHash());
InetSocketAddress addr = new InetSocketAddress(
server.getHostName(), server.getPort());
DatagramPacket packet = new DatagramPacket(buf.array(), b.length,
addr);
socket.send(packet);
packet = new DatagramPacket(new byte[2], 2, addr);
socket.receive(packet);
buf = ByteBuffer.wrap(packet.getData());
short exists = buf.getShort();
if (exists == 0)
hcmd.exists = false;
else
hcmd.exists = true;
}
b = null;
}
public void close() {
try {
os.write(NetworkCMDS.QUIT_CMD);
os.flush();
} catch (Exception e) {
} finally {
try {
inReader.close();
} catch (IOException e) {
}
try {
os.close();
} catch (IOException e) {
}
try {
is.close();
} catch (IOException e) {
}
try {
clientSocket.close();
} catch (IOException e) {
}
os = null;
is = null;
inReader = null;
this.closed = true;
}
}
public boolean writeChunk(byte[] hash, byte[] aContents, int position,
int len) throws IOException {
WriteHashCmd cmd = new WriteHashCmd(hash, aContents, len, server
.isCompress());
this.executeCmd(cmd);
return cmd.wasWritten();
}
public byte[] fetchChunk(byte[] hash) throws IOException {
FetchChunkCmd cmd = new FetchChunkCmd(hash, server.isCompress());
this.executeCmd(cmd);
return cmd.getChunk();
}
public boolean hashExists(byte[] hash) throws IOException {
HashExistsCmd cmd = new HashExistsCmd(hash);
if (server.isUseUDP()) {
try {
this.executeUDPCmd(cmd);
} catch (IOException e) {
System.out.println("trying tcp");
this.executeCmd(cmd);
}
} else {
this.executeCmd(cmd);
}
return cmd.exists();
}
public void ping() throws IOException {
PingCmd cmd = new PingCmd();
this.executeCmd(cmd);
}
}