2
* Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
28
import java.io.FileDescriptor;
29
import java.io.FileOutputStream;
30
import java.io.IOException;
31
import java.nio.channels.FileChannel;
32
import static ikvm.internal.Winsock.*;
33
import static java.net.net_util_md.*;
36
* This stream extends FileOutputStream to implement a
37
* SocketOutputStream. Note that this class should <b>NOT</b> be
40
* @author Jonathan Payne
41
* @author Arthur van Hoff
42
* @author Jeroen Frijters
44
class SocketOutputStream extends FileOutputStream
46
private AbstractPlainSocketImpl impl = null;
47
private byte temp[] = new byte[1];
48
private Socket socket = null;
51
* Creates a new SocketOutputStream. Can only be called
52
* by a Socket. This method needs to hang on to the owner Socket so
53
* that the fd will not be closed.
54
* @param impl the socket output stream inplemented
56
SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
57
super(impl.getFileDescriptor());
59
socket = impl.getSocket();
63
* Returns the unique {@link java.nio.channels.FileChannel FileChannel}
64
* object associated with this file output stream. </p>
66
* The <code>getChannel</code> method of <code>SocketOutputStream</code>
67
* returns <code>null</code> since it is a socket based stream.</p>
69
* @return the file channel associated with this file output stream
74
public final FileChannel getChannel() {
79
* Writes to the socket.
80
* @param fd the FileDescriptor
81
* @param b the data to be written
82
* @param off the start offset in the data
83
* @param len the number of bytes that are written
84
* @exception IOException If an I/O error has occurred.
86
private void socketWrite0(FileDescriptor fdObj, byte[] data, int off, int len) throws IOException
88
// [IKVM] this method is a direct port of the native code in openjdk6-b18\jdk\src\windows\native\java\net\SocketOutputStream.c
89
final int MAX_BUFFER_LEN = 2048;
90
cli.System.Net.Sockets.Socket fd;
91
int buflen = 65536; // MAX_HEAP_BUFFER_LEN
95
throw new SocketException("socket closed");
97
fd = fdObj.getSocket();
100
throw new NullPointerException("data argument");
105
int chunkLen = Math.min(buflen, len);
110
n = send(fd, data, off + loff, llen, 0);
118
* Due to a bug in Windows Sockets (observed on NT and Windows
119
* 2000) it may be necessary to retry the send. The issue is that
120
* on blocking sockets send/WSASend is supposed to block if there
121
* is insufficient buffer space available. If there are a large
122
* number of threads blocked on write due to congestion then it's
123
* possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
124
* The workaround we use is to retry the send. If we have a
125
* large buffer to send (>2k) then we retry with a maximum of
126
* 2k buffer. If we hit the issue with <=2k buffer then we backoff
127
* for 1 second and retry again. We repeat this up to a reasonable
128
* limit before bailing out and throwing an exception. In load
129
* conditions we've observed that the send will succeed after 2-3
130
* attempts but this depends on network buffers associated with
131
* other sockets draining.
133
if (WSAGetLastError() == WSAENOBUFS) {
134
if (llen > MAX_BUFFER_LEN) {
135
buflen = MAX_BUFFER_LEN;
136
chunkLen = MAX_BUFFER_LEN;
137
llen = MAX_BUFFER_LEN;
141
throw new SocketException("No buffer space available - exhausted attempts to queue buffer");
143
cli.System.Threading.Thread.Sleep(1000);
149
* Send failed - can be caused by close or write error.
151
if (WSAGetLastError() == WSAENOTSOCK) {
152
throw new SocketException("Socket closed");
154
throw NET_ThrowCurrent("socket write error");
163
* Writes to the socket with appropriate locking of the
165
* @param b the data to be written
166
* @param off the start offset in the data
167
* @param len the number of bytes that are written
168
* @exception IOException If an I/O error has occurred.
170
private void socketWrite(byte b[], int off, int len) throws IOException {
172
if (len <= 0 || off < 0 || off + len > b.length) {
176
throw new ArrayIndexOutOfBoundsException();
179
FileDescriptor fd = impl.acquireFD();
181
socketWrite0(fd, b, off, len);
182
} catch (SocketException se) {
183
if (se instanceof sun.net.ConnectionResetException) {
184
impl.setConnectionResetPending();
185
se = new SocketException("Connection reset");
187
if (impl.isClosedOrPending()) {
188
throw new SocketException("Socket closed");
198
* Writes a byte to the socket.
199
* @param b the data to be written
200
* @exception IOException If an I/O error has occurred.
202
public void write(int b) throws IOException {
204
socketWrite(temp, 0, 1);
208
* Writes the contents of the buffer <i>b</i> to the socket.
209
* @param b the data to be written
210
* @exception SocketException If an I/O error has occurred.
212
public void write(byte b[]) throws IOException {
213
socketWrite(b, 0, b.length);
217
* Writes <i>length</i> bytes from buffer <i>b</i> starting at
219
* @param b the data to be written
220
* @param off the start offset in the data
221
* @param len the number of bytes that are written
222
* @exception SocketException If an I/O error has occurred.
224
public void write(byte b[], int off, int len) throws IOException {
225
socketWrite(b, off, len);
231
private boolean closing = false;
232
public void close() throws IOException {
233
// Prevent recursion. See BugId 4484411
237
if (socket != null) {
238
if (!socket.isClosed())
246
* Overrides finalize, the fd is closed by the Socket.
248
protected void finalize() {}