1. /*
  2. * @(#)IIOPConnection.java 1.124 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * Licensed Materials - Property of IBM
  9. * RMI-IIOP v1.0
  10. * Copyright IBM Corp. 1998 1999 All Rights Reserved
  11. *
  12. * US Government Users Restricted Rights - Use, duplication or
  13. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  14. */
  15. package com.sun.corba.se.internal.iiop;
  16. import java.util.Hashtable;
  17. import java.util.Enumeration;
  18. import java.util.Vector;
  19. import java.util.*; // Once we get beyond 5 does it make sense to do otherwise?
  20. import java.net.ServerSocket;
  21. import java.net.Socket;
  22. import java.net.InetAddress;
  23. import java.net.SocketException;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.io.OutputStream;
  27. import org.omg.CORBA.SystemException;
  28. import org.omg.CORBA.CompletionStatus;
  29. import org.omg.CORBA.COMM_FAILURE;
  30. import org.omg.CORBA.INTERNAL;
  31. import org.omg.CORBA.Object;
  32. import com.sun.org.omg.SendingContext.CodeBase;
  33. import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
  34. import com.sun.corba.se.internal.core.ServerGIOP;
  35. import com.sun.corba.se.internal.core.EndPoint;
  36. import com.sun.corba.se.internal.core.RequestHandler;
  37. import com.sun.corba.se.internal.core.IOR;
  38. import com.sun.corba.se.internal.core.ServerRequest;
  39. import com.sun.corba.se.internal.core.MarshalOutputStream;
  40. import com.sun.corba.se.internal.orbutil.MinorCodes;
  41. import com.sun.corba.se.internal.core.GIOPVersion;
  42. import com.sun.corba.se.internal.orbutil.Condition;
  43. import com.sun.corba.se.internal.orbutil.Lock;
  44. import com.sun.corba.se.internal.iiop.messages.Message;
  45. import com.sun.corba.se.internal.iiop.messages.MessageBase;
  46. import com.sun.corba.se.internal.iiop.messages.RequestMessage;
  47. import com.sun.corba.se.internal.iiop.messages.ReplyMessage;
  48. import com.sun.corba.se.internal.iiop.messages.FragmentMessage;
  49. import java.security.AccessController;
  50. import java.security.PrivilegedAction;
  51. /**
  52. * A network connection which processes IIOP messages.
  53. */
  54. public final class IIOPConnection extends Connection
  55. {
  56. final static class OutCallDesc
  57. {
  58. java.lang.Object done = new java.lang.Object();
  59. Thread thd;
  60. SystemException exc;
  61. IIOPInputStream s;
  62. }
  63. final static class DeleteConn extends java.lang.Throwable {
  64. int minorCode;
  65. DeleteConn (int code) {
  66. minorCode = code;
  67. }
  68. }
  69. //
  70. // Connection status
  71. //
  72. private static final int OPENING = 1;
  73. private static final int ESTABLISHED = 2;
  74. private static final int CLOSE_SENT = 3;
  75. private static final int CLOSE_RECVD = 4;
  76. private static final int ABORT = 5;
  77. //
  78. // Table of pending invocations on this connection indexed by
  79. // Integer(requestId). These are only relevant if this is
  80. // a client.
  81. //
  82. // The clientReplyMap maps request ID to an IIOPInputStream.
  83. // The out_calls map request ID to an OutCallDesc.
  84. // This is so the client thread can start unmarshaling
  85. // the reply and remove it from the out_calls map while the
  86. // ReaderThread can still obtain the input stream to give
  87. // new fragments. Only the ReaderThread touches the clientReplyMap,
  88. // so it doesn't incur synchronization overhead.
  89. //
  90. Hashtable out_calls = null;
  91. ClientResponseImpl theOnly1_1ClientResponseImpl = null;
  92. Map clientReplyMap = null;
  93. // This map allows the ORB to ask "have any fragments
  94. // been sent?" if it catches an exception after already
  95. // sending at least one fragment and before the last is sent.
  96. // This can happen on both the client and server side.
  97. // We want a synchronized Hashtable.
  98. Hashtable idToFragmentedOutputStream;
  99. private MessageMediator mediator;
  100. //
  101. // Remote address that we're talking to.
  102. //
  103. private String threadName;
  104. protected EndPoint endpoint;
  105. protected int requestCount = 0;
  106. private ServerGIOP server;
  107. // Server request map: used on the server side of Connection
  108. // Maps request ID to IIOPInputStream.
  109. Map serverRequestMap = null;
  110. ServerRequestImpl theOnly1_1ServerRequestImpl = null;
  111. // This is a flag associated per connection telling us if the initial set of
  112. // sending contexts were sent to the receiver already...
  113. private boolean postInitialContexts = false;
  114. // Remote reference to CodeBase server (supplies FullValueDescription, among other things)
  115. private IOR codeBaseServerIOR;
  116. // CodeBase cache for this connection. This will cache remote operations,
  117. // handle connecting, and ensure we don't do any remote operations until
  118. // necessary.
  119. private CachedCodeBase cachedCodeBase = new CachedCodeBase(this);
  120. private String getStateString( int state )
  121. {
  122. synchronized ( stateEvent ){
  123. switch (state) {
  124. case OPENING : return "OPENING" ;
  125. case ESTABLISHED : return "ESTABLISHED" ;
  126. case CLOSE_SENT : return "CLOSE_SENT" ;
  127. case CLOSE_RECVD : return "CLOSE_RECVD" ;
  128. case ABORT : return "ABORT" ;
  129. default : return "???" ;
  130. }
  131. }
  132. }
  133. public String toString()
  134. {
  135. synchronized ( stateEvent ){
  136. return
  137. "Connection[" +
  138. "type=" + endpoint.getType() +
  139. " remote_host=" + endpoint.getHostName() +
  140. " remote_port=" + endpoint.getPort() +
  141. " state=" + getStateString( state ) + "]" ;
  142. }
  143. }
  144. //
  145. // Various connection state.
  146. //
  147. Thread reader;
  148. int state;
  149. private java.lang.Object stateEvent = new java.lang.Object();
  150. private java.lang.Object writeEvent = new java.lang.Object();
  151. private boolean writeLocked;
  152. // These I/O streams are the ONLY ONES that should be used.
  153. // i.e. Do not directly use the input/output streams that socket gives.
  154. // This restriction is to allow connections to service multiple
  155. // protocols (e.g. http for tunneling), which may require the
  156. // socket's streams to be wrapped in other streams.
  157. InputStream inputStream;
  158. OutputStream outputStream;
  159. /**
  160. * Called after client creates a connection to server
  161. * or after server accepts an incoming connection.
  162. * @param host The remote host pointed to by this connection.
  163. * @param port The remote port used by this connection.
  164. */
  165. public IIOPConnection(ORB orb, ServerGIOP server,
  166. ConnectionTable ctab, EndPoint ep)
  167. {
  168. this.orb = orb;
  169. this.server = server;
  170. this.connectionTable = ctab;
  171. this.endpoint = ep;
  172. this.codeBaseServerIOR = null;
  173. String host = endpoint.getHostName();
  174. int port = endpoint.getPort();
  175. threadName = "JavaIDL Reader for " + host + ":" + port;
  176. mediator = new MessageMediator(this);
  177. // Only do the next two because we're a client
  178. clientReplyMap = new HashMap();
  179. out_calls = new Hashtable();
  180. // Both client and servers.
  181. idToFragmentedOutputStream = new Hashtable();
  182. final ThreadGroup finalThreadGroup = orb.threadGroup;
  183. final String finalThreadName = threadName;
  184. final IIOPConnection finalThis = this;
  185. final boolean finalTransportDebugFlag = orb.transportDebugFlag;
  186. try {
  187. AccessController.doPrivileged(new PrivilegedAction() {
  188. public java.lang.Object run() {
  189. reader = new ReaderThread(finalThreadGroup, finalThis, finalThreadName, finalTransportDebugFlag);
  190. return null;
  191. }
  192. });
  193. } catch (SecurityException e) {
  194. //
  195. // For some reason we're not allowed to create a new thread
  196. // in the same thread group that the ORB was initialized in.
  197. // Fall back on creating the thread in the calling thread's
  198. // group.
  199. //
  200. AccessController.doPrivileged(new PrivilegedAction() {
  201. public java.lang.Object run() {
  202. reader = new ReaderThread(finalThis, finalThreadName, finalTransportDebugFlag);
  203. return null;
  204. }
  205. });
  206. }
  207. synchronized ( stateEvent ){
  208. state = OPENING;
  209. }
  210. }
  211. /**
  212. * Called only from ConnectionTable.get() after server accepts an
  213. * incoming connection.
  214. * @param sock The socket for this connection.
  215. * @param inputStream The inputstream to use. It may be different
  216. * from a socket's inputstream.
  217. * @param outputStream The outputstream to use. It may be different
  218. * from a socket's outputstream.
  219. */
  220. public IIOPConnection(ORB orb,
  221. ServerGIOP server,
  222. EndPoint ep,
  223. Socket sock,
  224. InputStream inputStream,
  225. OutputStream outputStream,
  226. ConnectionTable ct)
  227. {
  228. this(orb, server, ct, ep);
  229. mediator = new MessageMediator(this);
  230. this.socket = sock;
  231. this.inputStream = inputStream;
  232. this.outputStream = outputStream;
  233. this.connectionTable = ct;
  234. isServer = true;
  235. // Only create the serverRequestMap for servers
  236. serverRequestMap = Collections.synchronizedMap(new HashMap());
  237. // Both client and servers.
  238. idToFragmentedOutputStream = new Hashtable();
  239. state = ESTABLISHED;
  240. // Catch exceptions since setDaemon can cause a
  241. // security exception to be thrown under netscape
  242. // in the Applet mode
  243. try {
  244. AccessController.doPrivileged(new PrivilegedAction() {
  245. public java.lang.Object run() {
  246. reader.setDaemon(true);
  247. return null;
  248. }
  249. });
  250. } catch (Exception e) {}
  251. reader.start();
  252. }
  253. public synchronized boolean isPostInitialContexts() {
  254. return postInitialContexts;
  255. }
  256. // Can never be unset...
  257. public synchronized void setPostInitialContexts(){
  258. postInitialContexts = true;
  259. }
  260. public java.io.InputStream getInputStream() {
  261. return inputStream;
  262. }
  263. public ServerGIOP getServerGIOP() {
  264. return server;
  265. }
  266. String getHost() {
  267. return endpoint.getHostName();
  268. }
  269. int getPort() {
  270. return endpoint.getPort();
  271. }
  272. EndPoint getEndpoint() {
  273. return endpoint;
  274. }
  275. /**
  276. * Read in the IIOP message from the network's InputStream and
  277. * create an IIOPInputStream object.
  278. * Called from ReaderThread only.
  279. *
  280. * The protocol of use by ReaderThread has been changed
  281. * so that non-null return values are not expected
  282. * for Fragment message types.
  283. *
  284. */
  285. public final void processInput() throws Exception
  286. {
  287. mediator.processRequest();
  288. }
  289. /**
  290. * Signal the client thread that the given request has been received,
  291. * and set the input stream on its out call descriptor.
  292. */
  293. void signalReplyReceived(int requestId, IIOPInputStream is)
  294. {
  295. Integer id = new Integer(requestId);
  296. OutCallDesc call = (OutCallDesc) out_calls.get(id);
  297. // This is an interesting case. It could mean that someone sent us a
  298. // reply message, but we don't know what request it was for. That
  299. // would probably call for an error. However, there's another case
  300. // that's normal and we should think about --
  301. //
  302. // If the unmarshaling thread does all of its work inbetween the time
  303. // the ReaderThread gives it the last fragment and gets to the
  304. // out_calls.get line, then it will also be null, so just return;
  305. if (call == null)
  306. return;
  307. // Set the reply IIOPInputStream and signal the client thread
  308. // that the reply has been received.
  309. // The thread signalled will remove outcall descriptor if appropriate.
  310. // Otherwise, it'll be removed when last fragment for it has been put on
  311. // BufferManagerRead's queue.
  312. synchronized (call.done) {
  313. call.s = is;
  314. call.done.notify();
  315. }
  316. }
  317. /**
  318. * Wake up the outstanding requests on the connection, and hand them
  319. * COMM_FAILURE exception with a given minor code. Also, delete connection
  320. * from connection table and stop the reader thread. Note that this should only
  321. * ever be called by the Reader thread for this connection.
  322. * @param minor_code The minor code for the COMM_FAILURE major code.
  323. * @param die Kill the reader thread (this thread) before exiting.
  324. */
  325. void purge_calls(int minor_code, boolean die, boolean lockHeld)
  326. {
  327. OutCallDesc call;
  328. if (orb.transportDebugFlag) {
  329. dprint("purge_calls: starting: code = " + minor_code
  330. + " die = " + die);
  331. }
  332. //
  333. // If this invocation is a result of ThreadDeath caused
  334. // by a previous execution of this routine, just exit.
  335. //
  336. synchronized ( stateEvent ){
  337. if ((state == ABORT) || (state == CLOSE_RECVD)) {
  338. if (orb.transportDebugFlag)
  339. dprint("purge_calls: exiting duplicate invocation");
  340. return;
  341. }
  342. }
  343. //
  344. // Grab the writeLock (freeze the calls)
  345. //
  346. try {
  347. if (!lockHeld)
  348. writeLock();
  349. } catch (SystemException ex) {
  350. if (orb.transportDebugFlag)
  351. dprint("purge_calls: caught exception " + ex + "; continuing");
  352. }
  353. //
  354. // Mark the state of the connection and determine the request status
  355. //
  356. org.omg.CORBA.CompletionStatus completion_status;
  357. synchronized ( stateEvent ){
  358. if (minor_code == Connection.CONN_REBIND) {
  359. state = CLOSE_RECVD;
  360. completion_status = CompletionStatus.COMPLETED_NO;
  361. } else {
  362. state = ABORT;
  363. completion_status = CompletionStatus.COMPLETED_MAYBE;
  364. }
  365. stateEvent.notifyAll();
  366. }
  367. //
  368. // Close the socket (if its not already closed)
  369. //
  370. try {
  371. // if theres no socket/connection, this is just ignored
  372. inputStream.close();
  373. outputStream.close();
  374. socket.close();
  375. } catch (Exception ex) {
  376. }
  377. SystemException comm_failure_exc =
  378. new COMM_FAILURE(minor_code, completion_status);
  379. // Signal all threads with outstanding requests on this
  380. // connection and give them the COMM_FAILURE exception.
  381. java.util.Enumeration e = out_calls.elements();
  382. while(e.hasMoreElements()) {
  383. call = (OutCallDesc) e.nextElement();
  384. synchronized(call.done){
  385. call.s = null;
  386. call.exc = comm_failure_exc;
  387. call.done.notify();
  388. }
  389. }
  390. //
  391. // delete connection from cache and stop the reader thread
  392. //
  393. connectionTable.deleteConn(endpoint);
  394. //
  395. // Signal all the waiters of the writeLock.
  396. // There are 4 types of writeLock waiters:
  397. // 1. Send waiters:
  398. // 2. SendReply waiters:
  399. // 3. cleanUp waiters:
  400. // 4. purge_call waiters:
  401. //
  402. writeUnlock();
  403. }
  404. /**
  405. * Sets up an established connection
  406. */
  407. public void setConnection(Socket _socket, ConnectionTable ctab)
  408. throws Exception
  409. {
  410. socket = _socket;
  411. inputStream = socket.getInputStream();
  412. outputStream = socket.getOutputStream();
  413. connectionTable = ctab;
  414. synchronized ( stateEvent ){
  415. state = ESTABLISHED;
  416. // Catch exceptions since setDaemon can cause a
  417. // security exception to be thrown under netscape
  418. // in the Applet mode
  419. try {
  420. AccessController.doPrivileged(new PrivilegedAction() {
  421. public java.lang.Object run() {
  422. reader.setDaemon(true);
  423. return null;
  424. }
  425. });
  426. }
  427. catch (Exception e) {}
  428. reader.start();
  429. stateEvent.notifyAll();
  430. }
  431. }
  432. /**
  433. * Changes state of connection to aborted, notifying waiters
  434. */
  435. public void abortConnection()
  436. {
  437. synchronized ( stateEvent ){
  438. state = ABORT;
  439. ((ReaderThread) reader).shutdown();
  440. stateEvent.notifyAll();
  441. }
  442. }
  443. /**
  444. * Sets the writeLock for this connection.
  445. * If the writeLock is already set by someone else, block till the
  446. * writeLock is released and can set by us.
  447. * IMPORTANT: this connection's lock must be acquired before
  448. * setting the writeLock and must be unlocked after setting the writeLock.
  449. */
  450. protected boolean writeLock()
  451. {
  452. // Keep looping till we can set the writeLock.
  453. while ( true ) {
  454. synchronized ( stateEvent ){
  455. switch ( state ) {
  456. case OPENING:
  457. try {
  458. stateEvent.wait();
  459. } catch (InterruptedException ie) {};
  460. // Loop back
  461. break;
  462. case ESTABLISHED:
  463. synchronized (writeEvent) {
  464. if (!writeLocked) {
  465. writeLocked = true;
  466. return true;
  467. }
  468. try {
  469. writeEvent.wait();
  470. } catch (InterruptedException ie) {};
  471. }
  472. // Loop back
  473. break;
  474. //
  475. // XXX
  476. // Need to distinguish between client and server roles
  477. // here probably.
  478. //
  479. case ABORT:
  480. throw new COMM_FAILURE( MinorCodes.WRITE_ERROR_SEND,
  481. CompletionStatus.COMPLETED_NO);
  482. case CLOSE_RECVD:
  483. // the connection has been closed or closing
  484. // ==> throw rebind exception
  485. throw new COMM_FAILURE( MinorCodes.CONN_CLOSE_REBIND,
  486. CompletionStatus.COMPLETED_NO);
  487. default:
  488. if (orb.transportDebugFlag)
  489. dprint("Connection:writeLock: weird state");
  490. delete(Connection.CONN_ABORT);
  491. return false;
  492. }
  493. }
  494. }
  495. }
  496. /**
  497. * Release the write lock on this connection.
  498. */
  499. protected void writeUnlock()
  500. {
  501. synchronized (writeEvent) {
  502. writeLocked = false;
  503. writeEvent.notify(); // wake up one guy waiting to write
  504. }
  505. }
  506. public void delete()
  507. {
  508. delete(Connection.CONN_ABORT);
  509. }
  510. void delete(int code)
  511. {
  512. DeleteConn dc = new DeleteConn(code);
  513. reader.stop(dc);
  514. }
  515. /** Send a two-way IIOP message to the server.
  516. */
  517. public IIOPInputStream invoke(IIOPOutputStream s)
  518. throws SystemException
  519. {
  520. return send(s, false);
  521. }
  522. /**
  523. * In 1.1 and 1.2, it seeds the response to be
  524. * continued if it's not the last fragment.
  525. */
  526. IIOPInputStream getResponse(boolean isOneway, int requestID)
  527. {
  528. IIOPInputStream returnStream = null;
  529. Integer requestId = new Integer(requestID);
  530. OutCallDesc call = (OutCallDesc)out_calls.get(requestId);
  531. if (isOneway) {
  532. out_calls.remove(requestId);
  533. return null;
  534. }
  535. // It's very important that only the client thread
  536. // removes its OutCallDesc from the table.
  537. if (call == null)
  538. throw new INTERNAL(MinorCodes.NULL_OUT_CALL,
  539. CompletionStatus.COMPLETED_MAYBE);
  540. synchronized(call.done) {
  541. while (call.s == null && call.exc == null) {
  542. // Wait for the reply from the server.
  543. // The ReaderThread reads in the reply IIOP message
  544. // and signals us.
  545. try {
  546. call.done.wait();
  547. } catch (InterruptedException ie) {};
  548. }
  549. // Remove this request ID from the out call descriptor map.
  550. // The ReaderThread can continue to add fragments because it
  551. // still has access to the input stream via the clientReplyMap.
  552. out_calls.remove(requestId);
  553. if (call.exc != null) {
  554. throw call.exc;
  555. }
  556. returnStream = call.s;
  557. }
  558. // REVISIT -- exceptions from unmarshaling code will
  559. // go up through this client thread!
  560. // If the header was already unmarshaled, this won't
  561. // do anything
  562. if (returnStream != null)
  563. returnStream.unmarshalHeader();
  564. return returnStream;
  565. }
  566. void createOutCallDescriptor(int requestId)
  567. {
  568. // Temporary solution -- check if we're a server or not
  569. if (!isServer) {
  570. Integer requestID = new Integer(requestId);
  571. OutCallDesc call = new OutCallDesc();
  572. call.thd = Thread.currentThread();
  573. out_calls.put(requestID, call);
  574. }
  575. }
  576. public void removeOutCallDescriptor(int requestId)
  577. {
  578. if (!isServer) {
  579. Integer requestID = new Integer(requestId);
  580. out_calls.remove(requestID);
  581. }
  582. }
  583. // Assumes the caller handles writeLock and writeUnlock
  584. void sendWithoutLock(IIOPOutputStream os)
  585. {
  586. // Don't we need to check for CloseConnection
  587. // here? REVISIT
  588. try {
  589. // Write the fragment/message
  590. os.writeTo(outputStream);
  591. outputStream.flush();
  592. } catch (IOException e1) {
  593. /*
  594. * ADDED(Ram J) 10/13/2000 In the event of an IOException, try
  595. * sending a CancelRequest for regular requests / locate requests
  596. */
  597. // Since IIOPOutputStream's msgheader is set only once, and not
  598. // altered during sending multiple fragments, the original
  599. // msgheader will always have the requestId.
  600. // REVISIT This could be optimized to send a CancelRequest only
  601. // if any fragments had been sent already.
  602. Message msg = os.getMessage();
  603. if (msg.getType() == Message.GIOPRequest ||
  604. msg.getType() == Message.GIOPLocateRequest) {
  605. GIOPVersion requestVersion = msg.getGIOPVersion();
  606. int requestId = MessageBase.getRequestId(msg);
  607. try {
  608. sendCancelRequest(requestVersion, requestId);
  609. } catch (IOException e2) {
  610. // most likely an abortive connection closure.
  611. // ignore, since nothing more can be done.
  612. }
  613. }
  614. // REVISIT When a send failure happens, purge_calls() need to be
  615. // called to ensure that the connection is properly removed from
  616. // further usage (ie., cancelling pending requests with COMM_FAILURE
  617. // with an appropriate minor_code CompletionStatus.MAY_BE).
  618. // Relying on the IIOPOutputStream (as noted below) is not
  619. // sufficient as it handles COMM_FAILURE only for the final
  620. // fragment (during invoke processing). Note that COMM_FAILURE could
  621. // happen while sending the initial fragments.
  622. // Also the IIOPOutputStream does not properly close the connection.
  623. // It simply removes the connection from the table. An orderly
  624. // closure is needed (ie., cancel pending requests on the connection
  625. // COMM_FAILURE as well.
  626. // IIOPOutputStream will cleanup the connection info when it
  627. // sees this exception.
  628. throw new COMM_FAILURE(MinorCodes.WRITE_ERROR_SEND,
  629. CompletionStatus.COMPLETED_NO);
  630. }
  631. }
  632. /** Send an IIOP message to the server.
  633. * If not oneway, wait for the reply.
  634. */
  635. public IIOPInputStream send(IIOPOutputStream s, boolean oneWay)
  636. {
  637. /*
  638. writeLock();
  639. createOutCallDescriptor(MessageBase.getRequestId(s.getMessage()));
  640. try {
  641. sendWithoutLock(s);
  642. } finally {
  643. writeUnlock();
  644. }
  645. */
  646. // This will force all fragments to be sent.
  647. s.finishSendingMessage();
  648. return getResponse(oneWay, MessageBase.getRequestId(s.getMessage()));
  649. }
  650. public void sendReply(IIOPOutputStream os)
  651. throws Exception
  652. {
  653. os.finishSendingMessage();
  654. }
  655. /** public IOR locate(byte[] key) is now in Connection.java */
  656. /***************************************************************************
  657. * The following methods are for dealing with Connection cleaning for
  658. * better scalability of servers in high network load conditions.
  659. ***************************************************************************/
  660. /**
  661. * Send a CancelRequest message. This does not lock the connection, so the
  662. * caller needs to ensure this method is called appropriately.
  663. *
  664. * @exception IOException if an I/O error occurs (could be due to abortive
  665. * connection closure).
  666. */
  667. public void sendCancelRequest(GIOPVersion giopVersion, int requestId)
  668. throws IOException {
  669. Message msg = MessageBase.createCancelRequest(giopVersion, requestId);
  670. IIOPOutputStream os = new IIOPOutputStream(giopVersion, orb, this);
  671. os.setMessage(msg);
  672. msg.write(os);
  673. os.writeTo(outputStream);
  674. outputStream.flush();
  675. }
  676. public void sendCancelRequestWithLock(GIOPVersion giopVersion,
  677. int requestId)
  678. throws
  679. IOException
  680. {
  681. writeLock();
  682. try {
  683. sendCancelRequest(giopVersion, requestId);
  684. } finally {
  685. writeUnlock();
  686. }
  687. }
  688. /**
  689. * Send a CloseConnection message. This does not lock the connection, so the
  690. * caller needs to ensure this method is called appropriately.
  691. *
  692. * @exception IOException if an I/O error occurs (could be due to abortive
  693. * connection closure).
  694. */
  695. public void sendCloseConnection(GIOPVersion giopVersion)
  696. throws IOException {
  697. Message msg = MessageBase.createCloseConnection(giopVersion);
  698. IIOPOutputStream os = new IIOPOutputStream(giopVersion, orb, this);
  699. os.setMessage(msg);
  700. msg.write(os);
  701. os.writeTo(outputStream);
  702. outputStream.flush();
  703. }
  704. /**
  705. * Send a MessageError message. This does not lock the connection, so the
  706. * caller needs to ensure this method is called appropriately.
  707. *
  708. * @exception IOException if an I/O error occurs (could be due to abortive
  709. * connection closure).
  710. */
  711. public void sendMessageError(GIOPVersion giopVersion)
  712. throws IOException {
  713. Message msg =
  714. MessageBase.createMessageError(giopVersion);
  715. IIOPOutputStream os = new IIOPOutputStream(giopVersion, orb, this);
  716. os.setMessage(msg);
  717. msg.write(os);
  718. os.writeTo(outputStream);
  719. outputStream.flush();
  720. }
  721. public boolean isBusy()
  722. {
  723. // Note: Hashtable.size() is not synchronized
  724. if (requestCount > 0 || out_calls.size() > 0)
  725. return true;
  726. else
  727. return false;
  728. }
  729. /**
  730. * Cleans up this Connection.
  731. * This is called from ConnectionTable, from the ListenerThread.
  732. * Note:it is possible for this to be called more than once
  733. */
  734. public synchronized void cleanUp() throws Exception
  735. {
  736. writeLock();
  737. // REVISIT It will be good to have a read lock on the reader thread
  738. // before we proceed further, to avoid the reader thread (server side)
  739. // from processing requests. This avoids the risk that a new request
  740. // will be accepted by ReaderThread while the ListenerThread is
  741. // attempting to close this connection.
  742. if (requestCount > 0 || out_calls.size() > 0) { // we are busy!
  743. writeUnlock();
  744. throw new Exception();
  745. }
  746. try {
  747. sendCloseConnection(GIOPVersion.V1_0);
  748. synchronized ( stateEvent ){
  749. state = CLOSE_SENT;
  750. stateEvent.notifyAll();
  751. }
  752. // stop the reader without causing it to do purge_calls
  753. Exception ex = new Exception();
  754. reader.stop(ex);
  755. // this also does writeUnlock();
  756. purge_calls(Connection.CONN_REBIND, false, true);
  757. } catch (Exception ex) {}
  758. }
  759. /** It is possible for a Close Connection to have been
  760. ** sent here, but we will not check for this. A "lazy"
  761. ** Exception will be thrown in the Worker thread after the
  762. ** incoming request has been processed even though the connection
  763. ** is closed before the request is processed. This is o.k because
  764. ** it is a boundary condition. To prevent it we would have to add
  765. ** more locks which would reduce performance in the normal case.
  766. **/
  767. public synchronized void requestBegins()
  768. {
  769. requestCount++;
  770. }
  771. public synchronized void requestEnds(IIOPInputStream request)
  772. {
  773. if (request.getGIOPVersion().equals(GIOPVersion.V1_2))
  774. serverRequestMap.remove(new Integer(MessageBase.getRequestId(request.getMessage())));
  775. if (request.getGIOPVersion().equals(GIOPVersion.V1_1))
  776. theOnly1_1ServerRequestImpl = null;
  777. requestCount--;
  778. }
  779. void shutdown()
  780. {
  781. // The order is important here. First make sure that the thread knows what to do
  782. // after the socket closes before we close it.
  783. ((ReaderThread)reader).shutdown();
  784. super.shutdown();
  785. }
  786. public void print()
  787. {
  788. System.out.println("Connection for " + endpoint.getHostName() +
  789. " @ " + endpoint.getPort());
  790. System.out.println(" Time stamp = " + timeStamp);
  791. boolean alive = reader.isAlive();
  792. if (alive)
  793. System.out.println(" Reader is Alive");
  794. else
  795. System.out.println(" Reader is not Alive");
  796. }
  797. // Begin Code Base methods ---------------------------------------
  798. //
  799. // Set this connection's code base IOR. The IOR comes from the
  800. // SendingContext. This is an optional service context, but all
  801. // JavaSoft ORBs send it.
  802. //
  803. // The set and get methods don't need to be synchronized since the
  804. // first possible get would occur during reading a valuetype, and
  805. // that would be after the set.
  806. public final void setCodeBaseIOR(IOR ior) {
  807. codeBaseServerIOR = ior;
  808. }
  809. final IOR getCodeBaseIOR() {
  810. return codeBaseServerIOR;
  811. }
  812. // Get a CodeBase stub to use in unmarshaling. The CachedCodeBase
  813. // won't connect to the remote codebase unless it's necessary.
  814. final CodeBase getCodeBase() {
  815. return cachedCodeBase;
  816. }
  817. // End Code Base methods -----------------------------------------
  818. final void createIdToFragmentedOutputStreamEntry (
  819. int requestID,
  820. IIOPOutputStream outputStream)
  821. {
  822. idToFragmentedOutputStream.put(new Integer(requestID),
  823. outputStream);
  824. }
  825. public final IIOPOutputStream getIdToFragmentedOutputStreamEntry(
  826. int requestID)
  827. {
  828. return (IIOPOutputStream)
  829. idToFragmentedOutputStream.get(new Integer(requestID));
  830. }
  831. public final void removeIdToFragmentedOutputStreamEntry(int requestID)
  832. {
  833. idToFragmentedOutputStream.remove(new Integer(requestID));
  834. }
  835. }