1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.net;
28 
29 import java.io.FileDescriptor;
30 import java.io.FileOutputStream;
31 import java.io.IOException;
32 import java.nio.channels.FileChannel;
33 
34 import dalvik.system.BlockGuard;
35 import sun.misc.IoTrace;
36 
37 /**
38  * This stream extends FileOutputStream to implement a
39  * SocketOutputStream. Note that this class should <b>NOT</b> be
40  * public.
41  *
42  * @author      Jonathan Payne
43  * @author      Arthur van Hoff
44  */
45 class SocketOutputStream extends FileOutputStream
46 {
47     private AbstractPlainSocketImpl impl = null;
48     private byte temp[] = new byte[1];
49     private Socket socket = null;
50 
51     /**
52      * Creates a new SocketOutputStream. Can only be called
53      * by a Socket. This method needs to hang on to the owner Socket so
54      * that the fd will not be closed.
55      * @param impl the socket output stream inplemented
56      */
SocketOutputStream(AbstractPlainSocketImpl impl)57     SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
58         super(impl.getFileDescriptor());
59         this.impl = impl;
60         socket = impl.getSocket();
61     }
62 
63     /**
64      * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
65      * object associated with this file output stream. </p>
66      *
67      * The <code>getChannel</code> method of <code>SocketOutputStream</code>
68      * returns <code>null</code> since it is a socket based stream.</p>
69      *
70      * @return  the file channel associated with this file output stream
71      *
72      * @since 1.4
73      * @spec JSR-51
74      */
getChannel()75     public final FileChannel getChannel() {
76         return null;
77     }
78 
79     /**
80      * Writes to the socket.
81      * @param fd the FileDescriptor
82      * @param b the data to be written
83      * @param off the start offset in the data
84      * @param len the number of bytes that are written
85      * @exception IOException If an I/O error has occurred.
86      */
socketWrite0(FileDescriptor fd, byte[] b, int off, int len)87     private native void socketWrite0(FileDescriptor fd, byte[] b, int off,
88                                      int len) throws IOException;
89 
90     /**
91      * Writes to the socket with appropriate locking of the
92      * FileDescriptor.
93      * @param b the data to be written
94      * @param off the start offset in the data
95      * @param len the number of bytes that are written
96      * @exception IOException If an I/O error has occurred.
97      */
socketWrite(byte b[], int off, int len)98     private void socketWrite(byte b[], int off, int len) throws IOException {
99 
100         if (len <= 0 || off < 0 || off + len > b.length) {
101             if (len == 0) {
102                 return;
103             }
104             throw new ArrayIndexOutOfBoundsException();
105         }
106 
107         Object traceContext = IoTrace.socketWriteBegin();
108         int bytesWritten = 0;
109         FileDescriptor fd = impl.acquireFD();
110         try {
111             BlockGuard.getThreadPolicy().onNetwork();
112             socketWrite0(fd, b, off, len);
113             bytesWritten = len;
114         } catch (SocketException se) {
115             if (se instanceof sun.net.ConnectionResetException) {
116                 impl.setConnectionResetPending();
117                 se = new SocketException("Connection reset");
118             }
119             if (impl.isClosedOrPending()) {
120                 throw new SocketException("Socket closed");
121             } else {
122                 throw se;
123             }
124         } finally {
125             IoTrace.socketWriteEnd(traceContext, impl.address, impl.port, bytesWritten);
126         }
127     }
128 
129     /**
130      * Writes a byte to the socket.
131      * @param b the data to be written
132      * @exception IOException If an I/O error has occurred.
133      */
write(int b)134     public void write(int b) throws IOException {
135         temp[0] = (byte)b;
136         socketWrite(temp, 0, 1);
137     }
138 
139     /**
140      * Writes the contents of the buffer <i>b</i> to the socket.
141      * @param b the data to be written
142      * @exception SocketException If an I/O error has occurred.
143      */
write(byte b[])144     public void write(byte b[]) throws IOException {
145         socketWrite(b, 0, b.length);
146     }
147 
148     /**
149      * Writes <i>length</i> bytes from buffer <i>b</i> starting at
150      * offset <i>len</i>.
151      * @param b the data to be written
152      * @param off the start offset in the data
153      * @param len the number of bytes that are written
154      * @exception SocketException If an I/O error has occurred.
155      */
write(byte b[], int off, int len)156     public void write(byte b[], int off, int len) throws IOException {
157         socketWrite(b, off, len);
158     }
159 
160     /**
161      * Closes the stream.
162      */
163     private boolean closing = false;
close()164     public void close() throws IOException {
165         // Prevent recursion. See BugId 4484411
166         if (closing)
167             return;
168         closing = true;
169         if (socket != null) {
170             if (!socket.isClosed())
171                 socket.close();
172         } else
173             impl.close();
174         closing = false;
175     }
176 
177     /**
178      * Overrides finalize, the fd is closed by the Socket.
179      */
finalize()180     protected void finalize() {}
181 }
182