21
vendor/github.com/anacrolix/chansync/LICENSE
generated
vendored
Normal file
21
vendor/github.com/anacrolix/chansync/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Matt Joiner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
34
vendor/github.com/anacrolix/chansync/broadcast-cond.go.go
generated
vendored
Normal file
34
vendor/github.com/anacrolix/chansync/broadcast-cond.go.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package chansync
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/chansync/events"
|
||||
"github.com/anacrolix/sync"
|
||||
)
|
||||
|
||||
// Can be used as zero-value. Due to the caller needing to bring their own synchronization, an
|
||||
// equivalent to "sync".Cond.Signal is not provided. BroadcastCond is intended to be selected on
|
||||
// with other channels.
|
||||
type BroadcastCond struct {
|
||||
mu sync.Mutex
|
||||
ch chan struct{}
|
||||
}
|
||||
|
||||
func (me *BroadcastCond) Broadcast() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.ch != nil {
|
||||
close(me.ch)
|
||||
me.ch = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Should be called before releasing locks on resources that might trigger subsequent Broadcasts.
|
||||
// The channel is closed when the condition changes.
|
||||
func (me *BroadcastCond) Signaled() events.Signaled {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.ch == nil {
|
||||
me.ch = make(chan struct{})
|
||||
}
|
||||
return me.ch
|
||||
}
|
||||
12
vendor/github.com/anacrolix/chansync/events/events.go
generated
vendored
Normal file
12
vendor/github.com/anacrolix/chansync/events/events.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package events
|
||||
|
||||
// Here we'll strongly-type channels to assist correct usage, if possible.
|
||||
|
||||
type (
|
||||
Signaled <-chan struct{}
|
||||
Done <-chan struct{}
|
||||
Active <-chan struct{}
|
||||
Signal chan<- struct{}
|
||||
Acquire chan<- struct{}
|
||||
Release <-chan struct{}
|
||||
)
|
||||
79
vendor/github.com/anacrolix/chansync/flag.go
generated
vendored
Normal file
79
vendor/github.com/anacrolix/chansync/flag.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package chansync
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/chansync/events"
|
||||
)
|
||||
|
||||
// Flag wraps a boolean value that starts as false (off). You can wait for it to be on or off, and
|
||||
// set the value as needed.
|
||||
type Flag struct {
|
||||
mu sync.Mutex
|
||||
on chan struct{}
|
||||
off chan struct{}
|
||||
state bool
|
||||
inited bool
|
||||
}
|
||||
|
||||
func (me *Flag) Bool() bool {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
return me.state
|
||||
}
|
||||
|
||||
func (me *Flag) On() events.Active {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
me.init()
|
||||
return me.on
|
||||
}
|
||||
|
||||
func (me *Flag) Off() events.Active {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
me.init()
|
||||
return me.off
|
||||
}
|
||||
|
||||
func (me *Flag) init() {
|
||||
if me.inited {
|
||||
return
|
||||
}
|
||||
me.on = make(chan struct{})
|
||||
me.off = make(chan struct{})
|
||||
close(me.off)
|
||||
me.inited = true
|
||||
}
|
||||
|
||||
func (me *Flag) SetBool(b bool) {
|
||||
if b {
|
||||
me.Set()
|
||||
} else {
|
||||
me.Clear()
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Flag) Set() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
me.init()
|
||||
if me.state {
|
||||
return
|
||||
}
|
||||
me.state = true
|
||||
close(me.on)
|
||||
me.off = make(chan struct{})
|
||||
}
|
||||
|
||||
func (me *Flag) Clear() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
me.init()
|
||||
if !me.state {
|
||||
return
|
||||
}
|
||||
me.state = false
|
||||
close(me.off)
|
||||
me.on = make(chan struct{})
|
||||
}
|
||||
28
vendor/github.com/anacrolix/chansync/level.go
generated
vendored
Normal file
28
vendor/github.com/anacrolix/chansync/level.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package chansync
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/chansync/events"
|
||||
)
|
||||
|
||||
type LevelTrigger struct {
|
||||
ch chan struct{}
|
||||
initOnce sync.Once
|
||||
}
|
||||
|
||||
func (me *LevelTrigger) Signal() events.Signal {
|
||||
me.init()
|
||||
return me.ch
|
||||
}
|
||||
|
||||
func (me *LevelTrigger) Active() events.Active {
|
||||
me.init()
|
||||
return me.ch
|
||||
}
|
||||
|
||||
func (me *LevelTrigger) init() {
|
||||
me.initOnce.Do(func() {
|
||||
me.ch = make(chan struct{})
|
||||
})
|
||||
}
|
||||
26
vendor/github.com/anacrolix/chansync/semaphore.go
generated
vendored
Normal file
26
vendor/github.com/anacrolix/chansync/semaphore.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package chansync
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/chansync/events"
|
||||
)
|
||||
|
||||
// Channel semaphore, as is popular for controlling access to limited resources. Should not be used
|
||||
// zero-initialized.
|
||||
type Semaphore struct {
|
||||
ch chan struct{}
|
||||
}
|
||||
|
||||
// Returns an initialized semaphore with n slots.
|
||||
func NewSemaphore(n int) Semaphore {
|
||||
return Semaphore{ch: make(chan struct{}, n)}
|
||||
}
|
||||
|
||||
// Returns a channel for acquiring a slot.
|
||||
func (me Semaphore) Acquire() events.Acquire {
|
||||
return me.ch
|
||||
}
|
||||
|
||||
// Returns a channel for releasing a slot.
|
||||
func (me Semaphore) Release() events.Release {
|
||||
return me.ch
|
||||
}
|
||||
44
vendor/github.com/anacrolix/chansync/set-once.go
generated
vendored
Normal file
44
vendor/github.com/anacrolix/chansync/set-once.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package chansync
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/anacrolix/chansync/events"
|
||||
)
|
||||
|
||||
// SetOnce is a boolean value that can only be flipped from false to true.
|
||||
type SetOnce struct {
|
||||
ch chan struct{}
|
||||
// Could be faster than trying to receive from ch
|
||||
closed uint32
|
||||
initOnce sync.Once
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// Returns a channel that is closed when the event is flagged.
|
||||
func (me *SetOnce) Done() events.Done {
|
||||
me.init()
|
||||
return me.ch
|
||||
}
|
||||
|
||||
func (me *SetOnce) init() {
|
||||
me.initOnce.Do(func() {
|
||||
me.ch = make(chan struct{})
|
||||
})
|
||||
}
|
||||
|
||||
// Set only returns true the first time it is called.
|
||||
func (me *SetOnce) Set() (first bool) {
|
||||
me.closeOnce.Do(func() {
|
||||
me.init()
|
||||
first = true
|
||||
atomic.StoreUint32(&me.closed, 1)
|
||||
close(me.ch)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (me *SetOnce) IsSet() bool {
|
||||
return atomic.LoadUint32(&me.closed) != 0
|
||||
}
|
||||
373
vendor/github.com/anacrolix/confluence/LICENSE
generated
vendored
Normal file
373
vendor/github.com/anacrolix/confluence/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
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/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
7
vendor/github.com/anacrolix/confluence/debug-writer/debug-writer.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/confluence/debug-writer/debug-writer.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package debug_writer
|
||||
|
||||
import "io"
|
||||
|
||||
type Interface interface {
|
||||
WriteDebug(w io.Writer)
|
||||
}
|
||||
362
vendor/github.com/anacrolix/dht/v2/LICENSE
generated
vendored
Normal file
362
vendor/github.com/anacrolix/dht/v2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
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/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
21
vendor/github.com/anacrolix/dht/v2/README.md
generated
vendored
Normal file
21
vendor/github.com/anacrolix/dht/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# dht
|
||||
|
||||
[](https://pkg.go.dev/github.com/anacrolix/dht/v2)
|
||||
|
||||
## Installation
|
||||
|
||||
Get the library package with `go get github.com/anacrolix/dht/v2`, or the provided cmds with `go install github.com/anacrolix/dht/v2/cmd/...@latest`.
|
||||
|
||||
## Commands
|
||||
|
||||
Here I'll describe what some of the provided commands in `./cmd` do.
|
||||
|
||||
### dht-ping
|
||||
|
||||
Pings DHT nodes with the given network addresses.
|
||||
|
||||
$ go run ./cmd/dht-ping router.bittorrent.com:6881 router.utorrent.com:6881
|
||||
2015/04/01 17:21:23 main.go:33: dht server on [::]:60058
|
||||
32f54e697351ff4aec29cdbaabf2fbe3467cc267 (router.bittorrent.com:6881): 648.218621ms
|
||||
ebff36697351ff4aec29cdbaabf2fbe3467cc267 (router.utorrent.com:6881): 873.864706ms
|
||||
2/2 responses (100.000000%)
|
||||
61
vendor/github.com/anacrolix/dht/v2/addr.go
generated
vendored
Normal file
61
vendor/github.com/anacrolix/dht/v2/addr.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/anacrolix/missinggo/v2"
|
||||
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
)
|
||||
|
||||
// Used internally to refer to node network addresses. String() is called a
|
||||
// lot, and so can be optimized. Network() is not exposed, so that the
|
||||
// interface does not satisfy net.Addr, as the underlying type must be passed
|
||||
// to any OS-level function that take net.Addr.
|
||||
type Addr interface {
|
||||
Raw() net.Addr
|
||||
Port() int
|
||||
IP() net.IP
|
||||
String() string
|
||||
KRPC() krpc.NodeAddr
|
||||
}
|
||||
|
||||
// Speeds up some of the commonly called Addr methods.
|
||||
type cachedAddr struct {
|
||||
raw net.Addr
|
||||
port int
|
||||
ip net.IP
|
||||
s string
|
||||
}
|
||||
|
||||
func (ca cachedAddr) String() string {
|
||||
return ca.s
|
||||
}
|
||||
|
||||
func (ca cachedAddr) KRPC() krpc.NodeAddr {
|
||||
return krpc.NodeAddr{
|
||||
IP: ca.ip,
|
||||
Port: ca.port,
|
||||
}
|
||||
}
|
||||
|
||||
func (ca cachedAddr) IP() net.IP {
|
||||
return ca.ip
|
||||
}
|
||||
|
||||
func (ca cachedAddr) Port() int {
|
||||
return ca.port
|
||||
}
|
||||
|
||||
func (ca cachedAddr) Raw() net.Addr {
|
||||
return ca.raw
|
||||
}
|
||||
|
||||
func NewAddr(raw net.Addr) Addr {
|
||||
return cachedAddr{
|
||||
raw: raw,
|
||||
s: raw.String(),
|
||||
ip: missinggo.AddrIP(raw),
|
||||
port: missinggo.AddrPort(raw),
|
||||
}
|
||||
}
|
||||
215
vendor/github.com/anacrolix/dht/v2/announce.go
generated
vendored
Normal file
215
vendor/github.com/anacrolix/dht/v2/announce.go
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
package dht
|
||||
|
||||
// get_peers and announce_peers.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/anacrolix/chansync"
|
||||
"github.com/anacrolix/chansync/events"
|
||||
"github.com/anacrolix/dht/v2/traversal"
|
||||
"github.com/anacrolix/log"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
dhtutil "github.com/anacrolix/dht/v2/k-nearest-nodes"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
)
|
||||
|
||||
// Maintains state for an ongoing Announce operation. An Announce is started by calling
|
||||
// Server.Announce.
|
||||
type Announce struct {
|
||||
Peers chan PeersValues
|
||||
|
||||
server *Server
|
||||
infoHash int160.T // Target
|
||||
|
||||
announcePeerOpts *AnnouncePeerOpts
|
||||
scrape bool
|
||||
peerAnnounced chansync.SetOnce
|
||||
|
||||
traversal *traversal.Operation
|
||||
|
||||
closed chansync.SetOnce
|
||||
}
|
||||
|
||||
func (a *Announce) String() string {
|
||||
return fmt.Sprintf("%[1]T %[1]p of %v on %v", a, a.infoHash, a.server)
|
||||
}
|
||||
|
||||
// Returns the number of distinct remote addresses the announce has queried.
|
||||
func (a *Announce) NumContacted() uint32 {
|
||||
return atomic.LoadUint32(&a.traversal.Stats().NumAddrsTried)
|
||||
}
|
||||
|
||||
// Server.Announce option
|
||||
type AnnounceOpt func(a *Announce)
|
||||
|
||||
// Scrape BEP 33 bloom filters in queries.
|
||||
func Scrape() AnnounceOpt {
|
||||
return func(a *Announce) {
|
||||
a.scrape = true
|
||||
}
|
||||
}
|
||||
|
||||
// Arguments for announce_peer from a Server.Announce.
|
||||
type AnnouncePeerOpts struct {
|
||||
// The peer port that we're announcing.
|
||||
Port int
|
||||
// The peer port should be determined by the receiver to be the source port of the query packet.
|
||||
ImpliedPort bool
|
||||
}
|
||||
|
||||
// Finish an Announce get_peers traversal with an announce of a local peer.
|
||||
func AnnouncePeer(opts AnnouncePeerOpts) AnnounceOpt {
|
||||
return func(a *Announce) {
|
||||
a.announcePeerOpts = &opts
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: Use Server.AnnounceTraversal.
|
||||
// Traverses the DHT graph toward nodes that store peers for the infohash, streaming them to the
|
||||
// caller, and announcing the local node to each responding node if port is non-zero or impliedPort
|
||||
// is true.
|
||||
func (s *Server) Announce(infoHash [20]byte, port int, impliedPort bool, opts ...AnnounceOpt) (_ *Announce, err error) {
|
||||
if port != 0 || impliedPort {
|
||||
opts = append([]AnnounceOpt{AnnouncePeer(AnnouncePeerOpts{
|
||||
Port: port,
|
||||
ImpliedPort: impliedPort,
|
||||
})}, opts...)
|
||||
}
|
||||
return s.AnnounceTraversal(infoHash, opts...)
|
||||
}
|
||||
|
||||
// Traverses the DHT graph toward nodes that store peers for the infohash, streaming them to the
|
||||
// caller.
|
||||
func (s *Server) AnnounceTraversal(infoHash [20]byte, opts ...AnnounceOpt) (_ *Announce, err error) {
|
||||
infoHashInt160 := int160.FromByteArray(infoHash)
|
||||
a := &Announce{
|
||||
Peers: make(chan PeersValues),
|
||||
server: s,
|
||||
infoHash: infoHashInt160,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(a)
|
||||
}
|
||||
a.traversal = traversal.Start(traversal.OperationInput{
|
||||
Target: infoHash,
|
||||
DoQuery: a.getPeers,
|
||||
NodeFilter: s.TraversalNodeFilter,
|
||||
})
|
||||
nodes, err := s.TraversalStartingNodes()
|
||||
if err != nil {
|
||||
a.traversal.Stop()
|
||||
return
|
||||
}
|
||||
a.traversal.AddNodes(nodes)
|
||||
go func() {
|
||||
<-a.traversal.Stalled()
|
||||
a.traversal.Stop()
|
||||
<-a.traversal.Stopped()
|
||||
if a.announcePeerOpts != nil {
|
||||
a.announceClosest()
|
||||
}
|
||||
a.peerAnnounced.Set()
|
||||
close(a.Peers)
|
||||
}()
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (a *Announce) announceClosest() {
|
||||
var wg sync.WaitGroup
|
||||
a.traversal.Closest().Range(func(elem dhtutil.Elem) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
a.logger().Levelf(log.Debug,
|
||||
"announce_peer to %v: %v",
|
||||
elem, a.announcePeer(elem),
|
||||
)
|
||||
wg.Done()
|
||||
}()
|
||||
})
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (a *Announce) announcePeer(peer dhtutil.Elem) error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
go func() {
|
||||
select {
|
||||
case <-a.closed.Done():
|
||||
cancel()
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
return a.server.announcePeer(
|
||||
ctx,
|
||||
NewAddr(peer.Addr.UDP()),
|
||||
a.infoHash,
|
||||
a.announcePeerOpts.Port,
|
||||
peer.Data.(string),
|
||||
a.announcePeerOpts.ImpliedPort,
|
||||
QueryRateLimiting{},
|
||||
).Err
|
||||
}
|
||||
|
||||
func (a *Announce) getPeers(ctx context.Context, addr krpc.NodeAddr) (tqr traversal.QueryResult) {
|
||||
res := a.server.GetPeers(ctx, NewAddr(addr.UDP()), a.infoHash, a.scrape, QueryRateLimiting{})
|
||||
if r := res.Reply.R; r != nil {
|
||||
peersValues := PeersValues{
|
||||
Peers: r.Values,
|
||||
NodeInfo: krpc.NodeInfo{
|
||||
Addr: addr,
|
||||
ID: r.ID,
|
||||
},
|
||||
Return: *r,
|
||||
}
|
||||
select {
|
||||
case a.Peers <- peersValues:
|
||||
case <-a.traversal.Stopped():
|
||||
}
|
||||
if r.Token != nil {
|
||||
tqr.ClosestData = *r.Token
|
||||
tqr.ResponseFrom = &krpc.NodeInfo{
|
||||
ID: r.ID,
|
||||
Addr: addr,
|
||||
}
|
||||
}
|
||||
tqr.Nodes = r.Nodes
|
||||
tqr.Nodes6 = r.Nodes6
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Corresponds to the "values" key in a get_peers KRPC response. A list of
|
||||
// peers that a node has reported as being in the swarm for a queried info
|
||||
// hash.
|
||||
type PeersValues struct {
|
||||
Peers []Peer // Peers given in get_peers response.
|
||||
krpc.NodeInfo // The node that gave the response.
|
||||
krpc.Return
|
||||
}
|
||||
|
||||
// Stop the announce.
|
||||
func (a *Announce) Close() {
|
||||
a.StopTraversing()
|
||||
// This will prevent peer announces from proceeding.
|
||||
a.closed.Set()
|
||||
}
|
||||
|
||||
func (a *Announce) logger() log.Logger {
|
||||
return a.server.logger()
|
||||
}
|
||||
|
||||
// Halts traversal, but won't block peer announcing.
|
||||
func (a *Announce) StopTraversing() {
|
||||
a.traversal.Stop()
|
||||
}
|
||||
|
||||
// Traversal and peer announcing steps are done.
|
||||
func (a *Announce) Finished() events.Done {
|
||||
// This is the last step in an announce.
|
||||
return a.peerAnnounced.Done()
|
||||
}
|
||||
27
vendor/github.com/anacrolix/dht/v2/bep44/error.go
generated
vendored
Normal file
27
vendor/github.com/anacrolix/dht/v2/bep44/error.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package bep44
|
||||
|
||||
import "github.com/anacrolix/dht/v2/krpc"
|
||||
|
||||
var (
|
||||
ErrValueFieldTooBig = krpc.Error{
|
||||
Code: krpc.ErrorCodeMessageValueFieldTooBig,
|
||||
Msg: "message (v field) too big",
|
||||
}
|
||||
ErrInvalidSignature = krpc.Error{
|
||||
Code: krpc.ErrorCodeInvalidSignature,
|
||||
Msg: "invalid signature",
|
||||
}
|
||||
|
||||
ErrSaltFieldTooBig = krpc.Error{
|
||||
Code: krpc.ErrorCodeSaltFieldTooBig,
|
||||
Msg: "salt (salt field) too big",
|
||||
}
|
||||
ErrCasHashMismatched = krpc.Error{
|
||||
Code: krpc.ErrorCodeCasHashMismatched,
|
||||
Msg: "the CAS hash mismatched, re-read value and try again",
|
||||
}
|
||||
ErrSequenceNumberLessThanCurrent = krpc.Error{
|
||||
Code: krpc.ErrorCodeSequenceNumberLessThanCurrent,
|
||||
Msg: "sequence number less than current",
|
||||
}
|
||||
)
|
||||
177
vendor/github.com/anacrolix/dht/v2/bep44/item.go
generated
vendored
Normal file
177
vendor/github.com/anacrolix/dht/v2/bep44/item.go
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
package bep44
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
var Empty32ByteArray [32]byte
|
||||
|
||||
type Item struct {
|
||||
// time when this object was added to storage
|
||||
created time.Time
|
||||
|
||||
// Value to be stored
|
||||
V interface{}
|
||||
|
||||
// 32 byte ed25519 public key
|
||||
K [32]byte
|
||||
Salt []byte
|
||||
Sig [64]byte
|
||||
Cas int64
|
||||
Seq int64
|
||||
}
|
||||
|
||||
func (i *Item) ToPut() Put {
|
||||
p := Put{
|
||||
V: i.V,
|
||||
Salt: i.Salt,
|
||||
Sig: i.Sig,
|
||||
Cas: i.Cas,
|
||||
Seq: i.Seq,
|
||||
}
|
||||
if i.K != Empty32ByteArray {
|
||||
p.K = &i.K
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// NewItem creates a new arbitrary DHT element. The distinction between storing mutable
|
||||
// and immutable items is the inclusion of a public key, a sequence number, signature
|
||||
// and an optional salt.
|
||||
//
|
||||
// cas parameter is short for compare and swap, it has similar semantics as CAS CPU
|
||||
// instructions. It is used to avoid race conditions when multiple nodes are writing
|
||||
// to the same slot in the DHT. It is optional. If present it specifies the sequence
|
||||
// number of the data blob being overwritten by the put.
|
||||
//
|
||||
// salt parameter is used to make possible several targets using the same private key.
|
||||
//
|
||||
// The optional seq field specifies that an item's value should only be sent if its
|
||||
// sequence number is greater than the given value.
|
||||
func NewItem(value interface{}, salt []byte, seq, cas int64, k ed25519.PrivateKey) (*Item, error) {
|
||||
v, err := bencode.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var kk [32]byte
|
||||
var sig [64]byte
|
||||
|
||||
if k != nil {
|
||||
pk := []byte(k.Public().(ed25519.PublicKey))
|
||||
copy(kk[:], pk)
|
||||
copy(sig[:], Sign(k, salt, seq, v))
|
||||
}
|
||||
|
||||
return &Item{
|
||||
V: value,
|
||||
Salt: salt,
|
||||
Cas: cas,
|
||||
Seq: seq,
|
||||
|
||||
K: kk,
|
||||
Sig: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (i *Item) Target() Target {
|
||||
if i.IsMutable() {
|
||||
return sha1.Sum(append(i.K[:], i.Salt...))
|
||||
}
|
||||
|
||||
return sha1.Sum(bencode.MustMarshal(i.V))
|
||||
}
|
||||
|
||||
func (i *Item) Modify(value interface{}, k ed25519.PrivateKey) bool {
|
||||
if !i.IsMutable() {
|
||||
return false
|
||||
}
|
||||
|
||||
v, err := bencode.Marshal(value)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
i.V = value
|
||||
i.Seq++
|
||||
var sig [64]byte
|
||||
copy(sig[:], Sign(k, i.Salt, i.Seq, v))
|
||||
i.Sig = sig
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *Item) IsMutable() bool {
|
||||
return s.K != Empty32ByteArray
|
||||
}
|
||||
|
||||
func bufferToSign(salt, bv []byte, seq int64) []byte {
|
||||
var bts []byte
|
||||
if len(salt) != 0 {
|
||||
bts = append(bts, []byte("4:salt")...)
|
||||
x := bencode.MustMarshal(salt)
|
||||
bts = append(bts, x...)
|
||||
}
|
||||
bts = append(bts, []byte(fmt.Sprintf("3:seqi%de1:v", seq))...)
|
||||
bts = append(bts, bv...)
|
||||
return bts
|
||||
}
|
||||
|
||||
func Check(i *Item) error {
|
||||
bv, err := bencode.Marshal(i.V)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(bv) > 1000 {
|
||||
return ErrValueFieldTooBig
|
||||
}
|
||||
|
||||
if !i.IsMutable() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(i.Salt) > 64 {
|
||||
return ErrSaltFieldTooBig
|
||||
}
|
||||
|
||||
if !Verify(i.K[:], i.Salt, i.Seq, bv, i.Sig[:]) {
|
||||
return ErrInvalidSignature
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckIncoming(stored, incoming *Item) error {
|
||||
// If the sequence number is equal, and the value is also the same,
|
||||
// the node SHOULD reset its timeout counter.
|
||||
if stored.Seq == incoming.Seq {
|
||||
if bytes.Equal(
|
||||
bencode.MustMarshal(stored.V),
|
||||
bencode.MustMarshal(incoming.V),
|
||||
) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if stored.Seq >= incoming.Seq {
|
||||
return ErrSequenceNumberLessThanCurrent
|
||||
}
|
||||
|
||||
// Cas should be ignored if not present
|
||||
if stored.Cas == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if stored.Cas != incoming.Cas {
|
||||
return ErrCasHashMismatched
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
13
vendor/github.com/anacrolix/dht/v2/bep44/key.go
generated
vendored
Normal file
13
vendor/github.com/anacrolix/dht/v2/bep44/key.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package bep44
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
)
|
||||
|
||||
func Sign(k ed25519.PrivateKey, salt []byte, seq int64, bv []byte) []byte {
|
||||
return ed25519.Sign(k, bufferToSign(salt, bv, seq))
|
||||
}
|
||||
|
||||
func Verify(k ed25519.PublicKey, salt []byte, seq int64, bv []byte, sig []byte) bool {
|
||||
return ed25519.Verify(k, bufferToSign(salt, bv, seq), sig)
|
||||
}
|
||||
49
vendor/github.com/anacrolix/dht/v2/bep44/memory.go
generated
vendored
Normal file
49
vendor/github.com/anacrolix/dht/v2/bep44/memory.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package bep44
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var _ Store = &Memory{}
|
||||
|
||||
type Memory struct {
|
||||
// protects m
|
||||
mu sync.RWMutex
|
||||
m map[Target]*Item
|
||||
}
|
||||
|
||||
func NewMemory() *Memory {
|
||||
return &Memory{
|
||||
m: make(map[Target]*Item),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Memory) Put(i *Item) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
m.m[i.Target()] = i
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Memory) Get(t Target) (*Item, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
i, ok := m.m[t]
|
||||
if !ok {
|
||||
return nil, ErrItemNotFound
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *Memory) Del(t Target) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
delete(m.m, t)
|
||||
|
||||
return nil
|
||||
}
|
||||
47
vendor/github.com/anacrolix/dht/v2/bep44/put.go
generated
vendored
Normal file
47
vendor/github.com/anacrolix/dht/v2/bep44/put.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package bep44
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha1"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
type Put struct {
|
||||
V interface{}
|
||||
K *[32]byte
|
||||
Salt []byte
|
||||
Sig [64]byte
|
||||
Cas int64
|
||||
Seq int64
|
||||
}
|
||||
|
||||
func (p *Put) ToItem() *Item {
|
||||
i := &Item{
|
||||
V: p.V,
|
||||
Salt: p.Salt,
|
||||
Sig: p.Sig,
|
||||
Cas: p.Cas,
|
||||
Seq: p.Seq,
|
||||
}
|
||||
if p.K != nil {
|
||||
i.K = *p.K
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (p *Put) Sign(k ed25519.PrivateKey) {
|
||||
copy(p.Sig[:], Sign(k, p.Salt, p.Seq, bencode.MustMarshal(p.V)))
|
||||
}
|
||||
|
||||
func (i *Put) Target() Target {
|
||||
if i.IsMutable() {
|
||||
return MakeMutableTarget(*i.K, i.Salt)
|
||||
} else {
|
||||
return sha1.Sum(bencode.MustMarshal(i.V))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Put) IsMutable() bool {
|
||||
return s.K != nil
|
||||
}
|
||||
65
vendor/github.com/anacrolix/dht/v2/bep44/store.go
generated
vendored
Normal file
65
vendor/github.com/anacrolix/dht/v2/bep44/store.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package bep44
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrItemNotFound = errors.New("item not found")
|
||||
|
||||
type Store interface {
|
||||
Put(*Item) error
|
||||
Get(Target) (*Item, error)
|
||||
Del(Target) error
|
||||
}
|
||||
|
||||
// Wrapper is in charge of validate all new items and
|
||||
// decide when to store, or ignore them depending of the BEP 44 definition.
|
||||
// It is also in charge of removing expired items.
|
||||
type Wrapper struct {
|
||||
s Store
|
||||
exp time.Duration
|
||||
}
|
||||
|
||||
func NewWrapper(s Store, exp time.Duration) *Wrapper {
|
||||
return &Wrapper{s: s, exp: exp}
|
||||
}
|
||||
|
||||
func (w *Wrapper) Put(i *Item) error {
|
||||
if err := Check(i); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
is, err := w.s.Get(i.Target())
|
||||
if errors.Is(err, ErrItemNotFound) {
|
||||
i.created = time.Now().Local()
|
||||
return w.s.Put(i)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := CheckIncoming(is, i); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.created = time.Now().Local()
|
||||
return w.s.Put(i)
|
||||
}
|
||||
|
||||
func (w *Wrapper) Get(t Target) (*Item, error) {
|
||||
i, err := w.s.Get(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if i.created.Add(w.exp).After(time.Now().Local()) {
|
||||
return i, nil
|
||||
}
|
||||
|
||||
if err := w.s.Del(t); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, ErrItemNotFound
|
||||
}
|
||||
11
vendor/github.com/anacrolix/dht/v2/bep44/target.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/dht/v2/bep44/target.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package bep44
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
)
|
||||
|
||||
type Target = [sha1.Size]byte
|
||||
|
||||
func MakeMutableTarget(pubKey [32]byte, salt []byte) Target {
|
||||
return sha1.Sum(append(pubKey[:], salt...))
|
||||
}
|
||||
51
vendor/github.com/anacrolix/dht/v2/bootstrap.go
generated
vendored
Normal file
51
vendor/github.com/anacrolix/dht/v2/bootstrap.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
"github.com/anacrolix/dht/v2/traversal"
|
||||
)
|
||||
|
||||
type TraversalStats = traversal.Stats
|
||||
|
||||
// Populates the node table.
|
||||
func (s *Server) Bootstrap() (_ TraversalStats, err error) {
|
||||
s.mu.Lock()
|
||||
if s.bootstrappingNow {
|
||||
s.mu.Unlock()
|
||||
err = errors.New("already bootstrapping")
|
||||
return
|
||||
}
|
||||
s.bootstrappingNow = true
|
||||
s.mu.Unlock()
|
||||
defer func() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.bootstrappingNow = false
|
||||
}()
|
||||
// Track number of responses, for STM use. (It's available via atomic in TraversalStats but that
|
||||
// won't let wake up STM transactions that are observing the value.)
|
||||
t := traversal.Start(traversal.OperationInput{
|
||||
Target: krpc.ID(s.id.AsByteArray()),
|
||||
K: 16,
|
||||
DoQuery: func(ctx context.Context, addr krpc.NodeAddr) traversal.QueryResult {
|
||||
return s.FindNode(NewAddr(addr.UDP()), s.id, QueryRateLimiting{}).TraversalQueryResult(addr)
|
||||
},
|
||||
NodeFilter: s.TraversalNodeFilter,
|
||||
})
|
||||
nodes, err := s.TraversalStartingNodes()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t.AddNodes(nodes)
|
||||
s.mu.Lock()
|
||||
s.lastBootstrap = time.Now()
|
||||
s.mu.Unlock()
|
||||
<-t.Stalled()
|
||||
t.Stop()
|
||||
<-t.Stopped()
|
||||
return *t.Stats(), nil
|
||||
}
|
||||
50
vendor/github.com/anacrolix/dht/v2/bucket.go
generated
vendored
Normal file
50
vendor/github.com/anacrolix/dht/v2/bucket.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/chansync"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
)
|
||||
|
||||
type bucket struct {
|
||||
// Per the "Routing Table" section of BEP 5.
|
||||
changed chansync.BroadcastCond
|
||||
lastChanged time.Time
|
||||
nodes map[*node]struct{}
|
||||
}
|
||||
|
||||
func (b *bucket) Len() int {
|
||||
return len(b.nodes)
|
||||
}
|
||||
|
||||
func (b *bucket) EachNode(f func(*node) bool) bool {
|
||||
for n := range b.nodes {
|
||||
if !f(n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *bucket) AddNode(n *node, k int) {
|
||||
if _, ok := b.nodes[n]; ok {
|
||||
return
|
||||
}
|
||||
if b.nodes == nil {
|
||||
b.nodes = make(map[*node]struct{}, k)
|
||||
}
|
||||
b.nodes[n] = struct{}{}
|
||||
b.lastChanged = time.Now()
|
||||
b.changed.Broadcast()
|
||||
}
|
||||
|
||||
func (b *bucket) GetNode(addr Addr, id int160.T) *node {
|
||||
for n := range b.nodes {
|
||||
if n.hasAddrAndID(addr, id) {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
44
vendor/github.com/anacrolix/dht/v2/containers/addr-maybe-ids-by-distance.go
generated
vendored
Normal file
44
vendor/github.com/anacrolix/dht/v2/containers/addr-maybe-ids-by-distance.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package containers
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
"github.com/anacrolix/dht/v2/types"
|
||||
"github.com/anacrolix/missinggo/v2/iter"
|
||||
"github.com/anacrolix/stm/stmutil"
|
||||
)
|
||||
|
||||
type addrMaybeId = types.AddrMaybeId
|
||||
|
||||
type AddrMaybeIdsByDistance interface {
|
||||
Add(addrMaybeId) AddrMaybeIdsByDistance
|
||||
Next() addrMaybeId
|
||||
Delete(addrMaybeId) AddrMaybeIdsByDistance
|
||||
Len() int
|
||||
}
|
||||
|
||||
type stmSettishWrapper struct {
|
||||
set stmutil.Settish
|
||||
}
|
||||
|
||||
func (me stmSettishWrapper) Next() addrMaybeId {
|
||||
first, _ := iter.First(me.set.Iter)
|
||||
return first.(addrMaybeId)
|
||||
}
|
||||
|
||||
func (me stmSettishWrapper) Delete(x addrMaybeId) AddrMaybeIdsByDistance {
|
||||
return stmSettishWrapper{me.set.Delete(x)}
|
||||
}
|
||||
|
||||
func (me stmSettishWrapper) Len() int {
|
||||
return me.set.Len()
|
||||
}
|
||||
|
||||
func (me stmSettishWrapper) Add(x addrMaybeId) AddrMaybeIdsByDistance {
|
||||
return stmSettishWrapper{me.set.Add(x)}
|
||||
}
|
||||
|
||||
func NewImmutableAddrMaybeIdsByDistance(target int160.T) AddrMaybeIdsByDistance {
|
||||
return stmSettishWrapper{stmutil.NewSortedSet(func(l, r interface{}) bool {
|
||||
return l.(addrMaybeId).CloserThan(r.(addrMaybeId), target)
|
||||
})}
|
||||
}
|
||||
153
vendor/github.com/anacrolix/dht/v2/dht.go
generated
vendored
Normal file
153
vendor/github.com/anacrolix/dht/v2/dht.go
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
_ "crypto/sha1"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/dht/v2/bep44"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
peer_store "github.com/anacrolix/dht/v2/peer-store"
|
||||
"github.com/anacrolix/log"
|
||||
"github.com/anacrolix/missinggo/v2"
|
||||
"github.com/anacrolix/torrent/iplist"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
func defaultQueryResendDelay() time.Duration {
|
||||
// This should be the highest reasonable UDP latency an end-user might have.
|
||||
return 2 * time.Second
|
||||
}
|
||||
|
||||
// Uniquely identifies a transaction to us.
|
||||
type transactionKey struct {
|
||||
RemoteAddr string // host:port
|
||||
T string // The KRPC transaction ID.
|
||||
}
|
||||
|
||||
type StartingNodesGetter func() ([]Addr, error)
|
||||
|
||||
// ServerConfig allows setting up a configuration of the `Server` instance to be created with
|
||||
// NewServer.
|
||||
type ServerConfig struct {
|
||||
// Set NodeId Manually. Caller must ensure that if NodeId does not conform
|
||||
// to DHT Security Extensions, that NoSecurity is also set.
|
||||
NodeId krpc.ID
|
||||
Conn net.PacketConn
|
||||
// Don't respond to queries from other nodes.
|
||||
Passive bool
|
||||
// Whether to wait for rate limiting to allow us to reply.
|
||||
WaitToReply bool
|
||||
|
||||
StartingNodes StartingNodesGetter
|
||||
// Disable the DHT security extension: http://www.libtorrent.org/dht_sec.html.
|
||||
NoSecurity bool
|
||||
// Initial IP blocklist to use. Applied before serving and bootstrapping
|
||||
// begins.
|
||||
IPBlocklist iplist.Ranger
|
||||
// Used to secure the server's ID. Defaults to the Conn's LocalAddr(). Set to the IP that remote
|
||||
// nodes will see, as that IP is what they'll use to validate our ID.
|
||||
PublicIP net.IP
|
||||
|
||||
// Hook received queries. Return false if you don't want to propagate to the default handlers.
|
||||
OnQuery func(query *krpc.Msg, source net.Addr) (propagate bool)
|
||||
// Called when a peer successfully announces to us.
|
||||
OnAnnouncePeer func(infoHash metainfo.Hash, ip net.IP, port int, portOk bool)
|
||||
// How long to wait before resending queries that haven't received a response. Defaults to a
|
||||
// random value between 4.5 and 5.5s.
|
||||
QueryResendDelay func() time.Duration
|
||||
// TODO: Expose Peers, to return NodeInfo for received get_peers queries.
|
||||
PeerStore peer_store.Interface
|
||||
// BEP-44: Storing arbitrary data in the DHT. If not store provided, a default in-memory
|
||||
// implementation will be used.
|
||||
Store bep44.Store
|
||||
// BEP-44: expiration time with non-announced items. Two hours by default
|
||||
Exp time.Duration
|
||||
|
||||
// If no Logger is provided, log.Default is used and log.Debug messages are filtered out. Note
|
||||
// that all messages without a log.Level, have log.Debug added to them before being passed to
|
||||
// this Logger.
|
||||
Logger log.Logger
|
||||
|
||||
DefaultWant []krpc.Want
|
||||
|
||||
SendLimiter *rate.Limiter
|
||||
}
|
||||
|
||||
// ServerStats instance is returned by Server.Stats() and stores Server metrics
|
||||
type ServerStats struct {
|
||||
// Count of nodes in the node table that responded to our last query or
|
||||
// haven't yet been queried.
|
||||
GoodNodes int
|
||||
// Count of nodes in the node table.
|
||||
Nodes int
|
||||
// Transactions awaiting a response.
|
||||
OutstandingTransactions int
|
||||
// Individual announce_peer requests that got a success response.
|
||||
SuccessfulOutboundAnnouncePeerQueries int64
|
||||
// Nodes that have been blocked.
|
||||
BadNodes uint
|
||||
OutboundQueriesAttempted int64
|
||||
}
|
||||
|
||||
func jitterDuration(average time.Duration, plusMinus time.Duration) time.Duration {
|
||||
return average - plusMinus/2 + time.Duration(rand.Int63n(int64(plusMinus)))
|
||||
}
|
||||
|
||||
type Peer = krpc.NodeAddr
|
||||
|
||||
var DefaultGlobalBootstrapHostPorts = []string{
|
||||
"router.utorrent.com:6881",
|
||||
"router.bittorrent.com:6881",
|
||||
"dht.transmissionbt.com:6881",
|
||||
"dht.aelitis.com:6881", // Vuze
|
||||
"router.silotis.us:6881", // IPv6
|
||||
"dht.libtorrent.org:25401", // @arvidn's
|
||||
"dht.anacrolix.link:42069",
|
||||
"router.bittorrent.cloud:42069",
|
||||
}
|
||||
|
||||
func GlobalBootstrapAddrs(network string) (addrs []Addr, err error) {
|
||||
initDnsResolver()
|
||||
for _, s := range DefaultGlobalBootstrapHostPorts {
|
||||
host, port, err := net.SplitHostPort(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
hostAddrs, err := dnsResolver.LookupHost(context.Background(), host)
|
||||
if err != nil {
|
||||
// log.Default.WithDefaultLevel(log.Debug).Printf("error looking up %q: %v", s, err)
|
||||
continue
|
||||
}
|
||||
for _, a := range hostAddrs {
|
||||
ua, err := net.ResolveUDPAddr("udp", net.JoinHostPort(a, port))
|
||||
if err != nil {
|
||||
log.Printf("error resolving %q: %v", a, err)
|
||||
continue
|
||||
}
|
||||
addrs = append(addrs, NewAddr(ua))
|
||||
}
|
||||
}
|
||||
if len(addrs) == 0 {
|
||||
err = errors.New("nothing resolved")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Deprecated: Use function from krpc.
|
||||
func RandomNodeID() (id krpc.ID) {
|
||||
return krpc.RandomNodeID()
|
||||
}
|
||||
|
||||
func MakeDeterministicNodeID(public net.Addr) (id krpc.ID) {
|
||||
h := crypto.SHA1.New()
|
||||
h.Write([]byte(public.String()))
|
||||
h.Sum(id[:0:20])
|
||||
SecureNodeId(&id, missinggo.AddrIP(public))
|
||||
return
|
||||
}
|
||||
31
vendor/github.com/anacrolix/dht/v2/dns.go
generated
vendored
Normal file
31
vendor/github.com/anacrolix/dht/v2/dns.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/dnscache"
|
||||
)
|
||||
|
||||
var (
|
||||
// A cache to prevent wasteful/excessive use of DNS when trying to bootstrap.
|
||||
dnsResolver *dnscache.Resolver
|
||||
dnsResolverInit sync.Once
|
||||
)
|
||||
|
||||
func dnsResolverRefresher() {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
<-ticker.C
|
||||
dnsResolver.Refresh(false)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/anacrolix/dht/issues/43
|
||||
func initDnsResolver() {
|
||||
dnsResolverInit.Do(func() {
|
||||
dnsResolver = &dnscache.Resolver{}
|
||||
go dnsResolverRefresher()
|
||||
})
|
||||
}
|
||||
22
vendor/github.com/anacrolix/dht/v2/doc.go
generated
vendored
Normal file
22
vendor/github.com/anacrolix/dht/v2/doc.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// Package dht implements a Distributed Hash Table (DHT) part of
|
||||
// the BitTorrent protocol,
|
||||
// as specified by BEP 5: http://www.bittorrent.org/beps/bep_0005.html
|
||||
//
|
||||
// BitTorrent uses a "distributed hash table" (DHT)
|
||||
// for storing peer contact information for "trackerless" torrents.
|
||||
// In effect, each peer becomes a tracker.
|
||||
// The protocol is based on Kademila DHT protocol and is implemented over UDP.
|
||||
//
|
||||
// Please note the terminology used to avoid confusion.
|
||||
// A "peer" is a client/server listening on a TCP port that
|
||||
// implements the BitTorrent protocol.
|
||||
// A "node" is a client/server listening on a UDP port implementing
|
||||
// the distributed hash table protocol.
|
||||
// The DHT is composed of nodes and stores the location of peers.
|
||||
// BitTorrent clients include a DHT node, which is used to contact other nodes
|
||||
// in the DHT to get the location of peers to
|
||||
// download from using the BitTorrent protocol.
|
||||
//
|
||||
// Standard use involves creating a Server, and calling Announce on it with
|
||||
// the details of your local torrent client and infohash of interest.
|
||||
package dht
|
||||
16
vendor/github.com/anacrolix/dht/v2/expvar.go
generated
vendored
Normal file
16
vendor/github.com/anacrolix/dht/v2/expvar.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
)
|
||||
|
||||
var (
|
||||
readZeroPort = expvar.NewInt("dhtReadZeroPort")
|
||||
readBlocked = expvar.NewInt("dhtReadBlocked")
|
||||
readNotKRPCDict = expvar.NewInt("dhtReadNotKRPCDict")
|
||||
readUnmarshalError = expvar.NewInt("dhtReadUnmarshalError")
|
||||
announceErrors = expvar.NewInt("dhtAnnounceErrors")
|
||||
writeErrors = expvar.NewInt("dhtWriteErrors")
|
||||
writes = expvar.NewInt("dhtWrites")
|
||||
expvars = expvar.NewMap("dht")
|
||||
)
|
||||
7
vendor/github.com/anacrolix/dht/v2/globals.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/dht/v2/globals.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
var DefaultSendLimiter = rate.NewLimiter(25, 25)
|
||||
110
vendor/github.com/anacrolix/dht/v2/int160/int160.go
generated
vendored
Normal file
110
vendor/github.com/anacrolix/dht/v2/int160/int160.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
package int160
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type T struct {
|
||||
bits [20]uint8
|
||||
}
|
||||
|
||||
func (me T) String() string {
|
||||
return hex.EncodeToString(me.bits[:])
|
||||
}
|
||||
|
||||
func (me *T) AsByteArray() [20]byte {
|
||||
return me.bits
|
||||
}
|
||||
|
||||
func (me *T) ByteString() string {
|
||||
return string(me.bits[:])
|
||||
}
|
||||
|
||||
func (me *T) BitLen() int {
|
||||
var a big.Int
|
||||
a.SetBytes(me.bits[:])
|
||||
return a.BitLen()
|
||||
}
|
||||
|
||||
func (me *T) SetBytes(b []byte) {
|
||||
n := copy(me.bits[:], b)
|
||||
if n != 20 {
|
||||
panic(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *T) SetBit(index int, val bool) {
|
||||
var orVal uint8
|
||||
if val {
|
||||
orVal = 1 << (7 - index%8)
|
||||
}
|
||||
var mask uint8 = ^(1 << (7 - index%8))
|
||||
me.bits[index/8] = me.bits[index/8]&mask | orVal
|
||||
}
|
||||
|
||||
func (me *T) GetBit(index int) bool {
|
||||
return me.bits[index/8]>>(7-index%8)&1 == 1
|
||||
}
|
||||
|
||||
func (me T) Bytes() []byte {
|
||||
return me.bits[:]
|
||||
}
|
||||
|
||||
func (l T) Cmp(r T) int {
|
||||
for i := range l.bits {
|
||||
if l.bits[i] < r.bits[i] {
|
||||
return -1
|
||||
} else if l.bits[i] > r.bits[i] {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (me *T) SetMax() {
|
||||
for i := range me.bits {
|
||||
me.bits[i] = math.MaxUint8
|
||||
}
|
||||
}
|
||||
|
||||
func (me *T) Xor(a, b *T) {
|
||||
for i := range me.bits {
|
||||
me.bits[i] = a.bits[i] ^ b.bits[i]
|
||||
}
|
||||
}
|
||||
|
||||
func (me *T) IsZero() bool {
|
||||
for _, b := range me.bits {
|
||||
if b != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func FromBytes(b []byte) (ret T) {
|
||||
ret.SetBytes(b)
|
||||
return
|
||||
}
|
||||
|
||||
func FromByteArray(b [20]byte) (ret T) {
|
||||
ret.SetBytes(b[:])
|
||||
return
|
||||
}
|
||||
|
||||
func FromByteString(s string) (ret T) {
|
||||
ret.SetBytes([]byte(s))
|
||||
return
|
||||
}
|
||||
|
||||
func Distance(a, b T) (ret T) {
|
||||
ret.Xor(&a, &b)
|
||||
return
|
||||
}
|
||||
|
||||
func (a T) Distance(b T) (ret T) {
|
||||
ret.Xor(&a, &b)
|
||||
return
|
||||
}
|
||||
103
vendor/github.com/anacrolix/dht/v2/k-nearest-nodes/k-nearest-nodes.go.go
generated
vendored
Normal file
103
vendor/github.com/anacrolix/dht/v2/k-nearest-nodes/k-nearest-nodes.go.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
package k_nearest_nodes
|
||||
|
||||
import (
|
||||
"hash/maphash"
|
||||
|
||||
"github.com/anacrolix/multiless"
|
||||
"github.com/benbjohnson/immutable"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
)
|
||||
|
||||
type Key = krpc.NodeInfo
|
||||
|
||||
type Elem struct {
|
||||
Key
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
type Type struct {
|
||||
inner *immutable.SortedMap
|
||||
k int
|
||||
}
|
||||
|
||||
func New(target int160.T, k int) Type {
|
||||
seed := maphash.MakeSeed()
|
||||
return Type{
|
||||
k: k,
|
||||
inner: immutable.NewSortedMap(lessComparer{less: func(_l, _r interface{}) bool {
|
||||
l := _l.(Key)
|
||||
r := _r.(Key)
|
||||
return multiless.New().Cmp(
|
||||
l.ID.Int160().Distance(target).Cmp(r.ID.Int160().Distance(target)),
|
||||
).Lazy(func() multiless.Computation {
|
||||
var lh, rh maphash.Hash
|
||||
lh.SetSeed(seed)
|
||||
rh.SetSeed(seed)
|
||||
lh.WriteString(l.Addr.String())
|
||||
rh.WriteString(r.Addr.String())
|
||||
return multiless.New().Int64(int64(lh.Sum64()), int64(rh.Sum64()))
|
||||
}).Less()
|
||||
}}),
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Type) Range(f func(Elem)) {
|
||||
iter := me.inner.Iterator()
|
||||
for !iter.Done() {
|
||||
key, value := iter.Next()
|
||||
f(Elem{
|
||||
Key: key.(Key),
|
||||
Data: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (me Type) Len() int {
|
||||
return me.inner.Len()
|
||||
}
|
||||
|
||||
func (me Type) Push(elem Elem) Type {
|
||||
me.inner = me.inner.Set(elem.Key, elem.Data)
|
||||
for me.inner.Len() > me.k {
|
||||
iter := me.inner.Iterator()
|
||||
iter.Last()
|
||||
key, _ := iter.Next()
|
||||
me.inner = me.inner.Delete(key)
|
||||
}
|
||||
return me
|
||||
}
|
||||
|
||||
func (me Type) Farthest() (elem Elem) {
|
||||
iter := me.inner.Iterator()
|
||||
iter.Last()
|
||||
if iter.Done() {
|
||||
panic(me.k)
|
||||
}
|
||||
key, value := iter.Next()
|
||||
return Elem{
|
||||
Key: key.(Key),
|
||||
Data: value,
|
||||
}
|
||||
}
|
||||
|
||||
func (me Type) Full() bool {
|
||||
return me.Len() >= me.k
|
||||
}
|
||||
|
||||
type lessFunc func(l, r interface{}) bool
|
||||
|
||||
type lessComparer struct {
|
||||
less lessFunc
|
||||
}
|
||||
|
||||
func (me lessComparer) Compare(i, j interface{}) int {
|
||||
if me.less(i, j) {
|
||||
return -1
|
||||
} else if me.less(j, i) {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
36
vendor/github.com/anacrolix/dht/v2/krpc/CompactIPv4NodeAddrs.go
generated
vendored
Normal file
36
vendor/github.com/anacrolix/dht/v2/krpc/CompactIPv4NodeAddrs.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package krpc
|
||||
|
||||
import "github.com/anacrolix/missinggo/slices"
|
||||
|
||||
type CompactIPv4NodeAddrs []NodeAddr
|
||||
|
||||
func (CompactIPv4NodeAddrs) ElemSize() int { return 6 }
|
||||
|
||||
func (me CompactIPv4NodeAddrs) MarshalBinary() ([]byte, error) {
|
||||
return marshalBinarySlice(slices.Map(func(addr NodeAddr) NodeAddr {
|
||||
if a := addr.IP.To4(); a != nil {
|
||||
addr.IP = a
|
||||
}
|
||||
return addr
|
||||
}, me).(CompactIPv4NodeAddrs))
|
||||
}
|
||||
|
||||
func (me CompactIPv4NodeAddrs) MarshalBencode() ([]byte, error) {
|
||||
return bencodeBytesResult(me.MarshalBinary())
|
||||
}
|
||||
|
||||
func (me *CompactIPv4NodeAddrs) UnmarshalBinary(b []byte) error {
|
||||
return unmarshalBinarySlice(me, b)
|
||||
}
|
||||
|
||||
func (me *CompactIPv4NodeAddrs) UnmarshalBencode(b []byte) error {
|
||||
return unmarshalBencodedBinary(me, b)
|
||||
}
|
||||
|
||||
func (me CompactIPv4NodeAddrs) NodeAddrs() []NodeAddr {
|
||||
return me
|
||||
}
|
||||
|
||||
func (me CompactIPv4NodeAddrs) Index(x NodeAddr) int {
|
||||
return addrIndex(me, x)
|
||||
}
|
||||
37
vendor/github.com/anacrolix/dht/v2/krpc/CompactIPv4NodeInfo.go
generated
vendored
Normal file
37
vendor/github.com/anacrolix/dht/v2/krpc/CompactIPv4NodeInfo.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package krpc
|
||||
|
||||
import "github.com/anacrolix/missinggo/slices"
|
||||
|
||||
type (
|
||||
CompactIPv4NodeInfo []NodeInfo
|
||||
)
|
||||
|
||||
func (CompactIPv4NodeInfo) ElemSize() int {
|
||||
return 26
|
||||
}
|
||||
|
||||
// func (me *CompactIPv4NodeInfo) Scrub() {
|
||||
// slices.FilterInPlace(me, func(ni *NodeInfo) bool {
|
||||
// ni.Addr.IP = ni.Addr.IP.To4()
|
||||
// return ni.Addr.IP != nil
|
||||
// })
|
||||
// }
|
||||
|
||||
func (me CompactIPv4NodeInfo) MarshalBinary() ([]byte, error) {
|
||||
return marshalBinarySlice(slices.Map(func(ni NodeInfo) NodeInfo {
|
||||
ni.Addr.IP = ni.Addr.IP.To4()
|
||||
return ni
|
||||
}, me).(CompactIPv4NodeInfo))
|
||||
}
|
||||
|
||||
func (me CompactIPv4NodeInfo) MarshalBencode() ([]byte, error) {
|
||||
return bencodeBytesResult(me.MarshalBinary())
|
||||
}
|
||||
|
||||
func (me *CompactIPv4NodeInfo) UnmarshalBinary(b []byte) error {
|
||||
return unmarshalBinarySlice(me, b)
|
||||
}
|
||||
|
||||
func (me *CompactIPv4NodeInfo) UnmarshalBencode(b []byte) error {
|
||||
return unmarshalBencodedBinary(me, b)
|
||||
}
|
||||
34
vendor/github.com/anacrolix/dht/v2/krpc/CompactIPv6NodeAddrs.go
generated
vendored
Normal file
34
vendor/github.com/anacrolix/dht/v2/krpc/CompactIPv6NodeAddrs.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package krpc
|
||||
|
||||
import "github.com/anacrolix/missinggo/slices"
|
||||
|
||||
type CompactIPv6NodeAddrs []NodeAddr
|
||||
|
||||
func (CompactIPv6NodeAddrs) ElemSize() int { return 18 }
|
||||
|
||||
func (me CompactIPv6NodeAddrs) MarshalBinary() ([]byte, error) {
|
||||
return marshalBinarySlice(slices.Map(func(na NodeAddr) NodeAddr {
|
||||
na.IP = na.IP.To16()
|
||||
return na
|
||||
}, me).(CompactIPv6NodeAddrs))
|
||||
}
|
||||
|
||||
func (me CompactIPv6NodeAddrs) MarshalBencode() ([]byte, error) {
|
||||
return bencodeBytesResult(me.MarshalBinary())
|
||||
}
|
||||
|
||||
func (me *CompactIPv6NodeAddrs) UnmarshalBinary(b []byte) error {
|
||||
return unmarshalBinarySlice(me, b)
|
||||
}
|
||||
|
||||
func (me *CompactIPv6NodeAddrs) UnmarshalBencode(b []byte) error {
|
||||
return unmarshalBencodedBinary(me, b)
|
||||
}
|
||||
|
||||
func (me CompactIPv6NodeAddrs) NodeAddrs() []NodeAddr {
|
||||
return me
|
||||
}
|
||||
|
||||
func (me CompactIPv6NodeAddrs) Index(x NodeAddr) int {
|
||||
return addrIndex(me, x)
|
||||
}
|
||||
32
vendor/github.com/anacrolix/dht/v2/krpc/CompactIPv6NodeInfo.go
generated
vendored
Normal file
32
vendor/github.com/anacrolix/dht/v2/krpc/CompactIPv6NodeInfo.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/missinggo/slices"
|
||||
)
|
||||
|
||||
type (
|
||||
CompactIPv6NodeInfo []NodeInfo
|
||||
)
|
||||
|
||||
func (CompactIPv6NodeInfo) ElemSize() int {
|
||||
return 38
|
||||
}
|
||||
|
||||
func (me CompactIPv6NodeInfo) MarshalBinary() ([]byte, error) {
|
||||
return marshalBinarySlice(slices.Map(func(ni NodeInfo) NodeInfo {
|
||||
ni.Addr.IP = ni.Addr.IP.To16()
|
||||
return ni
|
||||
}, me).(CompactIPv6NodeInfo))
|
||||
}
|
||||
|
||||
func (me CompactIPv6NodeInfo) MarshalBencode() ([]byte, error) {
|
||||
return bencodeBytesResult(me.MarshalBinary())
|
||||
}
|
||||
|
||||
func (me *CompactIPv6NodeInfo) UnmarshalBinary(b []byte) error {
|
||||
return unmarshalBinarySlice(me, b)
|
||||
}
|
||||
|
||||
func (me *CompactIPv6NodeInfo) UnmarshalBencode(b []byte) error {
|
||||
return unmarshalBencodedBinary(me, b)
|
||||
}
|
||||
49
vendor/github.com/anacrolix/dht/v2/krpc/bep33.go
generated
vendored
Normal file
49
vendor/github.com/anacrolix/dht/v2/krpc/bep33.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"math"
|
||||
"math/bits"
|
||||
"net"
|
||||
)
|
||||
|
||||
const (
|
||||
m = 256 * 8
|
||||
k = 2
|
||||
)
|
||||
|
||||
type ScrapeBloomFilter [256]byte
|
||||
|
||||
// Note that if you intend for an IP to be in the IPv4 space, you might want to trim it to 4 bytes
|
||||
// with IP.To4.
|
||||
func (me *ScrapeBloomFilter) AddIp(ip net.IP) {
|
||||
h := sha1.New()
|
||||
h.Write(ip)
|
||||
var sum [20]byte
|
||||
h.Sum(sum[:0])
|
||||
me.addK(int(sum[0]) | int(sum[1])<<8)
|
||||
me.addK(int(sum[2]) | int(sum[3])<<8)
|
||||
}
|
||||
|
||||
func (me *ScrapeBloomFilter) addK(index int) {
|
||||
index %= m
|
||||
me[index/8] |= 1 << (index % 8)
|
||||
}
|
||||
|
||||
func (me ScrapeBloomFilter) countZeroes() (ret int) {
|
||||
for _, i := range me {
|
||||
ret += 8 - bits.OnesCount8(i)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *ScrapeBloomFilter) EstimateCount() float64 {
|
||||
if me == nil {
|
||||
return 0
|
||||
}
|
||||
c := float64(me.countZeroes())
|
||||
if c > m-1 {
|
||||
c = m - 1
|
||||
}
|
||||
return math.Log(c/m) / (k * math.Log(1.-1./m))
|
||||
}
|
||||
9
vendor/github.com/anacrolix/dht/v2/krpc/bep46.go
generated
vendored
Normal file
9
vendor/github.com/anacrolix/dht/v2/krpc/bep46.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
)
|
||||
|
||||
type Bep46Payload struct {
|
||||
Ih metainfo.Hash `bencode:"ih"`
|
||||
}
|
||||
23
vendor/github.com/anacrolix/dht/v2/krpc/compact-infohashes.go
generated
vendored
Normal file
23
vendor/github.com/anacrolix/dht/v2/krpc/compact-infohashes.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package krpc
|
||||
|
||||
type Infohash [20]byte
|
||||
|
||||
type CompactInfohashes [][20]byte
|
||||
|
||||
func (CompactInfohashes) ElemSize() int { return 20 }
|
||||
|
||||
func (me CompactInfohashes) MarshalBinary() ([]byte, error) {
|
||||
return marshalBinarySlice(me)
|
||||
}
|
||||
|
||||
func (me CompactInfohashes) MarshalBencode() ([]byte, error) {
|
||||
return bencodeBytesResult(me.MarshalBinary())
|
||||
}
|
||||
|
||||
func (me *CompactInfohashes) UnmarshalBinary(b []byte) error {
|
||||
return unmarshalBinarySlice(me, b)
|
||||
}
|
||||
|
||||
func (me *CompactInfohashes) UnmarshalBencode(b []byte) error {
|
||||
return unmarshalBencodedBinary(me, b)
|
||||
}
|
||||
84
vendor/github.com/anacrolix/dht/v2/krpc/compact_helpers.go
generated
vendored
Normal file
84
vendor/github.com/anacrolix/dht/v2/krpc/compact_helpers.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/anacrolix/missinggo/slices"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
func unmarshalBencodedBinary(u encoding.BinaryUnmarshaler, b []byte) (err error) {
|
||||
var ub string
|
||||
err = bencode.Unmarshal(b, &ub)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return u.UnmarshalBinary([]byte(ub))
|
||||
}
|
||||
|
||||
type elemSizer interface {
|
||||
ElemSize() int
|
||||
}
|
||||
|
||||
func unmarshalBinarySlice(slice elemSizer, b []byte) (err error) {
|
||||
sliceValue := reflect.ValueOf(slice).Elem()
|
||||
elemType := sliceValue.Type().Elem()
|
||||
bytesPerElem := slice.ElemSize()
|
||||
elem := reflect.New(elemType)
|
||||
for len(b) != 0 {
|
||||
if len(b) < bytesPerElem {
|
||||
err = fmt.Errorf("%d trailing bytes < %d required for element", len(b), bytesPerElem)
|
||||
break
|
||||
}
|
||||
if bu, ok := elem.Interface().(encoding.BinaryUnmarshaler); ok {
|
||||
err = bu.UnmarshalBinary(b[:bytesPerElem])
|
||||
} else if elem.Elem().Len() == bytesPerElem {
|
||||
reflect.Copy(elem.Elem(), reflect.ValueOf(b[:bytesPerElem]))
|
||||
} else {
|
||||
err = fmt.Errorf("can't unmarshal %v bytes into %v", bytesPerElem, elem.Type())
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sliceValue.Set(reflect.Append(sliceValue, elem.Elem()))
|
||||
b = b[bytesPerElem:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func marshalBinarySlice(slice elemSizer) (ret []byte, err error) {
|
||||
var elems []encoding.BinaryMarshaler
|
||||
slices.MakeInto(&elems, slice)
|
||||
for _, e := range elems {
|
||||
var b []byte
|
||||
b, err = e.MarshalBinary()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(b) != slice.ElemSize() {
|
||||
panic(fmt.Sprintf("marshalled %d bytes, but expected %d", len(b), slice.ElemSize()))
|
||||
}
|
||||
ret = append(ret, b...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func bencodeBytesResult(b []byte, err error) ([]byte, error) {
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
return bencode.Marshal(b)
|
||||
}
|
||||
|
||||
// returns position of x in v, or -1 if not found
|
||||
func addrIndex(v []NodeAddr, x NodeAddr) int {
|
||||
for i := 0; i < len(v); i += 1 {
|
||||
if v[i].Equal(x) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
73
vendor/github.com/anacrolix/dht/v2/krpc/error.go
generated
vendored
Normal file
73
vendor/github.com/anacrolix/dht/v2/krpc/error.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
const (
|
||||
// These are documented in BEP 5.
|
||||
ErrorCodeGenericError = 201
|
||||
ErrorCodeServerError = 202
|
||||
ErrorCodeProtocolError = 203
|
||||
ErrorCodeMethodUnknown = 204
|
||||
// BEP 44
|
||||
ErrorCodeMessageValueFieldTooBig = 205
|
||||
ErrorCodeInvalidSignature = 206
|
||||
ErrorCodeSaltFieldTooBig = 207
|
||||
ErrorCodeCasHashMismatched = 301
|
||||
ErrorCodeSequenceNumberLessThanCurrent = 302
|
||||
)
|
||||
|
||||
var ErrorMethodUnknown = Error{
|
||||
Code: ErrorCodeMethodUnknown,
|
||||
Msg: "Method Unknown",
|
||||
}
|
||||
|
||||
// Represented as a string or list in bencode.
|
||||
type Error struct {
|
||||
Code int
|
||||
Msg string
|
||||
}
|
||||
|
||||
var (
|
||||
_ bencode.Unmarshaler = (*Error)(nil)
|
||||
_ bencode.Marshaler = (*Error)(nil)
|
||||
_ error = Error{}
|
||||
)
|
||||
|
||||
func (e *Error) UnmarshalBencode(_b []byte) (err error) {
|
||||
var _v interface{}
|
||||
err = bencode.Unmarshal(_b, &_v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch v := _v.(type) {
|
||||
case []interface{}:
|
||||
func() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("unpacking %#v: %s", v, r)
|
||||
}()
|
||||
e.Code = int(v[0].(int64))
|
||||
e.Msg = v[1].(string)
|
||||
}()
|
||||
case string:
|
||||
e.Msg = v
|
||||
default:
|
||||
err = fmt.Errorf(`KRPC error bencode value has unexpected type: %T`, _v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (e Error) MarshalBencode() (ret []byte, err error) {
|
||||
return bencode.Marshal([]interface{}{e.Code, e.Msg})
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
return fmt.Sprintf("KRPC error %d: %s", e.Code, e.Msg)
|
||||
}
|
||||
74
vendor/github.com/anacrolix/dht/v2/krpc/id.go
generated
vendored
Normal file
74
vendor/github.com/anacrolix/dht/v2/krpc/id.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
)
|
||||
|
||||
func RandomNodeID() (id ID) {
|
||||
crand.Read(id[:])
|
||||
return
|
||||
}
|
||||
|
||||
type ID [20]byte
|
||||
|
||||
var (
|
||||
_ interface {
|
||||
bencode.Unmarshaler
|
||||
encoding.TextUnmarshaler
|
||||
} = (*ID)(nil)
|
||||
_ bencode.Marshaler = ID{}
|
||||
_ fmt.Formatter = ID{}
|
||||
)
|
||||
|
||||
func (h ID) Format(f fmt.State, c rune) {
|
||||
// See metainfo.Hash.
|
||||
f.Write([]byte(h.String()))
|
||||
}
|
||||
|
||||
func IdFromString(s string) (id ID) {
|
||||
if n := copy(id[:], s); n != 20 {
|
||||
panic(n)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (id ID) MarshalBencode() ([]byte, error) {
|
||||
return []byte("20:" + string(id[:])), nil
|
||||
}
|
||||
|
||||
func (id *ID) UnmarshalBencode(b []byte) error {
|
||||
var s string
|
||||
if err := bencode.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
if n := copy(id[:], s); n != 20 {
|
||||
return fmt.Errorf("string has wrong length: %d", n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (id *ID) UnmarshalText(b []byte) (err error) {
|
||||
n, err := hex.Decode(id[:], b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != len(*id) {
|
||||
err = fmt.Errorf("expected %v bytes, only got %v", len(*id), n)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (id ID) String() string {
|
||||
return hex.EncodeToString(id[:])
|
||||
}
|
||||
|
||||
func (id ID) Int160() int160.T {
|
||||
return int160.FromByteArray(id)
|
||||
}
|
||||
131
vendor/github.com/anacrolix/dht/v2/krpc/msg.go
generated
vendored
Normal file
131
vendor/github.com/anacrolix/dht/v2/krpc/msg.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package krpc
|
||||
|
||||
// Msg represents messages that nodes in the network send to each other as specified by the protocol.
|
||||
// They are also referred to as the KRPC messages.
|
||||
// There are three types of messages: QUERY, RESPONSE, ERROR
|
||||
// The message is a dictionary that is then
|
||||
// "bencoded" (serialization & compression format adopted by the BitTorrent)
|
||||
// and sent via the UDP connection to peers.
|
||||
//
|
||||
// A KRPC message is a single dictionary with two keys common to every message and additional keys depending on the type of message.
|
||||
// Every message has a key "t" with a string value representing a transaction ID.
|
||||
// This transaction ID is generated by the querying node and is echoed in the response, so responses
|
||||
// may be correlated with multiple queries to the same node. The transaction ID should be encoded as a short string of binary numbers, typically 2 characters are enough as they cover 2^16 outstanding queries. The other key contained in every KRPC message is "y" with a single character value describing the type of message. The value of the "y" key is one of "q" for query, "r" for response, or "e" for error.
|
||||
// 3 message types: QUERY, RESPONSE, ERROR
|
||||
type Msg struct {
|
||||
Q string `bencode:"q,omitempty"` // Query method (one of 4: "ping", "find_node", "get_peers", "announce_peer")
|
||||
A *MsgArgs `bencode:"a,omitempty"` // named arguments sent with a query
|
||||
T string `bencode:"t"` // required: transaction ID
|
||||
Y string `bencode:"y"` // required: type of the message: q for QUERY, r for RESPONSE, e for ERROR
|
||||
R *Return `bencode:"r,omitempty"` // RESPONSE type only
|
||||
E *Error `bencode:"e,omitempty"` // ERROR type only
|
||||
IP NodeAddr `bencode:"ip,omitempty"`
|
||||
ReadOnly bool `bencode:"ro,omitempty"` // BEP 43. Sender does not respond to queries.
|
||||
}
|
||||
|
||||
type MsgArgs struct {
|
||||
ID ID `bencode:"id"` // ID of the querying Node
|
||||
InfoHash ID `bencode:"info_hash,omitempty"` // InfoHash of the torrent
|
||||
Target ID `bencode:"target,omitempty"` // ID of the node sought
|
||||
// Token received from an earlier get_peers query. Also used in a BEP 44 put.
|
||||
Token string `bencode:"token,omitempty"`
|
||||
Port *int `bencode:"port,omitempty"` // Sender's torrent port
|
||||
ImpliedPort bool `bencode:"implied_port,omitempty"` // Use senders apparent DHT port
|
||||
Want []Want `bencode:"want,omitempty"` // Contains strings like "n4" and "n6" from BEP 32.
|
||||
NoSeed int `bencode:"noseed,omitempty"` // BEP 33
|
||||
Scrape int `bencode:"scrape,omitempty"` // BEP 33
|
||||
|
||||
// BEP 44
|
||||
|
||||
// I don't know if we should use bencode.Bytes for this. If we unmarshalled bytes that didn't
|
||||
// marshal back the same, our hashes will not match. But this might also serve to prevent abuse.
|
||||
V interface{} `bencode:"v,omitempty"`
|
||||
Seq *int64 `bencode:"seq,omitempty"`
|
||||
Cas int64 `bencode:"cas,omitempty"`
|
||||
K [32]byte `bencode:"k,omitempty"`
|
||||
Salt []byte `bencode:"salt,omitempty"`
|
||||
Sig [64]byte `bencode:"sig,omitempty"`
|
||||
}
|
||||
|
||||
type Want string
|
||||
|
||||
const (
|
||||
WantNodes Want = "n4"
|
||||
WantNodes6 Want = "n6"
|
||||
)
|
||||
|
||||
// BEP 51 (DHT Infohash Indexing)
|
||||
type Bep51Return struct {
|
||||
Interval *int64 `bencode:"interval,omitempty"`
|
||||
Num *int64 `bencode:"num,omitempty"`
|
||||
// Nodes supporting this extension should always include the samples field in the response, even
|
||||
// when it is zero-length. This lets indexing nodes to distinguish nodes supporting this
|
||||
// extension from those that respond to unknown query types which contain a target field [2].
|
||||
Samples *CompactInfohashes `bencode:"samples,omitempty"`
|
||||
}
|
||||
|
||||
type Bep44Return struct {
|
||||
V interface{} `bencode:"v,omitempty"`
|
||||
K [32]byte `bencode:"k,omitempty"`
|
||||
Sig [64]byte `bencode:"sig,omitempty"`
|
||||
Seq *int64 `bencode:"seq,omitempty"`
|
||||
}
|
||||
|
||||
type Return struct {
|
||||
// All returns are supposed to contain an ID, but what if they don't?
|
||||
ID ID `bencode:"id"` // ID of the queried (and responding) node
|
||||
|
||||
// K closest nodes to the requested target. Included in responses to queries that imply
|
||||
// traversal, for example get_peers, find_nodes, get, sample_infohashes.
|
||||
Nodes CompactIPv4NodeInfo `bencode:"nodes,omitempty"`
|
||||
Nodes6 CompactIPv6NodeInfo `bencode:"nodes6,omitempty"`
|
||||
|
||||
Token *string `bencode:"token,omitempty"` // Token for future announce_peer or put (BEP 44)
|
||||
Values []NodeAddr `bencode:"values,omitempty"` // Torrent peers
|
||||
|
||||
// BEP 33 (scrapes)
|
||||
BFsd *ScrapeBloomFilter `bencode:"BFsd,omitempty"`
|
||||
BFpe *ScrapeBloomFilter `bencode:"BFpe,omitempty"`
|
||||
|
||||
Bep51Return
|
||||
|
||||
// BEP 44
|
||||
Bep44Return
|
||||
}
|
||||
|
||||
func (r Return) ForAllNodes(f func(NodeInfo)) {
|
||||
for _, n := range r.Nodes {
|
||||
f(n)
|
||||
}
|
||||
for _, n := range r.Nodes6 {
|
||||
f(n)
|
||||
}
|
||||
}
|
||||
|
||||
// The node ID of the source of this Msg. Returns nil if it isn't present.
|
||||
// TODO: Can we verify Msgs more aggressively so this is guaranteed to return
|
||||
// a valid ID for a checked Msg?
|
||||
func (m Msg) SenderID() *ID {
|
||||
switch m.Y {
|
||||
case "q":
|
||||
if m.A == nil {
|
||||
return nil
|
||||
}
|
||||
return &m.A.ID
|
||||
case "r":
|
||||
if m.R == nil {
|
||||
return nil
|
||||
}
|
||||
return &m.R.ID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// This does not return an error, but (*Error)(nil) is still a non-nil error. You have been warned!
|
||||
// This language is evil.
|
||||
func (m Msg) Error() *Error {
|
||||
if m.Y != "e" {
|
||||
return nil
|
||||
}
|
||||
return m.E
|
||||
}
|
||||
66
vendor/github.com/anacrolix/dht/v2/krpc/nodeaddr.go
generated
vendored
Normal file
66
vendor/github.com/anacrolix/dht/v2/krpc/nodeaddr.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
type NodeAddr struct {
|
||||
IP net.IP
|
||||
Port int
|
||||
}
|
||||
|
||||
// A zero Port is taken to mean no port provided, per BEP 7.
|
||||
func (me NodeAddr) String() string {
|
||||
if me.Port == 0 {
|
||||
return me.IP.String()
|
||||
}
|
||||
return net.JoinHostPort(me.IP.String(), strconv.FormatInt(int64(me.Port), 10))
|
||||
}
|
||||
|
||||
func (me *NodeAddr) UnmarshalBinary(b []byte) error {
|
||||
me.IP = make(net.IP, len(b)-2)
|
||||
copy(me.IP, b[:len(b)-2])
|
||||
me.Port = int(binary.BigEndian.Uint16(b[len(b)-2:]))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (me *NodeAddr) UnmarshalBencode(b []byte) (err error) {
|
||||
var _b []byte
|
||||
err = bencode.Unmarshal(b, &_b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return me.UnmarshalBinary(_b)
|
||||
}
|
||||
|
||||
func (me NodeAddr) MarshalBinary() ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
b.Write(me.IP)
|
||||
binary.Write(&b, binary.BigEndian, uint16(me.Port))
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (me NodeAddr) MarshalBencode() ([]byte, error) {
|
||||
return bencodeBytesResult(me.MarshalBinary())
|
||||
}
|
||||
|
||||
func (me NodeAddr) UDP() *net.UDPAddr {
|
||||
return &net.UDPAddr{
|
||||
IP: me.IP,
|
||||
Port: me.Port,
|
||||
}
|
||||
}
|
||||
|
||||
func (me *NodeAddr) FromUDPAddr(ua *net.UDPAddr) {
|
||||
me.IP = ua.IP
|
||||
me.Port = ua.Port
|
||||
}
|
||||
|
||||
func (me NodeAddr) Equal(x NodeAddr) bool {
|
||||
return me.IP.Equal(x.IP) && me.Port == x.Port
|
||||
}
|
||||
46
vendor/github.com/anacrolix/dht/v2/krpc/nodeinfo.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/dht/v2/krpc/nodeinfo.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
)
|
||||
|
||||
type NodeInfo struct {
|
||||
ID ID
|
||||
Addr NodeAddr
|
||||
}
|
||||
|
||||
func (me NodeInfo) String() string {
|
||||
return fmt.Sprintf("{%x at %s}", me.ID, me.Addr)
|
||||
}
|
||||
|
||||
func RandomNodeInfo(ipLen int) (ni NodeInfo) {
|
||||
rand.Read(ni.ID[:])
|
||||
ni.Addr.IP = make(net.IP, ipLen)
|
||||
rand.Read(ni.Addr.IP)
|
||||
ni.Addr.Port = rand.Intn(math.MaxUint16 + 1)
|
||||
return
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
encoding.BinaryMarshaler
|
||||
encoding.BinaryUnmarshaler
|
||||
} = (*NodeInfo)(nil)
|
||||
|
||||
func (ni NodeInfo) MarshalBinary() ([]byte, error) {
|
||||
var w bytes.Buffer
|
||||
w.Write(ni.ID[:])
|
||||
w.Write(ni.Addr.IP)
|
||||
binary.Write(&w, binary.BigEndian, uint16(ni.Addr.Port))
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
func (ni *NodeInfo) UnmarshalBinary(b []byte) error {
|
||||
copy(ni.ID[:], b)
|
||||
return ni.Addr.UnmarshalBinary(b[20:])
|
||||
}
|
||||
36
vendor/github.com/anacrolix/dht/v2/misc.go
generated
vendored
Normal file
36
vendor/github.com/anacrolix/dht/v2/misc.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
"github.com/anacrolix/dht/v2/types"
|
||||
"github.com/anacrolix/missinggo/v2/iter"
|
||||
)
|
||||
|
||||
func mustListen(addr string) net.PacketConn {
|
||||
ret, err := net.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func addrResolver(addr string) func() ([]Addr, error) {
|
||||
return func() ([]Addr, error) {
|
||||
ua, err := net.ResolveUDPAddr("udp", addr)
|
||||
return []Addr{NewAddr(ua)}, err
|
||||
}
|
||||
}
|
||||
|
||||
type addrMaybeId = types.AddrMaybeId
|
||||
|
||||
func randomIdInBucket(rootId int160.T, bucketIndex int) int160.T {
|
||||
id := int160.FromByteArray(krpc.RandomNodeID())
|
||||
for i := range iter.N(bucketIndex) {
|
||||
id.SetBit(i, rootId.GetBit(i))
|
||||
}
|
||||
id.SetBit(bucketIndex, !rootId.GetBit(bucketIndex))
|
||||
return id
|
||||
}
|
||||
1
vendor/github.com/anacrolix/dht/v2/nearest-nodes.go
generated
vendored
Normal file
1
vendor/github.com/anacrolix/dht/v2/nearest-nodes.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package dht
|
||||
56
vendor/github.com/anacrolix/dht/v2/node.go
generated
vendored
Normal file
56
vendor/github.com/anacrolix/dht/v2/node.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
)
|
||||
|
||||
type nodeKey struct {
|
||||
Addr Addr
|
||||
Id int160.T
|
||||
}
|
||||
|
||||
type node struct {
|
||||
nodeKey
|
||||
|
||||
lastGotQuery time.Time // From the remote node
|
||||
lastGotResponse time.Time // From the remote node
|
||||
|
||||
numReceivesFrom int
|
||||
failedLastQuestionablePing bool
|
||||
}
|
||||
|
||||
func (s *Server) IsQuestionable(n *node) bool {
|
||||
return !s.IsGood(n) && !s.nodeIsBad(n)
|
||||
}
|
||||
|
||||
func (n *node) hasAddrAndID(addr Addr, id int160.T) bool {
|
||||
return id == n.Id && n.Addr.String() == addr.String()
|
||||
}
|
||||
|
||||
func (n *node) IsSecure() bool {
|
||||
return NodeIdSecure(n.Id.AsByteArray(), n.Addr.IP())
|
||||
}
|
||||
|
||||
func (n *node) idString() string {
|
||||
return n.Id.ByteString()
|
||||
}
|
||||
|
||||
func (n *node) NodeInfo() (ret krpc.NodeInfo) {
|
||||
ret.Addr = n.Addr.KRPC()
|
||||
if n := copy(ret.ID[:], n.idString()); n != 20 {
|
||||
panic(n)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Per the spec in BEP 5.
|
||||
func (s *Server) IsGood(n *node) bool {
|
||||
if s.nodeIsBad(n) {
|
||||
return false
|
||||
}
|
||||
return time.Since(n.lastGotResponse) < 15*time.Minute ||
|
||||
!n.lastGotResponse.IsZero() && time.Since(n.lastGotQuery) < 15*time.Minute
|
||||
}
|
||||
43
vendor/github.com/anacrolix/dht/v2/nodes_file.go
generated
vendored
Normal file
43
vendor/github.com/anacrolix/dht/v2/nodes_file.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
)
|
||||
|
||||
func WriteNodesToFile(ns []krpc.NodeInfo, fileName string) (err error) {
|
||||
b, err := krpc.CompactIPv6NodeInfo(ns).MarshalBinary()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
f, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o640)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
closeErr := f.Close()
|
||||
if err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
}()
|
||||
_, err = f.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
func ReadNodesFromFile(fileName string) (ns []krpc.NodeInfo, err error) {
|
||||
f, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
b, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var cnis krpc.CompactIPv6NodeInfo
|
||||
err = cnis.UnmarshalBinary(b)
|
||||
ns = cnis
|
||||
return
|
||||
}
|
||||
109
vendor/github.com/anacrolix/dht/v2/peer-store/in-memory.go
generated
vendored
Normal file
109
vendor/github.com/anacrolix/dht/v2/peer-store/in-memory.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package peer_store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
debug_writer "github.com/anacrolix/confluence/debug-writer"
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
"github.com/anacrolix/multiless"
|
||||
)
|
||||
|
||||
type InMemory struct {
|
||||
// This is used for sorting infohashes by distance in WriteDebug.
|
||||
RootId int160.T
|
||||
mu sync.RWMutex
|
||||
index map[InfoHash]indexValue
|
||||
}
|
||||
|
||||
// A uniqueness key for entries to the entry details
|
||||
type indexValue = map[string]NodeAndTime
|
||||
|
||||
var _ interface {
|
||||
debug_writer.Interface
|
||||
} = (*InMemory)(nil)
|
||||
|
||||
func (me *InMemory) GetPeers(ih InfoHash) (ret []krpc.NodeAddr) {
|
||||
me.mu.RLock()
|
||||
defer me.mu.RUnlock()
|
||||
for b := range me.index[ih] {
|
||||
var r krpc.NodeAddr
|
||||
err := r.UnmarshalBinary([]byte(b))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ret = append(ret, r)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *InMemory) AddPeer(ih InfoHash, na krpc.NodeAddr) {
|
||||
key := string(na.IP)
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.index == nil {
|
||||
me.index = make(map[InfoHash]indexValue)
|
||||
}
|
||||
nodes := me.index[ih]
|
||||
if nodes == nil {
|
||||
nodes = make(indexValue)
|
||||
me.index[ih] = nodes
|
||||
}
|
||||
nodes[key] = NodeAndTime{na, time.Now()}
|
||||
}
|
||||
|
||||
type NodeAndTime struct {
|
||||
krpc.NodeAddr
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (me *InMemory) GetAll() (ret map[InfoHash][]NodeAndTime) {
|
||||
me.mu.RLock()
|
||||
defer me.mu.RUnlock()
|
||||
ret = make(map[InfoHash][]NodeAndTime, len(me.index))
|
||||
for ih, nodes := range me.index {
|
||||
for _, v := range nodes {
|
||||
ret[ih] = append(ret[ih], v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *InMemory) WriteDebug(w io.Writer) {
|
||||
all := me.GetAll()
|
||||
var totalCount int
|
||||
type sliceElem struct {
|
||||
InfoHash
|
||||
addrs []NodeAndTime
|
||||
}
|
||||
var allSlice []sliceElem
|
||||
for ih, addrs := range all {
|
||||
totalCount += len(addrs)
|
||||
allSlice = append(allSlice, sliceElem{ih, addrs})
|
||||
}
|
||||
fmt.Fprintf(w, "total count: %v\n\n", totalCount)
|
||||
sort.Slice(allSlice, func(i, j int) bool {
|
||||
return int160.Distance(int160.FromByteArray(allSlice[i].InfoHash), me.RootId).Cmp(
|
||||
int160.Distance(int160.FromByteArray(allSlice[j].InfoHash), me.RootId)) < 0
|
||||
})
|
||||
for _, elem := range allSlice {
|
||||
addrs := elem.addrs
|
||||
fmt.Fprintf(w, "%v (count %v):\n", elem.InfoHash, len(addrs))
|
||||
sort.Slice(addrs, func(i, j int) bool {
|
||||
return multiless.New().Cmp(
|
||||
bytes.Compare(addrs[i].IP, addrs[j].IP)).Int64(
|
||||
addrs[j].Time.UnixNano(), addrs[i].Time.UnixNano()).Int(
|
||||
addrs[i].Port, addrs[j].Port,
|
||||
).MustLess()
|
||||
})
|
||||
for _, na := range addrs {
|
||||
fmt.Fprintf(w, "\t%v (age: %v)\n", na.NodeAddr, time.Since(na.Time))
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(w)
|
||||
}
|
||||
13
vendor/github.com/anacrolix/dht/v2/peer-store/peer-store.go
generated
vendored
Normal file
13
vendor/github.com/anacrolix/dht/v2/peer-store/peer-store.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package peer_store
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
)
|
||||
|
||||
type InfoHash = metainfo.Hash
|
||||
|
||||
type Interface interface {
|
||||
AddPeer(InfoHash, krpc.NodeAddr)
|
||||
GetPeers(InfoHash) []krpc.NodeAddr
|
||||
}
|
||||
102
vendor/github.com/anacrolix/dht/v2/security.go
generated
vendored
Normal file
102
vendor/github.com/anacrolix/dht/v2/security.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
"net"
|
||||
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
)
|
||||
|
||||
func maskForIP(ip net.IP) []byte {
|
||||
switch {
|
||||
case ip.To4() != nil:
|
||||
return []byte{0x03, 0x0f, 0x3f, 0xff}
|
||||
default:
|
||||
return []byte{0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the CRC used to make or validate secure node ID.
|
||||
func crcIP(ip net.IP, rand uint8) uint32 {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
ip = ip4
|
||||
}
|
||||
// Copy IP so we can make changes. Go sux at this.
|
||||
ip = append(make(net.IP, 0, len(ip)), ip...)
|
||||
mask := maskForIP(ip)
|
||||
for i := range mask {
|
||||
ip[i] &= mask[i]
|
||||
}
|
||||
r := rand & 7
|
||||
ip[0] |= r << 5
|
||||
return crc32.Checksum(ip[:len(mask)], crc32.MakeTable(crc32.Castagnoli))
|
||||
}
|
||||
|
||||
// Makes a node ID secure, in-place. The ID is 20 raw bytes.
|
||||
// http://www.libtorrent.org/dht_sec.html
|
||||
func SecureNodeId(id *krpc.ID, ip net.IP) {
|
||||
crc := crcIP(ip, id[19])
|
||||
id[0] = byte(crc >> 24 & 0xff)
|
||||
id[1] = byte(crc >> 16 & 0xff)
|
||||
id[2] = byte(crc>>8&0xf8) | id[2]&7
|
||||
}
|
||||
|
||||
// Returns whether the node ID is considered secure. The id is the 20 raw
|
||||
// bytes. http://www.libtorrent.org/dht_sec.html
|
||||
func NodeIdSecure(id [20]byte, ip net.IP) bool {
|
||||
if isLocalNetwork(ip) {
|
||||
return true
|
||||
}
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
ip = ip4
|
||||
}
|
||||
crc := crcIP(ip, id[19])
|
||||
if id[0] != byte(crc>>24&0xff) {
|
||||
return false
|
||||
}
|
||||
if id[1] != byte(crc>>16&0xff) {
|
||||
return false
|
||||
}
|
||||
if id[2]&0xf8 != byte(crc>>8&0xf8) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var classA, classB, classC *net.IPNet
|
||||
|
||||
func mustParseCIDRIPNet(s string) *net.IPNet {
|
||||
_, ret, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func init() {
|
||||
classA = mustParseCIDRIPNet("10.0.0.0/8")
|
||||
classB = mustParseCIDRIPNet("172.16.0.0/12")
|
||||
classC = mustParseCIDRIPNet("192.168.0.0/16")
|
||||
}
|
||||
|
||||
// Per http://www.libtorrent.org/dht_sec.html#enforcement, the IP is
|
||||
// considered a local network address and should be exempted from node ID
|
||||
// verification.
|
||||
func isLocalNetwork(ip net.IP) bool {
|
||||
if classA.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
if classB.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
if classC.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
if ip.IsLinkLocalUnicast() {
|
||||
return true
|
||||
}
|
||||
if ip.IsLoopback() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
1459
vendor/github.com/anacrolix/dht/v2/server.go
generated
vendored
Normal file
1459
vendor/github.com/anacrolix/dht/v2/server.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
134
vendor/github.com/anacrolix/dht/v2/table.go
generated
vendored
Normal file
134
vendor/github.com/anacrolix/dht/v2/table.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
)
|
||||
|
||||
// Node table, with indexes on distance from root ID to bucket, and node addr.
|
||||
type table struct {
|
||||
rootID int160.T
|
||||
k int
|
||||
buckets [160]bucket
|
||||
addrs map[string]map[int160.T]struct{}
|
||||
}
|
||||
|
||||
func (tbl *table) K() int {
|
||||
return tbl.k
|
||||
}
|
||||
|
||||
func (tbl *table) randomIdForBucket(bucketIndex int) int160.T {
|
||||
randomId := randomIdInBucket(tbl.rootID, bucketIndex)
|
||||
if randomIdBucketIndex := tbl.bucketIndex(randomId); randomIdBucketIndex != bucketIndex {
|
||||
panic(fmt.Sprintf("bucket index for random id %v == %v not %v", randomId, randomIdBucketIndex, bucketIndex))
|
||||
}
|
||||
return randomId
|
||||
}
|
||||
|
||||
func (tbl *table) addrNodes(addr Addr) []*node {
|
||||
a := tbl.addrs[addr.String()]
|
||||
ret := make([]*node, 0, len(a))
|
||||
for id := range a {
|
||||
ret = append(ret, tbl.getNode(addr, id))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (tbl *table) dropNode(n *node) {
|
||||
as := n.Addr.String()
|
||||
if _, ok := tbl.addrs[as][n.Id]; !ok {
|
||||
panic("missing id for addr")
|
||||
}
|
||||
delete(tbl.addrs[as], n.Id)
|
||||
if len(tbl.addrs[as]) == 0 {
|
||||
delete(tbl.addrs, as)
|
||||
}
|
||||
b := tbl.bucketForID(n.Id)
|
||||
if _, ok := b.nodes[n]; !ok {
|
||||
panic("expected node in bucket")
|
||||
}
|
||||
delete(b.nodes, n)
|
||||
}
|
||||
|
||||
func (tbl *table) bucketForID(id int160.T) *bucket {
|
||||
return &tbl.buckets[tbl.bucketIndex(id)]
|
||||
}
|
||||
|
||||
func (tbl *table) numNodes() (num int) {
|
||||
for _, b := range tbl.buckets {
|
||||
num += b.Len()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (tbl *table) bucketIndex(id int160.T) int {
|
||||
if id == tbl.rootID {
|
||||
panic("nobody puts the root ID in a bucket")
|
||||
}
|
||||
var a int160.T
|
||||
a.Xor(&tbl.rootID, &id)
|
||||
index := 160 - a.BitLen()
|
||||
return index
|
||||
}
|
||||
|
||||
func (tbl *table) forNodes(f func(*node) bool) bool {
|
||||
for _, b := range tbl.buckets {
|
||||
if !b.EachNode(f) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (tbl *table) getNode(addr Addr, id int160.T) *node {
|
||||
if id == tbl.rootID {
|
||||
return nil
|
||||
}
|
||||
return tbl.buckets[tbl.bucketIndex(id)].GetNode(addr, id)
|
||||
}
|
||||
|
||||
func (tbl *table) closestNodes(k int, target int160.T, filter func(*node) bool) (ret []*node) {
|
||||
for bi := func() int {
|
||||
if target == tbl.rootID {
|
||||
return len(tbl.buckets) - 1
|
||||
} else {
|
||||
return tbl.bucketIndex(target)
|
||||
}
|
||||
}(); bi >= 0 && len(ret) < k; bi-- {
|
||||
for n := range tbl.buckets[bi].nodes {
|
||||
if filter(n) {
|
||||
ret = append(ret, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Keep only the closest.
|
||||
if len(ret) > k {
|
||||
ret = ret[:k]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (tbl *table) addNode(n *node) error {
|
||||
if n.Id == tbl.rootID {
|
||||
return errors.New("is root id")
|
||||
}
|
||||
b := &tbl.buckets[tbl.bucketIndex(n.Id)]
|
||||
if b.GetNode(n.Addr, n.Id) != nil {
|
||||
return errors.New("already present")
|
||||
}
|
||||
if b.Len() >= tbl.k {
|
||||
return errors.New("bucket is full")
|
||||
}
|
||||
b.AddNode(n, tbl.k)
|
||||
if tbl.addrs == nil {
|
||||
tbl.addrs = make(map[string]map[int160.T]struct{}, 160*tbl.k)
|
||||
}
|
||||
as := n.Addr.String()
|
||||
if tbl.addrs[as] == nil {
|
||||
tbl.addrs[as] = make(map[int160.T]struct{}, 1)
|
||||
}
|
||||
tbl.addrs[as][n.Id] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
57
vendor/github.com/anacrolix/dht/v2/tokens.go
generated
vendored
Normal file
57
vendor/github.com/anacrolix/dht/v2/tokens.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"github.com/bradfitz/iter"
|
||||
)
|
||||
|
||||
// Manages creation and validation of tokens issued to querying nodes.
|
||||
type tokenServer struct {
|
||||
// Something only we know that peers can't guess, so they can't deduce valid tokens.
|
||||
secret []byte
|
||||
// How long between token changes.
|
||||
interval time.Duration
|
||||
// How many intervals may pass between the current interval, and one used to generate a token before it is invalid.
|
||||
maxIntervalDelta int
|
||||
timeNow func() time.Time
|
||||
}
|
||||
|
||||
func (me tokenServer) CreateToken(addr Addr) string {
|
||||
return me.createToken(addr, me.getTimeNow())
|
||||
}
|
||||
|
||||
func (me tokenServer) createToken(addr Addr, t time.Time) string {
|
||||
h := sha1.New()
|
||||
ip := addr.IP().To16()
|
||||
if len(ip) != 16 {
|
||||
panic(ip)
|
||||
}
|
||||
h.Write(ip)
|
||||
ti := t.UnixNano() / int64(me.interval)
|
||||
var b [8]byte
|
||||
binary.BigEndian.PutUint64(b[:], uint64(ti))
|
||||
h.Write(b[:])
|
||||
h.Write(me.secret)
|
||||
return string(h.Sum(nil))
|
||||
}
|
||||
|
||||
func (me *tokenServer) ValidToken(token string, addr Addr) bool {
|
||||
t := me.getTimeNow()
|
||||
for range iter.N(me.maxIntervalDelta + 1) {
|
||||
if me.createToken(addr, t) == token {
|
||||
return true
|
||||
}
|
||||
t = t.Add(-me.interval)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (me *tokenServer) getTimeNow() time.Time {
|
||||
if me.timeNow == nil {
|
||||
return time.Now()
|
||||
}
|
||||
return me.timeNow()
|
||||
}
|
||||
48
vendor/github.com/anacrolix/dht/v2/transaction.go
generated
vendored
Normal file
48
vendor/github.com/anacrolix/dht/v2/transaction.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
)
|
||||
|
||||
var TransactionTimeout = errors.New("transaction timed out")
|
||||
|
||||
// Transaction keeps track of a message exchange between nodes, such as a
|
||||
// query message and a response message.
|
||||
type Transaction struct {
|
||||
onResponse func(krpc.Msg)
|
||||
}
|
||||
|
||||
func (t *Transaction) handleResponse(m krpc.Msg) {
|
||||
t.onResponse(m)
|
||||
}
|
||||
|
||||
const defaultMaxQuerySends = 1
|
||||
|
||||
func transactionSender(
|
||||
ctx context.Context,
|
||||
send func() error,
|
||||
resendDelay func() time.Duration,
|
||||
maxSends int,
|
||||
) error {
|
||||
var delay time.Duration
|
||||
sends := 0
|
||||
for sends < maxSends {
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
err := send()
|
||||
sends++
|
||||
if err != nil {
|
||||
return fmt.Errorf("send %d: %w", sends, err)
|
||||
}
|
||||
delay = resendDelay()
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
232
vendor/github.com/anacrolix/dht/v2/traversal/operation.go
generated
vendored
Normal file
232
vendor/github.com/anacrolix/dht/v2/traversal/operation.go
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
package traversal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/anacrolix/chansync/events"
|
||||
"github.com/anacrolix/dht/v2/containers"
|
||||
"github.com/anacrolix/sync"
|
||||
|
||||
"github.com/anacrolix/chansync"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
k_nearest_nodes "github.com/anacrolix/dht/v2/k-nearest-nodes"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
"github.com/anacrolix/dht/v2/types"
|
||||
)
|
||||
|
||||
type QueryResult struct {
|
||||
// A node that should be considered for a closest entry.
|
||||
ResponseFrom *krpc.NodeInfo
|
||||
// Data associated with a closest node.
|
||||
ClosestData interface{}
|
||||
Nodes []krpc.NodeInfo
|
||||
Nodes6 []krpc.NodeInfo
|
||||
}
|
||||
|
||||
type OperationInput struct {
|
||||
Target krpc.ID
|
||||
Alpha int
|
||||
K int
|
||||
DoQuery func(context.Context, krpc.NodeAddr) QueryResult
|
||||
NodeFilter func(types.AddrMaybeId) bool
|
||||
}
|
||||
|
||||
type defaultsAppliedOperationInput OperationInput
|
||||
|
||||
func Start(input OperationInput) *Operation {
|
||||
herp := defaultsAppliedOperationInput(input)
|
||||
if herp.Alpha == 0 {
|
||||
herp.Alpha = 3
|
||||
}
|
||||
if herp.K == 0 {
|
||||
herp.K = 8
|
||||
}
|
||||
if herp.NodeFilter == nil {
|
||||
herp.NodeFilter = func(types.AddrMaybeId) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
targetInt160 := herp.Target.Int160()
|
||||
op := &Operation{
|
||||
targetInt160: targetInt160,
|
||||
input: herp,
|
||||
queried: make(map[addrString]struct{}),
|
||||
closest: k_nearest_nodes.New(targetInt160, herp.K),
|
||||
unqueried: containers.NewImmutableAddrMaybeIdsByDistance(targetInt160),
|
||||
}
|
||||
go op.run()
|
||||
return op
|
||||
}
|
||||
|
||||
type addrString string
|
||||
|
||||
type Operation struct {
|
||||
stats Stats
|
||||
mu sync.Mutex
|
||||
unqueried containers.AddrMaybeIdsByDistance
|
||||
queried map[addrString]struct{}
|
||||
closest k_nearest_nodes.Type
|
||||
targetInt160 int160.T
|
||||
input defaultsAppliedOperationInput
|
||||
outstanding int
|
||||
cond chansync.BroadcastCond
|
||||
stalled chansync.LevelTrigger
|
||||
stopping chansync.SetOnce
|
||||
stopped chansync.SetOnce
|
||||
}
|
||||
|
||||
func (op *Operation) Stats() *Stats {
|
||||
return &op.stats
|
||||
}
|
||||
|
||||
func (op *Operation) Stop() {
|
||||
if op.stopping.Set() {
|
||||
go func() {
|
||||
defer op.stopped.Set()
|
||||
op.mu.Lock()
|
||||
defer op.mu.Unlock()
|
||||
for {
|
||||
if op.outstanding == 0 {
|
||||
break
|
||||
}
|
||||
cond := op.cond.Signaled()
|
||||
op.mu.Unlock()
|
||||
<-cond
|
||||
op.mu.Lock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (op *Operation) Stopped() events.Done {
|
||||
return op.stopped.Done()
|
||||
}
|
||||
|
||||
func (op *Operation) Stalled() events.Active {
|
||||
return op.stalled.Active()
|
||||
}
|
||||
|
||||
func (op *Operation) AddNodes(nodes []types.AddrMaybeId) (added int) {
|
||||
op.mu.Lock()
|
||||
defer op.mu.Unlock()
|
||||
before := op.unqueried.Len()
|
||||
for _, n := range nodes {
|
||||
if _, ok := op.queried[addrString(n.Addr.String())]; ok {
|
||||
continue
|
||||
}
|
||||
if !op.input.NodeFilter(n) {
|
||||
continue
|
||||
}
|
||||
op.unqueried = op.unqueried.Add(n)
|
||||
}
|
||||
op.cond.Broadcast()
|
||||
return op.unqueried.Len() - before
|
||||
}
|
||||
|
||||
func (op *Operation) markQueried(addr krpc.NodeAddr) {
|
||||
op.queried[addrString(addr.String())] = struct{}{}
|
||||
}
|
||||
|
||||
func (op *Operation) closestUnqueried() (ret types.AddrMaybeId) {
|
||||
return op.unqueried.Next()
|
||||
}
|
||||
|
||||
func (op *Operation) popClosestUnqueried() types.AddrMaybeId {
|
||||
ret := op.closestUnqueried()
|
||||
op.unqueried = op.unqueried.Delete(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (op *Operation) haveQuery() bool {
|
||||
if op.unqueried.Len() == 0 {
|
||||
return false
|
||||
}
|
||||
if !op.closest.Full() {
|
||||
return true
|
||||
}
|
||||
cu := op.closestUnqueried()
|
||||
if cu.Id == nil {
|
||||
return false
|
||||
}
|
||||
return cu.Id.Distance(op.targetInt160).Cmp(op.closest.Farthest().ID.Int160().Distance(op.targetInt160)) <= 0
|
||||
}
|
||||
|
||||
func (op *Operation) run() {
|
||||
defer close(op.stalled.Signal())
|
||||
op.mu.Lock()
|
||||
defer op.mu.Unlock()
|
||||
for {
|
||||
if op.stopping.IsSet() {
|
||||
return
|
||||
}
|
||||
for op.outstanding < op.input.Alpha && op.haveQuery() {
|
||||
op.startQuery()
|
||||
}
|
||||
var stalled events.Signal
|
||||
if (!op.haveQuery() || op.input.Alpha == 0) && op.outstanding == 0 {
|
||||
stalled = op.stalled.Signal()
|
||||
}
|
||||
queryCondSignaled := op.cond.Signaled()
|
||||
op.mu.Unlock()
|
||||
select {
|
||||
case stalled <- struct{}{}:
|
||||
case <-op.stopping.Done():
|
||||
case <-queryCondSignaled:
|
||||
}
|
||||
op.mu.Lock()
|
||||
}
|
||||
}
|
||||
|
||||
func (op *Operation) addClosest(node krpc.NodeInfo, data interface{}) {
|
||||
var ami types.AddrMaybeId
|
||||
ami.FromNodeInfo(node)
|
||||
if !op.input.NodeFilter(ami) {
|
||||
return
|
||||
}
|
||||
op.closest = op.closest.Push(k_nearest_nodes.Elem{
|
||||
Key: node,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
func (op *Operation) Closest() *k_nearest_nodes.Type {
|
||||
return &op.closest
|
||||
}
|
||||
|
||||
func (op *Operation) startQuery() {
|
||||
a := op.popClosestUnqueried()
|
||||
op.markQueried(a.Addr)
|
||||
op.outstanding++
|
||||
go func() {
|
||||
defer func() {
|
||||
op.mu.Lock()
|
||||
defer op.mu.Unlock()
|
||||
op.outstanding--
|
||||
op.cond.Broadcast()
|
||||
}()
|
||||
// log.Printf("traversal querying %v", a)
|
||||
atomic.AddUint32(&op.stats.NumAddrsTried, 1)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-op.stopping.Done():
|
||||
cancel()
|
||||
}
|
||||
}()
|
||||
res := op.input.DoQuery(ctx, a.Addr)
|
||||
cancel()
|
||||
if res.ResponseFrom != nil {
|
||||
func() {
|
||||
op.mu.Lock()
|
||||
defer op.mu.Unlock()
|
||||
atomic.AddUint32(&op.stats.NumResponses, 1)
|
||||
op.addClosest(*res.ResponseFrom, res.ClosestData)
|
||||
}()
|
||||
}
|
||||
op.AddNodes(types.AddrMaybeIdSliceFromNodeInfoSlice(res.Nodes))
|
||||
op.AddNodes(types.AddrMaybeIdSliceFromNodeInfoSlice(res.Nodes6))
|
||||
}()
|
||||
}
|
||||
8
vendor/github.com/anacrolix/dht/v2/traversal/stats.go
generated
vendored
Normal file
8
vendor/github.com/anacrolix/dht/v2/traversal/stats.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
package traversal
|
||||
|
||||
type Stats struct {
|
||||
// Count of (probably) distinct addresses we've sent traversal queries to. Accessed with atomic.
|
||||
NumAddrsTried uint32
|
||||
// Number of responses we received to queries related to this traversal. Accessed with atomic.
|
||||
NumResponses uint32
|
||||
}
|
||||
72
vendor/github.com/anacrolix/dht/v2/types/addr-maybe-id.go
generated
vendored
Normal file
72
vendor/github.com/anacrolix/dht/v2/types/addr-maybe-id.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
|
||||
"github.com/anacrolix/multiless"
|
||||
|
||||
"github.com/anacrolix/dht/v2/int160"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
)
|
||||
|
||||
func AddrMaybeIdSliceFromNodeInfoSlice(nis []krpc.NodeInfo) (ret []AddrMaybeId) {
|
||||
ret = make([]AddrMaybeId, 0, len(nis))
|
||||
for _, ni := range nis {
|
||||
id := int160.FromByteArray(ni.ID)
|
||||
ret = append(ret, AddrMaybeId{
|
||||
Addr: ni.Addr,
|
||||
Id: &id,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type AddrMaybeId struct {
|
||||
Addr krpc.NodeAddr
|
||||
Id *int160.T
|
||||
}
|
||||
|
||||
func (me AddrMaybeId) TryIntoNodeInfo() *krpc.NodeInfo {
|
||||
if me.Id == nil {
|
||||
return nil
|
||||
}
|
||||
return &krpc.NodeInfo{
|
||||
ID: me.Id.AsByteArray(),
|
||||
Addr: me.Addr,
|
||||
}
|
||||
}
|
||||
|
||||
func (me *AddrMaybeId) FromNodeInfo(ni krpc.NodeInfo) {
|
||||
id := int160.FromByteArray(ni.ID)
|
||||
*me = AddrMaybeId{
|
||||
Addr: ni.Addr,
|
||||
Id: &id,
|
||||
}
|
||||
}
|
||||
|
||||
func (me AddrMaybeId) String() string {
|
||||
if me.Id == nil {
|
||||
return fmt.Sprintf("unknown id at %s", me.Addr)
|
||||
} else {
|
||||
return fmt.Sprintf("%v at %v", *me.Id, me.Addr)
|
||||
}
|
||||
}
|
||||
|
||||
func (l AddrMaybeId) CloserThan(r AddrMaybeId, target int160.T) bool {
|
||||
ml := multiless.New().Bool(l.Id == nil, r.Id == nil)
|
||||
if l.Id != nil && r.Id != nil {
|
||||
ml = ml.Cmp(l.Id.Distance(target).Cmp(r.Id.Distance(target)))
|
||||
}
|
||||
if !ml.Ok() {
|
||||
// We could use maphash, but it wasn't much faster, and requires a seed. A seed would allow
|
||||
// us to prevent deterministic handling of addrs for different uses.
|
||||
hashString := func(s string) uint64 {
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(s))
|
||||
return h.Sum64()
|
||||
}
|
||||
ml = ml.Uint64(hashString(l.Addr.String()), hashString(r.Addr.String()))
|
||||
}
|
||||
return ml.Less()
|
||||
}
|
||||
21
vendor/github.com/anacrolix/envpprof/LICENSE
generated
vendored
Normal file
21
vendor/github.com/anacrolix/envpprof/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Matt Joiner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
14
vendor/github.com/anacrolix/envpprof/README.md
generated
vendored
Normal file
14
vendor/github.com/anacrolix/envpprof/README.md
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# envpprof
|
||||
|
||||
[](https://pkg.go.dev/github.com/anacrolix/envpprof)
|
||||
|
||||
Allows run-time configuration of Go's pprof features and default HTTP mux using the environment variable `GOPPROF`. Import the package with `import _ "github.com/anacrolix/envpprof"`. `envpprof` has an `init` function that will run at process initialization that checks the value of the `GOPPROF` environment variable. The variable can contain a comma-separated list of values, for example `GOPPROF=http,block`. The supported keys are:
|
||||
|
||||
Key | Effect
|
||||
--- | ------
|
||||
http | Exposes the default HTTP muxer [`"net/http".DefaultServeMux`](https://pkg.go.dev/net/http?tab=doc#pkg-variables) to the first free TCP port after `6060` on `localhost`. The process PID, and location are logged automatically when this is enabled. `DefaultServeMux` is frequently the default location to expose status, and debugging endpoints, including those provided by [`net/http/pprof`](https://pkg.go.dev/net/http/pprof?tab=doc). Note that the `net/http/pprof` import is included with `envpprof`, and exposed on `DefaultServeMux`.
|
||||
cpu |Calls [`"runtime/pprof".StartCPUProfile`](https://pkg.go.dev/runtime/pprof?tab=doc#StartCPUProfile), writing to a temporary file in `$HOME/pprof` with the prefix `cpu`. The file is not removed after use. The name of the file is logged when this is enabled. [`envpprof.Stop`](https://pkg.go.dev/github.com/anacrolix/envpprof?tab=doc#Stop) should be deferred from `main` when this will be used, to ensure proper clean up.
|
||||
heap |This is similar to the `cpu` key, but writes heap profile information to a file prefixed with `heap`. The profile will not be written unless `Stop` is invoked. See `cpu` for more.
|
||||
block | This calls [`"runtime".SetBlockProfileRate(1)`](https://pkg.go.dev/runtime?tab=doc#SetBlockProfileRate) enabling the profiling of goroutine blocking events. Note that if `http` is enabled, this exposes the blocking profile at the HTTP path `/debug/pprof/block` per package [`net/http/pprof`](https://pkg.go.dev/net/http/pprof?tab=doc#pkg-overview).
|
||||
mutex | This calls [`"runtime".SetMutexProfileFraction(1)`](https://pkg.go.dev/runtime?tab=doc#SetMutexProfileFraction) enabling profiling of mutex contention events. Note that if `http` is enabled, this exposes the profile at the HTTP path `/debug/pprof/mutex` per package [`net/http/pprof`](https://pkg.go.dev/net/http/pprof?tab=doc#pkg-overview).
|
||||
|
||||
112
vendor/github.com/anacrolix/envpprof/envpprof.go
generated
vendored
Normal file
112
vendor/github.com/anacrolix/envpprof/envpprof.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package envpprof
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
|
||||
"github.com/anacrolix/log"
|
||||
)
|
||||
|
||||
var (
|
||||
pprofDir = filepath.Join(os.Getenv("HOME"), "pprof")
|
||||
heap bool
|
||||
)
|
||||
|
||||
func writeHeapProfile() {
|
||||
os.Mkdir(pprofDir, 0750)
|
||||
f, err := ioutil.TempFile(pprofDir, "heap")
|
||||
if err != nil {
|
||||
log.Printf("error creating heap profile file: %s", err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
pprof.WriteHeapProfile(f)
|
||||
log.Printf("wrote heap profile to %q", f.Name())
|
||||
}
|
||||
|
||||
// Stop ends CPU profiling, waiting for writes to complete. If heap profiling is enabled, it also
|
||||
// writes the heap profile to a file. Stop should be deferred from main if cpu or heap profiling
|
||||
// are to be used through envpprof.
|
||||
func Stop() {
|
||||
// Should we check if CPU profiling was initiated through this package?
|
||||
pprof.StopCPUProfile()
|
||||
if heap {
|
||||
// Can or should we do this concurrently with stopping CPU profiling?
|
||||
writeHeapProfile()
|
||||
}
|
||||
}
|
||||
|
||||
func startHTTP() {
|
||||
var l net.Listener
|
||||
for port := uint16(6061); port != 6060; port++ {
|
||||
var err error
|
||||
l, err = net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if l == nil {
|
||||
log.Print("unable to create envpprof listener for http")
|
||||
return
|
||||
}
|
||||
log.Printf("(pid=%d) envpprof serving http://%s", os.Getpid(), l.Addr())
|
||||
go func() {
|
||||
defer l.Close()
|
||||
log.Printf("error serving http on envpprof listener: %s", http.Serve(l, nil))
|
||||
}()
|
||||
}
|
||||
|
||||
func init() {
|
||||
expvar.Publish("numGoroutine", expvar.Func(func() interface{} { return runtime.NumGoroutine() }))
|
||||
_var := os.Getenv("GOPPROF")
|
||||
if _var == "" {
|
||||
return
|
||||
}
|
||||
for _, item := range strings.Split(os.Getenv("GOPPROF"), ",") {
|
||||
equalsPos := strings.IndexByte(item, '=')
|
||||
var key, value string
|
||||
if equalsPos < 0 {
|
||||
key = item
|
||||
} else {
|
||||
key = item[:equalsPos]
|
||||
value = item[equalsPos+1:]
|
||||
}
|
||||
if value != "" {
|
||||
log.Printf("values not yet supported")
|
||||
}
|
||||
switch key {
|
||||
case "http":
|
||||
startHTTP()
|
||||
case "cpu":
|
||||
os.Mkdir(pprofDir, 0750)
|
||||
f, err := ioutil.TempFile(pprofDir, "cpu")
|
||||
if err != nil {
|
||||
log.Printf("error creating cpu pprof file: %s", err)
|
||||
break
|
||||
}
|
||||
err = pprof.StartCPUProfile(f)
|
||||
if err != nil {
|
||||
log.Printf("error starting cpu profiling: %s", err)
|
||||
break
|
||||
}
|
||||
log.Printf("cpu profiling to file %q", f.Name())
|
||||
case "block":
|
||||
runtime.SetBlockProfileRate(1)
|
||||
case "heap":
|
||||
heap = true
|
||||
case "mutex":
|
||||
runtime.SetMutexProfileFraction(1)
|
||||
default:
|
||||
log.Printf("unexpected GOPPROF key %q", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
6
vendor/github.com/anacrolix/go-libutp/.gitignore
generated
vendored
Normal file
6
vendor/github.com/anacrolix/go-libutp/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
tags
|
||||
*~
|
||||
_obj
|
||||
19
vendor/github.com/anacrolix/go-libutp/LICENSE
generated
vendored
Normal file
19
vendor/github.com/anacrolix/go-libutp/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
8
vendor/github.com/anacrolix/go-libutp/README.md
generated
vendored
Normal file
8
vendor/github.com/anacrolix/go-libutp/README.md
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# go-libutp
|
||||
|
||||
[](http://godoc.org/github.com/anacrolix/go-libutp)
|
||||
[](https://circleci.com/gh/anacrolix/go-libutp)
|
||||
[](https://goreportcard.com/report/github.com/anacrolix/go-libutp)
|
||||
[](https://ci.appveyor.com/project/anacrolix/go-libutp)
|
||||
|
||||
This is a Go wrapper for [libutp](https://github.com/bittorrent/libutp).
|
||||
21
vendor/github.com/anacrolix/go-libutp/appveyor.yml
generated
vendored
Normal file
21
vendor/github.com/anacrolix/go-libutp/appveyor.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
|
||||
install:
|
||||
- set PATH=%GOPATH%\bin;%PATH%
|
||||
- set PATH=C:\msys64\mingw64\bin;%PATH%
|
||||
- go get github.com/anacrolix/envpprof
|
||||
- go get github.com/anacrolix/tagflag
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get github.com/anacrolix/mmsg
|
||||
- go get golang.org/x/net/nettest
|
||||
- go get github.com/anacrolix/sync
|
||||
|
||||
build_script:
|
||||
- go build -v -x -a
|
||||
|
||||
before_test:
|
||||
- go test -v
|
||||
183
vendor/github.com/anacrolix/go-libutp/callbacks.go
generated
vendored
Normal file
183
vendor/github.com/anacrolix/go-libutp/callbacks.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#include "utp.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (a *C.utp_callback_arguments) bufBytes() []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
||||
uintptr(unsafe.Pointer(a.buf)),
|
||||
int(a.len),
|
||||
int(a.len),
|
||||
}))
|
||||
}
|
||||
|
||||
func (a *C.utp_callback_arguments) state() C.int {
|
||||
return *(*C.int)(unsafe.Pointer(&a.anon0))
|
||||
}
|
||||
|
||||
func (a *C.utp_callback_arguments) error_code() C.int {
|
||||
return *(*C.int)(unsafe.Pointer(&a.anon0))
|
||||
}
|
||||
|
||||
func (a *C.utp_callback_arguments) address() *C.struct_sockaddr {
|
||||
return *(**C.struct_sockaddr)(unsafe.Pointer(&a.anon0[0]))
|
||||
}
|
||||
|
||||
func (a *C.utp_callback_arguments) addressLen() C.socklen_t {
|
||||
return *(*C.socklen_t)(unsafe.Pointer(&a.anon1[0]))
|
||||
}
|
||||
|
||||
var sends int64
|
||||
|
||||
//export sendtoCallback
|
||||
func sendtoCallback(a *C.utp_callback_arguments) (ret C.uint64) {
|
||||
s := getSocketForLibContext(a.context)
|
||||
b := a.bufBytes()
|
||||
var sendToUdpAddr net.UDPAddr
|
||||
if err := structSockaddrToUDPAddr(a.address(), &sendToUdpAddr); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
newSends := atomic.AddInt64(&sends, 1)
|
||||
if logCallbacks {
|
||||
s.logger.Printf("sending %d bytes, %d packets", len(b), newSends)
|
||||
}
|
||||
expMap.Add("socket PacketConn writes", 1)
|
||||
n, err := s.pc.WriteTo(b, &sendToUdpAddr)
|
||||
c := s.conns[a.socket]
|
||||
if err != nil {
|
||||
expMap.Add("socket PacketConn write errors", 1)
|
||||
if c != nil && c.userOnError != nil {
|
||||
go c.userOnError(err)
|
||||
} else if c != nil &&
|
||||
(strings.Contains(err.Error(), "can't assign requested address") ||
|
||||
strings.Contains(err.Error(), "invalid argument")) {
|
||||
// Should be an bad argument or network configuration problem we
|
||||
// can't recover from.
|
||||
c.onError(err)
|
||||
} else if c != nil && strings.Contains(err.Error(), "operation not permitted") {
|
||||
// Rate-limited. Probably Linux. The implementation might try
|
||||
// again later.
|
||||
} else {
|
||||
s.logger.Printf("error sending packet: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if n != len(b) {
|
||||
expMap.Add("socket PacketConn short writes", 1)
|
||||
s.logger.Printf("expected to send %d bytes but only sent %d", len(b), n)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//export errorCallback
|
||||
func errorCallback(a *C.utp_callback_arguments) C.uint64 {
|
||||
s := getSocketForLibContext(a.context)
|
||||
err := errorForCode(a.error_code())
|
||||
if logCallbacks {
|
||||
s.logger.Printf("error callback: socket %p: %s", a.socket, err)
|
||||
}
|
||||
libContextToSocket[a.context].conns[a.socket].onError(err)
|
||||
return 0
|
||||
}
|
||||
|
||||
//export logCallback
|
||||
func logCallback(a *C.utp_callback_arguments) C.uint64 {
|
||||
s := getSocketForLibContext(a.context)
|
||||
s.logger.Printf("libutp: %s", C.GoString((*C.char)(unsafe.Pointer(a.buf))))
|
||||
return 0
|
||||
}
|
||||
|
||||
//export stateChangeCallback
|
||||
func stateChangeCallback(a *C.utp_callback_arguments) C.uint64 {
|
||||
s := libContextToSocket[a.context]
|
||||
c := s.conns[a.socket]
|
||||
if logCallbacks {
|
||||
s.logger.Printf("state changed: conn %p: %s", c, libStateName(a.state()))
|
||||
}
|
||||
switch a.state() {
|
||||
case C.UTP_STATE_CONNECT:
|
||||
c.setConnected()
|
||||
// A dialled connection will not tell the remote it's ready until it
|
||||
// writes. If the dialer has no intention of writing, this will stall
|
||||
// everything. We do an empty write to get things rolling again. This
|
||||
// circumstance occurs when c1 in the RacyRead nettest is the dialer.
|
||||
C.utp_write(a.socket, nil, 0)
|
||||
case C.UTP_STATE_WRITABLE:
|
||||
c.cond.Broadcast()
|
||||
case C.UTP_STATE_EOF:
|
||||
c.setGotEOF()
|
||||
case C.UTP_STATE_DESTROYING:
|
||||
c.onDestroyed()
|
||||
s.onLibSocketDestroyed(a.socket)
|
||||
default:
|
||||
panic(a.state)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
//export readCallback
|
||||
func readCallback(a *C.utp_callback_arguments) C.uint64 {
|
||||
s := libContextToSocket[a.context]
|
||||
c := s.conns[a.socket]
|
||||
b := a.bufBytes()
|
||||
if logCallbacks {
|
||||
s.logger.Printf("read callback: conn %p: %d bytes", c, len(b))
|
||||
}
|
||||
if len(b) == 0 {
|
||||
panic("that will break the read drain invariant")
|
||||
}
|
||||
c.readBuf.Write(b)
|
||||
c.cond.Broadcast()
|
||||
return 0
|
||||
}
|
||||
|
||||
//export acceptCallback
|
||||
func acceptCallback(a *C.utp_callback_arguments) C.uint64 {
|
||||
s := getSocketForLibContext(a.context)
|
||||
if logCallbacks {
|
||||
s.logger.Printf("accept callback: %#v", *a)
|
||||
}
|
||||
c := s.newConn(a.socket)
|
||||
c.setRemoteAddr()
|
||||
s.pushBacklog(c)
|
||||
return 0
|
||||
}
|
||||
|
||||
//export getReadBufferSizeCallback
|
||||
func getReadBufferSizeCallback(a *C.utp_callback_arguments) (ret C.uint64) {
|
||||
s := libContextToSocket[a.context]
|
||||
c := s.conns[a.socket]
|
||||
if c == nil {
|
||||
// socket hasn't been added to the Socket.conns yet. The read buffer
|
||||
// starts out empty, and the default implementation for this callback
|
||||
// returns 0, so we'll return that.
|
||||
return 0
|
||||
}
|
||||
ret = C.uint64(c.readBuf.Len())
|
||||
return
|
||||
}
|
||||
|
||||
//export firewallCallback
|
||||
func firewallCallback(a *C.utp_callback_arguments) C.uint64 {
|
||||
s := getSocketForLibContext(a.context)
|
||||
if s.syncFirewallCallback != nil {
|
||||
var addr net.UDPAddr
|
||||
structSockaddrToUDPAddr(a.address(), &addr)
|
||||
if s.syncFirewallCallback(&addr) {
|
||||
return 1
|
||||
}
|
||||
} else if s.asyncBlock {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
307
vendor/github.com/anacrolix/go-libutp/conn.go
generated
vendored
Normal file
307
vendor/github.com/anacrolix/go-libutp/conn.go
generated
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#include "utp.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrConnClosed = errors.New("closed")
|
||||
errConnDestroyed = errors.New("destroyed")
|
||||
errDeadlineExceededValue = errDeadlineExceeded{}
|
||||
)
|
||||
|
||||
type Conn struct {
|
||||
s *Socket
|
||||
us *C.utp_socket
|
||||
cond sync.Cond
|
||||
readBuf bytes.Buffer
|
||||
gotEOF bool
|
||||
gotConnect bool
|
||||
// Set on state changed to UTP_STATE_DESTROYING. Not valid to refer to the
|
||||
// socket after getting this.
|
||||
destroyed bool
|
||||
// Conn.Close was called.
|
||||
closed bool
|
||||
|
||||
err error
|
||||
|
||||
writeDeadline time.Time
|
||||
writeDeadlineTimer *time.Timer
|
||||
readDeadline time.Time
|
||||
readDeadlineTimer *time.Timer
|
||||
|
||||
numBytesRead int64
|
||||
numBytesWritten int64
|
||||
|
||||
localAddr net.Addr
|
||||
remoteAddr net.Addr
|
||||
|
||||
// Called for non-fatal errors, such as packet write errors.
|
||||
userOnError func(error)
|
||||
}
|
||||
|
||||
func (c *Conn) onError(err error) {
|
||||
c.err = err
|
||||
c.cond.Broadcast()
|
||||
}
|
||||
|
||||
func (c *Conn) setConnected() {
|
||||
c.gotConnect = true
|
||||
c.cond.Broadcast()
|
||||
}
|
||||
|
||||
func (c *Conn) waitForConnect(ctx context.Context) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
c.cond.Broadcast()
|
||||
}()
|
||||
for {
|
||||
if c.closed {
|
||||
return ErrConnClosed
|
||||
}
|
||||
if c.err != nil {
|
||||
return c.err
|
||||
}
|
||||
if c.gotConnect {
|
||||
return nil
|
||||
}
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
c.cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) Close() error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
c.close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) close() {
|
||||
if !c.destroyed && !c.closed {
|
||||
C.utp_close(c.us)
|
||||
}
|
||||
c.closed = true
|
||||
c.cond.Broadcast()
|
||||
}
|
||||
|
||||
func (c *Conn) LocalAddr() net.Addr {
|
||||
return c.localAddr
|
||||
}
|
||||
|
||||
func (c *Conn) readNoWait(b []byte) (n int, err error) {
|
||||
n, _ = c.readBuf.Read(b)
|
||||
if n != 0 && c.readBuf.Len() == 0 {
|
||||
// Can we call this if the utp_socket is closed, destroyed or errored?
|
||||
if c.us != nil {
|
||||
C.utp_read_drained(c.us)
|
||||
// C.utp_issue_deferred_acks(C.utp_get_context(c.s))
|
||||
}
|
||||
}
|
||||
if c.readBuf.Len() != 0 {
|
||||
return
|
||||
}
|
||||
err = func() error {
|
||||
switch {
|
||||
case c.gotEOF:
|
||||
return io.EOF
|
||||
case c.err != nil:
|
||||
return c.err
|
||||
case c.destroyed:
|
||||
return errConnDestroyed
|
||||
case c.closed:
|
||||
return ErrConnClosed
|
||||
case !c.readDeadline.IsZero() && !time.Now().Before(c.readDeadline):
|
||||
return errDeadlineExceededValue
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Conn) Read(b []byte) (int, error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for {
|
||||
n, err := c.readNoWait(b)
|
||||
c.numBytesRead += int64(n)
|
||||
// log.Printf("read %d bytes", c.numBytesRead)
|
||||
if n != 0 || len(b) == 0 || err != nil {
|
||||
// log.Printf("conn %p: read %d bytes: %s", c, n, err)
|
||||
return n, err
|
||||
}
|
||||
c.cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) writeNoWait(b []byte) (n int, err error) {
|
||||
err = func() error {
|
||||
switch {
|
||||
case c.err != nil:
|
||||
return c.err
|
||||
case c.closed:
|
||||
return ErrConnClosed
|
||||
case c.destroyed:
|
||||
return errConnDestroyed
|
||||
case !c.writeDeadline.IsZero() && !time.Now().Before(c.writeDeadline):
|
||||
return errDeadlineExceededValue
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n = int(C.utp_write(c.us, unsafe.Pointer(&b[0]), C.size_t(len(b))))
|
||||
if n < 0 {
|
||||
panic(n)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Conn) Write(b []byte) (n int, err error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for len(b) != 0 {
|
||||
var n1 int
|
||||
n1, err = c.writeNoWait(b)
|
||||
b = b[n1:]
|
||||
n += n1
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if n1 != 0 {
|
||||
continue
|
||||
}
|
||||
c.cond.Wait()
|
||||
}
|
||||
c.numBytesWritten += int64(n)
|
||||
// log.Printf("wrote %d bytes", c.numBytesWritten)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Conn) setRemoteAddr() {
|
||||
var rsa syscall.RawSockaddrAny
|
||||
var addrlen C.socklen_t = C.socklen_t(unsafe.Sizeof(rsa))
|
||||
C.utp_getpeername(c.us, (*C.struct_sockaddr)(unsafe.Pointer(&rsa)), &addrlen)
|
||||
var udp net.UDPAddr
|
||||
if err := anySockaddrToUdp(&rsa, &udp); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.remoteAddr = &udp
|
||||
}
|
||||
|
||||
func (c *Conn) RemoteAddr() net.Addr {
|
||||
return c.remoteAddr
|
||||
}
|
||||
|
||||
func (c *Conn) SetDeadline(t time.Time) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
c.readDeadline = t
|
||||
c.writeDeadline = t
|
||||
if t.IsZero() {
|
||||
c.readDeadlineTimer.Stop()
|
||||
c.writeDeadlineTimer.Stop()
|
||||
} else {
|
||||
d := t.Sub(time.Now())
|
||||
c.readDeadlineTimer.Reset(d)
|
||||
c.writeDeadlineTimer.Reset(d)
|
||||
}
|
||||
c.cond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
c.readDeadline = t
|
||||
if t.IsZero() {
|
||||
c.readDeadlineTimer.Stop()
|
||||
} else {
|
||||
d := t.Sub(time.Now())
|
||||
c.readDeadlineTimer.Reset(d)
|
||||
}
|
||||
c.cond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
c.writeDeadline = t
|
||||
if t.IsZero() {
|
||||
c.writeDeadlineTimer.Stop()
|
||||
} else {
|
||||
d := t.Sub(time.Now())
|
||||
c.writeDeadlineTimer.Reset(d)
|
||||
}
|
||||
c.cond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) setGotEOF() {
|
||||
c.gotEOF = true
|
||||
c.cond.Broadcast()
|
||||
}
|
||||
|
||||
func (c *Conn) onDestroyed() {
|
||||
c.destroyed = true
|
||||
c.us = nil
|
||||
c.cond.Broadcast()
|
||||
}
|
||||
|
||||
func (c *Conn) WriteBufferLen() int {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return int(C.utp_getsockopt(c.us, C.UTP_SNDBUF))
|
||||
}
|
||||
|
||||
func (c *Conn) SetWriteBufferLen(len int) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
i := C.utp_setsockopt(c.us, C.UTP_SNDBUF, C.int(len))
|
||||
if i != 0 {
|
||||
panic(i)
|
||||
}
|
||||
}
|
||||
|
||||
// utp_connect *must* be called on a created socket or it's impossible to correctly deallocate it
|
||||
// (at least through utp API?). See https://github.com/bittorrent/libutp/issues/113. This function
|
||||
// does both in a single step to prevent incorrect use. Note that accept automatically creates a
|
||||
// socket (after the firewall check) and it arrives initialized correctly.
|
||||
func utpCreateSocketAndConnect(
|
||||
ctx *C.utp_context,
|
||||
addr syscall.RawSockaddrAny,
|
||||
addrlen C.socklen_t,
|
||||
) *C.utp_socket {
|
||||
utpSock := C.utp_create_socket(ctx)
|
||||
if n := C.utp_connect(utpSock, (*C.struct_sockaddr)(unsafe.Pointer(&addr)), addrlen); n != 0 {
|
||||
panic(n)
|
||||
}
|
||||
return utpSock
|
||||
}
|
||||
|
||||
func (c *Conn) OnError(f func(error)) {
|
||||
mu.Lock()
|
||||
c.userOnError = f
|
||||
mu.Unlock()
|
||||
}
|
||||
11
vendor/github.com/anacrolix/go-libutp/deadline.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/go-libutp/deadline.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package utp
|
||||
|
||||
import "net"
|
||||
|
||||
type errDeadlineExceeded struct{}
|
||||
|
||||
var _ net.Error = errDeadlineExceeded{}
|
||||
|
||||
func (errDeadlineExceeded) Error() string { return "deadline exceeded" }
|
||||
func (errDeadlineExceeded) Temporary() bool { return false }
|
||||
func (errDeadlineExceeded) Timeout() bool { return true }
|
||||
14
vendor/github.com/anacrolix/go-libutp/expvars.go
generated
vendored
Normal file
14
vendor/github.com/anacrolix/go-libutp/expvars.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
)
|
||||
|
||||
var (
|
||||
expMap = expvar.NewMap("go-libutp")
|
||||
socketUtpPacketsReceived = expvar.NewInt("utpSocketUtpPacketsReceived")
|
||||
socketNonUtpPacketsReceived = expvar.NewInt("utpSocketNonUtpPacketsReceived")
|
||||
nonUtpPacketsDropped = expvar.NewInt("utpNonUtpPacketsDropped")
|
||||
multiMsgRecvs = expvar.NewInt("utpMultiMsgRecvs")
|
||||
singleMsgRecvs = expvar.NewInt("utpSingleMsgRecvs")
|
||||
)
|
||||
38
vendor/github.com/anacrolix/go-libutp/libapi.go
generated
vendored
Normal file
38
vendor/github.com/anacrolix/go-libutp/libapi.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#include "utp.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/anacrolix/sync"
|
||||
)
|
||||
|
||||
type Option = C.int
|
||||
|
||||
const (
|
||||
LogNormal Option = C.UTP_LOG_NORMAL
|
||||
LogMtu Option = C.UTP_LOG_MTU
|
||||
LogDebug Option = C.UTP_LOG_DEBUG
|
||||
SendBuffer Option = C.UTP_SNDBUF
|
||||
RecvBuffer Option = C.UTP_RCVBUF
|
||||
TargetDelay Option = C.UTP_TARGET_DELAY
|
||||
|
||||
TimedOut = C.UTP_ETIMEDOUT
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
libContextToSocket = map[*C.utp_context]*Socket{}
|
||||
)
|
||||
|
||||
func getSocketForLibContext(uc *C.utp_context) *Socket {
|
||||
return libContextToSocket[uc]
|
||||
}
|
||||
|
||||
func errorForCode(code C.int) error {
|
||||
return errors.New(libErrorCodeNames(code))
|
||||
}
|
||||
65
vendor/github.com/anacrolix/go-libutp/libutp-2012.vcxproj.filters
generated
vendored
Normal file
65
vendor/github.com/anacrolix/go-libutp/libutp-2012.vcxproj.filters
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="utp_templates.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_callbacks.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_hash.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_internal.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_packedsockaddr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="libutp_inet_ntop.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="utp_api.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_callbacks.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_hash.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_internal.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_packedsockaddr.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="libutp_inet_ntop.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
258
vendor/github.com/anacrolix/go-libutp/libutp.vcxproj
generated
vendored
Normal file
258
vendor/github.com/anacrolix/go-libutp/libutp.vcxproj
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="WinRTDebug|Win32">
|
||||
<Configuration>WinRTDebug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="WinRTDebug|x64">
|
||||
<Configuration>WinRTDebug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="WinRTRelease|Win32">
|
||||
<Configuration>WinRTRelease</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="WinRTRelease|x64">
|
||||
<Configuration>WinRTRelease</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="utp_templates.h" />
|
||||
<ClInclude Include="utp.h" />
|
||||
<ClInclude Include="utp_callbacks.h" />
|
||||
<ClInclude Include="utp_hash.h" />
|
||||
<ClInclude Include="utp_internal.h" />
|
||||
<ClInclude Include="utp_packedsockaddr.h" />
|
||||
<ClInclude Include="utp_utils.h" />
|
||||
<ClInclude Include="utp_types.h" />
|
||||
<ClInclude Include="libutp_inet_ntop.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="libutp_inet_ntop.cpp" />
|
||||
<ClCompile Include="utp_api.cpp" />
|
||||
<ClCompile Include="utp_callbacks.cpp" />
|
||||
<ClCompile Include="utp_hash.cpp" />
|
||||
<ClCompile Include="utp_internal.cpp" />
|
||||
<ClCompile Include="utp_packedsockaddr.cpp" />
|
||||
<ClCompile Include="utp_utils.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5984D5CD-6ADD-4EB7-82E7-A555888FBBBD}</ProjectGuid>
|
||||
<RootNamespace>libutp2012</RootNamespace>
|
||||
<ProjectName>libutp</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\win32-2012.props" />
|
||||
<Import Project="prop_sheets\debug-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\win32-2012.props" />
|
||||
<Import Project="prop_sheets\debug-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\x64-2012.props" />
|
||||
<Import Project="prop_sheets\debug-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\x64-2012.props" />
|
||||
<Import Project="prop_sheets\debug-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\win32-2012.props" />
|
||||
<Import Project="prop_sheets\release-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\win32-2012.props" />
|
||||
<Import Project="prop_sheets\release-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\x64-2012.props" />
|
||||
<Import Project="prop_sheets\release-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\x64-2012.props" />
|
||||
<Import Project="prop_sheets\release-2012.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x501;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
68
vendor/github.com/anacrolix/go-libutp/libutp_inet_ntop.h
generated
vendored
Normal file
68
vendor/github.com/anacrolix/go-libutp/libutp_inet_ntop.h
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef LIBUTP_INET_NTOP_H
|
||||
#define LIBUTP_INET_NTOP_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// About us linking the system inet_pton and inet_ntop symbols:
|
||||
// 1) These symbols are usually defined on POSIX systems
|
||||
// 2) They are not defined on Windows versions earlier than Vista
|
||||
// Defined in:
|
||||
// ut_utils/src/sockaddr.cpp
|
||||
// libutp/win32_inet_ntop.obj
|
||||
//
|
||||
// When we drop support for XP we can just #include <ws2tcpip.h>, and use the system functions
|
||||
// For now, we will always use our functions on windows, on all builds
|
||||
// The reason is: we would like the debug build to behave as much as the release build as possible
|
||||
// It is much better to catch a problem in the debug build, than to link the system version
|
||||
// in debug, and our version int he wild.
|
||||
|
||||
#if defined(_WIN32_WINNT)
|
||||
#if _WIN32_WINNT >= 0x600 // Win32, post-XP
|
||||
#include <ws2tcpip.h> // for inet_ntop, inet_pton
|
||||
#define INET_NTOP inet_ntop
|
||||
#define INET_PTON inet_pton
|
||||
#else
|
||||
#define INET_NTOP libutp::inet_ntop // Win32, pre-XP: Use ours
|
||||
#define INET_PTON libutp::inet_pton
|
||||
#endif
|
||||
#else // not WIN32
|
||||
#include <arpa/inet.h> // for inet_ntop, inet_pton
|
||||
#define INET_NTOP inet_ntop
|
||||
#define INET_PTON inet_pton
|
||||
#endif
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
namespace libutp {
|
||||
|
||||
|
||||
//######################################################################
|
||||
const char *inet_ntop(int af, const void *src, char *dest, size_t length);
|
||||
|
||||
//######################################################################
|
||||
int inet_pton(int af, const char* src, void* dest);
|
||||
|
||||
|
||||
} //namespace libutp
|
||||
|
||||
#endif // LIBUTP_INET_NTOP_H
|
||||
11
vendor/github.com/anacrolix/go-libutp/logging.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/go-libutp/logging.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package utp
|
||||
|
||||
import "github.com/anacrolix/log"
|
||||
|
||||
const (
|
||||
logCallbacks = false
|
||||
utpLogging = false
|
||||
)
|
||||
|
||||
// The default Socket Logger. Override per Socket by using WithLogger with NewSocket.
|
||||
var Logger = log.Default.WithContextText("go-libutp")
|
||||
288
vendor/github.com/anacrolix/go-libutp/parse_log.py
generated
vendored
Normal file
288
vendor/github.com/anacrolix/go-libutp/parse_log.py
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
import os, sys, time
|
||||
|
||||
# usage: parse_log.py log-file [socket-index to focus on]
|
||||
|
||||
|
||||
socket_filter = None
|
||||
if len(sys.argv) >= 3:
|
||||
socket_filter = sys.argv[2].strip()
|
||||
|
||||
if socket_filter == None:
|
||||
print "scanning for socket with the most packets"
|
||||
file = open(sys.argv[1], 'rb')
|
||||
|
||||
sockets = {}
|
||||
|
||||
for l in file:
|
||||
if not 'our_delay' in l: continue
|
||||
|
||||
try:
|
||||
a = l.strip().split(" ")
|
||||
socket_index = a[1][:-1]
|
||||
except:
|
||||
continue
|
||||
|
||||
# msvc's runtime library doesn't prefix pointers
|
||||
# with '0x'
|
||||
# if socket_index[:2] != '0x':
|
||||
# continue
|
||||
|
||||
if socket_index in sockets:
|
||||
sockets[socket_index] += 1
|
||||
else:
|
||||
sockets[socket_index] = 1
|
||||
|
||||
items = sockets.items()
|
||||
items.sort(lambda x, y: y[1] - x[1])
|
||||
|
||||
count = 0
|
||||
for i in items:
|
||||
print '%s: %d' % (i[0], i[1])
|
||||
count += 1
|
||||
if count > 5: break
|
||||
|
||||
file.close()
|
||||
socket_filter = items[0][0]
|
||||
print '\nfocusing on socket %s' % socket_filter
|
||||
|
||||
file = open(sys.argv[1], 'rb')
|
||||
out_file = 'utp.out%s' % socket_filter;
|
||||
out = open(out_file, 'wb')
|
||||
|
||||
delay_samples = 'dots lc rgb "blue"'
|
||||
delay_base = 'steps lw 2 lc rgb "purple"'
|
||||
target_delay = 'steps lw 2 lc rgb "red"'
|
||||
off_target = 'dots lc rgb "blue"'
|
||||
cwnd = 'steps lc rgb "green"'
|
||||
window_size = 'steps lc rgb "sea-green"'
|
||||
rtt = 'lines lc rgb "light-blue"'
|
||||
|
||||
metrics = {
|
||||
'our_delay':['our delay (ms)', 'x1y2', delay_samples],
|
||||
'upload_rate':['send rate (B/s)', 'x1y1', 'lines'],
|
||||
'max_window':['cwnd (B)', 'x1y1', cwnd],
|
||||
'target_delay':['target delay (ms)', 'x1y2', target_delay],
|
||||
'cur_window':['bytes in-flight (B)', 'x1y1', window_size],
|
||||
'cur_window_packets':['number of packets in-flight', 'x1y2', 'steps'],
|
||||
'packet_size':['current packet size (B)', 'x1y2', 'steps'],
|
||||
'rtt':['rtt (ms)', 'x1y2', rtt],
|
||||
'off_target':['off-target (ms)', 'x1y2', off_target],
|
||||
'delay_sum':['delay sum (ms)', 'x1y2', 'steps'],
|
||||
'their_delay':['their delay (ms)', 'x1y2', delay_samples],
|
||||
'get_microseconds':['clock (us)', 'x1y1', 'steps'],
|
||||
'wnduser':['advertised window size (B)', 'x1y1', 'steps'],
|
||||
|
||||
'delay_base':['delay base (us)', 'x1y1', delay_base],
|
||||
'their_delay_base':['their delay base (us)', 'x1y1', delay_base],
|
||||
'their_actual_delay':['their actual delay (us)', 'x1y1', delay_samples],
|
||||
'actual_delay':['actual_delay (us)', 'x1y1', delay_samples]
|
||||
}
|
||||
|
||||
histogram_quantization = 1
|
||||
socket_index = None
|
||||
|
||||
columns = []
|
||||
|
||||
begin = None
|
||||
|
||||
title = "-"
|
||||
packet_loss = 0
|
||||
packet_timeout = 0
|
||||
|
||||
delay_histogram = {}
|
||||
window_size = {'0': 0, '1': 0}
|
||||
|
||||
# [35301484] 0x00ec1190: actual_delay:1021583 our_delay:102 their_delay:-1021345 off_target:297 max_window:2687 upload_rate:18942 delay_base:1021481154 delay_sum:-1021242 target_delay:400 acked_bytes:1441 cur_window:2882 scaled_gain:2.432
|
||||
|
||||
counter = 0
|
||||
|
||||
print "reading log file"
|
||||
|
||||
for l in file:
|
||||
if "UTP_Connect" in l:
|
||||
title = l[:-2]
|
||||
if socket_filter != None:
|
||||
title += ' socket: %s' % socket_filter
|
||||
else:
|
||||
title += ' sum of all sockets'
|
||||
continue
|
||||
|
||||
try:
|
||||
a = l.strip().split(" ")
|
||||
t = a[0][1:-1]
|
||||
socket_index = a[1][:-1]
|
||||
except:
|
||||
continue
|
||||
# if socket_index[:2] != '0x':
|
||||
# continue
|
||||
|
||||
if socket_filter != None and socket_index != socket_filter:
|
||||
continue
|
||||
|
||||
counter += 1
|
||||
if (counter % 300 == 0):
|
||||
print "\r%d " % counter,
|
||||
|
||||
if "lost." in l:
|
||||
packet_loss = packet_loss + 1
|
||||
continue
|
||||
if "Packet timeout" in l:
|
||||
packet_timeout = packet_timeout + 1
|
||||
continue
|
||||
if "our_delay:" not in l:
|
||||
continue
|
||||
|
||||
# used for Logf timestamps
|
||||
# t, m = t.split(".")
|
||||
# t = time.strptime(t, "%H:%M:%S")
|
||||
# t = list(t)
|
||||
# t[0] += 107
|
||||
# t = tuple(t)
|
||||
# m = float(m)
|
||||
# m /= 1000.0
|
||||
# t = time.mktime(t) + m
|
||||
|
||||
# used for tick count timestamps
|
||||
t = int(t)
|
||||
|
||||
if begin is None:
|
||||
begin = t
|
||||
t = t - begin
|
||||
# print time. Convert from milliseconds to seconds
|
||||
print >>out, '%f\t' % (float(t)/1000.),
|
||||
|
||||
#if t > 200000:
|
||||
# break
|
||||
|
||||
fill_columns = not columns
|
||||
for i in a[2:]:
|
||||
try:
|
||||
n, v = i.split(':')
|
||||
except:
|
||||
continue
|
||||
v = float(v)
|
||||
if n == "our_delay":
|
||||
bucket = v / histogram_quantization
|
||||
delay_histogram[bucket] = 1 + delay_histogram.get(bucket, 0)
|
||||
if not n in metrics: continue
|
||||
if fill_columns:
|
||||
columns.append(n)
|
||||
if n == "max_window":
|
||||
window_size[socket_index] = v
|
||||
print >>out, '%f\t' % int(reduce(lambda a,b: a+b, window_size.values())),
|
||||
else:
|
||||
print >>out, '%f\t' % v,
|
||||
print >>out, float(packet_loss * 8000), float(packet_timeout * 8000)
|
||||
packet_loss = 0
|
||||
packet_timeout = 0
|
||||
|
||||
out.close()
|
||||
|
||||
out = open('%s.histogram' % out_file, 'wb')
|
||||
for d,f in delay_histogram.iteritems():
|
||||
print >>out, float(d*histogram_quantization) + histogram_quantization / 2, f
|
||||
out.close()
|
||||
|
||||
|
||||
plot = [
|
||||
{
|
||||
'data': ['upload_rate', 'max_window', 'cur_window', 'wnduser', 'cur_window_packets', 'packet_size', 'rtt'],
|
||||
'title': 'send-packet-size',
|
||||
'y1': 'Bytes',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['our_delay', 'max_window', 'target_delay', 'cur_window', 'wnduser', 'cur_window_packets'],
|
||||
'title': 'uploading',
|
||||
'y1': 'Bytes',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['our_delay', 'max_window', 'target_delay', 'cur_window', 'cur_window_packets'],
|
||||
'title': 'uploading_packets',
|
||||
'y1': 'Bytes',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['get_microseconds'],
|
||||
'title': 'timer',
|
||||
'y1': 'Time microseconds',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['their_delay', 'target_delay', 'rtt'],
|
||||
'title': 'their_delay',
|
||||
'y1': '',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['their_actual_delay','their_delay_base'],
|
||||
'title': 'their_delay_base',
|
||||
'y1': 'Time (us)',
|
||||
'y2': ''
|
||||
},
|
||||
{
|
||||
'data': ['our_delay', 'target_delay', 'rtt'],
|
||||
'title': 'our-delay',
|
||||
'y1': '',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['actual_delay', 'delay_base'],
|
||||
'title': 'our_delay_base',
|
||||
'y1': 'Time (us)',
|
||||
'y2': ''
|
||||
}
|
||||
]
|
||||
|
||||
out = open('utp.gnuplot', 'w+')
|
||||
|
||||
files = ''
|
||||
|
||||
#print >>out, 'set xtics 0, 20'
|
||||
print >>out, "set term png size 1280,800"
|
||||
print >>out, 'set output "%s.delays.png"' % out_file
|
||||
print >>out, 'set xrange [0:250]'
|
||||
print >>out, 'set xlabel "delay (ms)"'
|
||||
print >>out, 'set boxwidth 1'
|
||||
print >>out, 'set style fill solid'
|
||||
print >>out, 'set ylabel "number of packets"'
|
||||
print >>out, 'plot "%s.histogram" using 1:2 with boxes' % out_file
|
||||
|
||||
print >>out, "set style data steps"
|
||||
#print >>out, "set yrange [0:*]"
|
||||
print >>out, "set y2range [*:*]"
|
||||
files += out_file + '.delays.png '
|
||||
#set hidden3d
|
||||
#set title "Peer bandwidth distribution"
|
||||
#set xlabel "Ratio"
|
||||
|
||||
for p in plot:
|
||||
print >>out, 'set title "%s %s"' % (p['title'], title)
|
||||
print >>out, 'set xlabel "time (s)"'
|
||||
print >>out, 'set ylabel "%s"' % p['y1']
|
||||
print >>out, "set tics nomirror"
|
||||
print >>out, 'set y2tics'
|
||||
print >>out, 'set y2label "%s"' % p['y2']
|
||||
print >>out, 'set xrange [0:*]'
|
||||
print >>out, "set key box"
|
||||
print >>out, "set term png size 1280,800"
|
||||
print >>out, 'set output "%s-%s.png"' % (out_file, p['title'])
|
||||
files += '%s-%s.png ' % (out_file, p['title'])
|
||||
|
||||
comma = ''
|
||||
print >>out, "plot",
|
||||
|
||||
for c in p['data']:
|
||||
if not c in metrics: continue
|
||||
i = columns.index(c)
|
||||
print >>out, '%s"%s" using 1:%d title "%s-%s" axes %s with %s' % (comma, out_file, i + 2, metrics[c][0], metrics[c][1], metrics[c][1], metrics[c][2]),
|
||||
comma = ', '
|
||||
print >>out, ''
|
||||
|
||||
out.close()
|
||||
|
||||
os.system("gnuplot utp.gnuplot")
|
||||
|
||||
os.system("open %s" % files)
|
||||
|
||||
95
vendor/github.com/anacrolix/go-libutp/sockaddr.go
generated
vendored
Normal file
95
vendor/github.com/anacrolix/go-libutp/sockaddr.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#include "utp.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/anacrolix/missinggo/inproc"
|
||||
)
|
||||
|
||||
func toSockaddrInet(ip net.IP, port int, zone string) (rsa syscall.RawSockaddrAny, len C.socklen_t) {
|
||||
if ip4 := ip.To4(); ip4 != nil && zone == "" {
|
||||
rsa4 := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&rsa))
|
||||
rsa4.Family = syscall.AF_INET
|
||||
rsa4.Port = uint16(port)
|
||||
if n := copy(rsa4.Addr[:], ip4); n != 4 {
|
||||
panic(n)
|
||||
}
|
||||
len = C.socklen_t(unsafe.Sizeof(*rsa4))
|
||||
return
|
||||
}
|
||||
rsa6 := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&rsa))
|
||||
rsa6.Family = syscall.AF_INET6
|
||||
rsa6.Scope_id = zoneToScopeId(zone)
|
||||
rsa6.Port = uint16(port)
|
||||
if ip != nil {
|
||||
if n := copy(rsa6.Addr[:], ip); n != 16 {
|
||||
panic(n)
|
||||
}
|
||||
}
|
||||
len = C.socklen_t(unsafe.Sizeof(*rsa6))
|
||||
return
|
||||
}
|
||||
|
||||
func zoneToScopeId(zone string) uint32 {
|
||||
if zone == "" {
|
||||
return 0
|
||||
}
|
||||
if ifi, err := net.InterfaceByName(zone); err == nil {
|
||||
return uint32(ifi.Index)
|
||||
}
|
||||
ui64, _ := strconv.ParseUint(zone, 10, 32)
|
||||
return uint32(ui64)
|
||||
}
|
||||
|
||||
func structSockaddrToUDPAddr(sa *C.struct_sockaddr, udp *net.UDPAddr) error {
|
||||
return anySockaddrToUdp((*syscall.RawSockaddrAny)(unsafe.Pointer(sa)), udp)
|
||||
}
|
||||
|
||||
func anySockaddrToUdp(rsa *syscall.RawSockaddrAny, udp *net.UDPAddr) error {
|
||||
switch rsa.Addr.Family {
|
||||
case syscall.AF_INET:
|
||||
sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||||
udp.Port = int(sa.Port)
|
||||
udp.IP = append(udp.IP[:0], sa.Addr[:]...)
|
||||
return nil
|
||||
case syscall.AF_INET6:
|
||||
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
|
||||
udp.Port = int(sa.Port)
|
||||
udp.IP = append(udp.IP[:0], sa.Addr[:]...)
|
||||
return nil
|
||||
default:
|
||||
return syscall.EAFNOSUPPORT
|
||||
}
|
||||
}
|
||||
|
||||
func sockaddrToUDP(sa syscall.Sockaddr) net.Addr {
|
||||
switch sa := sa.(type) {
|
||||
case *syscall.SockaddrInet4:
|
||||
return &net.UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
|
||||
case *syscall.SockaddrInet6:
|
||||
return &net.UDPAddr{IP: sa.Addr[0:], Port: sa.Port /*Zone: zoneToString(int(sa.ZoneId))*/}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func netAddrToLibSockaddr(na net.Addr) (rsa syscall.RawSockaddrAny, len C.socklen_t) {
|
||||
switch v := na.(type) {
|
||||
case *net.UDPAddr:
|
||||
return toSockaddrInet(v.IP, v.Port, v.Zone)
|
||||
case inproc.Addr:
|
||||
rsa6 := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&rsa))
|
||||
rsa6.Port = uint16(v.Port)
|
||||
len = C.socklen_t(unsafe.Sizeof(rsa))
|
||||
return
|
||||
default:
|
||||
panic(na)
|
||||
}
|
||||
}
|
||||
542
vendor/github.com/anacrolix/go-libutp/socket.go
generated
vendored
Normal file
542
vendor/github.com/anacrolix/go-libutp/socket.go
generated
vendored
Normal file
@@ -0,0 +1,542 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#include "utp.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
struct utp_process_udp_args {
|
||||
const byte *buf;
|
||||
size_t len;
|
||||
const struct sockaddr *sa;
|
||||
socklen_t sal;
|
||||
};
|
||||
|
||||
void process_received_messages(utp_context *ctx, struct utp_process_udp_args *args, size_t argslen)
|
||||
{
|
||||
bool gotUtp = false;
|
||||
size_t i;
|
||||
for (i = 0; i < argslen; i++) {
|
||||
struct utp_process_udp_args *a = &args[i];
|
||||
//if (!a->len) continue;
|
||||
if (utp_process_udp(ctx, a->buf, a->len, a->sa, a->sal)) {
|
||||
gotUtp = true;
|
||||
}
|
||||
}
|
||||
if (gotUtp) {
|
||||
utp_issue_deferred_acks(ctx);
|
||||
utp_check_timeouts(ctx);
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/anacrolix/log"
|
||||
"github.com/anacrolix/missinggo"
|
||||
"github.com/anacrolix/missinggo/inproc"
|
||||
"github.com/anacrolix/mmsg"
|
||||
)
|
||||
|
||||
const (
|
||||
utpCheckTimeoutInterval = 500 * time.Millisecond
|
||||
issueDeferredUtpAcksDelay = 1000 * time.Microsecond
|
||||
)
|
||||
|
||||
type Socket struct {
|
||||
pc net.PacketConn
|
||||
ctx *C.utp_context
|
||||
backlog chan *Conn
|
||||
closed bool
|
||||
conns map[*C.utp_socket]*Conn
|
||||
nonUtpReads chan packet
|
||||
writeDeadline time.Time
|
||||
readDeadline time.Time
|
||||
|
||||
// This is called without the package mutex, without knowing if the result will be needed.
|
||||
asyncFirewallCallback FirewallCallback
|
||||
// Whether the next accept is to be blocked.
|
||||
asyncBlock bool
|
||||
|
||||
// This is called with the package mutex, and preferred.
|
||||
syncFirewallCallback FirewallCallback
|
||||
|
||||
acksScheduled bool
|
||||
ackTimer *time.Timer
|
||||
|
||||
utpTimeoutChecker *time.Timer
|
||||
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// A firewall callback returns true if an incoming connection request should be ignored. This is
|
||||
// better than just accepting and closing, as it means no acknowledgement packet is sent.
|
||||
type FirewallCallback func(net.Addr) bool
|
||||
|
||||
var (
|
||||
_ net.PacketConn = (*Socket)(nil)
|
||||
_ net.Listener = (*Socket)(nil)
|
||||
errSocketClosed = errors.New("Socket closed")
|
||||
)
|
||||
|
||||
type packet struct {
|
||||
b []byte
|
||||
from net.Addr
|
||||
}
|
||||
|
||||
func listenPacket(network, addr string) (pc net.PacketConn, err error) {
|
||||
if network == "inproc" {
|
||||
return inproc.ListenPacket(network, addr)
|
||||
}
|
||||
return net.ListenPacket(network, addr)
|
||||
}
|
||||
|
||||
type NewSocketOpt func(s *Socket)
|
||||
|
||||
func WithLogger(l log.Logger) NewSocketOpt {
|
||||
return func(s *Socket) {
|
||||
s.logger = l
|
||||
}
|
||||
}
|
||||
|
||||
func NewSocket(network, addr string, opts ...NewSocketOpt) (*Socket, error) {
|
||||
pc, err := listenPacket(network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &Socket{
|
||||
pc: pc,
|
||||
backlog: make(chan *Conn, 5),
|
||||
conns: make(map[*C.utp_socket]*Conn),
|
||||
nonUtpReads: make(chan packet, 100),
|
||||
logger: Logger,
|
||||
}
|
||||
s.ackTimer = time.AfterFunc(math.MaxInt64, s.ackTimerFunc)
|
||||
s.ackTimer.Stop()
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
|
||||
func() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
ctx := C.utp_init(2)
|
||||
if ctx == nil {
|
||||
panic(ctx)
|
||||
}
|
||||
s.ctx = ctx
|
||||
ctx.setCallbacks()
|
||||
if utpLogging {
|
||||
ctx.setOption(C.UTP_LOG_NORMAL, 1)
|
||||
ctx.setOption(C.UTP_LOG_MTU, 1)
|
||||
ctx.setOption(C.UTP_LOG_DEBUG, 1)
|
||||
}
|
||||
libContextToSocket[ctx] = s
|
||||
s.utpTimeoutChecker = time.AfterFunc(0, s.timeoutCheckerTimerFunc)
|
||||
}()
|
||||
go s.packetReader()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Socket) onLibSocketDestroyed(ls *C.utp_socket) {
|
||||
delete(s.conns, ls)
|
||||
}
|
||||
|
||||
func (s *Socket) newConn(us *C.utp_socket) *Conn {
|
||||
c := &Conn{
|
||||
s: s,
|
||||
us: us,
|
||||
localAddr: s.pc.LocalAddr(),
|
||||
}
|
||||
c.cond.L = &mu
|
||||
s.conns[us] = c
|
||||
c.writeDeadlineTimer = time.AfterFunc(-1, c.cond.Broadcast)
|
||||
c.readDeadlineTimer = time.AfterFunc(-1, c.cond.Broadcast)
|
||||
return c
|
||||
}
|
||||
|
||||
const maxNumBuffers = 16
|
||||
|
||||
func (s *Socket) packetReader() {
|
||||
mc := mmsg.NewConn(s.pc)
|
||||
// Increasing the messages increases the memory use, but also means we can
|
||||
// reduces utp_issue_deferred_acks and syscalls which should improve
|
||||
// efficiency. On the flip side, not all OSs implement batched reads.
|
||||
ms := make([]mmsg.Message, func() int {
|
||||
if mc.Err() == nil {
|
||||
return maxNumBuffers
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}())
|
||||
for i := range ms {
|
||||
// The IPv4 UDP limit is allegedly about 64 KiB, and this message has
|
||||
// been seen on receiving on Windows with just 0x1000: wsarecvfrom: A
|
||||
// message sent on a datagram socket was larger than the internal
|
||||
// message buffer or some other network limit, or the buffer used to
|
||||
// receive a datagram into was smaller than the datagram itself.
|
||||
ms[i].Buffers = [][]byte{make([]byte, 0x10000)}
|
||||
}
|
||||
// Some crap OSs like Windoze will raise errors in Reads that don't
|
||||
// actually mean we should stop.
|
||||
consecutiveErrors := 0
|
||||
for {
|
||||
// In C, all the reads are processed and when it threatens to block,
|
||||
// we're supposed to call utp_issue_deferred_acks.
|
||||
n, err := mc.RecvMsgs(ms)
|
||||
if n == 1 {
|
||||
singleMsgRecvs.Add(1)
|
||||
}
|
||||
if n > 1 {
|
||||
multiMsgRecvs.Add(1)
|
||||
}
|
||||
if err != nil {
|
||||
mu.Lock()
|
||||
closed := s.closed
|
||||
mu.Unlock()
|
||||
if closed {
|
||||
// We don't care.
|
||||
return
|
||||
}
|
||||
// See https://github.com/anacrolix/torrent/issues/83. If we get
|
||||
// an endless stream of errors (such as the PacketConn being
|
||||
// Closed outside of our control, this work around may need to be
|
||||
// reconsidered.
|
||||
s.logger.Printf("ignoring socket read error: %s", err)
|
||||
consecutiveErrors++
|
||||
if consecutiveErrors >= 100 {
|
||||
s.logger.Print("too many consecutive errors, closing socket")
|
||||
s.Close()
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
consecutiveErrors = 0
|
||||
expMap.Add("successful mmsg receive calls", 1)
|
||||
expMap.Add("received messages", int64(n))
|
||||
s.processReceivedMessages(ms[:n])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Socket) processReceivedMessages(ms []mmsg.Message) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if s.closed {
|
||||
return
|
||||
}
|
||||
if processPacketsInC {
|
||||
var args [maxNumBuffers]C.struct_utp_process_udp_args
|
||||
for i, m := range ms {
|
||||
a := &args[i]
|
||||
a.buf = (*C.byte)(&m.Buffers[0][0])
|
||||
a.len = C.size_t(m.N)
|
||||
var rsa syscall.RawSockaddrAny
|
||||
rsa, a.sal = netAddrToLibSockaddr(m.Addr)
|
||||
a.sa = (*C.struct_sockaddr)(unsafe.Pointer(&rsa))
|
||||
}
|
||||
C.process_received_messages(s.ctx, &args[0], C.size_t(len(ms)))
|
||||
} else {
|
||||
gotUtp := false
|
||||
for _, m := range ms {
|
||||
gotUtp = s.processReceivedMessage(m.Buffers[0][:m.N], m.Addr) || gotUtp
|
||||
}
|
||||
if gotUtp && !s.closed {
|
||||
s.afterReceivingUtpMessages()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Socket) afterReceivingUtpMessages() {
|
||||
if s.acksScheduled {
|
||||
return
|
||||
}
|
||||
s.ackTimer.Reset(issueDeferredUtpAcksDelay)
|
||||
s.acksScheduled = true
|
||||
}
|
||||
|
||||
func (s *Socket) issueDeferredAcks() {
|
||||
expMap.Add("utp_issue_deferred_acks calls", 1)
|
||||
C.utp_issue_deferred_acks(s.ctx)
|
||||
}
|
||||
|
||||
func (s *Socket) checkUtpTimeouts() {
|
||||
expMap.Add("utp_check_timeouts calls", 1)
|
||||
C.utp_check_timeouts(s.ctx)
|
||||
}
|
||||
|
||||
func (s *Socket) ackTimerFunc() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if !s.acksScheduled || s.ctx == nil {
|
||||
return
|
||||
}
|
||||
s.acksScheduled = false
|
||||
s.issueDeferredAcks()
|
||||
}
|
||||
|
||||
func (s *Socket) processReceivedMessage(b []byte, addr net.Addr) (utp bool) {
|
||||
if s.utpProcessUdp(b, addr) {
|
||||
socketUtpPacketsReceived.Add(1)
|
||||
return true
|
||||
} else {
|
||||
s.onReadNonUtp(b, addr)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Process packet batches entirely from C, reducing CGO overhead. Currently
|
||||
// requires GODEBUG=cgocheck=0.
|
||||
const processPacketsInC = false
|
||||
|
||||
var staticRsa syscall.RawSockaddrAny
|
||||
|
||||
// Wraps libutp's utp_process_udp, returning relevant information.
|
||||
func (s *Socket) utpProcessUdp(b []byte, addr net.Addr) (utp bool) {
|
||||
if len(b) == 0 {
|
||||
// The implementation of utp_process_udp rejects null buffers, and
|
||||
// anything smaller than the UTP header size. It's also prone to
|
||||
// assert on those, which we don't want to trigger.
|
||||
return false
|
||||
}
|
||||
if missinggo.AddrPort(addr) == 0 {
|
||||
return false
|
||||
}
|
||||
mu.Unlock()
|
||||
// TODO: If it's okay to call the firewall callback without the package lock, aren't we assuming
|
||||
// that the next UDP packet to be processed by libutp has to be the one we've just used the
|
||||
// callback for? Why can't we assign directly to Socket.asyncBlock?
|
||||
asyncBlock := func() bool {
|
||||
if s.asyncFirewallCallback == nil || s.syncFirewallCallback != nil {
|
||||
return false
|
||||
}
|
||||
return s.asyncFirewallCallback(addr)
|
||||
}()
|
||||
mu.Lock()
|
||||
s.asyncBlock = asyncBlock
|
||||
if s.closed {
|
||||
return false
|
||||
}
|
||||
var sal C.socklen_t
|
||||
staticRsa, sal = netAddrToLibSockaddr(addr)
|
||||
ret := C.utp_process_udp(s.ctx, (*C.byte)(&b[0]), C.size_t(len(b)), (*C.struct_sockaddr)(unsafe.Pointer(&staticRsa)), sal)
|
||||
switch ret {
|
||||
case 1:
|
||||
return true
|
||||
case 0:
|
||||
return false
|
||||
default:
|
||||
panic(ret)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Socket) timeoutCheckerTimerFunc() {
|
||||
mu.Lock()
|
||||
ok := s.ctx != nil
|
||||
if ok {
|
||||
s.checkUtpTimeouts()
|
||||
}
|
||||
if ok {
|
||||
s.utpTimeoutChecker.Reset(utpCheckTimeoutInterval)
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *Socket) Close() error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return s.closeLocked()
|
||||
}
|
||||
|
||||
func (s *Socket) closeLocked() error {
|
||||
if s.closed {
|
||||
return nil
|
||||
}
|
||||
// Calling this deletes the pointer. It must not be referred to after
|
||||
// this.
|
||||
C.utp_destroy(s.ctx)
|
||||
s.ctx = nil
|
||||
s.pc.Close()
|
||||
close(s.backlog)
|
||||
close(s.nonUtpReads)
|
||||
s.closed = true
|
||||
s.ackTimer.Stop()
|
||||
s.utpTimeoutChecker.Stop()
|
||||
s.acksScheduled = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Socket) Addr() net.Addr {
|
||||
return s.pc.LocalAddr()
|
||||
}
|
||||
|
||||
func (s *Socket) LocalAddr() net.Addr {
|
||||
return s.pc.LocalAddr()
|
||||
}
|
||||
|
||||
func (s *Socket) Accept() (net.Conn, error) {
|
||||
nc, ok := <-s.backlog
|
||||
if !ok {
|
||||
return nil, errors.New("closed")
|
||||
}
|
||||
return nc, nil
|
||||
}
|
||||
|
||||
func (s *Socket) Dial(addr string) (net.Conn, error) {
|
||||
return s.DialTimeout(addr, 0)
|
||||
}
|
||||
|
||||
func (s *Socket) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
ctx := context.Background()
|
||||
if timeout != 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
}
|
||||
return s.DialContext(ctx, "", addr)
|
||||
}
|
||||
|
||||
func (s *Socket) resolveAddr(network, addr string) (net.Addr, error) {
|
||||
if network == "" {
|
||||
network = s.Addr().Network()
|
||||
}
|
||||
return resolveAddr(network, addr)
|
||||
}
|
||||
|
||||
func resolveAddr(network, addr string) (net.Addr, error) {
|
||||
switch network {
|
||||
case "inproc":
|
||||
return inproc.ResolveAddr(network, addr)
|
||||
default:
|
||||
return net.ResolveUDPAddr(network, addr)
|
||||
}
|
||||
}
|
||||
|
||||
// Passing an empty network will use the network of the Socket's listener.
|
||||
func (s *Socket) DialContext(ctx context.Context, network, addr string) (_ net.Conn, err error) {
|
||||
if network == "" {
|
||||
network = s.pc.LocalAddr().Network()
|
||||
}
|
||||
ua, err := resolveAddr(network, addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error resolving address: %v", err)
|
||||
}
|
||||
sa, sl := netAddrToLibSockaddr(ua)
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if s.closed {
|
||||
return nil, errSocketClosed
|
||||
}
|
||||
utpSock := utpCreateSocketAndConnect(s.ctx, sa, sl)
|
||||
c := s.newConn(utpSock)
|
||||
c.setRemoteAddr()
|
||||
err = c.waitForConnect(ctx)
|
||||
if err != nil {
|
||||
c.close()
|
||||
return
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (s *Socket) pushBacklog(c *Conn) {
|
||||
select {
|
||||
case s.backlog <- c:
|
||||
default:
|
||||
c.close()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Socket) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
p, ok := <-s.nonUtpReads
|
||||
if !ok {
|
||||
err = errors.New("closed")
|
||||
return
|
||||
}
|
||||
n = copy(b, p.b)
|
||||
addr = p.from
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Socket) onReadNonUtp(b []byte, from net.Addr) {
|
||||
if s.closed {
|
||||
return
|
||||
}
|
||||
socketNonUtpPacketsReceived.Add(1)
|
||||
select {
|
||||
case s.nonUtpReads <- packet{append([]byte(nil), b...), from}:
|
||||
default:
|
||||
// log.Printf("dropped non utp packet: no room in buffer")
|
||||
nonUtpPacketsDropped.Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Socket) SetReadDeadline(t time.Time) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (s *Socket) SetWriteDeadline(t time.Time) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (s *Socket) SetDeadline(t time.Time) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (s *Socket) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
return s.pc.WriteTo(b, addr)
|
||||
}
|
||||
|
||||
func (s *Socket) ReadBufferLen() int {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return int(C.utp_context_get_option(s.ctx, C.UTP_RCVBUF))
|
||||
}
|
||||
|
||||
func (s *Socket) WriteBufferLen() int {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return int(C.utp_context_get_option(s.ctx, C.UTP_SNDBUF))
|
||||
}
|
||||
|
||||
func (s *Socket) SetWriteBufferLen(len int) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
i := C.utp_context_set_option(s.ctx, C.UTP_SNDBUF, C.int(len))
|
||||
if i != 0 {
|
||||
panic(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Socket) SetOption(opt Option, val int) int {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return int(C.utp_context_set_option(s.ctx, opt, C.int(val)))
|
||||
}
|
||||
|
||||
// The callback is used before each packet is processed by libutp without the this package's mutex
|
||||
// being held. libutp may not actually need the result as the packet might not be a connection
|
||||
// attempt. If the callback function is expensive, it may be worth setting a synchronous callback
|
||||
// using SetSyncFirewallCallback.
|
||||
func (s *Socket) SetFirewallCallback(f FirewallCallback) {
|
||||
mu.Lock()
|
||||
s.asyncFirewallCallback = f
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
// SetSyncFirewallCallback sets a synchronous firewall callback. It's only called as needed by
|
||||
// libutp. It is called with the package-wide mutex held. Any locks acquired by the callback should
|
||||
// not also be held by code that might use this package.
|
||||
func (s *Socket) SetSyncFirewallCallback(f FirewallCallback) {
|
||||
mu.Lock()
|
||||
s.syncFirewallCallback = f
|
||||
mu.Unlock()
|
||||
}
|
||||
17
vendor/github.com/anacrolix/go-libutp/status.go
generated
vendored
Normal file
17
vendor/github.com/anacrolix/go-libutp/status.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func WriteStatus(w io.Writer) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, s := range libContextToSocket {
|
||||
fmt.Fprintf(w, "listening at %s\n", s.Addr())
|
||||
fmt.Fprintf(w, "has %d conns\n", len(s.conns))
|
||||
fmt.Fprintf(w, "backlog: %d\n", len(s.backlog))
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
}
|
||||
50
vendor/github.com/anacrolix/go-libutp/utp.go
generated
vendored
Normal file
50
vendor/github.com/anacrolix/go-libutp/utp.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#cgo CPPFLAGS: -DPOSIX -DUTP_DEBUG_LOGGING=0
|
||||
#cgo CFLAGS: -Wall -O3
|
||||
// These are all copied from the libutp Makefile.
|
||||
#cgo CXXFLAGS: -Wall -O3 -fPIC -Wno-sign-compare
|
||||
// There are some variables that aren't used unless UTP_DEBUG_LOGGING is defined.
|
||||
#cgo CXXFLAGS: -Wno-unused-const-variable
|
||||
// Windows additional flags
|
||||
#cgo windows LDFLAGS: -lws2_32
|
||||
#cgo windows CXXFLAGS: -D_WIN32_WINNT=0x600
|
||||
#include "utp.h"
|
||||
|
||||
uint64_t firewallCallback(utp_callback_arguments *);
|
||||
uint64_t errorCallback(utp_callback_arguments *);
|
||||
uint64_t logCallback(utp_callback_arguments *);
|
||||
uint64_t acceptCallback(utp_callback_arguments *);
|
||||
uint64_t sendtoCallback(utp_callback_arguments *);
|
||||
uint64_t stateChangeCallback(utp_callback_arguments *);
|
||||
uint64_t readCallback(utp_callback_arguments *);
|
||||
uint64_t getReadBufferSizeCallback(utp_callback_arguments *);
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
type socklen C.socklen_t
|
||||
|
||||
func (ctx *C.utp_context) setCallbacks() {
|
||||
C.utp_set_callback(ctx, C.UTP_ON_FIREWALL, (*C.utp_callback_t)(C.firewallCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_LOG, (*C.utp_callback_t)(C.logCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_ON_ACCEPT, (*C.utp_callback_t)(C.acceptCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_SENDTO, (*C.utp_callback_t)(C.sendtoCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_ON_STATE_CHANGE, (*C.utp_callback_t)(C.stateChangeCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_ON_READ, (*C.utp_callback_t)(C.readCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_ON_ERROR, (*C.utp_callback_t)(C.errorCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_GET_READ_BUFFER_SIZE, (*C.utp_callback_t)(C.getReadBufferSizeCallback))
|
||||
}
|
||||
|
||||
func (ctx *C.utp_context) setOption(opt Option, val int) int {
|
||||
return int(C.utp_context_set_option(ctx, opt, C.int(val)))
|
||||
}
|
||||
|
||||
func libStateName(state C.int) string {
|
||||
return C.GoString((*[5]*C.char)(unsafe.Pointer(&C.utp_state_names))[state])
|
||||
}
|
||||
|
||||
func libErrorCodeNames(error_code C.int) string {
|
||||
return C.GoString((*[3]*C.char)(unsafe.Pointer(&C.utp_error_code_names))[error_code])
|
||||
}
|
||||
187
vendor/github.com/anacrolix/go-libutp/utp.h
generated
vendored
Normal file
187
vendor/github.com/anacrolix/go-libutp/utp.h
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_H__
|
||||
#define __UTP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "utp_types.h"
|
||||
|
||||
typedef struct UTPSocket utp_socket;
|
||||
typedef struct struct_utp_context utp_context;
|
||||
|
||||
enum {
|
||||
UTP_UDP_DONTFRAG = 2, // Used to be a #define as UDP_IP_DONTFRAG
|
||||
};
|
||||
|
||||
enum {
|
||||
// socket has reveived syn-ack (notification only for outgoing connection completion)
|
||||
// this implies writability
|
||||
UTP_STATE_CONNECT = 1,
|
||||
|
||||
// socket is able to send more data
|
||||
UTP_STATE_WRITABLE = 2,
|
||||
|
||||
// connection closed
|
||||
UTP_STATE_EOF = 3,
|
||||
|
||||
// socket is being destroyed, meaning all data has been sent if possible.
|
||||
// it is not valid to refer to the socket after this state change occurs
|
||||
UTP_STATE_DESTROYING = 4,
|
||||
};
|
||||
|
||||
extern const char *utp_state_names[];
|
||||
|
||||
// Errors codes that can be passed to UTP_ON_ERROR callback
|
||||
enum {
|
||||
UTP_ECONNREFUSED = 0,
|
||||
UTP_ECONNRESET,
|
||||
UTP_ETIMEDOUT,
|
||||
};
|
||||
|
||||
extern const char *utp_error_code_names[];
|
||||
|
||||
enum {
|
||||
// callback names
|
||||
UTP_ON_FIREWALL = 0,
|
||||
UTP_ON_ACCEPT,
|
||||
UTP_ON_CONNECT,
|
||||
UTP_ON_ERROR,
|
||||
UTP_ON_READ,
|
||||
UTP_ON_OVERHEAD_STATISTICS,
|
||||
UTP_ON_STATE_CHANGE,
|
||||
UTP_GET_READ_BUFFER_SIZE,
|
||||
UTP_ON_DELAY_SAMPLE,
|
||||
UTP_GET_UDP_MTU,
|
||||
UTP_GET_UDP_OVERHEAD,
|
||||
UTP_GET_MILLISECONDS,
|
||||
UTP_GET_MICROSECONDS,
|
||||
UTP_GET_RANDOM,
|
||||
UTP_LOG,
|
||||
UTP_SENDTO,
|
||||
|
||||
// context and socket options that may be set/queried
|
||||
UTP_LOG_NORMAL,
|
||||
UTP_LOG_MTU,
|
||||
UTP_LOG_DEBUG,
|
||||
UTP_SNDBUF,
|
||||
UTP_RCVBUF,
|
||||
UTP_TARGET_DELAY,
|
||||
|
||||
UTP_ARRAY_SIZE, // must be last
|
||||
};
|
||||
|
||||
extern const char *utp_callback_names[];
|
||||
|
||||
typedef struct {
|
||||
utp_context *context;
|
||||
utp_socket *socket;
|
||||
size_t len;
|
||||
uint32 flags;
|
||||
int callback_type;
|
||||
const byte *buf;
|
||||
|
||||
union {
|
||||
const struct sockaddr *address;
|
||||
int send;
|
||||
int sample_ms;
|
||||
int error_code;
|
||||
int state;
|
||||
};
|
||||
|
||||
union {
|
||||
socklen_t address_len;
|
||||
int type;
|
||||
};
|
||||
} utp_callback_arguments;
|
||||
|
||||
typedef uint64 utp_callback_t(utp_callback_arguments *);
|
||||
|
||||
// Returned by utp_get_context_stats()
|
||||
typedef struct {
|
||||
uint32 _nraw_recv[5]; // total packets recieved less than 300/600/1200/MTU bytes fpr all connections (context-wide)
|
||||
uint32 _nraw_send[5]; // total packets sent less than 300/600/1200/MTU bytes for all connections (context-wide)
|
||||
} utp_context_stats;
|
||||
|
||||
// Returned by utp_get_stats()
|
||||
typedef struct {
|
||||
uint64 nbytes_recv; // total bytes received
|
||||
uint64 nbytes_xmit; // total bytes transmitted
|
||||
uint32 rexmit; // retransmit counter
|
||||
uint32 fastrexmit; // fast retransmit counter
|
||||
uint32 nxmit; // transmit counter
|
||||
uint32 nrecv; // receive counter (total)
|
||||
uint32 nduprecv; // duplicate receive counter
|
||||
uint32 mtu_guess; // Best guess at MTU
|
||||
} utp_socket_stats;
|
||||
|
||||
#define UTP_IOV_MAX 1024
|
||||
|
||||
// For utp_writev, to writes data from multiple buffers
|
||||
struct utp_iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
// Public Functions
|
||||
utp_context* utp_init (int version);
|
||||
void utp_destroy (utp_context *ctx);
|
||||
void utp_set_callback (utp_context *ctx, int callback_name, utp_callback_t *proc);
|
||||
void* utp_context_set_userdata (utp_context *ctx, void *userdata);
|
||||
void* utp_context_get_userdata (utp_context *ctx);
|
||||
int utp_context_set_option (utp_context *ctx, int opt, int val);
|
||||
int utp_context_get_option (utp_context *ctx, int opt);
|
||||
int utp_process_udp (utp_context *ctx, const byte *buf, size_t len, const struct sockaddr *to, socklen_t tolen);
|
||||
int utp_process_icmp_error (utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
|
||||
int utp_process_icmp_fragmentation (utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen, uint16 next_hop_mtu);
|
||||
void utp_check_timeouts (utp_context *ctx);
|
||||
void utp_issue_deferred_acks (utp_context *ctx);
|
||||
utp_context_stats* utp_get_context_stats (utp_context *ctx);
|
||||
utp_socket* utp_create_socket (utp_context *ctx);
|
||||
void* utp_set_userdata (utp_socket *s, void *userdata);
|
||||
void* utp_get_userdata (utp_socket *s);
|
||||
int utp_setsockopt (utp_socket *s, int opt, int val);
|
||||
int utp_getsockopt (utp_socket *s, int opt);
|
||||
int utp_connect (utp_socket *s, const struct sockaddr *to, socklen_t tolen);
|
||||
ssize_t utp_write (utp_socket *s, void *buf, size_t count);
|
||||
ssize_t utp_writev (utp_socket *s, struct utp_iovec *iovec, size_t num_iovecs);
|
||||
int utp_getpeername (utp_socket *s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
void utp_read_drained (utp_socket *s);
|
||||
int utp_get_delays (utp_socket *s, uint32 *ours, uint32 *theirs, uint32 *age);
|
||||
utp_socket_stats* utp_get_stats (utp_socket *s);
|
||||
utp_context* utp_get_context (utp_socket *s);
|
||||
void utp_shutdown (utp_socket *s, int how);
|
||||
void utp_close (utp_socket *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__UTP_H__
|
||||
139
vendor/github.com/anacrolix/go-libutp/utp_api.cpp
generated
vendored
Normal file
139
vendor/github.com/anacrolix/go-libutp/utp_api.cpp
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "utp_internal.h"
|
||||
#include "utp_utils.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
const char * utp_callback_names[] = {
|
||||
"UTP_ON_FIREWALL",
|
||||
"UTP_ON_ACCEPT",
|
||||
"UTP_ON_CONNECT",
|
||||
"UTP_ON_ERROR",
|
||||
"UTP_ON_READ",
|
||||
"UTP_ON_OVERHEAD_STATISTICS",
|
||||
"UTP_ON_STATE_CHANGE",
|
||||
"UTP_GET_READ_BUFFER_SIZE",
|
||||
"UTP_ON_DELAY_SAMPLE",
|
||||
"UTP_GET_UDP_MTU",
|
||||
"UTP_GET_UDP_OVERHEAD",
|
||||
"UTP_GET_MILLISECONDS",
|
||||
"UTP_GET_MICROSECONDS",
|
||||
"UTP_GET_RANDOM",
|
||||
"UTP_LOG",
|
||||
"UTP_SENDTO",
|
||||
};
|
||||
|
||||
const char * utp_error_code_names[] = {
|
||||
"UTP_ECONNREFUSED",
|
||||
"UTP_ECONNRESET",
|
||||
"UTP_ETIMEDOUT",
|
||||
};
|
||||
|
||||
const char *utp_state_names[] = {
|
||||
NULL,
|
||||
"UTP_STATE_CONNECT",
|
||||
"UTP_STATE_WRITABLE",
|
||||
"UTP_STATE_EOF",
|
||||
"UTP_STATE_DESTROYING",
|
||||
};
|
||||
|
||||
struct_utp_context::struct_utp_context()
|
||||
: userdata(NULL)
|
||||
, current_ms(0)
|
||||
, last_utp_socket(NULL)
|
||||
, log_normal(false)
|
||||
, log_mtu(false)
|
||||
, log_debug(false)
|
||||
{
|
||||
memset(&context_stats, 0, sizeof(context_stats));
|
||||
memset(callbacks, 0, sizeof(callbacks));
|
||||
target_delay = CCONTROL_TARGET;
|
||||
utp_sockets = new UTPSocketHT;
|
||||
|
||||
callbacks[UTP_GET_UDP_MTU] = &utp_default_get_udp_mtu;
|
||||
callbacks[UTP_GET_UDP_OVERHEAD] = &utp_default_get_udp_overhead;
|
||||
callbacks[UTP_GET_MILLISECONDS] = &utp_default_get_milliseconds;
|
||||
callbacks[UTP_GET_MICROSECONDS] = &utp_default_get_microseconds;
|
||||
callbacks[UTP_GET_RANDOM] = &utp_default_get_random;
|
||||
|
||||
// 1 MB of receive buffer (i.e. max bandwidth delay product)
|
||||
// means that from a peer with 200 ms RTT, we cannot receive
|
||||
// faster than 5 MB/s
|
||||
// from a peer with 10 ms RTT, we cannot receive faster than
|
||||
// 100 MB/s. This is assumed to be good enough, since bandwidth
|
||||
// often is proportional to RTT anyway
|
||||
// when setting a download rate limit, all sockets should have
|
||||
// their receive buffer set much lower, to say 60 kiB or so
|
||||
opt_rcvbuf = opt_sndbuf = 1024 * 1024;
|
||||
last_check = 0;
|
||||
}
|
||||
|
||||
struct_utp_context::~struct_utp_context() {
|
||||
delete this->utp_sockets;
|
||||
}
|
||||
|
||||
utp_context* utp_init (int version)
|
||||
{
|
||||
assert(version == 2);
|
||||
if (version != 2)
|
||||
return NULL;
|
||||
utp_context *ctx = new utp_context;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void utp_destroy(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
if (ctx) delete ctx;
|
||||
}
|
||||
|
||||
void utp_set_callback(utp_context *ctx, int callback_name, utp_callback_t *proc) {
|
||||
assert(ctx);
|
||||
if (ctx) ctx->callbacks[callback_name] = proc;
|
||||
}
|
||||
|
||||
void* utp_context_set_userdata(utp_context *ctx, void *userdata) {
|
||||
assert(ctx);
|
||||
if (ctx) ctx->userdata = userdata;
|
||||
return ctx ? ctx->userdata : NULL;
|
||||
}
|
||||
|
||||
void* utp_context_get_userdata(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
return ctx ? ctx->userdata : NULL;
|
||||
}
|
||||
|
||||
utp_context_stats* utp_get_context_stats(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
return ctx ? &ctx->context_stats : NULL;
|
||||
}
|
||||
|
||||
ssize_t utp_write(utp_socket *socket, void *buf, size_t len) {
|
||||
struct utp_iovec iovec = { buf, len };
|
||||
return utp_writev(socket, &iovec, 1);
|
||||
}
|
||||
|
||||
}
|
||||
208
vendor/github.com/anacrolix/go-libutp/utp_callbacks.cpp
generated
vendored
Normal file
208
vendor/github.com/anacrolix/go-libutp/utp_callbacks.cpp
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "utp_callbacks.h"
|
||||
|
||||
int utp_call_on_firewall(utp_context *ctx, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_FIREWALL]) return 0;
|
||||
args.callback_type = UTP_ON_FIREWALL;
|
||||
args.context = ctx;
|
||||
args.socket = NULL;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (int)ctx->callbacks[UTP_ON_FIREWALL](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_accept(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_ACCEPT]) return;
|
||||
args.callback_type = UTP_ON_ACCEPT;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
ctx->callbacks[UTP_ON_ACCEPT](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_connect(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_CONNECT]) return;
|
||||
args.callback_type = UTP_ON_CONNECT;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
ctx->callbacks[UTP_ON_CONNECT](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_error(utp_context *ctx, utp_socket *socket, int error_code)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_ERROR]) return;
|
||||
args.callback_type = UTP_ON_ERROR;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.error_code = error_code;
|
||||
ctx->callbacks[UTP_ON_ERROR](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_read(utp_context *ctx, utp_socket *socket, const byte *buf, size_t len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_READ]) return;
|
||||
args.callback_type = UTP_ON_READ;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
args.len = len;
|
||||
ctx->callbacks[UTP_ON_READ](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_overhead_statistics(utp_context *ctx, utp_socket *socket, int send, size_t len, int type)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS]) return;
|
||||
args.callback_type = UTP_ON_OVERHEAD_STATISTICS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.send = send;
|
||||
args.len = len;
|
||||
args.type = type;
|
||||
ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_delay_sample(utp_context *ctx, utp_socket *socket, int sample_ms)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_DELAY_SAMPLE]) return;
|
||||
args.callback_type = UTP_ON_DELAY_SAMPLE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.sample_ms = sample_ms;
|
||||
ctx->callbacks[UTP_ON_DELAY_SAMPLE](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_state_change(utp_context *ctx, utp_socket *socket, int state)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_STATE_CHANGE]) return;
|
||||
args.callback_type = UTP_ON_STATE_CHANGE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.state = state;
|
||||
ctx->callbacks[UTP_ON_STATE_CHANGE](&args);
|
||||
}
|
||||
|
||||
uint16 utp_call_get_udp_mtu(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_UDP_MTU]) return 0;
|
||||
args.callback_type = UTP_GET_UDP_MTU;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (uint16)ctx->callbacks[UTP_GET_UDP_MTU](&args);
|
||||
}
|
||||
|
||||
uint16 utp_call_get_udp_overhead(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_UDP_OVERHEAD]) return 0;
|
||||
args.callback_type = UTP_GET_UDP_OVERHEAD;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (uint16)ctx->callbacks[UTP_GET_UDP_OVERHEAD](&args);
|
||||
}
|
||||
|
||||
uint64 utp_call_get_milliseconds(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_MILLISECONDS]) return 0;
|
||||
args.callback_type = UTP_GET_MILLISECONDS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return ctx->callbacks[UTP_GET_MILLISECONDS](&args);
|
||||
}
|
||||
|
||||
uint64 utp_call_get_microseconds(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_MICROSECONDS]) return 0;
|
||||
args.callback_type = UTP_GET_MICROSECONDS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return ctx->callbacks[UTP_GET_MICROSECONDS](&args);
|
||||
}
|
||||
|
||||
uint32 utp_call_get_random(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_RANDOM]) return 0;
|
||||
args.callback_type = UTP_GET_RANDOM;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return (uint32)ctx->callbacks[UTP_GET_RANDOM](&args);
|
||||
}
|
||||
|
||||
size_t utp_call_get_read_buffer_size(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_READ_BUFFER_SIZE]) return 0;
|
||||
args.callback_type = UTP_GET_READ_BUFFER_SIZE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return (size_t)ctx->callbacks[UTP_GET_READ_BUFFER_SIZE](&args);
|
||||
}
|
||||
|
||||
void utp_call_log(utp_context *ctx, utp_socket *socket, const byte *buf)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_LOG]) return;
|
||||
args.callback_type = UTP_LOG;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
ctx->callbacks[UTP_LOG](&args);
|
||||
}
|
||||
|
||||
void utp_call_sendto(utp_context *ctx, utp_socket *socket, const byte *buf, size_t len, const struct sockaddr *address, socklen_t address_len, uint32 flags)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_SENDTO]) return;
|
||||
args.callback_type = UTP_SENDTO;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
args.len = len;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
args.flags = flags;
|
||||
ctx->callbacks[UTP_SENDTO](&args);
|
||||
}
|
||||
|
||||
47
vendor/github.com/anacrolix/go-libutp/utp_callbacks.h
generated
vendored
Normal file
47
vendor/github.com/anacrolix/go-libutp/utp_callbacks.h
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_CALLBACKS_H__
|
||||
#define __UTP_CALLBACKS_H__
|
||||
|
||||
#include "utp.h"
|
||||
#include "utp_internal.h"
|
||||
|
||||
// Generated by running: grep ^[a-z] utp_callbacks.cpp | sed 's/$/;/'
|
||||
int utp_call_on_firewall(utp_context *ctx, const struct sockaddr *address, socklen_t address_len);
|
||||
void utp_call_on_accept(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
void utp_call_on_connect(utp_context *ctx, utp_socket *s);
|
||||
void utp_call_on_error(utp_context *ctx, utp_socket *s, int error_code);
|
||||
void utp_call_on_read(utp_context *ctx, utp_socket *s, const byte *buf, size_t len);
|
||||
void utp_call_on_overhead_statistics(utp_context *ctx, utp_socket *s, int send, size_t len, int type);
|
||||
void utp_call_on_delay_sample(utp_context *ctx, utp_socket *s, int sample_ms);
|
||||
void utp_call_on_state_change(utp_context *ctx, utp_socket *s, int state);
|
||||
uint16 utp_call_get_udp_mtu(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
uint16 utp_call_get_udp_overhead(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
uint64 utp_call_get_milliseconds(utp_context *ctx, utp_socket *s);
|
||||
uint64 utp_call_get_microseconds(utp_context *ctx, utp_socket *s);
|
||||
uint32 utp_call_get_random(utp_context *ctx, utp_socket *s);
|
||||
size_t utp_call_get_read_buffer_size(utp_context *ctx, utp_socket *s);
|
||||
void utp_call_log(utp_context *ctx, utp_socket *s, const byte *buf);
|
||||
void utp_call_sendto(utp_context *ctx, utp_socket *s, const byte *buf, size_t len, const struct sockaddr *address, socklen_t address_len, uint32 flags);
|
||||
|
||||
#endif // __UTP_CALLBACKS_H__
|
||||
246
vendor/github.com/anacrolix/go-libutp/utp_hash.cpp
generated
vendored
Normal file
246
vendor/github.com/anacrolix/go-libutp/utp_hash.cpp
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "utp_hash.h"
|
||||
#include "utp_types.h"
|
||||
|
||||
#define LIBUTP_HASH_UNUSED ((utp_link_t)-1)
|
||||
|
||||
#ifdef STRICT_ALIGN
|
||||
inline uint32 Read32(const void *p)
|
||||
{
|
||||
uint32 tmp;
|
||||
memcpy(&tmp, p, sizeof tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#else
|
||||
inline uint32 Read32(const void *p) { return *(uint32*)p; }
|
||||
#endif
|
||||
|
||||
|
||||
// Get the amount of memory required for the hash parameters and the bucket set
|
||||
// Waste a space for an unused bucket in order to ensure the following managed memory have 32-bit aligned addresses
|
||||
// TODO: make this 64-bit clean
|
||||
#define BASE_SIZE(bc) (sizeof(utp_hash_t) + sizeof(utp_link_t) * ((bc) + 1))
|
||||
|
||||
// Get a pointer to the base of the structure array managed by the hash table
|
||||
#define get_bep(h) ((byte*)(h)) + BASE_SIZE((h)->N)
|
||||
|
||||
// Get the address of the information associated with a specific structure in the array,
|
||||
// given the address of the base of the structure.
|
||||
// This assumes a utp_link_t link member is at the end of the structure.
|
||||
// Given compilers filling out the memory to a 32-bit clean value, this may mean that
|
||||
// the location named in the structure may not be the location actually used by the hash table,
|
||||
// since the compiler may have padded the end of the structure with 2 bytes after the utp_link_t member.
|
||||
// TODO: this macro should not require that the variable pointing at the hash table be named 'hash'
|
||||
#define ptr_to_link(p) (utp_link_t *) (((byte *) (p)) + hash->E - sizeof(utp_link_t))
|
||||
|
||||
// Calculate how much to allocate for a hash table with bucket count, total size, and structure count
|
||||
// TODO: make this 64-bit clean
|
||||
#define ALLOCATION_SIZE(bc, ts, sc) (BASE_SIZE((bc)) + (ts) * (sc))
|
||||
|
||||
utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun, utp_hash_equal_t compfun)
|
||||
{
|
||||
// Must have odd number of hash buckets (prime number is best)
|
||||
assert(N % 2);
|
||||
// Ensure structures will be at aligned memory addresses
|
||||
// TODO: make this 64-bit clean
|
||||
assert(0 == (total_size % 4));
|
||||
|
||||
int size = ALLOCATION_SIZE(N, total_size, initial);
|
||||
utp_hash_t *hash = (utp_hash_t *) malloc( size );
|
||||
memset( hash, 0, size );
|
||||
|
||||
for (int i = 0; i < N + 1; ++i)
|
||||
hash->inits[i] = LIBUTP_HASH_UNUSED;
|
||||
hash->N = N;
|
||||
hash->K = key_size;
|
||||
hash->E = total_size;
|
||||
hash->hash_compute = hashfun;
|
||||
hash->hash_equal = compfun;
|
||||
hash->allocated = initial;
|
||||
hash->count = 0;
|
||||
hash->used = 0;
|
||||
hash->free = LIBUTP_HASH_UNUSED;
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint utp_hash_mem(const void *keyp, size_t keysize)
|
||||
{
|
||||
uint hash = 0;
|
||||
uint n = keysize;
|
||||
while (n >= 4) {
|
||||
hash ^= Read32(keyp);
|
||||
keyp = (byte*)keyp + sizeof(uint32);
|
||||
hash = (hash << 13) | (hash >> 19);
|
||||
n -= 4;
|
||||
}
|
||||
while (n != 0) {
|
||||
hash ^= *(byte*)keyp;
|
||||
keyp = (byte*)keyp + sizeof(byte);
|
||||
hash = (hash << 8) | (hash >> 24);
|
||||
n--;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint utp_hash_mkidx(utp_hash_t *hash, const void *keyp)
|
||||
{
|
||||
// Generate a key from the hash
|
||||
return hash->hash_compute(keyp, hash->K) % hash->N;
|
||||
}
|
||||
|
||||
static inline bool compare(byte *a, byte *b,int n)
|
||||
{
|
||||
assert(n >= 4);
|
||||
if (Read32(a) != Read32(b)) return false;
|
||||
return memcmp(a+4, b+4, n-4) == 0;
|
||||
}
|
||||
|
||||
#define COMPARE(h,k1,k2,ks) (((h)->hash_equal) ? (h)->hash_equal((void*)k1,(void*)k2,ks) : compare(k1,k2,ks))
|
||||
|
||||
// Look-up a key in the hash table.
|
||||
// Returns NULL if not found
|
||||
void *utp_hash_lookup(utp_hash_t *hash, const void *key)
|
||||
{
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
// base pointer
|
||||
byte *bep = get_bep(hash);
|
||||
|
||||
utp_link_t cur = hash->inits[idx];
|
||||
while (cur != LIBUTP_HASH_UNUSED) {
|
||||
byte *key2 = bep + (cur * hash->E);
|
||||
if (COMPARE(hash, (byte*)key, key2, hash->K))
|
||||
return key2;
|
||||
cur = *ptr_to_link(key2);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add a new element to the hash table.
|
||||
// Returns a pointer to the new element.
|
||||
// This assumes the element is not already present!
|
||||
void *utp_hash_add(utp_hash_t **hashp, const void *key)
|
||||
{
|
||||
//Allocate a new entry
|
||||
byte *elemp;
|
||||
utp_link_t elem;
|
||||
utp_hash_t *hash = *hashp;
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
if ((elem=hash->free) == LIBUTP_HASH_UNUSED) {
|
||||
utp_link_t all = hash->allocated;
|
||||
if (hash->used == all) {
|
||||
utp_hash_t *nhash;
|
||||
if (all <= (LIBUTP_HASH_UNUSED/2)) {
|
||||
all *= 2;
|
||||
} else if (all != LIBUTP_HASH_UNUSED) {
|
||||
all = LIBUTP_HASH_UNUSED;
|
||||
} else {
|
||||
// too many items! can't grow!
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
// otherwise need to allocate.
|
||||
nhash = (utp_hash_t*)realloc(hash, ALLOCATION_SIZE(hash->N, hash->E, all));
|
||||
if (!nhash) {
|
||||
// out of memory (or too big to allocate)
|
||||
assert(nhash);
|
||||
return NULL;
|
||||
}
|
||||
hash = *hashp = nhash;
|
||||
hash->allocated = all;
|
||||
}
|
||||
|
||||
elem = hash->used++;
|
||||
elemp = get_bep(hash) + elem * hash->E;
|
||||
} else {
|
||||
elemp = get_bep(hash) + elem * hash->E;
|
||||
hash->free = *ptr_to_link(elemp);
|
||||
}
|
||||
|
||||
*ptr_to_link(elemp) = hash->inits[idx];
|
||||
hash->inits[idx] = elem;
|
||||
hash->count++;
|
||||
|
||||
// copy key into it
|
||||
memcpy(elemp, key, hash->K);
|
||||
return elemp;
|
||||
}
|
||||
|
||||
// Delete an element from the utp_hash_t
|
||||
// Returns a pointer to the already deleted element.
|
||||
void *utp_hash_del(utp_hash_t *hash, const void *key)
|
||||
{
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
// base pointer
|
||||
byte *bep = get_bep(hash);
|
||||
|
||||
utp_link_t *curp = &hash->inits[idx];
|
||||
utp_link_t cur;
|
||||
while ((cur=*curp) != LIBUTP_HASH_UNUSED) {
|
||||
byte *key2 = bep + (cur * hash->E);
|
||||
if (COMPARE(hash,(byte*)key,(byte*)key2, hash->K )) {
|
||||
// found an item that matched. unlink it
|
||||
*curp = *ptr_to_link(key2);
|
||||
// Insert into freelist
|
||||
*ptr_to_link(key2) = hash->free;
|
||||
hash->free = cur;
|
||||
hash->count--;
|
||||
return key2;
|
||||
}
|
||||
curp = ptr_to_link(key2);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter)
|
||||
{
|
||||
utp_link_t elem;
|
||||
|
||||
if ((elem=iter->elem) == LIBUTP_HASH_UNUSED) {
|
||||
// Find a bucket with an element
|
||||
utp_link_t buck = iter->bucket + 1;
|
||||
for(;;) {
|
||||
if (buck >= hash->N)
|
||||
return NULL;
|
||||
if ((elem = hash->inits[buck]) != LIBUTP_HASH_UNUSED)
|
||||
break;
|
||||
buck++;
|
||||
}
|
||||
iter->bucket = buck;
|
||||
}
|
||||
|
||||
byte *elemp = get_bep(hash) + (elem * hash->E);
|
||||
iter->elem = *ptr_to_link(elemp);
|
||||
return elemp;
|
||||
}
|
||||
|
||||
void utp_hash_free_mem(utp_hash_t* hash)
|
||||
{
|
||||
free(hash);
|
||||
}
|
||||
146
vendor/github.com/anacrolix/go-libutp/utp_hash.h
generated
vendored
Normal file
146
vendor/github.com/anacrolix/go-libutp/utp_hash.h
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_HASH_H__
|
||||
#define __UTP_HASH_H__
|
||||
|
||||
#include <string.h> // memset
|
||||
#include <stdlib.h> // malloc
|
||||
|
||||
#include "utp_types.h"
|
||||
#include "utp_templates.h"
|
||||
|
||||
// TODO: make utp_link_t a template parameter to HashTable
|
||||
typedef uint32 utp_link_t;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Silence the warning about the C99-compliant zero-length array at the end of the structure
|
||||
#pragma warning (disable: 4200)
|
||||
#endif
|
||||
|
||||
typedef uint32 (*utp_hash_compute_t)(const void *keyp, size_t keysize);
|
||||
typedef uint (*utp_hash_equal_t)(const void *key_a, const void *key_b, size_t keysize);
|
||||
|
||||
// In memory the HashTable is laid out as follows:
|
||||
// ---------------------------- low
|
||||
// | hash table data members |
|
||||
// ---------------------------- _
|
||||
// | indices | ^
|
||||
// | . | | utp_link_t indices into the key-values.
|
||||
// | . | .
|
||||
// ---------------------------- - <----- bep
|
||||
// | keys and values | each key-value pair has size total_size
|
||||
// | . |
|
||||
// | . |
|
||||
// ---------------------------- high
|
||||
//
|
||||
// The code depends on the ability of the compiler to pad the length
|
||||
// of the hash table data members structure to
|
||||
// a length divisible by 32-bits with no remainder.
|
||||
//
|
||||
// Since the number of hash buckets (indices) should be odd, the code
|
||||
// asserts this and adds one to the hash bucket count to ensure that the
|
||||
// following key-value pairs array starts on a 32-bit boundary.
|
||||
//
|
||||
// The key-value pairs array should start on a 32-bit boundary, otherwise
|
||||
// processors like the ARM will silently mangle 32-bit data in these structures
|
||||
// (e.g., turning 0xABCD into 0XCDAB when moving a value from memory to register
|
||||
// when the memory address is 16 bits offset from a 32-bit boundary),
|
||||
// also, the value will be stored at an address two bytes lower than the address
|
||||
// value would ordinarily indicate.
|
||||
//
|
||||
// The key-value pair is of type T. The first field in T must
|
||||
// be the key, i.e., the first K bytes of T contains the key.
|
||||
// total_size = sizeof(T) and thus sizeof(T) >= sizeof(K)
|
||||
//
|
||||
// N is the number of buckets.
|
||||
//
|
||||
struct utp_hash_t {
|
||||
utp_link_t N;
|
||||
byte K;
|
||||
byte E;
|
||||
size_t count;
|
||||
utp_hash_compute_t hash_compute;
|
||||
utp_hash_equal_t hash_equal;
|
||||
utp_link_t allocated;
|
||||
utp_link_t used;
|
||||
utp_link_t free;
|
||||
utp_link_t inits[0];
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (default: 4200)
|
||||
#endif
|
||||
|
||||
struct utp_hash_iterator_t {
|
||||
utp_link_t bucket;
|
||||
utp_link_t elem;
|
||||
|
||||
utp_hash_iterator_t() : bucket(0xffffffff), elem(0xffffffff) {}
|
||||
};
|
||||
|
||||
uint utp_hash_mem(const void *keyp, size_t keysize);
|
||||
uint utp_hash_comp(const void *key_a, const void *key_b, size_t keysize);
|
||||
|
||||
utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun = utp_hash_mem, utp_hash_equal_t eqfun = NULL);
|
||||
void *utp_hash_lookup(utp_hash_t *hash, const void *key);
|
||||
void *utp_hash_add(utp_hash_t **hashp, const void *key);
|
||||
void *utp_hash_del(utp_hash_t *hash, const void *key);
|
||||
|
||||
void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter);
|
||||
void utp_hash_free_mem(utp_hash_t *hash);
|
||||
|
||||
/*
|
||||
This HashTable requires that T have at least sizeof(K)+sizeof(utp_link_t) bytes.
|
||||
Usually done like this:
|
||||
|
||||
struct K {
|
||||
int whatever;
|
||||
};
|
||||
|
||||
struct T {
|
||||
K wtf;
|
||||
utp_link_t link; // also wtf
|
||||
};
|
||||
*/
|
||||
|
||||
template<typename K, typename T> class utpHashTable {
|
||||
utp_hash_t *hash;
|
||||
public:
|
||||
static uint compare(const void *k1, const void *k2, size_t ks) {
|
||||
return *((K*)k1) == *((K*)k2);
|
||||
}
|
||||
static uint32 compute_hash(const void *k, size_t ks) {
|
||||
return ((K*)k)->compute_hash();
|
||||
}
|
||||
void Init() { hash = NULL; }
|
||||
bool Allocated() { return (hash != NULL); }
|
||||
void Free() { utp_hash_free_mem(hash); hash = NULL; }
|
||||
void Create(int N, int initial) { hash = utp_hash_create(N, sizeof(K), sizeof(T), initial, &compute_hash, &compare); }
|
||||
T *Lookup(const K &key) { return (T*)utp_hash_lookup(hash, &key); }
|
||||
T *Add(const K &key) { return (T*)utp_hash_add(&hash, &key); }
|
||||
T *Delete(const K &key) { return (T*)utp_hash_del(hash, &key); }
|
||||
T *Iterate(utp_hash_iterator_t &iterator) { return (T*)utp_hash_iterate(hash, &iterator); }
|
||||
size_t GetCount() { return hash->count; }
|
||||
};
|
||||
|
||||
#endif //__UTP_HASH_H__
|
||||
3489
vendor/github.com/anacrolix/go-libutp/utp_internal.cpp
generated
vendored
Normal file
3489
vendor/github.com/anacrolix/go-libutp/utp_internal.cpp
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
141
vendor/github.com/anacrolix/go-libutp/utp_internal.h
generated
vendored
Normal file
141
vendor/github.com/anacrolix/go-libutp/utp_internal.h
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_INTERNAL_H__
|
||||
#define __UTP_INTERNAL_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utp.h"
|
||||
#include "utp_callbacks.h"
|
||||
#include "utp_templates.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_packedsockaddr.h"
|
||||
|
||||
/* These originally lived in utp_config.h */
|
||||
#define CCONTROL_TARGET (100 * 1000) // us
|
||||
|
||||
enum bandwidth_type_t {
|
||||
payload_bandwidth, connect_overhead,
|
||||
close_overhead, ack_overhead,
|
||||
header_overhead, retransmit_overhead
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _MSC_VER
|
||||
#include "libutp_inet_ntop.h"
|
||||
#endif
|
||||
|
||||
// newer versions of MSVC define these in errno.h
|
||||
#ifndef ECONNRESET
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct PACKED_ATTRIBUTE RST_Info {
|
||||
PackedSockAddr addr;
|
||||
uint32 connid;
|
||||
uint16 ack_nr;
|
||||
uint64 timestamp;
|
||||
};
|
||||
|
||||
// It's really important that we don't have duplicate keys in the hash table.
|
||||
// If we do, we'll eventually crash. if we try to remove the second instance
|
||||
// of the key, we'll accidentally remove the first instead. then later,
|
||||
// checkTimeouts will try to access the second one's already freed memory.
|
||||
void UTP_FreeAll(struct UTPSocketHT *utp_sockets);
|
||||
|
||||
struct UTPSocketKey {
|
||||
PackedSockAddr addr;
|
||||
uint32 recv_id; // "conn_seed", "conn_id"
|
||||
|
||||
UTPSocketKey(const PackedSockAddr& _addr, uint32 _recv_id) {
|
||||
memset((void*)this, 0, sizeof(*this));
|
||||
addr = _addr;
|
||||
recv_id = _recv_id;
|
||||
}
|
||||
|
||||
bool operator == (const UTPSocketKey &other) const {
|
||||
return recv_id == other.recv_id && addr == other.addr;
|
||||
}
|
||||
|
||||
uint32 compute_hash() const {
|
||||
return recv_id ^ addr.compute_hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct UTPSocketKeyData {
|
||||
UTPSocketKey key;
|
||||
UTPSocket *socket;
|
||||
utp_link_t link;
|
||||
};
|
||||
|
||||
#define UTP_SOCKET_BUCKETS 79
|
||||
#define UTP_SOCKET_INIT 15
|
||||
|
||||
struct UTPSocketHT : utpHashTable<UTPSocketKey, UTPSocketKeyData> {
|
||||
UTPSocketHT() {
|
||||
const int buckets = UTP_SOCKET_BUCKETS;
|
||||
const int initial = UTP_SOCKET_INIT;
|
||||
this->Create(buckets, initial);
|
||||
}
|
||||
~UTPSocketHT() {
|
||||
UTP_FreeAll(this);
|
||||
this->Free();
|
||||
}
|
||||
};
|
||||
|
||||
struct struct_utp_context {
|
||||
void *userdata;
|
||||
utp_callback_t* callbacks[UTP_ARRAY_SIZE];
|
||||
|
||||
uint64 current_ms;
|
||||
utp_context_stats context_stats;
|
||||
UTPSocket *last_utp_socket;
|
||||
Array<UTPSocket*> ack_sockets;
|
||||
Array<RST_Info> rst_info;
|
||||
UTPSocketHT *utp_sockets;
|
||||
size_t target_delay;
|
||||
size_t opt_sndbuf;
|
||||
size_t opt_rcvbuf;
|
||||
uint64 last_check;
|
||||
|
||||
struct_utp_context();
|
||||
~struct_utp_context();
|
||||
|
||||
void log(int level, utp_socket *socket, char const *fmt, ...);
|
||||
void log_unchecked(utp_socket *socket, char const *fmt, ...);
|
||||
bool would_log(int level);
|
||||
|
||||
bool log_normal:1; // log normal events?
|
||||
bool log_mtu:1; // log MTU related events?
|
||||
bool log_debug:1; // log debugging events? (Must also compile with UTP_DEBUG_LOGGING defined)
|
||||
};
|
||||
|
||||
#endif //__UTP_INTERNAL_H__
|
||||
139
vendor/github.com/anacrolix/go-libutp/utp_packedsockaddr.cpp
generated
vendored
Normal file
139
vendor/github.com/anacrolix/go-libutp/utp_packedsockaddr.cpp
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utp_types.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_packedsockaddr.h"
|
||||
|
||||
#include "libutp_inet_ntop.h"
|
||||
|
||||
byte PackedSockAddr::get_family() const
|
||||
{
|
||||
#if defined(__sh__)
|
||||
return ((_sin6d[0] == 0) && (_sin6d[1] == 0) && (_sin6d[2] == htonl(0xffff)) != 0) ?
|
||||
AF_INET : AF_INET6;
|
||||
#else
|
||||
return (IN6_IS_ADDR_V4MAPPED(&_in._in6addr) != 0) ? AF_INET : AF_INET6;
|
||||
#endif // defined(__sh__)
|
||||
}
|
||||
|
||||
bool PackedSockAddr::operator==(const PackedSockAddr& rhs) const
|
||||
{
|
||||
if (&rhs == this)
|
||||
return true;
|
||||
if (_port != rhs._port)
|
||||
return false;
|
||||
return memcmp(_sin6, rhs._sin6, sizeof(_sin6)) == 0;
|
||||
}
|
||||
|
||||
bool PackedSockAddr::operator!=(const PackedSockAddr& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
uint32 PackedSockAddr::compute_hash() const {
|
||||
return utp_hash_mem(&_in, sizeof(_in)) ^ _port;
|
||||
}
|
||||
|
||||
void PackedSockAddr::set(const SOCKADDR_STORAGE* sa, socklen_t len)
|
||||
{
|
||||
if (sa->ss_family == AF_INET) {
|
||||
assert(len >= sizeof(sockaddr_in));
|
||||
const sockaddr_in *sin = (sockaddr_in*)sa;
|
||||
_sin6w[0] = 0;
|
||||
_sin6w[1] = 0;
|
||||
_sin6w[2] = 0;
|
||||
_sin6w[3] = 0;
|
||||
_sin6w[4] = 0;
|
||||
_sin6w[5] = 0xffff;
|
||||
_sin4 = sin->sin_addr.s_addr;
|
||||
_port = ntohs(sin->sin_port);
|
||||
} else {
|
||||
assert(len >= sizeof(sockaddr_in6));
|
||||
const sockaddr_in6 *sin6 = (sockaddr_in6*)sa;
|
||||
_in._in6addr = sin6->sin6_addr;
|
||||
_port = ntohs(sin6->sin6_port);
|
||||
}
|
||||
}
|
||||
|
||||
PackedSockAddr::PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len)
|
||||
{
|
||||
set(sa, len);
|
||||
}
|
||||
|
||||
PackedSockAddr::PackedSockAddr(void)
|
||||
{
|
||||
SOCKADDR_STORAGE sa;
|
||||
socklen_t len = sizeof(SOCKADDR_STORAGE);
|
||||
memset(&sa, 0, len);
|
||||
sa.ss_family = AF_INET;
|
||||
set(&sa, len);
|
||||
}
|
||||
|
||||
SOCKADDR_STORAGE PackedSockAddr::get_sockaddr_storage(socklen_t *len = NULL) const
|
||||
{
|
||||
SOCKADDR_STORAGE sa;
|
||||
const byte family = get_family();
|
||||
if (family == AF_INET) {
|
||||
sockaddr_in *sin = (sockaddr_in*)&sa;
|
||||
if (len) *len = sizeof(sockaddr_in);
|
||||
memset(sin, 0, sizeof(sockaddr_in));
|
||||
sin->sin_family = family;
|
||||
sin->sin_port = htons(_port);
|
||||
sin->sin_addr.s_addr = _sin4;
|
||||
} else {
|
||||
sockaddr_in6 *sin6 = (sockaddr_in6*)&sa;
|
||||
memset(sin6, 0, sizeof(sockaddr_in6));
|
||||
if (len) *len = sizeof(sockaddr_in6);
|
||||
sin6->sin6_family = family;
|
||||
sin6->sin6_addr = _in._in6addr;
|
||||
sin6->sin6_port = htons(_port);
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
||||
// #define addrfmt(x, s) x.fmt(s, sizeof(s))
|
||||
cstr PackedSockAddr::fmt(str s, size_t len) const
|
||||
{
|
||||
memset(s, 0, len);
|
||||
const byte family = get_family();
|
||||
str i;
|
||||
if (family == AF_INET) {
|
||||
INET_NTOP(family, (uint32*)&_sin4, s, len);
|
||||
i = s;
|
||||
while (*++i) {}
|
||||
} else {
|
||||
i = s;
|
||||
*i++ = '[';
|
||||
INET_NTOP(family, (in6_addr*)&_in._in6addr, i, len-1);
|
||||
while (*++i) {}
|
||||
*i++ = ']';
|
||||
}
|
||||
snprintf(i, len - (i-s), ":%u", _port);
|
||||
return s;
|
||||
}
|
||||
60
vendor/github.com/anacrolix/go-libutp/utp_packedsockaddr.h
generated
vendored
Normal file
60
vendor/github.com/anacrolix/go-libutp/utp_packedsockaddr.h
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_PACKEDSOCKADDR_H__
|
||||
#define __UTP_PACKEDSOCKADDR_H__
|
||||
|
||||
#include "utp_types.h"
|
||||
|
||||
struct PACKED_ATTRIBUTE PackedSockAddr {
|
||||
// The values are always stored here in network byte order
|
||||
union {
|
||||
byte _in6[16]; // IPv6
|
||||
uint16 _in6w[8]; // IPv6, word based (for convenience)
|
||||
uint32 _in6d[4]; // Dword access
|
||||
in6_addr _in6addr; // For convenience
|
||||
} _in;
|
||||
|
||||
// Host byte order
|
||||
uint16 _port;
|
||||
|
||||
#define _sin4 _in._in6d[3] // IPv4 is stored where it goes if mapped
|
||||
|
||||
#define _sin6 _in._in6
|
||||
#define _sin6w _in._in6w
|
||||
#define _sin6d _in._in6d
|
||||
|
||||
byte get_family() const;
|
||||
bool operator==(const PackedSockAddr& rhs) const;
|
||||
bool operator!=(const PackedSockAddr& rhs) const;
|
||||
void set(const SOCKADDR_STORAGE* sa, socklen_t len);
|
||||
|
||||
PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len);
|
||||
PackedSockAddr(void);
|
||||
|
||||
SOCKADDR_STORAGE get_sockaddr_storage(socklen_t *len) const;
|
||||
cstr fmt(str s, size_t len) const;
|
||||
|
||||
uint32 compute_hash() const;
|
||||
} ALIGNED_ATTRIBUTE(4);
|
||||
|
||||
#endif //__UTP_PACKEDSOCKADDR_H__
|
||||
195
vendor/github.com/anacrolix/go-libutp/utp_templates.h
generated
vendored
Normal file
195
vendor/github.com/anacrolix/go-libutp/utp_templates.h
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __TEMPLATES_H__
|
||||
#define __TEMPLATES_H__
|
||||
|
||||
#include "utp_types.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(POSIX)
|
||||
/* Allow over-writing FORCEINLINE from makefile because gcc 3.4.4 for buffalo
|
||||
doesn't seem to support __attribute__((always_inline)) in -O0 build
|
||||
(strangely, it works in -Os build) */
|
||||
#ifndef FORCEINLINE
|
||||
// The always_inline attribute asks gcc to inline the function even if no optimization is being requested.
|
||||
// This macro should be used exclusive-or with the inline directive (use one or the other but not both)
|
||||
// since Microsoft uses __forceinline to also mean inline,
|
||||
// and this code is following a Microsoft compatibility model.
|
||||
// Just setting the attribute without also specifying the inline directive apparently won't inline the function,
|
||||
// as evidenced by multiply-defined symbols found at link time.
|
||||
#define FORCEINLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Utility templates
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
template <typename T> static inline T min(T a, T b) { if (a < b) return a; return b; }
|
||||
template <typename T> static inline T max(T a, T b) { if (a > b) return a; return b; }
|
||||
|
||||
template <typename T> static inline T min(T a, T b, T c) { return min(min(a,b),c); }
|
||||
template <typename T> static inline T max(T a, T b, T c) { return max(max(a,b),c); }
|
||||
template <typename T> static inline T clamp(T v, T mi, T ma)
|
||||
{
|
||||
if (v > ma) v = ma;
|
||||
if (v < mi) v = mi;
|
||||
return v;
|
||||
}
|
||||
|
||||
#if (defined(__SVR4) && defined(__sun))
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push,1)
|
||||
#endif
|
||||
|
||||
|
||||
namespace aux
|
||||
{
|
||||
FORCEINLINE uint16 host_to_network(uint16 i) { return htons(i); }
|
||||
FORCEINLINE uint32 host_to_network(uint32 i) { return htonl(i); }
|
||||
FORCEINLINE int32 host_to_network(int32 i) { return htonl(i); }
|
||||
FORCEINLINE uint16 network_to_host(uint16 i) { return ntohs(i); }
|
||||
FORCEINLINE uint32 network_to_host(uint32 i) { return ntohl(i); }
|
||||
FORCEINLINE int32 network_to_host(int32 i) { return ntohl(i); }
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct PACKED_ATTRIBUTE big_endian
|
||||
{
|
||||
T operator=(T i) { m_integer = aux::host_to_network(i); return i; }
|
||||
operator T() const { return aux::network_to_host(m_integer); }
|
||||
private:
|
||||
T m_integer;
|
||||
};
|
||||
|
||||
typedef big_endian<int32> int32_big;
|
||||
typedef big_endian<uint32> uint32_big;
|
||||
typedef big_endian<uint16> uint16_big;
|
||||
|
||||
#if (defined(__SVR4) && defined(__sun))
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
template<typename T> static inline void zeromem(T *a, size_t count = 1) { memset(a, 0, count * sizeof(T)); }
|
||||
|
||||
typedef int SortCompareProc(const void *, const void *);
|
||||
|
||||
template<typename T> static FORCEINLINE void QuickSortT(T *base, size_t num, int (*comp)(const T *, const T *)) { qsort(base, num, sizeof(T), (SortCompareProc*)comp); }
|
||||
|
||||
|
||||
// WARNING: The template parameter MUST be a POD type!
|
||||
template <typename T, size_t minsize = 16> class Array {
|
||||
protected:
|
||||
T *mem;
|
||||
size_t alloc,count;
|
||||
|
||||
public:
|
||||
Array(size_t init) { Init(init); }
|
||||
Array() { Init(); }
|
||||
~Array() { Free(); }
|
||||
|
||||
void inline Init() { mem = NULL; alloc = count = 0; }
|
||||
void inline Init(size_t init) { Init(); if (init) Resize(init); }
|
||||
size_t inline GetCount() const { return count; }
|
||||
size_t inline GetAlloc() const { return alloc; }
|
||||
void inline SetCount(size_t c) { count = c; }
|
||||
|
||||
inline T& operator[](size_t offset) { assert(offset ==0 || offset<alloc); return mem[offset]; }
|
||||
inline const T& operator[](size_t offset) const { assert(offset ==0 || offset<alloc); return mem[offset]; }
|
||||
|
||||
void inline Resize(size_t a) {
|
||||
if (a == 0) { free(mem); Init(); }
|
||||
else { mem = (T*)realloc(mem, (alloc=a) * sizeof(T)); }
|
||||
}
|
||||
|
||||
void Grow() { Resize(::max<size_t>(minsize, alloc * 2)); }
|
||||
|
||||
inline size_t Append(const T &t) {
|
||||
if (count >= alloc) Grow();
|
||||
size_t r=count++;
|
||||
mem[r] = t;
|
||||
return r;
|
||||
}
|
||||
|
||||
T inline &Append() {
|
||||
if (count >= alloc) Grow();
|
||||
return mem[count++];
|
||||
}
|
||||
|
||||
void inline Compact() {
|
||||
Resize(count);
|
||||
}
|
||||
|
||||
void inline Free() {
|
||||
free(mem);
|
||||
Init();
|
||||
}
|
||||
|
||||
void inline Clear() {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
bool inline MoveUpLast(size_t index) {
|
||||
assert(index < count);
|
||||
size_t c = --count;
|
||||
if (index != c) {
|
||||
mem[index] = mem[c];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool inline MoveUpLastExist(const T &v) {
|
||||
return MoveUpLast(LookupElementExist(v));
|
||||
}
|
||||
|
||||
size_t inline LookupElement(const T &v) const {
|
||||
for(size_t i = 0; i != count; i++)
|
||||
if (mem[i] == v)
|
||||
return i;
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
bool inline HasElement(const T &v) const {
|
||||
return LookupElement(v) != -1;
|
||||
}
|
||||
|
||||
typedef int SortCompareProc(const T *a, const T *b);
|
||||
|
||||
void Sort(SortCompareProc* proc, size_t start, size_t end) {
|
||||
QuickSortT(&mem[start], end - start, proc);
|
||||
}
|
||||
|
||||
void Sort(SortCompareProc* proc, size_t start) {
|
||||
Sort(proc, start, count);
|
||||
}
|
||||
|
||||
void Sort(SortCompareProc* proc) {
|
||||
Sort(proc, 0, count);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //__TEMPLATES_H__
|
||||
123
vendor/github.com/anacrolix/go-libutp/utp_types.h
generated
vendored
Normal file
123
vendor/github.com/anacrolix/go-libutp/utp_types.h
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_TYPES_H__
|
||||
#define __UTP_TYPES_H__
|
||||
|
||||
// Allow libutp consumers or prerequisites to override PACKED_ATTRIBUTE
|
||||
#ifndef PACKED_ATTRIBUTE
|
||||
#if defined BROKEN_GCC_STRUCTURE_PACKING && defined __GNUC__
|
||||
// Used for gcc tool chains accepting but not supporting pragma pack
|
||||
// See http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html
|
||||
#define PACKED_ATTRIBUTE __attribute__((__packed__))
|
||||
#else
|
||||
#define PACKED_ATTRIBUTE
|
||||
#endif // defined BROKEN_GCC_STRUCTURE_PACKING && defined __GNUC__
|
||||
#endif // ndef PACKED_ATTRIBUTE
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ALIGNED_ATTRIBUTE(x) __attribute__((aligned (x)))
|
||||
#else
|
||||
#define ALIGNED_ATTRIBUTE(x)
|
||||
#endif
|
||||
|
||||
// hash.cpp needs socket definitions, which is why this networking specific
|
||||
// code is inclued in utypes.h
|
||||
#ifdef WIN32
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAGMENT
|
||||
#define SHUT_RD SD_RECEIVE
|
||||
#define SHUT_WR SD_SEND
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef IP_DONTFRAG
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAG
|
||||
#elif defined IP_DONTFRAGMENT
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAGMENT
|
||||
#else
|
||||
//#warning "I don't know how to set DF bit on this system"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
#ifdef POSIX
|
||||
typedef struct sockaddr_storage SOCKADDR_STORAGE;
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define I64u "%I64u"
|
||||
#else
|
||||
#define I64u "%Lu"
|
||||
#endif
|
||||
|
||||
// standard types
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char uint8;
|
||||
typedef signed char int8;
|
||||
typedef unsigned short uint16;
|
||||
typedef signed short int16;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned int uint32;
|
||||
typedef signed int int32;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef signed __int64 int64;
|
||||
#else
|
||||
typedef unsigned long long uint64;
|
||||
typedef long long int64;
|
||||
#endif
|
||||
|
||||
/* compile-time assert */
|
||||
#ifndef CASSERT
|
||||
#define CASSERT( exp, name ) typedef int is_not_##name [ (exp ) ? 1 : -1 ];
|
||||
#endif
|
||||
|
||||
CASSERT(8 == sizeof(uint64), sizeof_uint64_is_8)
|
||||
CASSERT(8 == sizeof(int64), sizeof_int64_is_8)
|
||||
|
||||
#ifndef INT64_MAX
|
||||
#define INT64_MAX 0x7fffffffffffffffLL
|
||||
#endif
|
||||
|
||||
// always ANSI
|
||||
typedef const char * cstr;
|
||||
typedef char * str;
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef uint8 bool;
|
||||
#endif
|
||||
|
||||
#endif //__UTP_TYPES_H__
|
||||
254
vendor/github.com/anacrolix/go-libutp/utp_utils.cpp
generated
vendored
Normal file
254
vendor/github.com/anacrolix/go-libutp/utp_utils.cpp
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "utp.h"
|
||||
#include "utp_types.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else //!WIN32
|
||||
#include <time.h>
|
||||
#include <sys/time.h> // Linux needs both time.h and sys/time.h
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#include "utp_utils.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
typedef ULONGLONG (WINAPI GetTickCount64Proc)(void);
|
||||
static GetTickCount64Proc *pt2GetTickCount64;
|
||||
static GetTickCount64Proc *pt2RealGetTickCount;
|
||||
|
||||
static uint64 startPerformanceCounter;
|
||||
static uint64 startGetTickCount;
|
||||
// MSVC 6 standard doesn't like division with uint64s
|
||||
static double counterPerMicrosecond;
|
||||
|
||||
static uint64 UTGetTickCount64()
|
||||
{
|
||||
if (pt2GetTickCount64) {
|
||||
return pt2GetTickCount64();
|
||||
}
|
||||
if (pt2RealGetTickCount) {
|
||||
uint64 v = pt2RealGetTickCount();
|
||||
// fix return value from GetTickCount
|
||||
return (DWORD)v | ((v >> 0x18) & 0xFFFFFFFF00000000);
|
||||
}
|
||||
return (uint64)GetTickCount();
|
||||
}
|
||||
|
||||
static void Time_Initialize()
|
||||
{
|
||||
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
||||
pt2GetTickCount64 = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount64");
|
||||
// not a typo. GetTickCount actually returns 64 bits
|
||||
pt2RealGetTickCount = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount");
|
||||
|
||||
uint64 frequency;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&startPerformanceCounter);
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
|
||||
counterPerMicrosecond = (double)frequency / 1000000.0f;
|
||||
startGetTickCount = UTGetTickCount64();
|
||||
}
|
||||
|
||||
static int64 abs64(int64 x) { return x < 0 ? -x : x; }
|
||||
|
||||
static uint64 __GetMicroseconds()
|
||||
{
|
||||
static bool time_init = false;
|
||||
if (!time_init) {
|
||||
time_init = true;
|
||||
Time_Initialize();
|
||||
}
|
||||
|
||||
uint64 counter;
|
||||
uint64 tick;
|
||||
|
||||
QueryPerformanceCounter((LARGE_INTEGER*) &counter);
|
||||
tick = UTGetTickCount64();
|
||||
|
||||
// unfortunately, QueryPerformanceCounter is not guaranteed
|
||||
// to be monotonic. Make it so.
|
||||
int64 ret = (int64)(((int64)counter - (int64)startPerformanceCounter) / counterPerMicrosecond);
|
||||
// if the QPC clock leaps more than one second off GetTickCount64()
|
||||
// something is seriously fishy. Adjust QPC to stay monotonic
|
||||
int64 tick_diff = tick - startGetTickCount;
|
||||
if (abs64(ret / 100000 - tick_diff / 100) > 10) {
|
||||
startPerformanceCounter -= (uint64)((int64)(tick_diff * 1000 - ret) * counterPerMicrosecond);
|
||||
ret = (int64)((counter - startPerformanceCounter) / counterPerMicrosecond);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64 UTP_GetMilliseconds()
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
#else //!WIN32
|
||||
|
||||
static inline uint64 UTP_GetMicroseconds(void);
|
||||
static inline uint64 UTP_GetMilliseconds()
|
||||
{
|
||||
return UTP_GetMicroseconds() / 1000;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
static uint64 __GetMicroseconds()
|
||||
{
|
||||
// http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
|
||||
// http://www.macresearch.org/tutorial_performance_and_time
|
||||
static mach_timebase_info_data_t sTimebaseInfo;
|
||||
static uint64_t start_tick = 0;
|
||||
uint64_t tick;
|
||||
// Returns a counter in some fraction of a nanoseconds
|
||||
tick = mach_absolute_time();
|
||||
if (sTimebaseInfo.denom == 0) {
|
||||
// Get the timer ratio to convert mach_absolute_time to nanoseconds
|
||||
mach_timebase_info(&sTimebaseInfo);
|
||||
start_tick = tick;
|
||||
}
|
||||
// Calculate the elapsed time, convert it to microseconds and return it.
|
||||
return ((tick - start_tick) * sTimebaseInfo.numer) / (sTimebaseInfo.denom * 1000);
|
||||
}
|
||||
|
||||
#else // !__APPLE__
|
||||
|
||||
#if ! (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC))
|
||||
#warning "Using non-monotonic function gettimeofday() in UTP_GetMicroseconds()"
|
||||
#endif
|
||||
|
||||
/* Unfortunately, #ifdef CLOCK_MONOTONIC is not enough to make sure that
|
||||
POSIX clocks work -- we could be running a recent libc with an ancient
|
||||
kernel (think OpenWRT). -- jch */
|
||||
|
||||
static uint64_t __GetMicroseconds()
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC)
|
||||
static int have_posix_clocks = -1;
|
||||
int rc;
|
||||
|
||||
if (have_posix_clocks < 0) {
|
||||
struct timespec ts;
|
||||
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (rc < 0) {
|
||||
have_posix_clocks = 0;
|
||||
} else {
|
||||
have_posix_clocks = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_posix_clocks) {
|
||||
struct timespec ts;
|
||||
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return uint64(ts.tv_sec) * 1000000 + uint64(ts.tv_nsec) / 1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
return uint64(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
}
|
||||
|
||||
#endif //!__APPLE__
|
||||
|
||||
#endif //!WIN32
|
||||
|
||||
/*
|
||||
* Whew. Okay. After that #ifdef maze above, we now know we have a working
|
||||
* __GetMicroseconds() implementation on all platforms.
|
||||
*
|
||||
* Because there are a number of assertions in libutp that will cause a crash
|
||||
* if monotonic time isn't monotonic, now apply some safety checks. While in
|
||||
* principle we're already protecting ourselves in cases where non-monotonic
|
||||
* time is likely to happen, this protects all versions.
|
||||
*/
|
||||
|
||||
static inline uint64 UTP_GetMicroseconds()
|
||||
{
|
||||
static uint64 offset = 0, previous = 0;
|
||||
|
||||
uint64 now = __GetMicroseconds() + offset;
|
||||
if (previous > now) {
|
||||
/* Eek! */
|
||||
offset += previous - now;
|
||||
now = previous;
|
||||
}
|
||||
previous = now;
|
||||
return now;
|
||||
}
|
||||
|
||||
#define ETHERNET_MTU 1500
|
||||
#define IPV4_HEADER_SIZE 20
|
||||
#define IPV6_HEADER_SIZE 40
|
||||
#define UDP_HEADER_SIZE 8
|
||||
#define GRE_HEADER_SIZE 24
|
||||
#define PPPOE_HEADER_SIZE 8
|
||||
#define MPPE_HEADER_SIZE 2
|
||||
// packets have been observed in the wild that were fragmented
|
||||
// with a payload of 1416 for the first fragment
|
||||
// There are reports of routers that have MTU sizes as small as 1392
|
||||
#define FUDGE_HEADER_SIZE 36
|
||||
#define TEREDO_MTU 1280
|
||||
|
||||
#define UDP_IPV4_OVERHEAD (IPV4_HEADER_SIZE + UDP_HEADER_SIZE)
|
||||
#define UDP_IPV6_OVERHEAD (IPV6_HEADER_SIZE + UDP_HEADER_SIZE)
|
||||
#define UDP_TEREDO_OVERHEAD (UDP_IPV4_OVERHEAD + UDP_IPV6_OVERHEAD)
|
||||
|
||||
#define UDP_IPV4_MTU (ETHERNET_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
|
||||
#define UDP_IPV6_MTU (ETHERNET_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
|
||||
#define UDP_TEREDO_MTU (TEREDO_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE)
|
||||
|
||||
uint64 utp_default_get_udp_mtu(utp_callback_arguments *args) {
|
||||
// Since we don't know the local address of the interface,
|
||||
// be conservative and assume all IPv6 connections are Teredo.
|
||||
return (args->address->sa_family == AF_INET6) ? UDP_TEREDO_MTU : UDP_IPV4_MTU;
|
||||
}
|
||||
|
||||
uint64 utp_default_get_udp_overhead(utp_callback_arguments *args) {
|
||||
// Since we don't know the local address of the interface,
|
||||
// be conservative and assume all IPv6 connections are Teredo.
|
||||
return (args->address->sa_family == AF_INET6) ? UDP_TEREDO_OVERHEAD : UDP_IPV4_OVERHEAD;
|
||||
}
|
||||
|
||||
uint64 utp_default_get_random(utp_callback_arguments *args) {
|
||||
return rand();
|
||||
}
|
||||
|
||||
uint64 utp_default_get_milliseconds(utp_callback_arguments *args) {
|
||||
return UTP_GetMilliseconds();
|
||||
}
|
||||
|
||||
uint64 utp_default_get_microseconds(utp_callback_arguments *args) {
|
||||
return UTP_GetMicroseconds();
|
||||
}
|
||||
27
vendor/github.com/anacrolix/go-libutp/utp_utils.h
generated
vendored
Normal file
27
vendor/github.com/anacrolix/go-libutp/utp_utils.h
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
uint64 utp_default_get_udp_mtu(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_udp_overhead(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_random(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_milliseconds(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_microseconds(utp_callback_arguments *args);
|
||||
373
vendor/github.com/anacrolix/log/LICENSE
generated
vendored
Normal file
373
vendor/github.com/anacrolix/log/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
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/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
39
vendor/github.com/anacrolix/log/global.go
generated
vendored
Normal file
39
vendor/github.com/anacrolix/log/global.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultHandler = StreamHandler{
|
||||
W: os.Stderr,
|
||||
Fmt: LineFormatter,
|
||||
}
|
||||
Default = Logger{
|
||||
nonZero: true,
|
||||
filterLevel: Error,
|
||||
Handlers: []Handler{DefaultHandler},
|
||||
}
|
||||
DiscardHandler = StreamHandler{
|
||||
W: ioutil.Discard,
|
||||
Fmt: func(Record) []byte { return nil },
|
||||
}
|
||||
)
|
||||
|
||||
func Levelf(level Level, format string, a ...interface{}) {
|
||||
Default.LazyLog(level, func() Msg {
|
||||
return Fmsg(format, a...).Skip(1)
|
||||
})
|
||||
}
|
||||
|
||||
func Printf(format string, a ...interface{}) {
|
||||
Default.Log(Fmsg(format, a...).Skip(1))
|
||||
}
|
||||
|
||||
// Prints the arguments to the Default Logger.
|
||||
func Print(a ...interface{}) {
|
||||
// TODO: There's no "Print" equivalent constructor for a Msg, and I don't know what I'd call it.
|
||||
Str(fmt.Sprint(a...)).Skip(1).Log(Default)
|
||||
}
|
||||
11
vendor/github.com/anacrolix/log/handler.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/log/handler.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package log
|
||||
|
||||
type Handler interface {
|
||||
Handle(Record)
|
||||
}
|
||||
|
||||
type Record struct {
|
||||
Msg
|
||||
Level Level
|
||||
Names []string
|
||||
}
|
||||
51
vendor/github.com/anacrolix/log/level.go
generated
vendored
Normal file
51
vendor/github.com/anacrolix/log/level.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Level struct {
|
||||
rank int
|
||||
logStr string
|
||||
}
|
||||
|
||||
var levelKey = new(struct{})
|
||||
|
||||
var (
|
||||
NotSet = Level{0, "UNSET"}
|
||||
Debug = Level{1, "DEBUG"}
|
||||
Info = Level{2, "INFO"}
|
||||
Warning = Level{3, "WARN"}
|
||||
Error = Level{4, "ERROR"}
|
||||
Critical = Level{5, "CRIT"}
|
||||
// Will this get special treatment? Not yet.
|
||||
Fatal = Level{6, "FATAL"}
|
||||
)
|
||||
|
||||
func (l Level) LogString() string {
|
||||
switch l.rank {
|
||||
case NotSet.rank:
|
||||
return "unset"
|
||||
case Debug.rank:
|
||||
return "debug"
|
||||
case Info.rank:
|
||||
return "info"
|
||||
case Warning.rank:
|
||||
return "warn"
|
||||
case Error.rank:
|
||||
return "error"
|
||||
case Critical.rank:
|
||||
return "crit"
|
||||
case Fatal.rank:
|
||||
return "fatal"
|
||||
default:
|
||||
return strconv.FormatInt(int64(l.rank), 10)
|
||||
}
|
||||
}
|
||||
|
||||
func (l Level) LessThan(r Level) bool {
|
||||
if l.rank == NotSet.rank {
|
||||
return false
|
||||
}
|
||||
return l.rank < r.rank
|
||||
}
|
||||
13
vendor/github.com/anacrolix/log/log.go
generated
vendored
Normal file
13
vendor/github.com/anacrolix/log/log.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func Call() Msg {
|
||||
var pc [1]uintptr
|
||||
n := runtime.Callers(4, pc[:])
|
||||
fs := runtime.CallersFrames(pc[:n])
|
||||
f, _ := fs.Next()
|
||||
return Fmsg("called %q", f.Function)
|
||||
}
|
||||
135
vendor/github.com/anacrolix/log/logger.go
generated
vendored
Normal file
135
vendor/github.com/anacrolix/log/logger.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Logger is a helper wrapping LoggerImpl.
|
||||
type Logger struct {
|
||||
nonZero bool
|
||||
names []string
|
||||
values []interface{}
|
||||
defaultLevel Level
|
||||
filterLevel Level
|
||||
msgMaps []func(Msg) Msg
|
||||
Handlers []Handler
|
||||
}
|
||||
|
||||
// Returns a logger that adds the given values to logged messages.
|
||||
func (l Logger) WithValues(v ...interface{}) Logger {
|
||||
l.values = append(l.values, v...)
|
||||
return l
|
||||
}
|
||||
|
||||
// Returns a logger that for a given message propagates the result of `f` instead.
|
||||
func (l Logger) WithMap(f func(m Msg) Msg) Logger {
|
||||
l.msgMaps = append(l.msgMaps, f)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l Logger) WithText(f func(Msg) string) Logger {
|
||||
l.msgMaps = append(l.msgMaps, func(msg Msg) Msg {
|
||||
return msg.WithText(f)
|
||||
})
|
||||
return l
|
||||
}
|
||||
|
||||
// Helper for compatibility with "log".Logger.
|
||||
func (l Logger) Printf(format string, a ...interface{}) {
|
||||
l.LazyLog(l.defaultLevel, func() Msg {
|
||||
return Fmsg(format, a...).Skip(1)
|
||||
})
|
||||
}
|
||||
|
||||
func (l Logger) Log(m Msg) {
|
||||
l.LogLevel(l.defaultLevel, m.Skip(1))
|
||||
}
|
||||
|
||||
func (l Logger) LogLevel(level Level, m Msg) {
|
||||
l.LazyLog(level, func() Msg {
|
||||
return m.Skip(1)
|
||||
})
|
||||
}
|
||||
|
||||
// Helper for compatibility with "log".Logger.
|
||||
func (l Logger) Print(v ...interface{}) {
|
||||
l.LazyLog(l.defaultLevel, func() Msg {
|
||||
return Str(fmt.Sprint(v...)).Skip(1)
|
||||
})
|
||||
}
|
||||
|
||||
func (l Logger) WithDefaultLevel(level Level) Logger {
|
||||
l.defaultLevel = level
|
||||
return l
|
||||
}
|
||||
|
||||
func (l Logger) FilterLevel(minLevel Level) Logger {
|
||||
l.filterLevel = minLevel
|
||||
return l
|
||||
}
|
||||
|
||||
func (l Logger) WithContextValue(v interface{}) Logger {
|
||||
return l.WithText(func(m Msg) string {
|
||||
return fmt.Sprintf("%v: %v", v, m)
|
||||
})
|
||||
}
|
||||
|
||||
func (l Logger) WithContextText(s string) Logger {
|
||||
return l.WithText(func(m Msg) string {
|
||||
return s + ": " + m.Text()
|
||||
})
|
||||
}
|
||||
|
||||
func (l Logger) IsZero() bool {
|
||||
return !l.nonZero
|
||||
}
|
||||
|
||||
func (l Logger) SkipCallers(skip int) Logger {
|
||||
return l.WithMap(func(m Msg) Msg {
|
||||
return m.Skip(skip)
|
||||
})
|
||||
}
|
||||
|
||||
func (l Logger) IsEnabledFor(level Level) bool {
|
||||
for i := len(rules) - 1; i >= 0; i-- {
|
||||
r := rules[i]
|
||||
minLevel, matched := r(l.names)
|
||||
if matched {
|
||||
//log.Print(level, minLevel)
|
||||
return !level.LessThan(minLevel)
|
||||
}
|
||||
}
|
||||
return !level.LessThan(l.filterLevel)
|
||||
}
|
||||
|
||||
func (l Logger) LazyLog(level Level, f func() Msg) {
|
||||
l.lazyLog(level, 1, f)
|
||||
}
|
||||
|
||||
func (l Logger) lazyLog(level Level, skip int, f func() Msg) {
|
||||
if l.IsEnabledFor(level) {
|
||||
l.handle(level, f().Skip(skip+1))
|
||||
}
|
||||
}
|
||||
|
||||
func (l Logger) handle(level Level, m Msg) {
|
||||
r := Record{
|
||||
Msg: m.Skip(1),
|
||||
Level: level,
|
||||
Names: l.names,
|
||||
}
|
||||
for _, h := range l.Handlers {
|
||||
h.Handle(r)
|
||||
}
|
||||
}
|
||||
|
||||
func (l Logger) WithNames(names ...string) Logger {
|
||||
l.names = append(l.names, names...)
|
||||
return l
|
||||
}
|
||||
|
||||
func (l Logger) Levelf(level Level, format string, a ...interface{}) {
|
||||
l.LazyLog(level, func() Msg {
|
||||
return Fmsg(format, a...).Skip(1)
|
||||
})
|
||||
}
|
||||
155
vendor/github.com/anacrolix/log/msg.go
generated
vendored
Normal file
155
vendor/github.com/anacrolix/log/msg.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anacrolix/missinggo/iter"
|
||||
)
|
||||
|
||||
type Msg struct {
|
||||
MsgImpl
|
||||
}
|
||||
|
||||
func (me Msg) String() string {
|
||||
return me.Text()
|
||||
}
|
||||
|
||||
func newMsg(text func() string) Msg {
|
||||
return Msg{rootMsgImpl{text}}
|
||||
}
|
||||
|
||||
func Fmsg(format string, a ...interface{}) Msg {
|
||||
return newMsg(func() string { return fmt.Sprintf(format, a...) })
|
||||
}
|
||||
|
||||
var Fstr = Fmsg
|
||||
|
||||
func Str(s string) (m Msg) {
|
||||
return newMsg(func() string { return s })
|
||||
}
|
||||
|
||||
type msgSkipCaller struct {
|
||||
MsgImpl
|
||||
skip int
|
||||
}
|
||||
|
||||
func (me msgSkipCaller) Callers(skip int, pc []uintptr) int {
|
||||
return me.MsgImpl.Callers(skip+1+me.skip, pc)
|
||||
}
|
||||
|
||||
func (m Msg) Skip(skip int) Msg {
|
||||
return Msg{msgSkipCaller{m.MsgImpl, skip}}
|
||||
}
|
||||
|
||||
type item struct {
|
||||
key, value interface{}
|
||||
}
|
||||
|
||||
// rename sink
|
||||
func (m Msg) Log(l Logger) Msg {
|
||||
l.Log(m.Skip(1))
|
||||
return m
|
||||
}
|
||||
|
||||
func (m Msg) LogLevel(level Level, l Logger) Msg {
|
||||
l.LogLevel(level, m.Skip(1))
|
||||
return m
|
||||
}
|
||||
|
||||
type msgWithValues struct {
|
||||
MsgImpl
|
||||
values []interface{}
|
||||
}
|
||||
|
||||
func (me msgWithValues) Values(cb iter.Callback) {
|
||||
for _, v := range me.values {
|
||||
if !cb(v) {
|
||||
return
|
||||
}
|
||||
}
|
||||
me.MsgImpl.Values(cb)
|
||||
}
|
||||
|
||||
// TODO: What ordering should be applied to the values here, per MsgImpl.Values. For now they're
|
||||
// traversed in order of the slice.
|
||||
func (m Msg) WithValues(v ...interface{}) Msg {
|
||||
return Msg{msgWithValues{m.MsgImpl, v}}
|
||||
}
|
||||
|
||||
func (m Msg) AddValues(v ...interface{}) Msg {
|
||||
return m.WithValues(v...)
|
||||
}
|
||||
|
||||
func (m Msg) With(key, value interface{}) Msg {
|
||||
return m.WithValues(item{key, value})
|
||||
}
|
||||
|
||||
func (m Msg) Add(key, value interface{}) Msg {
|
||||
return m.With(key, value)
|
||||
}
|
||||
|
||||
//func (m Msg) SetLevel(level Level) Msg {
|
||||
// return m.With(levelKey, level)
|
||||
//}
|
||||
|
||||
//func (m Msg) GetByKey(key interface{}) (value interface{}, ok bool) {
|
||||
// m.Values(func(i interface{}) bool {
|
||||
// if keyValue, isKeyValue := i.(item); isKeyValue && keyValue.key == key {
|
||||
// value = keyValue.value
|
||||
// ok = true
|
||||
// }
|
||||
// return !ok
|
||||
// })
|
||||
// return
|
||||
//}
|
||||
|
||||
//func (m Msg) GetLevel() (l Level, ok bool) {
|
||||
// v, ok := m.GetByKey(levelKey)
|
||||
// if ok {
|
||||
// l = v.(Level)
|
||||
// }
|
||||
// return
|
||||
//}
|
||||
|
||||
func (m Msg) HasValue(v interface{}) (has bool) {
|
||||
m.Values(func(i interface{}) bool {
|
||||
if i == v {
|
||||
has = true
|
||||
}
|
||||
return !has
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (m Msg) AddValue(v interface{}) Msg {
|
||||
return m.AddValues(v)
|
||||
}
|
||||
|
||||
//func (m Msg) GetValueByType(p interface{}) bool {
|
||||
// pve := reflect.ValueOf(p).Elem()
|
||||
// t := pve.Type()
|
||||
// return !iter.All(func(i interface{}) bool {
|
||||
// iv := reflect.ValueOf(i)
|
||||
// if iv.Type() == t {
|
||||
// pve.Set(iv)
|
||||
// return false
|
||||
// }
|
||||
// return true
|
||||
// }, m.Values)
|
||||
//}
|
||||
|
||||
func (m Msg) WithText(f func(Msg) string) Msg {
|
||||
return Msg{msgWithText{
|
||||
m,
|
||||
func() string { return f(m) },
|
||||
}}
|
||||
}
|
||||
|
||||
type msgWithText struct {
|
||||
MsgImpl
|
||||
text func() string
|
||||
}
|
||||
|
||||
func (me msgWithText) Text() string {
|
||||
return me.text()
|
||||
}
|
||||
33
vendor/github.com/anacrolix/log/msgimpl.go
generated
vendored
Normal file
33
vendor/github.com/anacrolix/log/msgimpl.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/anacrolix/missinggo/iter"
|
||||
)
|
||||
|
||||
// The minimal interface required for the Msg helper/wrapper to operate on.
|
||||
type MsgImpl interface {
|
||||
// Returns the message text. Allows for lazy evaluation/prefixing etc.
|
||||
Text() string
|
||||
// Sets the program counters in pc. Having it in the interface may allow us to cache/freeze them
|
||||
// for serialization etc.
|
||||
Callers(skip int, pc []uintptr) int
|
||||
// Iterates over the values as added LIFO.
|
||||
Values(callback iter.Callback)
|
||||
}
|
||||
|
||||
// maybe implement finalizer to ensure msgs are sunk
|
||||
type rootMsgImpl struct {
|
||||
text func() string
|
||||
}
|
||||
|
||||
func (m rootMsgImpl) Text() string {
|
||||
return m.text()
|
||||
}
|
||||
|
||||
func (m rootMsgImpl) Callers(skip int, pc []uintptr) int {
|
||||
return runtime.Callers(skip+2, pc)
|
||||
}
|
||||
|
||||
func (m rootMsgImpl) Values(iter.Callback) {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user