gnu_java_nio_VMChannel.c 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036
  1. /* gnu_java_nio_VMChannel.c -
  2. Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. #ifdef HAVE_CONFIG_H
  32. #include <config.h>
  33. #endif
  34. #include <config-int.h>
  35. #include <sys/types.h>
  36. #ifdef HAVE_SYS_MMAN_H
  37. #include <sys/mman.h>
  38. #endif
  39. #include <sys/socket.h>
  40. #include <sys/stat.h>
  41. #include <sys/uio.h>
  42. #include <netinet/in.h>
  43. #include <stdlib.h>
  44. #include <errno.h>
  45. #include <unistd.h>
  46. #include <string.h>
  47. #include <jni.h>
  48. #include <jcl.h>
  49. #include "cpio.h"
  50. #include "gnu_java_nio_VMChannel.h"
  51. #include "javanio.h"
  52. #ifdef HAVE_FCNTL_H
  53. #include <fcntl.h>
  54. #endif /* HAVE_FCNTL_H */
  55. #if defined(HAVE_SYS_IOCTL_H)
  56. #define BSD_COMP /* Get FIONREAD on Solaris2 */
  57. #include <sys/ioctl.h>
  58. #endif
  59. #if defined(HAVE_SYS_FILIO_H) /* Get FIONREAD on Solaris 2.5 */
  60. #include <sys/filio.h>
  61. #endif
  62. #define CONNECT_EXCEPTION "java/net/ConnectException"
  63. #define IO_EXCEPTION "java/io/IOException"
  64. #define SOCKET_EXCEPTION "java/net/SocketException"
  65. #define INTERRUPTED_IO_EXCEPTION "java/io/InterruptedIOException"
  66. #define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException"
  67. #define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException"
  68. #define SOCKET_TIMEOUT_EXCEPTION "java/net/SocketTimeoutException"
  69. /* Align a value up or down to a multiple of the pagesize. */
  70. #define ALIGN_DOWN(p,s) ((p) - ((p) % (s)))
  71. #define ALIGN_UP(p,s) ((p) + ((s) - ((p) % (s))))
  72. /*
  73. * Limit to maximum of 16 buffers
  74. */
  75. #define JCL_IOV_MAX 16
  76. #ifdef __cplusplus
  77. extern "C"
  78. {
  79. #endif
  80. enum JCL_buffer_type { DIRECT, HEAP, ARRAY, UNKNOWN };
  81. struct JCL_buffer
  82. {
  83. enum JCL_buffer_type type;
  84. jbyte *ptr;
  85. jint offset;
  86. jint position;
  87. jint limit;
  88. jint count;
  89. };
  90. jmethodID get_method_id(JNIEnv *, jclass, const char *, const char *);
  91. void JCL_print_buffer(JNIEnv *, struct JCL_buffer *);
  92. int JCL_init_buffer(JNIEnv *, struct JCL_buffer *, jobject);
  93. void JCL_release_buffer(JNIEnv *, struct JCL_buffer *, jobject, jint);
  94. void JCL_cleanup_buffers(JNIEnv *, struct JCL_buffer *, jint, jobjectArray, jint, jlong);
  95. int JCL_thread_interrupted(JNIEnv *);
  96. static jfieldID address_fid;
  97. static jmethodID get_position_mid;
  98. static jmethodID set_position_mid;
  99. static jmethodID get_limit_mid;
  100. static jmethodID set_limit_mid;
  101. static jmethodID has_array_mid;
  102. static jmethodID array_mid;
  103. static jmethodID array_offset_mid;
  104. static jmethodID thread_interrupted_mid;
  105. static jclass vm_channel_class;
  106. jmethodID
  107. get_method_id(JNIEnv *env, jclass clazz, const char *name,
  108. const char *sig)
  109. {
  110. jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig);
  111. /* NIODBG("name: %s; sig: %s", name, sig); */
  112. if (mid == NULL)
  113. {
  114. JCL_ThrowException(env, "java/lang/InternalError", name);
  115. return NULL;
  116. }
  117. return mid;
  118. }
  119. inline void
  120. JCL_print_buffer(JNIEnv *env __attribute__((__unused__)), struct JCL_buffer *buf)
  121. {
  122. fprintf (stderr, "Buffer - type: %d, ptr: %p\n", buf->type, buf->ptr);
  123. }
  124. int
  125. JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
  126. {
  127. void *addr = (*env)->GetDirectBufferAddress (env, bbuf);
  128. /* NIODBG("buf: %p; bbuf: %p; addr: %p", (void *) buf, bbuf, addr); */
  129. buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid);
  130. buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid);
  131. buf->offset = 0;
  132. buf->count = 0;
  133. buf->type = UNKNOWN;
  134. if (addr != NULL)
  135. {
  136. buf->ptr = (jbyte *) addr;
  137. buf->type = DIRECT;
  138. }
  139. else
  140. {
  141. jboolean has_array;
  142. has_array = (*env)->CallBooleanMethod(env, bbuf, has_array_mid);
  143. if (has_array == JNI_TRUE)
  144. {
  145. jbyteArray arr;
  146. buf->offset = (*env)->CallIntMethod(env, bbuf, array_offset_mid);
  147. arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
  148. buf->ptr = (*env)->GetByteArrayElements(env, arr, 0);
  149. buf->type = ARRAY;
  150. (*env)->DeleteLocalRef(env, arr);
  151. }
  152. else
  153. {
  154. jobject address = (*env)->GetObjectField (env, bbuf, address_fid);
  155. if (address == NULL)
  156. return -1; /* XXX handle non-array, non-native buffers? */
  157. buf->ptr = (jbyte *) JCL_GetRawData(env, address);
  158. buf->type = HEAP;
  159. (*env)->DeleteLocalRef(env, address);
  160. }
  161. }
  162. return 0;
  163. }
  164. void
  165. JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf,
  166. jint action)
  167. {
  168. jbyteArray arr;
  169. /* NIODBG("buf: %p; bbuf: %p; action: %x", (void *) buf, bbuf, action); */
  170. /* Set the position to the appropriate value */
  171. if (buf->count > 0)
  172. {
  173. jobject bbufTemp;
  174. bbufTemp = (*env)->CallObjectMethod(env, bbuf, set_position_mid,
  175. buf->position + buf->count);
  176. (*env)->DeleteLocalRef(env, bbufTemp);
  177. }
  178. switch (buf->type)
  179. {
  180. case DIRECT:
  181. case HEAP:
  182. break;
  183. case ARRAY:
  184. arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
  185. (*env)->ReleaseByteArrayElements(env, arr, buf->ptr, action);
  186. (*env)->DeleteLocalRef(env, arr);
  187. break;
  188. case UNKNOWN:
  189. /* TODO: Handle buffers that are not direct or array backed */
  190. break;
  191. }
  192. }
  193. void
  194. JCL_cleanup_buffers(JNIEnv *env,
  195. struct JCL_buffer *bi_list,
  196. jint vec_len,
  197. jobjectArray bbufs,
  198. jint offset,
  199. jlong num_bytes)
  200. {
  201. jint i;
  202. /* NIODBG("bi_list: %p; vec_len: %d; bbufs: %p; offset: %d; num_bytes: %lld", */
  203. /* (void *) bi_list, vec_len, bbufs, offset, num_bytes); */
  204. /* Update all of the bbufs with the approriate information */
  205. for (i = 0; i < vec_len; i++)
  206. {
  207. struct JCL_buffer* buf;
  208. jobject bbuf;
  209. buf = &bi_list[i];
  210. bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
  211. if (num_bytes > (buf->limit - buf->position))
  212. buf->count = (buf->limit - buf->position);
  213. else
  214. buf->count = num_bytes;
  215. num_bytes -= buf->count;
  216. JCL_release_buffer(env, buf, bbuf, JNI_ABORT);
  217. (*env)->DeleteLocalRef(env, bbuf);
  218. }
  219. }
  220. int
  221. JCL_thread_interrupted(JNIEnv *env)
  222. {
  223. return (int) (*env)->CallStaticBooleanMethod(env, vm_channel_class,
  224. thread_interrupted_mid);
  225. }
  226. /*
  227. * Class: gnu_java_nio_VMChannel
  228. * Method: stdin_fd
  229. * Signature: ()I
  230. */
  231. JNIEXPORT jint JNICALL
  232. Java_gnu_java_nio_VMChannel_stdin_1fd (JNIEnv *env __attribute__((unused)),
  233. jclass c __attribute__((unused)))
  234. {
  235. /* NIODBG("%d", fileno (stdin)); */
  236. return fileno (stdin);
  237. }
  238. /*
  239. * Class: gnu_java_nio_VMChannel
  240. * Method: stdout_fd
  241. * Signature: ()I
  242. */
  243. JNIEXPORT jint JNICALL
  244. Java_gnu_java_nio_VMChannel_stdout_1fd (JNIEnv *env __attribute__((unused)),
  245. jclass c __attribute__((unused)))
  246. {
  247. /* NIODBG("%d", fileno (stdout)); */
  248. return fileno (stdout);
  249. }
  250. /*
  251. * Class: gnu_java_nio_VMChannel
  252. * Method: stderr_fd
  253. * Signature: ()I
  254. */
  255. JNIEXPORT jint JNICALL
  256. Java_gnu_java_nio_VMChannel_stderr_1fd (JNIEnv *env __attribute__((unused)),
  257. jclass c __attribute__((unused)))
  258. {
  259. /* NIODBG("%d", fileno (stderr)); */
  260. return fileno (stderr);
  261. }
  262. JNIEXPORT void JNICALL
  263. Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env,
  264. jclass clazz)
  265. {
  266. jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer");
  267. jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer");
  268. /* NIODBG("%s", "..."); */
  269. address_fid = (*env)->GetFieldID(env, bufferClass, "address",
  270. "Lgnu/classpath/Pointer;");
  271. if (address_fid == NULL)
  272. {
  273. JCL_ThrowException(env, "java/lang/InternalError",
  274. "Unable to find internal field");
  275. return;
  276. }
  277. get_position_mid = get_method_id(env, bufferClass, "position", "()I");
  278. set_position_mid = get_method_id(env, bufferClass, "position",
  279. "(I)Ljava/nio/Buffer;");
  280. get_limit_mid = get_method_id(env, bufferClass, "limit", "()I");
  281. set_limit_mid = get_method_id(env, bufferClass, "limit",
  282. "(I)Ljava/nio/Buffer;");
  283. has_array_mid = get_method_id(env, byteBufferClass, "hasArray", "()Z");
  284. array_mid = get_method_id(env, byteBufferClass, "array", "()[B");
  285. array_offset_mid = get_method_id(env, byteBufferClass, "arrayOffset", "()I");
  286. vm_channel_class = clazz;
  287. thread_interrupted_mid = (*env)->GetStaticMethodID(env, clazz,
  288. "isThreadInterrupted",
  289. "()Z");
  290. }
  291. JNIEXPORT void JNICALL
  292. Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env,
  293. jobject o __attribute__ ((__unused__)),
  294. jint fd,
  295. jboolean blocking)
  296. {
  297. int opts;
  298. /* NIODBG("fd: %d; blocking: %d", fd, blocking); */
  299. opts = fcntl(fd, F_GETFL);
  300. if (opts < 0)
  301. {
  302. JCL_ThrowException(env, IO_EXCEPTION,
  303. "Failed to get flags for file desriptor");
  304. return;
  305. }
  306. if (blocking == JNI_TRUE)
  307. opts &= ~(O_NONBLOCK);
  308. else
  309. opts |= O_NONBLOCK;
  310. opts = fcntl(fd, F_SETFL, opts);
  311. if (opts < 0)
  312. {
  313. JCL_ThrowException(env, IO_EXCEPTION,
  314. "Failed to set flags for file desriptor");
  315. return;
  316. }
  317. }
  318. /* Return true if fd is in non-blocking mode. */
  319. static jboolean
  320. is_non_blocking_fd(jint fd)
  321. {
  322. int opts;
  323. opts = fcntl(fd, F_GETFL);
  324. if (opts == -1)
  325. {
  326. /* Assume blocking on error. */
  327. return 0;
  328. }
  329. return (opts & O_NONBLOCK) != 0;
  330. }
  331. JNIEXPORT jint JNICALL
  332. Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
  333. jobject o __attribute__ ((__unused__)),
  334. jint fd,
  335. jobject bbuf)
  336. {
  337. #ifdef HAVE_READ
  338. jint len;
  339. ssize_t result;
  340. struct JCL_buffer buf;
  341. int tmp_errno;
  342. /* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
  343. if (JCL_init_buffer(env, &buf, bbuf) < 0)
  344. {
  345. /* TODO: Rethrown exception */
  346. JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
  347. return -1;
  348. }
  349. len = buf.limit - buf.position;
  350. if (len == 0)
  351. {
  352. JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
  353. return 0;
  354. }
  355. do
  356. {
  357. result = cpnio_read (fd, &(buf.ptr[buf.position + buf.offset]), len);
  358. tmp_errno = errno;
  359. }
  360. while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
  361. errno = tmp_errno;
  362. if (result == 0)
  363. {
  364. result = -1;
  365. buf.count = 0;
  366. }
  367. else if (result == -1)
  368. {
  369. buf.count = 0;
  370. if (errno == EAGAIN)
  371. {
  372. if (is_non_blocking_fd(fd))
  373. {
  374. /* Non-blocking */
  375. result = 0;
  376. }
  377. else
  378. {
  379. /* Read timeout on a socket with SO_RCVTIMEO != 0. */
  380. JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
  381. JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
  382. return -1;
  383. }
  384. }
  385. else if (errno == EBADF) /* Bad fd */
  386. {
  387. JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
  388. JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
  389. strerror(errno));
  390. return -1;
  391. }
  392. else if (EINTR == errno) /* read interrupted */
  393. {
  394. JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
  395. JCL_ThrowException(env, INTERRUPTED_IO_EXCEPTION, strerror (errno));
  396. return -1;
  397. }
  398. else
  399. {
  400. JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
  401. JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
  402. return -1;
  403. }
  404. }
  405. else
  406. buf.count = result;
  407. JCL_release_buffer(env, &buf, bbuf, 0);
  408. return result;
  409. #else
  410. (void) fd;
  411. (void) bbuf;
  412. JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
  413. return -1;
  414. #endif /* HAVE_READ */
  415. }
  416. JNIEXPORT jint JNICALL
  417. Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2 (JNIEnv *env,
  418. jobject o __attribute__ ((__unused__)),
  419. jint fd,
  420. jobject bbuf)
  421. {
  422. #ifdef HAVE_WRITE
  423. jint len;
  424. ssize_t result;
  425. struct JCL_buffer buf;
  426. int tmp_errno;
  427. /* NIODBG("fd: %d; bbuf: %p", fd, bbuf); */
  428. if (JCL_init_buffer(env, &buf, bbuf) < 0)
  429. {
  430. /* TODO: Rethrown exception */
  431. JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
  432. return -1;
  433. }
  434. len = buf.limit - buf.position;
  435. if (len == 0)
  436. {
  437. JCL_release_buffer (env, &buf, bbuf, JNI_ABORT);
  438. return 0;
  439. }
  440. do
  441. {
  442. result = cpnio_write (fd, &(buf.ptr[buf.position + buf.offset]), len);
  443. tmp_errno = errno;
  444. }
  445. while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
  446. errno = tmp_errno;
  447. buf.count = result;
  448. if (result == -1)
  449. {
  450. if (errno == EAGAIN) /* Non-blocking */
  451. {
  452. result = 0;
  453. }
  454. else
  455. {
  456. JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
  457. JCL_ThrowException(env, IO_EXCEPTION, strerror(errno));
  458. return -1;
  459. }
  460. }
  461. JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
  462. return result;
  463. #else
  464. (void) fd;
  465. (void) bbuf;
  466. JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
  467. return -1;
  468. #endif /* HAVE_WRITE */
  469. }
  470. /*
  471. * Implementation of a scattering read. Will use the appropriate
  472. * vector based read call (currently readv on Linux).
  473. *
  474. * This has a limit to the number of buffers that will be read. It
  475. * will not make muliple readv calls. This is to ensure that operations
  476. * are atomic. Currently it is limited to 16 buffers. This is for
  477. * compatibiliy with Sun.
  478. */
  479. JNIEXPORT jlong JNICALL
  480. Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env,
  481. jobject o __attribute__ ((__unused__)),
  482. jint fd,
  483. jobjectArray bbufs,
  484. jint offset,
  485. jint length)
  486. {
  487. jint i;
  488. /* jboolean is_error = JNI_FALSE; */
  489. /* char *error_msg; */
  490. struct iovec buffers[JCL_IOV_MAX];
  491. struct JCL_buffer bi_list[JCL_IOV_MAX];
  492. ssize_t result;
  493. jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
  494. jlong bytes_read = 0;
  495. int tmp_errno;
  496. /* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
  497. /* fd, bbufs, offset, length); */
  498. /* Build the vector of buffers to read into */
  499. for (i = 0; i < vec_len; i++)
  500. {
  501. struct JCL_buffer* buf;
  502. jobject bbuf;
  503. buf = &bi_list[i];
  504. bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
  505. JCL_init_buffer(env, buf, bbuf);
  506. /* JCL_print_buffer (env, buf); */
  507. buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
  508. buffers[i].iov_len = buf->limit - buf->position;
  509. (*env)->DeleteLocalRef(env, bbuf);
  510. }
  511. /* Work the scattering magic */
  512. do
  513. {
  514. result = cpnio_readv (fd, buffers, vec_len);
  515. tmp_errno = errno;
  516. }
  517. while (result == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
  518. errno = tmp_errno;
  519. bytes_read = (jlong) result;
  520. /* Handle the response */
  521. if (result < 0)
  522. {
  523. if (errno == EAGAIN)
  524. {
  525. if (is_non_blocking_fd(fd))
  526. {
  527. /* Non-blocking */
  528. result = 0;
  529. }
  530. else
  531. {
  532. /* Read timeout on a socket with SO_RCVTIMEO != 0. */
  533. JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
  534. JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
  535. return -1;
  536. }
  537. }
  538. else if (errno == EBADF) /* Bad fd */
  539. {
  540. JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
  541. JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION,
  542. strerror(errno));
  543. return -1;
  544. }
  545. else
  546. {
  547. JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
  548. JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
  549. return -1;
  550. }
  551. bytes_read = 0;
  552. }
  553. else if (result == 0) /* EOF */
  554. {
  555. result = -1;
  556. }
  557. JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
  558. return (jlong) result;
  559. }
  560. /*
  561. * Implementation of a gathering write. Will use the appropriate
  562. * vector based read call (currently readv on Linux).
  563. *
  564. * This has a limit to the number of buffers that will be read. It
  565. * will not make muliple readv calls. This is to ensure that operations
  566. * are atomic. Currently it is limited to 16 buffers. This is for
  567. * compatibiliy with Sun.
  568. */
  569. JNIEXPORT jlong JNICALL
  570. Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env,
  571. jobject o __attribute__ ((__unused__)),
  572. jint fd,
  573. jobjectArray bbufs,
  574. jint offset,
  575. jint length)
  576. {
  577. int i;
  578. /* jboolean is_error = JNI_FALSE; */
  579. /* char *error_msg; */
  580. struct iovec buffers[JCL_IOV_MAX];
  581. struct JCL_buffer bi_list[JCL_IOV_MAX];
  582. ssize_t result;
  583. jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
  584. jlong bytes_written;
  585. int tmp_errno;
  586. /* NIODBG("fd: %d; bbufs: %p; offset: %d; length: %d", */
  587. /* fd, bbufs, offset, length); */
  588. /* Build the vector of buffers to read into */
  589. for (i = 0; i < vec_len; i++)
  590. {
  591. struct JCL_buffer* buf;
  592. jobject bbuf;
  593. buf = &bi_list[i];
  594. bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
  595. JCL_init_buffer(env, buf, bbuf);
  596. /* JCL_print_buffer(env, buf); */
  597. buffers[i].iov_base = &(buf->ptr[buf->position + buf->offset]);
  598. buffers[i].iov_len = buf->limit - buf->position;
  599. (*env)->DeleteLocalRef(env, bbuf);
  600. }
  601. /* Work the gathering magic */
  602. do
  603. {
  604. result = cpnio_writev (fd, buffers, vec_len);
  605. tmp_errno = errno;
  606. }
  607. while (result == -1 && tmp_errno == EINTR && ! JCL_thread_interrupted(env));
  608. errno = tmp_errno;
  609. bytes_written = (jlong) result;
  610. if (result < 0)
  611. {
  612. bytes_written = 0;
  613. if (errno == EAGAIN) /* Non blocking */
  614. result = 0;
  615. else if (errno == EBADF) /* Bad fd */
  616. {
  617. JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
  618. bytes_written);
  619. JCL_ThrowException (env, NON_WRITABLE_CHANNEL_EXCEPTION,
  620. strerror(errno));
  621. return -1;
  622. }
  623. else
  624. {
  625. JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
  626. bytes_written);
  627. JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
  628. return -1;
  629. }
  630. }
  631. else if (result == 0) /* EOF?? Does this happen on a write */
  632. result = -1;
  633. JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_written);
  634. return (jlong) result;
  635. }
  636. /*
  637. * Class: gnu_java_nio_VMChannel
  638. * Method: receive
  639. * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I
  640. */
  641. JNIEXPORT jint JNICALL
  642. Java_gnu_java_nio_VMChannel_receive (JNIEnv *env,
  643. jclass c __attribute__((unused)),
  644. jint fd, jobject dst, jobject addrPort)
  645. {
  646. #ifdef HAVE_RECVFROM
  647. char *addrPortPtr = (*env)->GetDirectBufferAddress (env, addrPort);
  648. struct JCL_buffer buf;
  649. #ifdef HAVE_INET6
  650. struct sockaddr_in6 sock_storage;
  651. struct sockaddr_in6 *sock6;
  652. socklen_t slen = sizeof (struct sockaddr_in6);
  653. #else
  654. struct sockaddr_in sock_storage;
  655. socklen_t slen = sizeof (struct sockaddr_in);
  656. #endif /* HAVE_INET6 */
  657. struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
  658. struct sockaddr_in *sock4;
  659. int ret;
  660. jint result = -1;
  661. if (JCL_init_buffer (env, &buf, dst) == -1)
  662. JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
  663. #ifndef HAVE_MSG_WAITALL
  664. #define MSG_WAITALL 0
  665. #endif
  666. ret = cpnio_recvfrom (fd, &(buf.ptr[buf.position + buf.offset]),
  667. buf.limit - buf.position, MSG_WAITALL,
  668. sockaddr, &slen);
  669. if (-1 == ret)
  670. {
  671. JCL_release_buffer (env, &buf, dst, JNI_ABORT);
  672. if (EINTR == errno)
  673. JCL_ThrowException (env, "java/io/InterruptedIOException", strerror (errno));
  674. else if (EAGAIN == errno)
  675. {
  676. /* If the socket is in blocking mode, our timeout expired. */
  677. int val = fcntl (fd, F_GETFL, 0);
  678. if (val == -1)
  679. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  680. else if ((val & O_NONBLOCK) == 0)
  681. JCL_ThrowException (env, "java/net/SocketTimeoutException",
  682. "read timed out");
  683. }
  684. else
  685. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  686. return 0;
  687. }
  688. if (sockaddr->sa_family == AF_INET)
  689. {
  690. sock4 = (struct sockaddr_in *) sockaddr;
  691. memcpy (addrPortPtr, &(sock4->sin_addr.s_addr), 4);
  692. ;memcpy (addrPortPtr + 4, &(sock4->sin_port), 2);
  693. result = 4;
  694. }
  695. #ifdef HAVE_INET6
  696. else if (sockaddr->sa_family == AF_INET6)
  697. {
  698. sock6 = (struct sockaddr_in6 *) sockaddr;
  699. memcpy (addrPortPtr, &(sock6->sin6_addr.s6_addr), 16);
  700. memcpy (addrPortPtr + 16, &(sock6->sin6_port), 2);
  701. result = 16;
  702. }
  703. #endif /* HAVE_INET6 */
  704. else if (ret == 0)
  705. {
  706. result = 0;
  707. }
  708. else
  709. {
  710. JCL_ThrowException (env, "java/net/SocketException",
  711. "unsupported address type returned");
  712. }
  713. buf.count += ret;
  714. JCL_release_buffer (env, &buf, dst, 0);
  715. return result;
  716. #else
  717. (void) fd;
  718. (void) dst;
  719. (void) addrPort;
  720. JCL_ThrowException (env, IO_EXCEPTION, "recvfrom not supported");
  721. #endif /* HAVE_RECVFROM */
  722. }
  723. /*
  724. * Class: gnu_java_nio_VMChannel
  725. * Method: send
  726. * Signature: (Ljava/nio/ByteBuffer;[BI)I
  727. */
  728. JNIEXPORT jint JNICALL
  729. Java_gnu_java_nio_VMChannel_send (JNIEnv *env,
  730. jclass c __attribute__((unused)),
  731. int fd, jobject src, jbyteArray addr, jint port)
  732. {
  733. #ifdef HAVE_SENDTO
  734. struct sockaddr_in sockaddr;
  735. jbyte *elems;
  736. struct JCL_buffer buf;
  737. int ret;
  738. /* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
  739. /* fd, src, addr, port); */
  740. if (JCL_init_buffer (env, &buf, src) == -1)
  741. {
  742. JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
  743. return -1;
  744. }
  745. /* JCL_print_buffer (env, &buf); */
  746. elems = (*env)->GetByteArrayElements (env, addr, NULL);
  747. sockaddr.sin_family = AF_INET;
  748. sockaddr.sin_addr.s_addr = *((uint32_t *) elems);
  749. sockaddr.sin_port = htons (port);
  750. do
  751. {
  752. ret = cpnio_sendto (fd, &(buf.ptr[buf.position + buf.offset]),
  753. buf.limit - buf.position,
  754. 0, (const struct sockaddr *) &sockaddr,
  755. sizeof (struct sockaddr_in));
  756. }
  757. while (-1 == ret && EINTR == errno);
  758. (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
  759. if (-1 == ret)
  760. {
  761. if (errno != EAGAIN)
  762. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  763. JCL_release_buffer (env, &buf, src, JNI_ABORT);
  764. return 0;
  765. }
  766. buf.count += ret;
  767. JCL_release_buffer (env, &buf, src, JNI_ABORT);
  768. return ret;
  769. #else
  770. (void) fd;
  771. (void) src;
  772. (void) addr;
  773. (void) port;
  774. #endif /* HAVE_SENDTO */
  775. }
  776. /*
  777. * Class: gnu_java_nio_VMChannel
  778. * Method: send6
  779. * Signature: (Ljava/nio/ByteBuffer;[BI)I
  780. */
  781. JNIEXPORT jint JNICALL
  782. Java_gnu_java_nio_VMChannel_send6 (JNIEnv *env,
  783. jclass c __attribute__((unused)),
  784. int fd, jobject src, jbyteArray addr, jint port)
  785. {
  786. #if defined(HAVE_SENDTO) && defined(HAVE_INET6)
  787. struct sockaddr_in6 sockaddr;
  788. jbyte *elems;
  789. struct JCL_buffer buf;
  790. int ret;
  791. /* NIODBG("fd: %d; src: %p; addr: %p; port: %d", */
  792. /* fd, src, addr, port); */
  793. if (JCL_init_buffer (env, &buf, src) == -1)
  794. {
  795. JCL_ThrowException (env, IO_EXCEPTION, "loading buffer failed");
  796. return -1;
  797. }
  798. /* JCL_print_buffer (env, &buf); */
  799. elems = (*env)->GetByteArrayElements (env, addr, NULL);
  800. sockaddr.sin6_family = AF_INET6;
  801. memcpy (&sockaddr.sin6_addr.s6_addr, elems, 16);
  802. sockaddr.sin6_port = htons (port);
  803. do
  804. {
  805. ret = cpnio_sendto (fd, (const void *) (buf.ptr + buf.offset),
  806. buf.limit - buf.position,
  807. 0, (const struct sockaddr *) &sockaddr,
  808. sizeof (struct sockaddr_in6));
  809. }
  810. while (-1 == ret && EINTR == errno);
  811. (*env)->ReleaseByteArrayElements (env, addr, elems, JNI_ABORT);
  812. if (-1 == ret)
  813. {
  814. if (errno != EAGAIN)
  815. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  816. JCL_release_buffer (env, &buf, src, JNI_ABORT);
  817. return 0;
  818. }
  819. buf.count += ret;
  820. JCL_release_buffer (env, &buf, src, JNI_ABORT);
  821. return ret;
  822. #else
  823. (void) fd;
  824. (void) src;
  825. (void) addr;
  826. (void) port;
  827. JCL_ThrowException (env, IO_EXCEPTION, "IPv6 sendto not supported");
  828. return -1;
  829. #endif /* HAVE_SENDTO && HAVE_INET6 */
  830. }
  831. /*
  832. * Class: gnu_java_nio_VMChannel
  833. * Method: read
  834. * Signature: (I)I
  835. */
  836. JNIEXPORT jint JNICALL
  837. Java_gnu_java_nio_VMChannel_read__I (JNIEnv *env,
  838. jclass c __attribute__((unused)),
  839. jint fd)
  840. {
  841. #ifdef HAVE_READ
  842. char in;
  843. int ret;
  844. int tmp_errno;
  845. /* NIODBG("fd: %d", fd); */
  846. do
  847. {
  848. ret = cpnio_read (fd, &in, 1);
  849. tmp_errno = errno;
  850. }
  851. while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
  852. errno = tmp_errno;
  853. if (-1 == ret)
  854. {
  855. if (errno == EAGAIN && !is_non_blocking_fd(fd))
  856. {
  857. /* Read timeout on a socket with SO_RCVTIMEO != 0. */
  858. JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "read timed out");
  859. }
  860. else
  861. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  862. return -1;
  863. }
  864. if (0 == ret)
  865. return -1;
  866. return (in & 0xFF);
  867. #else
  868. (void) fd;
  869. JCL_ThrowException (env, IO_EXCEPTION, "read not supported");
  870. #endif /* HAVE_READ */
  871. }
  872. /*
  873. * Class: gnu_java_nio_VMChannel
  874. * Method: write
  875. * Signature: (I)V
  876. */
  877. JNIEXPORT void JNICALL
  878. Java_gnu_java_nio_VMChannel_write__II (JNIEnv *env,
  879. jclass c __attribute__((unused)),
  880. jint fd, jint data)
  881. {
  882. #ifdef HAVE_WRITE
  883. char out = (char) data;
  884. int ret;
  885. int tmp_errno;
  886. /* NIODBG("fd: %d; data: %d", fd, data); */
  887. do
  888. {
  889. ret = cpnio_write (fd, &out, 1);
  890. tmp_errno = errno;
  891. }
  892. while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
  893. errno = tmp_errno;
  894. if (-1 == ret)
  895. JCL_ThrowException(env, IO_EXCEPTION, strerror (errno));
  896. #else
  897. (void) fd;
  898. (void) data;
  899. JCL_ThrowException (env, IO_EXCEPTION, "write not supported");
  900. #endif /* HAVE_WRITE */
  901. }
  902. /*
  903. * Class: gnu_java_nio_VMChannel
  904. * Method: socket
  905. * Signature: (Z)I
  906. */
  907. JNIEXPORT jint JNICALL
  908. Java_gnu_java_nio_VMChannel_socket (JNIEnv *env, jclass clazz __attribute__((unused)),
  909. jboolean stream)
  910. {
  911. #ifdef HAVE_SOCKET
  912. int ret;
  913. do
  914. {
  915. ret = cpnio_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
  916. }
  917. while (-1 == ret && EINTR == errno);
  918. if (ret == -1)
  919. JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
  920. /* NIODBG("created socket %d", ret); */
  921. return ret;
  922. #else
  923. (void) stream;
  924. JCL_ThrowException (env, IO_EXCEPTION, "socket not supported");
  925. return -1;
  926. #endif /* HAVE_SOCKET */
  927. }
  928. /*
  929. * Class: gnu_java_nio_VMChannel
  930. * Method: connect
  931. * Signature: (I[BI)Z
  932. */
  933. JNIEXPORT jboolean JNICALL
  934. Java_gnu_java_nio_VMChannel_connect (JNIEnv *env, jclass clazz __attribute__((unused)),
  935. jint fd, jbyteArray addr, jint port, jint timeout)
  936. {
  937. #ifdef HAVE_CONNECT
  938. struct sockaddr_in sockaddr;
  939. struct timeval timeo;
  940. int origflags = 0, flags;
  941. jbyte *addr_elems;
  942. int ret;
  943. int tmpErrno;
  944. if ((*env)->GetArrayLength (env, addr) != 4)
  945. {
  946. JCL_ThrowException (env, SOCKET_EXCEPTION,
  947. "expecting 4-byte address");
  948. return JNI_FALSE;
  949. }
  950. if (timeout > 0)
  951. {
  952. timeo.tv_sec = timeout / 1000;
  953. timeo.tv_usec = (timeout % 1000) * 1000;
  954. origflags = fcntl (fd, F_GETFL, 0);
  955. if (origflags == -1)
  956. {
  957. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  958. return JNI_FALSE;
  959. }
  960. /* Set nonblocking mode, if not already set. */
  961. if (!(origflags & O_NONBLOCK))
  962. {
  963. flags = origflags | O_NONBLOCK;
  964. if (fcntl (fd, F_SETFL, flags) == -1)
  965. {
  966. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  967. return JNI_FALSE;
  968. }
  969. }
  970. }
  971. addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
  972. memset (&sockaddr, 0, sizeof (struct sockaddr_in));
  973. sockaddr.sin_family = AF_INET;
  974. sockaddr.sin_port = htons (port);
  975. sockaddr.sin_addr.s_addr = *((uint32_t *) addr_elems);
  976. do
  977. {
  978. ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
  979. sizeof (struct sockaddr_in));
  980. tmpErrno = errno;
  981. }
  982. while (ret == -1 && errno == EINTR && ! JCL_thread_interrupted(env));
  983. errno = tmpErrno;
  984. (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
  985. /* If a timeout was specified, select on the file descriptor with
  986. the timeout. */
  987. if (timeout > 0 && ret == -1)
  988. {
  989. /* Reset the non-blocking flag, if needed. */
  990. if (!(origflags & O_NONBLOCK))
  991. {
  992. if (fcntl (fd, F_SETFL, origflags) == -1)
  993. {
  994. /* oops */
  995. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  996. return JNI_FALSE;
  997. }
  998. }
  999. if (EINPROGRESS == errno)
  1000. {
  1001. fd_set wrfds;
  1002. FD_ZERO(&wrfds);
  1003. FD_SET(fd, &wrfds);
  1004. ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
  1005. if (ret == -1)
  1006. {
  1007. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1008. return JNI_FALSE;
  1009. }
  1010. if (ret == 0) /* connect timed out */
  1011. {
  1012. JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
  1013. "connect timed out");
  1014. return JNI_FALSE;
  1015. }
  1016. return JNI_TRUE; /* Connected! */
  1017. }
  1018. else if (ECONNREFUSED == errno)
  1019. {
  1020. JCL_ThrowException (env, CONNECT_EXCEPTION,
  1021. strerror (errno));
  1022. return JNI_FALSE;
  1023. }
  1024. else
  1025. {
  1026. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1027. return JNI_FALSE;
  1028. }
  1029. }
  1030. if (ret == -1)
  1031. {
  1032. if (EINPROGRESS == errno)
  1033. return JNI_FALSE;
  1034. else if (ECONNREFUSED == errno)
  1035. {
  1036. JCL_ThrowException (env, CONNECT_EXCEPTION,
  1037. strerror (errno));
  1038. return JNI_FALSE;
  1039. }
  1040. else
  1041. {
  1042. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1043. return JNI_FALSE;
  1044. }
  1045. }
  1046. return JNI_TRUE;
  1047. #else
  1048. (void) fd;
  1049. (void) addr;
  1050. (void) port;
  1051. (void) timeout;
  1052. JCL_ThrowException (env, SOCKET_EXCEPTION, "connect not supported");
  1053. return JNI_FALSE;
  1054. #endif /* HAVE_CONNECT */
  1055. }
  1056. /*
  1057. * Class: gnu_java_nio_VMChannel
  1058. * Method: connect6
  1059. * Signature: (I[BI)Z
  1060. */
  1061. JNIEXPORT jboolean JNICALL
  1062. Java_gnu_java_nio_VMChannel_connect6 (JNIEnv *env, jclass clazz __attribute__((unused)),
  1063. jint fd, jbyteArray addr, jint port, int timeout)
  1064. {
  1065. #if defined(HAVE_CONNECT) && defined(HAVE_INET6)
  1066. struct sockaddr_in6 sockaddr;
  1067. struct timeval timeo;
  1068. int flags, origflags = 0;
  1069. jbyte *addr_elems;
  1070. int ret;
  1071. if (timeout > 0)
  1072. {
  1073. timeo.tv_sec = timeout / 1000;
  1074. timeo.tv_usec = (timeout % 1000) * 1000;
  1075. origflags = fcntl (fd, F_GETFL, 0);
  1076. if (origflags == -1)
  1077. {
  1078. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1079. return JNI_FALSE;
  1080. }
  1081. /* Set nonblocking mode, if not already set. */
  1082. if (!(origflags & O_NONBLOCK))
  1083. {
  1084. flags = origflags | O_NONBLOCK;
  1085. if (fcntl (fd, F_SETFL, flags) == -1)
  1086. {
  1087. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1088. return JNI_FALSE;
  1089. }
  1090. }
  1091. }
  1092. addr_elems = (*env)->GetByteArrayElements (env, addr, NULL);
  1093. memset (&sockaddr, 0, sizeof (struct sockaddr_in6));
  1094. sockaddr.sin6_family = AF_INET6;
  1095. sockaddr.sin6_port = htons (port);
  1096. memcpy (&sockaddr.sin6_addr.s6_addr, addr_elems, 16);
  1097. ret = cpnio_connect (fd, (struct sockaddr *) &sockaddr,
  1098. sizeof (struct sockaddr_in6));
  1099. (*env)->ReleaseByteArrayElements (env, addr, addr_elems, JNI_ABORT);
  1100. /* If a timeout was specified, select on the file descriptor with
  1101. the timeout. */
  1102. if (timeout > 0 && ret == -1)
  1103. {
  1104. /* Reset the non-blocking flag, if needed. */
  1105. if (!(origflags & O_NONBLOCK))
  1106. {
  1107. if (fcntl (fd, F_SETFL, origflags) == -1)
  1108. {
  1109. /* oops */
  1110. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1111. return JNI_FALSE;
  1112. }
  1113. }
  1114. if (EINPROGRESS == errno)
  1115. {
  1116. fd_set wrfds;
  1117. FD_ZERO(&wrfds);
  1118. FD_SET(fd, &wrfds);
  1119. ret = cpnio_select (fd + 1, NULL, &wrfds, NULL, &timeo);
  1120. if (ret == -1)
  1121. {
  1122. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1123. return JNI_FALSE;
  1124. }
  1125. if (ret == 0) /* connect timed out */
  1126. {
  1127. JCL_ThrowException (env, SOCKET_TIMEOUT_EXCEPTION,
  1128. "connect timed out");
  1129. return JNI_FALSE;
  1130. }
  1131. return JNI_TRUE; /* Connected! */
  1132. }
  1133. else if (ECONNREFUSED == errno)
  1134. {
  1135. JCL_ThrowException (env, CONNECT_EXCEPTION,
  1136. strerror (errno));
  1137. return JNI_FALSE;
  1138. }
  1139. else
  1140. {
  1141. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1142. return JNI_FALSE;
  1143. }
  1144. }
  1145. if (ret == -1)
  1146. {
  1147. if (EAGAIN == errno)
  1148. return JNI_FALSE;
  1149. else if (ECONNREFUSED == errno)
  1150. {
  1151. JCL_ThrowException (env, CONNECT_EXCEPTION,
  1152. strerror (errno));
  1153. return JNI_FALSE;
  1154. }
  1155. else
  1156. {
  1157. JCL_ThrowException (env, SOCKET_EXCEPTION, strerror (errno));
  1158. return JNI_FALSE;
  1159. }
  1160. }
  1161. return JNI_TRUE;
  1162. #else
  1163. (void) fd;
  1164. (void) addr;
  1165. (void) port;
  1166. (void) timeout;
  1167. JCL_ThrowException (env, SOCKET_EXCEPTION, "IPv6 connect not supported");
  1168. return JNI_FALSE;
  1169. #endif /* HAVE_CONNECT && HAVE_INET6 */
  1170. }
  1171. /*
  1172. * Class: gnu_java_nio_VMChannel
  1173. * Method: getsockname
  1174. * Signature: (ILjava/nio/ByteBuffer;)I
  1175. */
  1176. JNIEXPORT jint JNICALL
  1177. Java_gnu_java_nio_VMChannel_getsockname (JNIEnv *env, jclass clazz __attribute__((unused)),
  1178. jint fd, jobject name)
  1179. {
  1180. #ifdef HAVE_GETSOCKNAME
  1181. #ifdef HAVE_INET6
  1182. struct sockaddr_in6 *addr6;
  1183. struct sockaddr_in6 sock_storage;
  1184. socklen_t socklen = sizeof (struct sockaddr_in6);
  1185. #else
  1186. struct sockaddr_in sock_storage;
  1187. socklen_t socklen = sizeof (struct sockaddr_in);
  1188. #endif /* HAVE_INET6 */
  1189. struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
  1190. struct sockaddr_in *addr4;
  1191. int ret;
  1192. char *nameptr = (*env)->GetDirectBufferAddress (env, name);
  1193. ret = getsockname (fd, sockaddr, &socklen);
  1194. if (ret == -1)
  1195. {
  1196. JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
  1197. return 0;
  1198. }
  1199. if (sockaddr->sa_family == AF_INET)
  1200. {
  1201. addr4 = (struct sockaddr_in *) sockaddr;
  1202. memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
  1203. memcpy (nameptr + 4, &(addr4->sin_port), 2);
  1204. return 4;
  1205. }
  1206. #ifdef HAVE_INET6
  1207. /* IPv6 */
  1208. if (sockaddr->sa_family == AF_INET6)
  1209. {
  1210. addr6 = (struct sockaddr_in6 *) sockaddr;
  1211. memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
  1212. memcpy (nameptr + 16, &(addr6->sin6_port), 2);
  1213. return 16;
  1214. }
  1215. #endif /* HAVE_INET6 */
  1216. JCL_ThrowException (env, IO_EXCEPTION, "unsupported address format");
  1217. return -1;
  1218. #else
  1219. (void) fd;
  1220. (void) name;
  1221. JCL_ThrowException (env, IO_EXCEPTION, "getsockname not supported");
  1222. return -1;
  1223. #endif /* HAVE_GETSOCKNAME */
  1224. }
  1225. /*
  1226. * Class: gnu_java_nio_VMChannel
  1227. * Method: getpeername
  1228. * Signature: (ILjava/nio/ByteBuffer;)I
  1229. */
  1230. JNIEXPORT jint JNICALL
  1231. Java_gnu_java_nio_VMChannel_getpeername (JNIEnv *env, jclass clazz __attribute__((unused)),
  1232. jint fd, jobject name)
  1233. {
  1234. #ifdef HAVE_GETPEERNAME
  1235. #ifdef HAVE_INET6
  1236. struct sockaddr_in6 *addr6;
  1237. struct sockaddr_in6 sock_storage;
  1238. socklen_t socklen = sizeof (struct sockaddr_in6);
  1239. #else
  1240. struct sockaddr_in sock_storage;
  1241. socklen_t socklen = sizeof (struct sockaddr_in);
  1242. #endif /* HAVE_INET6 */
  1243. struct sockaddr *sockaddr = (struct sockaddr *) &sock_storage;
  1244. struct sockaddr_in *addr4;
  1245. int ret;
  1246. char *nameptr = (*env)->GetDirectBufferAddress (env, name);
  1247. ret = getpeername (fd, sockaddr, &socklen);
  1248. if (ret == -1)
  1249. {
  1250. if (ENOTCONN != errno)
  1251. JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
  1252. return 0;
  1253. }
  1254. if (sockaddr->sa_family == AF_INET)
  1255. {
  1256. addr4 = (struct sockaddr_in *) sockaddr;
  1257. memcpy (nameptr, &(addr4->sin_addr.s_addr), 4);
  1258. memcpy (nameptr + 4, &(addr4->sin_port), 2);
  1259. return 4;
  1260. }
  1261. #ifdef HAVE_INET6
  1262. else if (sockaddr->sa_family == AF_INET6)
  1263. {
  1264. addr6 = (struct sockaddr_in6 *) sockaddr;
  1265. memcpy (nameptr, &(addr6->sin6_addr.s6_addr), 16);
  1266. memcpy (nameptr + 16, &(addr6->sin6_port), 2);
  1267. return 16;
  1268. }
  1269. #endif /* HAVE_INET6 */
  1270. JCL_ThrowException (env, "java/net/SocketException",
  1271. "unsupported address type");
  1272. return -1;
  1273. #else
  1274. (void) fd;
  1275. (void) name;
  1276. JCL_ThrowException (env, IO_EXCEPTION, "getpeername not supported");
  1277. return -1;
  1278. #endif /* HAVE_GETPEERNAME */
  1279. }
  1280. /*
  1281. * Class: gnu_java_nio_VMChannel
  1282. * Method: accept
  1283. * Signature: (I)I
  1284. */
  1285. JNIEXPORT jint JNICALL
  1286. Java_gnu_java_nio_VMChannel_accept (JNIEnv *env,
  1287. jclass c __attribute__((unused)),
  1288. jint fd)
  1289. {
  1290. #ifdef HAVE_ACCEPT
  1291. int ret;
  1292. int tmp_errno = 0;
  1293. #ifdef HAVE_INET6
  1294. struct sockaddr_in6 addr;
  1295. socklen_t alen = sizeof (struct sockaddr_in6);
  1296. #else
  1297. struct sockaddr_in addr;
  1298. socklen_t alen = sizeof (struct sockaddr_in);
  1299. #endif /* HAVE_INET6 */
  1300. do
  1301. {
  1302. ret = cpnio_accept (fd, (struct sockaddr *) &addr, &alen);
  1303. tmp_errno = errno;
  1304. if (ret == -1)
  1305. switch (tmp_errno)
  1306. {
  1307. case EINTR:
  1308. /* Check if interrupted by Thread.interrupt(). If not then some
  1309. * other unrelated signal interrupted the system function and
  1310. * we should start over again.
  1311. */
  1312. if (JCL_thread_interrupted(env))
  1313. {
  1314. JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
  1315. return -1;
  1316. }
  1317. break;
  1318. #if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN
  1319. case EWOULDBLOCK:
  1320. #endif
  1321. case EAGAIN:
  1322. if (!is_non_blocking_fd(fd))
  1323. {
  1324. JCL_ThrowException(env, SOCKET_TIMEOUT_EXCEPTION, "Accept timed out");
  1325. }
  1326. /* Socket in non-blocking mode and no pending connection. */
  1327. return -1;
  1328. default:
  1329. JCL_ThrowException (env, "java/net/SocketException", strerror (tmp_errno));
  1330. return -1;
  1331. }
  1332. else
  1333. break;
  1334. }
  1335. while (1);
  1336. cpio_closeOnExec(ret);
  1337. return ret;
  1338. #else
  1339. (void) fd;
  1340. JCL_ThrowException (env, IO_EXCEPTION, "accept not supported");
  1341. return -1;
  1342. #endif /* HAVE_ACCEPT */
  1343. }
  1344. /*
  1345. * Class: gnu_java_nio_VMChannel
  1346. * Method: disconnect
  1347. * Signature: (I)V
  1348. */
  1349. JNIEXPORT void JNICALL
  1350. Java_gnu_java_nio_VMChannel_disconnect (JNIEnv *env,
  1351. jclass c __attribute__((unused)),
  1352. jint fd)
  1353. {
  1354. struct sockaddr sockaddr;
  1355. sockaddr.sa_family = AF_UNSPEC;
  1356. if (connect (fd, &sockaddr, sizeof (struct sockaddr)) == -1)
  1357. {
  1358. /* The expected error for a successful disconnect is EAFNOSUPPORT. */
  1359. if (errno != EAFNOSUPPORT)
  1360. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1361. }
  1362. }
  1363. /*
  1364. * Class: gnu_java_nio_VMChannel
  1365. * Method: close
  1366. * Signature: (I)V
  1367. */
  1368. JNIEXPORT void JNICALL
  1369. Java_gnu_java_nio_VMChannel_close (JNIEnv *env,
  1370. jclass c __attribute__((unused)),
  1371. jint fd)
  1372. {
  1373. if (close (fd) == -1)
  1374. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1375. }
  1376. /*
  1377. * Class: gnu_java_nio_VMChannel
  1378. * Method: available
  1379. * Signature: (I)I
  1380. */
  1381. JNIEXPORT jint JNICALL
  1382. Java_gnu_java_nio_VMChannel_available (JNIEnv *env,
  1383. jclass c __attribute__((unused)),
  1384. jint fd)
  1385. {
  1386. #if defined (FIONREAD)
  1387. jint avail = 0;
  1388. #if defined(ENOTTY) && defined(HAVE_FSTAT)
  1389. struct stat statBuffer;
  1390. off_t n;
  1391. #endif
  1392. /* NIODBG("fd: %d", fd); */
  1393. if (ioctl (fd, FIONREAD, &avail) == -1)
  1394. {
  1395. #if defined(ENOTTY) && defined(HAVE_FSTAT)
  1396. if (errno == ENOTTY)
  1397. {
  1398. if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
  1399. {
  1400. n = lseek (fd, 0, SEEK_CUR);
  1401. if (n != -1)
  1402. {
  1403. avail = statBuffer.st_size - n;
  1404. return avail;
  1405. }
  1406. }
  1407. }
  1408. #endif
  1409. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1410. }
  1411. /* NIODBG("avail: %d", avail); */
  1412. return avail;
  1413. #elif defined(HAVE_FSTAT)
  1414. jint avail = 0;
  1415. struct stat statBuffer;
  1416. off_t n;
  1417. if ((fstat (fd, &statBuffer) == 0) && S_ISREG (statBuffer.st_mode))
  1418. {
  1419. n = lseek (fd, 0, SEEK_CUR);
  1420. if (n != -1)
  1421. {
  1422. avail = statBuffer.st_size - n;
  1423. return avail;
  1424. }
  1425. }
  1426. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1427. #elif defined(HAVE_SELECT)
  1428. jint avail = 0;
  1429. fd_set filedescriptset;
  1430. struct timeval tv;
  1431. FD_ZERO (&filedescriptset);
  1432. FD_SET (fd,&filedescriptset);
  1433. memset (&tv, 0, sizeof(tv));
  1434. switch (select (fd+1, &filedescriptset, NULL, NULL, &tv))
  1435. {
  1436. case -1:
  1437. break;
  1438. case 0:
  1439. avail = 0;
  1440. return avail;
  1441. default:
  1442. avail = 1;
  1443. return avail;
  1444. }
  1445. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1446. #else
  1447. JCL_ThrowException (env, IO_EXCEPTION, "No native method for available");
  1448. #endif
  1449. }
  1450. enum FileChannel_mode {
  1451. CPNIO_READ = 1,
  1452. CPNIO_WRITE = 2,
  1453. CPNIO_APPEND = 4,
  1454. CPNIO_EXCL = 8,
  1455. CPNIO_SYNC = 16,
  1456. CPNIO_DSYNC = 32
  1457. };
  1458. /*
  1459. * Class: gnu_java_nio_VMChannel
  1460. * Method: open
  1461. * Signature: (Ljava/lang/String;I)I
  1462. */
  1463. JNIEXPORT jint JNICALL
  1464. Java_gnu_java_nio_VMChannel_open (JNIEnv *env,
  1465. jclass c __attribute__((unused)),
  1466. jstring path, jint mode)
  1467. {
  1468. int nmode = 0;
  1469. int ret;
  1470. const char *npath;
  1471. if ((mode & CPNIO_READ) && (mode & CPNIO_WRITE))
  1472. nmode = O_RDWR;
  1473. else if (mode & CPNIO_WRITE)
  1474. nmode = O_WRONLY;
  1475. else
  1476. nmode = O_RDONLY;
  1477. nmode = (nmode
  1478. | ((nmode == O_RDWR || nmode == O_WRONLY) ? O_CREAT : 0)
  1479. | ((mode & CPNIO_APPEND) ? O_APPEND :
  1480. ((nmode == O_WRONLY) ? O_TRUNC : 0))
  1481. | ((mode & CPNIO_EXCL) ? O_EXCL : 0)
  1482. | ((mode & CPNIO_SYNC) ? O_SYNC : 0));
  1483. npath = JCL_jstring_to_cstring (env, path);
  1484. /* NIODBG("path: %s; mode: %x", npath, nmode); */
  1485. ret = open (npath, nmode, 0666);
  1486. /* NIODBG("ret: %d\n", ret); */
  1487. JCL_free_cstring (env, path, npath);
  1488. if (-1 == ret)
  1489. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1490. return ret;
  1491. }
  1492. /*
  1493. * Class: gnu_java_nio_VMChannel
  1494. * Method: position
  1495. * Signature: (I)J
  1496. */
  1497. JNIEXPORT jlong JNICALL
  1498. Java_gnu_java_nio_VMChannel_position (JNIEnv *env,
  1499. jclass c __attribute__((unused)),
  1500. jint fd)
  1501. {
  1502. #ifdef HAVE_LSEEK
  1503. off_t ret;
  1504. ret = lseek (fd, 0, SEEK_CUR);
  1505. if (-1 == ret)
  1506. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1507. return (jlong) ret;
  1508. #else
  1509. JCL_ThrowException (env, IO_EXCEPTION, "position not supported");
  1510. return -1;
  1511. #endif /* HAVE_LSEEK */
  1512. }
  1513. /*
  1514. * Class: gnu_java_nio_VMChannel
  1515. * Method: seek
  1516. * Signature: (IJ)V
  1517. */
  1518. JNIEXPORT void JNICALL
  1519. Java_gnu_java_nio_VMChannel_seek (JNIEnv *env,
  1520. jclass c __attribute__((unused)),
  1521. jint fd, jlong pos)
  1522. {
  1523. #ifdef HAVE_LSEEK
  1524. if (lseek (fd, (off_t) pos, SEEK_SET) == -1)
  1525. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1526. #else
  1527. JCL_ThrowException (env, IO_EXCEPTION, "seek not supported");
  1528. #endif /* HAVE_LSEEK */
  1529. }
  1530. /*
  1531. * Class: gnu_java_nio_VMChannel
  1532. * Method: truncate
  1533. * Signature: (IJ)V
  1534. */
  1535. JNIEXPORT void JNICALL
  1536. Java_gnu_java_nio_VMChannel_truncate (JNIEnv *env,
  1537. jclass c __attribute__((unused)),
  1538. jint fd, jlong len)
  1539. {
  1540. #if defined(HAVE_FTRUNCATE) && defined(HAVE_LSEEK)
  1541. off_t pos = lseek (fd, 0, SEEK_CUR);
  1542. if (pos == -1)
  1543. {
  1544. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1545. return;
  1546. }
  1547. if (ftruncate (fd, (off_t) len) == -1)
  1548. {
  1549. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1550. return;
  1551. }
  1552. if (pos > len)
  1553. {
  1554. if (lseek (fd, len, SEEK_SET) == -1)
  1555. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1556. }
  1557. #else
  1558. JCL_ThrowException (env, IO_EXCEPTION, "truncate not supported");
  1559. #endif /* HAVE_FTRUNCATE && HAVE_LSEEK */
  1560. }
  1561. /*
  1562. * Class: gnu_java_nio_VMChannel
  1563. * Method: lock
  1564. * Signature: (IJJZZ)Z
  1565. */
  1566. JNIEXPORT jboolean JNICALL
  1567. Java_gnu_java_nio_VMChannel_lock (JNIEnv *env,
  1568. jclass c __attribute__((unused)),
  1569. jint fd, jlong pos, jlong len,
  1570. jboolean shared, jboolean wait)
  1571. {
  1572. #if HAVE_FCNTL
  1573. struct flock fl;
  1574. fl.l_start = (off_t) pos;
  1575. /* Long.MAX_VALUE means lock everything possible starting at pos. */
  1576. if (len == 9223372036854775807LL)
  1577. fl.l_len = 0;
  1578. else
  1579. fl.l_len = (off_t) len;
  1580. fl.l_pid = getpid ();
  1581. fl.l_type = (shared ? F_RDLCK : F_WRLCK);
  1582. fl.l_whence = SEEK_SET;
  1583. if (cpnio_fcntl (fd, (wait ? F_SETLKW : F_SETLK), (long) &fl) == -1)
  1584. {
  1585. if (errno != EAGAIN)
  1586. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1587. return JNI_FALSE;
  1588. }
  1589. return JNI_TRUE;
  1590. #else
  1591. JCL_ThrowException (env, IO_EXCEPTION, "lock not supported");
  1592. return JNI_FALSE;
  1593. #endif /* HAVE_FCNTL */
  1594. }
  1595. /*
  1596. * Class: gnu_java_nio_VMChannel
  1597. * Method: unlock
  1598. * Signature: (IJJ)V
  1599. */
  1600. JNIEXPORT void JNICALL
  1601. Java_gnu_java_nio_VMChannel_unlock (JNIEnv *env,
  1602. jclass c __attribute__((unused)),
  1603. jint fd, jlong pos, jlong len)
  1604. {
  1605. #if HAVE_FCNTL
  1606. struct flock fl;
  1607. fl.l_start = (off_t) pos;
  1608. fl.l_len = (off_t) len;
  1609. fl.l_pid = getpid ();
  1610. fl.l_type = F_UNLCK;
  1611. fl.l_whence = SEEK_SET;
  1612. if (cpnio_fcntl (fd, F_SETLK, (long) &fl) == -1)
  1613. {
  1614. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1615. }
  1616. #else
  1617. JCL_ThrowException (env, IO_EXCEPTION, "unlock not supported");
  1618. #endif /* HAVE_FCNTL */
  1619. }
  1620. /*
  1621. * Class: gnu_java_nio_VMChannel
  1622. * Method: size
  1623. * Signature: (I)J
  1624. */
  1625. JNIEXPORT jlong JNICALL
  1626. Java_gnu_java_nio_VMChannel_size (JNIEnv *env,
  1627. jclass c __attribute__((unused)),
  1628. jint fd)
  1629. {
  1630. #ifdef HAVE_FSTAT
  1631. struct stat st;
  1632. if (fstat (fd, &st) == -1)
  1633. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1634. return (jlong) st.st_size;
  1635. #else
  1636. JCL_ThrowException (env, IO_EXCEPTION, "size not supported");
  1637. return 0;
  1638. #endif
  1639. }
  1640. /*
  1641. * Class: gnu_java_nio_VMChannel
  1642. * Method: map
  1643. * Signature: (ICJI)Lgnu/classpath/Pointer;
  1644. */
  1645. JNIEXPORT jobject JNICALL
  1646. Java_gnu_java_nio_VMChannel_map (JNIEnv *env,
  1647. jclass clazz __attribute__((unused)),
  1648. jint fd, jchar mode, jlong position, jint size)
  1649. {
  1650. #ifdef HAVE_MMAP
  1651. jclass MappedByteBufferImpl_class;
  1652. jmethodID MappedByteBufferImpl_init = NULL;
  1653. jobject Pointer_instance;
  1654. volatile jobject buffer;
  1655. long pagesize;
  1656. int prot, flags;
  1657. void *p;
  1658. void *address;
  1659. /* NIODBG("fd: %d; mode: %x; position: %lld; size: %d", */
  1660. /* fd, mode, position, size); */
  1661. /* FIXME: should we just assume we're on an OS modern enough to
  1662. have 'sysconf'? And not check for 'getpagesize'? */
  1663. #if defined(HAVE_GETPAGESIZE)
  1664. pagesize = getpagesize ();
  1665. #elif defined(HAVE_SYSCONF)
  1666. pagesize = sysconf (_SC_PAGESIZE);
  1667. #else
  1668. JCL_ThrowException (env, IO_EXCEPTION,
  1669. "can't determine memory page size");
  1670. return NULL;
  1671. #endif /* HAVE_GETPAGESIZE/HAVE_SYSCONF */
  1672. if ((*env)->ExceptionOccurred (env))
  1673. {
  1674. return NULL;
  1675. }
  1676. prot = PROT_READ;
  1677. if (mode == '+' || mode == 'c')
  1678. {
  1679. /* When writing we need to make sure the file is big enough,
  1680. otherwise the result of mmap is undefined. */
  1681. struct stat st;
  1682. if (fstat (fd, &st) == -1)
  1683. {
  1684. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1685. return NULL;
  1686. }
  1687. if (position + size > st.st_size)
  1688. {
  1689. if (ftruncate(fd, position + size) == -1)
  1690. {
  1691. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1692. return NULL;
  1693. }
  1694. }
  1695. prot |= PROT_WRITE;
  1696. }
  1697. flags = (mode == 'c' ? MAP_PRIVATE : MAP_SHARED);
  1698. p = mmap (NULL, (size_t) ALIGN_UP (size, pagesize), prot, flags,
  1699. fd, ALIGN_DOWN (position, pagesize));
  1700. if (p == MAP_FAILED)
  1701. {
  1702. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1703. return NULL;
  1704. }
  1705. /* Unalign the mapped value back up, since we aligned offset
  1706. down to a multiple of the page size. */
  1707. address = (void *) ((char *) p + (position % pagesize));
  1708. Pointer_instance = JCL_NewRawDataObject(env, address);
  1709. MappedByteBufferImpl_class = (*env)->FindClass (env,
  1710. "java/nio/MappedByteBufferImpl");
  1711. if (MappedByteBufferImpl_class != NULL)
  1712. {
  1713. MappedByteBufferImpl_init =
  1714. (*env)->GetMethodID (env, MappedByteBufferImpl_class,
  1715. "<init>", "(Lgnu/classpath/Pointer;IZ)V");
  1716. }
  1717. if ((*env)->ExceptionOccurred (env))
  1718. {
  1719. munmap (p, ALIGN_UP (size, pagesize));
  1720. return NULL;
  1721. }
  1722. if (MappedByteBufferImpl_init == NULL)
  1723. {
  1724. JCL_ThrowException (env, "java/lang/InternalError",
  1725. "could not get MappedByteBufferImpl constructor");
  1726. munmap (p, ALIGN_UP (size, pagesize));
  1727. return NULL;
  1728. }
  1729. buffer = (*env)->NewObject (env, MappedByteBufferImpl_class,
  1730. MappedByteBufferImpl_init, Pointer_instance,
  1731. (jint) size, mode == 'r');
  1732. return buffer;
  1733. #else
  1734. (void) fd;
  1735. (void) mode;
  1736. (void) position;
  1737. (void) size;
  1738. JCL_ThrowException (env, IO_EXCEPTION,
  1739. "memory-mapped files not implemented");
  1740. return 0;
  1741. #endif /* HAVE_MMAP */
  1742. }
  1743. /*
  1744. * Class: gnu_java_nio_VMChannel
  1745. * Method: flush
  1746. * Signature: (IZ)Z
  1747. */
  1748. JNIEXPORT jboolean JNICALL
  1749. Java_gnu_java_nio_VMChannel_flush (JNIEnv *env,
  1750. jclass c __attribute__((unused)),
  1751. jint fd, jboolean metadata __attribute__((unused)))
  1752. {
  1753. #ifdef HAVE_FSYNC
  1754. /* XXX blocking? */
  1755. if (fsync (fd) == -1)
  1756. {
  1757. JCL_ThrowException (env, IO_EXCEPTION, strerror (errno));
  1758. return JNI_FALSE;
  1759. }
  1760. return JNI_TRUE;
  1761. #else
  1762. JCL_ThrowException (env, IO_EXCEPTION, "flush not implemented");
  1763. return JNI_TRUE;
  1764. #endif /* HAVE_FSYNC */
  1765. }
  1766. #ifdef __cplusplus
  1767. }
  1768. #endif