mirror of https://github.com/grpc/grpc-go.git
Fix close in use certificate providers after double `Close()` method call on wrapper object (#7128)
This commit is contained in:
parent
33faea8c2a
commit
24e9024375
|
|
@ -19,8 +19,10 @@
|
||||||
package certprovider
|
package certprovider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// provStore is the global singleton certificate provider store.
|
// provStore is the global singleton certificate provider store.
|
||||||
|
|
@ -53,6 +55,22 @@ type wrappedProvider struct {
|
||||||
store *store
|
store *store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// closedProvider always returns errProviderClosed error.
|
||||||
|
type closedProvider struct{}
|
||||||
|
|
||||||
|
func (c closedProvider) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
|
||||||
|
return nil, errProviderClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c closedProvider) Close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// singleCloseWrappedProvider wraps a provider instance with a reference count
|
||||||
|
// to properly handle multiple calls to Close.
|
||||||
|
type singleCloseWrappedProvider struct {
|
||||||
|
provider atomic.Pointer[Provider]
|
||||||
|
}
|
||||||
|
|
||||||
// store is a collection of provider instances, safe for concurrent access.
|
// store is a collection of provider instances, safe for concurrent access.
|
||||||
type store struct {
|
type store struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
@ -75,6 +93,28 @@ func (wp *wrappedProvider) Close() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close overrides the Close method of the embedded provider to avoid release the
|
||||||
|
// already released reference.
|
||||||
|
func (w *singleCloseWrappedProvider) Close() {
|
||||||
|
newProvider := Provider(closedProvider{})
|
||||||
|
oldProvider := w.provider.Swap(&newProvider)
|
||||||
|
(*oldProvider).Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyMaterial returns the key material sourced by the Provider.
|
||||||
|
// Callers are expected to use the returned value as read-only.
|
||||||
|
func (w *singleCloseWrappedProvider) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
|
||||||
|
return (*w.provider.Load()).KeyMaterial(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newSingleCloseWrappedProvider create wrapper a provider instance with a reference count
|
||||||
|
// to properly handle multiple calls to Close.
|
||||||
|
func newSingleCloseWrappedProvider(provider Provider) *singleCloseWrappedProvider {
|
||||||
|
w := &singleCloseWrappedProvider{}
|
||||||
|
w.provider.Store(&provider)
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
// BuildableConfig wraps parsed provider configuration and functionality to
|
// BuildableConfig wraps parsed provider configuration and functionality to
|
||||||
// instantiate provider instances.
|
// instantiate provider instances.
|
||||||
type BuildableConfig struct {
|
type BuildableConfig struct {
|
||||||
|
|
@ -112,7 +152,7 @@ func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
|
||||||
}
|
}
|
||||||
if wp, ok := provStore.providers[sk]; ok {
|
if wp, ok := provStore.providers[sk]; ok {
|
||||||
wp.refCount++
|
wp.refCount++
|
||||||
return wp, nil
|
return newSingleCloseWrappedProvider(wp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := bc.starter(opts)
|
provider := bc.starter(opts)
|
||||||
|
|
@ -126,7 +166,7 @@ func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
|
||||||
store: provStore,
|
store: provStore,
|
||||||
}
|
}
|
||||||
provStore.providers[sk] = wp
|
provStore.providers[sk] = wp
|
||||||
return wp, nil
|
return newSingleCloseWrappedProvider(wp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the provider name and config as a colon separated string.
|
// String returns the provider name and config as a colon separated string.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue