Path: blob/master/src/java.rmi/share/classes/sun/rmi/transport/ConnectionInputStream.java
41154 views
/*1* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package sun.rmi.transport;2526import java.io.*;27import java.util.*;28import java.rmi.RemoteException;29import java.rmi.server.UID;30import sun.rmi.server.MarshalInputStream;31import sun.rmi.runtime.Log;3233/**34* Special stream to keep track of refs being unmarshaled so that35* refs can be ref-counted locally.36*37* @author Ann Wollrath38*/39class ConnectionInputStream extends MarshalInputStream {4041/** indicates whether ack is required for DGC */42private boolean dgcAckNeeded = false;4344/** Hashtable mapping Endpoints to lists of LiveRefs to register */45private Map<Endpoint, List<LiveRef>> incomingRefTable = new HashMap<>(5);4647/** identifier for gc ack*/48private UID ackID;4950/**51* Constructs a marshal input stream using the underlying52* stream "in".53*/54ConnectionInputStream(InputStream in) throws IOException {55super(in);56}5758void readID() throws IOException {59ackID = UID.read((DataInput) this);60}6162/**63* Save reference in order to send "dirty" call after all args/returns64* have been unmarshaled. Save in hashtable incomingRefTable. This65* table is keyed on endpoints, and holds objects of type66* IncomingRefTableEntry.67*/68void saveRef(LiveRef ref) {69Endpoint ep = ref.getEndpoint();7071// check whether endpoint is already in the hashtable72List<LiveRef> refList = incomingRefTable.get(ep);7374if (refList == null) {75refList = new ArrayList<LiveRef>();76incomingRefTable.put(ep, refList);77}7879// add ref to list of refs for endpoint ep80refList.add(ref);81}8283/**84* Discard the saved incoming refs so there is nothing to register85* when {@code registerRefs} is called.86*/87void discardRefs() {88incomingRefTable.clear();89}9091/**92* Add references to DGC table (and possibly send dirty call).93* RegisterRefs now calls DGCClient.referenced on all94* refs with the same endpoint at once to achieve batching of95* calls to the DGC96*/97void registerRefs() throws IOException {98if (!incomingRefTable.isEmpty()) {99for (Map.Entry<Endpoint, List<LiveRef>> entry :100incomingRefTable.entrySet()) {101DGCClient.registerRefs(entry.getKey(), entry.getValue());102}103}104}105106/**107* Indicate that an ack is required to the distributed108* collector.109*/110void setAckNeeded() {111dgcAckNeeded = true;112}113114/**115* Done with input stream for remote call. Send DGC ack if necessary.116* Allow sending of ack to fail without flagging an error.117*/118void done(Connection c) {119/*120* WARNING: The connection c may have already been freed. It121* is only be safe to use c to obtain c's channel.122*/123124if (dgcAckNeeded) {125Connection conn = null;126Channel ch = null;127boolean reuse = true;128129DGCImpl.dgcLog.log(Log.VERBOSE, "send ack");130131try {132ch = c.getChannel();133conn = ch.newConnection();134DataOutputStream out =135new DataOutputStream(conn.getOutputStream());136out.writeByte(TransportConstants.DGCAck);137if (ackID == null) {138ackID = new UID();139}140ackID.write((DataOutput) out);141conn.releaseOutputStream();142143/*144* Fix for 4221173: if this connection is on top of an145* HttpSendSocket, the DGCAck won't actually get sent until a146* read operation is attempted on the socket. Calling147* available() is the most innocuous way of triggering the148* write.149*/150conn.getInputStream().available();151conn.releaseInputStream();152} catch (RemoteException e) {153reuse = false;154} catch (IOException e) {155reuse = false;156}157try {158if (conn != null)159ch.free(conn, reuse);160} catch (RemoteException e){161// eat exception162}163}164}165}166167168