1 /* 2 * Copyright (c) 1997, 2016, 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 <malloc.h> 26 27 #include "net_util.h" 28 29 #include "java_net_SocketInputStream.h" 30 31 /************************************************************************* 32 * SocketInputStream 33 */ 34 static jfieldID IO_fd_fdID; 35 36 /* 37 * Class: java_net_SocketInputStream 38 * Method: init 39 * Signature: ()V 40 */ 41 JNIEXPORT void JNICALL 42 Java_java_net_SocketInputStream_init(JNIEnv *env, jclass cls) { 43 IO_fd_fdID = NET_GetFileDescriptorID(env); 44 } 45 46 /* 47 * Class: java_net_SocketInputStream 48 * Method: socketRead 49 * Signature: (Ljava/io/FileDescriptor;[BIII)I 50 */ 51 JNIEXPORT jint JNICALL 52 Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this, 53 jobject fdObj, jbyteArray data, 54 jint off, jint len, jint timeout) 55 { 56 char BUF[MAX_BUFFER_LEN]; 57 char *bufP; 58 jint fd, newfd, nread; 59 60 if (IS_NULL(fdObj)) { 61 JNU_ThrowByName(env, "java/net/SocketException", 62 "Socket closed"); 63 return -1; 64 } 65 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 66 if (fd == -1) { 67 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 68 return -1; 69 } 70 71 /* 72 * If the caller buffer is large than our stack buffer then we allocate 73 * from the heap (up to a limit). If memory is exhausted we always use 74 * the stack buffer. 75 */ 76 if (len <= MAX_BUFFER_LEN) { 77 bufP = BUF; 78 } else { 79 if (len > MAX_HEAP_BUFFER_LEN) { 80 len = MAX_HEAP_BUFFER_LEN; 81 } 82 bufP = (char *)malloc((size_t)len); 83 if (bufP == NULL) { 84 /* allocation failed so use stack buffer */ 85 bufP = BUF; 86 len = MAX_BUFFER_LEN; 87 } 88 } 89 90 91 if (timeout) { 92 if (timeout <= 5000 || !isRcvTimeoutSupported) { 93 int ret = NET_Timeout (fd, timeout); 94 95 if (ret <= 0) { 96 if (ret == 0) { 97 JNU_ThrowByName(env, "java/net/SocketTimeoutException", 98 "Read timed out"); 99 } else if (ret == -1) { 100 JNU_ThrowByName(env, "java/net/SocketException", "socket closed"); 101 } 102 if (bufP != BUF) { 103 free(bufP); 104 } 105 return -1; 106 } 107 108 /*check if the socket has been closed while we were in timeout*/ 109 newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); 110 if (newfd == -1) { 111 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 112 if (bufP != BUF) { 113 free(bufP); 114 } 115 return -1; 116 } 117 } 118 } 119 120 nread = recv(fd, bufP, len, 0); 121 if (nread > 0) { 122 (*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP); 123 } else { 124 if (nread < 0) { 125 int err = WSAGetLastError(); 126 // Check if the socket has been closed since we last checked. 127 // This could be a reason for recv failing. 128 if ((*env)->GetIntField(env, fdObj, IO_fd_fdID) == -1) { 129 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 130 } else { 131 switch (err) { 132 case WSAEINTR: 133 JNU_ThrowByName(env, "java/net/SocketException", 134 "socket closed"); 135 break; 136 137 case WSAECONNRESET: 138 case WSAESHUTDOWN: 139 /* 140 * Connection has been reset - Windows sometimes reports 141 * the reset as a shutdown error. 142 */ 143 JNU_ThrowByName(env, "sun/net/ConnectionResetException", 144 ""); 145 break; 146 147 case WSAETIMEDOUT : 148 JNU_ThrowByName(env, "java/net/SocketTimeoutException", 149 "Read timed out"); 150 break; 151 152 default: 153 NET_ThrowCurrent(env, "recv failed"); 154 } 155 } 156 } 157 } 158 if (bufP != BUF) { 159 free(bufP); 160 } 161 return nread; 162 }