2
Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
4
Redistribution and use in source and binary forms, with or without
5
modification, are permitted provided that the following conditions are met:
7
1. Redistributions of source code must retain the above copyright notice,
8
this list of conditions and the following disclaimer.
10
2. Redistributions in binary form must reproduce the above copyright
11
notice, this list of conditions and the following disclaimer in
12
the documentation and/or other materials provided with the distribution.
14
3. The names of the authors may not be used to endorse or promote products
15
derived from this software without specific prior written permission.
17
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
18
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
20
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
21
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
This code is based on jsch (http://www.jcraft.com/jsch).
29
All credit should go to the authors of jsch.
33
using System.Collections;
40
public abstract class Channel : Runnable
42
internal const int SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91;
44
internal const int SSH_MSG_CHANNEL_OPEN_FAILURE = 92;
46
internal const int SSH_MSG_CHANNEL_WINDOW_ADJUST = 93;
48
internal const int SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1;
50
internal const int SSH_OPEN_CONNECT_FAILED = 2;
52
internal const int SSH_OPEN_UNKNOWN_CHANNEL_TYPE = 3;
54
internal const int SSH_OPEN_RESOURCE_SHORTAGE = 4;
56
internal static int index = 0;
58
private static ArrayList pool = new ArrayList();
60
internal static NSch.Channel GetChannel(string type)
62
if (type.Equals("session"))
64
return new ChannelSession();
66
if (type.Equals("shell"))
68
return new ChannelShell();
70
if (type.Equals("exec"))
72
return new ChannelExec();
74
if (type.Equals("x11"))
76
return new ChannelX11();
78
if (type.Equals("auth-agent@openssh.com"))
80
return new ChannelAgentForwarding();
82
if (type.Equals("direct-tcpip"))
84
return new ChannelDirectTCPIP();
86
if (type.Equals("forwarded-tcpip"))
88
return new ChannelForwardedTCPIP();
90
if (type.Equals("sftp"))
92
return new ChannelSftp();
94
if (type.Equals("subsystem"))
96
return new ChannelSubsystem();
101
internal static NSch.Channel GetChannel(int id, Session session)
105
for (int i = 0; i < pool.Count; i++)
107
NSch.Channel c = (NSch.Channel)(pool[i]);
108
if (c.id == id && c.session == session)
117
internal static void Del(NSch.Channel c)
121
pool.RemoveElement(c);
127
internal int recipient = -1;
129
internal byte[] type = Util.Str2byte("foo");
131
internal int lwsize_max = unchecked((int)(0x100000));
135
internal int lmpsize = unchecked((int)(0x4000));
137
internal long rwsize = 0;
139
internal int rmpsize = 0;
141
internal IO io = null;
143
internal Sharpen.Thread thread = null;
145
internal bool eof_local = false;
147
internal bool eof_remote = false;
149
internal bool close = false;
151
internal bool connected = false;
153
internal int exitstatus = -1;
155
internal int reply = 0;
157
internal int connectTimeout = 0;
159
private Session session;
161
internal int notifyme = 0;
166
//int lwsize_max=0x20000; // 32*1024*4
167
// local initial window size
168
// local maximum packet size
169
//int lmpsize=0x8000; // local maximum packet size
170
// remote initial window size
171
// remote maximum packet size
179
internal virtual void SetRecipient(int foo)
181
this.recipient = foo;
184
internal virtual int GetRecipient()
189
/// <exception cref="NSch.JSchException"></exception>
190
internal virtual void Init()
194
/// <exception cref="NSch.JSchException"></exception>
195
public virtual void Connect()
200
/// <exception cref="NSch.JSchException"></exception>
201
public virtual void Connect(int connectTimeout)
203
Session _session = GetSession();
204
if (!_session.IsConnected())
206
throw new JSchException("session is down");
208
this.connectTimeout = connectTimeout;
211
Buffer buf = new Buffer(100);
212
Packet packet = new Packet(buf);
214
// byte SSH_MSG_CHANNEL_OPEN(90)
215
// string channel type //
216
// uint32 sender channel // 0
217
// uint32 initial window size // 0x100000(65536)
218
// uint32 maxmum packet size // 0x4000(16384)
220
buf.PutByte(unchecked((byte)90));
221
buf.PutString(this.type);
223
buf.PutInt(this.lwsize);
224
buf.PutInt(this.lmpsize);
225
_session.Write(packet);
227
long start = Runtime.CurrentTimeMillis();
228
long timeout = connectTimeout;
229
while (this.GetRecipient() == -1 && _session.IsConnected() && retry > 0)
233
if ((Runtime.CurrentTimeMillis() - start) > timeout)
241
Sharpen.Thread.Sleep(50);
248
if (!_session.IsConnected())
250
throw new JSchException("session is down");
254
throw new JSchException("channel is not opened.");
258
throw new JSchException("channel is not opened.");
267
if (e is JSchException)
269
throw (JSchException)e;
271
throw new JSchException(e.ToString(), e);
275
public virtual void SetXForwarding(bool foo)
279
/// <exception cref="NSch.JSchException"></exception>
280
public virtual void Start()
284
public virtual bool IsEOF()
289
internal virtual void GetData(Buffer buf)
291
SetRecipient(buf.GetInt());
292
SetRemoteWindowSize(buf.GetUInt());
293
SetRemotePacketSize(buf.GetInt());
296
public virtual void SetInputStream(InputStream @in)
298
io.SetInputStream(@in, false);
301
public virtual void SetInputStream(InputStream @in, bool dontclose)
303
io.SetInputStream(@in, dontclose);
306
public virtual void SetOutputStream(OutputStream @out)
308
io.SetOutputStream(@out, false);
311
public virtual void SetOutputStream(OutputStream @out, bool dontclose)
313
io.SetOutputStream(@out, dontclose);
316
public virtual void SetExtOutputStream(OutputStream @out)
318
io.SetExtOutputStream(@out, false);
321
public virtual void SetExtOutputStream(OutputStream @out, bool dontclose)
323
io.SetExtOutputStream(@out, dontclose);
326
/// <exception cref="System.IO.IOException"></exception>
327
public virtual InputStream GetInputStream()
329
PipedInputStream @in = new Channel.MyPipedInputStream(this, 32 * 1024);
330
// this value should be customizable.
331
io.SetOutputStream(new Channel.PassiveOutputStream(this, @in), false);
335
/// <exception cref="System.IO.IOException"></exception>
336
public virtual InputStream GetExtInputStream()
338
PipedInputStream @in = new Channel.MyPipedInputStream(this, 32 * 1024);
339
// this value should be customizable.
340
io.SetExtOutputStream(new Channel.PassiveOutputStream(this, @in), false);
344
/// <exception cref="System.IO.IOException"></exception>
345
public virtual OutputStream GetOutputStream()
347
NSch.Channel channel = this;
348
OutputStream @out = new _OutputStream_268(this, channel);
349
// close should be finished silently.
353
private sealed class _OutputStream_268 : OutputStream
355
public _OutputStream_268(Channel _enclosing, NSch.Channel channel)
357
this._enclosing = _enclosing;
358
this.channel = channel;
363
this.b = new byte[1];
368
private Buffer buffer;
370
private Packet packet;
374
/// <exception cref="System.IO.IOException"></exception>
379
this.buffer = new Buffer(this._enclosing.rmpsize);
380
this.packet = new Packet(this.buffer);
381
byte[] _buf = this.buffer.buffer;
382
if (_buf.Length - (14 + 0) - 32 - 20 <= 0)
386
throw new IOException("failed to initialize the channel.");
393
/// <exception cref="System.IO.IOException"></exception>
394
public override void Write(int w)
396
this.b[0] = unchecked((byte)w);
397
this.Write(this.b, 0, 1);
400
/// <exception cref="System.IO.IOException"></exception>
401
public override void Write(byte[] buf, int s, int l)
403
if (this.packet == null)
409
throw new IOException("Already closed");
411
byte[] _buf = this.buffer.buffer;
412
int _bufl = _buf.Length;
416
if (l > _bufl - (14 + this.dataLen) - 32 - 20)
418
_l = _bufl - (14 + this.dataLen) - 32 - 20;
425
System.Array.Copy(buf, s, _buf, 14 + this.dataLen, _l);
432
/// <exception cref="System.IO.IOException"></exception>
433
public override void Flush()
437
throw new IOException("Already closed");
439
if (this.dataLen == 0)
444
this.buffer.PutByte(unchecked((byte)Session.SSH_MSG_CHANNEL_DATA));
445
this.buffer.PutInt(this._enclosing.recipient);
446
this.buffer.PutInt(this.dataLen);
447
this.buffer.Skip(this.dataLen);
450
int foo = this.dataLen;
452
this._enclosing.GetSession().Write(this.packet, channel, foo);
457
throw new IOException(e.ToString());
461
/// <exception cref="System.IO.IOException"></exception>
462
public override void Close()
464
if (this.packet == null)
479
if (this.dataLen > 0)
487
private readonly Channel _enclosing;
489
private readonly NSch.Channel channel;
492
internal class MyPipedInputStream : PipedInputStream
494
/// <exception cref="System.IO.IOException"></exception>
495
public MyPipedInputStream(Channel _enclosing) : base()
497
this._enclosing = _enclosing;
500
/// <exception cref="System.IO.IOException"></exception>
501
public MyPipedInputStream(Channel _enclosing, int size) : base()
503
this._enclosing = _enclosing;
504
this.buffer = new byte[size];
507
/// <exception cref="System.IO.IOException"></exception>
508
public MyPipedInputStream(Channel _enclosing, PipedOutputStream @out) : base(@out
511
this._enclosing = _enclosing;
514
/// <exception cref="System.IO.IOException"></exception>
515
public MyPipedInputStream(Channel _enclosing, PipedOutputStream @out, int size) :
518
this._enclosing = _enclosing;
519
this.buffer = new byte[size];
522
private readonly Channel _enclosing;
525
internal virtual void SetLocalWindowSizeMax(int foo)
527
this.lwsize_max = foo;
530
internal virtual void SetLocalWindowSize(int foo)
535
internal virtual void SetLocalPacketSize(int foo)
540
internal virtual void SetRemoteWindowSize(long foo)
548
internal virtual void AddRemoteWindowSize(int foo)
555
Sharpen.Runtime.NotifyAll(this);
560
internal virtual void SetRemotePacketSize(int foo)
565
public virtual void Run()
569
/// <exception cref="System.IO.IOException"></exception>
570
internal virtual void Write(byte[] foo)
572
Write(foo, 0, foo.Length);
575
/// <exception cref="System.IO.IOException"></exception>
576
internal virtual void Write(byte[] foo, int s, int l)
582
catch (ArgumentNullException)
587
/// <exception cref="System.IO.IOException"></exception>
588
internal virtual void Write_ext(byte[] foo, int s, int l)
592
io.Put_ext(foo, s, l);
594
catch (ArgumentNullException)
599
internal virtual void Eof_remote()
606
catch (ArgumentNullException)
611
internal virtual void Eof()
620
Buffer buf = new Buffer(100);
621
Packet packet = new Packet(buf);
623
buf.PutByte(unchecked((byte)Session.SSH_MSG_CHANNEL_EOF));
624
buf.PutInt(GetRecipient());
629
GetSession().Write(packet);
638
//System.err.println("Channel.eof");
639
//e.printStackTrace();
640
internal virtual void Close()
647
eof_local = eof_remote = true;
650
Buffer buf = new Buffer(100);
651
Packet packet = new Packet(buf);
653
buf.PutByte(unchecked((byte)Session.SSH_MSG_CHANNEL_CLOSE));
654
buf.PutInt(GetRecipient());
657
GetSession().Write(packet);
665
//e.printStackTrace();
666
public virtual bool IsClosed()
671
internal static void Disconnect(Session session)
673
Channel[] channels = null;
677
channels = new Channel[pool.Count];
678
for (int i = 0; i < pool.Count; i++)
682
Channel c = ((Channel)(pool[i]));
683
if (c.session == session)
685
channels[count++] = c;
693
for (int i_1 = 0; i_1 < count; i_1++)
695
channels[i_1].Disconnect();
699
public virtual void Disconnect()
701
//System.err.println(this+":disconnect "+io+" "+connected);
702
//Thread.dumpStack();
714
eof_remote = eof_local = true;
729
//e.printStackTrace();
735
public virtual bool IsConnected()
737
Session _session = this.session;
738
if (_session != null)
740
return _session.IsConnected() && connected;
745
/// <exception cref="System.Exception"></exception>
746
public virtual void SendSignal(string signal)
748
RequestSignal request = new RequestSignal();
749
request.SetSignal(signal);
750
request.DoRequest(GetSession(), this);
753
internal class PassiveInputStream : Channel.MyPipedInputStream
755
internal PipedOutputStream @out;
757
/// <exception cref="System.IO.IOException"></exception>
758
public PassiveInputStream(Channel _enclosing, PipedOutputStream @out, int size) :
761
this._enclosing = _enclosing;
762
// public String toString(){
763
// return "Channel: type="+new String(type)+",id="+id+",recipient="+recipient+",window_size="+window_size+",packet_size="+packet_size;
768
/// <exception cref="System.IO.IOException"></exception>
769
public PassiveInputStream(Channel _enclosing, PipedOutputStream @out) : base(_enclosing
772
this._enclosing = _enclosing;
776
/// <exception cref="System.IO.IOException"></exception>
777
public override void Close()
779
if (this.@out != null)
786
private readonly Channel _enclosing;
789
internal class PassiveOutputStream : PipedOutputStream
791
/// <exception cref="System.IO.IOException"></exception>
792
public PassiveOutputStream(Channel _enclosing, PipedInputStream @in) : base(@in)
794
this._enclosing = _enclosing;
797
private readonly Channel _enclosing;
800
internal virtual void SetExitStatus(int status)
805
public virtual int GetExitStatus()
810
internal virtual void SetSession(Session session)
812
this.session = session;
815
/// <exception cref="NSch.JSchException"></exception>
816
public virtual Session GetSession()
818
Session _session = session;
819
if (_session == null)
821
throw new JSchException("session is not available");
826
public virtual int GetId()
831
/// <exception cref="System.Exception"></exception>
832
protected internal virtual void SendOpenConfirmation()
834
Buffer buf = new Buffer(100);
835
Packet packet = new Packet(buf);
837
buf.PutByte(unchecked((byte)SSH_MSG_CHANNEL_OPEN_CONFIRMATION));
838
buf.PutInt(GetRecipient());
842
GetSession().Write(packet);
845
protected internal virtual void SendOpenFailure(int reasoncode)
849
Buffer buf = new Buffer(100);
850
Packet packet = new Packet(buf);
852
buf.PutByte(unchecked((byte)SSH_MSG_CHANNEL_OPEN_FAILURE));
853
buf.PutInt(GetRecipient());
854
buf.PutInt(reasoncode);
855
buf.PutString(Util.Str2byte("open failed"));
856
buf.PutString(Util.empty);
857
GetSession().Write(packet);