123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- /*
- *
- * Copyright 2020 gRPC authors.
- *
- * 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.
- *
- */
- package certprovider
- import (
- "context"
- "sync"
- "google.golang.org/grpc/internal/grpcsync"
- )
- // Distributor makes it easy for provider implementations to furnish new key
- // materials by handling synchronization between the producer and consumers of
- // the key material.
- //
- // Provider implementations which choose to use a Distributor should do the
- // following:
- // - create a new Distributor using the NewDistributor() function.
- // - invoke the Set() method whenever they have new key material or errors to
- // report.
- // - delegate to the distributor when handing calls to KeyMaterial().
- // - invoke the Stop() method when they are done using the distributor.
- type Distributor struct {
- // mu protects the underlying key material.
- mu sync.Mutex
- km *KeyMaterial
- pErr error
- // ready channel to unblock KeyMaterial() invocations blocked on
- // availability of key material.
- ready *grpcsync.Event
- // done channel to notify provider implementations and unblock any
- // KeyMaterial() calls, once the Distributor is closed.
- closed *grpcsync.Event
- }
- // NewDistributor returns a new Distributor.
- func NewDistributor() *Distributor {
- return &Distributor{
- ready: grpcsync.NewEvent(),
- closed: grpcsync.NewEvent(),
- }
- }
- // Set updates the key material in the distributor with km.
- //
- // Provider implementations which use the distributor must not modify the
- // contents of the KeyMaterial struct pointed to by km.
- //
- // A non-nil err value indicates the error that the provider implementation ran
- // into when trying to fetch key material, and makes it possible to surface the
- // error to the user. A non-nil error value passed here causes distributor's
- // KeyMaterial() method to return nil key material.
- func (d *Distributor) Set(km *KeyMaterial, err error) {
- d.mu.Lock()
- d.km = km
- d.pErr = err
- if err != nil {
- // If a non-nil err is passed, we ignore the key material being passed.
- d.km = nil
- }
- d.ready.Fire()
- d.mu.Unlock()
- }
- // KeyMaterial returns the most recent key material provided to the Distributor.
- // If no key material was provided at the time of this call, it will block until
- // the deadline on the context expires or fresh key material arrives.
- func (d *Distributor) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
- if d.closed.HasFired() {
- return nil, errProviderClosed
- }
- if d.ready.HasFired() {
- return d.keyMaterial()
- }
- select {
- case <-ctx.Done():
- return nil, ctx.Err()
- case <-d.closed.Done():
- return nil, errProviderClosed
- case <-d.ready.Done():
- return d.keyMaterial()
- }
- }
- func (d *Distributor) keyMaterial() (*KeyMaterial, error) {
- d.mu.Lock()
- defer d.mu.Unlock()
- return d.km, d.pErr
- }
- // Stop turns down the distributor, releases allocated resources and fails any
- // active KeyMaterial() call waiting for new key material.
- func (d *Distributor) Stop() {
- d.closed.Fire()
- }
|