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 */ 34static jfieldID IO_fd_fdID; 35 36/* 37 * Class: java_net_SocketInputStream 38 * Method: init 39 * Signature: ()V 40 */ 41JNIEXPORT void JNICALL 42Java_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 */ 51JNIEXPORT jint JNICALL 52Java_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 // Check if the socket has been closed since we last checked. 126 // This could be a reason for recv failing. 127 if ((*env)->GetIntField(env, fdObj, IO_fd_fdID) == -1) { 128 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed"); 129 } else { 130 switch (WSAGetLastError()) { 131 case WSAEINTR: 132 JNU_ThrowByName(env, "java/net/SocketException", 133 "socket closed"); 134 break; 135 136 case WSAECONNRESET: 137 case WSAESHUTDOWN: 138 /* 139 * Connection has been reset - Windows sometimes reports 140 * the reset as a shutdown error. 141 */ 142 JNU_ThrowByName(env, "sun/net/ConnectionResetException", 143 ""); 144 break; 145 146 case WSAETIMEDOUT : 147 JNU_ThrowByName(env, "java/net/SocketTimeoutException", 148 "Read timed out"); 149 break; 150 151 default: 152 NET_ThrowCurrent(env, "recv failed"); 153 } 154 } 155 } 156 } 157 if (bufP != BUF) { 158 free(bufP); 159 } 160 return nread; 161} 162