Author: mturk Date: Thu Aug 11 11:23:54 2011 New Revision: 1156578 URL: http://svn.apache.org/viewvc?rev=1156578&view=rev Log: Add java sendfile api
Added: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Sendfile.java (with props) Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr/descriptor.h commons/sandbox/runtime/trunk/src/main/native/os/linux/sendfile.c commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfile.c commons/sandbox/runtime/trunk/src/main/native/os/win32/sendfile.c commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestLocalEndpoint.java Added: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Sendfile.java URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Sendfile.java?rev=1156578&view=auto ============================================================================== --- commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Sendfile.java (added) +++ commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Sendfile.java Thu Aug 11 11:23:54 2011 @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.runtime.net; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; +import java.io.SyncFailedException; +import java.io.File; +import java.net.SocketException; +import org.apache.commons.runtime.io.ClosedDescriptorException; +import org.apache.commons.runtime.io.Descriptor; +import org.apache.commons.runtime.io.Stream; +import org.apache.commons.runtime.OperationNotImplementedException; +import org.apache.commons.runtime.OverflowException; + +/** + * This class represents a sendfile object. + */ +public class Sendfile implements Closeable +{ + private long sf; + private boolean closed = true; + + private static native long open0(String path) + throws IOException; + private static native int close0(long sf); + private static native int send0(long sd, long sf) + throws IOException; + private static native long size0(long sf); + private static native long size1(long sf); + private static native long size2(long sf); + + private Sendfile() + { + // No instance + } + + /** + * Creates a new Sendfile object. + */ + public Sendfile(String path) + throws IOException + { + sf = open0(path); + closed = false; + } + + /** + * Creates a new Sendfile object. + */ + public Sendfile(File path) + throws IOException + { + sf = open0(path.getPath()); + closed = false; + } + + /** + * Free the allocated resource by the Operating system. + * <p> + * Note that {@code Object.finalize()} method will call + * this function. However if the native code can block for + * long time explicit {@code close()} should be called. + * </p> + * @see java.io.Closeable#close() + * @throws IOException if an I/O error occurs. + */ + @Override + public void close() + throws IOException + { + if (!closed) { + closed = true; + int rc = close0(sf); + sf = 0L; + } + } + + /** + * Returns whether this sendfile object is closed. + * + * @return {@code true} if the sendfile is closed, + * {@code false} otherwise. + */ + public boolean closed() + { + return closed; + } + + /** + * Send file. + * The function sends file data and returns the number of bytes + * actually send. User should call this function untill it returns + * {@code zero}. + * + * @return number of bytes send or {@code -1} if the + * entire file was send. + * @throws IOException in case of error. + */ + public int send(Endpoint endpoint) + throws IOException + { + if (endpoint.closed() || closed) + throw new ClosedDescriptorException(); + return send0(endpoint.descriptor().fd(), sf); + } + + /** + * Get the size of the file to send. + * + * @return number of bytes that equals to opened file size. + */ + public long length() + throws IOException + { + if (closed) + throw new ClosedDescriptorException(); + return size0(sf); + } + + /** + * Returns the number of bytes send so far. + * + * @return number of bytes send so far. + */ + public long position() + throws IOException + { + if (closed) + throw new ClosedDescriptorException(); + return size1(sf); + } + + /** + * Returns the number of bytes to be send. + * + * @return number of bytes that has to be send. + */ + public long remaining() + throws IOException + { + if (closed) + throw new ClosedDescriptorException(); + return size2(sf); + } + +} Propchange: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/net/Sendfile.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr/descriptor.h URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr/descriptor.h?rev=1156578&r1=1156577&r2=1156578&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/include/acr/descriptor.h (original) +++ commons/sandbox/runtime/trunk/src/main/native/include/acr/descriptor.h Thu Aug 11 11:23:54 2011 @@ -92,13 +92,14 @@ struct acr_sf_t { #else HANDLE fh; #endif - acr_off_t off; #if !defined(WINDOWS) - struct_stat_t info; + off_t off; + off_t size; #else + acr_off_t off; + acr_off_t size; LPOVERLAPPED pob; /**< For TransmitFile */ #endif - acr_off_t size; }; Modified: commons/sandbox/runtime/trunk/src/main/native/os/linux/sendfile.c URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/linux/sendfile.c?rev=1156578&r1=1156577&r2=1156578&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/os/linux/sendfile.c (original) +++ commons/sandbox/runtime/trunk/src/main/native/os/linux/sendfile.c Thu Aug 11 11:23:54 2011 @@ -48,19 +48,23 @@ ACR_NET_EXPORT(jint, Sendfile, send0)(JN ACR_THROW_NET_ERROR(ACR_EBADF); return -1; } - if (sf->info.st_size != 0) { - if ((sf->info.st_size - sf->off) > INT_MAX) + if (sf->size != 0) { + if ((sf->size - sf->off) > INT_MAX) cnt = INT_MAX; else - cnt = sf->info.st_size - sf->off; + cnt = sf->size - sf->off; } if (ACR_HASFLAG(sd, ACR_SO_WPART)) { ACR_CLRFLAG(sd, ACR_SO_WPART); rc = AcrWaitIO(sock, sd->timeout, POLLOUT); + if (rc != 0) + goto finally; + } + if (cnt == 0) { + AcrSdRelease(sd); + return -1; } while (rc == 0) { - if (cnt == 0) - break; wr = sendfile(sock, /* socket */ sf->fd, /* file descriptor of the file to be sent */ &sf->off, /* where in the file to start */ @@ -76,6 +80,7 @@ ACR_NET_EXPORT(jint, Sendfile, send0)(JN break; } } +finally: if (rc != 0) { wr = -1; ACR_THROW_NET_ERROR(rc); Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfile.c URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfile.c?rev=1156578&r1=1156577&r2=1156578&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfile.c (original) +++ commons/sandbox/runtime/trunk/src/main/native/os/unix/sendfile.c Thu Aug 11 11:23:54 2011 @@ -17,7 +17,6 @@ #include "acr/jnitypes.h" #include "acr/error.h" #include "acr/debug.h" -#include "acr/iofd.h" #include "acr/memory.h" #include "acr/netapi.h" #include "acr/string.h" @@ -31,6 +30,7 @@ ACR_NET_EXPORT(jlong, Sendfile, open0)(J { int rc = 0; acr_sf_t *sf; + struct_stat_t info; if ((sf = ACR_TALLOC(acr_sf_t)) == 0) return 0; @@ -49,8 +49,10 @@ ACR_NET_EXPORT(jlong, Sendfile, open0)(J if ((rc = AcrCloseOnExec(sf->fd, 1)) == 0) #endif { - if (fstat(sf->fd, &sf->info) != 0) + if (fstat(sf->fd, &info) == -1) rc = errno; + else + sf->size = info.st_size; } } } DONE_WITH_STR(fname); @@ -63,54 +65,6 @@ ACR_NET_EXPORT(jlong, Sendfile, open0)(J return P2J(sf); } -ACR_NET_EXPORT(jlong, Sendfile, open1)(JNI_STDARGS, jobject fd) -{ - int rc = 0; - int nd; - acr_sf_t *sf; - - if (fd == 0) { - ACR_THROW_NET_ERROR(ACR_EBADF); - return 0; - } - nd = AcrGetFileDescriptorFd(env, fd); - if (nd == -1) { - ACR_THROW_NET_ERROR(ACR_EIO); - return 0; - } - if ((sf = ACR_TALLOC(acr_sf_t)) == 0) - return 0; - /* Duplicate FileDescriptor so - * we don't have to reference it - */ -#if HAVE_DUP3 - sf->fd = dup3(nd, -1, O_CLOEXEC); -#else - sf->fd = dup2(nd, -1); - if (sf->fd != -1) { - rc = AcrCloseOnExec(sf->fd, 1); - if (rc != 0) { - r_close(sf->fd); - errno = rc; - sf->fd = -1; - } - } -#endif - if (sf->fd == -1) { - ACR_THROW_NET_ERRNO(); - AcrFree(sf); - return 0; - } - if (fstat(sf->fd, &sf->info) != 0) { - rc = ACR_GET_OS_ERROR(); - r_close(sf->fd); - AcrFree(sf); - ACR_THROW_NET_ERROR(rc); - return 0; - } - return P2J(sf); -} - ACR_NET_EXPORT(jint, Sendfile, close0)(JNI_STDARGS, jlong fp) { int rc = 0; @@ -124,13 +78,17 @@ ACR_NET_EXPORT(jint, Sendfile, close0)(J ACR_NET_EXPORT(jlong, Sendfile, size0)(JNI_STDARGS, jlong fp) { acr_sf_t *sf = J2P(fp, acr_sf_t *); - - return (jlong)sf->info.st_size; + return (jlong)sf->size; } ACR_NET_EXPORT(jlong, Sendfile, size1)(JNI_STDARGS, jlong fp) { acr_sf_t *sf = J2P(fp, acr_sf_t *); - return (jlong)sf->off; } + +ACR_NET_EXPORT(jlong, Sendfile, size2)(JNI_STDARGS, jlong fp) +{ + acr_sf_t *sf = J2P(fp, acr_sf_t *); + return (jlong)(sf->size - sf->off); +} Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/sendfile.c URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/sendfile.c?rev=1156578&r1=1156577&r2=1156578&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/os/win32/sendfile.c (original) +++ commons/sandbox/runtime/trunk/src/main/native/os/win32/sendfile.c Thu Aug 11 11:23:54 2011 @@ -70,56 +70,6 @@ ACR_NET_EXPORT(jlong, SendFile, open0)(J } } -ACR_NET_EXPORT(jlong, SendFile, open1)(JNI_STDARGS, jobject fd) -{ - int rc = 0; - HANDLE nd; - acr_sf_t *sf; - - if (fd == 0) { - ACR_THROW_NET_ERROR(ACR_EBADF); - return 0; - } - nd = AcrGetFileDescriptorHandle(env, fd); - if (IS_INVALID_HANDLE(nd)) { - ACR_THROW_NET_ERROR(ACR_EIO); - return 0; - } - if ((sf = ACR_TALLOC(acr_sf_t)) == 0) - return 0; - /* Duplicate FileDescriptor so - * we don't have to reference it - */ - if (!DuplicateHandle(GetCurrentProcess(), nd, - GetCurrentProcess(), &sf->fh, - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - rc = GetLastError(); - } - else { - BY_HANDLE_FILE_INFORMATION fi; - if (GetFileInformationByHandle(sf->fh, &fi)) - sf->size = AcrToInt64(fi.nFileSizeHigh, fi.nFileSizeLow); - else - rc = GetLastError(); - } - if (rc != 0) { - SAFE_CLOSE_HANDLE(sf->fh); - AcrFree(sf); - ACR_THROW_NET_ERROR(rc); - return 0; - } - sf->pob = ACR_TALLOC(OVERLAPPED); - if (sf->pob != 0) { - sf->pob->hEvent = CreateEvent(0, FALSE, FALSE, 0); - return P2J(sf); - } - else { - CloseHandle(sf->fh); - AcrFree(sf); - return 0; - } -} - ACR_NET_EXPORT(jint, SendFile, close0)(JNI_STDARGS, jlong fp) { int rc = 0; @@ -144,6 +94,12 @@ ACR_NET_EXPORT(jlong, Sendfile, size1)(J return (jlong)sf->off; } +ACR_NET_EXPORT(jlong, Sendfile, size2)(JNI_STDARGS, jlong fp) +{ + acr_sf_t *sf = J2P(fp, acr_sf_t *); + return (jlong)(sf->size - sf->off); +} + #define MAX_SEGMENT_SIZE 65536 ACR_NET_EXPORT(jint, Sendfile, send0)(JNI_STDARGS, jlong sp, jlong fp) { @@ -169,6 +125,12 @@ ACR_NET_EXPORT(jint, Sendfile, send0)(JN ACR_CLRFLAG(sd, ACR_SO_WPART); /* Wait for the previous operation to finish */ rc = AcrWaitIO(sock, sd->timeout, POLLOUT); + if (rc != 0) + goto finally; + } + if (tosend == 0) { + AcrSdRelease(sd); + return -1; } sf->pob->Offset = (DWORD)(sf->off); sf->pob->OffsetHigh = (DWORD)(sf->off >> 32); @@ -211,6 +173,7 @@ ACR_NET_EXPORT(jint, Sendfile, send0)(JN sf->off += cnt; xmitted += cnt; } +finally: if (rc != 0) { xmitted = -1; ACR_THROW_NET_ERROR(rc); Modified: commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestLocalEndpoint.java URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestLocalEndpoint.java?rev=1156578&r1=1156577&r2=1156578&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestLocalEndpoint.java (original) +++ commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestLocalEndpoint.java Thu Aug 11 11:23:54 2011 @@ -17,6 +17,8 @@ package org.apache.commons.runtime.net; import java.io.File; +import java.io.FileDescriptor; +import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import org.testng.annotations.*; @@ -132,7 +134,7 @@ public class TestLocalEndpoint extends A // sync.wait(); } - Thread.sleep(100); + Thread.sleep(200); } catch (InterruptedException x) { // Ignore } @@ -143,6 +145,24 @@ public class TestLocalEndpoint extends A LocalEndpoint cs = new LocalEndpoint(); cs.connect(sa); assertTrue(cs.isBlocking()); + File sendf = new File("acrsendfile.tmp"); + sendf.deleteOnExit(); + FileOutputStream fs = new FileOutputStream(sendf); + byte[] b = new byte[1000]; + for (int i = 0; i < 500; i++) + fs.write(b); + fs.close(); + try { + Sendfile sf = new Sendfile(sendf); + cs.configureBlocking(false); + int send = sf.send(cs); + assertTrue(send > 0); + assertEquals(sf.length() - send, sf.remaining()); + cs.configureBlocking(true); + System.out.println("Send " + send + " bytes."); + } catch (Exception se) { + System.out.println("Error sending file " + se); + } cs.close(); ps.interrupt(); try {