net.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * Copyright (c) 2016, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. // for HTTPSServer.ServeTLS:
  20. /*
  21. Copyright (c) 2012 The Go Authors. All rights reserved.
  22. Redistribution and use in source and binary forms, with or without
  23. modification, are permitted provided that the following conditions are
  24. met:
  25. * Redistributions of source code must retain the above copyright
  26. notice, this list of conditions and the following disclaimer.
  27. * Redistributions in binary form must reproduce the above
  28. copyright notice, this list of conditions and the following disclaimer
  29. in the documentation and/or other materials provided with the
  30. distribution.
  31. * Neither the name of Google Inc. nor the names of its
  32. contributors may be used to endorse or promote products derived from
  33. this software without specific prior written permission.
  34. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  35. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  36. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  37. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  38. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  39. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  40. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  41. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  42. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  43. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  44. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45. */
  46. package server
  47. import (
  48. "container/list"
  49. "crypto/tls"
  50. "net"
  51. "net/http"
  52. "sync"
  53. "sync/atomic"
  54. "time"
  55. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  56. )
  57. // LRUConns is a concurrency-safe list of net.Conns ordered
  58. // by recent activity. Its purpose is to facilitate closing
  59. // the oldest connection in a set of connections.
  60. //
  61. // New connections added are referenced by a LRUConnsEntry,
  62. // which is used to Touch() active connections, which
  63. // promotes them to the front of the order and to Remove()
  64. // connections that are no longer LRU candidates.
  65. //
  66. // CloseOldest() will remove the oldest connection from the
  67. // list and call net.Conn.Close() on the connection.
  68. //
  69. // After an entry has been removed, LRUConnsEntry Touch()
  70. // and Remove() will have no effect.
  71. type LRUConns struct {
  72. mutex sync.Mutex
  73. list *list.List
  74. }
  75. // NewLRUConns initializes a new LRUConns.
  76. func NewLRUConns() *LRUConns {
  77. return &LRUConns{list: list.New()}
  78. }
  79. // Add inserts a net.Conn as the freshest connection
  80. // in a LRUConns and returns an LRUConnsEntry to be
  81. // used to freshen the connection or remove the connection
  82. // from the LRU list.
  83. func (conns *LRUConns) Add(conn net.Conn) *LRUConnsEntry {
  84. conns.mutex.Lock()
  85. defer conns.mutex.Unlock()
  86. return &LRUConnsEntry{
  87. lruConns: conns,
  88. element: conns.list.PushFront(conn),
  89. }
  90. }
  91. // CloseOldest closes the oldest connection in a
  92. // LRUConns. It calls net.Conn.Close() on the
  93. // connection.
  94. func (conns *LRUConns) CloseOldest() {
  95. conns.mutex.Lock()
  96. oldest := conns.list.Back()
  97. conn, ok := oldest.Value.(net.Conn)
  98. if oldest != nil {
  99. conns.list.Remove(oldest)
  100. }
  101. // Release mutex before closing conn
  102. conns.mutex.Unlock()
  103. if ok {
  104. conn.Close()
  105. }
  106. }
  107. // LRUConnsEntry is an entry in a LRUConns list.
  108. type LRUConnsEntry struct {
  109. lruConns *LRUConns
  110. element *list.Element
  111. }
  112. // Remove deletes the connection referenced by the
  113. // LRUConnsEntry from the associated LRUConns.
  114. // Has no effect if the entry was not initialized
  115. // or previously removed.
  116. func (entry *LRUConnsEntry) Remove() {
  117. if entry.lruConns == nil || entry.element == nil {
  118. return
  119. }
  120. entry.lruConns.mutex.Lock()
  121. defer entry.lruConns.mutex.Unlock()
  122. entry.lruConns.list.Remove(entry.element)
  123. }
  124. // Touch promotes the connection referenced by the
  125. // LRUConnsEntry to the front of the associated LRUConns.
  126. // Has no effect if the entry was not initialized
  127. // or previously removed.
  128. func (entry *LRUConnsEntry) Touch() {
  129. if entry.lruConns == nil || entry.element == nil {
  130. return
  131. }
  132. entry.lruConns.mutex.Lock()
  133. defer entry.lruConns.mutex.Unlock()
  134. entry.lruConns.list.MoveToFront(entry.element)
  135. }
  136. // ActivityMonitoredConn wraps a net.Conn, adding logic to deal with
  137. // events triggered by I/O activity.
  138. //
  139. // When an inactivity timeout is specified, the network I/O will
  140. // timeout after the specified period of read inactivity. Optionally,
  141. // ActivityMonitoredConn will also consider the connection active when
  142. // data is written to it.
  143. //
  144. // When a LRUConnsEntry is specified, then the LRU entry is promoted on
  145. // either a successful read or write.
  146. //
  147. type ActivityMonitoredConn struct {
  148. // Note: 64-bit ints used with atomic operations are at placed
  149. // at the start of struct to ensure 64-bit alignment.
  150. // (https://golang.org/pkg/sync/atomic/#pkg-note-BUG)
  151. startTime int64
  152. lastReadActivityTime int64
  153. net.Conn
  154. inactivityTimeout time.Duration
  155. activeOnWrite bool
  156. lruEntry *LRUConnsEntry
  157. }
  158. func NewActivityMonitoredConn(
  159. conn net.Conn,
  160. inactivityTimeout time.Duration,
  161. activeOnWrite bool,
  162. lruEntry *LRUConnsEntry) (*ActivityMonitoredConn, error) {
  163. if inactivityTimeout > 0 {
  164. err := conn.SetDeadline(time.Now().Add(inactivityTimeout))
  165. if err != nil {
  166. return nil, common.ContextError(err)
  167. }
  168. }
  169. now := time.Now().UnixNano()
  170. return &ActivityMonitoredConn{
  171. Conn: conn,
  172. inactivityTimeout: inactivityTimeout,
  173. activeOnWrite: activeOnWrite,
  174. startTime: now,
  175. lastReadActivityTime: now,
  176. lruEntry: lruEntry,
  177. }, nil
  178. }
  179. // GetStartTime gets the time when the ActivityMonitoredConn was
  180. // initialized.
  181. func (conn *ActivityMonitoredConn) GetStartTime() time.Time {
  182. return time.Unix(0, conn.startTime)
  183. }
  184. // GetActiveDuration returns the time elapsed between the initialization
  185. // of the ActivityMonitoredConn and the last Read. Only reads are used
  186. // for this calculation since writes may succeed locally due to buffering.
  187. func (conn *ActivityMonitoredConn) GetActiveDuration() time.Duration {
  188. return time.Duration(atomic.LoadInt64(&conn.lastReadActivityTime) - conn.startTime)
  189. }
  190. func (conn *ActivityMonitoredConn) Read(buffer []byte) (int, error) {
  191. n, err := conn.Conn.Read(buffer)
  192. if err == nil {
  193. if conn.inactivityTimeout > 0 {
  194. err = conn.Conn.SetDeadline(time.Now().Add(conn.inactivityTimeout))
  195. if err != nil {
  196. return n, common.ContextError(err)
  197. }
  198. }
  199. if conn.lruEntry != nil {
  200. conn.lruEntry.Touch()
  201. }
  202. atomic.StoreInt64(&conn.lastReadActivityTime, time.Now().UnixNano())
  203. }
  204. // Note: no context error to preserve error type
  205. return n, err
  206. }
  207. func (conn *ActivityMonitoredConn) Write(buffer []byte) (int, error) {
  208. n, err := conn.Conn.Write(buffer)
  209. if err == nil && conn.activeOnWrite {
  210. if conn.inactivityTimeout > 0 {
  211. err = conn.Conn.SetDeadline(time.Now().Add(conn.inactivityTimeout))
  212. if err != nil {
  213. return n, common.ContextError(err)
  214. }
  215. }
  216. if conn.lruEntry != nil {
  217. conn.lruEntry.Touch()
  218. }
  219. }
  220. // Note: no context error to preserve error type
  221. return n, err
  222. }
  223. // HTTPSServer is a wrapper around http.Server which adds the
  224. // ServeTLS function.
  225. type HTTPSServer struct {
  226. http.Server
  227. }
  228. // ServeTLS is a offers the equivalent interface as http.Serve.
  229. // The http package has both ListenAndServe and ListenAndServeTLS higher-
  230. // level interfaces, but only Serve (not TLS) offers a lower-level interface that
  231. // allows the caller to keep a refererence to the Listener, allowing for external
  232. // shutdown. ListenAndServeTLS also requires the TLS cert and key to be in files
  233. // and we avoid that here.
  234. // tcpKeepAliveListener is used in http.ListenAndServeTLS but not exported,
  235. // so we use a copy from https://golang.org/src/net/http/server.go.
  236. func (server *HTTPSServer) ServeTLS(listener net.Listener) error {
  237. tlsListener := tls.NewListener(tcpKeepAliveListener{listener.(*net.TCPListener)}, server.TLSConfig)
  238. return server.Serve(tlsListener)
  239. }
  240. type tcpKeepAliveListener struct {
  241. *net.TCPListener
  242. }
  243. func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
  244. tc, err := ln.AcceptTCP()
  245. if err != nil {
  246. return
  247. }
  248. tc.SetKeepAlive(true)
  249. tc.SetKeepAlivePeriod(3 * time.Minute)
  250. return tc, nil
  251. }