Skip to content

Commit e953f3f

Browse files
authored
Merge pull request #45 from blacknon/develop
- Bugfix session keepalive - Modify it to allow specifying the Pty in order to combine with [gowid](https://github.com/blacknon/gowid/tree/topic/terminal_pty).
2 parents d6e302b + 1b4de0c commit e953f3f

File tree

3 files changed

+97
-29
lines changed

3 files changed

+97
-29
lines changed

cmd.go

+30-13
Original file line numberDiff line numberDiff line change
@@ -24,35 +24,52 @@ func (c *Connect) Command(command string) (err error) {
2424
}
2525
defer func() { c.Session = nil }()
2626

27-
// setup options
28-
err = c.setOption(c.Session)
29-
if err != nil {
30-
return
31-
}
32-
33-
// Set Stdin, Stdout, Stderr...
34-
if c.Stdin != nil {
27+
// Set Stdin
28+
switch {
29+
case c.Stdin != nil:
3530
w, _ := c.Session.StdinPipe()
3631
go io.Copy(w, c.Stdin)
37-
} else {
32+
33+
case c.PtyRelayTty != nil:
34+
c.Session.Stdin = c.PtyRelayTty
35+
36+
default:
3837
stdin := GetStdin()
3938
c.Session.Stdin = stdin
4039
}
4140

42-
if c.Stdout != nil {
41+
// Set Stdout
42+
switch {
43+
case c.Stdout != nil:
4344
or, _ := c.Session.StdoutPipe()
4445
go io.Copy(c.Stdout, or)
45-
} else {
46+
47+
case c.PtyRelayTty != nil:
48+
c.Session.Stdout = c.PtyRelayTty
49+
50+
default:
4651
c.Session.Stdout = os.Stdout
4752
}
4853

49-
if c.Stderr != nil {
54+
// Set Stderr
55+
switch {
56+
case c.Stderr != nil:
5057
er, _ := c.Session.StderrPipe()
5158
go io.Copy(c.Stderr, er)
52-
} else {
59+
60+
case c.PtyRelayTty != nil:
61+
c.Session.Stderr = c.PtyRelayTty
62+
63+
default:
5364
c.Session.Stderr = os.Stderr
5465
}
5566

67+
// setup options
68+
err = c.setOption(c.Session)
69+
if err != nil {
70+
return
71+
}
72+
5673
// Run Command
5774
c.Session.Run(command)
5875

connect.go

+17-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package sshlib
66

77
import (
88
"context"
9-
"errors"
109
"io"
1110
"log"
1211
"net"
@@ -51,6 +50,9 @@ type Connect struct {
5150
// Set it before CraeteClient.
5251
ForwardAgent bool
5352

53+
// Set the TTY to be used as the input and output for the Session/Cmd.
54+
PtyRelayTty *os.File
55+
5456
// CheckKnownHosts if true, check knownhosts.
5557
// Ignored if HostKeyCallback is set.
5658
// Set it before CraeteClient.
@@ -191,36 +193,37 @@ func (c *Connect) SendKeepAlive(session *ssh.Session) {
191193
interval = c.SendKeepAliveInterval
192194
}
193195

196+
max := 3
197+
if c.SendKeepAliveMax > 0 {
198+
max = c.SendKeepAliveMax
199+
}
200+
194201
t := time.NewTicker(time.Duration(c.ConnectTimeout) * time.Second)
195202
defer t.Stop()
196203

204+
count := 0
197205
for {
198206
select {
199207
case <-t.C:
200208
if _, err := session.SendRequest("[email protected]", true, nil); err != nil {
201-
if !errors.Is(err, io.EOF) {
202-
log.Println("Failed to send keepalive packet:", err)
203-
session.Close()
204-
c.Client.Close()
205-
break
206-
} else {
207-
// sleep
208-
time.Sleep(time.Duration(interval) * time.Second)
209-
continue
210-
}
209+
log.Println("Failed to send keepalive packet:", err)
210+
count += 1
211211
} else {
212-
// sleep
212+
// err is nil.
213213
time.Sleep(time.Duration(interval) * time.Second)
214-
continue
215214
}
216215
}
216+
217+
if count > max {
218+
return
219+
}
217220
}
218221
}
219222

220223
// CheckClientAlive check alive ssh.Client.
221224
func (c *Connect) CheckClientAlive() error {
222225
_, _, err := c.Client.SendRequest("keepalive", true, nil)
223-
if err == nil || err.Error() == "request failed" {
226+
if err == nil {
224227
return nil
225228
}
226229
return err

shell.go

+50-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@ import (
2020
// Shell connect login shell over ssh.
2121
func (c *Connect) Shell(session *ssh.Session) (err error) {
2222
// Input terminal Make raw
23-
fd := int(os.Stdin.Fd())
23+
var fd int
24+
if c.PtyRelayTty != nil {
25+
fd = int(c.PtyRelayTty.Fd())
26+
} else {
27+
fd = int(os.Stdin.Fd())
28+
}
29+
2430
state, err := terminal.MakeRaw(fd)
2531
if err != nil {
2632
return
@@ -33,6 +39,13 @@ func (c *Connect) Shell(session *ssh.Session) (err error) {
3339
return
3440
}
3541

42+
// set tty
43+
if c.PtyRelayTty != nil {
44+
session.Stdin = c.PtyRelayTty
45+
session.Stdout = c.PtyRelayTty
46+
session.Stderr = c.PtyRelayTty
47+
}
48+
3649
// Start shell
3750
err = session.Shell()
3851
if err != nil {
@@ -42,6 +55,11 @@ func (c *Connect) Shell(session *ssh.Session) (err error) {
4255
// keep alive packet
4356
go c.SendKeepAlive(session)
4457

58+
// if tty is set, get signal winch
59+
if c.PtyRelayTty != nil {
60+
go c.ChangeWinSize(session)
61+
}
62+
4563
err = session.Wait()
4664
if err != nil {
4765
return
@@ -54,7 +72,13 @@ func (c *Connect) Shell(session *ssh.Session) (err error) {
5472
// Used to start a shell with a specified command.
5573
func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) {
5674
// Input terminal Make raw
57-
fd := int(os.Stdin.Fd())
75+
var fd int
76+
if c.PtyRelayTty != nil {
77+
fd = int(c.PtyRelayTty.Fd())
78+
} else {
79+
fd = int(os.Stdin.Fd())
80+
}
81+
5882
state, err := terminal.MakeRaw(fd)
5983
if err != nil {
6084
return
@@ -67,6 +91,13 @@ func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) {
6791
return
6892
}
6993

94+
// set tty
95+
if c.PtyRelayTty != nil {
96+
session.Stdin = c.PtyRelayTty
97+
session.Stdout = c.PtyRelayTty
98+
session.Stderr = c.PtyRelayTty
99+
}
100+
70101
// Start shell
71102
err = session.Start(command)
72103
if err != nil {
@@ -84,6 +115,23 @@ func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) {
84115
return
85116
}
86117

118+
func (c *Connect) ChangeWinSize(session *ssh.Session) {
119+
// Get terminal window size
120+
var fd int
121+
if c.PtyRelayTty != nil {
122+
fd = int(c.PtyRelayTty.Fd())
123+
} else {
124+
fd = int(os.Stdout.Fd())
125+
}
126+
width, height, err := terminal.GetSize(fd)
127+
if err != nil {
128+
return
129+
}
130+
131+
// Send window size
132+
session.WindowChange(height, width)
133+
}
134+
87135
// SetLog set up terminal log logging.
88136
// This only happens in Connect.Shell().
89137
func (c *Connect) SetLog(path string, timestamp bool) {

0 commit comments

Comments
 (0)