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