~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/java/net/SocketOutputStream.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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.
 
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
package java.net;
 
27
 
 
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.*;
 
34
 
 
35
/**
 
36
 * This stream extends FileOutputStream to implement a
 
37
 * SocketOutputStream. Note that this class should <b>NOT</b> be
 
38
 * public.
 
39
 *
 
40
 * @author      Jonathan Payne
 
41
 * @author      Arthur van Hoff
 
42
 * @author      Jeroen Frijters
 
43
 */
 
44
class SocketOutputStream extends FileOutputStream
 
45
{
 
46
    private AbstractPlainSocketImpl impl = null;
 
47
    private byte temp[] = new byte[1];
 
48
    private Socket socket = null;
 
49
 
 
50
    /**
 
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
 
55
     */
 
56
    SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
 
57
        super(impl.getFileDescriptor());
 
58
        this.impl = impl;
 
59
        socket = impl.getSocket();
 
60
    }
 
61
 
 
62
    /**
 
63
     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
 
64
     * object associated with this file output stream. </p>
 
65
     *
 
66
     * The <code>getChannel</code> method of <code>SocketOutputStream</code>
 
67
     * returns <code>null</code> since it is a socket based stream.</p>
 
68
     *
 
69
     * @return  the file channel associated with this file output stream
 
70
     *
 
71
     * @since 1.4
 
72
     * @spec JSR-51
 
73
     */
 
74
    public final FileChannel getChannel() {
 
75
        return null;
 
76
    }
 
77
 
 
78
    /**
 
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.
 
85
     */
 
86
    private void socketWrite0(FileDescriptor fdObj, byte[] data, int off, int len) throws IOException
 
87
    {
 
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
 
92
        int n;
 
93
 
 
94
        if (IS_NULL(fdObj)) {
 
95
            throw new SocketException("socket closed");
 
96
        } else {
 
97
            fd = fdObj.getSocket();
 
98
        }
 
99
        if (IS_NULL(data)) {
 
100
            throw new NullPointerException("data argument");
 
101
        }
 
102
        
 
103
        while(len > 0) {
 
104
            int loff = 0;
 
105
            int chunkLen = Math.min(buflen, len);
 
106
            int llen = chunkLen;
 
107
            int retry = 0;
 
108
 
 
109
            while(llen > 0) {
 
110
                n = send(fd, data, off + loff, llen, 0);
 
111
                if (n > 0) {
 
112
                    llen -= n;
 
113
                    loff += n;
 
114
                    continue;
 
115
                }
 
116
 
 
117
                /*
 
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.
 
132
                 */
 
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;
 
138
                        continue;
 
139
                    }
 
140
                    if (retry >= 30) {
 
141
                        throw new SocketException("No buffer space available - exhausted attempts to queue buffer");
 
142
                    }
 
143
                    cli.System.Threading.Thread.Sleep(1000);
 
144
                    retry++;
 
145
                    continue;
 
146
                }
 
147
 
 
148
                /*
 
149
                 * Send failed - can be caused by close or write error.
 
150
                 */
 
151
                if (WSAGetLastError() == WSAENOTSOCK) {
 
152
                    throw new SocketException("Socket closed");
 
153
                } else {
 
154
                    throw NET_ThrowCurrent("socket write error");
 
155
                }
 
156
            }
 
157
            len -= chunkLen;
 
158
            off += chunkLen;
 
159
        }
 
160
    }
 
161
 
 
162
    /**
 
163
     * Writes to the socket with appropriate locking of the
 
164
     * FileDescriptor.
 
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.
 
169
     */
 
170
    private void socketWrite(byte b[], int off, int len) throws IOException {
 
171
 
 
172
        if (len <= 0 || off < 0 || off + len > b.length) {
 
173
            if (len == 0) {
 
174
                return;
 
175
            }
 
176
            throw new ArrayIndexOutOfBoundsException();
 
177
        }
 
178
 
 
179
        FileDescriptor fd = impl.acquireFD();
 
180
        try {
 
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");
 
186
            }
 
187
            if (impl.isClosedOrPending()) {
 
188
                throw new SocketException("Socket closed");
 
189
            } else {
 
190
                throw se;
 
191
            }
 
192
        } finally {
 
193
            impl.releaseFD();
 
194
        }
 
195
    }
 
196
 
 
197
    /**
 
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.
 
201
     */
 
202
    public void write(int b) throws IOException {
 
203
        temp[0] = (byte)b;
 
204
        socketWrite(temp, 0, 1);
 
205
    }
 
206
 
 
207
    /**
 
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.
 
211
     */
 
212
    public void write(byte b[]) throws IOException {
 
213
        socketWrite(b, 0, b.length);
 
214
    }
 
215
 
 
216
    /**
 
217
     * Writes <i>length</i> bytes from buffer <i>b</i> starting at
 
218
     * offset <i>len</i>.
 
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.
 
223
     */
 
224
    public void write(byte b[], int off, int len) throws IOException {
 
225
        socketWrite(b, off, len);
 
226
    }
 
227
 
 
228
    /**
 
229
     * Closes the stream.
 
230
     */
 
231
    private boolean closing = false;
 
232
    public void close() throws IOException {
 
233
        // Prevent recursion. See BugId 4484411
 
234
        if (closing)
 
235
            return;
 
236
        closing = true;
 
237
        if (socket != null) {
 
238
            if (!socket.isClosed())
 
239
                socket.close();
 
240
        } else
 
241
            impl.close();
 
242
        closing = false;
 
243
    }
 
244
 
 
245
    /**
 
246
     * Overrides finalize, the fd is closed by the Socket.
 
247
     */
 
248
    protected void finalize() {}
 
249
}