1 package com.coldcore.coloradoftp.connection.impl; 2 3 import com.coldcore.coloradoftp.command.Reply; 4 import com.coldcore.coloradoftp.connection.*; 5 import com.coldcore.coloradoftp.factory.ObjectFactory; 6 import com.coldcore.coloradoftp.factory.ObjectName; 7 import com.coldcore.coloradoftp.session.Session; 8 import com.coldcore.coloradoftp.session.SessionAttributeName; 9 import org.apache.log4j.Logger; 10 11 import java.nio.ByteBuffer ; 12 import java.nio.channels.ReadableByteChannel ; 13 import java.nio.channels.WritableByteChannel ; 14 import java.nio.channels.Channel ; 15 16 19 public class GenericDataConnection extends GenericConnection implements DataConnection { 20 21 private static Logger log = Logger.getLogger(GenericDataConnection.class); 22 protected ControlConnection controlConnection; 23 protected ReadableByteChannel rbc; 24 protected WritableByteChannel wbc; 25 protected DataConnectionMode mode; 26 protected String filename; 27 protected boolean userAborted; 28 protected boolean successful; 29 protected boolean skipReply; 30 protected DataConnectionCallback callback; 31 32 33 public GenericDataConnection(int bufferSize) { 34 super(); 35 36 rbuffer = ByteBuffer.allocate(bufferSize); 38 rbuffer.flip(); 39 } 40 41 42 43 protected void read() throws Exception { 44 48 49 if (!rbuffer.hasRemaining()) { 51 rbuffer.clear(); 52 int i = sc.read(rbuffer); rbuffer.flip(); 54 55 if (i == -1) { 57 successful = true; 58 throw new TransferCompleteException(); 59 } 60 61 bytesRead += i; 62 log.debug("Read from socket "+i+" bytes (total "+bytesRead+")"); 63 } 64 65 wbc.write(rbuffer); 67 } 68 69 70 71 protected void write() throws Exception { 72 76 77 if (!rbuffer.hasRemaining()) { 79 rbuffer.clear(); 80 int i = rbc.read(rbuffer); 81 rbuffer.flip(); 82 83 if (i == -1) { 85 successful = true; 86 throw new TransferCompleteException(); 87 } 88 } 89 90 int i = sc.write(rbuffer); 93 if (i == -1) throw new TransferAbortedException(); 95 96 bytesWrote += i; 97 log.debug("Wrote into socket "+i+" bytes (total "+bytesWrote+")"); 98 } 99 100 101 102 protected void activate() { 103 108 109 if (rbc != null || wbc != null) return; 110 111 if (mode == null) { 112 Session session = controlConnection.getSession(); 113 mode = (DataConnectionMode) session.getAttribute(SessionAttributeName.DATA_CONNECTION_MODE); 114 if (mode != null) { 115 log.debug("Mode extracted from user session"); 116 } 117 } 118 119 if (mode == null) return; 121 122 if (filename == null) { 123 Session session = controlConnection.getSession(); 124 filename = (String ) session.getAttribute(SessionAttributeName.DATA_CONNECTION_FILENAME); 125 if (filename != null) { 126 log.debug("Filename extracted from user session"); 127 } 128 } 129 130 if (mode != DataConnectionMode.LIST && filename == null) return; 132 133 if (rbc == null && wbc == null) { 135 Session session = controlConnection.getSession(); 136 if (mode == DataConnectionMode.LIST || mode == DataConnectionMode.RETR) { 137 rbc = (ReadableByteChannel ) session.getAttribute(SessionAttributeName.DATA_CONNECTION_CHANNEL); 138 startWriterThread(); } else { 140 wbc = (WritableByteChannel ) session.getAttribute(SessionAttributeName.DATA_CONNECTION_CHANNEL); 141 startReaderThread(); } 143 if (rbc != null || wbc != null) { 144 log.debug("Channel extracted from user session (data transfer begins)"); 145 } 146 } 147 } 148 149 150 public void service() throws Exception { 151 if (userAborted) throw new TransferAbortedException(); 153 154 activate(); 156 } 157 158 159 160 protected void closeDataChannel() { 161 Session session = controlConnection.getSession(); 162 Channel odc = (Channel ) session.getAttribute(SessionAttributeName.DATA_CONNECTION_CHANNEL); 163 session.removeAttribute(SessionAttributeName.DATA_CONNECTION_FILENAME); 164 try { 165 if (odc != null) odc.close(); 166 } catch (Throwable e) { 167 log.error("Error closing data channel (ignoring)", e); 168 } 169 } 170 171 172 173 protected void reply() { 174 try { 175 if (userAborted) { 177 Reply reply = (Reply) ObjectFactory.getObject(ObjectName.REPLY); 178 reply.setCode("426"); 179 reply.setText("Connection closed, transfer aborted."); 180 controlConnection.reply(reply); 181 182 reply = (Reply) ObjectFactory.getObject(ObjectName.REPLY); 183 reply.setCode("226"); 184 reply.setText("Abort command successful."); 185 controlConnection.reply(reply); 186 187 log.debug("User aborted data transfer"); 188 return; 189 } 190 191 if (!successful) { 193 Reply reply = (Reply) ObjectFactory.getObject(ObjectName.REPLY); 194 reply.setCode("426"); 195 reply.setText("Connection closed, transfer aborted."); 196 controlConnection.reply(reply); 197 198 log.debug("Data transfer failed"); 199 return; 200 } 201 202 Reply reply = (Reply) ObjectFactory.getObject(ObjectName.REPLY); 204 if (mode == DataConnectionMode.STOU) reply.setCode("250"); 205 else reply.setCode("226"); 206 207 if (mode == DataConnectionMode.LIST) { 208 reply.setText("Transfer completed."); 209 } else { 210 String encf = filename.replaceAll("\"", "\"\""); 212 reply.setText("Transfer completed for \""+encf+"\"."); 213 } 214 controlConnection.reply(reply); 215 216 log.debug("Data transfer successful"); 217 218 } catch (Throwable e) { 219 log.error("Error sending completion reply (ignoring)", e); 220 } 221 } 222 223 224 225 public synchronized void destroy() { 226 closeDataChannel(); 227 228 if (!skipReply && callback != null) 230 try { 231 if (successful) callback.onTransferComplete(this); 232 else callback.onTransferAbort(this); 233 } catch (Throwable e) { 234 log.error("Callback error (ignoring)", e); 235 } 236 237 if (!skipReply) reply(); 239 240 Session session = controlConnection.getSession(); 242 session.removeAttribute(SessionAttributeName.DATA_CONNECTION_MODE); 243 session.removeAttribute(SessionAttributeName.DATA_CONNECTION_CHANNEL); 244 245 if (controlConnection != null) controlConnection.setDataConnection(null); 247 248 super.destroy(); 249 } 250 251 252 public void destroyNoReply() { 253 skipReply = true; 254 destroy(); 255 } 256 257 258 public void abort() { 259 userAborted = true; 260 } 261 262 263 public ControlConnection getControlConnection() { 264 return controlConnection; 265 } 266 267 268 public void setControlConnection(ControlConnection controlConnection) { 269 this.controlConnection = controlConnection; 270 } 271 272 273 public DataConnectionCallback getDataConnectionCallback() { 274 return callback; 275 } 276 277 278 public void setDataConnectionCallback(DataConnectionCallback callback) { 279 this.callback = callback; 280 } 281 } 282 | Popular Tags |