Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

414
vendor/github.com/akutz/memconn/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,414 @@
*.a
*.out
*.test
*.stderr
*.stdout
*.log
.vscode/
# Created by https://www.gitignore.io
### Windows ###
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### OSX ###
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
### Go ###
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
### SublimeText ###
# cache files for sublime text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
# workspace files are user-specific
*.sublime-workspace
# project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using SublimeText
# *.sublime-project
# sftp configuration file
sftp-config.json
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studo 2015 cache/options directory
.vs/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
*.[Cc]ache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
### Java ###
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties

21
vendor/github.com/akutz/memconn/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,21 @@
# Setting "sudo" to false forces Travis-CI to use its
# container-based build infrastructure, which has shorter
# queue times.
sudo: false
# Use the newer Travis-CI build templates based on the
# Debian Linux distribution "Trusty" release.
dist: trusty
# Select Go as the language used to run the buid.
language: go
go:
- 1.8.x
- 1.9.x
- 1.10.x
go_import_path: github.com/akutz/memconn
install: true
script:
- make test
- make benchmark

201
vendor/github.com/akutz/memconn/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

31
vendor/github.com/akutz/memconn/Makefile generated vendored Normal file
View File

@@ -0,0 +1,31 @@
SHELL := /bin/bash
all: build
build: memconn.a
memconn.a: $(filter-out %_test.go, $(wildcard *.go))
go build -o $@
GO_VERSION ?= 1.9.4
IMPORT_PATH := github.com/akutz/memconn
docker-run:
docker run --rm -it \
-v $$(pwd):/go/src/$(IMPORT_PATH) \
golang:$(GO_VERSION) \
make -C /go/src/$(IMPORT_PATH) $(MAKE_TARGET)
BENCH ?= .
benchmark:
go test -bench $(BENCH) -run Bench -benchmem .
benchmark-go1.9:
MAKE_TARGET=benchmark $(MAKE) docker-run
test:
go test
go test -race -run 'Race$$'
test-go1.9:
MAKE_TARGET=test $(MAKE) docker-run

38
vendor/github.com/akutz/memconn/README.md generated vendored Normal file
View File

