Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: mindbright/ssh/SSHSocketTunnel.java


1   /******************************************************************************
2    *
3    * Copyright (c) 1998,99 by Mindbright Technology AB, Stockholm, Sweden.
4    *                 www.mindbright.se, info@mindbright.se
5    *
6    * This program is free software; you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation; either version 2 of the License, or
9    * (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   *****************************************************************************
17   * $Author: nallen $
18   * $Date: 2001/11/12 16:31:23 $
19   * $Name:  $
20   *****************************************************************************/
21  package mindbright.ssh;
22  
23  import java.net.*;
24  import java.io.*;
25  
26  public final class SSHSocketTunnel extends SSHTunnel {
27  
28    public final static class SSHSocketIS extends InputStream {
29      protected SSHSocketTunnel tunnel;
30      protected SSHSocketIS(SSHSocketTunnel tunnel) {
31        this.tunnel = tunnel;
32      }
33      public int read() throws IOException {
34        byte[] b = new byte[1];
35        if(read(b, 0, 1) == -1)
36    return -1;
37        return (int) b[0];
38      }
39      public int read(byte b[], int off, int len) throws IOException {
40        return tunnel.read(b, off, len);
41      }
42      public void close() throws IOException {
43        tunnel.closein(true);
44      }
45    }
46  
47    public final static class SSHSocketOS extends OutputStream {
48      protected SSHSocketTunnel tunnel;
49      protected SSHSocketOS(SSHSocketTunnel tunnel) {
50        this.tunnel = tunnel;
51      }
52      public void write(int b) throws IOException {
53        byte[] ba = new byte[1];
54        ba[0] = (byte) b;
55        tunnel.write(ba, 0, 1);
56      }
57      public void write(byte b[], int off, int len) throws IOException {
58        tunnel.write(b, off, len);
59      }
60      public void close() throws IOException {
61        tunnel.closeout();
62      }
63    }
64  
65    Object  lock;
66    boolean inputClosePending;
67    boolean inputExplicitClosed;
68    boolean outputClosed;
69    boolean terminated;
70    boolean openFail;
71  
72    protected SSHPdu      rest;
73    protected SSHSocketIS in;
74    protected SSHSocketOS out;
75    protected InetAddress localAddress;
76  
77    protected SSHSocketImpl impl;
78  
79    public SSHSocketTunnel(SSHChannelController controller, SSHSocketImpl impl) throws IOException {
80      super(null, controller.newChannelId(), SSH.UNKNOWN_CHAN_NUM, controller);
81  
82      this.lock    = new Object();
83  
84      this.inputClosePending   = false;
85      this.inputExplicitClosed = false;
86      this.outputClosed        = false;
87      this.terminated          = false;
88      this.openFail            = false;
89  
90      this.txQueue = new SSHPduQueue();
91      this.in      = new SSHSocketIS(this);
92      this.out     = new SSHSocketOS(this);
93      this.impl    = impl;
94    }
95  
96    public void start() {
97      synchronized(lock) {
98        lock.notify();
99      }
100   }
101 
102   public void openFailure() {
103     openFail = true;
104     start();
105   }
106 
107   public int read(byte b[], int off, int len) throws IOException {
108     SSHPdu pdu = null;
109     int    actLen;
110 
111     synchronized(this) {
112   if(inputExplicitClosed)
113       throw new SocketException("Socket closed");
114     }
115 
116     // We reuse the connect-lock since it is only used before we
117     // start, after that it becomes the read-synchronization lock
118     //
119     synchronized(lock) {
120   if(rest != null) {
121       pdu  = rest;
122       rest = null;
123   } else if(inputClosePending && txQueue.isEmpty()) {
124       pdu = null;
125   } else {
126       pdu = txQueue.getFirst();
127   }
128 
129   if(pdu == null)
130       return -1;
131 
132   int rawLen = pdu.rawSize();
133   if(len < rawLen) {
134       rest   = pdu;
135       actLen = len;
136   } else {
137       actLen = rawLen;
138   }
139 
140   System.arraycopy(pdu.rawData(), pdu.rawOffset(), b, off, actLen);
141 
142   if(rest != null) {
143       rest.rawAdjustSize(rawLen - len);
144   }
145     }
146 
147     return actLen;
148   }
149 
150   public void write(byte b[], int off, int len) throws IOException {
151     SSHPduOutputStream pdu;
152 
153     synchronized(this) {
154   if(outputClosed)
155       throw new IOException("Resource temporarily unavailable");
156     }
157 
158     pdu = new SSHPduOutputStream(SSH.MSG_CHANNEL_DATA, controller.sndCipher);
159     pdu = (SSHPduOutputStream)prepare(pdu);
160     pdu.writeInt(len);
161     pdu.write(b, off, len);
162     controller.transmit(pdu);
163   }
164 
165   public void connect(String host, int port) throws IOException {
166     SSHPduOutputStream respPdu;
167 
168     setRemoteDesc(host + ":" + port);
169 
170     respPdu = new SSHPduOutputStream(SSH.MSG_PORT_OPEN, controller.sndCipher);
171     controller.addTunnel(this);
172     respPdu.writeInt(channelId);
173     respPdu.writeString(host);
174     respPdu.writeInt(port);
175     respPdu.writeString(localAddress.getHostAddress());
176     controller.transmit(respPdu);
177 
178     // Wait for start() to be called (i.e. the channel to be confirmed open)
179     //
180     synchronized(lock) {
181       try {
182   lock.wait();
183       } catch(InterruptedException e) {
184   // !!!
185       }
186     }
187 
188     if(openFail)
189       throw new ConnectException("Connection Refused");
190   }
191 
192   public void close() throws IOException {
193     closein(true);
194     closeout();
195   }
196 
197   public synchronized void closeout() {
198     outputClosed = true;
199     sendInputEOF();
200   }
201 
202   public void closein(boolean explicit) {
203     txQueue.release();
204     synchronized(this) {
205       inputClosePending   = true;
206       inputExplicitClosed = explicit;
207       sendOutputClosed();
208     }
209   }
210 
211   public int available() throws IOException {
212     if(rest != null)
213       return rest.rawSize();
214     else
215       return 0;
216   }
217 
218   protected void setLocalAddress(InetAddress localAddress) {
219     this.localAddress = localAddress;
220   }
221 
222   public synchronized void checkTermination() {
223     if(sentInputEOF && sentOutputClosed &&
224        receivedInputEOF && receivedOutputClosed) {
225       terminated = true;
226       controller.delTunnel(channelId);
227       impl.factory.closePseudoUser(controller.sshAsClient(), impl);
228     }
229   }
230 
231   public synchronized boolean terminated() {
232     return terminated;
233   }
234 
235   public void receiveOutputClosed() {
236     super.receiveOutputClosed();
237     closeout();
238   }
239 
240   public void receiveInputEOF() {
241     // !!! NOTE: we do not call super's method...
242     receivedInputEOF = true;
243     closein(false);
244     closeout();
245     checkTermination();
246   }
247 
248 }