Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/java/net/SocketOutputStream.c
32287 views
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
26
#include <windows.h>
27
#include <winsock2.h>
28
#include <ctype.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <malloc.h>
32
#include <sys/types.h>
33
34
#include "java_net_SocketOutputStream.h"
35
36
#include "net_util.h"
37
#include "jni_util.h"
38
39
/************************************************************************
40
* SocketOutputStream
41
*/
42
static jfieldID IO_fd_fdID;
43
44
/*
45
* Class: java_net_SocketOutputStream
46
* Method: init
47
* Signature: ()V
48
*/
49
JNIEXPORT void JNICALL
50
Java_java_net_SocketOutputStream_init(JNIEnv *env, jclass cls) {
51
IO_fd_fdID = NET_GetFileDescriptorID(env);
52
}
53
54
/*
55
* Class: java_net_SocketOutputStream
56
* Method: socketWrite
57
* Signature: (Ljava/io/FileDescriptor;[BII)V
58
*/
59
JNIEXPORT void JNICALL
60
Java_java_net_SocketOutputStream_socketWrite0(JNIEnv *env, jobject this,
61
jobject fdObj, jbyteArray data,
62
jint off, jint len) {
63
char *bufP;
64
char BUF[MAX_BUFFER_LEN];
65
int buflen;
66
int fd;
67
68
if (IS_NULL(fdObj)) {
69
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
70
return;
71
} else {
72
fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
73
}
74
if (IS_NULL(data)) {
75
JNU_ThrowNullPointerException(env, "data argument");
76
return;
77
}
78
79
/*
80
* Use stack allocate buffer if possible. For large sizes we allocate
81
* an intermediate buffer from the heap (up to a maximum). If heap is
82
* unavailable just use our stack buffer.
83
*/
84
if (len <= MAX_BUFFER_LEN) {
85
bufP = BUF;
86
buflen = MAX_BUFFER_LEN;
87
} else {
88
buflen = min(MAX_HEAP_BUFFER_LEN, len);
89
bufP = (char *)malloc((size_t)buflen);
90
if (bufP == NULL) {
91
bufP = BUF;
92
buflen = MAX_BUFFER_LEN;
93
}
94
}
95
96
while(len > 0) {
97
int loff = 0;
98
int chunkLen = min(buflen, len);
99
int llen = chunkLen;
100
int retry = 0;
101
102
(*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
103
if ((*env)->ExceptionCheck(env)) {
104
break;
105
} else {
106
while(llen > 0) {
107
int n = send(fd, bufP + loff, llen, 0);
108
if (n > 0) {
109
llen -= n;
110
loff += n;
111
continue;
112
}
113
114
/*
115
* Due to a bug in Windows Sockets (observed on NT and Windows
116
* 2000) it may be necessary to retry the send. The issue is that
117
* on blocking sockets send/WSASend is supposed to block if there
118
* is insufficient buffer space available. If there are a large
119
* number of threads blocked on write due to congestion then it's
120
* possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
121
* The workaround we use is to retry the send. If we have a
122
* large buffer to send (>2k) then we retry with a maximum of
123
* 2k buffer. If we hit the issue with <=2k buffer then we backoff
124
* for 1 second and retry again. We repeat this up to a reasonable
125
* limit before bailing out and throwing an exception. In load
126
* conditions we've observed that the send will succeed after 2-3
127
* attempts but this depends on network buffers associated with
128
* other sockets draining.
129
*/
130
if (WSAGetLastError() == WSAENOBUFS) {
131
if (llen > MAX_BUFFER_LEN) {
132
buflen = MAX_BUFFER_LEN;
133
chunkLen = MAX_BUFFER_LEN;
134
llen = MAX_BUFFER_LEN;
135
continue;
136
}
137
if (retry >= 30) {
138
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
139
"No buffer space available - exhausted attempts to queue buffer");
140
if (bufP != BUF) {
141
free(bufP);
142
}
143
return;
144
}
145
Sleep(1000);
146
retry++;
147
continue;
148
}
149
150
/*
151
* Send failed - can be caused by close or write error.
152
*/
153
if (WSAGetLastError() == WSAENOTSOCK) {
154
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
155
} else {
156
NET_ThrowCurrent(env, "socket write error");
157
}
158
if (bufP != BUF) {
159
free(bufP);
160
}
161
return;
162
}
163
len -= chunkLen;
164
off += chunkLen;
165
}
166
}
167
168
if (bufP != BUF) {
169
free(bufP);
170
}
171
}
172
173