2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
namespace NGit.Transport
53
/// <summary>Run remote commands using Jsch.</summary>
55
/// Run remote commands using Jsch.
57
/// This class is the default session implementation using Jsch. Note that
58
/// <see cref="JschConfigSessionFactory">JschConfigSessionFactory</see>
59
/// is used to create the actual session passed
60
/// to the constructor.
62
public class JschSession : RemoteSession
64
private readonly Session sock;
66
private readonly URIish uri;
69
/// Create a new session object by passing the real Jsch session and the URI
73
/// Create a new session object by passing the real Jsch session and the URI
76
/// <param name="session">the real Jsch session created elsewhere.</param>
77
/// <param name="uri">the URI information for the remote connection</param>
78
public JschSession(Session session, URIish uri)
84
/// <exception cref="System.IO.IOException"></exception>
85
public virtual SystemProcess Exec(string command, int timeout)
87
return new JschSession.JschProcess(this, command, timeout);
90
public virtual void Disconnect()
92
if (sock.IsConnected())
100
/// <see cref="TransportSftp">TransportSftp</see>
101
/// to get an Sftp channel from Jsch.
102
/// Ideally, this method would be generic, which would require implementing
103
/// generic Sftp channel operations in the RemoteSession class.
105
/// <returns>a channel suitable for Sftp operations.</returns>
106
/// <exception cref="NSch.JSchException">on problems getting the channel.</exception>
107
public virtual Channel GetSftpChannel()
109
return sock.OpenChannel("sftp");
112
/// <summary>Implementation of Process for running a single command using Jsch.</summary>
114
/// Implementation of Process for running a single command using Jsch.
116
/// Uses the Jsch session to do actual command execution and manage the
119
internal class JschProcess : SystemProcess
121
private ChannelExec channel;
123
private readonly int timeout;
125
private InputStream inputStream;
127
private OutputStream outputStream;
129
private InputStream errStream;
132
/// Opens a channel on the session ("sock") for executing the given
133
/// command, opens streams, and starts command execution.
136
/// Opens a channel on the session ("sock") for executing the given
137
/// command, opens streams, and starts command execution.
139
/// <param name="commandName">the command to execute</param>
140
/// <param name="tms">the timeout value, in seconds, for the command.</param>
141
/// <exception cref="NGit.Errors.TransportException">
142
/// on problems opening a channel or connecting to the remote
145
/// <exception cref="System.IO.IOException">on problems opening streams</exception>
146
public JschProcess(JschSession _enclosing, string commandName, int tms)
148
this._enclosing = _enclosing;
152
this.channel = (ChannelExec)this._enclosing.sock.OpenChannel("exec");
153
this.channel.SetCommand(commandName);
155
this.channel.Connect(this.timeout > 0 ? this.timeout * 1000 : 0);
156
if (!this.channel.IsConnected())
158
throw new TransportException(this._enclosing.uri, "connection failed");
161
catch (JSchException e)
163
throw new TransportException(this._enclosing.uri, e.Message, e);
167
/// <exception cref="System.IO.IOException"></exception>
168
private void SetupStreams()
170
this.inputStream = this.channel.GetInputStream();
171
// JSch won't let us interrupt writes when we use our InterruptTimer
172
// to break out of a long-running write operation. To work around
173
// that we spawn a background thread to shuttle data through a pipe,
174
// as we can issue an interrupted write out of that. Its slower, so
175
// we only use this route if there is a timeout.
176
OutputStream @out = this.channel.GetOutputStream();
177
if (this.timeout <= 0)
179
this.outputStream = @out;
183
PipedInputStream pipeIn = new PipedInputStream();
184
StreamCopyThread copier = new StreamCopyThread(pipeIn, @out);
185
PipedOutputStream pipeOut = new _PipedOutputStream_173(this, copier, pipeIn);
186
// Just wake early, the thread will terminate
189
this.outputStream = pipeOut;
191
this.errStream = this.channel.GetErrStream();
194
private sealed class _PipedOutputStream_173 : PipedOutputStream
196
public _PipedOutputStream_173(JschProcess _enclosing, StreamCopyThread copier, PipedInputStream
197
baseArg1) : base(baseArg1)
199
this._enclosing = _enclosing;
200
this.copier = copier;
203
/// <exception cref="System.IO.IOException"></exception>
204
public override void Flush()
210
/// <exception cref="System.IO.IOException"></exception>
211
public override void Close()
216
copier.Join(this._enclosing.timeout * 1000);
223
private readonly JschProcess _enclosing;
225
private readonly StreamCopyThread copier;
228
public override InputStream GetInputStream()
230
return this.inputStream;
233
public override OutputStream GetOutputStream()
235
return this.outputStream;
238
public override InputStream GetErrorStream()
240
return this.errStream;
243
public override int ExitValue()
245
if (this.IsRunning())
247
throw new InvalidOperationException();
249
return this.channel.GetExitStatus();
252
private bool IsRunning()
254
return this.channel.GetExitStatus() < 0 && this.channel.IsConnected();
257
public override void Destroy()
259
if (this.channel.IsConnected())
261
this.channel.Disconnect();
265
/// <exception cref="System.Exception"></exception>
266
public override int WaitFor()
268
while (this.IsRunning())
270
Sharpen.Thread.Sleep(100);
272
return this.ExitValue();
275
private readonly JschSession _enclosing;