structs.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package connections
  7. import (
  8. "crypto/tls"
  9. "fmt"
  10. "io"
  11. "net"
  12. "net/url"
  13. "time"
  14. "github.com/syncthing/syncthing/lib/config"
  15. "github.com/syncthing/syncthing/lib/nat"
  16. "github.com/syncthing/syncthing/lib/protocol"
  17. )
  18. // Connection is what we expose to the outside. It is a protocol.Connection
  19. // that can be closed and has some metadata.
  20. type Connection interface {
  21. protocol.Connection
  22. io.Closer
  23. Type() string
  24. Transport() string
  25. RemoteAddr() net.Addr
  26. Priority() int
  27. String() string
  28. }
  29. // completeConn is the aggregation of an internalConn and the
  30. // protocol.Connection running on top of it. It implements the Connection
  31. // interface.
  32. type completeConn struct {
  33. internalConn
  34. protocol.Connection
  35. }
  36. // internalConn is the raw TLS connection plus some metadata on where it
  37. // came from (type, priority).
  38. type internalConn struct {
  39. *tls.Conn
  40. connType connType
  41. priority int
  42. }
  43. type connType int
  44. const (
  45. connTypeRelayClient connType = iota
  46. connTypeRelayServer
  47. connTypeTCPClient
  48. connTypeTCPServer
  49. )
  50. func (t connType) String() string {
  51. switch t {
  52. case connTypeRelayClient:
  53. return "relay-client"
  54. case connTypeRelayServer:
  55. return "relay-server"
  56. case connTypeTCPClient:
  57. return "tcp-client"
  58. case connTypeTCPServer:
  59. return "tcp-server"
  60. default:
  61. return "unknown-type"
  62. }
  63. }
  64. func (t connType) Transport() string {
  65. switch t {
  66. case connTypeRelayClient, connTypeRelayServer:
  67. return "relay"
  68. case connTypeTCPClient, connTypeTCPServer:
  69. return "tcp"
  70. default:
  71. return "unknown"
  72. }
  73. }
  74. func (c internalConn) Type() string {
  75. return c.connType.String()
  76. }
  77. func (c internalConn) Priority() int {
  78. return c.priority
  79. }
  80. func (c internalConn) Transport() string {
  81. transport := c.connType.Transport()
  82. host, _, err := net.SplitHostPort(c.LocalAddr().String())
  83. if err != nil {
  84. return transport
  85. }
  86. ip := net.ParseIP(host)
  87. if ip == nil {
  88. return transport
  89. }
  90. if ip.To4() != nil {
  91. return transport + "4"
  92. }
  93. return transport + "6"
  94. }
  95. func (c internalConn) String() string {
  96. return fmt.Sprintf("%s-%s/%s", c.LocalAddr(), c.RemoteAddr(), c.Type())
  97. }
  98. type dialerFactory interface {
  99. New(*config.Wrapper, *tls.Config) genericDialer
  100. Priority() int
  101. AlwaysWAN() bool
  102. Valid(config.Configuration) error
  103. String() string
  104. }
  105. type genericDialer interface {
  106. Dial(protocol.DeviceID, *url.URL) (internalConn, error)
  107. RedialFrequency() time.Duration
  108. }
  109. type listenerFactory interface {
  110. New(*url.URL, *config.Wrapper, *tls.Config, chan internalConn, *nat.Service) genericListener
  111. Valid(config.Configuration) error
  112. }
  113. type genericListener interface {
  114. Serve()
  115. Stop()
  116. URI() *url.URL
  117. // A given address can potentially be mutated by the listener.
  118. // For example we bind to tcp://0.0.0.0, but that for example might return
  119. // tcp://gateway1.ip and tcp://gateway2.ip as WAN addresses due to there
  120. // being multiple gateways, and us managing to get a UPnP mapping on both
  121. // and tcp://192.168.0.1 and tcp://10.0.0.1 due to there being multiple
  122. // network interfaces. (The later case for LAN addresses is made up just
  123. // to provide an example)
  124. WANAddresses() []*url.URL
  125. LANAddresses() []*url.URL
  126. Error() error
  127. OnAddressesChanged(func(genericListener))
  128. String() string
  129. Factory() listenerFactory
  130. NATType() string
  131. }
  132. type Model interface {
  133. protocol.Model
  134. AddConnection(conn Connection, hello protocol.HelloResult)
  135. Connection(remoteID protocol.DeviceID) (Connection, bool)
  136. OnHello(protocol.DeviceID, net.Addr, protocol.HelloResult) error
  137. GetHello(protocol.DeviceID) protocol.HelloIntf
  138. }
  139. // serviceFunc wraps a function to create a suture.Service without stop
  140. // functionality.
  141. type serviceFunc func()
  142. func (f serviceFunc) Serve() { f() }
  143. func (f serviceFunc) Stop() {}
  144. type onAddressesChangedNotifier struct {
  145. callbacks []func(genericListener)
  146. }
  147. func (o *onAddressesChangedNotifier) OnAddressesChanged(callback func(genericListener)) {
  148. o.callbacks = append(o.callbacks, callback)
  149. }
  150. func (o *onAddressesChangedNotifier) notifyAddressesChanged(l genericListener) {
  151. for _, callback := range o.callbacks {
  152. callback(l)
  153. }
  154. }
  155. type dialTarget struct {
  156. dialer genericDialer
  157. priority int
  158. uri *url.URL
  159. deviceID protocol.DeviceID
  160. }
  161. func (t dialTarget) Dial() (internalConn, error) {
  162. l.Debugln("dialing", t.deviceID, t.uri, "prio", t.priority)
  163. conn, err := t.dialer.Dial(t.deviceID, t.uri)
  164. if err != nil {
  165. l.Debugln("dialing", t.deviceID, t.uri, "error:", err)
  166. } else {
  167. l.Debugln("dialing", t.deviceID, t.uri, "success:", conn)
  168. }
  169. return conn, err
  170. }