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 38static jfieldID IO_fd_fdID; 39 40/* 41 * Class: java_net_SocketInputStream 42 * Method: init 43 * Signature: ()V 44 */ 45JNIEXPORT void JNICALL 46Java_java_net_SocketInputStream_init(JNIEnv *env, jclass cls) { 47 IO_fd_fdID = NET_GetFileDescriptorID(env); 48} 49 50static 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 */ 90JNIEXPORT jint JNICALL 91Java_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 (*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP); 164 } 165 166 if (bufP != BUF) { 167 free(bufP); 168 } 169 return nread; 170} 171