init
This commit is contained in:
362
vendor/github.com/anacrolix/dht/LICENSE
generated
vendored
Normal file
362
vendor/github.com/anacrolix/dht/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
25
vendor/github.com/anacrolix/dht/README.md
generated
vendored
Normal file
25
vendor/github.com/anacrolix/dht/README.md
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# dht
|
||||
|
||||
[](https://circleci.com/gh/anacrolix/dht)
|
||||
[](https://godoc.org/github.com/anacrolix/dht)
|
||||
[](https://gitter.im/anacrolix/torrent?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
## Installation
|
||||
|
||||
Install the library package with `go get github.com/anacrolix/dht`, or the provided cmds with `go get github.com/anacrolix/dht/cmd/...`.
|
||||
|
||||
## Commands
|
||||
|
||||
Here I'll describe what some of the provided commands in `./cmd` do.
|
||||
|
||||
Note that the [`godo`](https://github.com/anacrolix/godo) command which is invoked in the following examples builds and executes a Go import path, like `go run`. It's easier to use this convention than to spell out the install/invoke cycle for every single example.
|
||||
|
||||
### dht-ping
|
||||
|
||||
Pings DHT nodes with the given network addresses.
|
||||
|
||||
$ godo ./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%)
|
45
vendor/github.com/anacrolix/dht/addr.go
generated
vendored
Normal file
45
vendor/github.com/anacrolix/dht/addr.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/anacrolix/dht/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 {
|
||||
UDPAddr() *net.UDPAddr
|
||||
String() string
|
||||
KRPC() krpc.NodeAddr
|
||||
}
|
||||
|
||||
// Speeds up some of the commonly called Addr methods.
|
||||
type cachedAddr struct {
|
||||
ua net.UDPAddr
|
||||
s string
|
||||
}
|
||||
|
||||
func (ca cachedAddr) String() string {
|
||||
return ca.s
|
||||
}
|
||||
|
||||
func (ca cachedAddr) UDPAddr() *net.UDPAddr {
|
||||
return &ca.ua
|
||||
}
|
||||
|
||||
func (ca cachedAddr) KRPC() krpc.NodeAddr {
|
||||
return krpc.NodeAddr{
|
||||
IP: ca.ua.IP,
|
||||
Port: ca.ua.Port,
|
||||
}
|
||||
}
|
||||
|
||||
func NewAddr(ua *net.UDPAddr) Addr {
|
||||
return cachedAddr{
|
||||
ua: *ua,
|
||||
s: ua.String(),
|
||||
}
|
||||
}
|
233
vendor/github.com/anacrolix/dht/announce.go
generated
vendored
Normal file
233
vendor/github.com/anacrolix/dht/announce.go
generated
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
package dht
|
||||
|
||||
// get_peers and announce_peers.
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/sync"
|
||||
"github.com/anacrolix/torrent/logonce"
|
||||
"github.com/willf/bloom"
|
||||
|
||||
"github.com/anacrolix/dht/krpc"
|
||||
)
|
||||
|
||||
// Maintains state for an ongoing Announce operation. An Announce is started
|
||||
// by calling Server.Announce.
|
||||
type Announce struct {
|
||||
mu sync.Mutex
|
||||
Peers chan PeersValues
|
||||
// Inner chan is set to nil when on close.
|
||||
values chan PeersValues
|
||||
stop chan struct{}
|
||||
triedAddrs *bloom.BloomFilter
|
||||
// True when contact with all starting addrs has been initiated. This
|
||||
// prevents a race where the first transaction finishes before the rest
|
||||
// have been opened, sees no other transactions are pending and ends the
|
||||
// announce.
|
||||
contactedStartAddrs bool
|
||||
// How many transactions are still ongoing.
|
||||
pending int
|
||||
server *Server
|
||||
infoHash int160
|
||||
// Count of (probably) distinct addresses we've sent get_peers requests
|
||||
// to.
|
||||
numContacted int
|
||||
// The torrent port that we're announcing.
|
||||
announcePort int
|
||||
// The torrent port should be determined by the receiver in case we're
|
||||
// being NATed.
|
||||
announcePortImplied bool
|
||||
}
|
||||
|
||||
// Returns the number of distinct remote addresses the announce has queried.
|
||||
func (a *Announce) NumContacted() int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.numContacted
|
||||
}
|
||||
|
||||
func newBloomFilterForTraversal() *bloom.BloomFilter {
|
||||
return bloom.NewWithEstimates(10000, 0.5)
|
||||
}
|
||||
|
||||
// This is kind of the main thing you want to do with DHT. It traverses the
|
||||
// graph toward nodes that store peers for the infohash, streaming them to the
|
||||
// caller, and announcing the local node to each node if allowed and
|
||||
// specified.
|
||||
func (s *Server) Announce(infoHash [20]byte, port int, impliedPort bool) (*Announce, error) {
|
||||
startAddrs, err := s.traversalStartingAddrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
disc := &Announce{
|
||||
Peers: make(chan PeersValues, 100),
|
||||
stop: make(chan struct{}),
|
||||
values: make(chan PeersValues),
|
||||
triedAddrs: newBloomFilterForTraversal(),
|
||||
server: s,
|
||||
infoHash: int160FromByteArray(infoHash),
|
||||
announcePort: port,
|
||||
announcePortImplied: impliedPort,
|
||||
}
|
||||
// Function ferries from values to Values until discovery is halted.
|
||||
go func() {
|
||||
defer close(disc.Peers)
|
||||
for {
|
||||
select {
|
||||
case psv := <-disc.values:
|
||||
select {
|
||||
case disc.Peers <- psv:
|
||||
case <-disc.stop:
|
||||
return
|
||||
}
|
||||
case <-disc.stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
disc.mu.Lock()
|
||||
defer disc.mu.Unlock()
|
||||
for i, addr := range startAddrs {
|
||||
if i != 0 {
|
||||
disc.mu.Unlock()
|
||||
time.Sleep(time.Millisecond)
|
||||
disc.mu.Lock()
|
||||
}
|
||||
disc.contact(addr)
|
||||
}
|
||||
disc.contactedStartAddrs = true
|
||||
// If we failed to contact any of the starting addrs, no transactions
|
||||
// will complete triggering a check that there are no pending
|
||||
// responses.
|
||||
disc.maybeClose()
|
||||
}()
|
||||
return disc, nil
|
||||
}
|
||||
|
||||
func validNodeAddr(addr Addr) bool {
|
||||
ua := addr.UDPAddr()
|
||||
if ua.Port == 0 {
|
||||
return false
|
||||
}
|
||||
if ip4 := ua.IP.To4(); ip4 != nil && ip4[0] == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: Merge this with maybeGetPeersFromAddr.
|
||||
func (a *Announce) gotNodeAddr(addr Addr) {
|
||||
if !validNodeAddr(addr) {
|
||||
return
|
||||
}
|
||||
if a.triedAddrs.Test([]byte(addr.String())) {
|
||||
return
|
||||
}
|
||||
if a.server.ipBlocked(addr.UDPAddr().IP) {
|
||||
return
|
||||
}
|
||||
a.contact(addr)
|
||||
}
|
||||
|
||||
// TODO: Merge this with maybeGetPeersFromAddr.
|
||||
func (a *Announce) contact(addr Addr) {
|
||||
a.numContacted++
|
||||
a.triedAddrs.Add([]byte(addr.String()))
|
||||
a.pending++
|
||||
go func() {
|
||||
err := a.getPeers(addr)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
a.mu.Lock()
|
||||
a.transactionClosed()
|
||||
a.mu.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
func (a *Announce) maybeClose() {
|
||||
if a.contactedStartAddrs && a.pending == 0 {
|
||||
a.close()
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Announce) transactionClosed() {
|
||||
a.pending--
|
||||
a.maybeClose()
|
||||
}
|
||||
|
||||
func (a *Announce) responseNode(node krpc.NodeInfo) {
|
||||
a.gotNodeAddr(NewAddr(node.Addr.UDP()))
|
||||
}
|
||||
|
||||
// Announce to a peer, if appropriate.
|
||||
func (a *Announce) maybeAnnouncePeer(to Addr, token string, peerId *krpc.ID) {
|
||||
if !a.server.config.NoSecurity && (peerId == nil || !NodeIdSecure(*peerId, to.UDPAddr().IP)) {
|
||||
return
|
||||
}
|
||||
a.server.mu.Lock()
|
||||
defer a.server.mu.Unlock()
|
||||
err := a.server.announcePeer(to, a.infoHash, a.announcePort, token, a.announcePortImplied, nil)
|
||||
if err != nil {
|
||||
logonce.Stderr.Printf("error announcing peer: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Announce) getPeers(addr Addr) error {
|
||||
a.server.mu.Lock()
|
||||
defer a.server.mu.Unlock()
|
||||
return a.server.getPeers(addr, a.infoHash, func(m krpc.Msg, err error) {
|
||||
// Register suggested nodes closer to the target info-hash.
|
||||
if m.R != nil && m.SenderID() != nil {
|
||||
expvars.Add("announce get_peers response nodes values", int64(len(m.R.Nodes)))
|
||||
expvars.Add("announce get_peers response nodes6 values", int64(len(m.R.Nodes6)))
|
||||
a.mu.Lock()
|
||||
for _, n := range m.R.Nodes {
|
||||
a.responseNode(n)
|
||||
}
|
||||
for _, n := range m.R.Nodes6 {
|
||||
a.responseNode(n)
|
||||
}
|
||||
a.mu.Unlock()
|
||||
select {
|
||||
case a.values <- PeersValues{
|
||||
Peers: m.R.Values,
|
||||
NodeInfo: krpc.NodeInfo{
|
||||
Addr: addr.KRPC(),
|
||||
ID: *m.SenderID(),
|
||||
},
|
||||
}:
|
||||
case <-a.stop:
|
||||
}
|
||||
a.maybeAnnouncePeer(addr, m.R.Token, m.SenderID())
|
||||
}
|
||||
a.mu.Lock()
|
||||
a.transactionClosed()
|
||||
a.mu.Unlock()
|
||||
})
|
||||
}
|
||||
|
||||
// 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.
|
||||
}
|
||||
|
||||
// Stop the announce.
|
||||
func (a *Announce) Close() {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.close()
|
||||
}
|
||||
|
||||
func (a *Announce) close() {
|
||||
select {
|
||||
case <-a.stop:
|
||||
default:
|
||||
close(a.stop)
|
||||
}
|
||||
}
|
37
vendor/github.com/anacrolix/dht/bucket.go
generated
vendored
Normal file
37
vendor/github.com/anacrolix/dht/bucket.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package dht
|
||||
|
||||
type bucket struct {
|
||||
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{}{}
|
||||
}
|
||||
|
||||
func (b *bucket) GetNode(addr Addr, id int160) *node {
|
||||
for n := range b.nodes {
|
||||
if n.hasAddrAndID(addr, id) {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
131
vendor/github.com/anacrolix/dht/dht.go
generated
vendored
Normal file
131
vendor/github.com/anacrolix/dht/dht.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
crand "crypto/rand"
|
||||
_ "crypto/sha1"
|
||||
"errors"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
"github.com/anacrolix/torrent/iplist"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
|
||||
"github.com/anacrolix/dht/krpc"
|
||||
)
|
||||
|
||||
func defaultQueryResendDelay() time.Duration {
|
||||
return jitterDuration(5*time.Second, 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 to set 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 [20]byte
|
||||
Conn net.PacketConn
|
||||
// Don't respond to queries from other nodes.
|
||||
Passive 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, peer Peer)
|
||||
// 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.
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
func GlobalBootstrapAddrs() (addrs []Addr, err error) {
|
||||
for _, s := range []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
|
||||
|
||||
} {
|
||||
host, port, err := net.SplitHostPort(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
hostAddrs, err := net.LookupHost(host)
|
||||
if err != nil {
|
||||
log.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
|
||||
}
|
||||
|
||||
func RandomNodeID() (id [20]byte) {
|
||||
crand.Read(id[:])
|
||||
return
|
||||
}
|
||||
|
||||
func MakeDeterministicNodeID(public net.Addr) (id [20]byte) {
|
||||
h := crypto.SHA1.New()
|
||||
h.Write([]byte(public.String()))
|
||||
h.Sum(id[:0:20])
|
||||
SecureNodeId(&id, missinggo.AddrIP(public))
|
||||
return
|
||||
}
|
22
vendor/github.com/anacrolix/dht/doc.go
generated
vendored
Normal file
22
vendor/github.com/anacrolix/dht/doc.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// Package dht implements a Distributed Hash Table (DHT) part of
|
||||
// the BitTorrent protocol,
|
||||
// as specified by BEP 5: http://www.bittorrent.org/beps/bep_0005.html
|
||||
//
|
||||
// BitTorrent uses a "distributed hash table" (DHT)
|
||||
// for storing peer contact information for "trackerless" torrents.
|
||||
// In effect, each peer becomes a tracker.
|
||||
// The protocol is based on Kademila DHT protocol and is implemented over UDP.
|
||||
//
|
||||
// Please note the terminology used to avoid confusion.
|
||||
// A "peer" is a client/server listening on a TCP port that
|
||||
// implements the BitTorrent protocol.
|
||||
// A "node" is a client/server listening on a UDP port implementing
|
||||
// the distributed hash table protocol.
|
||||
// The DHT is composed of nodes and stores the location of peers.
|
||||
// BitTorrent clients include a DHT node, which is used to contact other nodes
|
||||
// in the DHT to get the location of peers to
|
||||
// download from using the BitTorrent protocol.
|
||||
//
|
||||
// Standard use involves creating a Server, and calling Announce on it with
|
||||
// the details of your local torrent client and infohash of interest.
|
||||
package dht
|
19
vendor/github.com/anacrolix/dht/expvar.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/dht/expvar.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
)
|
||||
|
||||
var (
|
||||
read = expvar.NewInt("dhtRead")
|
||||
readZeroPort = expvar.NewInt("dhtReadZeroPort")
|
||||
readBlocked = expvar.NewInt("dhtReadBlocked")
|
||||
readNotKRPCDict = expvar.NewInt("dhtReadNotKRPCDict")
|
||||
readUnmarshalError = expvar.NewInt("dhtReadUnmarshalError")
|
||||
readQuery = expvar.NewInt("dhtReadQuery")
|
||||
readAnnouncePeer = expvar.NewInt("dhtReadAnnouncePeer")
|
||||
announceErrors = expvar.NewInt("dhtAnnounceErrors")
|
||||
writeErrors = expvar.NewInt("dhtWriteErrors")
|
||||
writes = expvar.NewInt("dhtWrites")
|
||||
expvars = expvar.NewMap("dht")
|
||||
)
|
16
vendor/github.com/anacrolix/dht/go.mod
generated
vendored
Normal file
16
vendor/github.com/anacrolix/dht/go.mod
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
module github.com/anacrolix/dht
|
||||
|
||||
require (
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa
|
||||
github.com/anacrolix/missinggo v0.0.0-20180621131740-7fc7cfea16ea
|
||||
github.com/anacrolix/sync v0.0.0-20180611022320-3c4cb11f5a01
|
||||
github.com/anacrolix/tagflag v0.0.0-20180605133421-f477c8c2f14c
|
||||
github.com/anacrolix/torrent v0.0.0-20180622074351-fefeef4ee9eb
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2
|
||||
github.com/davecgh/go-spew v1.1.0
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/stretchr/testify v1.2.1
|
||||
github.com/willf/bloom v0.0.0-20170505221640-54e3b963ee16
|
||||
)
|
56
vendor/github.com/anacrolix/dht/go.sum
generated
vendored
Normal file
56
vendor/github.com/anacrolix/dht/go.sum
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
|
||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||
github.com/anacrolix/dht v0.0.0-20180412060941-24cbf25b72a4/go.mod h1:hQfX2BrtuQsLQMYQwsypFAab/GvHg8qxwVi4OJdR1WI=
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa h1:xCaATLKmn39QqLs3tUZYr6eKvezJV+FYvVOLTklxK6U=
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||
github.com/anacrolix/go-libutp v0.0.0-20180522111405-6baeb806518d/go.mod h1:beQSaSxwH2d9Eeu5ijrEnHei5Qhk+J6cDm1QkWFru4E=
|
||||
github.com/anacrolix/log v0.0.0-20180412014343-2323884b361d/go.mod h1:sf/7c2aTldL6sRQj/4UKyjgVZBu2+M2z9wf7MmwPiew=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180522035225-b4a5853e62ff/go.mod h1:b0p+7cn+rWMIphK1gDH2hrDuwGOcbB6V4VXeSsEfHVk=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180621131740-7fc7cfea16ea h1:zgemcMeWIWXhwvxFSqVZzW695Q0erYNkfM1X3lZf/8w=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180621131740-7fc7cfea16ea/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s=
|
||||
github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw=
|
||||
github.com/anacrolix/sync v0.0.0-20171108081538-eee974e4f8c1/go.mod h1:+u91KiUuf0lyILI6x3n/XrW7iFROCZCG+TjgK8nW52w=
|
||||
github.com/anacrolix/sync v0.0.0-20180611022320-3c4cb11f5a01 h1:14t4kCoWXaUXrHErRD0bLMNolOE50nyPA0gO8+J3hP8=
|
||||
github.com/anacrolix/sync v0.0.0-20180611022320-3c4cb11f5a01/go.mod h1:+u91KiUuf0lyILI6x3n/XrW7iFROCZCG+TjgK8nW52w=
|
||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||
github.com/anacrolix/tagflag v0.0.0-20180605133421-f477c8c2f14c h1:kBea2eTysvA8qHScuAufErjwV6/wwqoOe03h7W9d1h0=
|
||||
github.com/anacrolix/tagflag v0.0.0-20180605133421-f477c8c2f14c/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||
github.com/anacrolix/torrent v0.0.0-20180622074351-fefeef4ee9eb h1:XTz2SGqfyyk/fvDYPZe3VaZqAH4heDTMz5WQmBm6F5w=
|
||||
github.com/anacrolix/torrent v0.0.0-20180622074351-fefeef4ee9eb/go.mod h1:3vcFVxgOASslNXHdivT8spyMRBanMCenHRpe0u5vpBs=
|
||||
github.com/anacrolix/utp v0.0.0-20180219060659-9e0e1d1d0572/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2 h1:1B/+1BcRhOMG1KH/YhNIU8OppSWk5d/NGyfRla88CuY=
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e h1:Fw7ZmgiklsLh5EQWyHh1sumKSCG1+yjEctIpGKib87s=
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8=
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/gosuri/uilive v0.0.0-20170323041506-ac356e6e42cd/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
|
||||
github.com/gosuri/uiprogress v0.0.0-20170224063937-d0567a9d84a1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
|
||||
github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk=
|
||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/mattn/go-sqlite3 v1.7.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/syncthing/syncthing v0.14.48-rc.4/go.mod h1:nw3siZwHPA6M8iSfjDCWQ402eqvEIasMQOE8nFOxy7M=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/willf/bitset v1.1.3 h1:ekJIKh6+YbUIVt9DfNbkR5d6aFcFTLDRyJNAACURBg8=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/willf/bloom v0.0.0-20170505221640-54e3b963ee16 h1:hDGatoumfYOxzIZGsSylJuxTzu9k86BJl8OQhm72anI=
|
||||
github.com/willf/bloom v0.0.0-20170505221640-54e3b963ee16/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
87
vendor/github.com/anacrolix/dht/int160.go
generated
vendored
Normal file
87
vendor/github.com/anacrolix/dht/int160.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type int160 struct {
|
||||
bits [20]uint8
|
||||
}
|
||||
|
||||
func (me *int160) AsByteArray() [20]byte {
|
||||
return me.bits
|
||||
}
|
||||
|
||||
func (me *int160) ByteString() string {
|
||||
return string(me.bits[:])
|
||||
}
|
||||
|
||||
func (me *int160) BitLen() int {
|
||||
var a big.Int
|
||||
a.SetBytes(me.bits[:])
|
||||
return a.BitLen()
|
||||
}
|
||||
|
||||
func (me *int160) SetBytes(b []byte) {
|
||||
n := copy(me.bits[:], b)
|
||||
if n != 20 {
|
||||
panic(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (me int160) Bytes() []byte {
|
||||
return me.bits[:]
|
||||
}
|
||||
|
||||
func (l int160) Cmp(r int160) 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 *int160) SetMax() {
|
||||
for i := range me.bits {
|
||||
me.bits[i] = math.MaxUint8
|
||||
}
|
||||
}
|
||||
|
||||
func (me *int160) Xor(a, b *int160) {
|
||||
for i := range me.bits {
|
||||
me.bits[i] = a.bits[i] ^ b.bits[i]
|
||||
}
|
||||
}
|
||||
|
||||
func (me *int160) IsZero() bool {
|
||||
for _, b := range me.bits {
|
||||
if b != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func int160FromBytes(b []byte) (ret int160) {
|
||||
ret.SetBytes(b)
|
||||
return
|
||||
}
|
||||
|
||||
func int160FromByteArray(b [20]byte) (ret int160) {
|
||||
ret.SetBytes(b[:])
|
||||
return
|
||||
}
|
||||
|
||||
func int160FromByteString(s string) (ret int160) {
|
||||
ret.SetBytes([]byte(s))
|
||||
return
|
||||
}
|
||||
|
||||
func distance(a, b *int160) (ret int160) {
|
||||
ret.Xor(a, b)
|
||||
return
|
||||
}
|
25
vendor/github.com/anacrolix/dht/krpc/CompactIPv4NodeAddrs.go
generated
vendored
Normal file
25
vendor/github.com/anacrolix/dht/krpc/CompactIPv4NodeAddrs.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package krpc
|
||||
|
||||
type CompactIPv4NodeAddrs []NodeAddr
|
||||
|
||||
func (CompactIPv4NodeAddrs) ElemSize() int { return 6 }
|
||||
|
||||
func (me CompactIPv4NodeAddrs) MarshalBinary() ([]byte, error) {
|
||||
return marshalBinarySlice(me)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
37
vendor/github.com/anacrolix/dht/krpc/CompactIPv4NodeInfo.go
generated
vendored
Normal file
37
vendor/github.com/anacrolix/dht/krpc/CompactIPv4NodeInfo.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package krpc
|
||||
|
||||
import "github.com/anacrolix/missinggo/slices"
|
||||
|
||||
type (
|
||||
CompactIPv4NodeInfo []NodeInfo
|
||||
)
|
||||
|
||||
func (CompactIPv4NodeInfo) ElemSize() int {
|
||||
return 26
|
||||
}
|
||||
|
||||
// func (me *CompactIPv4NodeInfo) Scrub() {
|
||||
// slices.FilterInPlace(me, func(ni *NodeInfo) bool {
|
||||
// ni.Addr.IP = ni.Addr.IP.To4()
|
||||
// return ni.Addr.IP != nil
|
||||
// })
|
||||
// }
|
||||
|
||||
func (me CompactIPv4NodeInfo) MarshalBinary() ([]byte, error) {
|
||||
return marshalBinarySlice(slices.Map(func(ni NodeInfo) NodeInfo {
|
||||
ni.Addr.IP = ni.Addr.IP.To4()
|
||||
return ni
|
||||
}, me).(CompactIPv4NodeInfo))
|
||||
}
|
||||
|
||||
func (me CompactIPv4NodeInfo) MarshalBencode() ([]byte, error) {
|
||||
return bencodeBytesResult(me.MarshalBinary())
|
||||
}
|
||||
|
||||
func (me *CompactIPv4NodeInfo) UnmarshalBinary(b []byte) error {
|
||||
return unmarshalBinarySlice(me, b)
|
||||
}
|
||||
|
||||
func (me *CompactIPv4NodeInfo) UnmarshalBencode(b []byte) error {
|
||||
return unmarshalBencodedBinary(me, b)
|
||||
}
|
30
vendor/github.com/anacrolix/dht/krpc/CompactIPv6NodeAddrs.go
generated
vendored
Normal file
30
vendor/github.com/anacrolix/dht/krpc/CompactIPv6NodeAddrs.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
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
|
||||
}
|
32
vendor/github.com/anacrolix/dht/krpc/CompactIPv6NodeInfo.go
generated
vendored
Normal file
32
vendor/github.com/anacrolix/dht/krpc/CompactIPv6NodeInfo.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"github.com/anacrolix/missinggo/slices"
|
||||
)
|
||||
|
||||
type (
|
||||
CompactIPv6NodeInfo []NodeInfo
|
||||
)
|
||||
|
||||
func (CompactIPv6NodeInfo) ElemSize() int {
|
||||
return 38
|
||||
}
|
||||
|
||||
func (me CompactIPv6NodeInfo) MarshalBinary() ([]byte, error) {
|
||||
return marshalBinarySlice(slices.Map(func(ni NodeInfo) NodeInfo {
|
||||
ni.Addr.IP = ni.Addr.IP.To16()
|
||||
return ni
|
||||
}, me).(CompactIPv6NodeInfo))
|
||||
}
|
||||
|
||||
func (me CompactIPv6NodeInfo) MarshalBencode() ([]byte, error) {
|
||||
return bencodeBytesResult(me.MarshalBinary())
|
||||
}
|
||||
|
||||
func (me *CompactIPv6NodeInfo) UnmarshalBinary(b []byte) error {
|
||||
return unmarshalBinarySlice(me, b)
|
||||
}
|
||||
|
||||
func (me *CompactIPv6NodeInfo) UnmarshalBencode(b []byte) error {
|
||||
return unmarshalBencodedBinary(me, b)
|
||||
}
|
67
vendor/github.com/anacrolix/dht/krpc/compact_helpers.go
generated
vendored
Normal file
67
vendor/github.com/anacrolix/dht/krpc/compact_helpers.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
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()
|
||||
for len(b) != 0 {
|
||||
if len(b) < bytesPerElem {
|
||||
err = fmt.Errorf("%d trailing bytes < %d required for element", len(b), bytesPerElem)
|
||||
break
|
||||
}
|
||||
elem := reflect.New(elemType)
|
||||
err = elem.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b[:bytesPerElem])
|
||||
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)
|
||||
}
|
59
vendor/github.com/anacrolix/dht/krpc/error.go
generated
vendored
Normal file
59
vendor/github.com/anacrolix/dht/krpc/error.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
var ErrorMethodUnknown = Error{
|
||||
Code: 204,
|
||||
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)
|
||||
}
|
36
vendor/github.com/anacrolix/dht/krpc/id.go
generated
vendored
Normal file
36
vendor/github.com/anacrolix/dht/krpc/id.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
)
|
||||
|
||||
type ID [20]byte
|
||||
|
||||
var _ interface {
|
||||
bencode.Marshaler
|
||||
bencode.Unmarshaler
|
||||
} = (*ID)(nil)
|
||||
|
||||
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
|
||||
}
|
85
vendor/github.com/anacrolix/dht/krpc/msg.go
generated
vendored
Normal file
85
vendor/github.com/anacrolix/dht/krpc/msg.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Msg represents messages that nodes in the network send to each other as specified by the protocol.
|
||||
// They are also refered to as the KRPC messages.
|
||||
// There are three types of messages: QUERY, RESPONSE, ERROR
|
||||
// The message is a dictonary 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"`
|
||||
}
|
||||
|
||||
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 string `bencode:"token,omitempty"` // Token received from an earlier get_peers query
|
||||
Port int `bencode:"port,omitempty"` // Senders 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.
|
||||
}
|
||||
|
||||
type Want string
|
||||
|
||||
const (
|
||||
WantNodes Want = "n4"
|
||||
WantNodes6 Want = "n6"
|
||||
)
|
||||
|
||||
type Return struct {
|
||||
ID ID `bencode:"id"` // ID of the querying node
|
||||
Nodes CompactIPv4NodeInfo `bencode:"nodes,omitempty"` // K closest nodes to the requested target
|
||||
Nodes6 CompactIPv6NodeInfo `bencode:"nodes6,omitempty"` // K closest nodes to the requested target
|
||||
Token string `bencode:"token,omitempty"` // Token for future announce_peer
|
||||
Values []NodeAddr `bencode:"values,omitempty"` // Torrent peers
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = Msg{}
|
||||
|
||||
func (m Msg) String() string {
|
||||
return fmt.Sprintf("%#v", m)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (m Msg) Error() *Error {
|
||||
if m.Y != "e" {
|
||||
return nil
|
||||
}
|
||||
return m.E
|
||||
}
|
62
vendor/github.com/anacrolix/dht/krpc/nodeaddr.go
generated
vendored
Normal file
62
vendor/github.com/anacrolix/dht/krpc/nodeaddr.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
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
|
||||
}
|
46
vendor/github.com/anacrolix/dht/krpc/nodeinfo.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/dht/krpc/nodeinfo.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package krpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
)
|
||||
|
||||
type NodeInfo struct {
|
||||
ID [20]byte
|
||||
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:])
|
||||
}
|
20
vendor/github.com/anacrolix/dht/misc.go
generated
vendored
Normal file
20
vendor/github.com/anacrolix/dht/misc.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
57
vendor/github.com/anacrolix/dht/node.go
generated
vendored
Normal file
57
vendor/github.com/anacrolix/dht/node.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/dht/krpc"
|
||||
)
|
||||
|
||||
type nodeKey struct {
|
||||
addr Addr
|
||||
id int160
|
||||
}
|
||||
|
||||
type node struct {
|
||||
nodeKey
|
||||
announceToken string
|
||||
readOnly bool
|
||||
|
||||
lastGotQuery time.Time
|
||||
lastGotResponse time.Time
|
||||
|
||||
consecutiveFailures int
|
||||
}
|
||||
|
||||
func (n *node) hasAddrAndID(addr Addr, id int160) bool {
|
||||
return id == n.id && n.addr.String() == addr.String()
|
||||
}
|
||||
|
||||
func (n *node) IsSecure() bool {
|
||||
return NodeIdSecure(n.id.AsByteArray(), n.addr.UDPAddr().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 (n *node) IsGood() bool {
|
||||
if n.id.IsZero() {
|
||||
return false
|
||||
}
|
||||
if time.Since(n.lastGotResponse) < 15*time.Minute {
|
||||
return true
|
||||
}
|
||||
if !n.lastGotResponse.IsZero() && time.Since(n.lastGotQuery) < 15*time.Minute {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
43
vendor/github.com/anacrolix/dht/nodes_file.go
generated
vendored
Normal file
43
vendor/github.com/anacrolix/dht/nodes_file.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/anacrolix/dht/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, 0640)
|
||||
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
|
||||
}
|
102
vendor/github.com/anacrolix/dht/security.go
generated
vendored
Normal file
102
vendor/github.com/anacrolix/dht/security.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
"net"
|
||||
)
|
||||
|
||||
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 *[20]byte, 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
|
||||
}
|
813
vendor/github.com/anacrolix/dht/server.go
generated
vendored
Normal file
813
vendor/github.com/anacrolix/dht/server.go
generated
vendored
Normal file
@@ -0,0 +1,813 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
"github.com/anacrolix/torrent/bencode"
|
||||
"github.com/anacrolix/torrent/iplist"
|
||||
"github.com/anacrolix/torrent/logonce"
|
||||
"github.com/anacrolix/torrent/metainfo"
|
||||
|
||||
"github.com/anacrolix/dht/krpc"
|
||||
)
|
||||
|
||||
// A Server defines parameters for a DHT node server that is able to send
|
||||
// queries, and respond to the ones from the network. Each node has a globally
|
||||
// unique identifier known as the "node ID." Node IDs are chosen at random
|
||||
// from the same 160-bit space as BitTorrent infohashes and define the
|
||||
// behaviour of the node. Zero valued Server does not have a valid ID and thus
|
||||
// is unable to function properly. Use `NewServer(nil)` to initialize a
|
||||
// default node.
|
||||
type Server struct {
|
||||
id int160
|
||||
socket net.PacketConn
|
||||
|
||||
mu sync.RWMutex
|
||||
transactions map[transactionKey]*Transaction
|
||||
nextT uint64 // unique "t" field for outbound queries
|
||||
table table
|
||||
closed missinggo.Event
|
||||
ipBlockList iplist.Ranger
|
||||
tokenServer tokenServer // Manages tokens we issue to our queriers.
|
||||
config ServerConfig
|
||||
stats ServerStats
|
||||
}
|
||||
|
||||
func (s *Server) numGoodNodes() (num int) {
|
||||
s.table.forNodes(func(n *node) bool {
|
||||
if n.IsGood() {
|
||||
num++
|
||||
}
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func prettySince(t time.Time) string {
|
||||
if t.IsZero() {
|
||||
return "never"
|
||||
}
|
||||
d := time.Since(t)
|
||||
d /= time.Second
|
||||
d *= time.Second
|
||||
return fmt.Sprintf("%s ago", d)
|
||||
}
|
||||
|
||||
func (s *Server) WriteStatus(w io.Writer) {
|
||||
fmt.Fprintf(w, "Listening on %s\n", s.Addr())
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
fmt.Fprintf(w, "Nodes in table: %d good, %d total\n", s.numGoodNodes(), s.numNodes())
|
||||
fmt.Fprintf(w, "Ongoing transactions: %d\n", len(s.transactions))
|
||||
fmt.Fprintf(w, "Server node ID: %x\n", s.id.Bytes())
|
||||
fmt.Fprintln(w)
|
||||
tw := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
|
||||
fmt.Fprintf(tw, "b#\tnode id\taddr\tanntok\tlast query\tlast response\tcf\n")
|
||||
for i, b := range s.table.buckets {
|
||||
b.EachNode(func(n *node) bool {
|
||||
fmt.Fprintf(tw, "%d\t%x\t%s\t%v\t%s\t%s\t%d\n",
|
||||
i,
|
||||
n.id.Bytes(),
|
||||
n.addr,
|
||||
len(n.announceToken),
|
||||
prettySince(n.lastGotQuery),
|
||||
prettySince(n.lastGotResponse),
|
||||
n.consecutiveFailures,
|
||||
)
|
||||
return true
|
||||
})
|
||||
}
|
||||
tw.Flush()
|
||||
}
|
||||
|
||||
func (s *Server) numNodes() (num int) {
|
||||
s.table.forNodes(func(n *node) bool {
|
||||
num++
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Stats returns statistics for the server.
|
||||
func (s *Server) Stats() ServerStats {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
ss := s.stats
|
||||
ss.GoodNodes = s.numGoodNodes()
|
||||
ss.Nodes = s.numNodes()
|
||||
ss.OutstandingTransactions = len(s.transactions)
|
||||
return ss
|
||||
}
|
||||
|
||||
// Addr returns the listen address for the server. Packets arriving to this address
|
||||
// are processed by the server (unless aliens are involved).
|
||||
func (s *Server) Addr() net.Addr {
|
||||
return s.socket.LocalAddr()
|
||||
}
|
||||
|
||||
// NewServer initializes a new DHT node server.
|
||||
func NewServer(c *ServerConfig) (s *Server, err error) {
|
||||
if c == nil {
|
||||
c = &ServerConfig{
|
||||
Conn: mustListen(":0"),
|
||||
NoSecurity: true,
|
||||
StartingNodes: GlobalBootstrapAddrs,
|
||||
}
|
||||
}
|
||||
if missinggo.IsZeroValue(c.NodeId) {
|
||||
c.NodeId = RandomNodeID()
|
||||
if !c.NoSecurity && c.PublicIP != nil {
|
||||
SecureNodeId(&c.NodeId, c.PublicIP)
|
||||
}
|
||||
}
|
||||
s = &Server{
|
||||
config: *c,
|
||||
ipBlockList: c.IPBlocklist,
|
||||
tokenServer: tokenServer{
|
||||
maxIntervalDelta: 2,
|
||||
interval: 5 * time.Minute,
|
||||
secret: make([]byte, 20),
|
||||
},
|
||||
transactions: make(map[transactionKey]*Transaction),
|
||||
table: table{
|
||||
k: 8,
|
||||
},
|
||||
}
|
||||
rand.Read(s.tokenServer.secret)
|
||||
s.socket = c.Conn
|
||||
s.id = int160FromByteArray(c.NodeId)
|
||||
s.table.rootID = s.id
|
||||
go func() {
|
||||
err := s.serve()
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.closed.IsSet() {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
// Returns a description of the Server. Python repr-style.
|
||||
func (s *Server) String() string {
|
||||
return fmt.Sprintf("dht server on %s", s.socket.LocalAddr())
|
||||
}
|
||||
|
||||
// Packets to and from any address matching a range in the list are dropped.
|
||||
func (s *Server) SetIPBlockList(list iplist.Ranger) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.ipBlockList = list
|
||||
}
|
||||
|
||||
func (s *Server) IPBlocklist() iplist.Ranger {
|
||||
return s.ipBlockList
|
||||
}
|
||||
|
||||
func (s *Server) processPacket(b []byte, addr Addr) {
|
||||
if len(b) < 2 || b[0] != 'd' || b[len(b)-1] != 'e' {
|
||||
// KRPC messages are bencoded dicts.
|
||||
readNotKRPCDict.Add(1)
|
||||
return
|
||||
}
|
||||
var d krpc.Msg
|
||||
err := bencode.Unmarshal(b, &d)
|
||||
if err != nil {
|
||||
readUnmarshalError.Add(1)
|
||||
func() {
|
||||
if se, ok := err.(*bencode.SyntaxError); ok {
|
||||
// The message was truncated.
|
||||
if int(se.Offset) == len(b) {
|
||||
return
|
||||
}
|
||||
// Some messages seem to drop to nul chars abrubtly.
|
||||
if int(se.Offset) < len(b) && b[se.Offset] == 0 {
|
||||
return
|
||||
}
|
||||
// The message isn't bencode from the first.
|
||||
if se.Offset == 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
// if missinggo.CryHeard() {
|
||||
// log.Printf("%s: received bad krpc message from %s: %s: %+q", s, addr, err, b)
|
||||
// }
|
||||
}()
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.closed.IsSet() {
|
||||
return
|
||||
}
|
||||
var n *node
|
||||
if sid := d.SenderID(); sid != nil {
|
||||
n, _ = s.getNode(addr, int160FromByteArray(*sid), !d.ReadOnly)
|
||||
if n != nil && d.ReadOnly {
|
||||
n.readOnly = true
|
||||
}
|
||||
}
|
||||
if d.Y == "q" {
|
||||
readQuery.Add(1)
|
||||
s.handleQuery(addr, d)
|
||||
return
|
||||
}
|
||||
t := s.findResponseTransaction(d.T, addr)
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
go t.handleResponse(d)
|
||||
if n != nil {
|
||||
n.lastGotResponse = time.Now()
|
||||
n.consecutiveFailures = 0
|
||||
}
|
||||
s.deleteTransaction(t)
|
||||
}
|
||||
|
||||
func (s *Server) serve() error {
|
||||
var b [0x10000]byte
|
||||
for {
|
||||
n, addr, err := s.socket.ReadFrom(b[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
read.Add(1)
|
||||
if n == len(b) {
|
||||
logonce.Stderr.Printf("received dht packet exceeds buffer size")
|
||||
continue
|
||||
}
|
||||
if missinggo.AddrPort(addr) == 0 {
|
||||
readZeroPort.Add(1)
|
||||
continue
|
||||
}
|
||||
s.mu.Lock()
|
||||
blocked := s.ipBlocked(missinggo.AddrIP(addr))
|
||||
s.mu.Unlock()
|
||||
if blocked {
|
||||
readBlocked.Add(1)
|
||||
continue
|
||||
}
|
||||
s.processPacket(b[:n], NewAddr(addr.(*net.UDPAddr)))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ipBlocked(ip net.IP) (blocked bool) {
|
||||
if s.ipBlockList == nil {
|
||||
return
|
||||
}
|
||||
_, blocked = s.ipBlockList.Lookup(ip)
|
||||
return
|
||||
}
|
||||
|
||||
// Adds directly to the node table.
|
||||
func (s *Server) AddNode(ni krpc.NodeInfo) error {
|
||||
id := int160FromByteArray(ni.ID)
|
||||
if id.IsZero() {
|
||||
return s.Ping(ni.Addr.UDP(), nil)
|
||||
}
|
||||
_, err := s.getNode(NewAddr(ni.Addr.UDP()), int160FromByteArray(ni.ID), true)
|
||||
return err
|
||||
}
|
||||
|
||||
func wantsContain(ws []krpc.Want, w krpc.Want) bool {
|
||||
for _, _w := range ws {
|
||||
if _w == w {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func shouldReturnNodes(queryWants []krpc.Want, querySource net.IP) bool {
|
||||
if len(queryWants) != 0 {
|
||||
return wantsContain(queryWants, krpc.WantNodes)
|
||||
}
|
||||
return querySource.To4() != nil
|
||||
}
|
||||
|
||||
func shouldReturnNodes6(queryWants []krpc.Want, querySource net.IP) bool {
|
||||
if len(queryWants) != 0 {
|
||||
return wantsContain(queryWants, krpc.WantNodes6)
|
||||
}
|
||||
return querySource.To4() == nil
|
||||
}
|
||||
|
||||
func (s *Server) makeReturnNodes(target int160, filter func(krpc.NodeAddr) bool) []krpc.NodeInfo {
|
||||
return s.closestGoodNodeInfos(8, target, filter)
|
||||
}
|
||||
|
||||
func (s *Server) setReturnNodes(r *krpc.Return, queryMsg krpc.Msg, querySource Addr) {
|
||||
target := int160FromByteArray(queryMsg.A.InfoHash)
|
||||
if shouldReturnNodes(queryMsg.A.Want, querySource.UDPAddr().IP) {
|
||||
r.Nodes = s.makeReturnNodes(target, func(na krpc.NodeAddr) bool { return na.IP.To4() != nil })
|
||||
}
|
||||
if shouldReturnNodes6(queryMsg.A.Want, querySource.UDPAddr().IP) {
|
||||
r.Nodes6 = s.makeReturnNodes(target, func(krpc.NodeAddr) bool { return true })
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Probably should write error messages back to senders if something is
|
||||
// wrong.
|
||||
func (s *Server) handleQuery(source Addr, m krpc.Msg) {
|
||||
if m.SenderID() != nil {
|
||||
if n, _ := s.getNode(source, int160FromByteArray(*m.SenderID()), !m.ReadOnly); n != nil {
|
||||
n.lastGotQuery = time.Now()
|
||||
}
|
||||
}
|
||||
if s.config.OnQuery != nil {
|
||||
propagate := s.config.OnQuery(&m, source.UDPAddr())
|
||||
if !propagate {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Don't respond.
|
||||
if s.config.Passive {
|
||||
return
|
||||
}
|
||||
// TODO: Should we disallow replying to ourself?
|
||||
args := m.A
|
||||
switch m.Q {
|
||||
case "ping":
|
||||
s.reply(source, m.T, krpc.Return{})
|
||||
case "get_peers":
|
||||
var r krpc.Return
|
||||
// TODO: Return nodes.
|
||||
s.setReturnNodes(&r, m, source)
|
||||
r.Token = s.createToken(source)
|
||||
s.reply(source, m.T, r)
|
||||
case "find_node":
|
||||
var r krpc.Return
|
||||
s.setReturnNodes(&r, m, source)
|
||||
s.reply(source, m.T, r)
|
||||
case "announce_peer":
|
||||
readAnnouncePeer.Add(1)
|
||||
if !s.validToken(args.Token, source) {
|
||||
expvars.Add("received announce_peer with invalid token", 1)
|
||||
return
|
||||
}
|
||||
expvars.Add("received announce_peer with valid token", 1)
|
||||
if h := s.config.OnAnnouncePeer; h != nil {
|
||||
p := Peer{
|
||||
IP: source.UDPAddr().IP,
|
||||
Port: args.Port,
|
||||
}
|
||||
if args.ImpliedPort {
|
||||
p.Port = source.UDPAddr().Port
|
||||
}
|
||||
go h(metainfo.Hash(args.InfoHash), p)
|
||||
}
|
||||
s.reply(source, m.T, krpc.Return{})
|
||||
default:
|
||||
s.sendError(source, m.T, krpc.ErrorMethodUnknown)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) sendError(addr Addr, t string, e krpc.Error) {
|
||||
m := krpc.Msg{
|
||||
T: t,
|
||||
Y: "e",
|
||||
E: &e,
|
||||
}
|
||||
b, err := bencode.Marshal(m)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = s.writeToNode(b, addr)
|
||||
if err != nil {
|
||||
log.Printf("error replying to %s: %s", addr, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) reply(addr Addr, t string, r krpc.Return) {
|
||||
expvars.Add("replied to peer", 1)
|
||||
r.ID = s.id.AsByteArray()
|
||||
m := krpc.Msg{
|
||||
T: t,
|
||||
Y: "r",
|
||||
R: &r,
|
||||
IP: addr.KRPC(),
|
||||
}
|
||||
b, err := bencode.Marshal(m)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = s.writeToNode(b, addr)
|
||||
if err != nil {
|
||||
log.Printf("error replying to %s: %s", addr, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the node if it's in the routing table, adding it if appropriate.
|
||||
func (s *Server) getNode(addr Addr, id int160, tryAdd bool) (*node, error) {
|
||||
if n := s.table.getNode(addr, id); n != nil {
|
||||
return n, nil
|
||||
}
|
||||
n := &node{nodeKey: nodeKey{
|
||||
id: id,
|
||||
addr: addr,
|
||||
}}
|
||||
// Check that the node would be good to begin with. (It might have a bad
|
||||
// ID or banned address, or we fucked up the initial node field
|
||||
// invariant.)
|
||||
if err := s.nodeErr(n); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !tryAdd {
|
||||
return nil, errors.New("node not present and add flag false")
|
||||
}
|
||||
b := s.table.bucketForID(id)
|
||||
if b.Len() >= s.table.k {
|
||||
if b.EachNode(func(n *node) bool {
|
||||
if s.nodeIsBad(n) {
|
||||
s.table.dropNode(n)
|
||||
}
|
||||
return b.Len() >= s.table.k
|
||||
}) {
|
||||
// No room.
|
||||
return nil, errors.New("no room in bucket")
|
||||
}
|
||||
}
|
||||
if err := s.table.addNode(n); err != nil {
|
||||
panic(fmt.Sprintf("expected to add node: %s", err))
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (s *Server) nodeIsBad(n *node) bool {
|
||||
return s.nodeErr(n) != nil
|
||||
}
|
||||
|
||||
func (s *Server) nodeErr(n *node) error {
|
||||
if n.id == s.id {
|
||||
return errors.New("is self")
|
||||
}
|
||||
if n.id.IsZero() {
|
||||
return errors.New("has zero id")
|
||||
}
|
||||
if !s.config.NoSecurity && !n.IsSecure() {
|
||||
return errors.New("not secure")
|
||||
}
|
||||
if n.IsGood() {
|
||||
return nil
|
||||
}
|
||||
if n.consecutiveFailures >= 3 {
|
||||
return fmt.Errorf("has %d consecutive failures", n.consecutiveFailures)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) writeToNode(b []byte, node Addr) (err error) {
|
||||
if list := s.ipBlockList; list != nil {
|
||||
if r, ok := list.Lookup(missinggo.AddrIP(node.UDPAddr())); ok {
|
||||
err = fmt.Errorf("write to %s blocked: %s", node, r.Description)
|
||||
return
|
||||
}
|
||||
}
|
||||
// log.Printf("writing to %s: %q", node.UDPAddr(), b)
|
||||
n, err := s.socket.WriteTo(b, node.UDPAddr())
|
||||
writes.Add(1)
|
||||
if err != nil {
|
||||
writeErrors.Add(1)
|
||||
err = fmt.Errorf("error writing %d bytes to %s: %s", len(b), node, err)
|
||||
return
|
||||
}
|
||||
if n != len(b) {
|
||||
err = io.ErrShortWrite
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Server) findResponseTransaction(transactionID string, sourceNode Addr) *Transaction {
|
||||
return s.transactions[transactionKey{
|
||||
sourceNode.String(),
|
||||
transactionID}]
|
||||
}
|
||||
|
||||
func (s *Server) nextTransactionID() string {
|
||||
var b [binary.MaxVarintLen64]byte
|
||||
n := binary.PutUvarint(b[:], s.nextT)
|
||||
s.nextT++
|
||||
return string(b[:n])
|
||||
}
|
||||
|
||||
func (s *Server) deleteTransaction(t *Transaction) {
|
||||
delete(s.transactions, t.key())
|
||||
}
|
||||
|
||||
func (s *Server) deleteTransactionUnlocked(t *Transaction) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.deleteTransaction(t)
|
||||
}
|
||||
|
||||
func (s *Server) addTransaction(t *Transaction) {
|
||||
if _, ok := s.transactions[t.key()]; ok {
|
||||
panic("transaction not unique")
|
||||
}
|
||||
s.transactions[t.key()] = t
|
||||
}
|
||||
|
||||
// ID returns the 20-byte server ID. This is the ID used to communicate with the
|
||||
// DHT network.
|
||||
func (s *Server) ID() [20]byte {
|
||||
return s.id.AsByteArray()
|
||||
}
|
||||
|
||||
func (s *Server) createToken(addr Addr) string {
|
||||
return s.tokenServer.CreateToken(addr)
|
||||
}
|
||||
|
||||
func (s *Server) validToken(token string, addr Addr) bool {
|
||||
return s.tokenServer.ValidToken(token, addr)
|
||||
}
|
||||
|
||||
func (s *Server) query(addr Addr, q string, a *krpc.MsgArgs, callback func(krpc.Msg, error)) error {
|
||||
tid := s.nextTransactionID()
|
||||
if a == nil {
|
||||
a = &krpc.MsgArgs{}
|
||||
}
|
||||
if callback == nil {
|
||||
callback = func(krpc.Msg, error) {}
|
||||
}
|
||||
a.ID = s.ID()
|
||||
m := krpc.Msg{
|
||||
T: tid,
|
||||
Y: "q",
|
||||
Q: q,
|
||||
A: a,
|
||||
}
|
||||
// BEP 43. Outgoing queries from passive nodes should contain "ro":1 in
|
||||
// the top level dictionary.
|
||||
if s.config.Passive {
|
||||
m.ReadOnly = true
|
||||
}
|
||||
b, err := bencode.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var t *Transaction
|
||||
t = &Transaction{
|
||||
remoteAddr: addr,
|
||||
t: tid,
|
||||
querySender: func() error {
|
||||
return s.writeToNode(b, addr)
|
||||
},
|
||||
onResponse: func(m krpc.Msg) {
|
||||
go callback(m, nil)
|
||||
go s.deleteTransactionUnlocked(t)
|
||||
},
|
||||
onTimeout: func() {
|
||||
go callback(krpc.Msg{}, errors.New("query timed out"))
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.deleteTransaction(t)
|
||||
for _, n := range s.table.addrNodes(addr) {
|
||||
n.consecutiveFailures++
|
||||
}
|
||||
},
|
||||
onSendError: func(err error) {
|
||||
go callback(krpc.Msg{}, fmt.Errorf("error resending query: %s", err))
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.deleteTransaction(t)
|
||||
for _, n := range s.table.addrNodes(addr) {
|
||||
n.consecutiveFailures++
|
||||
}
|
||||
},
|
||||
queryResendDelay: func() time.Duration {
|
||||
if s.config.QueryResendDelay != nil {
|
||||
return s.config.QueryResendDelay()
|
||||
}
|
||||
return defaultQueryResendDelay()
|
||||
},
|
||||
}
|
||||
s.stats.OutboundQueriesAttempted++
|
||||
err = t.sendQuery()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// s.getNode(node, "").lastSentQuery = time.Now()
|
||||
t.mu.Lock()
|
||||
t.startResendTimer()
|
||||
t.mu.Unlock()
|
||||
s.addTransaction(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sends a ping query to the address given.
|
||||
func (s *Server) Ping(node *net.UDPAddr, callback func(krpc.Msg, error)) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.ping(node, callback)
|
||||
}
|
||||
|
||||
func (s *Server) ping(node *net.UDPAddr, callback func(krpc.Msg, error)) error {
|
||||
return s.query(NewAddr(node), "ping", nil, callback)
|
||||
}
|
||||
|
||||
func (s *Server) announcePeer(node Addr, infoHash int160, port int, token string, impliedPort bool, callback func(krpc.Msg, error)) error {
|
||||
if port == 0 && !impliedPort {
|
||||
return errors.New("nothing to announce")
|
||||
}
|
||||
return s.query(node, "announce_peer", &krpc.MsgArgs{
|
||||
ImpliedPort: impliedPort,
|
||||
InfoHash: infoHash.AsByteArray(),
|
||||
Port: port,
|
||||
Token: token,
|
||||
}, func(m krpc.Msg, err error) {
|
||||
if callback != nil {
|
||||
go callback(m, err)
|
||||
}
|
||||
if err := m.Error(); err != nil {
|
||||
announceErrors.Add(1)
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.stats.SuccessfulOutboundAnnouncePeerQueries++
|
||||
})
|
||||
}
|
||||
|
||||
// Add response nodes to node table.
|
||||
func (s *Server) addResponseNodes(d krpc.Msg) {
|
||||
if d.R == nil {
|
||||
return
|
||||
}
|
||||
for _, cni := range d.R.Nodes {
|
||||
s.getNode(NewAddr(cni.Addr.UDP()), int160FromByteArray(cni.ID), true)
|
||||
}
|
||||
}
|
||||
|
||||
// Sends a find_node query to addr. targetID is the node we're looking for.
|
||||
func (s *Server) findNode(addr Addr, targetID int160, callback func(krpc.Msg, error)) (err error) {
|
||||
return s.query(addr, "find_node", &krpc.MsgArgs{
|
||||
Target: targetID.AsByteArray(),
|
||||
Want: []krpc.Want{krpc.WantNodes, krpc.WantNodes6},
|
||||
}, func(m krpc.Msg, err error) {
|
||||
// Scrape peers from the response to put in the server's table before
|
||||
// handing the response back to the caller.
|
||||
s.mu.Lock()
|
||||
s.addResponseNodes(m)
|
||||
s.mu.Unlock()
|
||||
callback(m, err)
|
||||
})
|
||||
}
|
||||
|
||||
type TraversalStats struct {
|
||||
NumAddrsTried int
|
||||
NumResponses int
|
||||
}
|
||||
|
||||
// Populates the node table.
|
||||
func (s *Server) Bootstrap() (ts TraversalStats, err error) {
|
||||
initialAddrs, err := s.traversalStartingAddrs()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var outstanding sync.WaitGroup
|
||||
triedAddrs := newBloomFilterForTraversal()
|
||||
var onAddr func(addr Addr)
|
||||
onAddr = func(addr Addr) {
|
||||
if triedAddrs.Test([]byte(addr.String())) {
|
||||
return
|
||||
}
|
||||
ts.NumAddrsTried++
|
||||
outstanding.Add(1)
|
||||
triedAddrs.AddString(addr.String())
|
||||
s.findNode(addr, s.id, func(m krpc.Msg, err error) {
|
||||
defer outstanding.Done()
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ts.NumResponses++
|
||||
if r := m.R; r != nil {
|
||||
for _, addr := range r.Nodes {
|
||||
onAddr(NewAddr(addr.Addr.UDP()))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
s.mu.Lock()
|
||||
for _, addr := range initialAddrs {
|
||||
onAddr(addr)
|
||||
}
|
||||
s.mu.Unlock()
|
||||
outstanding.Wait()
|
||||
return
|
||||
}
|
||||
|
||||
// Returns how many nodes are in the node table.
|
||||
func (s *Server) NumNodes() int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.numNodes()
|
||||
}
|
||||
|
||||
// Exports the current node table.
|
||||
func (s *Server) Nodes() (nis []krpc.NodeInfo) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.table.forNodes(func(n *node) bool {
|
||||
nis = append(nis, krpc.NodeInfo{
|
||||
Addr: n.addr.KRPC(),
|
||||
ID: n.id.AsByteArray(),
|
||||
})
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Stops the server network activity. This is all that's required to clean-up a Server.
|
||||
func (s *Server) Close() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.closed.Set()
|
||||
s.socket.Close()
|
||||
}
|
||||
|
||||
func (s *Server) getPeers(addr Addr, infoHash int160, callback func(krpc.Msg, error)) (err error) {
|
||||
return s.query(addr, "get_peers", &krpc.MsgArgs{
|
||||
InfoHash: infoHash.AsByteArray(),
|
||||
Want: []krpc.Want{krpc.WantNodes, krpc.WantNodes6},
|
||||
}, func(m krpc.Msg, err error) {
|
||||
go callback(m, err)
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.addResponseNodes(m)
|
||||
if m.R != nil && m.R.Token != "" && m.SenderID() != nil {
|
||||
if n, _ := s.getNode(addr, int160FromByteArray(*m.SenderID()), false); n != nil {
|
||||
n.announceToken = m.R.Token
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) closestGoodNodeInfos(
|
||||
k int,
|
||||
targetID int160,
|
||||
filter func(krpc.NodeAddr) bool,
|
||||
) (
|
||||
ret []krpc.NodeInfo,
|
||||
) {
|
||||
for _, n := range s.closestNodes(k, targetID, func(n *node) bool {
|
||||
return n.IsGood() && filter(n.NodeInfo().Addr)
|
||||
}) {
|
||||
ret = append(ret, n.NodeInfo())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Server) closestNodes(k int, target int160, filter func(*node) bool) []*node {
|
||||
return s.table.closestNodes(k, target, filter)
|
||||
}
|
||||
|
||||
func (s *Server) traversalStartingAddrs() (addrs []Addr, err error) {
|
||||
s.mu.RLock()
|
||||
s.table.forNodes(func(n *node) bool {
|
||||
addrs = append(addrs, n.addr)
|
||||
return true
|
||||
})
|
||||
s.mu.RUnlock()
|
||||
if len(addrs) > 0 {
|
||||
return
|
||||
}
|
||||
if s.config.StartingNodes != nil {
|
||||
addrs, err = s.config.StartingNodes()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(addrs) == 0 {
|
||||
err = errors.New("no initial nodes")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Server) AddNodesFromFile(fileName string) (added int, err error) {
|
||||
ns, err := ReadNodesFromFile(fileName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, n := range ns {
|
||||
if s.AddNode(n) == nil {
|
||||
added++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
117
vendor/github.com/anacrolix/dht/table.go
generated
vendored
Normal file
117
vendor/github.com/anacrolix/dht/table.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package dht
|
||||
|
||||
import "errors"
|
||||
|
||||
// Node table, with indexes on distance from root ID to bucket, and node addr.
|
||||
type table struct {
|
||||
rootID int160
|
||||
k int
|
||||
buckets [160]bucket
|
||||
addrs map[string]map[int160]struct{}
|
||||
}
|
||||
|
||||
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) *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) int {
|
||||
if id == tbl.rootID {
|
||||
panic("nobody puts the root ID in a bucket")
|
||||
}
|
||||
var a int160
|
||||
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) *node {
|
||||
if id == tbl.rootID {
|
||||
return nil
|
||||
}
|
||||
return tbl.buckets[tbl.bucketIndex(id)].GetNode(addr, id)
|
||||
}
|
||||
|
||||
func (tbl *table) closestNodes(k int, target int160, 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]struct{}, 160*tbl.k)
|
||||
}
|
||||
as := n.addr.String()
|
||||
if tbl.addrs[as] == nil {
|
||||
tbl.addrs[as] = make(map[int160]struct{}, 1)
|
||||
}
|
||||
tbl.addrs[as][n.id] = struct{}{}
|
||||
return nil
|
||||
}
|
57
vendor/github.com/anacrolix/dht/tokens.go
generated
vendored
Normal file
57
vendor/github.com/anacrolix/dht/tokens.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"github.com/bradfitz/iter"
|
||||
)
|
||||
|
||||
// Manages creation and validation of tokens issued to querying nodes.
|
||||
type tokenServer struct {
|
||||
// Something only we know that peers can't guess, so they can't deduce valid tokens.
|
||||
secret []byte
|
||||
// How long between token changes.
|
||||
interval time.Duration
|
||||
// How many intervals may pass between the current interval, and one used to generate a token before it is invalid.
|
||||
maxIntervalDelta int
|
||||
timeNow func() time.Time
|
||||
}
|
||||
|
||||
func (me tokenServer) CreateToken(addr Addr) string {
|
||||
return me.createToken(addr, me.getTimeNow())
|
||||
}
|
||||
|
||||
func (me tokenServer) createToken(addr Addr, t time.Time) string {
|
||||
h := sha1.New()
|
||||
ip := addr.UDPAddr().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()
|
||||
}
|
72
vendor/github.com/anacrolix/dht/transaction.go
generated
vendored
Normal file
72
vendor/github.com/anacrolix/dht/transaction.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
package dht
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/dht/krpc"
|
||||
)
|
||||
|
||||
// Transaction keeps track of a message exchange between nodes, such as a
|
||||
// query message and a response message.
|
||||
type Transaction struct {
|
||||
remoteAddr Addr
|
||||
t string
|
||||
onResponse func(krpc.Msg)
|
||||
onTimeout func()
|
||||
onSendError func(error)
|
||||
querySender func() error
|
||||
queryResendDelay func() time.Duration
|
||||
|
||||
mu sync.Mutex
|
||||
gotResponse bool
|
||||
timer *time.Timer
|
||||
retries int
|
||||
lastSend time.Time
|
||||
}
|
||||
|
||||
func (t *Transaction) handleResponse(m krpc.Msg) {
|
||||
t.mu.Lock()
|
||||
t.gotResponse = true
|
||||
t.mu.Unlock()
|
||||
t.onResponse(m)
|
||||
}
|
||||
|
||||
func (t *Transaction) key() transactionKey {
|
||||
return transactionKey{
|
||||
t.remoteAddr.String(),
|
||||
t.t,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transaction) startResendTimer() {
|
||||
t.timer = time.AfterFunc(t.queryResendDelay(), t.resendCallback)
|
||||
}
|
||||
|
||||
func (t *Transaction) resendCallback() {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.gotResponse {
|
||||
return
|
||||
}
|
||||
if t.retries == 2 {
|
||||
go t.onTimeout()
|
||||
return
|
||||
}
|
||||
t.retries++
|
||||
if err := t.sendQuery(); err != nil {
|
||||
go t.onSendError(err)
|
||||
return
|
||||
}
|
||||
if t.timer.Reset(t.queryResendDelay()) {
|
||||
panic("timer should have fired to get here")
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transaction) sendQuery() error {
|
||||
if err := t.querySender(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.lastSend = time.Now()
|
||||
return nil
|
||||
}
|
19
vendor/github.com/anacrolix/go-libutp/LICENSE
generated
vendored
Normal file
19
vendor/github.com/anacrolix/go-libutp/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
8
vendor/github.com/anacrolix/go-libutp/README.md
generated
vendored
Normal file
8
vendor/github.com/anacrolix/go-libutp/README.md
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# go-libutp
|
||||
|
||||
[](http://godoc.org/github.com/anacrolix/go-libutp)
|
||||
[](https://circleci.com/gh/anacrolix/go-libutp)
|
||||
[](https://goreportcard.com/report/github.com/anacrolix/go-libutp)
|
||||
[](https://ci.appveyor.com/project/anacrolix/go-libutp)
|
||||
|
||||
This is a Go wrapper for [libutp](https://github.com/bittorrent/libutp).
|
21
vendor/github.com/anacrolix/go-libutp/appveyor.yml
generated
vendored
Normal file
21
vendor/github.com/anacrolix/go-libutp/appveyor.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
|
||||
install:
|
||||
- set PATH=%GOPATH%\bin;%PATH%
|
||||
- set PATH=C:\msys64\mingw64\bin;%PATH%
|
||||
- go get github.com/anacrolix/envpprof
|
||||
- go get github.com/anacrolix/tagflag
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get github.com/anacrolix/mmsg
|
||||
- go get golang.org/x/net/nettest
|
||||
- go get github.com/anacrolix/sync
|
||||
|
||||
build_script:
|
||||
- go build -v -x -a
|
||||
|
||||
before_test:
|
||||
- go test -v
|
173
vendor/github.com/anacrolix/go-libutp/callbacks.go
generated
vendored
Normal file
173
vendor/github.com/anacrolix/go-libutp/callbacks.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#include "utp.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"log"
|
||||
"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()
|
||||
addr := structSockaddrToUDPAddr(a.address())
|
||||
newSends := atomic.AddInt64(&sends, 1)
|
||||
if logCallbacks {
|
||||
Logger.Printf("sending %d bytes, %d packets", len(b), newSends)
|
||||
}
|
||||
expMap.Add("socket PacketConn writes", 1)
|
||||
n, err := s.pc.WriteTo(b, addr)
|
||||
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 {
|
||||
Logger.Printf("error sending packet: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if n != len(b) {
|
||||
expMap.Add("socket PacketConn short writes", 1)
|
||||
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 {
|
||||
err := errorForCode(a.error_code())
|
||||
if logCallbacks {
|
||||
log.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 {
|
||||
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 {
|
||||
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 {
|
||||
log.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 {
|
||||
if logCallbacks {
|
||||
log.Printf("accept callback: %#v", *a)
|
||||
}
|
||||
s := getSocketForLibContext(a.context)
|
||||
c := s.newConn(a.socket)
|
||||
c.setRemoteAddr()
|
||||
c.inited = true
|
||||
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.block {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
327
vendor/github.com/anacrolix/go-libutp/conn.go
generated
vendored
Normal file
327
vendor/github.com/anacrolix/go-libutp/conn.go
generated
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#include "utp.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"runtime/pprof"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrConnClosed = errors.New("closed")
|
||||
errConnDestroyed = errors.New("destroyed")
|
||||
)
|
||||
|
||||
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
|
||||
// Corresponds to utp_socket.state != CS_UNITIALIZED. This requires the
|
||||
// utp_socket was obtained from the accept callback, or has had
|
||||
// utp_connect called on it. We can't call utp_close until it's true.
|
||||
inited 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.inited && !c.destroyed && !c.closed {
|
||||
C.utp_close(c.us)
|
||||
}
|
||||
if !c.inited {
|
||||
// We'll never receive a destroy message, so we should remove it now.
|
||||
delete(c.s.conns, 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 errors.New("closed")
|
||||
case !c.readDeadline.IsZero() && !time.Now().Before(c.readDeadline):
|
||||
return errDeadlineExceeded{}
|
||||
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 errDeadlineExceeded{}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
pprof.Do(context.Background(), pprof.Labels("cgo", "utp_write"), func(context.Context) {
|
||||
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)
|
||||
sa, err := anyToSockaddr(&rsa)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.remoteAddr = sockaddrToUDP(sa)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect an unconnected Conn (obtained through Socket.NewConn).
|
||||
func (c *Conn) Connect(ctx context.Context, network, addr string) error {
|
||||
if network == "" {
|
||||
network = c.localAddr.Network()
|
||||
}
|
||||
ua, err := resolveAddr(network, addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error resolving address: %v", err)
|
||||
}
|
||||
sa, sl := netAddrToLibSockaddr(ua)
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if c.s.closed {
|
||||
return errSocketClosed
|
||||
}
|
||||
if n := C.utp_connect(c.us, sa, sl); n != 0 {
|
||||
panic(n)
|
||||
}
|
||||
c.inited = true
|
||||
c.setRemoteAddr()
|
||||
err = c.waitForConnect(ctx)
|
||||
if err != nil {
|
||||
c.close()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) OnError(f func(error)) {
|
||||
mu.Lock()
|
||||
c.userOnError = f
|
||||
mu.Unlock()
|
||||
}
|
11
vendor/github.com/anacrolix/go-libutp/deadline.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/go-libutp/deadline.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package utp
|
||||
|
||||
import "net"
|
||||
|
||||
type errDeadlineExceeded struct{}
|
||||
|
||||
var _ net.Error = errDeadlineExceeded{}
|
||||
|
||||
func (errDeadlineExceeded) Error() string { return "deadline exceeded" }
|
||||
func (errDeadlineExceeded) Temporary() bool { return false }
|
||||
func (errDeadlineExceeded) Timeout() bool { return true }
|
14
vendor/github.com/anacrolix/go-libutp/expvars.go
generated
vendored
Normal file
14
vendor/github.com/anacrolix/go-libutp/expvars.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
)
|
||||
|
||||
var (
|
||||
expMap = expvar.NewMap("go-libutp")
|
||||
socketUtpPacketsReceived = expvar.NewInt("utpSocketUtpPacketsReceived")
|
||||
socketNonUtpPacketsReceived = expvar.NewInt("utpSocketNonUtpPacketsReceived")
|
||||
nonUtpPacketsDropped = expvar.NewInt("utpNonUtpPacketsDropped")
|
||||
multiMsgRecvs = expvar.NewInt("utpMultiMsgRecvs")
|
||||
singleMsgRecvs = expvar.NewInt("utpSingleMsgRecvs")
|
||||
)
|
16
vendor/github.com/anacrolix/go-libutp/go.mod
generated
vendored
Normal file
16
vendor/github.com/anacrolix/go-libutp/go.mod
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
module github.com/anacrolix/go-libutp
|
||||
|
||||
require (
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa
|
||||
github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df
|
||||
github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb
|
||||
github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778
|
||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2
|
||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e
|
||||
github.com/huandu/xstrings v1.0.0
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.2.1
|
||||
golang.org/x/net v0.0.0-20180524181706-dfa909b99c79
|
||||
)
|
36
vendor/github.com/anacrolix/go-libutp/go.sum
generated
vendored
Normal file
36
vendor/github.com/anacrolix/go-libutp/go.sum
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa h1:xCaATLKmn39QqLs3tUZYr6eKvezJV+FYvVOLTklxK6U=
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180522035225-b4a5853e62ff h1:c2Hrwd+LaVrsLJQ5nV8dAP4z6iM0G6aewsbrj3x515s=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180522035225-b4a5853e62ff/go.mod h1:b0p+7cn+rWMIphK1gDH2hrDuwGOcbB6V4VXeSsEfHVk=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df h1:+se8qhX5ivmSCkP+gZXyFx2ETjk1pmnrYJ0Iyc+hZKY=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s=
|
||||
github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb h1:2Or5ccMoY4Kfao+WdL2w6tpY6ZEe+2VTVbIPd7A/Ajk=
|
||||
github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw=
|
||||
github.com/anacrolix/sync v0.0.0-20180725074606-fda11526ff08 h1:w0QQ3EPXGMOFLBRvBk7vCeNkfreNQ5xhTzUIDIEdNm0=
|
||||
github.com/anacrolix/sync v0.0.0-20180725074606-fda11526ff08/go.mod h1:+u91KiUuf0lyILI6x3n/XrW7iFROCZCG+TjgK8nW52w=
|
||||
github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778 h1:XpCDEixzXOB8yaTW/4YBzKrJdMcFI0DzpPTYNv75wzk=
|
||||
github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk=
|
||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0 h1:xcd2GmlPWBsGNjdbwriHXvJJtagl1AnbjTPhJTksJDQ=
|
||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2 h1:1B/+1BcRhOMG1KH/YhNIU8OppSWk5d/NGyfRla88CuY=
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e h1:Fw7ZmgiklsLh5EQWyHh1sumKSCG1+yjEctIpGKib87s=
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk=
|
||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||
github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
golang.org/x/net v0.0.0-20180524181706-dfa909b99c79 h1:1FDlG4HI84rVePw1/0E/crL5tt2N+1blLJpY6UZ6krs=
|
||||
golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
37
vendor/github.com/anacrolix/go-libutp/libapi.go
generated
vendored
Normal file
37
vendor/github.com/anacrolix/go-libutp/libapi.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#include "utp.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/anacrolix/sync"
|
||||
)
|
||||
|
||||
type Option = C.int
|
||||
|
||||
const (
|
||||
LogNormal Option = C.UTP_LOG_NORMAL
|
||||
LogMtu Option = C.UTP_LOG_MTU
|
||||
LogDebug Option = C.UTP_LOG_DEBUG
|
||||
SendBuffer Option = C.UTP_SNDBUF
|
||||
RecvBuffer Option = C.UTP_RCVBUF
|
||||
TargetDelay Option = C.UTP_TARGET_DELAY
|
||||
|
||||
TimedOut = C.UTP_ETIMEDOUT
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
libContextToSocket = map[*C.utp_context]*Socket{}
|
||||
)
|
||||
|
||||
func getSocketForLibContext(uc *C.utp_context) *Socket {
|
||||
return libContextToSocket[uc]
|
||||
}
|
||||
|
||||
func errorForCode(code C.int) error {
|
||||
return errors.New(libErrorCodeNames(code))
|
||||
}
|
65
vendor/github.com/anacrolix/go-libutp/libutp-2012.vcxproj.filters
generated
vendored
Normal file
65
vendor/github.com/anacrolix/go-libutp/libutp-2012.vcxproj.filters
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="utp_templates.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_callbacks.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_hash.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_internal.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_packedsockaddr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp_types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="libutp_inet_ntop.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="utp_api.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_callbacks.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_hash.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_internal.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_packedsockaddr.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utp_utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="libutp_inet_ntop.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
258
vendor/github.com/anacrolix/go-libutp/libutp.vcxproj
generated
vendored
Normal file
258
vendor/github.com/anacrolix/go-libutp/libutp.vcxproj
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="WinRTDebug|Win32">
|
||||
<Configuration>WinRTDebug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="WinRTDebug|x64">
|
||||
<Configuration>WinRTDebug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="WinRTRelease|Win32">
|
||||
<Configuration>WinRTRelease</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="WinRTRelease|x64">
|
||||
<Configuration>WinRTRelease</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="utp_templates.h" />
|
||||
<ClInclude Include="utp.h" />
|
||||
<ClInclude Include="utp_callbacks.h" />
|
||||
<ClInclude Include="utp_hash.h" />
|
||||
<ClInclude Include="utp_internal.h" />
|
||||
<ClInclude Include="utp_packedsockaddr.h" />
|
||||
<ClInclude Include="utp_utils.h" />
|
||||
<ClInclude Include="utp_types.h" />
|
||||
<ClInclude Include="libutp_inet_ntop.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="libutp_inet_ntop.cpp" />
|
||||
<ClCompile Include="utp_api.cpp" />
|
||||
<ClCompile Include="utp_callbacks.cpp" />
|
||||
<ClCompile Include="utp_hash.cpp" />
|
||||
<ClCompile Include="utp_internal.cpp" />
|
||||
<ClCompile Include="utp_packedsockaddr.cpp" />
|
||||
<ClCompile Include="utp_utils.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5984D5CD-6ADD-4EB7-82E7-A555888FBBBD}</ProjectGuid>
|
||||
<RootNamespace>libutp2012</RootNamespace>
|
||||
<ProjectName>libutp</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\win32-2012.props" />
|
||||
<Import Project="prop_sheets\debug-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\win32-2012.props" />
|
||||
<Import Project="prop_sheets\debug-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\x64-2012.props" />
|
||||
<Import Project="prop_sheets\debug-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\x64-2012.props" />
|
||||
<Import Project="prop_sheets\debug-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\win32-2012.props" />
|
||||
<Import Project="prop_sheets\release-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\win32-2012.props" />
|
||||
<Import Project="prop_sheets\release-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\x64-2012.props" />
|
||||
<Import Project="prop_sheets\release-2012.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="prop_sheets\x64-2012.props" />
|
||||
<Import Project="prop_sheets\release-2012.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='WinRTDebug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x501;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='WinRTRelease|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
68
vendor/github.com/anacrolix/go-libutp/libutp_inet_ntop.h
generated
vendored
Normal file
68
vendor/github.com/anacrolix/go-libutp/libutp_inet_ntop.h
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef LIBUTP_INET_NTOP_H
|
||||
#define LIBUTP_INET_NTOP_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// About us linking the system inet_pton and inet_ntop symbols:
|
||||
// 1) These symbols are usually defined on POSIX systems
|
||||
// 2) They are not defined on Windows versions earlier than Vista
|
||||
// Defined in:
|
||||
// ut_utils/src/sockaddr.cpp
|
||||
// libutp/win32_inet_ntop.obj
|
||||
//
|
||||
// When we drop support for XP we can just #include <ws2tcpip.h>, and use the system functions
|
||||
// For now, we will always use our functions on windows, on all builds
|
||||
// The reason is: we would like the debug build to behave as much as the release build as possible
|
||||
// It is much better to catch a problem in the debug build, than to link the system version
|
||||
// in debug, and our version int he wild.
|
||||
|
||||
#if defined(_WIN32_WINNT)
|
||||
#if _WIN32_WINNT >= 0x600 // Win32, post-XP
|
||||
#include <ws2tcpip.h> // for inet_ntop, inet_pton
|
||||
#define INET_NTOP inet_ntop
|
||||
#define INET_PTON inet_pton
|
||||
#else
|
||||
#define INET_NTOP libutp::inet_ntop // Win32, pre-XP: Use ours
|
||||
#define INET_PTON libutp::inet_pton
|
||||
#endif
|
||||
#else // not WIN32
|
||||
#include <arpa/inet.h> // for inet_ntop, inet_pton
|
||||
#define INET_NTOP inet_ntop
|
||||
#define INET_PTON inet_pton
|
||||
#endif
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
namespace libutp {
|
||||
|
||||
|
||||
//######################################################################
|
||||
const char *inet_ntop(int af, const void *src, char *dest, size_t length);
|
||||
|
||||
//######################################################################
|
||||
int inet_pton(int af, const char* src, void* dest);
|
||||
|
||||
|
||||
} //namespace libutp
|
||||
|
||||
#endif // LIBUTP_INET_NTOP_H
|
13
vendor/github.com/anacrolix/go-libutp/logging.go
generated
vendored
Normal file
13
vendor/github.com/anacrolix/go-libutp/logging.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
logCallbacks = false
|
||||
utpLogging = false
|
||||
)
|
||||
|
||||
var Logger = log.New(os.Stderr, "go-libutp: ", log.LstdFlags|log.Lshortfile)
|
288
vendor/github.com/anacrolix/go-libutp/parse_log.py
generated
vendored
Normal file
288
vendor/github.com/anacrolix/go-libutp/parse_log.py
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
import os, sys, time
|
||||
|
||||
# usage: parse_log.py log-file [socket-index to focus on]
|
||||
|
||||
|
||||
socket_filter = None
|
||||
if len(sys.argv) >= 3:
|
||||
socket_filter = sys.argv[2].strip()
|
||||
|
||||
if socket_filter == None:
|
||||
print "scanning for socket with the most packets"
|
||||
file = open(sys.argv[1], 'rb')
|
||||
|
||||
sockets = {}
|
||||
|
||||
for l in file:
|
||||
if not 'our_delay' in l: continue
|
||||
|
||||
try:
|
||||
a = l.strip().split(" ")
|
||||
socket_index = a[1][:-1]
|
||||
except:
|
||||
continue
|
||||
|
||||
# msvc's runtime library doesn't prefix pointers
|
||||
# with '0x'
|
||||
# if socket_index[:2] != '0x':
|
||||
# continue
|
||||
|
||||
if socket_index in sockets:
|
||||
sockets[socket_index] += 1
|
||||
else:
|
||||
sockets[socket_index] = 1
|
||||
|
||||
items = sockets.items()
|
||||
items.sort(lambda x, y: y[1] - x[1])
|
||||
|
||||
count = 0
|
||||
for i in items:
|
||||
print '%s: %d' % (i[0], i[1])
|
||||
count += 1
|
||||
if count > 5: break
|
||||
|
||||
file.close()
|
||||
socket_filter = items[0][0]
|
||||
print '\nfocusing on socket %s' % socket_filter
|
||||
|
||||
file = open(sys.argv[1], 'rb')
|
||||
out_file = 'utp.out%s' % socket_filter;
|
||||
out = open(out_file, 'wb')
|
||||
|
||||
delay_samples = 'dots lc rgb "blue"'
|
||||
delay_base = 'steps lw 2 lc rgb "purple"'
|
||||
target_delay = 'steps lw 2 lc rgb "red"'
|
||||
off_target = 'dots lc rgb "blue"'
|
||||
cwnd = 'steps lc rgb "green"'
|
||||
window_size = 'steps lc rgb "sea-green"'
|
||||
rtt = 'lines lc rgb "light-blue"'
|
||||
|
||||
metrics = {
|
||||
'our_delay':['our delay (ms)', 'x1y2', delay_samples],
|
||||
'upload_rate':['send rate (B/s)', 'x1y1', 'lines'],
|
||||
'max_window':['cwnd (B)', 'x1y1', cwnd],
|
||||
'target_delay':['target delay (ms)', 'x1y2', target_delay],
|
||||
'cur_window':['bytes in-flight (B)', 'x1y1', window_size],
|
||||
'cur_window_packets':['number of packets in-flight', 'x1y2', 'steps'],
|
||||
'packet_size':['current packet size (B)', 'x1y2', 'steps'],
|
||||
'rtt':['rtt (ms)', 'x1y2', rtt],
|
||||
'off_target':['off-target (ms)', 'x1y2', off_target],
|
||||
'delay_sum':['delay sum (ms)', 'x1y2', 'steps'],
|
||||
'their_delay':['their delay (ms)', 'x1y2', delay_samples],
|
||||
'get_microseconds':['clock (us)', 'x1y1', 'steps'],
|
||||
'wnduser':['advertised window size (B)', 'x1y1', 'steps'],
|
||||
|
||||
'delay_base':['delay base (us)', 'x1y1', delay_base],
|
||||
'their_delay_base':['their delay base (us)', 'x1y1', delay_base],
|
||||
'their_actual_delay':['their actual delay (us)', 'x1y1', delay_samples],
|
||||
'actual_delay':['actual_delay (us)', 'x1y1', delay_samples]
|
||||
}
|
||||
|
||||
histogram_quantization = 1
|
||||
socket_index = None
|
||||
|
||||
columns = []
|
||||
|
||||
begin = None
|
||||
|
||||
title = "-"
|
||||
packet_loss = 0
|
||||
packet_timeout = 0
|
||||
|
||||
delay_histogram = {}
|
||||
window_size = {'0': 0, '1': 0}
|
||||
|
||||
# [35301484] 0x00ec1190: actual_delay:1021583 our_delay:102 their_delay:-1021345 off_target:297 max_window:2687 upload_rate:18942 delay_base:1021481154 delay_sum:-1021242 target_delay:400 acked_bytes:1441 cur_window:2882 scaled_gain:2.432
|
||||
|
||||
counter = 0
|
||||
|
||||
print "reading log file"
|
||||
|
||||
for l in file:
|
||||
if "UTP_Connect" in l:
|
||||
title = l[:-2]
|
||||
if socket_filter != None:
|
||||
title += ' socket: %s' % socket_filter
|
||||
else:
|
||||
title += ' sum of all sockets'
|
||||
continue
|
||||
|
||||
try:
|
||||
a = l.strip().split(" ")
|
||||
t = a[0][1:-1]
|
||||
socket_index = a[1][:-1]
|
||||
except:
|
||||
continue
|
||||
# if socket_index[:2] != '0x':
|
||||
# continue
|
||||
|
||||
if socket_filter != None and socket_index != socket_filter:
|
||||
continue
|
||||
|
||||
counter += 1
|
||||
if (counter % 300 == 0):
|
||||
print "\r%d " % counter,
|
||||
|
||||
if "lost." in l:
|
||||
packet_loss = packet_loss + 1
|
||||
continue
|
||||
if "Packet timeout" in l:
|
||||
packet_timeout = packet_timeout + 1
|
||||
continue
|
||||
if "our_delay:" not in l:
|
||||
continue
|
||||
|
||||
# used for Logf timestamps
|
||||
# t, m = t.split(".")
|
||||
# t = time.strptime(t, "%H:%M:%S")
|
||||
# t = list(t)
|
||||
# t[0] += 107
|
||||
# t = tuple(t)
|
||||
# m = float(m)
|
||||
# m /= 1000.0
|
||||
# t = time.mktime(t) + m
|
||||
|
||||
# used for tick count timestamps
|
||||
t = int(t)
|
||||
|
||||
if begin is None:
|
||||
begin = t
|
||||
t = t - begin
|
||||
# print time. Convert from milliseconds to seconds
|
||||
print >>out, '%f\t' % (float(t)/1000.),
|
||||
|
||||
#if t > 200000:
|
||||
# break
|
||||
|
||||
fill_columns = not columns
|
||||
for i in a[2:]:
|
||||
try:
|
||||
n, v = i.split(':')
|
||||
except:
|
||||
continue
|
||||
v = float(v)
|
||||
if n == "our_delay":
|
||||
bucket = v / histogram_quantization
|
||||
delay_histogram[bucket] = 1 + delay_histogram.get(bucket, 0)
|
||||
if not n in metrics: continue
|
||||
if fill_columns:
|
||||
columns.append(n)
|
||||
if n == "max_window":
|
||||
window_size[socket_index] = v
|
||||
print >>out, '%f\t' % int(reduce(lambda a,b: a+b, window_size.values())),
|
||||
else:
|
||||
print >>out, '%f\t' % v,
|
||||
print >>out, float(packet_loss * 8000), float(packet_timeout * 8000)
|
||||
packet_loss = 0
|
||||
packet_timeout = 0
|
||||
|
||||
out.close()
|
||||
|
||||
out = open('%s.histogram' % out_file, 'wb')
|
||||
for d,f in delay_histogram.iteritems():
|
||||
print >>out, float(d*histogram_quantization) + histogram_quantization / 2, f
|
||||
out.close()
|
||||
|
||||
|
||||
plot = [
|
||||
{
|
||||
'data': ['upload_rate', 'max_window', 'cur_window', 'wnduser', 'cur_window_packets', 'packet_size', 'rtt'],
|
||||
'title': 'send-packet-size',
|
||||
'y1': 'Bytes',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['our_delay', 'max_window', 'target_delay', 'cur_window', 'wnduser', 'cur_window_packets'],
|
||||
'title': 'uploading',
|
||||
'y1': 'Bytes',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['our_delay', 'max_window', 'target_delay', 'cur_window', 'cur_window_packets'],
|
||||
'title': 'uploading_packets',
|
||||
'y1': 'Bytes',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['get_microseconds'],
|
||||
'title': 'timer',
|
||||
'y1': 'Time microseconds',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['their_delay', 'target_delay', 'rtt'],
|
||||
'title': 'their_delay',
|
||||
'y1': '',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['their_actual_delay','their_delay_base'],
|
||||
'title': 'their_delay_base',
|
||||
'y1': 'Time (us)',
|
||||
'y2': ''
|
||||
},
|
||||
{
|
||||
'data': ['our_delay', 'target_delay', 'rtt'],
|
||||
'title': 'our-delay',
|
||||
'y1': '',
|
||||
'y2': 'Time (ms)'
|
||||
},
|
||||
{
|
||||
'data': ['actual_delay', 'delay_base'],
|
||||
'title': 'our_delay_base',
|
||||
'y1': 'Time (us)',
|
||||
'y2': ''
|
||||
}
|
||||
]
|
||||
|
||||
out = open('utp.gnuplot', 'w+')
|
||||
|
||||
files = ''
|
||||
|
||||
#print >>out, 'set xtics 0, 20'
|
||||
print >>out, "set term png size 1280,800"
|
||||
print >>out, 'set output "%s.delays.png"' % out_file
|
||||
print >>out, 'set xrange [0:250]'
|
||||
print >>out, 'set xlabel "delay (ms)"'
|
||||
print >>out, 'set boxwidth 1'
|
||||
print >>out, 'set style fill solid'
|
||||
print >>out, 'set ylabel "number of packets"'
|
||||
print >>out, 'plot "%s.histogram" using 1:2 with boxes' % out_file
|
||||
|
||||
print >>out, "set style data steps"
|
||||
#print >>out, "set yrange [0:*]"
|
||||
print >>out, "set y2range [*:*]"
|
||||
files += out_file + '.delays.png '
|
||||
#set hidden3d
|
||||
#set title "Peer bandwidth distribution"
|
||||
#set xlabel "Ratio"
|
||||
|
||||
for p in plot:
|
||||
print >>out, 'set title "%s %s"' % (p['title'], title)
|
||||
print >>out, 'set xlabel "time (s)"'
|
||||
print >>out, 'set ylabel "%s"' % p['y1']
|
||||
print >>out, "set tics nomirror"
|
||||
print >>out, 'set y2tics'
|
||||
print >>out, 'set y2label "%s"' % p['y2']
|
||||
print >>out, 'set xrange [0:*]'
|
||||
print >>out, "set key box"
|
||||
print >>out, "set term png size 1280,800"
|
||||
print >>out, 'set output "%s-%s.png"' % (out_file, p['title'])
|
||||
files += '%s-%s.png ' % (out_file, p['title'])
|
||||
|
||||
comma = ''
|
||||
print >>out, "plot",
|
||||
|
||||
for c in p['data']:
|
||||
if not c in metrics: continue
|
||||
i = columns.index(c)
|
||||
print >>out, '%s"%s" using 1:%d title "%s-%s" axes %s with %s' % (comma, out_file, i + 2, metrics[c][0], metrics[c][1], metrics[c][1], metrics[c][2]),
|
||||
comma = ', '
|
||||
print >>out, ''
|
||||
|
||||
out.close()
|
||||
|
||||
os.system("gnuplot utp.gnuplot")
|
||||
|
||||
os.system("open %s" % files)
|
||||
|
115
vendor/github.com/anacrolix/go-libutp/sockaddr.go
generated
vendored
Normal file
115
vendor/github.com/anacrolix/go-libutp/sockaddr.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
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) (*C.struct_sockaddr, C.socklen_t) {
|
||||
if ip4 := ip.To4(); ip4 != nil && zone == "" {
|
||||
rsa := syscall.RawSockaddrInet4{
|
||||
// Len: syscall.SizeofSockaddrInet4,
|
||||
Family: syscall.AF_INET,
|
||||
Port: uint16(port),
|
||||
}
|
||||
if n := copy(rsa.Addr[:], ip4); n != 4 {
|
||||
panic(n)
|
||||
}
|
||||
return (*C.struct_sockaddr)(unsafe.Pointer(&rsa)), C.socklen_t(unsafe.Sizeof(rsa))
|
||||
}
|
||||
rsa := syscall.RawSockaddrInet6{
|
||||
// Len: syscall.SizeofSockaddrInet6,
|
||||
Family: syscall.AF_INET6,
|
||||
Scope_id: zoneToScopeId(zone),
|
||||
Port: uint16(port),
|
||||
}
|
||||
if ip != nil {
|
||||
if n := copy(rsa.Addr[:], ip); n != 16 {
|
||||
panic(n)
|
||||
}
|
||||
}
|
||||
return (*C.struct_sockaddr)(unsafe.Pointer(&rsa)), C.socklen_t(unsafe.Sizeof(rsa))
|
||||
}
|
||||
|
||||
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) *net.UDPAddr {
|
||||
meh, err := anyToSockaddr((*syscall.RawSockaddrAny)(unsafe.Pointer(sa)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sockaddrToUDP(meh).(*net.UDPAddr)
|
||||
}
|
||||
|
||||
func anyToSockaddr(rsa *syscall.RawSockaddrAny) (syscall.Sockaddr, error) {
|
||||
// log.Printf("anyToSockaddr %#v", rsa)
|
||||
switch rsa.Addr.Family {
|
||||
|
||||
case syscall.AF_INET:
|
||||
pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||||
sa := new(syscall.SockaddrInet4)
|
||||
// p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
// sa.Port = int(p[0])<<8 + int(p[1])
|
||||
// I don't know why the port isn't reversed when it comes from utp.
|
||||
sa.Port = int(pp.Port)
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
|
||||
case syscall.AF_INET6:
|
||||
pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
|
||||
sa := new(syscall.SockaddrInet6)
|
||||
// p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
// sa.Port = int(p[0])<<8 + int(p[1])
|
||||
// I don't know why the port isn't reversed when it comes from utp.
|
||||
sa.Port = int(pp.Port)
|
||||
sa.ZoneId = pp.Scope_id
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, nil
|
||||
}
|
||||
return nil, 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) (*C.struct_sockaddr, C.socklen_t) {
|
||||
switch v := na.(type) {
|
||||
case *net.UDPAddr:
|
||||
return toSockaddrInet(v.IP, v.Port, v.Zone)
|
||||
case inproc.Addr:
|
||||
rsa := syscall.RawSockaddrInet6{
|
||||
Port: uint16(v.Port),
|
||||
}
|
||||
return (*C.struct_sockaddr)(unsafe.Pointer(&rsa)), C.socklen_t(unsafe.Sizeof(rsa))
|
||||
default:
|
||||
panic(na)
|
||||
}
|
||||
}
|
454
vendor/github.com/anacrolix/go-libutp/socket.go
generated
vendored
Normal file
454
vendor/github.com/anacrolix/go-libutp/socket.go
generated
vendored
Normal file
@@ -0,0 +1,454 @@
|
||||
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"
|
||||
"net"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
"github.com/anacrolix/missinggo/inproc"
|
||||
"github.com/anacrolix/mmsg"
|
||||
)
|
||||
|
||||
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
|
||||
firewallCallback FirewallCallback
|
||||
// Whether the next accept is to be blocked.
|
||||
block bool
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func NewSocket(network, addr string) (*Socket, error) {
|
||||
pc, err := listenPacket(network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
ctx := C.utp_init(2)
|
||||
if ctx == nil {
|
||||
panic(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)
|
||||
}
|
||||
s := &Socket{
|
||||
pc: pc,
|
||||
ctx: ctx,
|
||||
backlog: make(chan *Conn, 5),
|
||||
conns: make(map[*C.utp_socket]*Conn),
|
||||
nonUtpReads: make(chan packet, 100),
|
||||
}
|
||||
libContextToSocket[ctx] = s
|
||||
go s.timeoutChecker()
|
||||
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.
|
||||
Logger.Printf("ignoring socket read error: %s", err)
|
||||
consecutiveErrors++
|
||||
if consecutiveErrors >= 100 {
|
||||
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)
|
||||
a.sa, a.sal = netAddrToLibSockaddr(m.Addr)
|
||||
}
|
||||
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() {
|
||||
pprof.Do(context.Background(), pprof.Labels("go-libutp", "afterReceivingUtpMessages"), func(context.Context) {
|
||||
C.utp_issue_deferred_acks(s.ctx)
|
||||
// TODO: When is this done in C?
|
||||
C.utp_check_timeouts(s.ctx)
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// Wraps libutp's utp_process_udp, returning relevant information.
|
||||
func (s *Socket) utpProcessUdp(b []byte, addr net.Addr) (utp bool) {
|
||||
sa, sal := netAddrToLibSockaddr(addr)
|
||||
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()
|
||||
block := func() bool {
|
||||
if s.firewallCallback == nil {
|
||||
return false
|
||||
}
|
||||
return s.firewallCallback(addr)
|
||||
}()
|
||||
mu.Lock()
|
||||
s.block = block
|
||||
if s.closed {
|
||||
return false
|
||||
}
|
||||
ret := C.utp_process_udp(s.ctx, (*C.byte)(&b[0]), C.size_t(len(b)), sa, sal)
|
||||
switch ret {
|
||||
case 1:
|
||||
return true
|
||||
case 0:
|
||||
return false
|
||||
default:
|
||||
panic(ret)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Socket) timeoutChecker() {
|
||||
for {
|
||||
mu.Lock()
|
||||
if s.closed {
|
||||
mu.Unlock()
|
||||
return
|
||||
}
|
||||
// C.utp_issue_deferred_acks(s.ctx)
|
||||
C.utp_check_timeouts(s.ctx)
|
||||
mu.Unlock()
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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, error) {
|
||||
c, err := s.NewConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = c.Connect(ctx, network, addr)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (s *Socket) NewConn() (*Conn, error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if s.closed {
|
||||
return nil, errors.New("socket closed")
|
||||
}
|
||||
return s.newConn(C.utp_create_socket(s.ctx)), nil
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
func (s *Socket) SetFirewallCallback(f FirewallCallback) {
|
||||
mu.Lock()
|
||||
s.firewallCallback = f
|
||||
mu.Unlock()
|
||||
}
|
17
vendor/github.com/anacrolix/go-libutp/status.go
generated
vendored
Normal file
17
vendor/github.com/anacrolix/go-libutp/status.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package utp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func WriteStatus(w io.Writer) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, s := range libContextToSocket {
|
||||
fmt.Fprintf(w, "listening at %s\n", s.Addr())
|
||||
fmt.Fprintf(w, "has %d conns\n", len(s.conns))
|
||||
fmt.Fprintf(w, "backlog: %d\n", len(s.backlog))
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
}
|
50
vendor/github.com/anacrolix/go-libutp/utp.go
generated
vendored
Normal file
50
vendor/github.com/anacrolix/go-libutp/utp.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package utp
|
||||
|
||||
/*
|
||||
#cgo CPPFLAGS: -DPOSIX -DUTP_DEBUG_LOGGING=0
|
||||
#cgo CFLAGS: -Wall -O3
|
||||
// These are all copied from the libutp Makefile.
|
||||
#cgo CXXFLAGS: -Wall -O3 -fPIC -Wno-sign-compare
|
||||
// There are some variables that aren't used unless UTP_DEBUG_LOGGING is defined.
|
||||
#cgo CXXFLAGS: -Wno-unused-const-variable
|
||||
// Windows additional flags
|
||||
#cgo windows LDFLAGS: -lws2_32
|
||||
#cgo windows CXXFLAGS: -D_WIN32_WINNT=0x600
|
||||
#include "utp.h"
|
||||
|
||||
uint64_t firewallCallback(utp_callback_arguments *);
|
||||
uint64_t errorCallback(utp_callback_arguments *);
|
||||
uint64_t logCallback(utp_callback_arguments *);
|
||||
uint64_t acceptCallback(utp_callback_arguments *);
|
||||
uint64_t sendtoCallback(utp_callback_arguments *);
|
||||
uint64_t stateChangeCallback(utp_callback_arguments *);
|
||||
uint64_t readCallback(utp_callback_arguments *);
|
||||
uint64_t getReadBufferSizeCallback(utp_callback_arguments *);
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
type socklen C.socklen_t
|
||||
|
||||
func (ctx *C.utp_context) setCallbacks() {
|
||||
C.utp_set_callback(ctx, C.UTP_ON_FIREWALL, (*C.utp_callback_t)(C.firewallCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_LOG, (*C.utp_callback_t)(C.logCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_ON_ACCEPT, (*C.utp_callback_t)(C.acceptCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_SENDTO, (*C.utp_callback_t)(C.sendtoCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_ON_STATE_CHANGE, (*C.utp_callback_t)(C.stateChangeCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_ON_READ, (*C.utp_callback_t)(C.readCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_ON_ERROR, (*C.utp_callback_t)(C.errorCallback))
|
||||
C.utp_set_callback(ctx, C.UTP_GET_READ_BUFFER_SIZE, (*C.utp_callback_t)(C.getReadBufferSizeCallback))
|
||||
}
|
||||
|
||||
func (ctx *C.utp_context) setOption(opt Option, val int) int {
|
||||
return int(C.utp_context_set_option(ctx, opt, C.int(val)))
|
||||
}
|
||||
|
||||
func libStateName(state C.int) string {
|
||||
return C.GoString((*[5]*C.char)(unsafe.Pointer(&C.utp_state_names))[state])
|
||||
}
|
||||
|
||||
func libErrorCodeNames(error_code C.int) string {
|
||||
return C.GoString((*[3]*C.char)(unsafe.Pointer(&C.utp_error_code_names))[error_code])
|
||||
}
|
187
vendor/github.com/anacrolix/go-libutp/utp.h
generated
vendored
Normal file
187
vendor/github.com/anacrolix/go-libutp/utp.h
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_H__
|
||||
#define __UTP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "utp_types.h"
|
||||
|
||||
typedef struct UTPSocket utp_socket;
|
||||
typedef struct struct_utp_context utp_context;
|
||||
|
||||
enum {
|
||||
UTP_UDP_DONTFRAG = 2, // Used to be a #define as UDP_IP_DONTFRAG
|
||||
};
|
||||
|
||||
enum {
|
||||
// socket has reveived syn-ack (notification only for outgoing connection completion)
|
||||
// this implies writability
|
||||
UTP_STATE_CONNECT = 1,
|
||||
|
||||
// socket is able to send more data
|
||||
UTP_STATE_WRITABLE = 2,
|
||||
|
||||
// connection closed
|
||||
UTP_STATE_EOF = 3,
|
||||
|
||||
// socket is being destroyed, meaning all data has been sent if possible.
|
||||
// it is not valid to refer to the socket after this state change occurs
|
||||
UTP_STATE_DESTROYING = 4,
|
||||
};
|
||||
|
||||
extern const char *utp_state_names[];
|
||||
|
||||
// Errors codes that can be passed to UTP_ON_ERROR callback
|
||||
enum {
|
||||
UTP_ECONNREFUSED = 0,
|
||||
UTP_ECONNRESET,
|
||||
UTP_ETIMEDOUT,
|
||||
};
|
||||
|
||||
extern const char *utp_error_code_names[];
|
||||
|
||||
enum {
|
||||
// callback names
|
||||
UTP_ON_FIREWALL = 0,
|
||||
UTP_ON_ACCEPT,
|
||||
UTP_ON_CONNECT,
|
||||
UTP_ON_ERROR,
|
||||
UTP_ON_READ,
|
||||
UTP_ON_OVERHEAD_STATISTICS,
|
||||
UTP_ON_STATE_CHANGE,
|
||||
UTP_GET_READ_BUFFER_SIZE,
|
||||
UTP_ON_DELAY_SAMPLE,
|
||||
UTP_GET_UDP_MTU,
|
||||
UTP_GET_UDP_OVERHEAD,
|
||||
UTP_GET_MILLISECONDS,
|
||||
UTP_GET_MICROSECONDS,
|
||||
UTP_GET_RANDOM,
|
||||
UTP_LOG,
|
||||
UTP_SENDTO,
|
||||
|
||||
// context and socket options that may be set/queried
|
||||
UTP_LOG_NORMAL,
|
||||
UTP_LOG_MTU,
|
||||
UTP_LOG_DEBUG,
|
||||
UTP_SNDBUF,
|
||||
UTP_RCVBUF,
|
||||
UTP_TARGET_DELAY,
|
||||
|
||||
UTP_ARRAY_SIZE, // must be last
|
||||
};
|
||||
|
||||
extern const char *utp_callback_names[];
|
||||
|
||||
typedef struct {
|
||||
utp_context *context;
|
||||
utp_socket *socket;
|
||||
size_t len;
|
||||
uint32 flags;
|
||||
int callback_type;
|
||||
const byte *buf;
|
||||
|
||||
union {
|
||||
const struct sockaddr *address;
|
||||
int send;
|
||||
int sample_ms;
|
||||
int error_code;
|
||||
int state;
|
||||
};
|
||||
|
||||
union {
|
||||
socklen_t address_len;
|
||||
int type;
|
||||
};
|
||||
} utp_callback_arguments;
|
||||
|
||||
typedef uint64 utp_callback_t(utp_callback_arguments *);
|
||||
|
||||
// Returned by utp_get_context_stats()
|
||||
typedef struct {
|
||||
uint32 _nraw_recv[5]; // total packets recieved less than 300/600/1200/MTU bytes fpr all connections (context-wide)
|
||||
uint32 _nraw_send[5]; // total packets sent less than 300/600/1200/MTU bytes for all connections (context-wide)
|
||||
} utp_context_stats;
|
||||
|
||||
// Returned by utp_get_stats()
|
||||
typedef struct {
|
||||
uint64 nbytes_recv; // total bytes received
|
||||
uint64 nbytes_xmit; // total bytes transmitted
|
||||
uint32 rexmit; // retransmit counter
|
||||
uint32 fastrexmit; // fast retransmit counter
|
||||
uint32 nxmit; // transmit counter
|
||||
uint32 nrecv; // receive counter (total)
|
||||
uint32 nduprecv; // duplicate receive counter
|
||||
uint32 mtu_guess; // Best guess at MTU
|
||||
} utp_socket_stats;
|
||||
|
||||
#define UTP_IOV_MAX 1024
|
||||
|
||||
// For utp_writev, to writes data from multiple buffers
|
||||
struct utp_iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
// Public Functions
|
||||
utp_context* utp_init (int version);
|
||||
void utp_destroy (utp_context *ctx);
|
||||
void utp_set_callback (utp_context *ctx, int callback_name, utp_callback_t *proc);
|
||||
void* utp_context_set_userdata (utp_context *ctx, void *userdata);
|
||||
void* utp_context_get_userdata (utp_context *ctx);
|
||||
int utp_context_set_option (utp_context *ctx, int opt, int val);
|
||||
int utp_context_get_option (utp_context *ctx, int opt);
|
||||
int utp_process_udp (utp_context *ctx, const byte *buf, size_t len, const struct sockaddr *to, socklen_t tolen);
|
||||
int utp_process_icmp_error (utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
|
||||
int utp_process_icmp_fragmentation (utp_context *ctx, const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen, uint16 next_hop_mtu);
|
||||
void utp_check_timeouts (utp_context *ctx);
|
||||
void utp_issue_deferred_acks (utp_context *ctx);
|
||||
utp_context_stats* utp_get_context_stats (utp_context *ctx);
|
||||
utp_socket* utp_create_socket (utp_context *ctx);
|
||||
void* utp_set_userdata (utp_socket *s, void *userdata);
|
||||
void* utp_get_userdata (utp_socket *s);
|
||||
int utp_setsockopt (utp_socket *s, int opt, int val);
|
||||
int utp_getsockopt (utp_socket *s, int opt);
|
||||
int utp_connect (utp_socket *s, const struct sockaddr *to, socklen_t tolen);
|
||||
ssize_t utp_write (utp_socket *s, void *buf, size_t count);
|
||||
ssize_t utp_writev (utp_socket *s, struct utp_iovec *iovec, size_t num_iovecs);
|
||||
int utp_getpeername (utp_socket *s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
void utp_read_drained (utp_socket *s);
|
||||
int utp_get_delays (utp_socket *s, uint32 *ours, uint32 *theirs, uint32 *age);
|
||||
utp_socket_stats* utp_get_stats (utp_socket *s);
|
||||
utp_context* utp_get_context (utp_socket *s);
|
||||
void utp_shutdown (utp_socket *s, int how);
|
||||
void utp_close (utp_socket *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__UTP_H__
|
139
vendor/github.com/anacrolix/go-libutp/utp_api.cpp
generated
vendored
Normal file
139
vendor/github.com/anacrolix/go-libutp/utp_api.cpp
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "utp_internal.h"
|
||||
#include "utp_utils.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
const char * utp_callback_names[] = {
|
||||
"UTP_ON_FIREWALL",
|
||||
"UTP_ON_ACCEPT",
|
||||
"UTP_ON_CONNECT",
|
||||
"UTP_ON_ERROR",
|
||||
"UTP_ON_READ",
|
||||
"UTP_ON_OVERHEAD_STATISTICS",
|
||||
"UTP_ON_STATE_CHANGE",
|
||||
"UTP_GET_READ_BUFFER_SIZE",
|
||||
"UTP_ON_DELAY_SAMPLE",
|
||||
"UTP_GET_UDP_MTU",
|
||||
"UTP_GET_UDP_OVERHEAD",
|
||||
"UTP_GET_MILLISECONDS",
|
||||
"UTP_GET_MICROSECONDS",
|
||||
"UTP_GET_RANDOM",
|
||||
"UTP_LOG",
|
||||
"UTP_SENDTO",
|
||||
};
|
||||
|
||||
const char * utp_error_code_names[] = {
|
||||
"UTP_ECONNREFUSED",
|
||||
"UTP_ECONNRESET",
|
||||
"UTP_ETIMEDOUT",
|
||||
};
|
||||
|
||||
const char *utp_state_names[] = {
|
||||
NULL,
|
||||
"UTP_STATE_CONNECT",
|
||||
"UTP_STATE_WRITABLE",
|
||||
"UTP_STATE_EOF",
|
||||
"UTP_STATE_DESTROYING",
|
||||
};
|
||||
|
||||
struct_utp_context::struct_utp_context()
|
||||
: userdata(NULL)
|
||||
, current_ms(0)
|
||||
, last_utp_socket(NULL)
|
||||
, log_normal(false)
|
||||
, log_mtu(false)
|
||||
, log_debug(false)
|
||||
{
|
||||
memset(&context_stats, 0, sizeof(context_stats));
|
||||
memset(callbacks, 0, sizeof(callbacks));
|
||||
target_delay = CCONTROL_TARGET;
|
||||
utp_sockets = new UTPSocketHT;
|
||||
|
||||
callbacks[UTP_GET_UDP_MTU] = &utp_default_get_udp_mtu;
|
||||
callbacks[UTP_GET_UDP_OVERHEAD] = &utp_default_get_udp_overhead;
|
||||
callbacks[UTP_GET_MILLISECONDS] = &utp_default_get_milliseconds;
|
||||
callbacks[UTP_GET_MICROSECONDS] = &utp_default_get_microseconds;
|
||||
callbacks[UTP_GET_RANDOM] = &utp_default_get_random;
|
||||
|
||||
// 1 MB of receive buffer (i.e. max bandwidth delay product)
|
||||
// means that from a peer with 200 ms RTT, we cannot receive
|
||||
// faster than 5 MB/s
|
||||
// from a peer with 10 ms RTT, we cannot receive faster than
|
||||
// 100 MB/s. This is assumed to be good enough, since bandwidth
|
||||
// often is proportional to RTT anyway
|
||||
// when setting a download rate limit, all sockets should have
|
||||
// their receive buffer set much lower, to say 60 kiB or so
|
||||
opt_rcvbuf = opt_sndbuf = 1024 * 1024;
|
||||
last_check = 0;
|
||||
}
|
||||
|
||||
struct_utp_context::~struct_utp_context() {
|
||||
delete this->utp_sockets;
|
||||
}
|
||||
|
||||
utp_context* utp_init (int version)
|
||||
{
|
||||
assert(version == 2);
|
||||
if (version != 2)
|
||||
return NULL;
|
||||
utp_context *ctx = new utp_context;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void utp_destroy(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
if (ctx) delete ctx;
|
||||
}
|
||||
|
||||
void utp_set_callback(utp_context *ctx, int callback_name, utp_callback_t *proc) {
|
||||
assert(ctx);
|
||||
if (ctx) ctx->callbacks[callback_name] = proc;
|
||||
}
|
||||
|
||||
void* utp_context_set_userdata(utp_context *ctx, void *userdata) {
|
||||
assert(ctx);
|
||||
if (ctx) ctx->userdata = userdata;
|
||||
return ctx ? ctx->userdata : NULL;
|
||||
}
|
||||
|
||||
void* utp_context_get_userdata(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
return ctx ? ctx->userdata : NULL;
|
||||
}
|
||||
|
||||
utp_context_stats* utp_get_context_stats(utp_context *ctx) {
|
||||
assert(ctx);
|
||||
return ctx ? &ctx->context_stats : NULL;
|
||||
}
|
||||
|
||||
ssize_t utp_write(utp_socket *socket, void *buf, size_t len) {
|
||||
struct utp_iovec iovec = { buf, len };
|
||||
return utp_writev(socket, &iovec, 1);
|
||||
}
|
||||
|
||||
}
|
208
vendor/github.com/anacrolix/go-libutp/utp_callbacks.cpp
generated
vendored
Normal file
208
vendor/github.com/anacrolix/go-libutp/utp_callbacks.cpp
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "utp_callbacks.h"
|
||||
|
||||
int utp_call_on_firewall(utp_context *ctx, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_FIREWALL]) return 0;
|
||||
args.callback_type = UTP_ON_FIREWALL;
|
||||
args.context = ctx;
|
||||
args.socket = NULL;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (int)ctx->callbacks[UTP_ON_FIREWALL](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_accept(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_ACCEPT]) return;
|
||||
args.callback_type = UTP_ON_ACCEPT;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
ctx->callbacks[UTP_ON_ACCEPT](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_connect(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_CONNECT]) return;
|
||||
args.callback_type = UTP_ON_CONNECT;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
ctx->callbacks[UTP_ON_CONNECT](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_error(utp_context *ctx, utp_socket *socket, int error_code)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_ERROR]) return;
|
||||
args.callback_type = UTP_ON_ERROR;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.error_code = error_code;
|
||||
ctx->callbacks[UTP_ON_ERROR](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_read(utp_context *ctx, utp_socket *socket, const byte *buf, size_t len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_READ]) return;
|
||||
args.callback_type = UTP_ON_READ;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
args.len = len;
|
||||
ctx->callbacks[UTP_ON_READ](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_overhead_statistics(utp_context *ctx, utp_socket *socket, int send, size_t len, int type)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS]) return;
|
||||
args.callback_type = UTP_ON_OVERHEAD_STATISTICS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.send = send;
|
||||
args.len = len;
|
||||
args.type = type;
|
||||
ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_delay_sample(utp_context *ctx, utp_socket *socket, int sample_ms)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_DELAY_SAMPLE]) return;
|
||||
args.callback_type = UTP_ON_DELAY_SAMPLE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.sample_ms = sample_ms;
|
||||
ctx->callbacks[UTP_ON_DELAY_SAMPLE](&args);
|
||||
}
|
||||
|
||||
void utp_call_on_state_change(utp_context *ctx, utp_socket *socket, int state)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_ON_STATE_CHANGE]) return;
|
||||
args.callback_type = UTP_ON_STATE_CHANGE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.state = state;
|
||||
ctx->callbacks[UTP_ON_STATE_CHANGE](&args);
|
||||
}
|
||||
|
||||
uint16 utp_call_get_udp_mtu(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_UDP_MTU]) return 0;
|
||||
args.callback_type = UTP_GET_UDP_MTU;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (uint16)ctx->callbacks[UTP_GET_UDP_MTU](&args);
|
||||
}
|
||||
|
||||
uint16 utp_call_get_udp_overhead(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_UDP_OVERHEAD]) return 0;
|
||||
args.callback_type = UTP_GET_UDP_OVERHEAD;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
return (uint16)ctx->callbacks[UTP_GET_UDP_OVERHEAD](&args);
|
||||
}
|
||||
|
||||
uint64 utp_call_get_milliseconds(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_MILLISECONDS]) return 0;
|
||||
args.callback_type = UTP_GET_MILLISECONDS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return ctx->callbacks[UTP_GET_MILLISECONDS](&args);
|
||||
}
|
||||
|
||||
uint64 utp_call_get_microseconds(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_MICROSECONDS]) return 0;
|
||||
args.callback_type = UTP_GET_MICROSECONDS;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return ctx->callbacks[UTP_GET_MICROSECONDS](&args);
|
||||
}
|
||||
|
||||
uint32 utp_call_get_random(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_RANDOM]) return 0;
|
||||
args.callback_type = UTP_GET_RANDOM;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return (uint32)ctx->callbacks[UTP_GET_RANDOM](&args);
|
||||
}
|
||||
|
||||
size_t utp_call_get_read_buffer_size(utp_context *ctx, utp_socket *socket)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_GET_READ_BUFFER_SIZE]) return 0;
|
||||
args.callback_type = UTP_GET_READ_BUFFER_SIZE;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
return (size_t)ctx->callbacks[UTP_GET_READ_BUFFER_SIZE](&args);
|
||||
}
|
||||
|
||||
void utp_call_log(utp_context *ctx, utp_socket *socket, const byte *buf)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_LOG]) return;
|
||||
args.callback_type = UTP_LOG;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
ctx->callbacks[UTP_LOG](&args);
|
||||
}
|
||||
|
||||
void utp_call_sendto(utp_context *ctx, utp_socket *socket, const byte *buf, size_t len, const struct sockaddr *address, socklen_t address_len, uint32 flags)
|
||||
{
|
||||
utp_callback_arguments args;
|
||||
if (!ctx->callbacks[UTP_SENDTO]) return;
|
||||
args.callback_type = UTP_SENDTO;
|
||||
args.context = ctx;
|
||||
args.socket = socket;
|
||||
args.buf = buf;
|
||||
args.len = len;
|
||||
args.address = address;
|
||||
args.address_len = address_len;
|
||||
args.flags = flags;
|
||||
ctx->callbacks[UTP_SENDTO](&args);
|
||||
}
|
||||
|
47
vendor/github.com/anacrolix/go-libutp/utp_callbacks.h
generated
vendored
Normal file
47
vendor/github.com/anacrolix/go-libutp/utp_callbacks.h
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_CALLBACKS_H__
|
||||
#define __UTP_CALLBACKS_H__
|
||||
|
||||
#include "utp.h"
|
||||
#include "utp_internal.h"
|
||||
|
||||
// Generated by running: grep ^[a-z] utp_callbacks.cpp | sed 's/$/;/'
|
||||
int utp_call_on_firewall(utp_context *ctx, const struct sockaddr *address, socklen_t address_len);
|
||||
void utp_call_on_accept(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
void utp_call_on_connect(utp_context *ctx, utp_socket *s);
|
||||
void utp_call_on_error(utp_context *ctx, utp_socket *s, int error_code);
|
||||
void utp_call_on_read(utp_context *ctx, utp_socket *s, const byte *buf, size_t len);
|
||||
void utp_call_on_overhead_statistics(utp_context *ctx, utp_socket *s, int send, size_t len, int type);
|
||||
void utp_call_on_delay_sample(utp_context *ctx, utp_socket *s, int sample_ms);
|
||||
void utp_call_on_state_change(utp_context *ctx, utp_socket *s, int state);
|
||||
uint16 utp_call_get_udp_mtu(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
uint16 utp_call_get_udp_overhead(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
|
||||
uint64 utp_call_get_milliseconds(utp_context *ctx, utp_socket *s);
|
||||
uint64 utp_call_get_microseconds(utp_context *ctx, utp_socket *s);
|
||||
uint32 utp_call_get_random(utp_context *ctx, utp_socket *s);
|
||||
size_t utp_call_get_read_buffer_size(utp_context *ctx, utp_socket *s);
|
||||
void utp_call_log(utp_context *ctx, utp_socket *s, const byte *buf);
|
||||
void utp_call_sendto(utp_context *ctx, utp_socket *s, const byte *buf, size_t len, const struct sockaddr *address, socklen_t address_len, uint32 flags);
|
||||
|
||||
#endif // __UTP_CALLBACKS_H__
|
246
vendor/github.com/anacrolix/go-libutp/utp_hash.cpp
generated
vendored
Normal file
246
vendor/github.com/anacrolix/go-libutp/utp_hash.cpp
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "utp_hash.h"
|
||||
#include "utp_types.h"
|
||||
|
||||
#define LIBUTP_HASH_UNUSED ((utp_link_t)-1)
|
||||
|
||||
#ifdef STRICT_ALIGN
|
||||
inline uint32 Read32(const void *p)
|
||||
{
|
||||
uint32 tmp;
|
||||
memcpy(&tmp, p, sizeof tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#else
|
||||
inline uint32 Read32(const void *p) { return *(uint32*)p; }
|
||||
#endif
|
||||
|
||||
|
||||
// Get the amount of memory required for the hash parameters and the bucket set
|
||||
// Waste a space for an unused bucket in order to ensure the following managed memory have 32-bit aligned addresses
|
||||
// TODO: make this 64-bit clean
|
||||
#define BASE_SIZE(bc) (sizeof(utp_hash_t) + sizeof(utp_link_t) * ((bc) + 1))
|
||||
|
||||
// Get a pointer to the base of the structure array managed by the hash table
|
||||
#define get_bep(h) ((byte*)(h)) + BASE_SIZE((h)->N)
|
||||
|
||||
// Get the address of the information associated with a specific structure in the array,
|
||||
// given the address of the base of the structure.
|
||||
// This assumes a utp_link_t link member is at the end of the structure.
|
||||
// Given compilers filling out the memory to a 32-bit clean value, this may mean that
|
||||
// the location named in the structure may not be the location actually used by the hash table,
|
||||
// since the compiler may have padded the end of the structure with 2 bytes after the utp_link_t member.
|
||||
// TODO: this macro should not require that the variable pointing at the hash table be named 'hash'
|
||||
#define ptr_to_link(p) (utp_link_t *) (((byte *) (p)) + hash->E - sizeof(utp_link_t))
|
||||
|
||||
// Calculate how much to allocate for a hash table with bucket count, total size, and structure count
|
||||
// TODO: make this 64-bit clean
|
||||
#define ALLOCATION_SIZE(bc, ts, sc) (BASE_SIZE((bc)) + (ts) * (sc))
|
||||
|
||||
utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun, utp_hash_equal_t compfun)
|
||||
{
|
||||
// Must have odd number of hash buckets (prime number is best)
|
||||
assert(N % 2);
|
||||
// Ensure structures will be at aligned memory addresses
|
||||
// TODO: make this 64-bit clean
|
||||
assert(0 == (total_size % 4));
|
||||
|
||||
int size = ALLOCATION_SIZE(N, total_size, initial);
|
||||
utp_hash_t *hash = (utp_hash_t *) malloc( size );
|
||||
memset( hash, 0, size );
|
||||
|
||||
for (int i = 0; i < N + 1; ++i)
|
||||
hash->inits[i] = LIBUTP_HASH_UNUSED;
|
||||
hash->N = N;
|
||||
hash->K = key_size;
|
||||
hash->E = total_size;
|
||||
hash->hash_compute = hashfun;
|
||||
hash->hash_equal = compfun;
|
||||
hash->allocated = initial;
|
||||
hash->count = 0;
|
||||
hash->used = 0;
|
||||
hash->free = LIBUTP_HASH_UNUSED;
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint utp_hash_mem(const void *keyp, size_t keysize)
|
||||
{
|
||||
uint hash = 0;
|
||||
uint n = keysize;
|
||||
while (n >= 4) {
|
||||
hash ^= Read32(keyp);
|
||||
keyp = (byte*)keyp + sizeof(uint32);
|
||||
hash = (hash << 13) | (hash >> 19);
|
||||
n -= 4;
|
||||
}
|
||||
while (n != 0) {
|
||||
hash ^= *(byte*)keyp;
|
||||
keyp = (byte*)keyp + sizeof(byte);
|
||||
hash = (hash << 8) | (hash >> 24);
|
||||
n--;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint utp_hash_mkidx(utp_hash_t *hash, const void *keyp)
|
||||
{
|
||||
// Generate a key from the hash
|
||||
return hash->hash_compute(keyp, hash->K) % hash->N;
|
||||
}
|
||||
|
||||
static inline bool compare(byte *a, byte *b,int n)
|
||||
{
|
||||
assert(n >= 4);
|
||||
if (Read32(a) != Read32(b)) return false;
|
||||
return memcmp(a+4, b+4, n-4) == 0;
|
||||
}
|
||||
|
||||
#define COMPARE(h,k1,k2,ks) (((h)->hash_equal) ? (h)->hash_equal((void*)k1,(void*)k2,ks) : compare(k1,k2,ks))
|
||||
|
||||
// Look-up a key in the hash table.
|
||||
// Returns NULL if not found
|
||||
void *utp_hash_lookup(utp_hash_t *hash, const void *key)
|
||||
{
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
// base pointer
|
||||
byte *bep = get_bep(hash);
|
||||
|
||||
utp_link_t cur = hash->inits[idx];
|
||||
while (cur != LIBUTP_HASH_UNUSED) {
|
||||
byte *key2 = bep + (cur * hash->E);
|
||||
if (COMPARE(hash, (byte*)key, key2, hash->K))
|
||||
return key2;
|
||||
cur = *ptr_to_link(key2);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add a new element to the hash table.
|
||||
// Returns a pointer to the new element.
|
||||
// This assumes the element is not already present!
|
||||
void *utp_hash_add(utp_hash_t **hashp, const void *key)
|
||||
{
|
||||
//Allocate a new entry
|
||||
byte *elemp;
|
||||
utp_link_t elem;
|
||||
utp_hash_t *hash = *hashp;
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
if ((elem=hash->free) == LIBUTP_HASH_UNUSED) {
|
||||
utp_link_t all = hash->allocated;
|
||||
if (hash->used == all) {
|
||||
utp_hash_t *nhash;
|
||||
if (all <= (LIBUTP_HASH_UNUSED/2)) {
|
||||
all *= 2;
|
||||
} else if (all != LIBUTP_HASH_UNUSED) {
|
||||
all = LIBUTP_HASH_UNUSED;
|
||||
} else {
|
||||
// too many items! can't grow!
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
// otherwise need to allocate.
|
||||
nhash = (utp_hash_t*)realloc(hash, ALLOCATION_SIZE(hash->N, hash->E, all));
|
||||
if (!nhash) {
|
||||
// out of memory (or too big to allocate)
|
||||
assert(nhash);
|
||||
return NULL;
|
||||
}
|
||||
hash = *hashp = nhash;
|
||||
hash->allocated = all;
|
||||
}
|
||||
|
||||
elem = hash->used++;
|
||||
elemp = get_bep(hash) + elem * hash->E;
|
||||
} else {
|
||||
elemp = get_bep(hash) + elem * hash->E;
|
||||
hash->free = *ptr_to_link(elemp);
|
||||
}
|
||||
|
||||
*ptr_to_link(elemp) = hash->inits[idx];
|
||||
hash->inits[idx] = elem;
|
||||
hash->count++;
|
||||
|
||||
// copy key into it
|
||||
memcpy(elemp, key, hash->K);
|
||||
return elemp;
|
||||
}
|
||||
|
||||
// Delete an element from the utp_hash_t
|
||||
// Returns a pointer to the already deleted element.
|
||||
void *utp_hash_del(utp_hash_t *hash, const void *key)
|
||||
{
|
||||
utp_link_t idx = utp_hash_mkidx(hash, key);
|
||||
|
||||
// base pointer
|
||||
byte *bep = get_bep(hash);
|
||||
|
||||
utp_link_t *curp = &hash->inits[idx];
|
||||
utp_link_t cur;
|
||||
while ((cur=*curp) != LIBUTP_HASH_UNUSED) {
|
||||
byte *key2 = bep + (cur * hash->E);
|
||||
if (COMPARE(hash,(byte*)key,(byte*)key2, hash->K )) {
|
||||
// found an item that matched. unlink it
|
||||
*curp = *ptr_to_link(key2);
|
||||
// Insert into freelist
|
||||
*ptr_to_link(key2) = hash->free;
|
||||
hash->free = cur;
|
||||
hash->count--;
|
||||
return key2;
|
||||
}
|
||||
curp = ptr_to_link(key2);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter)
|
||||
{
|
||||
utp_link_t elem;
|
||||
|
||||
if ((elem=iter->elem) == LIBUTP_HASH_UNUSED) {
|
||||
// Find a bucket with an element
|
||||
utp_link_t buck = iter->bucket + 1;
|
||||
for(;;) {
|
||||
if (buck >= hash->N)
|
||||
return NULL;
|
||||
if ((elem = hash->inits[buck]) != LIBUTP_HASH_UNUSED)
|
||||
break;
|
||||
buck++;
|
||||
}
|
||||
iter->bucket = buck;
|
||||
}
|
||||
|
||||
byte *elemp = get_bep(hash) + (elem * hash->E);
|
||||
iter->elem = *ptr_to_link(elemp);
|
||||
return elemp;
|
||||
}
|
||||
|
||||
void utp_hash_free_mem(utp_hash_t* hash)
|
||||
{
|
||||
free(hash);
|
||||
}
|
146
vendor/github.com/anacrolix/go-libutp/utp_hash.h
generated
vendored
Normal file
146
vendor/github.com/anacrolix/go-libutp/utp_hash.h
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_HASH_H__
|
||||
#define __UTP_HASH_H__
|
||||
|
||||
#include <string.h> // memset
|
||||
#include <stdlib.h> // malloc
|
||||
|
||||
#include "utp_types.h"
|
||||
#include "utp_templates.h"
|
||||
|
||||
// TODO: make utp_link_t a template parameter to HashTable
|
||||
typedef uint32 utp_link_t;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Silence the warning about the C99-compliant zero-length array at the end of the structure
|
||||
#pragma warning (disable: 4200)
|
||||
#endif
|
||||
|
||||
typedef uint32 (*utp_hash_compute_t)(const void *keyp, size_t keysize);
|
||||
typedef uint (*utp_hash_equal_t)(const void *key_a, const void *key_b, size_t keysize);
|
||||
|
||||
// In memory the HashTable is laid out as follows:
|
||||
// ---------------------------- low
|
||||
// | hash table data members |
|
||||
// ---------------------------- _
|
||||
// | indices | ^
|
||||
// | . | | utp_link_t indices into the key-values.
|
||||
// | . | .
|
||||
// ---------------------------- - <----- bep
|
||||
// | keys and values | each key-value pair has size total_size
|
||||
// | . |
|
||||
// | . |
|
||||
// ---------------------------- high
|
||||
//
|
||||
// The code depends on the ability of the compiler to pad the length
|
||||
// of the hash table data members structure to
|
||||
// a length divisible by 32-bits with no remainder.
|
||||
//
|
||||
// Since the number of hash buckets (indices) should be odd, the code
|
||||
// asserts this and adds one to the hash bucket count to ensure that the
|
||||
// following key-value pairs array starts on a 32-bit boundary.
|
||||
//
|
||||
// The key-value pairs array should start on a 32-bit boundary, otherwise
|
||||
// processors like the ARM will silently mangle 32-bit data in these structures
|
||||
// (e.g., turning 0xABCD into 0XCDAB when moving a value from memory to register
|
||||
// when the memory address is 16 bits offset from a 32-bit boundary),
|
||||
// also, the value will be stored at an address two bytes lower than the address
|
||||
// value would ordinarily indicate.
|
||||
//
|
||||
// The key-value pair is of type T. The first field in T must
|
||||
// be the key, i.e., the first K bytes of T contains the key.
|
||||
// total_size = sizeof(T) and thus sizeof(T) >= sizeof(K)
|
||||
//
|
||||
// N is the number of buckets.
|
||||
//
|
||||
struct utp_hash_t {
|
||||
utp_link_t N;
|
||||
byte K;
|
||||
byte E;
|
||||
size_t count;
|
||||
utp_hash_compute_t hash_compute;
|
||||
utp_hash_equal_t hash_equal;
|
||||
utp_link_t allocated;
|
||||
utp_link_t used;
|
||||
utp_link_t free;
|
||||
utp_link_t inits[0];
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (default: 4200)
|
||||
#endif
|
||||
|
||||
struct utp_hash_iterator_t {
|
||||
utp_link_t bucket;
|
||||
utp_link_t elem;
|
||||
|
||||
utp_hash_iterator_t() : bucket(0xffffffff), elem(0xffffffff) {}
|
||||
};
|
||||
|
||||
uint utp_hash_mem(const void *keyp, size_t keysize);
|
||||
uint utp_hash_comp(const void *key_a, const void *key_b, size_t keysize);
|
||||
|
||||
utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun = utp_hash_mem, utp_hash_equal_t eqfun = NULL);
|
||||
void *utp_hash_lookup(utp_hash_t *hash, const void *key);
|
||||
void *utp_hash_add(utp_hash_t **hashp, const void *key);
|
||||
void *utp_hash_del(utp_hash_t *hash, const void *key);
|
||||
|
||||
void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter);
|
||||
void utp_hash_free_mem(utp_hash_t *hash);
|
||||
|
||||
/*
|
||||
This HashTable requires that T have at least sizeof(K)+sizeof(utp_link_t) bytes.
|
||||
Usually done like this:
|
||||
|
||||
struct K {
|
||||
int whatever;
|
||||
};
|
||||
|
||||
struct T {
|
||||
K wtf;
|
||||
utp_link_t link; // also wtf
|
||||
};
|
||||
*/
|
||||
|
||||
template<typename K, typename T> class utpHashTable {
|
||||
utp_hash_t *hash;
|
||||
public:
|
||||
static uint compare(const void *k1, const void *k2, size_t ks) {
|
||||
return *((K*)k1) == *((K*)k2);
|
||||
}
|
||||
static uint32 compute_hash(const void *k, size_t ks) {
|
||||
return ((K*)k)->compute_hash();
|
||||
}
|
||||
void Init() { hash = NULL; }
|
||||
bool Allocated() { return (hash != NULL); }
|
||||
void Free() { utp_hash_free_mem(hash); hash = NULL; }
|
||||
void Create(int N, int initial) { hash = utp_hash_create(N, sizeof(K), sizeof(T), initial, &compute_hash, &compare); }
|
||||
T *Lookup(const K &key) { return (T*)utp_hash_lookup(hash, &key); }
|
||||
T *Add(const K &key) { return (T*)utp_hash_add(&hash, &key); }
|
||||
T *Delete(const K &key) { return (T*)utp_hash_del(hash, &key); }
|
||||
T *Iterate(utp_hash_iterator_t &iterator) { return (T*)utp_hash_iterate(hash, &iterator); }
|
||||
size_t GetCount() { return hash->count; }
|
||||
};
|
||||
|
||||
#endif //__UTP_HASH_H__
|
3489
vendor/github.com/anacrolix/go-libutp/utp_internal.cpp
generated
vendored
Normal file
3489
vendor/github.com/anacrolix/go-libutp/utp_internal.cpp
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
141
vendor/github.com/anacrolix/go-libutp/utp_internal.h
generated
vendored
Normal file
141
vendor/github.com/anacrolix/go-libutp/utp_internal.h
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_INTERNAL_H__
|
||||
#define __UTP_INTERNAL_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utp.h"
|
||||
#include "utp_callbacks.h"
|
||||
#include "utp_templates.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_packedsockaddr.h"
|
||||
|
||||
/* These originally lived in utp_config.h */
|
||||
#define CCONTROL_TARGET (100 * 1000) // us
|
||||
|
||||
enum bandwidth_type_t {
|
||||
payload_bandwidth, connect_overhead,
|
||||
close_overhead, ack_overhead,
|
||||
header_overhead, retransmit_overhead
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _MSC_VER
|
||||
#include "libutp_inet_ntop.h"
|
||||
#endif
|
||||
|
||||
// newer versions of MSVC define these in errno.h
|
||||
#ifndef ECONNRESET
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct PACKED_ATTRIBUTE RST_Info {
|
||||
PackedSockAddr addr;
|
||||
uint32 connid;
|
||||
uint16 ack_nr;
|
||||
uint64 timestamp;
|
||||
};
|
||||
|
||||
// It's really important that we don't have duplicate keys in the hash table.
|
||||
// If we do, we'll eventually crash. if we try to remove the second instance
|
||||
// of the key, we'll accidentally remove the first instead. then later,
|
||||
// checkTimeouts will try to access the second one's already freed memory.
|
||||
void UTP_FreeAll(struct UTPSocketHT *utp_sockets);
|
||||
|
||||
struct UTPSocketKey {
|
||||
PackedSockAddr addr;
|
||||
uint32 recv_id; // "conn_seed", "conn_id"
|
||||
|
||||
UTPSocketKey(const PackedSockAddr& _addr, uint32 _recv_id) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
addr = _addr;
|
||||
recv_id = _recv_id;
|
||||
}
|
||||
|
||||
bool operator == (const UTPSocketKey &other) const {
|
||||
return recv_id == other.recv_id && addr == other.addr;
|
||||
}
|
||||
|
||||
uint32 compute_hash() const {
|
||||
return recv_id ^ addr.compute_hash();
|
||||
}
|
||||
};
|
||||
|
||||
struct UTPSocketKeyData {
|
||||
UTPSocketKey key;
|
||||
UTPSocket *socket;
|
||||
utp_link_t link;
|
||||
};
|
||||
|
||||
#define UTP_SOCKET_BUCKETS 79
|
||||
#define UTP_SOCKET_INIT 15
|
||||
|
||||
struct UTPSocketHT : utpHashTable<UTPSocketKey, UTPSocketKeyData> {
|
||||
UTPSocketHT() {
|
||||
const int buckets = UTP_SOCKET_BUCKETS;
|
||||
const int initial = UTP_SOCKET_INIT;
|
||||
this->Create(buckets, initial);
|
||||
}
|
||||
~UTPSocketHT() {
|
||||
UTP_FreeAll(this);
|
||||
this->Free();
|
||||
}
|
||||
};
|
||||
|
||||
struct struct_utp_context {
|
||||
void *userdata;
|
||||
utp_callback_t* callbacks[UTP_ARRAY_SIZE];
|
||||
|
||||
uint64 current_ms;
|
||||
utp_context_stats context_stats;
|
||||
UTPSocket *last_utp_socket;
|
||||
Array<UTPSocket*> ack_sockets;
|
||||
Array<RST_Info> rst_info;
|
||||
UTPSocketHT *utp_sockets;
|
||||
size_t target_delay;
|
||||
size_t opt_sndbuf;
|
||||
size_t opt_rcvbuf;
|
||||
uint64 last_check;
|
||||
|
||||
struct_utp_context();
|
||||
~struct_utp_context();
|
||||
|
||||
void log(int level, utp_socket *socket, char const *fmt, ...);
|
||||
void log_unchecked(utp_socket *socket, char const *fmt, ...);
|
||||
bool would_log(int level);
|
||||
|
||||
bool log_normal:1; // log normal events?
|
||||
bool log_mtu:1; // log MTU related events?
|
||||
bool log_debug:1; // log debugging events? (Must also compile with UTP_DEBUG_LOGGING defined)
|
||||
};
|
||||
|
||||
#endif //__UTP_INTERNAL_H__
|
139
vendor/github.com/anacrolix/go-libutp/utp_packedsockaddr.cpp
generated
vendored
Normal file
139
vendor/github.com/anacrolix/go-libutp/utp_packedsockaddr.cpp
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
// vim:set ts=4 sw=4 ai:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utp_types.h"
|
||||
#include "utp_hash.h"
|
||||
#include "utp_packedsockaddr.h"
|
||||
|
||||
#include "libutp_inet_ntop.h"
|
||||
|
||||
byte PackedSockAddr::get_family() const
|
||||
{
|
||||
#if defined(__sh__)
|
||||
return ((_sin6d[0] == 0) && (_sin6d[1] == 0) && (_sin6d[2] == htonl(0xffff)) != 0) ?
|
||||
AF_INET : AF_INET6;
|
||||
#else
|
||||
return (IN6_IS_ADDR_V4MAPPED(&_in._in6addr) != 0) ? AF_INET : AF_INET6;
|
||||
#endif // defined(__sh__)
|
||||
}
|
||||
|
||||
bool PackedSockAddr::operator==(const PackedSockAddr& rhs) const
|
||||
{
|
||||
if (&rhs == this)
|
||||
return true;
|
||||
if (_port != rhs._port)
|
||||
return false;
|
||||
return memcmp(_sin6, rhs._sin6, sizeof(_sin6)) == 0;
|
||||
}
|
||||
|
||||
bool PackedSockAddr::operator!=(const PackedSockAddr& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
uint32 PackedSockAddr::compute_hash() const {
|
||||
return utp_hash_mem(&_in, sizeof(_in)) ^ _port;
|
||||
}
|
||||
|
||||
void PackedSockAddr::set(const SOCKADDR_STORAGE* sa, socklen_t len)
|
||||
{
|
||||
if (sa->ss_family == AF_INET) {
|
||||
assert(len >= sizeof(sockaddr_in));
|
||||
const sockaddr_in *sin = (sockaddr_in*)sa;
|
||||
_sin6w[0] = 0;
|
||||
_sin6w[1] = 0;
|
||||
_sin6w[2] = 0;
|
||||
_sin6w[3] = 0;
|
||||
_sin6w[4] = 0;
|
||||
_sin6w[5] = 0xffff;
|
||||
_sin4 = sin->sin_addr.s_addr;
|
||||
_port = ntohs(sin->sin_port);
|
||||
} else {
|
||||
assert(len >= sizeof(sockaddr_in6));
|
||||
const sockaddr_in6 *sin6 = (sockaddr_in6*)sa;
|
||||
_in._in6addr = sin6->sin6_addr;
|
||||
_port = ntohs(sin6->sin6_port);
|
||||
}
|
||||
}
|
||||
|
||||
PackedSockAddr::PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len)
|
||||
{
|
||||
set(sa, len);
|
||||
}
|
||||
|
||||
PackedSockAddr::PackedSockAddr(void)
|
||||
{
|
||||
SOCKADDR_STORAGE sa;
|
||||
socklen_t len = sizeof(SOCKADDR_STORAGE);
|
||||
memset(&sa, 0, len);
|
||||
sa.ss_family = AF_INET;
|
||||
set(&sa, len);
|
||||
}
|
||||
|
||||
SOCKADDR_STORAGE PackedSockAddr::get_sockaddr_storage(socklen_t *len = NULL) const
|
||||
{
|
||||
SOCKADDR_STORAGE sa;
|
||||
const byte family = get_family();
|
||||
if (family == AF_INET) {
|
||||
sockaddr_in *sin = (sockaddr_in*)&sa;
|
||||
if (len) *len = sizeof(sockaddr_in);
|
||||
memset(sin, 0, sizeof(sockaddr_in));
|
||||
sin->sin_family = family;
|
||||
sin->sin_port = htons(_port);
|
||||
sin->sin_addr.s_addr = _sin4;
|
||||
} else {
|
||||
sockaddr_in6 *sin6 = (sockaddr_in6*)&sa;
|
||||
memset(sin6, 0, sizeof(sockaddr_in6));
|
||||
if (len) *len = sizeof(sockaddr_in6);
|
||||
sin6->sin6_family = family;
|
||||
sin6->sin6_addr = _in._in6addr;
|
||||
sin6->sin6_port = htons(_port);
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
||||
// #define addrfmt(x, s) x.fmt(s, sizeof(s))
|
||||
cstr PackedSockAddr::fmt(str s, size_t len) const
|
||||
{
|
||||
memset(s, 0, len);
|
||||
const byte family = get_family();
|
||||
str i;
|
||||
if (family == AF_INET) {
|
||||
INET_NTOP(family, (uint32*)&_sin4, s, len);
|
||||
i = s;
|
||||
while (*++i) {}
|
||||
} else {
|
||||
i = s;
|
||||
*i++ = '[';
|
||||
INET_NTOP(family, (in6_addr*)&_in._in6addr, i, len-1);
|
||||
while (*++i) {}
|
||||
*i++ = ']';
|
||||
}
|
||||
snprintf(i, len - (i-s), ":%u", _port);
|
||||
return s;
|
||||
}
|
60
vendor/github.com/anacrolix/go-libutp/utp_packedsockaddr.h
generated
vendored
Normal file
60
vendor/github.com/anacrolix/go-libutp/utp_packedsockaddr.h
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_PACKEDSOCKADDR_H__
|
||||
#define __UTP_PACKEDSOCKADDR_H__
|
||||
|
||||
#include "utp_types.h"
|
||||
|
||||
struct PACKED_ATTRIBUTE PackedSockAddr {
|
||||
// The values are always stored here in network byte order
|
||||
union {
|
||||
byte _in6[16]; // IPv6
|
||||
uint16 _in6w[8]; // IPv6, word based (for convenience)
|
||||
uint32 _in6d[4]; // Dword access
|
||||
in6_addr _in6addr; // For convenience
|
||||
} _in;
|
||||
|
||||
// Host byte order
|
||||
uint16 _port;
|
||||
|
||||
#define _sin4 _in._in6d[3] // IPv4 is stored where it goes if mapped
|
||||
|
||||
#define _sin6 _in._in6
|
||||
#define _sin6w _in._in6w
|
||||
#define _sin6d _in._in6d
|
||||
|
||||
byte get_family() const;
|
||||
bool operator==(const PackedSockAddr& rhs) const;
|
||||
bool operator!=(const PackedSockAddr& rhs) const;
|
||||
void set(const SOCKADDR_STORAGE* sa, socklen_t len);
|
||||
|
||||
PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len);
|
||||
PackedSockAddr(void);
|
||||
|
||||
SOCKADDR_STORAGE get_sockaddr_storage(socklen_t *len) const;
|
||||
cstr fmt(str s, size_t len) const;
|
||||
|
||||
uint32 compute_hash() const;
|
||||
} ALIGNED_ATTRIBUTE(4);
|
||||
|
||||
#endif //__UTP_PACKEDSOCKADDR_H__
|
195
vendor/github.com/anacrolix/go-libutp/utp_templates.h
generated
vendored
Normal file
195
vendor/github.com/anacrolix/go-libutp/utp_templates.h
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __TEMPLATES_H__
|
||||
#define __TEMPLATES_H__
|
||||
|
||||
#include "utp_types.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(POSIX)
|
||||
/* Allow over-writing FORCEINLINE from makefile because gcc 3.4.4 for buffalo
|
||||
doesn't seem to support __attribute__((always_inline)) in -O0 build
|
||||
(strangely, it works in -Os build) */
|
||||
#ifndef FORCEINLINE
|
||||
// The always_inline attribute asks gcc to inline the function even if no optimization is being requested.
|
||||
// This macro should be used exclusive-or with the inline directive (use one or the other but not both)
|
||||
// since Microsoft uses __forceinline to also mean inline,
|
||||
// and this code is following a Microsoft compatibility model.
|
||||
// Just setting the attribute without also specifying the inline directive apparently won't inline the function,
|
||||
// as evidenced by multiply-defined symbols found at link time.
|
||||
#define FORCEINLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Utility templates
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
template <typename T> static inline T min(T a, T b) { if (a < b) return a; return b; }
|
||||
template <typename T> static inline T max(T a, T b) { if (a > b) return a; return b; }
|
||||
|
||||
template <typename T> static inline T min(T a, T b, T c) { return min(min(a,b),c); }
|
||||
template <typename T> static inline T max(T a, T b, T c) { return max(max(a,b),c); }
|
||||
template <typename T> static inline T clamp(T v, T mi, T ma)
|
||||
{
|
||||
if (v > ma) v = ma;
|
||||
if (v < mi) v = mi;
|
||||
return v;
|
||||
}
|
||||
|
||||
#if (defined(__SVR4) && defined(__sun))
|
||||
#pragma pack(1)
|
||||
#else
|
||||
#pragma pack(push,1)
|
||||
#endif
|
||||
|
||||
|
||||
namespace aux
|
||||
{
|
||||
FORCEINLINE uint16 host_to_network(uint16 i) { return htons(i); }
|
||||
FORCEINLINE uint32 host_to_network(uint32 i) { return htonl(i); }
|
||||
FORCEINLINE int32 host_to_network(int32 i) { return htonl(i); }
|
||||
FORCEINLINE uint16 network_to_host(uint16 i) { return ntohs(i); }
|
||||
FORCEINLINE uint32 network_to_host(uint32 i) { return ntohl(i); }
|
||||
FORCEINLINE int32 network_to_host(int32 i) { return ntohl(i); }
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct PACKED_ATTRIBUTE big_endian
|
||||
{
|
||||
T operator=(T i) { m_integer = aux::host_to_network(i); return i; }
|
||||
operator T() const { return aux::network_to_host(m_integer); }
|
||||
private:
|
||||
T m_integer;
|
||||
};
|
||||
|
||||
typedef big_endian<int32> int32_big;
|
||||
typedef big_endian<uint32> uint32_big;
|
||||
typedef big_endian<uint16> uint16_big;
|
||||
|
||||
#if (defined(__SVR4) && defined(__sun))
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
template<typename T> static inline void zeromem(T *a, size_t count = 1) { memset(a, 0, count * sizeof(T)); }
|
||||
|
||||
typedef int SortCompareProc(const void *, const void *);
|
||||
|
||||
template<typename T> static FORCEINLINE void QuickSortT(T *base, size_t num, int (*comp)(const T *, const T *)) { qsort(base, num, sizeof(T), (SortCompareProc*)comp); }
|
||||
|
||||
|
||||
// WARNING: The template parameter MUST be a POD type!
|
||||
template <typename T, size_t minsize = 16> class Array {
|
||||
protected:
|
||||
T *mem;
|
||||
size_t alloc,count;
|
||||
|
||||
public:
|
||||
Array(size_t init) { Init(init); }
|
||||
Array() { Init(); }
|
||||
~Array() { Free(); }
|
||||
|
||||
void inline Init() { mem = NULL; alloc = count = 0; }
|
||||
void inline Init(size_t init) { Init(); if (init) Resize(init); }
|
||||
size_t inline GetCount() const { return count; }
|
||||
size_t inline GetAlloc() const { return alloc; }
|
||||
void inline SetCount(size_t c) { count = c; }
|
||||
|
||||
inline T& operator[](size_t offset) { assert(offset ==0 || offset<alloc); return mem[offset]; }
|
||||
inline const T& operator[](size_t offset) const { assert(offset ==0 || offset<alloc); return mem[offset]; }
|
||||
|
||||
void inline Resize(size_t a) {
|
||||
if (a == 0) { free(mem); Init(); }
|
||||
else { mem = (T*)realloc(mem, (alloc=a) * sizeof(T)); }
|
||||
}
|
||||
|
||||
void Grow() { Resize(::max<size_t>(minsize, alloc * 2)); }
|
||||
|
||||
inline size_t Append(const T &t) {
|
||||
if (count >= alloc) Grow();
|
||||
size_t r=count++;
|
||||
mem[r] = t;
|
||||
return r;
|
||||
}
|
||||
|
||||
T inline &Append() {
|
||||
if (count >= alloc) Grow();
|
||||
return mem[count++];
|
||||
}
|
||||
|
||||
void inline Compact() {
|
||||
Resize(count);
|
||||
}
|
||||
|
||||
void inline Free() {
|
||||
free(mem);
|
||||
Init();
|
||||
}
|
||||
|
||||
void inline Clear() {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
bool inline MoveUpLast(size_t index) {
|
||||
assert(index < count);
|
||||
size_t c = --count;
|
||||
if (index != c) {
|
||||
mem[index] = mem[c];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool inline MoveUpLastExist(const T &v) {
|
||||
return MoveUpLast(LookupElementExist(v));
|
||||
}
|
||||
|
||||
size_t inline LookupElement(const T &v) const {
|
||||
for(size_t i = 0; i != count; i++)
|
||||
if (mem[i] == v)
|
||||
return i;
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
bool inline HasElement(const T &v) const {
|
||||
return LookupElement(v) != -1;
|
||||
}
|
||||
|
||||
typedef int SortCompareProc(const T *a, const T *b);
|
||||
|
||||
void Sort(SortCompareProc* proc, size_t start, size_t end) {
|
||||
QuickSortT(&mem[start], end - start, proc);
|
||||
}
|
||||
|
||||
void Sort(SortCompareProc* proc, size_t start) {
|
||||
Sort(proc, start, count);
|
||||
}
|
||||
|
||||
void Sort(SortCompareProc* proc) {
|
||||
Sort(proc, 0, count);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //__TEMPLATES_H__
|
123
vendor/github.com/anacrolix/go-libutp/utp_types.h
generated
vendored
Normal file
123
vendor/github.com/anacrolix/go-libutp/utp_types.h
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __UTP_TYPES_H__
|
||||
#define __UTP_TYPES_H__
|
||||
|
||||
// Allow libutp consumers or prerequisites to override PACKED_ATTRIBUTE
|
||||
#ifndef PACKED_ATTRIBUTE
|
||||
#if defined BROKEN_GCC_STRUCTURE_PACKING && defined __GNUC__
|
||||
// Used for gcc tool chains accepting but not supporting pragma pack
|
||||
// See http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html
|
||||
#define PACKED_ATTRIBUTE __attribute__((__packed__))
|
||||
#else
|
||||
#define PACKED_ATTRIBUTE
|
||||
#endif // defined BROKEN_GCC_STRUCTURE_PACKING && defined __GNUC__
|
||||
#endif // ndef PACKED_ATTRIBUTE
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ALIGNED_ATTRIBUTE(x) __attribute__((aligned (x)))
|
||||
#else
|
||||
#define ALIGNED_ATTRIBUTE(x)
|
||||
#endif
|
||||
|
||||
// hash.cpp needs socket definitions, which is why this networking specific
|
||||
// code is inclued in utypes.h
|
||||
#ifdef WIN32
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAGMENT
|
||||
#define SHUT_RD SD_RECEIVE
|
||||
#define SHUT_WR SD_SEND
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef IP_DONTFRAG
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAG
|
||||
#elif defined IP_DONTFRAGMENT
|
||||
#define IP_OPT_DONTFRAG IP_DONTFRAGMENT
|
||||
#else
|
||||
//#warning "I don't know how to set DF bit on this system"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
#ifdef POSIX
|
||||
typedef struct sockaddr_storage SOCKADDR_STORAGE;
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define I64u "%I64u"
|
||||
#else
|
||||
#define I64u "%Lu"
|
||||
#endif
|
||||
|
||||
// standard types
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char uint8;
|
||||
typedef signed char int8;
|
||||
typedef unsigned short uint16;
|
||||
typedef signed short int16;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned int uint32;
|
||||
typedef signed int int32;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef signed __int64 int64;
|
||||
#else
|
||||
typedef unsigned long long uint64;
|
||||
typedef long long int64;
|
||||
#endif
|
||||
|
||||
/* compile-time assert */
|
||||
#ifndef CASSERT
|
||||
#define CASSERT( exp, name ) typedef int is_not_##name [ (exp ) ? 1 : -1 ];
|
||||
#endif
|
||||
|
||||
CASSERT(8 == sizeof(uint64), sizeof_uint64_is_8)
|
||||
CASSERT(8 == sizeof(int64), sizeof_int64_is_8)
|
||||
|
||||
#ifndef INT64_MAX
|
||||
#define INT64_MAX 0x7fffffffffffffffLL
|
||||
#endif
|
||||
|
||||
// always ANSI
|
||||
typedef const char * cstr;
|
||||
typedef char * str;
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef uint8 bool;
|
||||
#endif
|
||||
|
||||
#endif //__UTP_TYPES_H__
|
254
vendor/github.com/anacrolix/go-libutp/utp_utils.cpp
generated
vendored
Normal file
254
vendor/github.com/anacrolix/go-libutp/utp_utils.cpp
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "utp.h"
|
||||
#include "utp_types.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else //!WIN32
|
||||
#include <time.h>
|
||||
#include <sys/time.h> // Linux needs both time.h and sys/time.h
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#include "utp_utils.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
typedef ULONGLONG (WINAPI GetTickCount64Proc)(void);
|
||||
static GetTickCount64Proc *pt2GetTickCount64;
|
||||
static GetTickCount64Proc *pt2RealGetTickCount;
|
||||
|
||||
static uint64 startPerformanceCounter;
|
||||
static uint64 startGetTickCount;
|
||||
// MSVC 6 standard doesn't like division with uint64s
|
||||
static double counterPerMicrosecond;
|
||||
|
||||
static uint64 UTGetTickCount64()
|
||||
{
|
||||
if (pt2GetTickCount64) {
|
||||
return pt2GetTickCount64();
|
||||
}
|
||||
if (pt2RealGetTickCount) {
|
||||
uint64 v = pt2RealGetTickCount();
|
||||
// fix return value from GetTickCount
|
||||
return (DWORD)v | ((v >> 0x18) & 0xFFFFFFFF00000000);
|
||||
}
|
||||
return (uint64)GetTickCount();
|
||||
}
|
||||
|
||||
static void Time_Initialize()
|
||||
{
|
||||
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
||||
pt2GetTickCount64 = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount64");
|
||||
// not a typo. GetTickCount actually returns 64 bits
|
||||
pt2RealGetTickCount = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount");
|
||||
|
||||
uint64 frequency;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&startPerformanceCounter);
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
|
||||
counterPerMicrosecond = (double)frequency / 1000000.0f;
|
||||
startGetTickCount = UTGetTickCount64();
|
||||
}
|
||||
|
||||
static int64 abs64(int64 x) { return x < 0 ? -x : x; }
|
||||
|
||||
static uint64 __GetMicroseconds()
|
||||
{
|
||||
static bool time_init = false;
|
||||
if (!time_init) {
|
||||
time_init = true;
|
||||
Time_Initialize();
|
||||
}
|
||||
|
||||
uint64 counter;
|
||||
uint64 tick;
|
||||
|
||||
QueryPerformanceCounter((LARGE_INTEGER*) &counter);
|
||||
tick = UTGetTickCount64();
|
||||
|
||||
// unfortunately, QueryPerformanceCounter is not guaranteed
|
||||
// to be monotonic. Make it so.
|
||||
int64 ret = (int64)(((int64)counter - (int64)startPerformanceCounter) / counterPerMicrosecond);
|
||||
// if the QPC clock leaps more than one second off GetTickCount64()
|
||||
// something is seriously fishy. Adjust QPC to stay monotonic
|
||||
int64 tick_diff = tick - startGetTickCount;
|
||||
if (abs64(ret / 100000 - tick_diff / 100) > 10) {
|
||||
startPerformanceCounter -= (uint64)((int64)(tick_diff * 1000 - ret) * counterPerMicrosecond);
|
||||
ret = (int64)((counter - startPerformanceCounter) / counterPerMicrosecond);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64 UTP_GetMilliseconds()
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
#else //!WIN32
|
||||
|
||||
static inline uint64 UTP_GetMicroseconds(void);
|
||||
static inline uint64 UTP_GetMilliseconds()
|
||||
{
|
||||
return UTP_GetMicroseconds() / 1000;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
static uint64 __GetMicroseconds()
|
||||
{
|
||||
// http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
|
||||
// http://www.macresearch.org/tutorial_performance_and_time
|
||||
static mach_timebase_info_data_t sTimebaseInfo;
|
||||
static uint64_t start_tick = 0;
|
||||
uint64_t tick;
|
||||
// Returns a counter in some fraction of a nanoseconds
|
||||
tick = mach_absolute_time();
|
||||
if (sTimebaseInfo.denom == 0) {
|
||||
// Get the timer ratio to convert mach_absolute_time to nanoseconds
|
||||
mach_timebase_info(&sTimebaseInfo);
|
||||
start_tick = tick;
|
||||
}
|
||||
// Calculate the elapsed time, convert it to microseconds and return it.
|
||||
return ((tick - start_tick) * sTimebaseInfo.numer) / (sTimebaseInfo.denom * 1000);
|
||||
}
|
||||
|
||||
#else // !__APPLE__
|
||||
|
||||
#if ! (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC))
|
||||
#warning "Using non-monotonic function gettimeofday() in UTP_GetMicroseconds()"
|
||||
#endif
|
||||
|
||||
/* Unfortunately, #ifdef CLOCK_MONOTONIC is not enough to make sure that
|
||||
POSIX clocks work -- we could be running a recent libc with an ancient
|
||||
kernel (think OpenWRT). -- jch */
|
||||
|
||||
static uint64_t __GetMicroseconds()
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC)
|
||||
static int have_posix_clocks = -1;
|
||||
int rc;
|
||||
|
||||
if (have_posix_clocks < 0) {
|
||||
struct timespec ts;
|
||||
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (rc < 0) {
|
||||
have_posix_clocks = 0;
|
||||
} else {
|
||||
have_posix_clocks = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_posix_clocks) {
|
||||
struct timespec ts;
|
||||
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return uint64(ts.tv_sec) * 1000000 + uint64(ts.tv_nsec) / 1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
return uint64(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
}
|
||||
|
||||
#endif //!__APPLE__
|
||||
|
||||
#endif //!WIN32
|
||||
|
||||
/*
|
||||
* Whew. Okay. After that #ifdef maze above, we now know we have a working
|
||||
* __GetMicroseconds() implementation on all platforms.
|
||||
*
|
||||
* Because there are a number of assertions in libutp that will cause a crash
|
||||
* if monotonic time isn't monotonic, now apply some safety checks. While in
|
||||
* principle we're already protecting ourselves in cases where non-monotonic
|
||||
* time is likely to happen, this protects all versions.
|
||||
*/
|
||||
|
||||
static inline uint64 UTP_GetMicroseconds()
|
||||
{
|
||||
static uint64 offset = 0, previous = 0;
|
||||
|
||||
uint64 now = __GetMicroseconds() + offset;
|
||||
if (previous > now) {
|
||||
/* Eek! */
|
||||
offset += previous - now;
|
||||
now = previous;
|
||||
}
|
||||
previous = now;
|
||||
return now;
|
||||
}
|
||||
|
||||
#define ETHERNET_MTU 1500
|
||||
#define IPV4_HEADER_SIZE 20
|
||||
#define IPV6_HEADER_SIZE 40
|
||||
#define UDP_HEADER_SIZE 8
|
||||
#define GRE_HEADER_SIZE 24
|
||||
#define PPPOE_HEADER_SIZE 8
|
||||
#define MPPE_HEADER_SIZE 2
|
||||
// packets have been observed in the wild that were fragmented
|
||||
// with a payload of 1416 for the first fragment
|
||||
// There are reports of routers that have MTU sizes as small as 1392
|
||||
#define FUDGE_HEADER_SIZE 36
|
||||
#define TEREDO_MTU 1280
|
||||
|
||||
#define UDP_IPV4_OVERHEAD (IPV4_HEADER_SIZE + UDP_HEADER_SIZE)
|
||||
#define UDP_IPV6_OVERHEAD (IPV6_HEADER_SIZE + UDP_HEADER_SIZE)
|
||||
#define UDP_TEREDO_OVERHEAD (UDP_IPV4_OVERHEAD + UDP_IPV6_OVERHEAD)
|
||||
|
||||
#define UDP_IPV4_MTU (ETHERNET_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
|
||||
#define UDP_IPV6_MTU (ETHERNET_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
|
||||
#define UDP_TEREDO_MTU (TEREDO_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE)
|
||||
|
||||
uint64 utp_default_get_udp_mtu(utp_callback_arguments *args) {
|
||||
// Since we don't know the local address of the interface,
|
||||
// be conservative and assume all IPv6 connections are Teredo.
|
||||
return (args->address->sa_family == AF_INET6) ? UDP_TEREDO_MTU : UDP_IPV4_MTU;
|
||||
}
|
||||
|
||||
uint64 utp_default_get_udp_overhead(utp_callback_arguments *args) {
|
||||
// Since we don't know the local address of the interface,
|
||||
// be conservative and assume all IPv6 connections are Teredo.
|
||||
return (args->address->sa_family == AF_INET6) ? UDP_TEREDO_OVERHEAD : UDP_IPV4_OVERHEAD;
|
||||
}
|
||||
|
||||
uint64 utp_default_get_random(utp_callback_arguments *args) {
|
||||
return rand();
|
||||
}
|
||||
|
||||
uint64 utp_default_get_milliseconds(utp_callback_arguments *args) {
|
||||
return UTP_GetMilliseconds();
|
||||
}
|
||||
|
||||
uint64 utp_default_get_microseconds(utp_callback_arguments *args) {
|
||||
return UTP_GetMicroseconds();
|
||||
}
|
27
vendor/github.com/anacrolix/go-libutp/utp_utils.h
generated
vendored
Normal file
27
vendor/github.com/anacrolix/go-libutp/utp_utils.h
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 BitTorrent, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
uint64 utp_default_get_udp_mtu(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_udp_overhead(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_random(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_milliseconds(utp_callback_arguments *args);
|
||||
uint64 utp_default_get_microseconds(utp_callback_arguments *args);
|
11
vendor/github.com/anacrolix/log/filter.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/log/filter.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package log
|
||||
|
||||
type FilterFunc func(m *Msg) bool
|
||||
|
||||
type Filter struct {
|
||||
ff FilterFunc
|
||||
}
|
||||
|
||||
func NewFilter(ff FilterFunc) *Filter {
|
||||
return &Filter{ff}
|
||||
}
|
1
vendor/github.com/anacrolix/log/go.mod
generated
vendored
Normal file
1
vendor/github.com/anacrolix/log/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/anacrolix/log
|
154
vendor/github.com/anacrolix/log/log.go
generated
vendored
Normal file
154
vendor/github.com/anacrolix/log/log.go
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
var Default = new(Logger)
|
||||
|
||||
func init() {
|
||||
Default.SetHandler(&StreamHandler{
|
||||
W: os.Stderr,
|
||||
Fmt: LineFormatter,
|
||||
})
|
||||
}
|
||||
|
||||
type Logger struct {
|
||||
hs map[Handler]struct{}
|
||||
values map[interface{}]struct{}
|
||||
filters map[*Filter]struct{}
|
||||
}
|
||||
|
||||
func (l *Logger) SetHandler(h Handler) {
|
||||
l.hs = map[Handler]struct{}{h: struct{}{}}
|
||||
}
|
||||
|
||||
func (l *Logger) Clone() *Logger {
|
||||
ret := &Logger{
|
||||
hs: make(map[Handler]struct{}),
|
||||
values: make(map[interface{}]struct{}),
|
||||
filters: make(map[*Filter]struct{}),
|
||||
}
|
||||
for h, v := range l.hs {
|
||||
ret.hs[h] = v
|
||||
}
|
||||
for v, v_ := range l.values {
|
||||
ret.values[v] = v_
|
||||
}
|
||||
for f := range l.filters {
|
||||
ret.filters[f] = struct{}{}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (l *Logger) AddValue(v interface{}) *Logger {
|
||||
l.values[v] = struct{}{}
|
||||
return l
|
||||
}
|
||||
|
||||
// rename Log to allow other implementers
|
||||
func (l *Logger) Handle(m Msg) {
|
||||
for v := range l.values {
|
||||
m.AddValue(v)
|
||||
}
|
||||
for f := range l.filters {
|
||||
if !f.ff(&m) {
|
||||
return
|
||||
}
|
||||
}
|
||||
for h := range l.hs {
|
||||
h.Emit(m)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) AddFilter(f *Filter) *Logger {
|
||||
if l.filters == nil {
|
||||
l.filters = make(map[*Filter]struct{})
|
||||
}
|
||||
l.filters[f] = struct{}{}
|
||||
return l
|
||||
}
|
||||
|
||||
type Handler interface {
|
||||
Emit(Msg)
|
||||
}
|
||||
|
||||
type ByteFormatter func(Msg) []byte
|
||||
|
||||
type StreamHandler struct {
|
||||
W io.Writer
|
||||
Fmt ByteFormatter
|
||||
}
|
||||
|
||||
func groupExtras(values map[interface{}]struct{}, fields map[string][]interface{}) (ret map[interface{}][]interface{}) {
|
||||
ret = make(map[interface{}][]interface{})
|
||||
for v := range values {
|
||||
ret[reflect.TypeOf(v)] = append(ret[reflect.TypeOf(v)], v)
|
||||
}
|
||||
for f, vs := range fields {
|
||||
ret[f] = append(ret[f], vs...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type extra struct {
|
||||
Key interface{}
|
||||
Values []interface{}
|
||||
}
|
||||
|
||||
func sortExtras(extras map[interface{}][]interface{}) (ret []extra) {
|
||||
for k, v := range extras {
|
||||
ret = append(ret, extra{k, v})
|
||||
}
|
||||
sort.Slice(ret, func(i, j int) bool {
|
||||
return fmt.Sprint(ret[i].Key) < fmt.Sprint(ret[j].Key)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func LineFormatter(msg Msg) []byte {
|
||||
ret := []byte(fmt.Sprintf(
|
||||
"%s %s: %s%s",
|
||||
time.Now().Format("2006-01-02 15:04:05"),
|
||||
humanPc(msg.callers[0]),
|
||||
msg.text,
|
||||
func() string {
|
||||
extras := groupExtras(msg.values, msg.fields)
|
||||
if len(extras) == 0 {
|
||||
return ""
|
||||
} else {
|
||||
return fmt.Sprintf(", %v", sortExtras(extras))
|
||||
}
|
||||
}(),
|
||||
))
|
||||
if ret[len(ret)-1] != '\n' {
|
||||
ret = append(ret, '\n')
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (me *StreamHandler) Emit(msg Msg) {
|
||||
me.W.Write(me.Fmt(msg))
|
||||
}
|
||||
|
||||
func Printf(format string, a ...interface{}) {
|
||||
Default.Handle(Fmsg(format, a...).Skip(1))
|
||||
}
|
||||
|
||||
func Print(v ...interface{}) {
|
||||
Default.Handle(Str(fmt.Sprint(v...)).Skip(1))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
77
vendor/github.com/anacrolix/log/msg.go
generated
vendored
Normal file
77
vendor/github.com/anacrolix/log/msg.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// maybe implement finalizer to ensure msgs are sunk
|
||||
type Msg struct {
|
||||
fields map[string][]interface{}
|
||||
values map[interface{}]struct{}
|
||||
text string
|
||||
callers [32]uintptr
|
||||
}
|
||||
|
||||
func Fmsg(format string, a ...interface{}) (m Msg) {
|
||||
m.text = fmt.Sprintf(format, a...)
|
||||
m.setCallers(1)
|
||||
return
|
||||
}
|
||||
|
||||
func Str(s string) (m Msg) {
|
||||
m.text = s
|
||||
m.setCallers(1)
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Msg) setCallers(skip int) {
|
||||
runtime.Callers(skip+2, m.callers[:])
|
||||
}
|
||||
|
||||
func (m Msg) Skip(skip int) Msg {
|
||||
copy(m.callers[:], m.callers[skip:])
|
||||
return m
|
||||
}
|
||||
|
||||
func (msg Msg) Add(key string, value interface{}) Msg {
|
||||
if msg.fields == nil {
|
||||
msg.fields = make(map[string][]interface{})
|
||||
}
|
||||
msg.fields[key] = append(msg.fields[key], value)
|
||||
return msg
|
||||
}
|
||||
|
||||
// rename sink
|
||||
func (msg Msg) Log(l *Logger) Msg {
|
||||
l.Handle(msg)
|
||||
return msg
|
||||
}
|
||||
|
||||
func (m Msg) Values() map[interface{}]struct{} {
|
||||
return m.values
|
||||
}
|
||||
|
||||
func (m Msg) AddValue(value interface{}) Msg {
|
||||
if m.values == nil {
|
||||
m.values = make(map[interface{}]struct{})
|
||||
}
|
||||
m.values[value] = struct{}{}
|
||||
return m
|
||||
}
|
||||
|
||||
func (m Msg) AddValues(values ...interface{}) Msg {
|
||||
for _, v := range values {
|
||||
m = m.AddValue(v)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func humanPc(pc uintptr) string {
|
||||
if pc == 0 {
|
||||
panic(pc)
|
||||
}
|
||||
f, _ := runtime.CallersFrames([]uintptr{pc}).Next()
|
||||
return fmt.Sprintf("%s:%d", filepath.Base(f.File), f.Line)
|
||||
}
|
21
vendor/github.com/anacrolix/missinggo/LICENSE
generated
vendored
Normal file
21
vendor/github.com/anacrolix/missinggo/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Matt Joiner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
4
vendor/github.com/anacrolix/missinggo/README.md
generated
vendored
Normal file
4
vendor/github.com/anacrolix/missinggo/README.md
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# missinggo
|
||||
[](https://godoc.org/github.com/anacrolix/missinggo)
|
||||
|
||||
Stuff that supplements Go's stdlib, or isn't significant enough to be in its own repo.
|
44
vendor/github.com/anacrolix/missinggo/addr.go
generated
vendored
Normal file
44
vendor/github.com/anacrolix/missinggo/addr.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Extracts the port as an integer from an address string.
|
||||
func AddrPort(addr net.Addr) int {
|
||||
switch raw := addr.(type) {
|
||||
case *net.UDPAddr:
|
||||
return raw.Port
|
||||
case *net.TCPAddr:
|
||||
return raw.Port
|
||||
default:
|
||||
_, port, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
i64, err := strconv.ParseInt(port, 0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return int(i64)
|
||||
}
|
||||
}
|
||||
|
||||
func AddrIP(addr net.Addr) net.IP {
|
||||
if addr == nil {
|
||||
return nil
|
||||
}
|
||||
switch raw := addr.(type) {
|
||||
case *net.UDPAddr:
|
||||
return raw.IP
|
||||
case *net.TCPAddr:
|
||||
return raw.IP
|
||||
default:
|
||||
host, _, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return net.ParseIP(host)
|
||||
}
|
||||
}
|
11
vendor/github.com/anacrolix/missinggo/atime.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/atime.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Extracts the access time from the FileInfo internals.
|
||||
func FileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
return fileInfoAccessTime(fi)
|
||||
}
|
14
vendor/github.com/anacrolix/missinggo/atime_atim.go
generated
vendored
Normal file
14
vendor/github.com/anacrolix/missinggo/atime_atim.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build linux dragonfly openbsd solaris
|
||||
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Stat_t).Atim
|
||||
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||
}
|
14
vendor/github.com/anacrolix/missinggo/atime_atimespec.go
generated
vendored
Normal file
14
vendor/github.com/anacrolix/missinggo/atime_atimespec.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build darwin freebsd netbsd
|
||||
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Stat_t).Atimespec
|
||||
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||
}
|
12
vendor/github.com/anacrolix/missinggo/atime_plan9.go
generated
vendored
Normal file
12
vendor/github.com/anacrolix/missinggo/atime_plan9.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
sec := fi.Sys().(*syscall.Dir).Atime
|
||||
return time.Unix(int64(sec), 0)
|
||||
}
|
12
vendor/github.com/anacrolix/missinggo/atime_windows.go
generated
vendored
Normal file
12
vendor/github.com/anacrolix/missinggo/atime_windows.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime
|
||||
return time.Unix(0, int64(ts.Nanoseconds()))
|
||||
}
|
171
vendor/github.com/anacrolix/missinggo/bitmap/bitmap.go
generated
vendored
Normal file
171
vendor/github.com/anacrolix/missinggo/bitmap/bitmap.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// Package bitmap provides a []bool/bitmap implementation with standardized
|
||||
// iteration. Bitmaps are the equivalent of []bool, with improved compression
|
||||
// for runs of similar values, and faster operations on ranges and the like.
|
||||
package bitmap
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/RoaringBitmap/roaring"
|
||||
|
||||
"github.com/anacrolix/missinggo/iter"
|
||||
)
|
||||
|
||||
const MaxInt = -1
|
||||
|
||||
type BitIndex = int
|
||||
|
||||
type Interface interface {
|
||||
Len() int
|
||||
}
|
||||
|
||||
// Bitmaps store the existence of values in [0,math.MaxUint32] more
|
||||
// efficiently than []bool. The empty value starts with no bits set.
|
||||
type Bitmap struct {
|
||||
rb *roaring.Bitmap
|
||||
}
|
||||
|
||||
var ToEnd int = -1
|
||||
|
||||
// The number of set bits in the bitmap. Also known as cardinality.
|
||||
func (me *Bitmap) Len() int {
|
||||
if me.rb == nil {
|
||||
return 0
|
||||
}
|
||||
return int(me.rb.GetCardinality())
|
||||
}
|
||||
|
||||
func (me Bitmap) ToSortedSlice() (ret []int) {
|
||||
if me.rb == nil {
|
||||
return
|
||||
}
|
||||
for _, ui32 := range me.rb.ToArray() {
|
||||
ret = append(ret, int(int32(ui32)))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *Bitmap) lazyRB() *roaring.Bitmap {
|
||||
if me.rb == nil {
|
||||
me.rb = roaring.NewBitmap()
|
||||
}
|
||||
return me.rb
|
||||
}
|
||||
|
||||
func (me Bitmap) Iter(cb iter.Callback) {
|
||||
me.IterTyped(func(i int) bool {
|
||||
return cb(i)
|
||||
})
|
||||
}
|
||||
|
||||
// Returns true if all values were traversed without early termination.
|
||||
func (me Bitmap) IterTyped(f func(int) bool) bool {
|
||||
if me.rb == nil {
|
||||
return true
|
||||
}
|
||||
it := me.rb.Iterator()
|
||||
for it.HasNext() {
|
||||
if !f(int(it.Next())) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkInt(i BitIndex) {
|
||||
if i < math.MinInt32 || i > math.MaxInt32 {
|
||||
panic("out of bounds")
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Bitmap) Add(is ...BitIndex) {
|
||||
rb := me.lazyRB()
|
||||
for _, i := range is {
|
||||
checkInt(i)
|
||||
rb.AddInt(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Bitmap) AddRange(begin, end BitIndex) {
|
||||
if begin >= end {
|
||||
return
|
||||
}
|
||||
me.lazyRB().AddRange(uint64(begin), uint64(end))
|
||||
}
|
||||
|
||||
func (me *Bitmap) Remove(i BitIndex) bool {
|
||||
if me.rb == nil {
|
||||
return false
|
||||
}
|
||||
return me.rb.CheckedRemove(uint32(i))
|
||||
}
|
||||
|
||||
func (me *Bitmap) Union(other Bitmap) {
|
||||
me.lazyRB().Or(other.lazyRB())
|
||||
}
|
||||
|
||||
func (me *Bitmap) Contains(i int) bool {
|
||||
if me.rb == nil {
|
||||
return false
|
||||
}
|
||||
return me.rb.Contains(uint32(i))
|
||||
}
|
||||
|
||||
func (me *Bitmap) Sub(other Bitmap) {
|
||||
if other.rb == nil {
|
||||
return
|
||||
}
|
||||
if me.rb == nil {
|
||||
return
|
||||
}
|
||||
me.rb.AndNot(other.rb)
|
||||
}
|
||||
|
||||
func (me *Bitmap) Clear() {
|
||||
if me.rb == nil {
|
||||
return
|
||||
}
|
||||
me.rb.Clear()
|
||||
}
|
||||
|
||||
func (me Bitmap) Copy() (ret Bitmap) {
|
||||
ret = me
|
||||
if ret.rb != nil {
|
||||
ret.rb = ret.rb.Clone()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *Bitmap) FlipRange(begin, end BitIndex) {
|
||||
me.lazyRB().FlipInt(begin, end)
|
||||
}
|
||||
|
||||
func (me *Bitmap) Get(bit BitIndex) bool {
|
||||
return me.rb != nil && me.rb.ContainsInt(bit)
|
||||
}
|
||||
|
||||
func (me *Bitmap) Set(bit BitIndex, value bool) {
|
||||
if value {
|
||||
me.lazyRB().AddInt(bit)
|
||||
} else {
|
||||
if me.rb != nil {
|
||||
me.rb.Remove(uint32(bit))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Bitmap) RemoveRange(begin, end BitIndex) *Bitmap {
|
||||
if me.rb == nil {
|
||||
return me
|
||||
}
|
||||
rangeEnd := uint64(end)
|
||||
if end == ToEnd {
|
||||
rangeEnd = 0x100000000
|
||||
}
|
||||
me.rb.RemoveRange(uint64(begin), rangeEnd)
|
||||
return me
|
||||
}
|
||||
|
||||
func (me Bitmap) IsEmpty() bool {
|
||||
return me.rb == nil || me.rb.IsEmpty()
|
||||
}
|
15
vendor/github.com/anacrolix/missinggo/bitmap/global.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/bitmap/global.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package bitmap
|
||||
|
||||
import "github.com/RoaringBitmap/roaring"
|
||||
|
||||
func Sub(left, right Bitmap) Bitmap {
|
||||
return Bitmap{
|
||||
rb: roaring.AndNot(left.lazyRB(), right.lazyRB()),
|
||||
}
|
||||
}
|
||||
|
||||
func Flip(bm Bitmap, start, end int) Bitmap {
|
||||
return Bitmap{
|
||||
rb: roaring.FlipInt(bm.lazyRB(), start, end),
|
||||
}
|
||||
}
|
24
vendor/github.com/anacrolix/missinggo/bitmap/iter.go
generated
vendored
Normal file
24
vendor/github.com/anacrolix/missinggo/bitmap/iter.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package bitmap
|
||||
|
||||
import "github.com/RoaringBitmap/roaring"
|
||||
|
||||
type Iter struct {
|
||||
ii roaring.IntIterable
|
||||
}
|
||||
|
||||
func (me *Iter) Next() bool {
|
||||
if me == nil {
|
||||
return false
|
||||
}
|
||||
return me.ii.HasNext()
|
||||
}
|
||||
|
||||
func (me *Iter) Value() interface{} {
|
||||
return me.ValueInt()
|
||||
}
|
||||
|
||||
func (me *Iter) ValueInt() int {
|
||||
return int(me.ii.Next())
|
||||
}
|
||||
|
||||
func (me *Iter) Stop() {}
|
46
vendor/github.com/anacrolix/missinggo/certdir.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/missinggo/certdir.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func LoadCertificateDir(dir string) (certs []tls.Certificate, err error) {
|
||||
d, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer d.Close()
|
||||
const defaultPEMFile = "default.pem"
|
||||
if p := filepath.Join(dir, defaultPEMFile); FilePathExists(p) {
|
||||
cert, err := tls.LoadX509KeyPair(p, p)
|
||||
if err == nil {
|
||||
certs = append(certs, cert)
|
||||
} else {
|
||||
log.Printf("error loading default certicate: %s", err)
|
||||
}
|
||||
}
|
||||
files, err := d.Readdir(-1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, f := range files {
|
||||
if f.Name() == defaultPEMFile {
|
||||
continue
|
||||
}
|
||||
if !strings.HasSuffix(f.Name(), ".pem") {
|
||||
continue
|
||||
}
|
||||
p := filepath.Join(dir, f.Name())
|
||||
cert, err := tls.LoadX509KeyPair(p, p)
|
||||
if err != nil {
|
||||
log.Printf("error loading key pair from %q: %s", p, err)
|
||||
continue
|
||||
}
|
||||
certs = append(certs, cert)
|
||||
}
|
||||
return
|
||||
}
|
36
vendor/github.com/anacrolix/missinggo/chancond.go
generated
vendored
Normal file
36
vendor/github.com/anacrolix/missinggo/chancond.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
type ChanCond struct {
|
||||
mu sync.Mutex
|
||||
ch chan struct{}
|
||||
}
|
||||
|
||||
func (me *ChanCond) Wait() <-chan struct{} {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.ch == nil {
|
||||
me.ch = make(chan struct{})
|
||||
}
|
||||
return me.ch
|
||||
}
|
||||
|
||||
func (me *ChanCond) Signal() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
select {
|
||||
case me.ch <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (me *ChanCond) Broadcast() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.ch == nil {
|
||||
return
|
||||
}
|
||||
close(me.ch)
|
||||
me.ch = nil
|
||||
}
|
34
vendor/github.com/anacrolix/missinggo/copy.go
generated
vendored
Normal file
34
vendor/github.com/anacrolix/missinggo/copy.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Copy elements from src to dst. Panics if the length of src and dst are
|
||||
// different.
|
||||
func CopyExact(dest interface{}, src interface{}) {
|
||||
dV := reflect.ValueOf(dest)
|
||||
sV := reflect.ValueOf(src)
|
||||
if dV.Kind() == reflect.Ptr {
|
||||
dV = dV.Elem()
|
||||
}
|
||||
if dV.Kind() == reflect.Array && !dV.CanAddr() {
|
||||
panic(fmt.Sprintf("dest not addressable: %T", dest))
|
||||
}
|
||||
if sV.Kind() == reflect.Ptr {
|
||||
sV = sV.Elem()
|
||||
}
|
||||
if sV.Kind() == reflect.String {
|
||||
sV = sV.Convert(reflect.SliceOf(dV.Type().Elem()))
|
||||
}
|
||||
if !sV.IsValid() {
|
||||
panic("invalid source, probably nil")
|
||||
}
|
||||
if dV.Len() != sV.Len() {
|
||||
panic(fmt.Sprintf("dest len (%d) != src len (%d)", dV.Len(), sV.Len()))
|
||||
}
|
||||
if dV.Len() != reflect.Copy(dV, sV) {
|
||||
panic("dammit")
|
||||
}
|
||||
}
|
18
vendor/github.com/anacrolix/missinggo/croak.go
generated
vendored
Normal file
18
vendor/github.com/anacrolix/missinggo/croak.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Unchomp(s string) string {
|
||||
if len(s) > 0 && s[len(s)-1] == '\n' {
|
||||
return s
|
||||
}
|
||||
return s + "\n"
|
||||
}
|
||||
|
||||
func Fatal(msg interface{}) {
|
||||
os.Stderr.WriteString(Unchomp(fmt.Sprint(msg)))
|
||||
os.Exit(1)
|
||||
}
|
3
vendor/github.com/anacrolix/missinggo/doc.go
generated
vendored
Normal file
3
vendor/github.com/anacrolix/missinggo/doc.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package missinggo contains miscellaneous helpers used in many of anacrolix'
|
||||
// projects.
|
||||
package missinggo
|
33
vendor/github.com/anacrolix/missinggo/empty_value.go
generated
vendored
Normal file
33
vendor/github.com/anacrolix/missinggo/empty_value.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package missinggo
|
||||
|
||||
import "reflect"
|
||||
|
||||
func IsZeroValue(i interface{}) bool {
|
||||
return IsEmptyValue(reflect.ValueOf(i))
|
||||
}
|
||||
|
||||
// Returns whether the value represents the empty value for its type. Used for
|
||||
// example to determine if complex types satisfy the common "omitempty" tag
|
||||
// option for marshalling. Taken from
|
||||
// http://stackoverflow.com/a/23555352/149482.
|
||||
func IsEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Func, reflect.Map, reflect.Slice:
|
||||
return v.IsNil()
|
||||
case reflect.Array:
|
||||
z := true
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
z = z && IsEmptyValue(v.Index(i))
|
||||
}
|
||||
return z
|
||||
case reflect.Struct:
|
||||
z := true
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
z = z && IsEmptyValue(v.Field(i))
|
||||
}
|
||||
return z
|
||||
}
|
||||
// Compare other types directly:
|
||||
z := reflect.Zero(v.Type())
|
||||
return v.Interface() == z.Interface()
|
||||
}
|
15
vendor/github.com/anacrolix/missinggo/encoding.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/encoding.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package missinggo
|
||||
|
||||
// An interface for "encoding/base64".Encoder
|
||||
type Encoding interface {
|
||||
EncodeToString([]byte) string
|
||||
DecodeString(string) ([]byte, error)
|
||||
}
|
||||
|
||||
// An encoding that does nothing.
|
||||
type IdentityEncoding struct{}
|
||||
|
||||
var _ Encoding = IdentityEncoding{}
|
||||
|
||||
func (IdentityEncoding) EncodeToString(b []byte) string { return string(b) }
|
||||
func (IdentityEncoding) DecodeString(s string) ([]byte, error) { return []byte(s), nil }
|
65
vendor/github.com/anacrolix/missinggo/event.go
generated
vendored
Normal file
65
vendor/github.com/anacrolix/missinggo/event.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
// Events are boolean flags that provide a channel that's closed when true.
|
||||
// This could go in the sync package, but that's more of a debug wrapper on
|
||||
// the standard library sync.
|
||||
type Event struct {
|
||||
ch chan struct{}
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (me *Event) LockedChan(lock sync.Locker) <-chan struct{} {
|
||||
lock.Lock()
|
||||
ch := me.C()
|
||||
lock.Unlock()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Returns a chan that is closed when the event is true.
|
||||
func (me *Event) C() <-chan struct{} {
|
||||
if me.ch == nil {
|
||||
me.ch = make(chan struct{})
|
||||
}
|
||||
return me.ch
|
||||
}
|
||||
|
||||
// TODO: Merge into Set.
|
||||
func (me *Event) Clear() {
|
||||
if me.closed {
|
||||
me.ch = nil
|
||||
me.closed = false
|
||||
}
|
||||
}
|
||||
|
||||
// Set the event to true/on.
|
||||
func (me *Event) Set() (first bool) {
|
||||
if me.closed {
|
||||
return false
|
||||
}
|
||||
if me.ch == nil {
|
||||
me.ch = make(chan struct{})
|
||||
}
|
||||
close(me.ch)
|
||||
me.closed = true
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: Change to Get.
|
||||
func (me *Event) IsSet() bool {
|
||||
return me.closed
|
||||
}
|
||||
|
||||
func (me *Event) Wait() {
|
||||
<-me.C()
|
||||
}
|
||||
|
||||
// TODO: Merge into Set.
|
||||
func (me *Event) SetBool(b bool) {
|
||||
if b {
|
||||
me.Set()
|
||||
} else {
|
||||
me.Clear()
|
||||
}
|
||||
}
|
26
vendor/github.com/anacrolix/missinggo/event_synchronized.go
generated
vendored
Normal file
26
vendor/github.com/anacrolix/missinggo/event_synchronized.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
type SynchronizedEvent struct {
|
||||
mu sync.Mutex
|
||||
e Event
|
||||
}
|
||||
|
||||
func (me *SynchronizedEvent) Set() {
|
||||
me.mu.Lock()
|
||||
me.e.Set()
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func (me *SynchronizedEvent) Clear() {
|
||||
me.mu.Lock()
|
||||
me.e.Clear()
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func (me *SynchronizedEvent) C() <-chan struct{} {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
return me.e.C()
|
||||
}
|
63
vendor/github.com/anacrolix/missinggo/expect/assert.go
generated
vendored
Normal file
63
vendor/github.com/anacrolix/missinggo/expect/assert.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package expect // import "github.com/anacrolix/missinggo/expect"
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func Nil(x interface{}) {
|
||||
if x != nil {
|
||||
panic(fmt.Sprintf("expected nil; got %v", x))
|
||||
}
|
||||
}
|
||||
|
||||
func NotNil(x interface{}) {
|
||||
if x == nil {
|
||||
panic(x)
|
||||
}
|
||||
}
|
||||
|
||||
func Equal(x, y interface{}) {
|
||||
if x == y {
|
||||
return
|
||||
}
|
||||
yAsXType := reflect.ValueOf(y).Convert(reflect.TypeOf(x)).Interface()
|
||||
if !reflect.DeepEqual(x, yAsXType) {
|
||||
panic(fmt.Sprintf("%v != %v", x, y))
|
||||
}
|
||||
}
|
||||
|
||||
func StrictlyEqual(x, y interface{}) {
|
||||
if x != y {
|
||||
panic(fmt.Sprintf("%s != %s", x, y))
|
||||
}
|
||||
}
|
||||
|
||||
func OneRowAffected(r sql.Result) {
|
||||
count, err := r.RowsAffected()
|
||||
Nil(err)
|
||||
if count != 1 {
|
||||
panic(count)
|
||||
}
|
||||
}
|
||||
|
||||
func True(b bool) {
|
||||
if !b {
|
||||
panic(b)
|
||||
}
|
||||
}
|
||||
|
||||
var Ok = True
|
||||
|
||||
func False(b bool) {
|
||||
if b {
|
||||
panic(b)
|
||||
}
|
||||
}
|
||||
|
||||
func Zero(x interface{}) {
|
||||
if x != reflect.Zero(reflect.TypeOf(x)).Interface() {
|
||||
panic(x)
|
||||
}
|
||||
}
|
35
vendor/github.com/anacrolix/missinggo/expvarIndentMap.go
generated
vendored
Normal file
35
vendor/github.com/anacrolix/missinggo/expvarIndentMap.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"expvar"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type IndentMap struct {
|
||||
expvar.Map
|
||||
}
|
||||
|
||||
var _ expvar.Var = (*IndentMap)(nil)
|
||||
|
||||
func NewExpvarIndentMap(name string) *IndentMap {
|
||||
v := new(IndentMap)
|
||||
v.Init()
|
||||
expvar.Publish(name, v)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *IndentMap) String() string {
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintf(&b, "{")
|
||||
first := true
|
||||
v.Do(func(kv expvar.KeyValue) {
|
||||
if !first {
|
||||
fmt.Fprintf(&b, ",")
|
||||
}
|
||||
fmt.Fprintf(&b, "\n\t%q: %v", kv.Key, kv.Value)
|
||||
first = false
|
||||
})
|
||||
fmt.Fprintf(&b, "}")
|
||||
return b.String()
|
||||
}
|
41
vendor/github.com/anacrolix/missinggo/flag.go
generated
vendored
Normal file
41
vendor/github.com/anacrolix/missinggo/flag.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
// Flag represents a boolean value, that signals sync.Cond's when it changes.
|
||||
// It's not concurrent safe by intention.
|
||||
type Flag struct {
|
||||
Conds map[*sync.Cond]struct{}
|
||||
value bool
|
||||
}
|
||||
|
||||
func (me *Flag) Set(value bool) {
|
||||
if value != me.value {
|
||||
me.broadcastChange()
|
||||
}
|
||||
me.value = value
|
||||
}
|
||||
|
||||
func (me *Flag) Get() bool {
|
||||
return me.value
|
||||
}
|
||||
|
||||
func (me *Flag) broadcastChange() {
|
||||
for cond := range me.Conds {
|
||||
cond.Broadcast()
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Flag) addCond(c *sync.Cond) {
|
||||
if me.Conds == nil {
|
||||
me.Conds = make(map[*sync.Cond]struct{})
|
||||
}
|
||||
me.Conds[c] = struct{}{}
|
||||
}
|
||||
|
||||
// Adds the sync.Cond to all the given Flag's.
|
||||
func AddCondToFlags(cond *sync.Cond, flags ...*Flag) {
|
||||
for _, f := range flags {
|
||||
f.addCond(cond)
|
||||
}
|
||||
}
|
18
vendor/github.com/anacrolix/missinggo/go.mod
generated
vendored
Normal file
18
vendor/github.com/anacrolix/missinggo/go.mod
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
module github.com/anacrolix/missinggo
|
||||
|
||||
require (
|
||||
github.com/RoaringBitmap/roaring v0.4.7
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa
|
||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
|
||||
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a
|
||||
github.com/huandu/xstrings v1.0.0
|
||||
github.com/philhofer/fwd v1.0.0
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46
|
||||
github.com/stretchr/testify v1.2.1
|
||||
github.com/tinylib/msgp v1.0.2
|
||||
)
|
52
vendor/github.com/anacrolix/missinggo/hostmaybeport.go
generated
vendored
Normal file
52
vendor/github.com/anacrolix/missinggo/hostmaybeport.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Represents a split host port.
|
||||
type HostMaybePort struct {
|
||||
Host string // Just the host, with no port.
|
||||
Port int // The port if NoPort is false.
|
||||
NoPort bool // Whether a port is specified.
|
||||
Err error // The error returned from net.SplitHostPort.
|
||||
}
|
||||
|
||||
func (me *HostMaybePort) String() string {
|
||||
if me.NoPort {
|
||||
return me.Host
|
||||
}
|
||||
return net.JoinHostPort(me.Host, strconv.FormatInt(int64(me.Port), 10))
|
||||
}
|
||||
|
||||
// Parse a "hostport" string, a concept that floats around the stdlib a lot
|
||||
// and is painful to work with. If no port is present, what's usually present
|
||||
// is just the host.
|
||||
func SplitHostMaybePort(hostport string) HostMaybePort {
|
||||
host, portStr, err := net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "missing port") {
|
||||
return HostMaybePort{
|
||||
Host: hostport,
|
||||
NoPort: true,
|
||||
}
|
||||
}
|
||||
return HostMaybePort{
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
portI64, err := strconv.ParseInt(portStr, 0, 0)
|
||||
if err != nil {
|
||||
return HostMaybePort{
|
||||
Host: host,
|
||||
Port: -1,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return HostMaybePort{
|
||||
Host: host,
|
||||
Port: int(portI64),
|
||||
}
|
||||
}
|
19
vendor/github.com/anacrolix/missinggo/hostport.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/missinggo/hostport.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ParseHostPort(hostport string) (host string, port int, err error) {
|
||||
host, portStr, err := net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
port64, err := strconv.ParseInt(portStr, 0, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
port = int(port64)
|
||||
return
|
||||
}
|
75
vendor/github.com/anacrolix/missinggo/httpresponsestatus.go
generated
vendored
Normal file
75
vendor/github.com/anacrolix/missinggo/httpresponsestatus.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package missinggo
|
||||
|
||||
// todo move to httptoo as ResponseRecorder
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A http.ResponseWriter that tracks the status of the response. The status
|
||||
// code, and number of bytes written for example.
|
||||
type StatusResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
Code int
|
||||
BytesWritten int64
|
||||
Started time.Time
|
||||
Ttfb time.Duration // Time to first byte
|
||||
GotFirstByte bool
|
||||
WroteHeader Event
|
||||
Hijacked bool
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
http.ResponseWriter
|
||||
http.Hijacker
|
||||
} = (*StatusResponseWriter)(nil)
|
||||
|
||||
func (me *StatusResponseWriter) Write(b []byte) (n int, err error) {
|
||||
// Exactly how it's done in the standard library. This ensures Code is
|
||||
// correct.
|
||||
if !me.WroteHeader.IsSet() {
|
||||
me.WriteHeader(http.StatusOK)
|
||||
}
|
||||
if !me.GotFirstByte && len(b) > 0 {
|
||||
if me.Started.IsZero() {
|
||||
panic("Started was not initialized")
|
||||
}
|
||||
me.Ttfb = time.Since(me.Started)
|
||||
me.GotFirstByte = true
|
||||
}
|
||||
n, err = me.ResponseWriter.Write(b)
|
||||
me.BytesWritten += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) WriteHeader(code int) {
|
||||
me.ResponseWriter.WriteHeader(code)
|
||||
if !me.WroteHeader.IsSet() {
|
||||
me.Code = code
|
||||
me.WroteHeader.Set()
|
||||
}
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) Hijack() (c net.Conn, b *bufio.ReadWriter, err error) {
|
||||
me.Hijacked = true
|
||||
c, b, err = me.ResponseWriter.(http.Hijacker).Hijack()
|
||||
if b.Writer.Buffered() != 0 {
|
||||
panic("unexpected buffered writes")
|
||||
}
|
||||
c = responseConn{c, me}
|
||||
return
|
||||
}
|
||||
|
||||
type responseConn struct {
|
||||
net.Conn
|
||||
s *StatusResponseWriter
|
||||
}
|
||||
|
||||
func (me responseConn) Write(b []byte) (n int, err error) {
|
||||
n, err = me.Conn.Write(b)
|
||||
me.s.BytesWritten += int64(n)
|
||||
return
|
||||
}
|
42
vendor/github.com/anacrolix/missinggo/httptoo/accept.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/missinggo/httptoo/accept.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/anacrolix/missinggo/mime"
|
||||
)
|
||||
|
||||
func ParseAccept(line string) (parsed AcceptDirectives, err error) {
|
||||
dirs := strings.Split(line, ",")
|
||||
for _, d := range dirs {
|
||||
p := AcceptDirective{
|
||||
Q: 1,
|
||||
}
|
||||
ss := strings.Split(d, ";")
|
||||
switch len(ss) {
|
||||
case 2:
|
||||
p.Q, err = strconv.ParseFloat(ss[1], 32)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 1:
|
||||
p.MimeType.FromString(ss[0])
|
||||
default:
|
||||
err = fmt.Errorf("error parsing %q", d)
|
||||
return
|
||||
}
|
||||
parsed = append(parsed, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type (
|
||||
AcceptDirectives []AcceptDirective
|
||||
AcceptDirective struct {
|
||||
MimeType mime.Type
|
||||
Q float64
|
||||
}
|
||||
)
|
106
vendor/github.com/anacrolix/missinggo/httptoo/bytes_content_range.go
generated
vendored
Normal file
106
vendor/github.com/anacrolix/missinggo/httptoo/bytes_content_range.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BytesContentRange struct {
|
||||
First, Last, Length int64
|
||||
}
|
||||
|
||||
type BytesRange struct {
|
||||
First, Last int64
|
||||
}
|
||||
|
||||
func (me BytesRange) String() string {
|
||||
if me.Last == math.MaxInt64 {
|
||||
return fmt.Sprintf("bytes=%d-", me.First)
|
||||
}
|
||||
return fmt.Sprintf("bytes=%d-%d", me.First, me.Last)
|
||||
}
|
||||
|
||||
var (
|
||||
httpBytesRangeRegexp = regexp.MustCompile(`bytes[ =](\d+)-(\d*)`)
|
||||
)
|
||||
|
||||
func ParseBytesRange(s string) (ret BytesRange, ok bool) {
|
||||
ss := httpBytesRangeRegexp.FindStringSubmatch(s)
|
||||
if ss == nil {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
ret.First, err = strconv.ParseInt(ss[1], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if ss[2] == "" {
|
||||
ret.Last = math.MaxInt64
|
||||
} else {
|
||||
ret.Last, err = strconv.ParseInt(ss[2], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
func parseUnitRanges(s string) (unit, ranges string) {
|
||||
s = strings.TrimSpace(s)
|
||||
i := strings.IndexAny(s, " =")
|
||||
if i == -1 {
|
||||
return
|
||||
}
|
||||
unit = s[:i]
|
||||
ranges = s[i+1:]
|
||||
return
|
||||
}
|
||||
|
||||
func parseFirstLast(s string) (first, last int64) {
|
||||
ss := strings.SplitN(s, "-", 2)
|
||||
first, err := strconv.ParseInt(ss[0], 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
last, err = strconv.ParseInt(ss[1], 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseContentRange(s string) (ret BytesContentRange) {
|
||||
ss := strings.SplitN(s, "/", 2)
|
||||
firstLast := strings.TrimSpace(ss[0])
|
||||
if firstLast == "*" {
|
||||
ret.First = -1
|
||||
ret.Last = -1
|
||||
} else {
|
||||
ret.First, ret.Last = parseFirstLast(firstLast)
|
||||
}
|
||||
il := strings.TrimSpace(ss[1])
|
||||
if il == "*" {
|
||||
ret.Length = -1
|
||||
} else {
|
||||
var err error
|
||||
ret.Length, err = strconv.ParseInt(il, 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ParseBytesContentRange(s string) (ret BytesContentRange, ok bool) {
|
||||
unit, ranges := parseUnitRanges(s)
|
||||
if unit != "bytes" {
|
||||
return
|
||||
}
|
||||
ret = parseContentRange(ranges)
|
||||
ok = true
|
||||
return
|
||||
}
|
19
vendor/github.com/anacrolix/missinggo/httptoo/client.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/missinggo/httptoo/client.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Returns the http.Client's TLS Config, traversing and generating any
|
||||
// defaults along the way to get it.
|
||||
func ClientTLSConfig(cl *http.Client) *tls.Config {
|
||||
if cl.Transport == nil {
|
||||
cl.Transport = http.DefaultTransport
|
||||
}
|
||||
tr := cl.Transport.(*http.Transport)
|
||||
if tr.TLSClientConfig == nil {
|
||||
tr.TLSClientConfig = &tls.Config{}
|
||||
}
|
||||
return tr.TLSClientConfig
|
||||
}
|
31
vendor/github.com/anacrolix/missinggo/httptoo/fs.go
generated
vendored
Normal file
31
vendor/github.com/anacrolix/missinggo/httptoo/fs.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Wraps a http.FileSystem, disabling directory listings, per the commonly
|
||||
// requested feature at https://groups.google.com/forum/#!topic/golang-
|
||||
// nuts/bStLPdIVM6w .
|
||||
type JustFilesFilesystem struct {
|
||||
Fs http.FileSystem
|
||||
}
|
||||
|
||||
func (fs JustFilesFilesystem) Open(name string) (http.File, error) {
|
||||
f, err := fs.Fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d, err := f.Stat()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
if d.IsDir() {
|
||||
f.Close()
|
||||
// This triggers http.FileServer to show a 404.
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
return f, nil
|
||||
}
|
49
vendor/github.com/anacrolix/missinggo/httptoo/gzip.go
generated
vendored
Normal file
49
vendor/github.com/anacrolix/missinggo/httptoo/gzip.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
haveWritten bool
|
||||
}
|
||||
|
||||
var _ http.ResponseWriter = &gzipResponseWriter{}
|
||||
|
||||
func (w *gzipResponseWriter) Write(b []byte) (int, error) {
|
||||
if w.haveWritten {
|
||||
goto write
|
||||
}
|
||||
w.haveWritten = true
|
||||
if w.Header().Get("Content-Type") != "" {
|
||||
goto write
|
||||
}
|
||||
if type_ := http.DetectContentType(b); type_ != "application/octet-stream" {
|
||||
w.Header().Set("Content-Type", type_)
|
||||
}
|
||||
write:
|
||||
return w.Writer.Write(b)
|
||||
}
|
||||
|
||||
// Gzips response body if the request says it'll allow it.
|
||||
func GzipHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") || w.Header().Get("Content-Encoding") != "" || w.Header().Get("Vary") != "" {
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
w.Header().Set("Vary", "Accept-Encoding")
|
||||
gz := gzip.NewWriter(w)
|
||||
defer gz.Close()
|
||||
h.ServeHTTP(&gzipResponseWriter{
|
||||
Writer: gz,
|
||||
ResponseWriter: w,
|
||||
}, r)
|
||||
})
|
||||
}
|
61
vendor/github.com/anacrolix/missinggo/httptoo/headers.go
generated
vendored
Normal file
61
vendor/github.com/anacrolix/missinggo/httptoo/headers.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Visibility int
|
||||
|
||||
const (
|
||||
Default = 0
|
||||
Public = 1
|
||||
Private = 2
|
||||
)
|
||||
|
||||
type CacheControlHeader struct {
|
||||
MaxAge time.Duration
|
||||
Caching Visibility
|
||||
NoStore bool
|
||||
}
|
||||
|
||||
func (me *CacheControlHeader) caching() []string {
|
||||
switch me.Caching {
|
||||
case Public:
|
||||
return []string{"public"}
|
||||
case Private:
|
||||
return []string{"private"}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (me *CacheControlHeader) maxAge() []string {
|
||||
if me.MaxAge == 0 {
|
||||
return nil
|
||||
}
|
||||
d := me.MaxAge
|
||||
if d < 0 {
|
||||
d = 0
|
||||
}
|
||||
return []string{fmt.Sprintf("max-age=%d", d/time.Second)}
|
||||
}
|
||||
|
||||
func (me *CacheControlHeader) noStore() []string {
|
||||
if me.NoStore {
|
||||
return []string{"no-store"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (me *CacheControlHeader) concat(sss ...[]string) (ret []string) {
|
||||
for _, ss := range sss {
|
||||
ret = append(ret, ss...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me CacheControlHeader) String() string {
|
||||
return strings.Join(me.concat(me.caching(), me.maxAge()), ", ")
|
||||
}
|
42
vendor/github.com/anacrolix/missinggo/httptoo/httptoo.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/missinggo/httptoo/httptoo.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bradfitz/iter"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
func OriginatingProtocol(r *http.Request) string {
|
||||
if fp := r.Header.Get("X-Forwarded-Proto"); fp != "" {
|
||||
return fp
|
||||
} else if r.TLS != nil {
|
||||
return "https"
|
||||
} else {
|
||||
return "http"
|
||||
}
|
||||
}
|
||||
|
||||
// Clears the named cookie for every domain that leads to the current one.
|
||||
func NukeCookie(w http.ResponseWriter, r *http.Request, name, path string) {
|
||||
parts := strings.Split(missinggo.SplitHostMaybePort(r.Host).Host, ".")
|
||||
for i := range iter.N(len(parts) + 1) { // Include the empty domain.
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: name,
|
||||
MaxAge: -1,
|
||||
Path: path,
|
||||
Domain: strings.Join(parts[i:], "."),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Performs quoted-string from http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html
|
||||
func EncodeQuotedString(s string) string {
|
||||
return strconv.Quote(s)
|
||||
}
|
||||
|
||||
// https://httpstatuses.com/499
|
||||
const StatusClientCancelledRequest = 499
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user