telnet.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "golang.org/x/crypto/ssh/terminal"
  6. "io"
  7. "net"
  8. "os"
  9. "os/signal"
  10. "strings"
  11. "syscall"
  12. )
  13. // Copyright 2012 the u-root Authors. All rights reserved
  14. // Use of this source code is governed by a BSD-style
  15. // license that can be found in the LICENSE file.
  16. type (
  17. chunk struct {
  18. id int
  19. buf []byte
  20. }
  21. )
  22. const (
  23. echo = false
  24. )
  25. func comprefix(lines [][]byte) (int, int) {
  26. var line0 []byte
  27. len0 := 0
  28. for _, ln := range lines {
  29. if len(ln) > len0 {
  30. line0 = ln
  31. len0 = len(ln)
  32. }
  33. }
  34. ndiff := 0
  35. for i := range line0 {
  36. nshort := 0
  37. for _, ln := range lines {
  38. if i >= len(ln) {
  39. nshort++
  40. } else if ln[i] != line0[i] {
  41. ndiff++
  42. }
  43. }
  44. if ndiff > 0 {
  45. return i, ndiff
  46. }
  47. if nshort > 0 {
  48. return i, ndiff
  49. }
  50. }
  51. return len(line0), ndiff
  52. }
  53. func main() {
  54. if len(os.Args) < 2 {
  55. os.Exit(1)
  56. }
  57. var conns []*net.TCPConn
  58. for _, a := range os.Args[1:] {
  59. port := "1522"
  60. if !strings.Contains(a, ":") {
  61. a = a + ":" + port
  62. }
  63. tcpdst, err := net.ResolveTCPAddr("tcp", a)
  64. if err != nil {
  65. fmt.Printf("%v\n", err)
  66. os.Exit(1)
  67. }
  68. c, err := net.DialTCP("tcp", nil, tcpdst)
  69. if err != nil {
  70. fmt.Printf("%v\n", err)
  71. os.Exit(1)
  72. }
  73. conns = append(conns, c)
  74. }
  75. unraw, err := terminal.MakeRaw(0)
  76. if err != nil {
  77. fmt.Printf("%v\n", err)
  78. os.Exit(1)
  79. }
  80. defer terminal.Restore(0, unraw)
  81. sigc := make(chan os.Signal, 1)
  82. signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
  83. go func() {
  84. for _ = range sigc {
  85. terminal.Restore(0, unraw)
  86. os.Exit(1)
  87. }
  88. }()
  89. go func() {
  90. buf := make([]byte, 256)
  91. for {
  92. n, err := os.Stdin.Read(buf)
  93. if err != nil {
  94. if err != io.EOF {
  95. fmt.Printf("%v\n", err)
  96. }
  97. for _, c := range conns {
  98. c.CloseWrite() // I know, I know.. but it is handy sometimes.
  99. }
  100. break
  101. }
  102. buf = buf[0:n]
  103. for i := range buf {
  104. if echo {
  105. fmt.Printf("%s", string(buf[i]))
  106. }
  107. if buf[i] == '\r' {
  108. buf[i] = '\n'
  109. if echo {
  110. fmt.Printf("\n")
  111. }
  112. }
  113. }
  114. for _, c := range conns {
  115. if _, err := c.Write(buf); err != nil {
  116. fmt.Printf("%v\n", err)
  117. break
  118. }
  119. }
  120. }
  121. }()
  122. waitc := make(chan int)
  123. chunkc := make(chan chunk)
  124. for id, c := range conns {
  125. go func(id int, c *net.TCPConn) {
  126. for {
  127. buf := make([]byte, 256)
  128. n, err := c.Read(buf)
  129. if err != nil {
  130. if err != io.EOF {
  131. fmt.Printf("%v\n", err)
  132. }
  133. c.Close()
  134. waitc <- 1
  135. break
  136. }
  137. if n == 0 {
  138. continue
  139. }
  140. chunkc <- chunk{id, buf[0:n]}
  141. }
  142. }(id, c)
  143. }
  144. act := make([][]byte, len(conns))
  145. go func() {
  146. oldpfix := 0
  147. insync := true
  148. for {
  149. chunk, more := <-chunkc
  150. if !more {
  151. break
  152. }
  153. id := chunk.id
  154. for _, b := range chunk.buf {
  155. act[id] = append(act[id], b)
  156. if false && b == '\b' {
  157. act[id] = append(act[id], ' ')
  158. act[id] = append(act[id], '\b')
  159. }
  160. }
  161. /* streams agree, so spit out all they agree on */
  162. if insync {
  163. newpfix, ndiff := comprefix(act)
  164. if ndiff == 0 && newpfix > oldpfix {
  165. os.Stdout.Write(act[id][oldpfix:newpfix])
  166. for {
  167. i := bytes.IndexByte(act[id][:newpfix], '\n')
  168. if i == -1 {
  169. break
  170. }
  171. for id := range act {
  172. clen := copy(act[id], act[id][i+1:])
  173. act[id] = act[id][0:clen]
  174. }
  175. newpfix = newpfix - (i + 1)
  176. }
  177. oldpfix = newpfix
  178. }
  179. if ndiff > 0 {
  180. insync = false
  181. }
  182. }
  183. /*
  184. * streams disagree, first to newline completes from oldpfix on.
  185. * the outer loop is just for transitioning from insync, where
  186. * a leader may be several lines ahead
  187. */
  188. if !insync {
  189. for id := range act {
  190. for {
  191. i := bytes.IndexByte(act[id], '\n')
  192. if i != -1 {
  193. if oldpfix == 0 {
  194. fmt.Fprintf(os.Stdout, "[%d]", id)
  195. }
  196. os.Stdout.Write(act[id][oldpfix : i+1])
  197. clen := copy(act[id], act[id][i+1:])
  198. act[id] = act[id][0:clen]
  199. oldpfix = 0
  200. } else {
  201. break
  202. }
  203. }
  204. }
  205. /* try for prompt (or sheer luck) */
  206. if _, ndiff := comprefix(act); ndiff == 0 {
  207. insync = true
  208. oldpfix = 0
  209. }
  210. }
  211. }
  212. waitc <- 1
  213. }()
  214. for _ = range conns {
  215. <-waitc
  216. }
  217. close(chunkc)
  218. <-waitc
  219. }