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