distributor.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. *
  3. * Copyright 2020 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package certprovider
  19. import (
  20. "context"
  21. "sync"
  22. "google.golang.org/grpc/internal/grpcsync"
  23. )
  24. // Distributor makes it easy for provider implementations to furnish new key
  25. // materials by handling synchronization between the producer and consumers of
  26. // the key material.
  27. //
  28. // Provider implementations which choose to use a Distributor should do the
  29. // following:
  30. // - create a new Distributor using the NewDistributor() function.
  31. // - invoke the Set() method whenever they have new key material or errors to
  32. // report.
  33. // - delegate to the distributor when handing calls to KeyMaterial().
  34. // - invoke the Stop() method when they are done using the distributor.
  35. type Distributor struct {
  36. // mu protects the underlying key material.
  37. mu sync.Mutex
  38. km *KeyMaterial
  39. pErr error
  40. // ready channel to unblock KeyMaterial() invocations blocked on
  41. // availability of key material.
  42. ready *grpcsync.Event
  43. // done channel to notify provider implementations and unblock any
  44. // KeyMaterial() calls, once the Distributor is closed.
  45. closed *grpcsync.Event
  46. }
  47. // NewDistributor returns a new Distributor.
  48. func NewDistributor() *Distributor {
  49. return &Distributor{
  50. ready: grpcsync.NewEvent(),
  51. closed: grpcsync.NewEvent(),
  52. }
  53. }
  54. // Set updates the key material in the distributor with km.
  55. //
  56. // Provider implementations which use the distributor must not modify the
  57. // contents of the KeyMaterial struct pointed to by km.
  58. //
  59. // A non-nil err value indicates the error that the provider implementation ran
  60. // into when trying to fetch key material, and makes it possible to surface the
  61. // error to the user. A non-nil error value passed here causes distributor's
  62. // KeyMaterial() method to return nil key material.
  63. func (d *Distributor) Set(km *KeyMaterial, err error) {
  64. d.mu.Lock()
  65. d.km = km
  66. d.pErr = err
  67. if err != nil {
  68. // If a non-nil err is passed, we ignore the key material being passed.
  69. d.km = nil
  70. }
  71. d.ready.Fire()
  72. d.mu.Unlock()
  73. }
  74. // KeyMaterial returns the most recent key material provided to the Distributor.
  75. // If no key material was provided at the time of this call, it will block until
  76. // the deadline on the context expires or fresh key material arrives.
  77. func (d *Distributor) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
  78. if d.closed.HasFired() {
  79. return nil, errProviderClosed
  80. }
  81. if d.ready.HasFired() {
  82. return d.keyMaterial()
  83. }
  84. select {
  85. case <-ctx.Done():
  86. return nil, ctx.Err()
  87. case <-d.closed.Done():
  88. return nil, errProviderClosed
  89. case <-d.ready.Done():
  90. return d.keyMaterial()
  91. }
  92. }
  93. func (d *Distributor) keyMaterial() (*KeyMaterial, error) {
  94. d.mu.Lock()
  95. defer d.mu.Unlock()
  96. return d.km, d.pErr
  97. }
  98. // Stop turns down the distributor, releases allocated resources and fails any
  99. // active KeyMaterial() call waiting for new key material.
  100. func (d *Distributor) Stop() {
  101. d.closed.Fire()
  102. }