@@ -0,0 +1,38 @@
# MemConn [![GoDoc](https://godoc.org/github.com/akutz/memconn?status.svg)](http://godoc.org/github.com/akutz/memconn) [![Build Status](http://travis-ci.org/akutz/memconn.svg?branch=master)](https://travis-ci.org/akutz/memconn) [![Go Report Card](http://goreportcard.com/badge/akutz/memconn)](http://goreportcard.com/report/akutz/memconn)
MemConn provides named, in-memory network connections for Go.
## Create a Server
A new `net.Listener` used to serve HTTP, gRPC, etc. is created with
`memconn.Listen`:
```go
lis, err := memconn.Listen("memu", "UniqueName")
```
## Creating a Client (Dial)
Clients can dial any named connection:
```go
client, err := memconn.Dial("memu", "UniqueName")
```
## Network Types
MemCon supports the following network types:
| Network | Description |
|---------|-------------|
| `memb` | A buffered, in-memory implementation of `net.Conn` |
| `memu` | An unbuffered, in-memory implementation of `net.Conn` |
## Performance
The benchmark results illustrate MemConn's performance versus TCP
and UNIX domain sockets:
![ops](https://imgur.com/o8mXla6.png "Ops (Larger is Better)")
![ns/op](https://imgur.com/8YvPmMU.png "Nanoseconds/Op (Smaller is Better)")
![B/op](https://imgur.com/vQSfIR2.png "Bytes/Op (Smaller is Better)")
![allocs/op](https://imgur.com/k263257.png "Allocs/Op (Smaller is Better)")
MemConn is more performant than TCP and UNIX domain sockets with respect
to the CPU. While MemConn does allocate more memory, this is to be expected
since MemConn is an in-memory implementation of the `net.Conn` interface.

1
vendor/github.com/akutz/memconn/VERSION generated vendored Normal file
View File

@@ -0,0 +1 @@
0.1.0

110
vendor/github.com/akutz/memconn/memconn.go generated vendored Normal file
View File

@@ -0,0 +1,110 @@
package memconn
import (
"context"
"net"
)
const (
// networkMemb is a buffered network connection. Write operations
// do not block as they are are buffered instead of waiting on a
// matching Read operation.
networkMemb = "memb"
// networkMemu is an unbuffered network connection. Write operations
// block until they are matched by a Read operation on the other side
// of the connected pipe.
networkMemu = "memu"
// addrLocalhost is a reserved address name. It is used when a
// Listen variant omits the local address or a Dial variant omits
// the remote address.
addrLocalhost = "localhost"
)
// provider is the package's default provider instance. All of the
// package-level functions interact with this object.
var provider Provider
// MapNetwork enables mapping the network value provided to this Provider's
// Dial and Listen functions from the specified "from" value to the
// specified "to" value.
//
// For example, calling MapNetwork("tcp", "memu") means a subsequent
// Dial("tcp", "address") gets translated to Dial("memu", "address").
//
// Calling MapNetwork("tcp", "") removes any previous translation for
// the "tcp" network.
func MapNetwork(from, to string) {
provider.MapNetwork(from, to)
}
// Listen begins listening at address for the specified network.
//
// Known networks are "memb" (memconn buffered) and "memu" (memconn unbuffered).
//
// When the specified address is already in use on the specified
// network an error is returned.
//
// When the provided network is unknown the operation defers to
// net.Dial.
func Listen(network, address string) (net.Listener, error) {
return provider.Listen(network, address)
}
// ListenMem begins listening at laddr.
//
// Known networks are "memb" (memconn buffered) and "memu" (memconn unbuffered).
//
// If laddr is nil then ListenMem listens on "localhost" on the
// specified network.
func ListenMem(network string, laddr *Addr) (*Listener, error) {
return provider.ListenMem(network, laddr)
}
// Dial dials a named connection.
//
// Known networks are "memb" (memconn buffered) and "memu" (memconn unbuffered).
//
// When the provided network is unknown the operation defers to
// net.Dial.
func Dial(network, address string) (net.Conn, error) {
return provider.Dial(network, address)
}
// DialContext dials a named connection using a
// Go context to provide timeout behavior.
//
// Please see Dial for more information.
func DialContext(
ctx context.Context,
network, address string) (net.Conn, error) {
return provider.DialContext(ctx, network, address)
}
// DialMem dials a named connection.
//
// Known networks are "memb" (memconn buffered) and "memu" (memconn unbuffered).
//
// If laddr is nil then a new address is generated using
// time.Now().UnixNano(). Please note that client addresses are
// not required to be unique.
//
// If raddr is nil then the "localhost" endpoint is used on the
// specified network.
func DialMem(network string, laddr, raddr *Addr) (*Conn, error) {
return provider.DialMem(network, laddr, raddr)
}
// DialMemContext dials a named connection using a
// Go context to provide timeout behavior.
//
// Please see DialMem for more information.
func DialMemContext(
ctx context.Context,
network string,
laddr, raddr *Addr) (*Conn, error) {
return provider.DialMemContext(ctx, network, laddr, raddr)
}

25
vendor/github.com/akutz/memconn/memconn_addr.go generated vendored Normal file
View File

@@ -0,0 +1,25 @@
package memconn
// Addr represents the address of an in-memory endpoint.
type Addr struct {
// Name is the name of the endpoint.
Name string
network string
}
// Buffered indicates whether or not the address refers to a buffered
// network type.
func (a Addr) Buffered() bool {
return a.network == networkMemb
}
// Network returns the address's network.
func (a Addr) Network() string {
return a.network
}
// String returns the address's name.
func (a Addr) String() string {
return a.Name
}

434
vendor/github.com/akutz/memconn/memconn_conn.go generated vendored Normal file
View File

@@ -0,0 +1,434 @@
package memconn
import (
"net"
"sync"
"time"
)
// Conn is an in-memory implementation of Golang's "net.Conn" interface.
type Conn struct {
pipe
laddr Addr
raddr Addr
// buf contains information about the connection's buffer state if
// the connection is buffered. Otherwise this field is nil.
buf *bufConn
}
type bufConn struct {
// Please see the SetCopyOnWrite function for more information.
cow bool
// Please see the SetBufferSize function for more information.
max uint64
// cur is the amount of buffered, pending Write data
cur uint64
// cond is a condition used to wait when writing buffered data
cond sync.Cond
// mu is the mutex used by the condition. The mutex is exposed
// directly in order to access RLock and RUnlock for getting the
// buffer size.
mu sync.RWMutex
// errs is the error channel returned by the Errs() function and
// used to report erros that occur as a result of buffered write
// operations. If the pipe does not use buffered writes then this
// field will always be nil.
errs chan error
// Please see the SetCloseTimeout function for more information.
closeTimeout time.Duration
}
func makeNewConns(network string, laddr, raddr Addr) (*Conn, *Conn) {
// This code is duplicated from the Pipe() function from the file
// "memconn_pipe.go". The reason for the duplication is to optimize
// the performance by removing the need to wrap the *pipe values as
// interface{} objects out of the Pipe() function and assert them
// back as *pipe* objects in this function.
cb1 := make(chan []byte)
cb2 := make(chan []byte)
cn1 := make(chan int)
cn2 := make(chan int)
done1 := make(chan struct{})
done2 := make(chan struct{})
// Wrap the pipes with Conn to support:
//
// * The correct address information for the functions LocalAddr()
// and RemoteAddr() return the
// * Errors returns from the internal pipe are checked and
// have their internal OpError addr information replaced with
// the correct address information.
// * A channel can be setup to cause the event of the Listener
// closing closes the remoteConn immediately.
// * Buffered writes
local := &Conn{
pipe: pipe{
rdRx: cb1, rdTx: cn1,
wrTx: cb2, wrRx: cn2,
localDone: done1, remoteDone: done2,
readDeadline: makePipeDeadline(),
writeDeadline: makePipeDeadline(),
},
laddr: laddr,
raddr: raddr,
}
remote := &Conn{
pipe: pipe{
rdRx: cb2, rdTx: cn2,
wrTx: cb1, wrRx: cn1,
localDone: done2, remoteDone: done1,
readDeadline: makePipeDeadline(),
writeDeadline: makePipeDeadline(),
},
laddr: raddr,
raddr: laddr,
}
if laddr.Buffered() {
local.buf = &bufConn{
errs: make(chan error),
closeTimeout: 10 * time.Second,
}
local.buf.cond.L = &local.buf.mu
}
if raddr.Buffered() {
remote.buf = &bufConn{
errs: make(chan error),
closeTimeout: 10 * time.Second,
}
remote.buf.cond.L = &remote.buf.mu
}
return local, remote
}
// LocalBuffered returns a flag indicating whether or not the local side
// of the connection is buffered.
func (c *Conn) LocalBuffered() bool {
return c.laddr.Buffered()
}
// RemoteBuffered returns a flag indicating whether or not the remote side
// of the connection is buffered.
func (c *Conn) RemoteBuffered() bool {
return c.raddr.Buffered()
}
// BufferSize gets the number of bytes allowed to be queued for
// asynchrnous Write operations.
//
// Please note that this function will always return zero for unbuffered
// connections.
//
// Please see the function SetBufferSize for more information.
func (c *Conn) BufferSize() uint64 {
if c.laddr.Buffered() {
c.buf.mu.RLock()
defer c.buf.mu.RUnlock()
return c.buf.max
}
return 0
}
// SetBufferSize sets the number of bytes allowed to be queued for
// asynchronous Write operations. Once the amount of data pending a Write
// operation exceeds the specified size, subsequent Writes will
// block until the queued data no longer exceeds the allowed ceiling.
//
// A value of zero means no maximum is defined.
//
// If a Write operation's payload length exceeds the buffer size
// (except for zero) then the Write operation is handled synchronously.
//
// Please note that setting the buffer size has no effect on unbuffered
// connections.
func (c *Conn) SetBufferSize(i uint64) {
if c.laddr.Buffered() {
c.buf.cond.L.Lock()
defer c.buf.cond.L.Unlock()
c.buf.max = i
}
}
// CloseTimeout gets the time.Duration value used when closing buffered
// connections.
//
// Please note that this function will always return zero for
// unbuffered connections.
//
// Please see the function SetCloseTimeout for more information.
func (c *Conn) CloseTimeout() time.Duration {
if c.laddr.Buffered() {
c.buf.mu.RLock()
defer c.buf.mu.RUnlock()
return c.buf.closeTimeout
}
return 0
}
// SetCloseTimeout sets a time.Duration value used by the Close function
// to determine the amount of time to wait for pending, buffered Writes
// to complete before closing the connection.
//
// The default timeout value is 10 seconds. A zero value does not
// mean there is no timeout, rather it means the timeout is immediate.
//
// Please note that setting this value has no effect on unbuffered
// connections.
func (c *Conn) SetCloseTimeout(duration time.Duration) {
if c.laddr.Buffered() {
c.buf.cond.L.Lock()
defer c.buf.cond.L.Unlock()
c.buf.closeTimeout = duration
}
}
// CopyOnWrite gets a flag indicating whether or not copy-on-write is
// enabled for this connection.
//
// Please note that this function will always return false for
// unbuffered connections.
//
// Please see the function SetCopyOnWrite for more information.
func (c *Conn) CopyOnWrite() bool {
if c.laddr.Buffered() {
c.buf.mu.RLock()
defer c.buf.mu.RUnlock()
return c.buf.cow
}
return false
}
// SetCopyOnWrite sets a flag indicating whether or not copy-on-write
// is enabled for this connection.
//
// When a connection is buffered, data submitted to a Write operation
// is processed in a goroutine and the function returns control to the
// caller immediately. Because of this, it's possible to modify the
// data provided to the Write function before or during the actual
// Write operation. Enabling copy-on-write causes the payload to be
// copied to a new buffer before control is returned to the caller.
//
// Please note that enabling copy-on-write will double the amount of
// memory required for all Write operations.
//
// Please note that enabling copy-on-write has no effect on unbuffered
// connections.
func (c *Conn) SetCopyOnWrite(enabled bool) {
if c.laddr.Buffered() {
c.buf.cond.L.Lock()
defer c.buf.cond.L.Unlock()
c.buf.cow = enabled
}
}
// LocalAddr implements the net.Conn LocalAddr method.
func (c *Conn) LocalAddr() net.Addr {
return c.laddr
}
// RemoteAddr implements the net.Conn RemoteAddr method.
func (c *Conn) RemoteAddr() net.Addr {
return c.raddr
}
// Close implements the net.Conn Close method.
func (c *Conn) Close() error {
c.pipe.once.Do(func() {
// Buffered connections will attempt to wait until all
// pending Writes are completed, until the specified
// timeout value has elapsed, or until the remote side
// of the connection is closed.
if c.laddr.Buffered() {
c.buf.mu.RLock()
timeout := c.buf.closeTimeout
c.buf.mu.RUnlock()
// Set up a channel that is closed when the specified
// timer elapses.
timeoutDone := make(chan struct{})
if timeout == 0 {
close(timeoutDone)
} else {
time.AfterFunc(timeout, func() { close(timeoutDone) })
}
// Set up a channel that is closed when the number of
// pending bytes is zero.
writesDone := make(chan struct{})
go func() {
c.buf.cond.L.Lock()
for c.buf.cur > 0 {
c.buf.cond.Wait()
}
close(writesDone)
c.buf.cond.L.Unlock()
}()
// Wait to close the connection.
select {
case <-writesDone:
case <-timeoutDone:
case <-c.pipe.remoteDone:
}
}
close(c.pipe.localDone)
})
return nil
}
// Errs returns a channel that receives errors that may occur as the
// result of buffered write operations.
//
// This function will always return nil for unbuffered connections.
//
// Please note that the channel returned by this function is not closed
// when the connection is closed. This is because errors may continue
// to be sent over this channel as the result of asynchronous writes
// occurring after the connection is closed. Therefore this channel
// should not be used to determine when the connection is closed.
func (c *Conn) Errs() <-chan error {
return c.buf.errs
}
// Read implements the net.Conn Read method.
func (c *Conn) Read(b []byte) (int, error) {
n, err := c.pipe.Read(b)
if err != nil {
if e, ok := err.(*net.OpError); ok {
e.Addr = c.raddr
e.Source = c.laddr
return n, e
}
return n, &net.OpError{
Op: "read",
Addr: c.raddr,
Source: c.laddr,
Net: c.raddr.Network(),
Err: err,
}
}
return n, nil
}
// Write implements the net.Conn Write method.
func (c *Conn) Write(b []byte) (int, error) {
if c.laddr.Buffered() {
return c.writeAsync(b)
}
return c.writeSync(b)
}
func (c *Conn) writeSync(b []byte) (int, error) {
n, err := c.pipe.Write(b)
if err != nil {
if e, ok := err.(*net.OpError); ok {
e.Addr = c.raddr
e.Source = c.laddr
return n, e
}
return n, &net.OpError{
Op: "write",
Addr: c.raddr,
Source: c.laddr,
Net: c.raddr.Network(),
Err: err,
}
}
return n, nil
}
// writeAsync performs the Write operation in a goroutine. This
// behavior means the Write operation is not blocking, but also means
// that when Write operations fail the associated error is not returned
// from this function.
func (c *Conn) writeAsync(b []byte) (int, error) {
// Perform a synchronous Write if the connection has a non-zero
// value for the maximum allowed buffer size and if the size of
// the payload exceeds that maximum value.
if c.buf.max > 0 && uint64(len(b)) > c.buf.max {
return c.writeSync(b)
}
// Block the operation from proceeding until there is available
// buffer space.
c.buf.cond.L.Lock()
for c.buf.max > 0 && uint64(len(b))+c.buf.cur > c.buf.max {
c.buf.cond.Wait()
}
// Copy the buffer if the connection uses copy-on-write.
cb := b
if c.buf.cow {
cb = make([]byte, len(b))
copy(cb, b)
}
// Update the amount of active data being written.
c.buf.cur = c.buf.cur + uint64(len(cb))
c.buf.cond.L.Unlock()
go func() {
if _, err := c.writeSync(cb); err != nil {
go func() { c.buf.errs <- err }()
}
// Decrement the enqueued buffer size and signal a blocked
// goroutine that it may proceed
c.buf.cond.L.Lock()
c.buf.cur = c.buf.cur - uint64(len(cb))
c.buf.cond.L.Unlock()
c.buf.cond.Signal()
}()
return len(cb), nil
}
// SetReadDeadline implements the net.Conn SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
if err := c.pipe.SetReadDeadline(t); err != nil {
if e, ok := err.(*net.OpError); ok {
e.Addr = c.laddr
e.Source = c.laddr
return e
}
return &net.OpError{
Op: "setReadDeadline",
Addr: c.laddr,
Source: c.laddr,
Net: c.laddr.Network(),
Err: err,
}
}
return nil
}
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
if err := c.pipe.SetWriteDeadline(t); err != nil {
if e, ok := err.(*net.OpError); ok {
e.Addr = c.laddr
e.Source = c.laddr
return e
}
return &net.OpError{
Op: "setWriteDeadline",
Addr: c.laddr,
Source: c.laddr,
Net: c.laddr.Network(),
Err: err,
}
}
return nil
}

105
vendor/github.com/akutz/memconn/memconn_listener.go generated vendored Normal file
View File

@@ -0,0 +1,105 @@
package memconn
import (
"context"
"errors"
"net"
"sync"
)
// Listener implements the net.Listener interface.
type Listener struct {
addr Addr
once sync.Once
rcvr chan *Conn
done chan struct{}
rmvd chan struct{}
}
func (l *Listener) dial(
ctx context.Context,
network string,
laddr, raddr Addr) (*Conn, error) {
local, remote := makeNewConns(network, laddr, raddr)
// TODO Figure out if this logic is valid.
//
// Start a goroutine that closes the remote side of the connection
// as soon as the listener's done channel is no longer blocked.
//go func() {
// <-l.done
// remoteConn.Close()
//}()
// If the provided context is nill then announce a new connection
// by placing the new remoteConn onto the rcvr channel. An Accept
// call from this listener will remove the remoteConn from the channel.
if ctx == nil {
l.rcvr <- remote
return local, nil
}
// Announce a new connection by placing the new remoteConn
// onto the rcvr channel. An Accept call from this listener will
// remove the remoteConn from the channel. However, if that does
// not occur by the time the context times out / is cancelled, then
// an error is returned.
select {
case l.rcvr <- remote:
return local, nil
case <-ctx.Done():
local.Close()
remote.Close()
return nil, &net.OpError{
Addr: raddr,
Source: laddr,
Net: network,
Op: "dial",
Err: ctx.Err(),
}
}
}
// Accept implements the net.Listener Accept method.
func (l *Listener) Accept() (net.Conn, error) {
return l.AcceptMemConn()
}
// AcceptMemConn implements the net.Listener Accept method logic and
// returns a *memconn.Conn object.
func (l *Listener) AcceptMemConn() (*Conn, error) {
select {
case remoteConn, ok := <-l.rcvr:
if ok {
return remoteConn, nil
}
return nil, &net.OpError{
Addr: l.addr,
Source: l.addr,
Net: l.addr.Network(),
Err: errors.New("listener closed"),
}
case <-l.done:
return nil, &net.OpError{
Addr: l.addr,
Source: l.addr,
Net: l.addr.Network(),
Err: errors.New("listener closed"),
}
}
}
// Close implements the net.Listener Close method.
func (l *Listener) Close() error {
l.once.Do(func() {
close(l.done)
<-l.rmvd
})
return nil
}
// Addr implements the net.Listener Addr method.
func (l *Listener) Addr() net.Addr {
return l.addr
}

265
vendor/github.com/akutz/memconn/memconn_pipe.go generated vendored Normal file
View File

@@ -0,0 +1,265 @@
// This file was copied from Go stdlib "net/pipe.go"
// and modified in order to optimally support:
//
// * Buffered writes
// * Custom local and remote address values
// * Error values that follow net.Conn's rules regarding
// net.OpError
//
// The above features could be implemented using the "net.Conn" values
// returned from the function "net.Pipe", but much of the same code
// would need to be duplicated regarding deadlines, done semantics, etc.
// Using the private "pipe" struct as the basis of a new, composite type
// is much more performant.
//
// FYI, the reason a new, composite type is used instead of modifying
// the existing type, "pipe", is to make it easier to replace this
// file with whatever changes Go stdlib make make to "net/pipe.go" in
// the future.
//
// This file is a Golang stdlib type and so the Go license is included:
//
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package memconn
import (
"io"
"net"
"sync"
"time"
)
// pipeDeadline is an abstraction for handling timeouts.
type pipeDeadline struct {
mu sync.Mutex // Guards timer and cancel
timer *time.Timer
cancel chan struct{} // Must be non-nil
}
func makePipeDeadline() pipeDeadline {
return pipeDeadline{cancel: make(chan struct{})}
}
// set sets the point in time when the deadline will time out.
// A timeout event is signaled by closing the channel returned by waiter.
// Once a timeout has occurred, the deadline can be refreshed by specifying a
// t value in the future.
//
// A zero value for t prevents timeout.
func (d *pipeDeadline) set(t time.Time) {
d.mu.Lock()
defer d.mu.Unlock()
if d.timer != nil && !d.timer.Stop() {
<-d.cancel // Wait for the timer callback to finish and close cancel
}
d.timer = nil
// Time is zero, then there is no deadline.
closed := isClosedChan(d.cancel)
if t.IsZero() {
if closed {
d.cancel = make(chan struct{})
}
return
}
// Time in the future, setup a timer to cancel in the future.
if dur := time.Until(t); dur > 0 {
if closed {
d.cancel = make(chan struct{})
}
d.timer = time.AfterFunc(dur, func() {
close(d.cancel)
})
return
}
// Time in the past, so close immediately.
if !closed {
close(d.cancel)
}
}
// wait returns a channel that is closed when the deadline is exceeded.
func (d *pipeDeadline) wait() chan struct{} {
d.mu.Lock()
defer d.mu.Unlock()
return d.cancel
}
func isClosedChan(c <-chan struct{}) bool {
select {
case <-c:
return true
default:
return false
}
}
type timeoutError struct{}
func (timeoutError) Error() string { return "deadline exceeded" }
func (timeoutError) Timeout() bool { return true }
func (timeoutError) Temporary() bool { return true }
type pipeAddr struct{}
func (pipeAddr) Network() string { return "pipe" }
func (pipeAddr) String() string { return "pipe" }
type pipe struct {
wrMu sync.Mutex // Serialize Write operations
// Used by local Read to interact with remote Write.
// Successful receive on rdRx is always followed by send on rdTx.
rdRx <-chan []byte
rdTx chan<- int
// Used by local Write to interact with remote Read.
// Successful send on wrTx is always followed by receive on wrRx.
wrTx chan<- []byte
wrRx <-chan int
once sync.Once // Protects closing localDone
localDone chan struct{}
remoteDone <-chan struct{}
readDeadline pipeDeadline
writeDeadline pipeDeadline
}
// Pipe creates a synchronous, in-memory, full duplex
// network connection; both ends implement the Conn interface.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal
// buffering.
func Pipe() (net.Conn, net.Conn) {
cb1 := make(chan []byte)
cb2 := make(chan []byte)
cn1 := make(chan int)
cn2 := make(chan int)
done1 := make(chan struct{})
done2 := make(chan struct{})
p1 := &pipe{
rdRx: cb1, rdTx: cn1,
wrTx: cb2, wrRx: cn2,
localDone: done1, remoteDone: done2,
readDeadline: makePipeDeadline(),
writeDeadline: makePipeDeadline(),
}
p2 := &pipe{
rdRx: cb2, rdTx: cn2,
wrTx: cb1, wrRx: cn1,
localDone: done2, remoteDone: done1,
readDeadline: makePipeDeadline(),
writeDeadline: makePipeDeadline(),
}
return p1, p2
}
func (*pipe) LocalAddr() net.Addr { return pipeAddr{} }
func (*pipe) RemoteAddr() net.Addr { return pipeAddr{} }
func (p *pipe) Read(b []byte) (int, error) {
n, err := p.read(b)
if err != nil && err != io.EOF && err != io.ErrClosedPipe {
err = &net.OpError{Op: "read", Net: "pipe", Err: err}
}
return n, err
}
func (p *pipe) read(b []byte) (n int, err error) {
switch {
case isClosedChan(p.localDone):
return 0, io.ErrClosedPipe
case isClosedChan(p.remoteDone):
return 0, io.EOF
case isClosedChan(p.readDeadline.wait()):
return 0, timeoutError{}
}
select {
case bw := <-p.rdRx:
nr := copy(b, bw)
p.rdTx <- nr
return nr, nil
case <-p.localDone:
return 0, io.ErrClosedPipe
case <-p.remoteDone:
return 0, io.EOF
case <-p.readDeadline.wait():
return 0, timeoutError{}
}
}
func (p *pipe) Write(b []byte) (int, error) {
n, err := p.write(b)
if err != nil && err != io.ErrClosedPipe {
err = &net.OpError{Op: "write", Net: "pipe", Err: err}
}
return n, err
}
func (p *pipe) write(b []byte) (n int, err error) {
switch {
case isClosedChan(p.localDone):
return 0, io.ErrClosedPipe
case isClosedChan(p.remoteDone):
return 0, io.ErrClosedPipe
case isClosedChan(p.writeDeadline.wait()):
return 0, timeoutError{}
}
p.wrMu.Lock() // Ensure entirety of b is written together
defer p.wrMu.Unlock()
for once := true; once || len(b) > 0; once = false {
select {
case p.wrTx <- b:
nw := <-p.wrRx
b = b[nw:]
n += nw
case <-p.localDone:
return n, io.ErrClosedPipe
case <-p.remoteDone:
return n, io.ErrClosedPipe
case <-p.writeDeadline.wait():
return n, timeoutError{}
}
}
return n, nil
}
func (p *pipe) SetDeadline(t time.Time) error {
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
return io.ErrClosedPipe
}
p.readDeadline.set(t)
p.writeDeadline.set(t)
return nil
}
func (p *pipe) SetReadDeadline(t time.Time) error {
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
return io.ErrClosedPipe
}
p.readDeadline.set(t)
return nil
}
func (p *pipe) SetWriteDeadline(t time.Time) error {
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
return io.ErrClosedPipe
}
p.writeDeadline.set(t)
return nil
}
func (p *pipe) Close() error {
p.once.Do(func() { close(p.localDone) })
return nil
}

