feat: Waku v2 bridge

Issue #12610
This commit is contained in:
Michal Iskierko
2023-11-12 13:29:38 +01:00
parent 56e7bd01ca
commit 6d31343205
6716 changed files with 1982502 additions and 5891 deletions

21
vendor/github.com/anacrolix/chansync/LICENSE generated vendored Normal file
View 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.

View 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
View 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
View 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
View 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
View 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
View 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
View 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.

View 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
View 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
View File

@@ -0,0 +1,21 @@
# dht
[![Go Reference](https://pkg.go.dev/badge/github.com/anacrolix/dht/v2.svg)](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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
}

View 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
}
}

View 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)
}

View 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)
}

View 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)
}

View 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
View 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
View File

@@ -0,0 +1,9 @@
package krpc
import (
"github.com/anacrolix/torrent/metainfo"
)
type Bep46Payload struct {
Ih metainfo.Hash `bencode:"ih"`
}

View 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)
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
package dht

56
vendor/github.com/anacrolix/dht/v2/node.go generated vendored Normal file
View 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
View 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
}

View 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)
}

View 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
View 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

File diff suppressed because it is too large Load Diff

134
vendor/github.com/anacrolix/dht/v2/table.go generated vendored Normal file
View 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
View 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
View 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
}

View 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))
}()
}

View 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
}

View 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
View 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
View File

@@ -0,0 +1,14 @@
# envpprof
[![pkg.go.dev badge](https://img.shields.io/badge/pkg.go.dev-reference-blue)](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
View 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
View File

@@ -0,0 +1,6 @@
*.o
*.a
*.so
tags
*~
_obj

19
vendor/github.com/anacrolix/go-libutp/LICENSE generated vendored Normal file
View 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
View File

@@ -0,0 +1,8 @@
# go-libutp
[![GoDoc](https://godoc.org/github.com/anacrolix/go-libutp?status.svg)](http://godoc.org/github.com/anacrolix/go-libutp)
[![CircleCI](https://circleci.com/gh/anacrolix/go-libutp.svg?style=shield)](https://circleci.com/gh/anacrolix/go-libutp)
[![Go Report Card](https://goreportcard.com/badge/github.com/anacrolix/go-libutp)](https://goreportcard.com/report/github.com/anacrolix/go-libutp)
[![Appveyor Status](https://ci.appveyor.com/api/projects/status/github/anacrolix/go-libutp?branch=master&svg=true)](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
View 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
View 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
View 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
View 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
View 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
View 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))
}

View 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
View 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>

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

141
vendor/github.com/anacrolix/go-libutp/utp_internal.h generated vendored Normal file
View 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__

View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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