2019-05-29 07:56:40 +00:00
|
|
|
// Copyright (C) 2019 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 http://mozilla.org/MPL/2.0/.
|
|
|
|
|
2024-02-09 15:35:29 +00:00
|
|
|
//go:build !noquic
|
|
|
|
// +build !noquic
|
2019-05-29 07:56:40 +00:00
|
|
|
|
|
|
|
package connections
|
|
|
|
|
|
|
|
import (
|
2023-08-21 13:25:52 +00:00
|
|
|
"context"
|
2020-05-01 07:14:28 +00:00
|
|
|
"crypto/tls"
|
2019-05-29 07:56:40 +00:00
|
|
|
"net"
|
2021-07-10 11:53:51 +00:00
|
|
|
"net/url"
|
2023-08-21 13:25:52 +00:00
|
|
|
"sync/atomic"
|
2022-08-03 13:43:26 +00:00
|
|
|
"time"
|
2019-05-29 07:56:40 +00:00
|
|
|
|
2023-02-02 21:00:50 +00:00
|
|
|
"github.com/quic-go/quic-go"
|
2023-08-21 13:25:52 +00:00
|
|
|
"github.com/quic-go/quic-go/logging"
|
2023-02-02 21:00:50 +00:00
|
|
|
|
2022-09-14 06:44:46 +00:00
|
|
|
"github.com/syncthing/syncthing/lib/osutil"
|
2019-05-29 07:56:40 +00:00
|
|
|
)
|
|
|
|
|
2023-02-02 21:00:50 +00:00
|
|
|
var quicConfig = &quic.Config{
|
2023-08-21 13:25:52 +00:00
|
|
|
MaxIdleTimeout: 30 * time.Second,
|
|
|
|
KeepAlivePeriod: 15 * time.Second,
|
2023-02-02 21:00:50 +00:00
|
|
|
}
|
2019-05-29 07:56:40 +00:00
|
|
|
|
2021-07-10 11:53:51 +00:00
|
|
|
func quicNetwork(uri *url.URL) string {
|
|
|
|
switch uri.Scheme {
|
|
|
|
case "quic4":
|
|
|
|
return "udp4"
|
|
|
|
case "quic6":
|
|
|
|
return "udp6"
|
|
|
|
default:
|
|
|
|
return "udp"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-29 07:56:40 +00:00
|
|
|
type quicTlsConn struct {
|
2022-04-12 12:27:29 +00:00
|
|
|
quic.Connection
|
2019-05-29 07:56:40 +00:00
|
|
|
quic.Stream
|
2019-06-09 21:14:00 +00:00
|
|
|
// If we created this connection, we should be the ones closing it.
|
|
|
|
createdConn net.PacketConn
|
2019-05-29 07:56:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (q *quicTlsConn) Close() error {
|
|
|
|
sterr := q.Stream.Close()
|
2022-04-12 12:27:29 +00:00
|
|
|
seerr := q.Connection.CloseWithError(0, "closing")
|
2019-06-09 21:14:00 +00:00
|
|
|
var pcerr error
|
|
|
|
if q.createdConn != nil {
|
|
|
|
pcerr = q.createdConn.Close()
|
|
|
|
}
|
2019-05-29 07:56:40 +00:00
|
|
|
if sterr != nil {
|
|
|
|
return sterr
|
|
|
|
}
|
2019-06-09 21:14:00 +00:00
|
|
|
if seerr != nil {
|
|
|
|
return seerr
|
|
|
|
}
|
|
|
|
return pcerr
|
2019-05-29 07:56:40 +00:00
|
|
|
}
|
|
|
|
|
2020-05-01 07:14:28 +00:00
|
|
|
func (q *quicTlsConn) ConnectionState() tls.ConnectionState {
|
2023-08-21 13:25:52 +00:00
|
|
|
return q.Connection.ConnectionState().TLS
|
2020-05-01 07:14:28 +00:00
|
|
|
}
|
|
|
|
|
2023-08-21 13:25:52 +00:00
|
|
|
func transportConnUnspecified(conn any) bool {
|
|
|
|
tran, ok := conn.(*quic.Transport)
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
addr := tran.Conn.LocalAddr()
|
2022-09-14 06:44:46 +00:00
|
|
|
ip, err := osutil.IPFromAddr(addr)
|
|
|
|
return err == nil && ip.IsUnspecified()
|
2019-05-29 07:56:40 +00:00
|
|
|
}
|
2023-08-21 13:25:52 +00:00
|
|
|
|
|
|
|
type writeTrackingTracer struct {
|
|
|
|
lastWrite atomic.Int64 // unix nanos
|
|
|
|
}
|
|
|
|
|
2023-09-25 19:45:57 +00:00
|
|
|
func (t *writeTrackingTracer) loggingTracer() *logging.Tracer {
|
|
|
|
return &logging.Tracer{
|
|
|
|
SentPacket: func(net.Addr, *logging.Header, logging.ByteCount, []logging.Frame) {
|
|
|
|
t.lastWrite.Store(time.Now().UnixNano())
|
|
|
|
},
|
|
|
|
SentVersionNegotiationPacket: func(net.Addr, logging.ArbitraryLenConnectionID, logging.ArbitraryLenConnectionID, []logging.VersionNumber) {
|
|
|
|
t.lastWrite.Store(time.Now().UnixNano())
|
|
|
|
},
|
|
|
|
}
|
2023-08-21 13:25:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *writeTrackingTracer) LastWrite() time.Time {
|
|
|
|
return time.Unix(0, t.lastWrite.Load())
|
|
|
|
}
|
|
|
|
|
|
|
|
// A transportPacketConn is a net.PacketConn that uses a quic.Transport.
|
|
|
|
type transportPacketConn struct {
|
|
|
|
tran *quic.Transport
|
|
|
|
readDeadline atomic.Value // time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *transportPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
|
|
|
ctx := context.Background()
|
|
|
|
if deadline, ok := t.readDeadline.Load().(time.Time); ok && !deadline.IsZero() {
|
|
|
|
var cancel context.CancelFunc
|
|
|
|
ctx, cancel = context.WithDeadline(ctx, deadline)
|
|
|
|
defer cancel()
|
|
|
|
}
|
|
|
|
return t.tran.ReadNonQUICPacket(ctx, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *transportPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|
|
|
return t.tran.WriteTo(p, addr)
|
|
|
|
}
|
|
|
|
|
2023-09-25 19:45:57 +00:00
|
|
|
func (*transportPacketConn) Close() error {
|
2023-08-21 13:25:52 +00:00
|
|
|
return errUnsupported
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *transportPacketConn) LocalAddr() net.Addr {
|
|
|
|
return t.tran.Conn.LocalAddr()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *transportPacketConn) SetDeadline(deadline time.Time) error {
|
|
|
|
return t.SetReadDeadline(deadline)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *transportPacketConn) SetReadDeadline(deadline time.Time) error {
|
|
|
|
t.readDeadline.Store(deadline)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-25 19:45:57 +00:00
|
|
|
func (*transportPacketConn) SetWriteDeadline(_ time.Time) error {
|
2023-08-21 13:25:52 +00:00
|
|
|
return nil // yolo
|
|
|
|
}
|