| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- // Copyright (C) 2016 The Syncthing Authors.
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
- // You can obtain one at https://mozilla.org/MPL/2.0/.
- package connections
- import (
- "crypto/tls"
- "net"
- "net/url"
- "sync"
- "time"
- "github.com/syncthing/syncthing/lib/config"
- "github.com/syncthing/syncthing/lib/dialer"
- "github.com/syncthing/syncthing/lib/nat"
- )
- func init() {
- factory := &tcpListenerFactory{}
- for _, scheme := range []string{"tcp", "tcp4", "tcp6"} {
- listeners[scheme] = factory
- }
- }
- type tcpListener struct {
- onAddressesChangedNotifier
- uri *url.URL
- cfg *config.Wrapper
- tlsCfg *tls.Config
- stop chan struct{}
- conns chan internalConn
- factory listenerFactory
- natService *nat.Service
- mapping *nat.Mapping
- err error
- mut sync.RWMutex
- }
- func (t *tcpListener) Serve() {
- t.mut.Lock()
- t.err = nil
- t.mut.Unlock()
- tcaddr, err := net.ResolveTCPAddr(t.uri.Scheme, t.uri.Host)
- if err != nil {
- t.mut.Lock()
- t.err = err
- t.mut.Unlock()
- l.Infoln("listen (BEP/tcp):", err)
- return
- }
- listener, err := net.ListenTCP(t.uri.Scheme, tcaddr)
- if err != nil {
- t.mut.Lock()
- t.err = err
- t.mut.Unlock()
- l.Infoln("listen (BEP/tcp):", err)
- return
- }
- defer listener.Close()
- l.Infof("TCP listener (%v) starting", listener.Addr())
- defer l.Infof("TCP listener (%v) shutting down", listener.Addr())
- mapping := t.natService.NewMapping(nat.TCP, tcaddr.IP, tcaddr.Port)
- mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) {
- t.notifyAddressesChanged(t)
- })
- defer t.natService.RemoveMapping(mapping)
- t.mut.Lock()
- t.mapping = mapping
- t.mut.Unlock()
- for {
- listener.SetDeadline(time.Now().Add(time.Second))
- conn, err := listener.Accept()
- select {
- case <-t.stop:
- if err == nil {
- conn.Close()
- }
- t.mut.Lock()
- t.mapping = nil
- t.mut.Unlock()
- return
- default:
- }
- if err != nil {
- if err, ok := err.(*net.OpError); !ok || !err.Timeout() {
- l.Warnln("Accepting connection (BEP/tcp):", err)
- }
- continue
- }
- l.Debugln("connect from", conn.RemoteAddr())
- err = dialer.SetTCPOptions(conn)
- if err != nil {
- l.Infoln(err)
- }
- err = dialer.SetTrafficClass(conn, t.cfg.Options().TrafficClass)
- if err != nil {
- l.Debugf("failed to set traffic class: %s", err)
- }
- tc := tls.Server(conn, t.tlsCfg)
- err = tlsTimedHandshake(tc)
- if err != nil {
- l.Infoln("TLS handshake (BEP/tcp):", err)
- tc.Close()
- continue
- }
- t.conns <- internalConn{tc, connTypeTCPServer, tcpPriority}
- }
- }
- func (t *tcpListener) Stop() {
- close(t.stop)
- }
- func (t *tcpListener) URI() *url.URL {
- return t.uri
- }
- func (t *tcpListener) WANAddresses() []*url.URL {
- uris := t.LANAddresses()
- t.mut.RLock()
- if t.mapping != nil {
- addrs := t.mapping.ExternalAddresses()
- for _, addr := range addrs {
- uri := *t.uri
- // Does net.JoinHostPort internally
- uri.Host = addr.String()
- uris = append(uris, &uri)
- // For every address with a specified IP, add one without an IP,
- // just in case the specified IP is still internal (router behind DMZ).
- if len(addr.IP) != 0 && !addr.IP.IsUnspecified() {
- uri = *t.uri
- addr.IP = nil
- uri.Host = addr.String()
- uris = append(uris, &uri)
- }
- }
- }
- t.mut.RUnlock()
- return uris
- }
- func (t *tcpListener) LANAddresses() []*url.URL {
- return []*url.URL{t.uri}
- }
- func (t *tcpListener) Error() error {
- t.mut.RLock()
- err := t.err
- t.mut.RUnlock()
- return err
- }
- func (t *tcpListener) String() string {
- return t.uri.String()
- }
- func (t *tcpListener) Factory() listenerFactory {
- return t.factory
- }
- func (t *tcpListener) NATType() string {
- return "unknown"
- }
- type tcpListenerFactory struct{}
- func (f *tcpListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
- return &tcpListener{
- uri: fixupPort(uri, config.DefaultTCPPort),
- cfg: cfg,
- tlsCfg: tlsCfg,
- conns: conns,
- natService: natService,
- stop: make(chan struct{}),
- factory: f,
- }
- }
- func (tcpListenerFactory) Enabled(cfg config.Configuration) bool {
- return true
- }
|