package org.dcache.pool.movers; /** * @author Patrick F. * @author Timur Perelmutov. timur@fnal.gov * @version 0.0, 28 Jun 2002 */ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; import diskCacheV111.util.CacheException; import diskCacheV111.util.PnfsId; import diskCacheV111.vehicles.DCapClientPortAvailableMessage; import diskCacheV111.vehicles.DCapClientProtocolInfo; import diskCacheV111.vehicles.ProtocolInfo; import diskCacheV111.vehicles.StorageInfo; import diskCacheV111.vehicles.StorageInfos; import dmg.cells.nucleus.CellEndpoint; import dmg.cells.nucleus.CellMessage; import dmg.cells.nucleus.CellPath; import org.dcache.pool.repository.Allocator; import org.dcache.pool.repository.RepositoryChannel; import org.dcache.util.NetworkUtils; import org.dcache.util.PortRange; import org.dcache.vehicles.FileAttributes; import static org.dcache.util.ByteUnit.KiB; public class DCapClientProtocol_1 implements MoverProtocol { private static final Logger _log = LoggerFactory.getLogger(DCapClientProtocol_1.class); public static final int READ = 1; public static final int WRITE = 2; private long last_transfer_time = System.currentTimeMillis(); private final CellEndpoint cell; private DCapClientProtocolInfo dcapClient; private long starttime; private volatile long transfered; public DCapClientProtocol_1(CellEndpoint cell) { this.cell = cell; say("DCapClientProtocol_1 created"); } private void say(String str){ _log.info(str); } private void esay(String str){ _log.error(str); } private void esay(Throwable t) { _log.error(t.toString()); } @Override public void runIO(FileAttributes fileAttributes, RepositoryChannel fileChannel, ProtocolInfo protocol , Allocator allocator , IoMode access) throws CacheException, IOException, InterruptedException { PnfsId pnfsId = fileAttributes.getPnfsId(); StorageInfo storage = StorageInfos.extractFrom(fileAttributes); say("runIO()\n\tprotocol="+ protocol+",\n\tStorageInfo="+storage+",\n\tPnfsId="+pnfsId+ ",\n\taccess ="+access); if(! (protocol instanceof DCapClientProtocolInfo)) { throw new CacheException( "protocol info is not RemoteGsiftpransferProtocolInfo"); } starttime = System.currentTimeMillis(); dcapClient = (DCapClientProtocolInfo) protocol; CellPath cellpath = new CellPath(dcapClient.getInitiatorCellName(), dcapClient.getInitiatorCellDomain()); say(" runIO() RemoteGsiftpTranferManager cellpath="+cellpath); ServerSocket serverSocket; int port; try { String dcachePorts = System.getProperty("org.dcache.net.tcp.portrange"); PortRange portRange = (dcachePorts != null) ? PortRange.valueOf(dcachePorts) : new PortRange(0); serverSocket = new ServerSocket(); port = portRange.bind(serverSocket, 1); } catch(IOException ioe) { esay("exception while trying to create a server socket : "+ioe); throw ioe; } InetAddress localAddress = NetworkUtils.getLocalAddress(dcapClient.getSocketAddress().getAddress()); DCapClientPortAvailableMessage cred_request = new DCapClientPortAvailableMessage(localAddress.getCanonicalHostName(), port,dcapClient.getId()); say(" runIO() created message"); cell.sendMessage (new CellMessage(cellpath,cred_request)); say("waiting for dcap server connection"); Socket dcap_socket = serverSocket.accept(); say("connected"); try { serverSocket.close(); } catch(IOException ioe) { esay("failed to close server socket"); esay(ioe); // we still can continue, this is non-fatal } if( access == IoMode.WRITE) { dcapReadFile(dcap_socket,fileChannel,allocator); } else { throw new IOException("read is not implemented"); } say(" runIO() done"); } @Override public long getLastTransferred() { return last_transfer_time; } @Override public long getBytesTransferred() { return transfered; } @Override public long getTransferTime() { return System.currentTimeMillis() -starttime; } private void dcapReadFile(Socket _socket, RepositoryChannel fileChannel, Allocator allocator) throws IOException, InterruptedException { last_transfer_time = System.currentTimeMillis(); DataInputStream in = new DataInputStream(_socket.getInputStream()); DataOutputStream out = new DataOutputStream(_socket.getOutputStream()); say("<init>"); int _sessionId = in.readInt(); int challengeSize = in.readInt(); while (challengeSize > 0) { challengeSize -= in.skipBytes(challengeSize); } say("<gettingFilesize>"); out.writeInt(4); // bytes following out.writeInt(9); // locate command // // waiting for reply // int following = in.readInt(); if(following < 28) { throw new IOException("Protocol Violation : ack too small : " + following); } int type = in.readInt(); if(type != 6) // REQUEST_ACK { throw new IOException("Protocol Violation : NOT REQUEST_ACK : " + type); } int mode = in.readInt(); if(mode != 9) // SEEK { throw new IOException("Protocol Violation : NOT SEEK : " + mode); } int returnCode = in.readInt(); if(returnCode != 0){ String error = in.readUTF(); throw new IOException("Seek Request Failed : ("+ returnCode+") "+error); } long filesize = in.readLong(); say("<WaitingForSpace-"+filesize+">"); allocator.allocate(filesize); // in.readLong(); // file position say("<StartingIO>"); // // request the full file // out.writeInt(12); // bytes following out.writeInt(2); // read command out.writeLong(filesize); // // waiting for reply // following = in.readInt(); if(following < 12) { throw new IOException("Protocol Violation : ack too small : " + following); } type = in.readInt(); if(type != 6) // REQUEST_ACK { throw new IOException("Protocol Violation : NOT REQUEST_ACK : " + type); } mode = in.readInt(); if(mode != 2) // READ { throw new IOException("Protocol Violation : NOT SEEK : " + mode); } returnCode = in.readInt(); if(returnCode != 0){ String error = in.readUTF(); throw new IOException("Read Request Failed : ("+ returnCode+") "+error); } say("<RunningIO>"); // // expecting data chain // // // waiting for reply // following = in.readInt(); if(following < 4) { throw new IOException("Protocol Violation : ack too small : " + following); } type = in.readInt(); if(type != 8) // DATA { throw new IOException("Protocol Violation : NOT DATA : " + type); } byte [] data = new byte[KiB.toBytes(256)]; ByteBuffer bb = ByteBuffer.wrap(data); int nextPacket; while(true){ if((nextPacket = in.readInt()) < 0) { break; } int restPacket = nextPacket; while(restPacket > 0){ bb.clear(); int block = Math.min(restPacket , data.length); // // we collect a full block before we write it out // (a block always fits into our buffer) // int position = 0; for(int rest = block; rest > 0;){ int rc = in.read(data , position , rest); last_transfer_time = System.currentTimeMillis(); if(rc < 0) { throw new IOException("Premature EOF"); } rest -= rc; position += rc; } transfered +=block; bb.limit(block); fileChannel.write(bb); restPacket -= block; } } say("<WaitingForReadAck>"); // // waiting for reply // following = in.readInt(); if(following < 12) { throw new IOException("Protocol Violation : ack too small : " + following); } type = in.readInt(); if(type != 7) // REQUEST_FIN { throw new IOException("Protocol Violation : NOT REQUEST_ACK : " + type); } mode = in.readInt(); if(mode != 2) // READ { throw new IOException("Protocol Violation : NOT SEEK : " + mode); } returnCode = in.readInt(); if(returnCode != 0){ String error = in.readUTF(); throw new IOException("Read Fin Failed : ("+ returnCode+") "+error); } say("<WaitingForCloseAck>"); // out.writeInt(4); // bytes following out.writeInt(4); // close request // // waiting for reply // following = in.readInt(); if(following < 12) { throw new IOException("Protocol Violation : ack too small : " + following); } type = in.readInt(); if(type != 6) // REQUEST_FIN { throw new IOException("Protocol Violation : NOT REQUEST_ACK : " + type); } mode = in.readInt(); if(mode != 4) // READ { throw new IOException("Protocol Violation : NOT SEEK : " + mode); } returnCode = in.readInt(); if(returnCode != 0){ String error = in.readUTF(); throw new IOException("Close ack Failed : ("+ returnCode+") "+error); } say("<Done>"); } }