client.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package ssh
  5. import (
  6. "crypto"
  7. "crypto/ecdsa"
  8. "crypto/elliptic"
  9. "crypto/rand"
  10. "crypto/rsa"
  11. "encoding/binary"
  12. "errors"
  13. "fmt"
  14. "io"
  15. "math/big"
  16. "net"
  17. "sync"
  18. )
  19. // clientVersion is the default identification string that the client will use.
  20. var clientVersion = []byte("SSH-2.0-Go")
  21. // ClientConn represents the client side of an SSH connection.
  22. type ClientConn struct {
  23. *transport
  24. config *ClientConfig
  25. chanList // channels associated with this connection
  26. forwardList // forwarded tcpip connections from the remote side
  27. globalRequest
  28. // Address as passed to the Dial function.
  29. dialAddress string
  30. serverVersion string
  31. }
  32. type globalRequest struct {
  33. sync.Mutex
  34. response chan interface{}
  35. }
  36. // Client returns a new SSH client connection using c as the underlying transport.
  37. func Client(c net.Conn, config *ClientConfig) (*ClientConn, error) {
  38. return clientWithAddress(c, "", config)
  39. }
  40. func clientWithAddress(c net.Conn, addr string, config *ClientConfig) (*ClientConn, error) {
  41. conn := &ClientConn{
  42. transport: newTransport(c, config.rand()),
  43. config: config,
  44. globalRequest: globalRequest{response: make(chan interface{}, 1)},
  45. dialAddress: addr,
  46. }
  47. if err := conn.handshake(); err != nil {
  48. conn.Close()
  49. return nil, fmt.Errorf("handshake failed: %v", err)
  50. }
  51. go conn.mainLoop()
  52. return conn, nil
  53. }
  54. // handshake performs the client side key exchange. See RFC 4253 Section 7.
  55. func (c *ClientConn) handshake() error {
  56. var magics handshakeMagics
  57. var version []byte
  58. if len(c.config.ClientVersion) > 0 {
  59. version = []byte(c.config.ClientVersion)
  60. } else {
  61. version = clientVersion
  62. }
  63. magics.clientVersion = version
  64. version = append(version, '\r', '\n')
  65. if _, err := c.Write(version); err != nil {
  66. return err
  67. }
  68. if err := c.Flush(); err != nil {
  69. return err
  70. }
  71. // read remote server version
  72. version, err := readVersion(c)
  73. if err != nil {
  74. return err
  75. }
  76. magics.serverVersion = version
  77. c.serverVersion = string(version)
  78. clientKexInit := kexInitMsg{
  79. KexAlgos: c.config.Crypto.kexes(),
  80. ServerHostKeyAlgos: supportedHostKeyAlgos,
  81. CiphersClientServer: c.config.Crypto.ciphers(),
  82. CiphersServerClient: c.config.Crypto.ciphers(),
  83. MACsClientServer: c.config.Crypto.macs(),
  84. MACsServerClient: c.config.Crypto.macs(),
  85. CompressionClientServer: supportedCompressions,
  86. CompressionServerClient: supportedCompressions,
  87. }
  88. kexInitPacket := marshal(msgKexInit, clientKexInit)
  89. magics.clientKexInit = kexInitPacket
  90. if err := c.writePacket(kexInitPacket); err != nil {
  91. return err
  92. }
  93. packet, err := c.readPacket()
  94. if err != nil {
  95. return err
  96. }
  97. magics.serverKexInit = packet
  98. var serverKexInit kexInitMsg
  99. if err = unmarshal(&serverKexInit, packet, msgKexInit); err != nil {
  100. return err
  101. }
  102. kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(c.transport, &clientKexInit, &serverKexInit)
  103. if !ok {
  104. return errors.New("ssh: no common algorithms")
  105. }
  106. if serverKexInit.FirstKexFollows && kexAlgo != serverKexInit.KexAlgos[0] {
  107. // The server sent a Kex message for the wrong algorithm,
  108. // which we have to ignore.
  109. if _, err := c.readPacket(); err != nil {
  110. return err
  111. }
  112. }
  113. var result *kexResult
  114. switch kexAlgo {
  115. case kexAlgoECDH256:
  116. result, err = c.kexECDH(elliptic.P256(), &magics, hostKeyAlgo)
  117. case kexAlgoECDH384:
  118. result, err = c.kexECDH(elliptic.P384(), &magics, hostKeyAlgo)
  119. case kexAlgoECDH521:
  120. result, err = c.kexECDH(elliptic.P521(), &magics, hostKeyAlgo)
  121. case kexAlgoDH14SHA1:
  122. dhGroup14Once.Do(initDHGroup14)
  123. result, err = c.kexDH(crypto.SHA1, dhGroup14, &magics, hostKeyAlgo)
  124. case kexAlgoDH1SHA1:
  125. dhGroup1Once.Do(initDHGroup1)
  126. result, err = c.kexDH(crypto.SHA1, dhGroup1, &magics, hostKeyAlgo)
  127. default:
  128. err = fmt.Errorf("ssh: unexpected key exchange algorithm %v", kexAlgo)
  129. }
  130. if err != nil {
  131. return err
  132. }
  133. err = verifyHostKeySignature(hostKeyAlgo, result.HostKey, result.H, result.Signature)
  134. if err != nil {
  135. return err
  136. }
  137. if checker := c.config.HostKeyChecker; checker != nil {
  138. err = checker.Check(c.dialAddress, c.RemoteAddr(), hostKeyAlgo, result.HostKey)
  139. if err != nil {
  140. return err
  141. }
  142. }
  143. if err = c.writePacket([]byte{msgNewKeys}); err != nil {
  144. return err
  145. }
  146. if err = c.transport.writer.setupKeys(clientKeys, result.K, result.H, result.H, result.Hash); err != nil {
  147. return err
  148. }
  149. if packet, err = c.readPacket(); err != nil {
  150. return err
  151. }
  152. if packet[0] != msgNewKeys {
  153. return UnexpectedMessageError{msgNewKeys, packet[0]}
  154. }
  155. if err := c.transport.reader.setupKeys(serverKeys, result.K, result.H, result.H, result.Hash); err != nil {
  156. return err
  157. }
  158. return c.authenticate(result.H)
  159. }
  160. // kexECDH performs Elliptic Curve Diffie-Hellman key exchange as
  161. // described in RFC 5656, section 4.
  162. func (c *ClientConn) kexECDH(curve elliptic.Curve, magics *handshakeMagics, hostKeyAlgo string) (*kexResult, error) {
  163. ephKey, err := ecdsa.GenerateKey(curve, c.config.rand())
  164. if err != nil {
  165. return nil, err
  166. }
  167. kexInit := kexECDHInitMsg{
  168. ClientPubKey: elliptic.Marshal(curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
  169. }
  170. serialized := marshal(msgKexECDHInit, kexInit)
  171. if err := c.writePacket(serialized); err != nil {
  172. return nil, err
  173. }
  174. packet, err := c.readPacket()
  175. if err != nil {
  176. return nil, err
  177. }
  178. var reply kexECDHReplyMsg
  179. if err = unmarshal(&reply, packet, msgKexECDHReply); err != nil {
  180. return nil, err
  181. }
  182. x, y := elliptic.Unmarshal(curve, reply.EphemeralPubKey)
  183. if x == nil {
  184. return nil, errors.New("ssh: elliptic.Unmarshal failure")
  185. }
  186. if !validateECPublicKey(curve, x, y) {
  187. return nil, errors.New("ssh: ephemeral server key not on curve")
  188. }
  189. // generate shared secret
  190. secret, _ := curve.ScalarMult(x, y, ephKey.D.Bytes())
  191. hashFunc := ecHash(curve)
  192. h := hashFunc.New()
  193. writeString(h, magics.clientVersion)
  194. writeString(h, magics.serverVersion)
  195. writeString(h, magics.clientKexInit)
  196. writeString(h, magics.serverKexInit)
  197. writeString(h, reply.HostKey)
  198. writeString(h, kexInit.ClientPubKey)
  199. writeString(h, reply.EphemeralPubKey)
  200. K := make([]byte, intLength(secret))
  201. marshalInt(K, secret)
  202. h.Write(K)
  203. return &kexResult{
  204. H: h.Sum(nil),
  205. K: K,
  206. HostKey: reply.HostKey,
  207. Signature: reply.Signature,
  208. Hash: hashFunc,
  209. }, nil
  210. }
  211. // Verify the host key obtained in the key exchange.
  212. func verifyHostKeySignature(hostKeyAlgo string, hostKeyBytes []byte, data []byte, signature []byte) error {
  213. hostKey, rest, ok := ParsePublicKey(hostKeyBytes)
  214. if len(rest) > 0 || !ok {
  215. return errors.New("ssh: could not parse hostkey")
  216. }
  217. // Select hash function to match the hostkey algorithm, as per
  218. // RFC 4253, section 6.1 (for RSA/DSS) and RFC 5656, section
  219. // 6.2.1 (for ECDSA).
  220. var hashFunc crypto.Hash
  221. switch hostKeyAlgo {
  222. case KeyAlgoRSA:
  223. hashFunc = crypto.SHA1
  224. case KeyAlgoDSA:
  225. hashFunc = crypto.SHA1
  226. case KeyAlgoECDSA256:
  227. hashFunc = crypto.SHA256
  228. case KeyAlgoECDSA384:
  229. hashFunc = crypto.SHA384
  230. case KeyAlgoECDSA521:
  231. hashFunc = crypto.SHA512
  232. default:
  233. return errors.New("ssh: unknown key algorithm: " + hostKeyAlgo)
  234. }
  235. signed := hashFunc.New()
  236. signed.Write(data)
  237. digest := signed.Sum(nil)
  238. sig, rest, ok := parseSignatureBody(signature)
  239. if len(rest) > 0 || !ok {
  240. return errors.New("ssh: signature parse error")
  241. }
  242. if sig.Format != hostKeyAlgo {
  243. return fmt.Errorf("ssh: unexpected signature type %q", sig.Format)
  244. }
  245. return verifySignature(digest, sig, hostKey)
  246. }
  247. func verifySignature(hash []byte, sig *signature, key interface{}) error {
  248. switch pubKey := key.(type) {
  249. case *rsa.PublicKey:
  250. return verifyRSASignature(hash, sig, pubKey)
  251. }
  252. return fmt.Errorf("ssh: unknown key type %T", key)
  253. }
  254. func verifyRSASignature(hash []byte, sig *signature, key *rsa.PublicKey) error {
  255. return rsa.VerifyPKCS1v15(key, crypto.SHA1, hash, sig.Blob)
  256. }
  257. // kexResult captures the outcome of a key exchange.
  258. type kexResult struct {
  259. // Session hash. See also RFC 4253, section 8.
  260. H []byte
  261. // Shared secret. See also RFC 4253, section 8.
  262. K []byte
  263. // Host key as hashed into H
  264. HostKey []byte
  265. // Signature of H
  266. Signature []byte
  267. // Hash function that was used.
  268. Hash crypto.Hash
  269. }
  270. // kexDH performs Diffie-Hellman key agreement on a ClientConn.
  271. func (c *ClientConn) kexDH(hashFunc crypto.Hash, group *dhGroup, magics *handshakeMagics, hostKeyAlgo string) (*kexResult, error) {
  272. x, err := rand.Int(c.config.rand(), group.p)
  273. if err != nil {
  274. return nil, err
  275. }
  276. X := new(big.Int).Exp(group.g, x, group.p)
  277. kexDHInit := kexDHInitMsg{
  278. X: X,
  279. }
  280. if err := c.writePacket(marshal(msgKexDHInit, kexDHInit)); err != nil {
  281. return nil, err
  282. }
  283. packet, err := c.readPacket()
  284. if err != nil {
  285. return nil, err
  286. }
  287. var kexDHReply kexDHReplyMsg
  288. if err = unmarshal(&kexDHReply, packet, msgKexDHReply); err != nil {
  289. return nil, err
  290. }
  291. kInt, err := group.diffieHellman(kexDHReply.Y, x)
  292. if err != nil {
  293. return nil, err
  294. }
  295. h := hashFunc.New()
  296. writeString(h, magics.clientVersion)
  297. writeString(h, magics.serverVersion)
  298. writeString(h, magics.clientKexInit)
  299. writeString(h, magics.serverKexInit)
  300. writeString(h, kexDHReply.HostKey)
  301. writeInt(h, X)
  302. writeInt(h, kexDHReply.Y)
  303. K := make([]byte, intLength(kInt))
  304. marshalInt(K, kInt)
  305. h.Write(K)
  306. return &kexResult{
  307. H: h.Sum(nil),
  308. K: K,
  309. HostKey: kexDHReply.HostKey,
  310. Signature: kexDHReply.Signature,
  311. Hash: hashFunc,
  312. }, nil
  313. }
  314. // mainLoop reads incoming messages and routes channel messages
  315. // to their respective ClientChans.
  316. func (c *ClientConn) mainLoop() {
  317. defer func() {
  318. c.Close()
  319. c.chanList.closeAll()
  320. c.forwardList.closeAll()
  321. }()
  322. for {
  323. packet, err := c.readPacket()
  324. if err != nil {
  325. break
  326. }
  327. // TODO(dfc) A note on blocking channel use.
  328. // The msg, data and dataExt channels of a clientChan can
  329. // cause this loop to block indefinately if the consumer does
  330. // not service them.
  331. switch packet[0] {
  332. case msgChannelData:
  333. if len(packet) < 9 {
  334. // malformed data packet
  335. return
  336. }
  337. remoteId := binary.BigEndian.Uint32(packet[1:5])
  338. length := binary.BigEndian.Uint32(packet[5:9])
  339. packet = packet[9:]
  340. if length != uint32(len(packet)) {
  341. return
  342. }
  343. ch, ok := c.getChan(remoteId)
  344. if !ok {
  345. return
  346. }
  347. ch.stdout.write(packet)
  348. case msgChannelExtendedData:
  349. if len(packet) < 13 {
  350. // malformed data packet
  351. return
  352. }
  353. remoteId := binary.BigEndian.Uint32(packet[1:5])
  354. datatype := binary.BigEndian.Uint32(packet[5:9])
  355. length := binary.BigEndian.Uint32(packet[9:13])
  356. packet = packet[13:]
  357. if length != uint32(len(packet)) {
  358. return
  359. }
  360. // RFC 4254 5.2 defines data_type_code 1 to be data destined
  361. // for stderr on interactive sessions. Other data types are
  362. // silently discarded.
  363. if datatype == 1 {
  364. ch, ok := c.getChan(remoteId)
  365. if !ok {
  366. return
  367. }
  368. ch.stderr.write(packet)
  369. }
  370. default:
  371. decoded, err := decode(packet)
  372. if err != nil {
  373. if _, ok := err.(UnexpectedMessageError); ok {
  374. fmt.Printf("mainLoop: unexpected message: %v\n", err)
  375. continue
  376. }
  377. return
  378. }
  379. switch msg := decoded.(type) {
  380. case *channelOpenMsg:
  381. c.handleChanOpen(msg)
  382. case *channelOpenConfirmMsg:
  383. ch, ok := c.getChan(msg.PeersId)
  384. if !ok {
  385. return
  386. }
  387. ch.msg <- msg
  388. case *channelOpenFailureMsg:
  389. ch, ok := c.getChan(msg.PeersId)
  390. if !ok {
  391. return
  392. }
  393. ch.msg <- msg
  394. case *channelCloseMsg:
  395. ch, ok := c.getChan(msg.PeersId)
  396. if !ok {
  397. return
  398. }
  399. ch.Close()
  400. close(ch.msg)
  401. c.chanList.remove(msg.PeersId)
  402. case *channelEOFMsg:
  403. ch, ok := c.getChan(msg.PeersId)
  404. if !ok {
  405. return
  406. }
  407. ch.stdout.eof()
  408. // RFC 4254 is mute on how EOF affects dataExt messages but
  409. // it is logical to signal EOF at the same time.
  410. ch.stderr.eof()
  411. case *channelRequestSuccessMsg:
  412. ch, ok := c.getChan(msg.PeersId)
  413. if !ok {
  414. return
  415. }
  416. ch.msg <- msg
  417. case *channelRequestFailureMsg:
  418. ch, ok := c.getChan(msg.PeersId)
  419. if !ok {
  420. return
  421. }
  422. ch.msg <- msg
  423. case *channelRequestMsg:
  424. ch, ok := c.getChan(msg.PeersId)
  425. if !ok {
  426. return
  427. }
  428. ch.msg <- msg
  429. case *windowAdjustMsg:
  430. ch, ok := c.getChan(msg.PeersId)
  431. if !ok {
  432. return
  433. }
  434. if !ch.remoteWin.add(msg.AdditionalBytes) {
  435. // invalid window update
  436. return
  437. }
  438. case *globalRequestMsg:
  439. // This handles keepalive messages and matches
  440. // the behaviour of OpenSSH.
  441. if msg.WantReply {
  442. c.writePacket(marshal(msgRequestFailure, globalRequestFailureMsg{}))
  443. }
  444. case *globalRequestSuccessMsg, *globalRequestFailureMsg:
  445. c.globalRequest.response <- msg
  446. case *disconnectMsg:
  447. return
  448. default:
  449. fmt.Printf("mainLoop: unhandled message %T: %v\n", msg, msg)
  450. }
  451. }
  452. }
  453. }
  454. // Handle channel open messages from the remote side.
  455. func (c *ClientConn) handleChanOpen(msg *channelOpenMsg) {
  456. if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
  457. c.sendConnectionFailed(msg.PeersId)
  458. }
  459. switch msg.ChanType {
  460. case "forwarded-tcpip":
  461. laddr, rest, ok := parseTCPAddr(msg.TypeSpecificData)
  462. if !ok {
  463. // invalid request
  464. c.sendConnectionFailed(msg.PeersId)
  465. return
  466. }
  467. l, ok := c.forwardList.lookup(*laddr)
  468. if !ok {
  469. // TODO: print on a more structured log.
  470. fmt.Println("could not find forward list entry for", laddr)
  471. // Section 7.2, implementations MUST reject suprious incoming
  472. // connections.
  473. c.sendConnectionFailed(msg.PeersId)
  474. return
  475. }
  476. raddr, rest, ok := parseTCPAddr(rest)
  477. if !ok {
  478. // invalid request
  479. c.sendConnectionFailed(msg.PeersId)
  480. return
  481. }
  482. ch := c.newChan(c.transport)
  483. ch.remoteId = msg.PeersId
  484. ch.remoteWin.add(msg.PeersWindow)
  485. ch.maxPacket = msg.MaxPacketSize
  486. m := channelOpenConfirmMsg{
  487. PeersId: ch.remoteId,
  488. MyId: ch.localId,
  489. MyWindow: 1 << 14,
  490. // As per RFC 4253 6.1, 32k is also the minimum.
  491. MaxPacketSize: 1 << 15,
  492. }
  493. c.writePacket(marshal(msgChannelOpenConfirm, m))
  494. l <- forward{ch, raddr}
  495. default:
  496. // unknown channel type
  497. m := channelOpenFailureMsg{
  498. PeersId: msg.PeersId,
  499. Reason: UnknownChannelType,
  500. Message: fmt.Sprintf("unknown channel type: %v", msg.ChanType),
  501. Language: "en_US.UTF-8",
  502. }
  503. c.writePacket(marshal(msgChannelOpenFailure, m))
  504. }
  505. }
  506. // sendGlobalRequest sends a global request message as specified
  507. // in RFC4254 section 4. To correctly synchronise messages, a lock
  508. // is held internally until a response is returned.
  509. func (c *ClientConn) sendGlobalRequest(m interface{}) (*globalRequestSuccessMsg, error) {
  510. c.globalRequest.Lock()
  511. defer c.globalRequest.Unlock()
  512. if err := c.writePacket(marshal(msgGlobalRequest, m)); err != nil {
  513. return nil, err
  514. }
  515. r := <-c.globalRequest.response
  516. if r, ok := r.(*globalRequestSuccessMsg); ok {
  517. return r, nil
  518. }
  519. return nil, errors.New("request failed")
  520. }
  521. // sendConnectionFailed rejects an incoming channel identified
  522. // by remoteId.
  523. func (c *ClientConn) sendConnectionFailed(remoteId uint32) error {
  524. m := channelOpenFailureMsg{
  525. PeersId: remoteId,
  526. Reason: ConnectionFailed,
  527. Message: "invalid request",
  528. Language: "en_US.UTF-8",
  529. }
  530. return c.writePacket(marshal(msgChannelOpenFailure, m))
  531. }
  532. // parseTCPAddr parses the originating address from the remote into a *net.TCPAddr.
  533. // RFC 4254 section 7.2 is mute on what to do if parsing fails but the forwardlist
  534. // requires a valid *net.TCPAddr to operate, so we enforce that restriction here.
  535. func parseTCPAddr(b []byte) (*net.TCPAddr, []byte, bool) {
  536. addr, b, ok := parseString(b)
  537. if !ok {
  538. return nil, b, false
  539. }
  540. port, b, ok := parseUint32(b)
  541. if !ok {
  542. return nil, b, false
  543. }
  544. ip := net.ParseIP(string(addr))
  545. if ip == nil {
  546. return nil, b, false
  547. }
  548. return &net.TCPAddr{IP: ip, Port: int(port)}, b, true
  549. }
  550. // Dial connects to the given network address using net.Dial and
  551. // then initiates a SSH handshake, returning the resulting client connection.
  552. func Dial(network, addr string, config *ClientConfig) (*ClientConn, error) {
  553. conn, err := net.Dial(network, addr)
  554. if err != nil {
  555. return nil, err
  556. }
  557. return clientWithAddress(conn, addr, config)
  558. }
  559. // A ClientConfig structure is used to configure a ClientConn. After one has
  560. // been passed to an SSH function it must not be modified.
  561. type ClientConfig struct {
  562. // Rand provides the source of entropy for key exchange. If Rand is
  563. // nil, the cryptographic random reader in package crypto/rand will
  564. // be used.
  565. Rand io.Reader
  566. // The username to authenticate.
  567. User string
  568. // A slice of ClientAuth methods. Only the first instance
  569. // of a particular RFC 4252 method will be used during authentication.
  570. Auth []ClientAuth
  571. // HostKeyChecker, if not nil, is called during the cryptographic
  572. // handshake to validate the server's host key. A nil HostKeyChecker
  573. // implies that all host keys are accepted.
  574. HostKeyChecker HostKeyChecker
  575. // Cryptographic-related configuration.
  576. Crypto CryptoConfig
  577. // The identification string that will be used for the connection.
  578. // If empty, a reasonable default is used.
  579. ClientVersion string
  580. }
  581. func (c *ClientConfig) rand() io.Reader {
  582. if c.Rand == nil {
  583. return rand.Reader
  584. }
  585. return c.Rand
  586. }
  587. // Thread safe channel list.
  588. type chanList struct {
  589. // protects concurrent access to chans
  590. sync.Mutex
  591. // chans are indexed by the local id of the channel, clientChan.localId.
  592. // The PeersId value of messages received by ClientConn.mainLoop is
  593. // used to locate the right local clientChan in this slice.
  594. chans []*clientChan
  595. }
  596. // Allocate a new ClientChan with the next avail local id.
  597. func (c *chanList) newChan(t *transport) *clientChan {
  598. c.Lock()
  599. defer c.Unlock()
  600. for i := range c.chans {
  601. if c.chans[i] == nil {
  602. ch := newClientChan(t, uint32(i))
  603. c.chans[i] = ch
  604. return ch
  605. }
  606. }
  607. i := len(c.chans)
  608. ch := newClientChan(t, uint32(i))
  609. c.chans = append(c.chans, ch)
  610. return ch
  611. }
  612. func (c *chanList) getChan(id uint32) (*clientChan, bool) {
  613. c.Lock()
  614. defer c.Unlock()
  615. if id >= uint32(len(c.chans)) {
  616. return nil, false
  617. }
  618. return c.chans[id], true
  619. }
  620. func (c *chanList) remove(id uint32) {
  621. c.Lock()
  622. defer c.Unlock()
  623. c.chans[id] = nil
  624. }
  625. func (c *chanList) closeAll() {
  626. c.Lock()
  627. defer c.Unlock()
  628. for _, ch := range c.chans {
  629. if ch == nil {
  630. continue
  631. }
  632. ch.Close()
  633. close(ch.msg)
  634. }
  635. }