12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036 |
- /* gnu_java_nio_VMChannel.c -
- Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <config-int.h>
- #include <sys/types.h>
- #ifdef HAVE_SYS_MMAN_H
- #include <sys/mman.h>
- #endif
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/uio.h>
- #include <netinet/in.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <jni.h>
- #include <jcl.h>
- #include "cpio.h"
- #include "gnu_java_nio_VMChannel.h"
- #include "javanio.h"
- #ifdef HAVE_FCNTL_H
- #include <fcntl.h>
- #endif /* HAVE_FCNTL_H */
- #if defined(HAVE_SYS_IOCTL_H)
- #define BSD_COMP /* Get FIONREAD on Solaris2 */
- #include <sys/ioctl.h>
- #endif
- #if defined(HAVE_SYS_FILIO_H) /* Get FIONREAD on Solaris 2.5 */
- #include <sys/filio.h>
- #endif
- #define CONNECT_EXCEPTION "java/net/ConnectException"
- #define IO_EXCEPTION "java/io/IOException"
- #define SOCKET_EXCEPTION "java/net/SocketException"
- #define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException"
- #define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException"
- #define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException"
- #define SOCKET_TIMEOUT_EXCEPTION "java/net/SocketTimeoutException"
- /* Align a value up or down to a multiple of the pagesize. */
- #define ALIGN_DOWN(p,s) ((p) - ((p) % (s)))
- #define ALIGN_UP(p,s) ((p) + ((s) - ((p) % (s))))
- /*
- * Limit to maximum of 16 buffers
- */
- #define JCL_IOV_MAX 16
- #ifdef __cplusplus
- extern "C"
- {
- #endif
- enum JCL_buffer_type { DIRECT, HEAP, ARRAY, UNKNOWN };
- struct JCL_buffer
- {
- enum JCL_buffer_type type;
- jbyte *ptr;
- jint offset;
- jint position;
- jint limit;
- jint count;
- };
- jmethodID get_method_id(JNIEnv *, jclass, const char *, const char *);
- void JCL_print_buffer(JNIEnv *, struct JCL_buffer *);
- int JCL_init_buffer(JNIEnv *, struct JCL_buffer *, jobject);
- void JCL_release_buffer(JNIEnv *, struct JCL_buffer *, jobject, jint);
- void JCL_cleanup_buffers(JNIEnv *, struct JCL_buffer *, jint, jobjectArray, jint, jlong);
- int JCL_thread_interrupted(JNIEnv *);
- static jfieldID address_fid;
- static jmethodID get_position_mid;
- static jmethodID set_position_mid;
- static jmethodID get_limit_mid;
- static jmethodID set_limit_mid;
- static jmethodID has_array_mid;
- static jmethodID array_mid;
- static jmethodID array_offset_mid;
- static jmethodID thread_interrupted_mid;
- static jclass vm_channel_class;
- jmethodID
- get_method_id(JNIEnv *env, jclass clazz, const char *name,
- const char *sig)
- {
- jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig);
- /* NIODBG("name: %s; sig: %s", name, sig); */
- if (mid == NULL)
- {
- JCL_ThrowException(env, "java/lang/InternalError", name);
- return NULL;
- }
-
- return mid;
- }
- inline void
- JCL_print_buffer(JNIEnv *env __attribute__((__unused__)), struct JCL_buffer *buf)
- {
- fprintf (stderr, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr);
- }
- int
- JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
- {
- void *addr = (*env)->GetDirectBufferAddress (env, bbuf);
- /* NIODBG("buf: %p; bbuf: %p; addr: %p", (void *) buf, bbuf, addr); */
-
- buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid);
- buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid);
- buf->offset = 0;
- buf->count = 0;
- buf->type = UNKNOWN;
-
- if (addr != NULL)
- {
- buf->ptr = (jbyte *) addr;
- buf->type = DIRECT;
- }
- else
- {
- jboolean has_array;
- has_array = (*env)->CallBooleanMethod(env, bbuf, has_array_mid);
-
- if (has_array == JNI_TRUE)
- {
- jbyteArray arr;
- buf->offset = (*env)->CallIntMethod(env, bbuf, array_offset_mid);
- arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
- buf->ptr = (*env)->GetByteArrayElements(env, arr, 0);
- buf->type = ARRAY;
- (*env)->DeleteLocalRef(env, arr);
- }
- else
- {
- jobject address = (*env)->GetObjectField (env, bbuf, address_fid);
- if (address == NULL)
- return -1; /* XXX handle non-array, non-native buffers? */
- buf->ptr = (jbyte *) JCL_GetRawData(env, address);
- buf->type = HEAP;
- (*env)->DeleteLocalRef(env, address);
- }
- }
-
- return 0;
- }
- void
- JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf,
- jint action)
- {
- jbyteArray arr;
- /* NIODBG("buf: %p; bbuf: %p; action: %x", (void *) buf, bbuf, action); */
-
- /* Set the position to the appropriate value */
- if (buf->count > 0)
- {
- jobject bbufTemp;
- bbufTemp = (*env)->CallObjectMethod(env, bbuf, set_position_mid,
- buf->position + buf->count);
- (*env)->DeleteLocalRef(env, bbufTemp);
- }
-
- switch (buf->type)
- {
- case DIRECT:
- case HEAP:
- break;
- case ARRAY:
- arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
- (*env)->ReleaseByteArrayElements(env, arr, buf->ptr, action);
- (*env)->DeleteLocalRef(env, arr);
- break;
- case UNKNOWN:
- /* TODO: Handle buffers that are not direct or array backed */
- break;
- }
- }
- void
- JCL_cleanup_buffers(JNIEnv *env,
- struct JCL_buffer *bi_list,
- jint vec_len,
- jobjectArray bbufs,
- jint offset,
- jlong num_bytes)
- {
- jint i;
- /* NIODBG("bi_list: %p; vec_len: %d; bbufs: %p; offset: %d; num_bytes: %lld", */
- /* (void *) bi_list, vec_len, bbufs, offset, num_bytes); */
-
- /* Update all of the bbufs with the approriate information */
- for (i = 0; i < vec_len; i++)
- {
- struct JCL_buffer* buf;
- jobject bbuf;
-
- buf = &bi_list[i];
- bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
- if (num_bytes > (buf->limit - buf->position))
- buf->count = (buf->limit - buf->position);
- else
- buf->count = num_bytes;
-
- num_bytes -= buf->count;
-
- JCL_release_buffer(env, buf, bbuf, JNI_ABORT);
- (*env)->DeleteLocalRef(env, bbuf);
- }
- }
- int
- JCL_thread_interrupted(JNIEnv *env)
- {
- return (int) (*env)->CallStaticBooleanMethod(env, vm_channel_class,
- thread_interrupted_mid);
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: stdin_fd
- * Signature: ()I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_stdin_1fd (JNIEnv *env __attribute__((unused)),
- jclass c __attribute__((unused)))
- {
- /* NIODBG("%d", fileno (stdin)); */
- return fileno (stdin);
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: stdout_fd
- * Signature: ()I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_stdout_1fd (JNIEnv *env __attribute__((unused)),
- jclass c __attribute__((unused)))
- {
- /* NIODBG("%d", fileno (stdout)); */
- return fileno (stdout);
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: stderr_fd
- * Signature: ()I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_stderr_1fd (JNIEnv *env __attribute__((unused)),
- jclass c __attribute__((unused)))
- {
- /* NIODBG("%d", fileno (stderr)); */
- return fileno (stderr);
- }
- JNIEXPORT void JNICALL
- Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env,
- jclass clazz)
- {
- jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer");
- jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer");
- /* NIODBG("%s", "..."); */
- address_fid = (*env)->GetFieldID(env, bufferClass, "address",
- "Lgnu/classpath/Pointer;");
- if (address_fid == NULL)
- {
- JCL_ThrowException(env, "java/lang/InternalError",
- "Unable to find internal field");
- return;
- }
-
- get_position_mid = get_method_id(env, bufferClass, "position", "()I");
- set_position_mid = get_method_id(env, bufferClass, "position",
- "(I)Ljava/nio/Buffer;");
- get_limit_mid = get_method_id(env, bufferClass, "limit", "()I");
- set_limit_mid = get_method_id(env, bufferClass, "limit",
- "(I)Ljava/nio/Buffer;");
- has_array_mid = get_method_id(env, byteBufferClass, "hasArray", "()Z");
- array_mid = get_method_id(env, byteBufferClass, "array", "()[B");
- array_offset_mid = get_method_id(env, byteBufferClass, "arrayOffset", "()I");
-
- vm_channel_class = clazz;
- thread_interrupted_mid = (*env)->GetStaticMethodID(env, clazz,
- "isThreadInterrupted",
- "()Z");
- }
- JNIEXPORT void JNICALL
- Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env,
- jobject o __attribute__ ((__unused__)),
- jint fd,
- jboolean blocking)
- {
- int opts;
-
- /* NIODBG("fd: %d; blocking: %d", fd, blocking); */
- opts = fcntl(fd, F_GETFL);
- if (opts < 0)
- {
- JCL_ThrowException(env, IO_EXCEPTION,
- "Failed to get flags for file desriptor");
- return;
- }
-
- if (blocking == JNI_TRUE)
- opts &= ~(O_NONBLOCK);
- else
- opts |= O_NONBLOCK;
-
- opts = fcntl(fd, F_SETFL, opts);
-
- if (opts < 0)
- {
- JCL_ThrowException(env, IO_EXCEPTION,
- "Failed to set flags for file desriptor");
- return;
- }
- }
- /* Return true if fd is in non-blocking mode. */
- static jboolean
- is_non_blocking_fd(jint fd)
- {
- int opts;
- opts = fcntl(fd, F_GETFL);
- if (opts == -1)
- {
- /* Assume blocking on error. */
- return 0;
- }
- return (opts & O_NONBLOCK) != 0;
- }
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
- jobject o __attribute__ ((__unused__)),
- jint fd,
- jobject bbuf)
- {
- #ifdef HAVE_READ
- jint len;
- ssize_t result;
- struct JCL_buffer buf;
- int tmp_errno;
- /* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
-
- if (JCL_init_buffer(env, &buf, bbuf) < 0)
- {
- /* TODO: Rethrown exception */
- JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
- return -1;
- }
- len = buf.limit - buf.position;
- if (len == 0)
- {
- JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
- return 0;
- }
-
- do
- {
- result = cpnio_read (fd, &(buf.ptr[buf.position + buf.offset]), len);
- tmp_errno = errno;
- }
- while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
- errno = tmp_errno;
-
- if (result == 0)
- {
- result = -1;
- buf.count = 0;
- }
- else if (result == -1)
- {
- buf.count = 0;
- if (errno == EAGAIN)
- {
- if (is_non_blocking_fd(fd))
- {
- /* Non-blocking */
- result = 0;
- }
- else
- {
- /* Read timeout on a socket with SO_RCVTIMEO != 0. */
- JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
- JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
- return -1;
- }
- }
- else if (errno == EBADF) /* Bad fd */
- {
- JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
- JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
- strerror(errno));
- return -1;
- }
- else if (EINTR == errno) /* read interrupted */
- {
- JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
- JCL_ThrowException(env, INTERRUPTED_IO_EXCEPTION, strerror (errno));
- return -1;
- }
- else
- {
- JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
- JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
- return -1;
- }
- }
- else
- buf.count = result;
-
- JCL_release_buffer(env, &buf, bbuf, 0);
-
- return result;
- #else
- (void) fd;
- (void) bbuf;
- JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
- return -1;
- #endif /* HAVE_READ */
- }
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
- jobject o __attribute__ ((__unused__)),
- jint fd,
- jobject bbuf)
- {
- #ifdef HAVE_WRITE
- jint len;
- ssize_t result;
- struct JCL_buffer buf;
- int tmp_errno;
- /* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
-
- if (JCL_init_buffer(env, &buf, bbuf) < 0)
- {
- /* TODO: Rethrown exception */
- JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
- return -1;
- }
- len = buf.limit - buf.position;
- if (len == 0)
- {
- JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
- return 0;
- }
-
- do
- {
- result = cpnio_write (fd, &(buf.ptr[buf.position + buf.offset]), len);
- tmp_errno = errno;
- }
- while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
- errno = tmp_errno;
- buf.count = result;
- if (result == -1)
- {
- if (errno == EAGAIN) /* Non-blocking */
- {
- result = 0;
- }
- else
- {
- JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
- JCL_ThrowException(env, IO_EXCEPTION, strerror(errno));
- return -1;
- }
- }
-
- JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
-
- return result;
- #else
- (void) fd;
- (void) bbuf;
- JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
- return -1;
- #endif /* HAVE_WRITE */
- }
- /*
- * Implementation of a scattering read. Will use the appropriate
- * vector based read call (currently readv on Linux).
- *
- * This has a limit to the number of buffers that will be read. It
- * will not make muliple readv calls. This is to ensure that operations
- * are atomic. Currently it is limited to 16 buffers. This is for
- * compatibiliy with Sun.
- */
- JNIEXPORT jlong JNICALL
- Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env,
- jobject o __attribute__ ((__unused__)),
- jint fd,
- jobjectArray bbufs,
- jint offset,
- jint length)
- {
- jint i;
- /* jboolean is_error = JNI_FALSE; */
- /* char *error_msg; */
- struct iovec buffers[JCL_IOV_MAX];
- struct JCL_buffer bi_list[JCL_IOV_MAX];
- ssize_t result;
- jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
- jlong bytes_read = 0;
- int tmp_errno;
- /* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
- /* fd, bbufs, offset, length); */
-
- /* Build the vector of buffers to read into */
- for (i = 0; i < vec_len; i++)
- {
- struct JCL_buffer* buf;
- jobject bbuf;
-
- buf = &bi_list[i];
- bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
-
- JCL_init_buffer(env, buf, bbuf);
- /* JCL_print_buffer (env, buf); */
-
- buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
- buffers[i].iov_len = buf->limit - buf->position;
- (*env)->DeleteLocalRef(env, bbuf);
- }
-
- /* Work the scattering magic */
- do
- {
- result = cpnio_readv (fd, buffers, vec_len);
- tmp_errno = errno;
- }
- while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
- errno = tmp_errno;
- bytes_read = (jlong) result;
-
- /* Handle the response */
- if (result < 0)
- {
- if (errno == EAGAIN)
- {
- if (is_non_blocking_fd(fd))
- {
- /* Non-blocking */
- result = 0;
- }
- else
- {
- /* Read timeout on a socket with SO_RCVTIMEO != 0. */
- JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
- JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
- return -1;
- }
- }
- else if (errno == EBADF) /* Bad fd */
- {
- JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
- JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
- strerror(errno));
- return -1;
- }
- else
- {
- JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
- JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
- return -1;
- }
- bytes_read = 0;
- }
- else if (result == 0) /* EOF */
- {
- result = -1;
- }
-
- JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
-
- return (jlong) result;
- }
- /*
- * Implementation of a gathering write. Will use the appropriate
- * vector based read call (currently readv on Linux).
- *
- * This has a limit to the number of buffers that will be read. It
- * will not make muliple readv calls. This is to ensure that operations
- * are atomic. Currently it is limited to 16 buffers. This is for
- * compatibiliy with Sun.
- */
- JNIEXPORT jlong JNICALL
- Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env,
- jobject o __attribute__ ((__unused__)),
- jint fd,
- jobjectArray bbufs,
- jint offset,
- jint length)
- {
- int i;
- /* jboolean is_error = JNI_FALSE; */
- /* char *error_msg; */
- struct iovec buffers[JCL_IOV_MAX];
- struct JCL_buffer bi_list[JCL_IOV_MAX];
- ssize_t result;
- jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
- jlong bytes_written;
- int tmp_errno;
-
- /* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
- /* fd, bbufs, offset, length); */
-
- /* Build the vector of buffers to read into */
- for (i = 0; i < vec_len; i++)
- {
- struct JCL_buffer* buf;
- jobject bbuf;
-
- buf = &bi_list[i];
- bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
-
- JCL_init_buffer(env, buf, bbuf);
-
- /* JCL_print_buffer(env, buf); */
- buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
- buffers[i].iov_len = buf->limit - buf->position;
- (*env)->DeleteLocalRef(env, bbuf);
- }
-
- /* Work the gathering magic */
- do
- {
- result = cpnio_writev (fd, buffers, vec_len);
- tmp_errno = errno;
- }
- while (result == -1 && tmp_errno == EINTR && ! JCL_thread_interrupted(env));
- errno = tmp_errno;
- bytes_written = (jlong) result;
- if (result < 0)
- {
- bytes_written = 0;
- if (errno == EAGAIN) /* Non blocking */
- result = 0;
- else if (errno == EBADF) /* Bad fd */
- {
- JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
- bytes_written);
- JCL_ThrowException (env, NON_WRITABLE_CHANNEL_EXCEPTION,
- strerror(errno));
- return -1;
- }
- else
- {
- JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
- bytes_written);
- JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
- return -1;
- }
- }
- else if (result == 0) /* EOF?? Does this happen on a write */
- result = -1;
-
- JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_written);
- return (jlong) result;
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: receive
- * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_receive (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd, jobject dst, jobject addrPort)
- {
- #ifdef HAVE_RECVFROM
- char *addrPortPtr = (*env)->GetDirectBufferAddress (env, addrPort);
- struct JCL_buffer buf;
- #ifdef HAVE_INET6
- struct sockaddr_in6 sock_storage;
- struct sockaddr_in6 *sock6;
- socklen_t slen = sizeof (struct sockaddr_in6);
- #else
- struct sockaddr_in sock_storage;
- socklen_t slen = sizeof (struct sockaddr_in);
- #endif /* HAVE_INET6 */
- struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
- struct sockaddr_in *sock4;
- int ret;
- jint result = -1;
- if (JCL_init_buffer (env, &buf, dst) == -1)
- JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
- #ifndef HAVE_MSG_WAITALL
- #define MSG_WAITALL 0
- #endif
- ret = cpnio_recvfrom (fd, &(buf.ptr[buf.position + buf.offset]),
- buf.limit - buf.position, MSG_WAITALL,
- sockaddr, &slen);
- if (-1 == ret)
- {
- JCL_release_buffer (env, &buf, dst, JNI_ABORT);
- if (EINTR == errno)
- JCL_ThrowException (env, "java/io/InterruptedIOException", strerror (errno));
- else if (EAGAIN == errno)
- {
- /* If the socket is in blocking mode, our timeout expired. */
- int val = fcntl (fd, F_GETFL, 0);
- if (val == -1)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- else if ((val & O_NONBLOCK) == 0)
- JCL_ThrowException (env, "java/net/SocketTimeoutException",
- "read timed out");
- }
- else
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return 0;
- }
- if (sockaddr->sa_family == AF_INET)
- {
- sock4 = (struct sockaddr_in *) sockaddr;
- memcpy (addrPortPtr, &(sock4->sin_addr.s_addr), 4);
- ;memcpy (addrPortPtr + 4, &(sock4->sin_port), 2);
- result = 4;
- }
- #ifdef HAVE_INET6
- else if (sockaddr->sa_family == AF_INET6)
- {
- sock6 = (struct sockaddr_in6 *) sockaddr;
- memcpy (addrPortPtr, &(sock6->sin6_addr.s6_addr), 16);
- memcpy (addrPortPtr + 16, &(sock6->sin6_port), 2);
- result = 16;
- }
- #endif /* HAVE_INET6 */
- else if (ret == 0)
- {
- result = 0;
- }
- else
- {
- JCL_ThrowException (env, "java/net/SocketException",
- "unsupported address type returned");
- }
- buf.count += ret;
- JCL_release_buffer (env, &buf, dst, 0);
- return result;
- #else
- (void) fd;
- (void) dst;
- (void) addrPort;
- JCL_ThrowException (env, IO_EXCEPTION, "recvfrom not supported");
- #endif /* HAVE_RECVFROM */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: send
- * Signature: (Ljava/nio/ByteBuffer;[BI)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_send (JNIEnv *env,
- jclass c __attribute__((unused)),
- int fd, jobject src, jbyteArray addr, jint port)
- {
- #ifdef HAVE_SENDTO
- struct sockaddr_in sockaddr;
- jbyte *elems;
- struct JCL_buffer buf;
- int ret;
- /* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
- /* fd, src, addr, port); */
- if (JCL_init_buffer (env, &buf, src) == -1)
- {
- JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
- return -1;
- }
- /* JCL_print_buffer (env, &buf); */
- elems = (*env)->GetByteArrayElements (env, addr, NULL);
- sockaddr.sin_family = AF_INET;
- sockaddr.sin_addr.s_addr = *((uint32_t *) elems);
- sockaddr.sin_port = htons (port);
- do
- {
- ret = cpnio_sendto (fd, &(buf.ptr[buf.position + buf.offset]),
- buf.limit - buf.position,
- 0, (const struct sockaddr *) &sockaddr,
- sizeof (struct sockaddr_in));
- }
- while (-1 == ret && EINTR == errno);
- (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
- if (-1 == ret)
- {
- if (errno != EAGAIN)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- JCL_release_buffer (env, &buf, src, JNI_ABORT);
- return 0;
- }
- buf.count += ret;
- JCL_release_buffer (env, &buf, src, JNI_ABORT);
- return ret;
- #else
- (void) fd;
- (void) src;
- (void) addr;
- (void) port;
- #endif /* HAVE_SENDTO */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: send6
- * Signature: (Ljava/nio/ByteBuffer;[BI)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_send6 (JNIEnv *env,
- jclass c __attribute__((unused)),
- int fd, jobject src, jbyteArray addr, jint port)
- {
- #if defined(HAVE_SENDTO) && defined(HAVE_INET6)
- struct sockaddr_in6 sockaddr;
- jbyte *elems;
- struct JCL_buffer buf;
- int ret;
- /* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
- /* fd, src, addr, port); */
- if (JCL_init_buffer (env, &buf, src) == -1)
- {
- JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
- return -1;
- }
- /* JCL_print_buffer (env, &buf); */
- elems = (*env)->GetByteArrayElements (env, addr, NULL);
- sockaddr.sin6_family = AF_INET6;
- memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16);
- sockaddr.sin6_port = htons (port);
- do
- {
- ret = cpnio_sendto (fd, (const void *) (buf.ptr + buf.offset),
- buf.limit - buf.position,
- 0, (const struct sockaddr *) &sockaddr,
- sizeof (struct sockaddr_in6));
- }
- while (-1 == ret && EINTR == errno);
- (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
- if (-1 == ret)
- {
- if (errno != EAGAIN)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- JCL_release_buffer (env, &buf, src, JNI_ABORT);
- return 0;
- }
- buf.count += ret;
- JCL_release_buffer (env, &buf, src, JNI_ABORT);
- return ret;
- #else
- (void) fd;
- (void) src;
- (void) addr;
- (void) port;
- JCL_ThrowException (env, IO_EXCEPTION, "IPv6 sendto not supported");
- return -1;
- #endif /* HAVE_SENDTO && HAVE_INET6 */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: read
- * Signature: (I)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_read__I (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd)
- {
- #ifdef HAVE_READ
- char in;
- int ret;
- int tmp_errno;
- /* NIODBG("fd: %d", fd); */
- do
- {
- ret = cpnio_read (fd, &in, 1);
- tmp_errno = errno;
- }
- while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
- errno = tmp_errno;
- if (-1 == ret)
- {
- if (errno == EAGAIN && !is_non_blocking_fd(fd))
- {
- /* Read timeout on a socket with SO_RCVTIMEO != 0. */
- JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
- }
- else
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return -1;
- }
-
- if (0 == ret)
- return -1;
- return (in & 0xFF);
- #else
- (void) fd;
- JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
- #endif /* HAVE_READ */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: write
- * Signature: (I)V
- */
- JNIEXPORT void JNICALL
- Java_gnu_java_nio_VMChannel_write__II (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd, jint data)
- {
- #ifdef HAVE_WRITE
- char out = (char) data;
- int ret;
- int tmp_errno;
- /* NIODBG("fd: %d; data: %d", fd, data); */
- do
- {
- ret = cpnio_write (fd, &out, 1);
- tmp_errno = errno;
- }
- while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
- errno = tmp_errno;
- if (-1 == ret)
- JCL_ThrowException(env, IO_EXCEPTION, strerror (errno));
- #else
- (void) fd;
- (void) data;
- JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
- #endif /* HAVE_WRITE */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: socket
- * Signature: (Z)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_socket (JNIEnv *env, jclass clazz __attribute__((unused)),
- jboolean stream)
- {
- #ifdef HAVE_SOCKET
- int ret;
- do
- {
- ret = cpnio_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
- }
- while (-1 == ret && EINTR == errno);
- if (ret == -1)
- JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
- /* NIODBG("created socket %d", ret); */
- return ret;
- #else
- (void) stream;
- JCL_ThrowException (env, IO_EXCEPTION, "socket not supported");
- return -1;
- #endif /* HAVE_SOCKET */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: connect
- * Signature: (I[BI)Z
- */
- JNIEXPORT jboolean JNICALL
- Java_gnu_java_nio_VMChannel_connect (JNIEnv *env, jclass clazz __attribute__((unused)),
- jint fd, jbyteArray addr, jint port, jint timeout)
- {
- #ifdef HAVE_CONNECT
- struct sockaddr_in sockaddr;
- struct timeval timeo;
- int origflags = 0, flags;
- jbyte *addr_elems;
- int ret;
- int tmpErrno;
- if ((*env)->GetArrayLength (env, addr) != 4)
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION,
- "expecting 4-byte address");
- return JNI_FALSE;
- }
- if (timeout > 0)
- {
- timeo.tv_sec = timeout / 1000;
- timeo.tv_usec = (timeout % 1000) * 1000;
- origflags = fcntl (fd, F_GETFL, 0);
- if (origflags == -1)
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- /* Set nonblocking mode, if not already set. */
- if (!(origflags & O_NONBLOCK))
- {
- flags = origflags | O_NONBLOCK;
- if (fcntl (fd, F_SETFL, flags) == -1)
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- }
- }
- addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
- memset (&sockaddr, 0, sizeof (struct sockaddr_in));
- sockaddr.sin_family = AF_INET;
- sockaddr.sin_port = htons (port);
- sockaddr.sin_addr.s_addr = *((uint32_t *) addr_elems);
- do
- {
- ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
- sizeof (struct sockaddr_in));
- tmpErrno = errno;
- }
- while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
- errno = tmpErrno;
- (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
- /* If a timeout was specified, select on the file descriptor with
- the timeout. */
- if (timeout > 0 && ret == -1)
- {
- /* Reset the non-blocking flag, if needed. */
- if (!(origflags & O_NONBLOCK))
- {
- if (fcntl (fd, F_SETFL, origflags) == -1)
- {
- /* oops */
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- }
- if (EINPROGRESS == errno)
- {
- fd_set wrfds;
- FD_ZERO(&wrfds);
- FD_SET(fd, &wrfds);
- ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
- if (ret == -1)
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- if (ret == 0) /* connect timed out */
- {
- JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
- "connect timed out");
- return JNI_FALSE;
- }
- return JNI_TRUE; /* Connected! */
- }
- else if (ECONNREFUSED == errno)
- {
- JCL_ThrowException (env, CONNECT_EXCEPTION,
- strerror (errno));
- return JNI_FALSE;
- }
- else
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- }
- if (ret == -1)
- {
- if (EINPROGRESS == errno)
- return JNI_FALSE;
- else if (ECONNREFUSED == errno)
- {
- JCL_ThrowException (env, CONNECT_EXCEPTION,
- strerror (errno));
- return JNI_FALSE;
- }
- else
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- }
- return JNI_TRUE;
- #else
- (void) fd;
- (void) addr;
- (void) port;
- (void) timeout;
- JCL_ThrowException (env, SOCKET_EXCEPTION, "connect not supported");
- return JNI_FALSE;
- #endif /* HAVE_CONNECT */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: connect6
- * Signature: (I[BI)Z
- */
- JNIEXPORT jboolean JNICALL
- Java_gnu_java_nio_VMChannel_connect6 (JNIEnv *env, jclass clazz __attribute__((unused)),
- jint fd, jbyteArray addr, jint port, int timeout)
- {
- #if defined(HAVE_CONNECT) && defined(HAVE_INET6)
- struct sockaddr_in6 sockaddr;
- struct timeval timeo;
- int flags, origflags = 0;
- jbyte *addr_elems;
- int ret;
- if (timeout > 0)
- {
- timeo.tv_sec = timeout / 1000;
- timeo.tv_usec = (timeout % 1000) * 1000;
- origflags = fcntl (fd, F_GETFL, 0);
- if (origflags == -1)
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- /* Set nonblocking mode, if not already set. */
- if (!(origflags & O_NONBLOCK))
- {
- flags = origflags | O_NONBLOCK;
- if (fcntl (fd, F_SETFL, flags) == -1)
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- }
- }
- addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
- memset (&sockaddr, 0, sizeof (struct sockaddr_in6));
- sockaddr.sin6_family = AF_INET6;
- sockaddr.sin6_port = htons (port);
- memcpy (&sockaddr.sin6_addr.s6_addr, addr_elems, 16);
- ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
- sizeof (struct sockaddr_in6));
- (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
- /* If a timeout was specified, select on the file descriptor with
- the timeout. */
- if (timeout > 0 && ret == -1)
- {
- /* Reset the non-blocking flag, if needed. */
- if (!(origflags & O_NONBLOCK))
- {
- if (fcntl (fd, F_SETFL, origflags) == -1)
- {
- /* oops */
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- }
- if (EINPROGRESS == errno)
- {
- fd_set wrfds;
- FD_ZERO(&wrfds);
- FD_SET(fd, &wrfds);
- ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
- if (ret == -1)
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- if (ret == 0) /* connect timed out */
- {
- JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
- "connect timed out");
- return JNI_FALSE;
- }
- return JNI_TRUE; /* Connected! */
- }
- else if (ECONNREFUSED == errno)
- {
- JCL_ThrowException (env, CONNECT_EXCEPTION,
- strerror (errno));
- return JNI_FALSE;
- }
- else
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- }
- if (ret == -1)
- {
- if (EAGAIN == errno)
- return JNI_FALSE;
- else if (ECONNREFUSED == errno)
- {
- JCL_ThrowException (env, CONNECT_EXCEPTION,
- strerror (errno));
- return JNI_FALSE;
- }
- else
- {
- JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- }
- return JNI_TRUE;
- #else
- (void) fd;
- (void) addr;
- (void) port;
- (void) timeout;
- JCL_ThrowException (env, SOCKET_EXCEPTION, "IPv6 connect not supported");
- return JNI_FALSE;
- #endif /* HAVE_CONNECT && HAVE_INET6 */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: getsockname
- * Signature: (ILjava/nio/ByteBuffer;)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_getsockname (JNIEnv *env, jclass clazz __attribute__((unused)),
- jint fd, jobject name)
- {
- #ifdef HAVE_GETSOCKNAME
- #ifdef HAVE_INET6
- struct sockaddr_in6 *addr6;
- struct sockaddr_in6 sock_storage;
- socklen_t socklen = sizeof (struct sockaddr_in6);
- #else
- struct sockaddr_in sock_storage;
- socklen_t socklen = sizeof (struct sockaddr_in);
- #endif /* HAVE_INET6 */
- struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
- struct sockaddr_in *addr4;
- int ret;
- char *nameptr = (*env)->GetDirectBufferAddress (env, name);
- ret = getsockname (fd, sockaddr, &socklen);
- if (ret == -1)
- {
- JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
- return 0;
- }
- if (sockaddr->sa_family == AF_INET)
- {
- addr4 = (struct sockaddr_in *) sockaddr;
- memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
- memcpy (nameptr + 4, &(addr4->sin_port), 2);
- return 4;
- }
- #ifdef HAVE_INET6
- /* IPv6 */
- if (sockaddr->sa_family == AF_INET6)
- {
- addr6 = (struct sockaddr_in6 *) sockaddr;
- memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
- memcpy (nameptr + 16, &(addr6->sin6_port), 2);
- return 16;
- }
- #endif /* HAVE_INET6 */
- JCL_ThrowException (env, IO_EXCEPTION, "unsupported address format");
- return -1;
- #else
- (void) fd;
- (void) name;
- JCL_ThrowException (env, IO_EXCEPTION, "getsockname not supported");
- return -1;
- #endif /* HAVE_GETSOCKNAME */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: getpeername
- * Signature: (ILjava/nio/ByteBuffer;)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_getpeername (JNIEnv *env, jclass clazz __attribute__((unused)),
- jint fd, jobject name)
- {
- #ifdef HAVE_GETPEERNAME
- #ifdef HAVE_INET6
- struct sockaddr_in6 *addr6;
- struct sockaddr_in6 sock_storage;
- socklen_t socklen = sizeof (struct sockaddr_in6);
- #else
- struct sockaddr_in sock_storage;
- socklen_t socklen = sizeof (struct sockaddr_in);
- #endif /* HAVE_INET6 */
- struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
- struct sockaddr_in *addr4;
- int ret;
- char *nameptr = (*env)->GetDirectBufferAddress (env, name);
-
- ret = getpeername (fd, sockaddr, &socklen);
- if (ret == -1)
- {
- if (ENOTCONN != errno)
- JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
- return 0;
- }
- if (sockaddr->sa_family == AF_INET)
- {
- addr4 = (struct sockaddr_in *) sockaddr;
- memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
- memcpy (nameptr + 4, &(addr4->sin_port), 2);
- return 4;
- }
- #ifdef HAVE_INET6
- else if (sockaddr->sa_family == AF_INET6)
- {
- addr6 = (struct sockaddr_in6 *) sockaddr;
- memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
- memcpy (nameptr + 16, &(addr6->sin6_port), 2);
- return 16;
- }
- #endif /* HAVE_INET6 */
- JCL_ThrowException (env, "java/net/SocketException",
- "unsupported address type");
- return -1;
- #else
- (void) fd;
- (void) name;
- JCL_ThrowException (env, IO_EXCEPTION, "getpeername not supported");
- return -1;
- #endif /* HAVE_GETPEERNAME */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: accept
- * Signature: (I)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_accept (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd)
- {
- #ifdef HAVE_ACCEPT
- int ret;
- int tmp_errno = 0;
- #ifdef HAVE_INET6
- struct sockaddr_in6 addr;
- socklen_t alen = sizeof (struct sockaddr_in6);
- #else
- struct sockaddr_in addr;
- socklen_t alen = sizeof (struct sockaddr_in);
- #endif /* HAVE_INET6 */
- do
- {
- ret = cpnio_accept (fd, (struct sockaddr *) &addr, &alen);
- tmp_errno = errno;
-
- if (ret == -1)
- switch (tmp_errno)
- {
- case EINTR:
- /* Check if interrupted by Thread.interrupt(). If not then some
- * other unrelated signal interrupted the system function and
- * we should start over again.
- */
- if (JCL_thread_interrupted(env))
- {
- JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
- return -1;
- }
- break;
- #if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
- #endif
- case EAGAIN:
- if (!is_non_blocking_fd(fd))
- {
- JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "Accept timed out");
- }
- /* Socket in non-blocking mode and no pending connection. */
- return -1;
- default:
- JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
- return -1;
- }
- else
- break;
- }
- while (1);
- cpio_closeOnExec(ret);
- return ret;
- #else
- (void) fd;
- JCL_ThrowException (env, IO_EXCEPTION, "accept not supported");
- return -1;
- #endif /* HAVE_ACCEPT */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: disconnect
- * Signature: (I)V
- */
- JNIEXPORT void JNICALL
- Java_gnu_java_nio_VMChannel_disconnect (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd)
- {
- struct sockaddr sockaddr;
- sockaddr.sa_family = AF_UNSPEC;
- if (connect (fd, &sockaddr, sizeof (struct sockaddr)) == -1)
- {
- /* The expected error for a successful disconnect is EAFNOSUPPORT. */
- if (errno != EAFNOSUPPORT)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- }
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: close
- * Signature: (I)V
- */
- JNIEXPORT void JNICALL
- Java_gnu_java_nio_VMChannel_close (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd)
- {
- if (close (fd) == -1)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: available
- * Signature: (I)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_available (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd)
- {
- #if defined (FIONREAD)
- jint avail = 0;
- #if defined(ENOTTY) && defined(HAVE_FSTAT)
- struct stat statBuffer;
- off_t n;
- #endif
- /* NIODBG("fd: %d", fd); */
- if (ioctl (fd, FIONREAD, &avail) == -1)
- {
- #if defined(ENOTTY) && defined(HAVE_FSTAT)
- if (errno == ENOTTY)
- {
- if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
- {
- n = lseek (fd, 0, SEEK_CUR);
- if (n != -1)
- {
- avail = statBuffer.st_size - n;
- return avail;
- }
- }
- }
- #endif
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- }
- /* NIODBG("avail: %d", avail); */
- return avail;
- #elif defined(HAVE_FSTAT)
- jint avail = 0;
- struct stat statBuffer;
- off_t n;
- if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
- {
- n = lseek (fd, 0, SEEK_CUR);
- if (n != -1)
- {
- avail = statBuffer.st_size - n;
- return avail;
- }
- }
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- #elif defined(HAVE_SELECT)
- jint avail = 0;
- fd_set filedescriptset;
- struct timeval tv;
- FD_ZERO (&filedescriptset);
- FD_SET (fd,&filedescriptset);
- memset (&tv, 0, sizeof(tv));
- switch (select (fd+1, &filedescriptset, NULL, NULL, &tv))
- {
- case -1:
- break;
- case 0:
- avail = 0;
- return avail;
- default:
- avail = 1;
- return avail;
- }
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- #else
- JCL_ThrowException (env, IO_EXCEPTION, "No native method for available");
- #endif
- }
- enum FileChannel_mode {
- CPNIO_READ = 1,
- CPNIO_WRITE = 2,
- CPNIO_APPEND = 4,
- CPNIO_EXCL = 8,
- CPNIO_SYNC = 16,
- CPNIO_DSYNC = 32
- };
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: open
- * Signature: (Ljava/lang/String;I)I
- */
- JNIEXPORT jint JNICALL
- Java_gnu_java_nio_VMChannel_open (JNIEnv *env,
- jclass c __attribute__((unused)),
- jstring path, jint mode)
- {
- int nmode = 0;
- int ret;
- const char *npath;
- if ((mode & CPNIO_READ) && (mode & CPNIO_WRITE))
- nmode = O_RDWR;
- else if (mode & CPNIO_WRITE)
- nmode = O_WRONLY;
- else
- nmode = O_RDONLY;
- nmode = (nmode
- | ((nmode == O_RDWR || nmode == O_WRONLY) ? O_CREAT : 0)
- | ((mode & CPNIO_APPEND) ? O_APPEND :
- ((nmode == O_WRONLY) ? O_TRUNC : 0))
- | ((mode & CPNIO_EXCL) ? O_EXCL : 0)
- | ((mode & CPNIO_SYNC) ? O_SYNC : 0));
- npath = JCL_jstring_to_cstring (env, path);
- /* NIODBG("path: %s; mode: %x", npath, nmode); */
- ret = open (npath, nmode, 0666);
- /* NIODBG("ret: %d\n", ret); */
- JCL_free_cstring (env, path, npath);
- if (-1 == ret)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return ret;
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: position
- * Signature: (I)J
- */
- JNIEXPORT jlong JNICALL
- Java_gnu_java_nio_VMChannel_position (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd)
- {
- #ifdef HAVE_LSEEK
- off_t ret;
- ret = lseek (fd, 0, SEEK_CUR);
- if (-1 == ret)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return (jlong) ret;
- #else
- JCL_ThrowException (env, IO_EXCEPTION, "position not supported");
- return -1;
- #endif /* HAVE_LSEEK */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: seek
- * Signature: (IJ)V
- */
- JNIEXPORT void JNICALL
- Java_gnu_java_nio_VMChannel_seek (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd, jlong pos)
- {
- #ifdef HAVE_LSEEK
- if (lseek (fd, (off_t) pos, SEEK_SET) == -1)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- #else
- JCL_ThrowException (env, IO_EXCEPTION, "seek not supported");
- #endif /* HAVE_LSEEK */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: truncate
- * Signature: (IJ)V
- */
- JNIEXPORT void JNICALL
- Java_gnu_java_nio_VMChannel_truncate (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd, jlong len)
- {
- #if defined(HAVE_FTRUNCATE) && defined(HAVE_LSEEK)
- off_t pos = lseek (fd, 0, SEEK_CUR);
- if (pos == -1)
- {
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return;
- }
- if (ftruncate (fd, (off_t) len) == -1)
- {
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return;
- }
- if (pos > len)
- {
- if (lseek (fd, len, SEEK_SET) == -1)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- }
- #else
- JCL_ThrowException (env, IO_EXCEPTION, "truncate not supported");
- #endif /* HAVE_FTRUNCATE && HAVE_LSEEK */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: lock
- * Signature: (IJJZZ)Z
- */
- JNIEXPORT jboolean JNICALL
- Java_gnu_java_nio_VMChannel_lock (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd, jlong pos, jlong len,
- jboolean shared, jboolean wait)
- {
- #if HAVE_FCNTL
- struct flock fl;
- fl.l_start = (off_t) pos;
- /* Long.MAX_VALUE means lock everything possible starting at pos. */
- if (len == 9223372036854775807LL)
- fl.l_len = 0;
- else
- fl.l_len = (off_t) len;
- fl.l_pid = getpid ();
- fl.l_type = (shared ? F_RDLCK : F_WRLCK);
- fl.l_whence = SEEK_SET;
- if (cpnio_fcntl (fd, (wait ? F_SETLKW : F_SETLK), (long) &fl) == -1)
- {
- if (errno != EAGAIN)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- return JNI_TRUE;
- #else
- JCL_ThrowException (env, IO_EXCEPTION, "lock not supported");
- return JNI_FALSE;
- #endif /* HAVE_FCNTL */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: unlock
- * Signature: (IJJ)V
- */
- JNIEXPORT void JNICALL
- Java_gnu_java_nio_VMChannel_unlock (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd, jlong pos, jlong len)
- {
- #if HAVE_FCNTL
- struct flock fl;
- fl.l_start = (off_t) pos;
- fl.l_len = (off_t) len;
- fl.l_pid = getpid ();
- fl.l_type = F_UNLCK;
- fl.l_whence = SEEK_SET;
- if (cpnio_fcntl (fd, F_SETLK, (long) &fl) == -1)
- {
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- }
- #else
- JCL_ThrowException (env, IO_EXCEPTION, "unlock not supported");
- #endif /* HAVE_FCNTL */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: size
- * Signature: (I)J
- */
- JNIEXPORT jlong JNICALL
- Java_gnu_java_nio_VMChannel_size (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd)
- {
- #ifdef HAVE_FSTAT
- struct stat st;
- if (fstat (fd, &st) == -1)
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return (jlong) st.st_size;
- #else
- JCL_ThrowException (env, IO_EXCEPTION, "size not supported");
- return 0;
- #endif
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: map
- * Signature: (ICJI)Lgnu/classpath/Pointer;
- */
- JNIEXPORT jobject JNICALL
- Java_gnu_java_nio_VMChannel_map (JNIEnv *env,
- jclass clazz __attribute__((unused)),
- jint fd, jchar mode, jlong position, jint size)
- {
- #ifdef HAVE_MMAP
- jclass MappedByteBufferImpl_class;
- jmethodID MappedByteBufferImpl_init = NULL;
- jobject Pointer_instance;
- volatile jobject buffer;
- long pagesize;
- int prot, flags;
- void *p;
- void *address;
- /* NIODBG("fd: %d; mode: %x; position: %lld; size: %d", */
- /* fd, mode, position, size); */
- /* FIXME: should we just assume we're on an OS modern enough to
- have 'sysconf'? And not check for 'getpagesize'? */
- #if defined(HAVE_GETPAGESIZE)
- pagesize = getpagesize ();
- #elif defined(HAVE_SYSCONF)
- pagesize = sysconf (_SC_PAGESIZE);
- #else
- JCL_ThrowException (env, IO_EXCEPTION,
- "can't determine memory page size");
- return NULL;
- #endif /* HAVE_GETPAGESIZE/HAVE_SYSCONF */
- if ((*env)->ExceptionOccurred (env))
- {
- return NULL;
- }
- prot = PROT_READ;
- if (mode == '+' || mode == 'c')
- {
- /* When writing we need to make sure the file is big enough,
- otherwise the result of mmap is undefined. */
- struct stat st;
- if (fstat (fd, &st) == -1)
- {
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return NULL;
- }
- if (position + size > st.st_size)
- {
- if (ftruncate(fd, position + size) == -1)
- {
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return NULL;
- }
- }
- prot |= PROT_WRITE;
- }
- flags = (mode == 'c' ? MAP_PRIVATE : MAP_SHARED);
- p = mmap (NULL, (size_t) ALIGN_UP (size, pagesize), prot, flags,
- fd, ALIGN_DOWN (position, pagesize));
- if (p == MAP_FAILED)
- {
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return NULL;
- }
- /* Unalign the mapped value back up, since we aligned offset
- down to a multiple of the page size. */
- address = (void *) ((char *) p + (position % pagesize));
- Pointer_instance = JCL_NewRawDataObject(env, address);
- MappedByteBufferImpl_class = (*env)->FindClass (env,
- "java/nio/MappedByteBufferImpl");
- if (MappedByteBufferImpl_class != NULL)
- {
- MappedByteBufferImpl_init =
- (*env)->GetMethodID (env, MappedByteBufferImpl_class,
- "<init>", "(Lgnu/classpath/Pointer;IZ)V");
- }
- if ((*env)->ExceptionOccurred (env))
- {
- munmap (p, ALIGN_UP (size, pagesize));
- return NULL;
- }
- if (MappedByteBufferImpl_init == NULL)
- {
- JCL_ThrowException (env, "java/lang/InternalError",
- "could not get MappedByteBufferImpl constructor");
- munmap (p, ALIGN_UP (size, pagesize));
- return NULL;
- }
- buffer = (*env)->NewObject (env, MappedByteBufferImpl_class,
- MappedByteBufferImpl_init, Pointer_instance,
- (jint) size, mode == 'r');
- return buffer;
- #else
- (void) fd;
- (void) mode;
- (void) position;
- (void) size;
- JCL_ThrowException (env, IO_EXCEPTION,
- "memory-mapped files not implemented");
- return 0;
- #endif /* HAVE_MMAP */
- }
- /*
- * Class: gnu_java_nio_VMChannel
- * Method: flush
- * Signature: (IZ)Z
- */
- JNIEXPORT jboolean JNICALL
- Java_gnu_java_nio_VMChannel_flush (JNIEnv *env,
- jclass c __attribute__((unused)),
- jint fd, jboolean metadata __attribute__((unused)))
- {
- #ifdef HAVE_FSYNC
- /* XXX blocking? */
- if (fsync (fd) == -1)
- {
- JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
- return JNI_FALSE;
- }
- return JNI_TRUE;
- #else
- JCL_ThrowException (env, IO_EXCEPTION, "flush not implemented");
- return JNI_TRUE;
- #endif /* HAVE_FSYNC */
- }
- #ifdef __cplusplus
- }
- #endif
|