1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1995, 2016, 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 
36 /**
37  * This stream extends FileOutputStream to implement a
38  * SocketOutputStream. Note that this class should <b>NOT</b> be
39  * public.
40  *
41  * @author      Jonathan Payne
42  * @author      Arthur van Hoff
43  */
44 class SocketOutputStream extends FileOutputStream
45 {
46     // Android-removed: Android doesn't need to call native init.
47     // static {
48     //    init();
49     //}
50 
51     private AbstractPlainSocketImpl impl = null;
52     private byte temp[] = new byte[1];
53     private Socket socket = null;
54 
55     /**
56      * Creates a new SocketOutputStream. Can only be called
57      * by a Socket. This method needs to hang on to the owner Socket so
58      * that the fd will not be closed.
59      * @param impl the socket output stream inplemented
60      */
SocketOutputStream(AbstractPlainSocketImpl impl)61     SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
62         super(impl.getFileDescriptor());
63         this.impl = impl;
64         socket = impl.getSocket();
65     }
66 
67     /**
68      * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
69      * object associated with this file output stream. </p>
70      *
71      * The {@code getChannel} method of {@code SocketOutputStream}
72      * returns {@code null} since it is a socket based stream.</p>
73      *
74      * @return  the file channel associated with this file output stream
75      *
76      * @since 1.4
77      * @spec JSR-51
78      */
getChannel()79     public final FileChannel getChannel() {
80         return null;
81     }
82 
83     /**
84      * Writes to the socket.
85      * @param fd the FileDescriptor
86      * @param b the data to be written
87      * @param off the start offset in the data
88      * @param len the number of bytes that are written
89      * @exception IOException If an I/O error has occurred.
90      */
socketWrite0(FileDescriptor fd, byte[] b, int off, int len)91     private native void socketWrite0(FileDescriptor fd, byte[] b, int off,
92                                      int len) throws IOException;
93 
94     /**
95      * Writes to the socket with appropriate locking of the
96      * FileDescriptor.
97      * @param b the data to be written
98      * @param off the start offset in the data
99      * @param len the number of bytes that are written
100      * @exception IOException If an I/O error has occurred.
101      */
socketWrite(byte b[], int off, int len)102     private void socketWrite(byte b[], int off, int len) throws IOException {
103 
104 
105         if (len <= 0 || off < 0 || len > b.length - off) {
106             if (len == 0) {
107                 return;
108             }
109             throw new ArrayIndexOutOfBoundsException("len == " + len
110                     + " off == " + off + " buffer length == " + b.length);
111         }
112 
113         FileDescriptor fd = impl.acquireFD();
114         try {
115             // Android-added: Check BlockGuard policy in socketWrite.
116             BlockGuard.getThreadPolicy().onNetwork();
117             socketWrite0(fd, b, off, len);
118         } catch (SocketException se) {
119             if (se instanceof sun.net.ConnectionResetException) {
120                 impl.setConnectionResetPending();
121                 se = new SocketException("Connection reset");
122             }
123             if (impl.isClosedOrPending()) {
124                 throw new SocketException("Socket closed");
125             } else {
126                 throw se;
127             }
128         } finally {
129             impl.releaseFD();
130         }
131     }
132 
133     /**
134      * Writes a byte to the socket.
135      * @param b the data to be written
136      * @exception IOException If an I/O error has occurred.
137      */
write(int b)138     public void write(int b) throws IOException {
139         temp[0] = (byte)b;
140         socketWrite(temp, 0, 1);
141     }
142 
143     /**
144      * Writes the contents of the buffer <i>b</i> to the socket.
145      * @param b the data to be written
146      * @exception SocketException If an I/O error has occurred.
147      */
write(byte b[])148     public void write(byte b[]) throws IOException {
149         socketWrite(b, 0, b.length);
150     }
151 
152     /**
153      * Writes <i>length</i> bytes from buffer <i>b</i> starting at
154      * offset <i>len</i>.
155      * @param b the data to be written
156      * @param off the start offset in the data
157      * @param len the number of bytes that are written
158      * @exception SocketException If an I/O error has occurred.
159      */
write(byte b[], int off, int len)160     public void write(byte b[], int off, int len) throws IOException {
161         socketWrite(b, off, len);
162     }
163 
164     /**
165      * Closes the stream.
166      */
167     private boolean closing = false;
close()168     public void close() throws IOException {
169         // Prevent recursion. See BugId 4484411
170         if (closing)
171             return;
172         closing = true;
173         if (socket != null) {
174             if (!socket.isClosed())
175                 socket.close();
176         } else
177             impl.close();
178         closing = false;
179     }
180 
181     /**
182      * Overrides finalize, the fd is closed by the Socket.
183      */
finalize()184     protected void finalize() {}
185 
186     // Android-removed: Android doesn't need native init.
187     /*
188      * Perform class load-time initializations.
189      *
190     private native static void init();
191     */
192 }
193