public SendfileState processSendfile( SelectionKey sk, NioSocketWrapper socketWrapper, boolean calledByProcessor) { NioChannel sc = null; try { unreg(sk, socketWrapper, sk.readyOps()); SendfileData sd = socketWrapper.getSendfileData(); if (log.isTraceEnabled()) { log.trace("Processing send file for: " + sd.fileName); } if (sd.fchannel == null) { // Setup the file channel File f = new File(sd.fileName); if (!f.exists()) { cancelledKey(sk); return SendfileState.ERROR; } @SuppressWarnings("resource") // Closed when channel is closed FileInputStream fis = new FileInputStream(f); sd.fchannel = fis.getChannel(); } // Configure output channel sc = socketWrapper.getSocket(); // TLS/SSL channel is slightly different WritableByteChannel wc = ((sc instanceof SecureNioChannel) ? sc : sc.getIOChannel()); // We still have data in the buffer if (sc.getOutboundRemaining() > 0) { if (sc.flushOutbound()) { socketWrapper.updateLastWrite(); } } else { long written = sd.fchannel.transferTo(sd.pos, sd.length, wc); if (written > 0) { sd.pos += written; sd.length -= written; socketWrapper.updateLastWrite(); } else { // Unusual not to be able to transfer any bytes // Check the length was set correctly if (sd.fchannel.size() <= sd.pos) { throw new IOException( "Sendfile configured to " + "send more data than was available"); } } } if (sd.length <= 0 && sc.getOutboundRemaining() <= 0) { if (log.isDebugEnabled()) { log.debug("Send file complete for: " + sd.fileName); } socketWrapper.setSendfileData(null); try { sd.fchannel.close(); } catch (Exception ignore) { } // For calls from outside the Poller, the caller is // responsible for registering the socket for the // appropriate event(s) if sendfile completes. if (!calledByProcessor) { if (sd.keepAlive) { if (log.isDebugEnabled()) { log.debug("Connection is keep alive, registering back for OP_READ"); } reg(sk, socketWrapper, SelectionKey.OP_READ); } else { if (log.isDebugEnabled()) { log.debug("Send file connection is being closed"); } close(sc, sk); } } return SendfileState.DONE; } else { if (log.isDebugEnabled()) { log.debug("OP_WRITE for sendfile: " + sd.fileName); } if (calledByProcessor) { add(socketWrapper.getSocket(), SelectionKey.OP_WRITE); } else { reg(sk, socketWrapper, SelectionKey.OP_WRITE); } return SendfileState.PENDING; } } catch (IOException x) { if (log.isDebugEnabled()) log.debug("Unable to complete sendfile request:", x); if (!calledByProcessor && sc != null) { close(sc, sk); } else { cancelledKey(sk); } return SendfileState.ERROR; } catch (Throwable t) { log.error("", t); if (!calledByProcessor && sc != null) { close(sc, sk); } else { cancelledKey(sk); } return SendfileState.ERROR; } }