Path: blob/master/src/java.base/windows/native/libnet/SocketOutputStream.c
41119 views
/*1* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24#include <malloc.h>2526#include "net_util.h"2728#include "java_net_SocketOutputStream.h"2930/************************************************************************31* SocketOutputStream32*/33static jfieldID IO_fd_fdID;3435/*36* Class: java_net_SocketOutputStream37* Method: init38* Signature: ()V39*/40JNIEXPORT void JNICALL41Java_java_net_SocketOutputStream_init(JNIEnv *env, jclass cls) {42IO_fd_fdID = NET_GetFileDescriptorID(env);43}4445/*46* Class: java_net_SocketOutputStream47* Method: socketWrite48* Signature: (Ljava/io/FileDescriptor;[BII)V49*/50JNIEXPORT void JNICALL51Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,52jobject fdObj, jbyteArray data,53jint off, jint len) {54char *bufP;55char BUF[MAX_BUFFER_LEN];56int buflen;57int fd;5859if (IS_NULL(fdObj)) {60JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");61return;62} else {63fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);64}65if (IS_NULL(data)) {66JNU_ThrowNullPointerException(env, "data argument");67return;68}6970/*71* Use stack allocate buffer if possible. For large sizes we allocate72* an intermediate buffer from the heap (up to a maximum). If heap is73* unavailable just use our stack buffer.74*/75if (len <= MAX_BUFFER_LEN) {76bufP = BUF;77buflen = MAX_BUFFER_LEN;78} else {79buflen = min(MAX_HEAP_BUFFER_LEN, len);80bufP = (char *)malloc((size_t)buflen);81if (bufP == NULL) {82bufP = BUF;83buflen = MAX_BUFFER_LEN;84}85}8687while(len > 0) {88int loff = 0;89int chunkLen = min(buflen, len);90int llen = chunkLen;91int retry = 0;9293(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);94if ((*env)->ExceptionCheck(env)) {95break;96} else {97while(llen > 0) {98int n = send(fd, bufP + loff, llen, 0);99if (n > 0) {100llen -= n;101loff += n;102continue;103}104105/*106* Due to a bug in Windows Sockets (observed on NT and Windows107* 2000) it may be necessary to retry the send. The issue is that108* on blocking sockets send/WSASend is supposed to block if there109* is insufficient buffer space available. If there are a large110* number of threads blocked on write due to congestion then it's111* possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.112* The workaround we use is to retry the send. If we have a113* large buffer to send (>2k) then we retry with a maximum of114* 2k buffer. If we hit the issue with <=2k buffer then we backoff115* for 1 second and retry again. We repeat this up to a reasonable116* limit before bailing out and throwing an exception. In load117* conditions we've observed that the send will succeed after 2-3118* attempts but this depends on network buffers associated with119* other sockets draining.120*/121if (WSAGetLastError() == WSAENOBUFS) {122if (llen > MAX_BUFFER_LEN) {123buflen = MAX_BUFFER_LEN;124chunkLen = MAX_BUFFER_LEN;125llen = MAX_BUFFER_LEN;126continue;127}128if (retry >= 30) {129JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",130"No buffer space available - exhausted attempts to queue buffer");131if (bufP != BUF) {132free(bufP);133}134return;135}136Sleep(1000);137retry++;138continue;139}140141/*142* Send failed - can be caused by close or write error.143*/144if (WSAGetLastError() == WSAENOTSOCK) {145JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");146} else {147NET_ThrowCurrent(env, "socket write error");148}149if (bufP != BUF) {150free(bufP);151}152return;153}154len -= chunkLen;155off += chunkLen;156}157}158159if (bufP != BUF) {160free(bufP);161}162}163164165