Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/net/SocketOutputStream.c
32287 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*/2425#include <windows.h>26#include <winsock2.h>27#include <ctype.h>28#include <stdio.h>29#include <stdlib.h>30#include <malloc.h>31#include <sys/types.h>3233#include "java_net_SocketOutputStream.h"3435#include "net_util.h"36#include "jni_util.h"3738/************************************************************************39* SocketOutputStream40*/41static jfieldID IO_fd_fdID;4243/*44* Class: java_net_SocketOutputStream45* Method: init46* Signature: ()V47*/48JNIEXPORT void JNICALL49Java_java_net_SocketOutputStream_init(JNIEnv *env, jclass cls) {50IO_fd_fdID = NET_GetFileDescriptorID(env);51}5253/*54* Class: java_net_SocketOutputStream55* Method: socketWrite56* Signature: (Ljava/io/FileDescriptor;[BII)V57*/58JNIEXPORT void JNICALL59Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,60jobject fdObj, jbyteArray data,61jint off, jint len) {62char *bufP;63char BUF[MAX_BUFFER_LEN];64int buflen;65int fd;6667if (IS_NULL(fdObj)) {68JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");69return;70} else {71fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);72}73if (IS_NULL(data)) {74JNU_ThrowNullPointerException(env, "data argument");75return;76}7778/*79* Use stack allocate buffer if possible. For large sizes we allocate80* an intermediate buffer from the heap (up to a maximum). If heap is81* unavailable just use our stack buffer.82*/83if (len <= MAX_BUFFER_LEN) {84bufP = BUF;85buflen = MAX_BUFFER_LEN;86} else {87buflen = min(MAX_HEAP_BUFFER_LEN, len);88bufP = (char *)malloc((size_t)buflen);89if (bufP == NULL) {90bufP = BUF;91buflen = MAX_BUFFER_LEN;92}93}9495while(len > 0) {96int loff = 0;97int chunkLen = min(buflen, len);98int llen = chunkLen;99int retry = 0;100101(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);102if ((*env)->ExceptionCheck(env)) {103break;104} else {105while(llen > 0) {106int n = send(fd, bufP + loff, llen, 0);107if (n > 0) {108llen -= n;109loff += n;110continue;111}112113/*114* Due to a bug in Windows Sockets (observed on NT and Windows115* 2000) it may be necessary to retry the send. The issue is that116* on blocking sockets send/WSASend is supposed to block if there117* is insufficient buffer space available. If there are a large118* number of threads blocked on write due to congestion then it's119* possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.120* The workaround we use is to retry the send. If we have a121* large buffer to send (>2k) then we retry with a maximum of122* 2k buffer. If we hit the issue with <=2k buffer then we backoff123* for 1 second and retry again. We repeat this up to a reasonable124* limit before bailing out and throwing an exception. In load125* conditions we've observed that the send will succeed after 2-3126* attempts but this depends on network buffers associated with127* other sockets draining.128*/129if (WSAGetLastError() == WSAENOBUFS) {130if (llen > MAX_BUFFER_LEN) {131buflen = MAX_BUFFER_LEN;132chunkLen = MAX_BUFFER_LEN;133llen = MAX_BUFFER_LEN;134continue;135}136if (retry >= 30) {137JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",138"No buffer space available - exhausted attempts to queue buffer");139if (bufP != BUF) {140free(bufP);141}142return;143}144Sleep(1000);145retry++;146continue;147}148149/*150* Send failed - can be caused by close or write error.151*/152if (WSAGetLastError() == WSAENOTSOCK) {153JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");154} else {155NET_ThrowCurrent(env, "socket write error");156}157if (bufP != BUF) {158free(bufP);159}160return;161}162len -= chunkLen;163off += chunkLen;164}165}166167if (bufP != BUF) {168free(bufP);169}170}171172173