245
vendor/github.com/akutz/memconn/memconn_provider.go generated vendored Normal file
View File

@@ -0,0 +1,245 @@
package memconn
import (
"context"
"errors"
"fmt"
"net"
"sync"
"time"
)
// Provider is used to track named MemConn objects.
type Provider struct {
nets networkMap
listeners listenerCache
}
type listenerCache struct {
sync.RWMutex
cache map[string]*Listener
}
type networkMap struct {
sync.RWMutex
cache map[string]string
}
// MapNetwork enables mapping the network value provided to this Provider's
// Dial and Listen functions from the specified "from" value to the
// specified "to" value.
//
// For example, calling MapNetwork("tcp", "memu") means a subsequent
// Dial("tcp", "address") gets translated to Dial("memu", "address").
//
// Calling MapNetwork("tcp", "") removes any previous translation for
// the "tcp" network.
func (p *Provider) MapNetwork(from, to string) {
p.nets.Lock()
defer p.nets.Unlock()
if p.nets.cache == nil {
p.nets.cache = map[string]string{}
}
if to == "" {
delete(p.nets.cache, from)
return
}
p.nets.cache[from] = to
}
func (p *Provider) mapNetwork(network string) string {
p.nets.RLock()
defer p.nets.RUnlock()
if to, ok := p.nets.cache[network]; ok {
return to
}
return network
}
// Listen begins listening at address for the specified network.
//
// Known networks are "memb" (memconn buffered) and "memu" (memconn unbuffered).
//
// When the specified address is already in use on the specified
// network an error is returned.
//
// When the provided network is unknown the operation defers to
// net.Dial.
func (p *Provider) Listen(network, address string) (net.Listener, error) {
switch p.mapNetwork(network) {
case networkMemb, networkMemu:
return p.ListenMem(
network, &Addr{Name: address, network: network})
default:
return net.Listen(network, address)
}
}
// ListenMem begins listening at laddr.
//
// Known networks are "memb" (memconn buffered) and "memu" (memconn unbuffered).
//
// If laddr is nil then ListenMem listens on "localhost" on the
// specified network.
func (p *Provider) ListenMem(network string, laddr *Addr) (*Listener, error) {
switch p.mapNetwork(network) {
case networkMemb, networkMemu:
// If laddr is not specified then set it to the reserved name
// "localhost".
if laddr == nil {
laddr = &Addr{Name: addrLocalhost, network: network}
} else {
laddr.network = network
}
default:
return nil, &net.OpError{
Addr: laddr,
Source: laddr,
Net: network,
Op: "listen",
Err: errors.New("unknown network"),
}
}
p.listeners.Lock()
defer p.listeners.Unlock()
if p.listeners.cache == nil {
p.listeners.cache = map[string]*Listener{}
}
if _, ok := p.listeners.cache[laddr.Name]; ok {
return nil, &net.OpError{
Addr: laddr,
Source: laddr,
Net: network,
Op: "listen",
Err: errors.New("addr unavailable"),
}
}
l := &Listener{
addr: *laddr,
done: make(chan struct{}),
rmvd: make(chan struct{}),
rcvr: make(chan *Conn, 1),
}
// Start a goroutine that removes the listener from
// the cache once the listener is closed.
go func() {
<-l.done
p.listeners.Lock()
defer p.listeners.Unlock()
delete(p.listeners.cache, laddr.Name)
close(l.rmvd)
}()
p.listeners.cache[laddr.Name] = l
return l, nil
}
// Dial dials a named connection.
//
// Known networks are "memb" (memconn buffered) and "memu" (memconn unbuffered).
//
// When the provided network is unknown the operation defers to
// net.Dial.
func (p *Provider) Dial(network, address string) (net.Conn, error) {
return p.DialContext(nil, network, address)
}
// DialMem dials a named connection.
//
// Known networks are "memb" (memconn buffered) and "memu" (memconn unbuffered).
//
// If laddr is nil then a new address is generated using
// time.Now().UnixNano(). Please note that client addresses are
// not required to be unique.
//
// If raddr is nil then the "localhost" endpoint is used on the
// specified network.
func (p *Provider) DialMem(
network string, laddr, raddr *Addr) (*Conn, error) {
return p.DialMemContext(nil, network, laddr, raddr)
}
// DialContext dials a named connection using a
// Go context to provide timeout behavior.
//
// Please see Dial for more information.
func (p *Provider) DialContext(
ctx context.Context,
network, address string) (net.Conn, error) {
switch p.mapNetwork(network) {
case networkMemb, networkMemu:
return p.DialMemContext(
ctx, network, nil, &Addr{
Name: address,
network: network,
})
default:
if ctx == nil {
return net.Dial(network, address)
}
return (&net.Dialer{}).DialContext(ctx, network, address)
}
}
// DialMemContext dials a named connection using a
// Go context to provide timeout behavior.
//
// Please see DialMem for more information.
func (p *Provider) DialMemContext(
ctx context.Context,
network string,
laddr, raddr *Addr) (*Conn, error) {
switch p.mapNetwork(network) {
case networkMemb, networkMemu:
// If laddr is not specified then create one with the current
// epoch in nanoseconds. This value need not be unique.
if laddr == nil {
laddr = &Addr{
Name: fmt.Sprintf("%d", time.Now().UnixNano()),
network: network,
}
} else {
laddr.network = network
}
if raddr == nil {
raddr = &Addr{Name: addrLocalhost, network: network}
} else {
raddr.network = network
}
default:
return nil, &net.OpError{
Addr: raddr,
Source: laddr,
Net: network,
Op: "dial",
Err: errors.New("unknown network"),
}
}
p.listeners.RLock()
defer p.listeners.RUnlock()
if l, ok := p.listeners.cache[raddr.Name]; ok {
// Update the provided raddr with the actual network type used
// by the listener.
raddr.network = l.addr.network
return l.dial(ctx, network, *laddr, *raddr)
}
return nil, &net.OpError{
Addr: raddr,
Source: laddr,
Net: network,
Op: "dial",
Err: errors.New("unknown remote address"),
}
}