1 /* 2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 #include <errno.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "jvm.h" 30 #include "net_util.h" 31 32 #include "java_net_SocketInputStream.h" 33 34 /* 35 * SocketInputStream 36 */ 37 38 static jfieldID IO_fd_fdID; 39 40 /* 41 * Class: java_net_SocketInputStream 42 * Method: init 43 * Signature: ()V 44 */ 45 JNIEXPORT void JNICALL 46 Java_java_net_SocketInputStream_init(JNIEnv *env, jclass cls) { 47 IO_fd_fdID = NET_GetFileDescriptorID(env); 48 } 49 50 static int NET_ReadWithTimeout(JNIEnv *env, int fd, char *bufP, int len, long timeout) { 51 int result = 0; 52 jlong prevNanoTime = JVM_NanoTime(env, 0); 53 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 54 while (nanoTimeout >= NET_NSEC_PER_MSEC) { 55 result = NET_Timeout(env, fd, nanoTimeout / NET_NSEC_PER_MSEC, prevNanoTime); 56 if (result <= 0) { 57 if (result == 0) { 58 JNU_ThrowByName(env, "java/net/SocketTimeoutException", "Read timed out"); 59 } else if (result == -1) { 60 if (errno == EBADF) { 61 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 62 } else if (errno == ENOMEM) { 63 JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed"); 64 } else { 65 JNU_ThrowByNameWithMessageAndLastError 66 (env, "java/net/SocketException", "select/poll failed"); 67 } 68 } 69 return -1; 70 } 71 result = NET_NonBlockingRead(fd, bufP, len); 72 if (result == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) { 73 jlong newtNanoTime = JVM_NanoTime(env, 0); 74 nanoTimeout -= newtNanoTime - prevNanoTime; 75 if (nanoTimeout >= NET_NSEC_PER_MSEC) { 76 prevNanoTime = newtNanoTime; 77 } 78 } else { 79 break; 80 } 81 } 82 return result; 83 } 84 85 /* 86 * Class: java_net_SocketInputStream 87 * Method: socketRead0 88 * Signature: (Ljava/io/FileDescriptor;[BIII)I 89 */ 90 JNIEXPORT jint JNICALL 91 Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this, 92 jobject fdObj, jbyteArray data, 93 jint off, jint len, jint timeout) 94 { 95 char BUF[MAX_BUFFER_LEN]; 96 char *bufP; 97 jint fd, nread; 98 99 if (IS_NULL(fdObj)) { 100 JNU_ThrowByName(env, "java/net/SocketException", 101 "Socket closed"); 102 return -1; 103 } 104 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 105 if (fd == -1) { 106 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 107 return -1; 108 } 109 110 /* 111 * If the read is greater than our stack allocated buffer then 112 * we allocate from the heap (up to a limit) 113 */ 114 if (len > MAX_BUFFER_LEN) { 115 if (len > MAX_HEAP_BUFFER_LEN) { 116 len = MAX_HEAP_BUFFER_LEN; 117 } 118 bufP = (char *)malloc((size_t)len); 119 if (bufP == NULL) { 120 bufP = BUF; 121 len = MAX_BUFFER_LEN; 122 } 123 } else { 124 bufP = BUF; 125 } 126 if (timeout) { 127 nread = NET_ReadWithTimeout(env, fd, bufP, len, timeout); 128 if ((*env)->ExceptionCheck(env)) { 129 if (bufP != BUF) { 130 free(bufP); 131 } 132 return nread; 133 } 134 } else { 135 nread = NET_Read(fd, bufP, len); 136 } 137 138 if (nread <= 0) { 139 if (nread < 0) { 140 141 switch (errno) { 142 case ECONNRESET: 143 case EPIPE: 144 JNU_ThrowByName(env, "sun/net/ConnectionResetException", 145 "Connection reset"); 146 break; 147 148 case EBADF: 149 JNU_ThrowByName(env, "java/net/SocketException", 150 "Socket closed"); 151 break; 152 153 case EINTR: 154 JNU_ThrowByName(env, "java/io/InterruptedIOException", 155 "Operation interrupted"); 156 break; 157 default: 158 JNU_ThrowByNameWithMessageAndLastError 159 (env, "java/net/SocketException", "Read failed"); 160 } 161 } 162 } else { 163 JVM_callNetworkReadBytes(env, nread); 164 (*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP); 165 } 166 167 if (bufP != BUF) { 168 free(bufP); 169 } 170 return nread; 171 }